1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.objects; 27 28 import static jdk.nashorn.internal.lookup.Lookup.MH; 29 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; 30 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 31 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 32 33 import java.io.IOException; 34 import java.io.PrintWriter; 35 import java.lang.invoke.MethodHandle; 36 import java.lang.invoke.MethodHandles; 37 import java.lang.invoke.MethodType; 38 import java.lang.invoke.SwitchPoint; 39 import java.lang.reflect.Field; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.concurrent.Callable; 45 import java.util.concurrent.ConcurrentHashMap; 46 import javax.script.ScriptContext; 47 import javax.script.ScriptEngine; 48 import jdk.internal.dynalink.CallSiteDescriptor; 49 import jdk.internal.dynalink.linker.GuardedInvocation; 50 import jdk.internal.dynalink.linker.LinkRequest; 51 import jdk.nashorn.api.scripting.ClassFilter; 52 import jdk.nashorn.api.scripting.ScriptObjectMirror; 53 import jdk.nashorn.internal.lookup.Lookup; 54 import jdk.nashorn.internal.objects.annotations.Attribute; 55 import jdk.nashorn.internal.objects.annotations.Property; 56 import jdk.nashorn.internal.objects.annotations.ScriptClass; 57 import jdk.nashorn.internal.runtime.ConsString; 58 import jdk.nashorn.internal.runtime.Context; 59 import jdk.nashorn.internal.runtime.ECMAErrors; 60 import jdk.nashorn.internal.runtime.GlobalConstants; 61 import jdk.nashorn.internal.runtime.GlobalFunctions; 62 import jdk.nashorn.internal.runtime.JSType; 63 import jdk.nashorn.internal.runtime.NativeJavaPackage; 64 import jdk.nashorn.internal.runtime.PropertyDescriptor; 65 import jdk.nashorn.internal.runtime.PropertyMap; 66 import jdk.nashorn.internal.runtime.Scope; 67 import jdk.nashorn.internal.runtime.ScriptEnvironment; 68 import jdk.nashorn.internal.runtime.ScriptFunction; 69 import jdk.nashorn.internal.runtime.ScriptObject; 70 import jdk.nashorn.internal.runtime.ScriptRuntime; 71 import jdk.nashorn.internal.runtime.ScriptingFunctions; 72 import jdk.nashorn.internal.runtime.Specialization; 73 import jdk.nashorn.internal.runtime.arrays.ArrayData; 74 import jdk.nashorn.internal.runtime.linker.Bootstrap; 75 import jdk.nashorn.internal.runtime.linker.InvokeByName; 76 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 77 import jdk.nashorn.internal.runtime.regexp.RegExpResult; 78 import jdk.nashorn.internal.scripts.JO; 79 80 /** 81 * Representation of global scope. 82 */ 83 @ScriptClass("Global") 84 public final class Global extends ScriptObject implements Scope { 85 // Placeholder value used in place of a location property (__FILE__, __DIR__, __LINE__) 86 private static final Object LOCATION_PROPERTY_PLACEHOLDER = new Object(); 87 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); 88 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); 89 90 /** 91 * Optimistic builtin names that require switchpoint invalidation 92 * upon assignment. Overly conservative, but works for now, to avoid 93 * any complicated scope checks and especially heavy weight guards 94 * like 95 * 96 * <pre> 97 * public boolean setterGuard(final Object receiver) { 98 * final Global global = Global.instance(); 99 * final ScriptObject sobj = global.getFunctionPrototype(); 100 * final Object apply = sobj.get("apply"); 101 * return apply == receiver; 102 * } 103 * </pre> 104 * 105 * Naturally, checking for builtin classes like NativeFunction is cheaper, 106 * it's when you start adding property checks for said builtins you have 107 * problems with guard speed. 108 */ 109 110 /** Nashorn extension: arguments array */ 111 @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 112 public Object arguments; 113 114 /** ECMA 15.1.2.2 parseInt (string , radix) */ 115 @Property(attributes = Attribute.NOT_ENUMERABLE) 116 public Object parseInt; 117 118 /** ECMA 15.1.2.3 parseFloat (string) */ 119 @Property(attributes = Attribute.NOT_ENUMERABLE) 120 public Object parseFloat; 121 122 /** ECMA 15.1.2.4 isNaN (number) */ 123 @Property(attributes = Attribute.NOT_ENUMERABLE) 124 public Object isNaN; 125 126 /** ECMA 15.1.2.5 isFinite (number) */ 127 @Property(attributes = Attribute.NOT_ENUMERABLE) 128 public Object isFinite; 129 130 /** ECMA 15.1.3.3 encodeURI */ 131 @Property(attributes = Attribute.NOT_ENUMERABLE) 132 public Object encodeURI; 133 134 /** ECMA 15.1.3.4 encodeURIComponent */ 135 @Property(attributes = Attribute.NOT_ENUMERABLE) 136 public Object encodeURIComponent; 137 138 /** ECMA 15.1.3.1 decodeURI */ 139 @Property(attributes = Attribute.NOT_ENUMERABLE) 140 public Object decodeURI; 141 142 /** ECMA 15.1.3.2 decodeURIComponent */ 143 @Property(attributes = Attribute.NOT_ENUMERABLE) 144 public Object decodeURIComponent; 145 146 /** ECMA B.2.1 escape (string) */ 147 @Property(attributes = Attribute.NOT_ENUMERABLE) 148 public Object escape; 149 150 /** ECMA B.2.2 unescape (string) */ 151 @Property(attributes = Attribute.NOT_ENUMERABLE) 152 public Object unescape; 153 154 /** Nashorn extension: global.print */ 155 @Property(attributes = Attribute.NOT_ENUMERABLE) 156 public Object print; 157 158 /** Nashorn extension: global.load */ 159 @Property(attributes = Attribute.NOT_ENUMERABLE) 160 public Object load; 161 162 /** Nashorn extension: global.loadWithNewGlobal */ 163 @Property(attributes = Attribute.NOT_ENUMERABLE) 164 public Object loadWithNewGlobal; 165 166 /** Nashorn extension: global.exit */ 167 @Property(attributes = Attribute.NOT_ENUMERABLE) 168 public Object exit; 169 170 /** Nashorn extension: global.quit */ 171 @Property(attributes = Attribute.NOT_ENUMERABLE) 172 public Object quit; 173 174 /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */ 175 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 176 public final double NaN = Double.NaN; 177 178 /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */ 179 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 180 public final double Infinity = Double.POSITIVE_INFINITY; 181 182 /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */ 183 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 184 public final Object undefined = UNDEFINED; 185 186 /** ECMA 15.1.2.1 eval(x) */ 187 @Property(attributes = Attribute.NOT_ENUMERABLE) 188 public Object eval; 189 190 /** ECMA 15.1.4.1 Object constructor. */ 191 @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE) 192 public volatile Object object; 193 194 /** ECMA 15.1.4.2 Function constructor. */ 195 @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE) 196 public volatile Object function; 197 198 /** ECMA 15.1.4.3 Array constructor. */ 199 @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE) 200 public volatile Object array; 201 202 /** ECMA 15.1.4.4 String constructor */ 203 @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE) 204 public volatile Object string; 205 206 /** ECMA 15.1.4.5 Boolean constructor */ 207 @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE) 208 public volatile Object _boolean; 209 210 /** ECMA 15.1.4.6 - Number constructor */ 211 @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE) 212 public volatile Object number; 213 214 /** ECMA 15.1.4.7 Date constructor */ 215 @Property(name = "Date", attributes = Attribute.NOT_ENUMERABLE) 216 public volatile Object date; 217 218 /** ECMA 15.1.4.8 RegExp constructor */ 219 @Property(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) 220 public volatile Object regexp; 221 222 /** ECMA 15.12 - The JSON object */ 223 @Property(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) 224 public volatile Object json; 225 226 /** Nashorn extension: global.JSAdapter */ 227 @Property(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) 228 public volatile Object jsadapter; 229 230 /** ECMA 15.8 - The Math object */ 231 @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE) 232 public volatile Object math; 233 234 /** Error object */ 235 @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE) 236 public volatile Object error; 237 238 /** EvalError object */ 239 @Property(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) 240 public volatile Object evalError; 241 242 /** RangeError object */ 243 @Property(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) 244 public volatile Object rangeError; 245 246 /** ReferenceError object */ 247 @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE) 248 public volatile Object referenceError; 249 250 /** SyntaxError object */ 251 @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE) 252 public volatile Object syntaxError; 253 254 /** TypeError object */ 255 @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE) 256 public volatile Object typeError; 257 258 /** URIError object */ 259 @Property(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) 260 public volatile Object uriError; 261 262 /** ArrayBuffer object */ 263 @Property(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) 264 public volatile Object arrayBuffer; 265 266 /** DataView object */ 267 @Property(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) 268 public volatile Object dataView; 269 270 /** TypedArray (int8) */ 271 @Property(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) 272 public volatile Object int8Array; 273 274 /** TypedArray (uint8) */ 275 @Property(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) 276 public volatile Object uint8Array; 277 278 /** TypedArray (uint8) - Clamped */ 279 @Property(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) 280 public volatile Object uint8ClampedArray; 281 282 /** TypedArray (int16) */ 283 @Property(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) 284 public volatile Object int16Array; 285 286 /** TypedArray (uint16) */ 287 @Property(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) 288 public volatile Object uint16Array; 289 290 /** TypedArray (int32) */ 291 @Property(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) 292 public volatile Object int32Array; 293 294 /** TypedArray (uint32) */ 295 @Property(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) 296 public volatile Object uint32Array; 297 298 /** TypedArray (float32) */ 299 @Property(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) 300 public volatile Object float32Array; 301 302 /** TypedArray (float64) */ 303 @Property(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) 304 public volatile Object float64Array; 305 306 /** Nashorn extension: Java access - global.Packages */ 307 @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE) 308 public volatile Object packages; 309 310 /** Nashorn extension: Java access - global.com */ 311 @Property(attributes = Attribute.NOT_ENUMERABLE) 312 public volatile Object com; 313 314 /** Nashorn extension: Java access - global.edu */ 315 @Property(attributes = Attribute.NOT_ENUMERABLE) 316 public volatile Object edu; 317 318 /** Nashorn extension: Java access - global.java */ 319 @Property(attributes = Attribute.NOT_ENUMERABLE) 320 public volatile Object java; 321 322 /** Nashorn extension: Java access - global.javafx */ 323 @Property(attributes = Attribute.NOT_ENUMERABLE) 324 public volatile Object javafx; 325 326 /** Nashorn extension: Java access - global.javax */ 327 @Property(attributes = Attribute.NOT_ENUMERABLE) 328 public volatile Object javax; 329 330 /** Nashorn extension: Java access - global.org */ 331 @Property(attributes = Attribute.NOT_ENUMERABLE) 332 public volatile Object org; 333 334 /** Nashorn extension: Java access - global.javaImporter */ 335 @Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) 336 public volatile Object javaImporter; 337 338 /** Nashorn extension: global.Java Object constructor. */ 339 @Property(name = "Java", attributes = Attribute.NOT_ENUMERABLE) 340 public volatile Object javaApi; 341 342 /** Nashorn extension: current script's file name */ 343 @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 344 public final Object __FILE__ = LOCATION_PROPERTY_PLACEHOLDER; 345 346 /** Nashorn extension: current script's directory */ 347 @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 348 public final Object __DIR__ = LOCATION_PROPERTY_PLACEHOLDER; 349 350 /** Nashorn extension: current source line number being executed */ 351 @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 352 public final Object __LINE__ = LOCATION_PROPERTY_PLACEHOLDER; 353 354 /** Used as Date.prototype's default value */ 355 public NativeDate DEFAULT_DATE; 356 357 /** Used as RegExp.prototype's default value */ 358 public NativeRegExp DEFAULT_REGEXP; 359 360 /* 361 * Built-in constructor objects: Even if user changes dynamic values of 362 * "Object", "Array" etc., we still want to keep original values of these 363 * constructors here. For example, we need to be able to create array, 364 * regexp literals even after user overwrites global "Array" or "RegExp" 365 * constructor - see also ECMA 262 spec. Annex D. 366 */ 367 private ScriptFunction builtinFunction; 368 private ScriptFunction builtinObject; 369 private ScriptFunction builtinArray; 370 private ScriptFunction builtinBoolean; 371 private ScriptFunction builtinDate; 372 private ScriptObject builtinJSON; 373 private ScriptFunction builtinJSAdapter; 374 private ScriptObject builtinMath; 375 private ScriptFunction builtinNumber; 376 private ScriptFunction builtinRegExp; 377 private ScriptFunction builtinString; 378 private ScriptFunction builtinError; 379 private ScriptFunction builtinEval; 380 private ScriptFunction builtinEvalError; 381 private ScriptFunction builtinRangeError; 382 private ScriptFunction builtinReferenceError; 383 private ScriptFunction builtinSyntaxError; 384 private ScriptFunction builtinTypeError; 385 private ScriptFunction builtinURIError; 386 private ScriptObject builtinPackages; 387 private ScriptObject builtinCom; 388 private ScriptObject builtinEdu; 389 private ScriptObject builtinJava; 390 private ScriptObject builtinJavafx; 391 private ScriptObject builtinJavax; 392 private ScriptObject builtinOrg; 393 private ScriptFunction builtinJavaImporter; 394 private ScriptObject builtinJavaApi; 395 private ScriptFunction builtinArrayBuffer; 396 private ScriptFunction builtinDataView; 397 private ScriptFunction builtinInt8Array; 398 private ScriptFunction builtinUint8Array; 399 private ScriptFunction builtinUint8ClampedArray; 400 private ScriptFunction builtinInt16Array; 401 private ScriptFunction builtinUint16Array; 402 private ScriptFunction builtinInt32Array; 403 private ScriptFunction builtinUint32Array; 404 private ScriptFunction builtinFloat32Array; 405 private ScriptFunction builtinFloat64Array; 406 407 /* 408 * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object 409 */ 410 private ScriptFunction typeErrorThrower; 411 412 // Flag to indicate that a split method issued a return statement 413 private int splitState = -1; 414 415 // Used to store the last RegExp result to support deprecated RegExp constructor properties 416 private RegExpResult lastRegExpResult; 417 418 private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); 419 private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); 420 private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); 421 private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); 422 private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); 423 private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); 424 private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); 425 private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); 426 427 // initialized by nasgen 428 private static PropertyMap $nasgenmap$; 429 430 // context to which this global belongs to 431 private final Context context; 432 433 // current ScriptContext to use - can be null. 434 private ScriptContext scontext; 435 // current ScriptEngine associated - can be null. 436 private ScriptEngine engine; 437 438 // ES6 global lexical scope. 439 private final LexicalScope lexicalScope; 440 441 // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. 442 private SwitchPoint lexicalScopeSwitchPoint; 443 444 /** 445 * Set the current script context 446 * @param scontext script context 447 */ 448 public void setScriptContext(final ScriptContext scontext) { 449 this.scontext = scontext; 450 } 451 452 @Override 453 protected Context getContext() { 454 return context; 455 } 456 457 // performs initialization checks for Global constructor and returns the 458 // PropertyMap, if everything is fine. 459 private static PropertyMap checkAndGetMap(final Context context) { 460 // security check first 461 final SecurityManager sm = System.getSecurityManager(); 462 if (sm != null) { 463 sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); 464 } 465 466 // null check on context 467 context.getClass(); 468 469 return $nasgenmap$; 470 } 471 472 /** 473 * Constructor 474 * 475 * @param context the context 476 */ 477 public Global(final Context context) { 478 super(checkAndGetMap(context)); 479 this.context = context; 480 this.setIsScope(); 481 this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; 482 } 483 484 /** 485 * Script access to "current" Global instance 486 * 487 * @return the global singleton 488 */ 489 public static Global instance() { 490 final Global global = Context.getGlobal(); 491 global.getClass(); // null check 492 return global; 493 } 494 495 private static Global instanceFrom(final Object self) { 496 return self instanceof Global? (Global)self : instance(); 497 } 498 499 /** 500 * Check if we have a Global instance 501 * @return true if one exists 502 */ 503 public static boolean hasInstance() { 504 return Context.getGlobal() != null; 505 } 506 507 /** 508 * Script access to {@link ScriptEnvironment} 509 * 510 * @return the script environment 511 */ 512 static ScriptEnvironment getEnv() { 513 return instance().getContext().getEnv(); 514 } 515 516 /** 517 * Script access to {@link Context} 518 * 519 * @return the context 520 */ 521 static Context getThisContext() { 522 return instance().getContext(); 523 } 524 525 // Runtime interface to Global 526 527 /** 528 * Is there a class filter in the current Context? 529 * @return class filter 530 */ 531 public ClassFilter getClassFilter() { 532 return context.getClassFilter(); 533 } 534 535 /** 536 * Is this global of the given Context? 537 * @param ctxt the context 538 * @return true if this global belongs to the given Context 539 */ 540 public boolean isOfContext(final Context ctxt) { 541 return this.context == ctxt; 542 } 543 544 /** 545 * Does this global belong to a strict Context? 546 * @return true if this global belongs to a strict Context 547 */ 548 public boolean isStrictContext() { 549 return context.getEnv()._strict; 550 } 551 552 /** 553 * Initialize standard builtin objects like "Object", "Array", "Function" etc. 554 * as well as our extension builtin objects like "Java", "JSAdapter" as properties 555 * of the global scope object. 556 * 557 * @param eng ScriptEngine to initialize 558 */ 559 public void initBuiltinObjects(final ScriptEngine eng) { 560 if (this.builtinObject != null) { 561 // already initialized, just return 562 return; 563 } 564 565 this.engine = eng; 566 init(eng); 567 } 568 569 /** 570 * Wrap a Java object as corresponding script object 571 * 572 * @param obj object to wrap 573 * @return wrapped object 574 */ 575 public Object wrapAsObject(final Object obj) { 576 if (obj instanceof Boolean) { 577 return new NativeBoolean((Boolean)obj, this); 578 } else if (obj instanceof Number) { 579 return new NativeNumber(((Number)obj).doubleValue(), this); 580 } else if (obj instanceof String || obj instanceof ConsString) { 581 return new NativeString((CharSequence)obj, this); 582 } else if (obj instanceof Object[]) { // extension 583 return new NativeArray(ArrayData.allocate((Object[])obj), this); 584 } else if (obj instanceof double[]) { // extension 585 return new NativeArray(ArrayData.allocate((double[])obj), this); 586 } else if (obj instanceof long[]) { 587 return new NativeArray(ArrayData.allocate((long[])obj), this); 588 } else if (obj instanceof int[]) { 589 return new NativeArray(ArrayData.allocate((int[]) obj), this); 590 } else if (obj instanceof ArrayData) { 591 return new NativeArray((ArrayData) obj, this); 592 } else { 593 // FIXME: more special cases? Map? List? 594 return obj; 595 } 596 } 597 598 /** 599 * Lookup helper for JS primitive types 600 * 601 * @param request the link request for the dynamic call site. 602 * @param self self reference 603 * 604 * @return guarded invocation 605 */ 606 public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { 607 if (self instanceof String || self instanceof ConsString) { 608 return NativeString.lookupPrimitive(request, self); 609 } else if (self instanceof Number) { 610 return NativeNumber.lookupPrimitive(request, self); 611 } else if (self instanceof Boolean) { 612 return NativeBoolean.lookupPrimitive(request, self); 613 } 614 throw new IllegalArgumentException("Unsupported primitive: " + self); 615 } 616 617 /** 618 * Returns a method handle that creates a wrapper object for a JS primitive value. 619 * 620 * @param self receiver object 621 * @return method handle to create wrapper objects for primitive receiver 622 */ 623 public static MethodHandle getPrimitiveWrapFilter(final Object self) { 624 if (self instanceof String || self instanceof ConsString) { 625 return NativeString.WRAPFILTER; 626 } else if (self instanceof Number) { 627 return NativeNumber.WRAPFILTER; 628 } else if (self instanceof Boolean) { 629 return NativeBoolean.WRAPFILTER; 630 } 631 throw new IllegalArgumentException("Unsupported primitive: " + self); 632 } 633 634 635 /** 636 * Create a new empty script object 637 * 638 * @return the new ScriptObject 639 */ 640 public ScriptObject newObject() { 641 return new JO(getObjectPrototype(), JO.getInitialMap()); 642 } 643 644 /** 645 * Default value of given type 646 * 647 * @param sobj script object 648 * @param typeHint type hint 649 * 650 * @return default value 651 */ 652 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) { 653 // When the [[DefaultValue]] internal method of O is called with no hint, 654 // then it behaves as if the hint were Number, unless O is a Date object 655 // in which case it behaves as if the hint were String. 656 Class<?> hint = typeHint; 657 if (hint == null) { 658 hint = Number.class; 659 } 660 661 try { 662 if (hint == String.class) { 663 664 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 665 666 if (Bootstrap.isCallable(toString)) { 667 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 668 if (JSType.isPrimitive(value)) { 669 return value; 670 } 671 } 672 673 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 674 if (Bootstrap.isCallable(valueOf)) { 675 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 676 if (JSType.isPrimitive(value)) { 677 return value; 678 } 679 } 680 throw typeError(this, "cannot.get.default.string"); 681 } 682 683 if (hint == Number.class) { 684 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 685 if (Bootstrap.isCallable(valueOf)) { 686 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 687 if (JSType.isPrimitive(value)) { 688 return value; 689 } 690 } 691 692 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 693 if (Bootstrap.isCallable(toString)) { 694 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 695 if (JSType.isPrimitive(value)) { 696 return value; 697 } 698 } 699 700 throw typeError(this, "cannot.get.default.number"); 701 } 702 } catch (final RuntimeException | Error e) { 703 throw e; 704 } catch (final Throwable t) { 705 throw new RuntimeException(t); 706 } 707 708 return UNDEFINED; 709 } 710 711 /** 712 * Is the given ScriptObject an ECMAScript Error object? 713 * 714 * @param sobj the object being checked 715 * @return true if sobj is an Error object 716 */ 717 public boolean isError(final ScriptObject sobj) { 718 final ScriptObject errorProto = getErrorPrototype(); 719 ScriptObject proto = sobj.getProto(); 720 while (proto != null) { 721 if (proto == errorProto) { 722 return true; 723 } 724 proto = proto.getProto(); 725 } 726 return false; 727 } 728 729 /** 730 * Create a new ECMAScript Error object. 731 * 732 * @param msg error message 733 * @return newly created Error object 734 */ 735 public ScriptObject newError(final String msg) { 736 return new NativeError(msg, this); 737 } 738 739 /** 740 * Create a new ECMAScript EvalError object. 741 * 742 * @param msg error message 743 * @return newly created EvalError object 744 */ 745 public ScriptObject newEvalError(final String msg) { 746 return new NativeEvalError(msg, this); 747 } 748 749 /** 750 * Create a new ECMAScript RangeError object. 751 * 752 * @param msg error message 753 * @return newly created RangeError object 754 */ 755 public ScriptObject newRangeError(final String msg) { 756 return new NativeRangeError(msg, this); 757 } 758 759 /** 760 * Create a new ECMAScript ReferenceError object. 761 * 762 * @param msg error message 763 * @return newly created ReferenceError object 764 */ 765 public ScriptObject newReferenceError(final String msg) { 766 return new NativeReferenceError(msg, this); 767 } 768 769 /** 770 * Create a new ECMAScript SyntaxError object. 771 * 772 * @param msg error message 773 * @return newly created SyntaxError object 774 */ 775 public ScriptObject newSyntaxError(final String msg) { 776 return new NativeSyntaxError(msg, this); 777 } 778 779 /** 780 * Create a new ECMAScript TypeError object. 781 * 782 * @param msg error message 783 * @return newly created TypeError object 784 */ 785 public ScriptObject newTypeError(final String msg) { 786 return new NativeTypeError(msg, this); 787 } 788 789 /** 790 * Create a new ECMAScript URIError object. 791 * 792 * @param msg error message 793 * @return newly created URIError object 794 */ 795 public ScriptObject newURIError(final String msg) { 796 return new NativeURIError(msg, this); 797 } 798 799 /** 800 * Create a new ECMAScript GenericDescriptor object. 801 * 802 * @param configurable is the property configurable? 803 * @param enumerable is the property enumerable? 804 * @return newly created GenericDescriptor object 805 */ 806 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { 807 return new GenericPropertyDescriptor(configurable, enumerable, this); 808 } 809 810 /** 811 * Create a new ECMAScript DatePropertyDescriptor object. 812 * 813 * @param value of the data property 814 * @param configurable is the property configurable? 815 * @param enumerable is the property enumerable? 816 * @param writable is the property writable? 817 * @return newly created DataPropertyDescriptor object 818 */ 819 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { 820 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); 821 } 822 823 /** 824 * Create a new ECMAScript AccessorPropertyDescriptor object. 825 * 826 * @param get getter function of the user accessor property 827 * @param set setter function of the user accessor property 828 * @param configurable is the property configurable? 829 * @param enumerable is the property enumerable? 830 * @return newly created AccessorPropertyDescriptor object 831 */ 832 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { 833 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); 834 835 if (get == null) { 836 desc.delete(PropertyDescriptor.GET, false); 837 } 838 839 if (set == null) { 840 desc.delete(PropertyDescriptor.SET, false); 841 } 842 843 return desc; 844 } 845 846 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) { 847 final T obj = map.get(key); 848 if (obj != null) { 849 return obj; 850 } 851 852 try { 853 final T newObj = creator.call(); 854 final T existingObj = map.putIfAbsent(key, newObj); 855 return existingObj != null ? existingObj : newObj; 856 } catch (final Exception exp) { 857 throw new RuntimeException(exp); 858 } 859 } 860 861 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>(); 862 863 864 /** 865 * Get cached InvokeByName object for the given key 866 * @param key key to be associated with InvokeByName object 867 * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) 868 * @return InvokeByName object associated with the key. 869 */ 870 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) { 871 return getLazilyCreatedValue(key, creator, namedInvokers); 872 } 873 874 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>(); 875 876 /** 877 * Get cached dynamic method handle for the given key 878 * @param key key to be associated with dynamic method handle 879 * @param creator if method handle is absent 'creator' is called to make one (lazy init) 880 * @return dynamic method handle associated with the key. 881 */ 882 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { 883 return getLazilyCreatedValue(key, creator, dynamicInvokers); 884 } 885 886 /** 887 * Hook to search missing variables in ScriptContext if available 888 * @param self used to detect if scope call or not (this function is 'strict') 889 * @param name name of the variable missing 890 * @return value of the missing variable or undefined (or TypeError for scope search) 891 */ 892 public static Object __noSuchProperty__(final Object self, final Object name) { 893 final Global global = Global.instance(); 894 final ScriptContext sctxt = global.scontext; 895 final String nameStr = name.toString(); 896 897 if (sctxt != null) { 898 final int scope = sctxt.getAttributesScope(nameStr); 899 if (scope != -1) { 900 return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global); 901 } 902 } 903 904 switch (nameStr) { 905 case "context": 906 return sctxt; 907 case "engine": 908 return global.engine; 909 default: 910 break; 911 } 912 913 if (self == UNDEFINED) { 914 // scope access and so throw ReferenceError 915 throw referenceError(global, "not.defined", nameStr); 916 } 917 918 return UNDEFINED; 919 } 920 921 /** 922 * This is the eval used when 'indirect' eval call is made. 923 * 924 * var global = this; 925 * global.eval("print('hello')"); 926 * 927 * @param self eval scope 928 * @param str eval string 929 * 930 * @return the result of eval 931 */ 932 public static Object eval(final Object self, final Object str) { 933 return directEval(self, str, UNDEFINED, UNDEFINED, false); 934 } 935 936 /** 937 * Direct eval 938 * 939 * @param self The scope of eval passed as 'self' 940 * @param str Evaluated code 941 * @param callThis "this" to be passed to the evaluated code 942 * @param location location of the eval call 943 * @param strict is eval called a strict mode code? 944 * 945 * @return the return value of the eval 946 * 947 * This is directly invoked from generated when eval(code) is called in user code 948 */ 949 public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) { 950 if (!(str instanceof String || str instanceof ConsString)) { 951 return str; 952 } 953 final Global global = Global.instanceFrom(self); 954 final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global; 955 956 return global.getContext().eval(scope, str.toString(), callThis, location, strict, true); 957 } 958 959 /** 960 * Global print implementation - Nashorn extension 961 * 962 * @param self scope 963 * @param objects arguments to print 964 * 965 * @return result of print (undefined) 966 */ 967 public static Object print(final Object self, final Object... objects) { 968 return Global.instanceFrom(self).printImpl(false, objects); 969 } 970 971 /** 972 * Global println implementation - Nashorn extension 973 * 974 * @param self scope 975 * @param objects arguments to print 976 * 977 * @return result of println (undefined) 978 */ 979 public static Object println(final Object self, final Object... objects) { 980 return Global.instanceFrom(self).printImpl(true, objects); 981 } 982 983 /** 984 * Global load implementation - Nashorn extension 985 * 986 * @param self scope 987 * @param source source to load 988 * 989 * @return result of load (undefined) 990 * 991 * @throws IOException if source could not be read 992 */ 993 public static Object load(final Object self, final Object source) throws IOException { 994 final Global global = Global.instanceFrom(self); 995 final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global; 996 return global.getContext().load(scope, source); 997 } 998 999 /** 1000 * Global loadWithNewGlobal implementation - Nashorn extension 1001 * 1002 * @param self scope 1003 * @param args from plus (optional) arguments to be passed to the loaded script 1004 * 1005 * @return result of load (may be undefined) 1006 * 1007 * @throws IOException if source could not be read 1008 */ 1009 public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { 1010 final Global global = Global.instanceFrom(self); 1011 final int length = args.length; 1012 final boolean hasArgs = 0 < length; 1013 final Object from = hasArgs ? args[0] : UNDEFINED; 1014 final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; 1015 1016 return global.getContext().loadWithNewGlobal(from, arguments); 1017 } 1018 1019 /** 1020 * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script 1021 * 1022 * @param self self reference 1023 * @param code exit code 1024 * 1025 * @return undefined (will never be reached) 1026 */ 1027 public static Object exit(final Object self, final Object code) { 1028 System.exit(JSType.toInt32(code)); 1029 return UNDEFINED; 1030 } 1031 1032 // builtin prototype accessors 1033 1034 /** 1035 * Get the builtin Object prototype. 1036 * @return the object prototype. 1037 */ 1038 public ScriptObject getObjectPrototype() { 1039 return ScriptFunction.getPrototype(builtinObject); 1040 } 1041 1042 ScriptObject getFunctionPrototype() { 1043 return ScriptFunction.getPrototype(builtinFunction); 1044 } 1045 1046 ScriptObject getArrayPrototype() { 1047 return ScriptFunction.getPrototype(builtinArray); 1048 } 1049 1050 ScriptObject getBooleanPrototype() { 1051 return ScriptFunction.getPrototype(builtinBoolean); 1052 } 1053 1054 ScriptObject getNumberPrototype() { 1055 return ScriptFunction.getPrototype(builtinNumber); 1056 } 1057 1058 ScriptObject getDatePrototype() { 1059 return ScriptFunction.getPrototype(builtinDate); 1060 } 1061 1062 ScriptObject getRegExpPrototype() { 1063 return ScriptFunction.getPrototype(builtinRegExp); 1064 } 1065 1066 ScriptObject getStringPrototype() { 1067 return ScriptFunction.getPrototype(builtinString); 1068 } 1069 1070 ScriptObject getErrorPrototype() { 1071 return ScriptFunction.getPrototype(builtinError); 1072 } 1073 1074 ScriptObject getEvalErrorPrototype() { 1075 return ScriptFunction.getPrototype(builtinEvalError); 1076 } 1077 1078 ScriptObject getRangeErrorPrototype() { 1079 return ScriptFunction.getPrototype(builtinRangeError); 1080 } 1081 1082 ScriptObject getReferenceErrorPrototype() { 1083 return ScriptFunction.getPrototype(builtinReferenceError); 1084 } 1085 1086 ScriptObject getSyntaxErrorPrototype() { 1087 return ScriptFunction.getPrototype(builtinSyntaxError); 1088 } 1089 1090 ScriptObject getTypeErrorPrototype() { 1091 return ScriptFunction.getPrototype(builtinTypeError); 1092 } 1093 1094 ScriptObject getURIErrorPrototype() { 1095 return ScriptFunction.getPrototype(builtinURIError); 1096 } 1097 1098 ScriptObject getJavaImporterPrototype() { 1099 return ScriptFunction.getPrototype(builtinJavaImporter); 1100 } 1101 1102 ScriptObject getJSAdapterPrototype() { 1103 return ScriptFunction.getPrototype(builtinJSAdapter); 1104 } 1105 1106 ScriptObject getArrayBufferPrototype() { 1107 return ScriptFunction.getPrototype(builtinArrayBuffer); 1108 } 1109 1110 ScriptObject getDataViewPrototype() { 1111 return ScriptFunction.getPrototype(builtinDataView); 1112 } 1113 1114 ScriptObject getInt8ArrayPrototype() { 1115 return ScriptFunction.getPrototype(builtinInt8Array); 1116 } 1117 1118 ScriptObject getUint8ArrayPrototype() { 1119 return ScriptFunction.getPrototype(builtinUint8Array); 1120 } 1121 1122 ScriptObject getUint8ClampedArrayPrototype() { 1123 return ScriptFunction.getPrototype(builtinUint8ClampedArray); 1124 } 1125 1126 ScriptObject getInt16ArrayPrototype() { 1127 return ScriptFunction.getPrototype(builtinInt16Array); 1128 } 1129 1130 ScriptObject getUint16ArrayPrototype() { 1131 return ScriptFunction.getPrototype(builtinUint16Array); 1132 } 1133 1134 ScriptObject getInt32ArrayPrototype() { 1135 return ScriptFunction.getPrototype(builtinInt32Array); 1136 } 1137 1138 ScriptObject getUint32ArrayPrototype() { 1139 return ScriptFunction.getPrototype(builtinUint32Array); 1140 } 1141 1142 ScriptObject getFloat32ArrayPrototype() { 1143 return ScriptFunction.getPrototype(builtinFloat32Array); 1144 } 1145 1146 ScriptObject getFloat64ArrayPrototype() { 1147 return ScriptFunction.getPrototype(builtinFloat64Array); 1148 } 1149 1150 private ScriptFunction getBuiltinArray() { 1151 return builtinArray; 1152 } 1153 1154 ScriptFunction getTypeErrorThrower() { 1155 return typeErrorThrower; 1156 } 1157 1158 /** 1159 * Called from compiled script code to test if builtin has been overridden 1160 * 1161 * @return true if builtin array has not been overridden 1162 */ 1163 public static boolean isBuiltinArray() { 1164 final Global instance = Global.instance(); 1165 return instance.array == instance.getBuiltinArray(); 1166 } 1167 1168 private ScriptFunction getBuiltinBoolean() { 1169 return builtinBoolean; 1170 } 1171 1172 /** 1173 * Called from compiled script code to test if builtin has been overridden 1174 * 1175 * @return true if builtin boolean has not been overridden 1176 */ 1177 public static boolean isBuiltinBoolean() { 1178 final Global instance = Global.instance(); 1179 return instance._boolean == instance.getBuiltinBoolean(); 1180 } 1181 1182 private ScriptFunction getBuiltinDate() { 1183 return builtinDate; 1184 } 1185 1186 /** 1187 * Called from compiled script code to test if builtin has been overridden 1188 * 1189 * @return true if builtin date has not been overridden 1190 */ 1191 public static boolean isBuiltinDate() { 1192 final Global instance = Global.instance(); 1193 return instance.date == instance.getBuiltinDate(); 1194 } 1195 1196 private ScriptFunction getBuiltinError() { 1197 return builtinError; 1198 } 1199 1200 /** 1201 * Called from compiled script code to test if builtin has been overridden 1202 * 1203 * @return true if builtin error has not been overridden 1204 */ 1205 public static boolean isBuiltinError() { 1206 final Global instance = Global.instance(); 1207 return instance.error == instance.getBuiltinError(); 1208 } 1209 1210 private ScriptFunction getBuiltinEvalError() { 1211 return builtinEvalError; 1212 } 1213 1214 /** 1215 * Called from compiled script code to test if builtin has been overridden 1216 * 1217 * @return true if builtin eval error has not been overridden 1218 */ 1219 public static boolean isBuiltinEvalError() { 1220 final Global instance = Global.instance(); 1221 return instance.evalError == instance.getBuiltinEvalError(); 1222 } 1223 1224 private ScriptFunction getBuiltinFunction() { 1225 return builtinFunction; 1226 } 1227 1228 /** 1229 * Called from compiled script code to test if builtin has been overridden 1230 * 1231 * @return true if builtin function has not been overridden 1232 */ 1233 public static boolean isBuiltinFunction() { 1234 final Global instance = Global.instance(); 1235 return instance.function == instance.getBuiltinFunction(); 1236 } 1237 1238 /** 1239 * Get the switchpoint used to check property changes for Function.prototype.apply 1240 * @return the switchpoint guarding apply (same as guarding call, and everything else in function) 1241 */ 1242 public static SwitchPoint getBuiltinFunctionApplySwitchPoint() { 1243 return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint(); 1244 } 1245 1246 private static boolean isBuiltinFunctionProperty(final String name) { 1247 final Global instance = Global.instance(); 1248 final ScriptFunction builtinFunction = instance.getBuiltinFunction(); 1249 if (builtinFunction == null) { 1250 return false; //conservative for compile-only mode 1251 } 1252 final boolean isBuiltinFunction = instance.function == builtinFunction; 1253 return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin(); 1254 } 1255 1256 /** 1257 * Check if the Function.prototype.apply has not been replaced 1258 * @return true if Function.prototype.apply has been replaced 1259 */ 1260 public static boolean isBuiltinFunctionPrototypeApply() { 1261 return isBuiltinFunctionProperty("apply"); 1262 } 1263 1264 /** 1265 * Check if the Function.prototype.apply has not been replaced 1266 * @return true if Function.prototype.call has been replaced 1267 */ 1268 public static boolean isBuiltinFunctionPrototypeCall() { 1269 return isBuiltinFunctionProperty("call"); 1270 } 1271 1272 private ScriptFunction getBuiltinJSAdapter() { 1273 return builtinJSAdapter; 1274 } 1275 1276 /** 1277 * Called from compiled script code to test if builtin has been overridden 1278 * 1279 * @return true if builtin JSAdapter has not been overridden 1280 */ 1281 public static boolean isBuiltinJSAdapter() { 1282 final Global instance = Global.instance(); 1283 return instance.jsadapter == instance.getBuiltinJSAdapter(); 1284 } 1285 1286 private ScriptObject getBuiltinJSON() { 1287 return builtinJSON; 1288 } 1289 1290 /** 1291 * Called from compiled script code to test if builtin has been overridden 1292 * 1293 * @return true if builtin JSON has has not been overridden 1294 */ 1295 public static boolean isBuiltinJSON() { 1296 final Global instance = Global.instance(); 1297 return instance.json == instance.getBuiltinJSON(); 1298 } 1299 1300 private ScriptObject getBuiltinJava() { 1301 return builtinJava; 1302 } 1303 1304 /** 1305 * Called from compiled script code to test if builtin has been overridden 1306 * 1307 * @return true if builtin Java has not been overridden 1308 */ 1309 public static boolean isBuiltinJava() { 1310 final Global instance = Global.instance(); 1311 return instance.java == instance.getBuiltinJava(); 1312 } 1313 1314 private ScriptObject getBuiltinJavax() { 1315 return builtinJavax; 1316 } 1317 1318 /** 1319 * Called from compiled script code to test if builtin has been overridden 1320 * 1321 * @return true if builtin Javax has not been overridden 1322 */ 1323 public static boolean isBuiltinJavax() { 1324 final Global instance = Global.instance(); 1325 return instance.javax == instance.getBuiltinJavax(); 1326 } 1327 1328 private ScriptObject getBuiltinJavaImporter() { 1329 return builtinJavaImporter; 1330 } 1331 1332 /** 1333 * Called from compiled script code to test if builtin has been overridden 1334 * 1335 * @return true if builtin Java importer has not been overridden 1336 */ 1337 public static boolean isBuiltinJavaImporter() { 1338 final Global instance = Global.instance(); 1339 return instance.javaImporter == instance.getBuiltinJavaImporter(); 1340 } 1341 1342 private ScriptObject getBuiltinMath() { 1343 return builtinMath; 1344 } 1345 1346 /** 1347 * Called from compiled script code to test if builtin has been overridden 1348 * 1349 * @return true if builtin math has not been overridden 1350 */ 1351 public static boolean isBuiltinMath() { 1352 final Global instance = Global.instance(); 1353 return instance.math == instance.getBuiltinMath(); 1354 } 1355 1356 private ScriptFunction getBuiltinNumber() { 1357 return builtinNumber; 1358 } 1359 1360 /** 1361 * Called from compiled script code to test if builtin has been overridden 1362 * 1363 * @return true if builtin number has not been overridden 1364 */ 1365 public static boolean isBuiltinNumber() { 1366 final Global instance = Global.instance(); 1367 return instance.number == instance.getBuiltinNumber(); 1368 } 1369 1370 private ScriptFunction getBuiltinObject() { 1371 return builtinObject; 1372 } 1373 1374 /** 1375 * Called from compiled script code to test if builtin has been overridden 1376 * 1377 * @return true if builtin object has not been overridden 1378 */ 1379 public static boolean isBuiltinObject() { 1380 final Global instance = Global.instance(); 1381 return instance.object == instance.getBuiltinObject(); 1382 } 1383 1384 private ScriptObject getBuiltinPackages() { 1385 return builtinPackages; 1386 } 1387 1388 /** 1389 * Called from compiled script code to test if builtin has been overridden 1390 * 1391 * @return true if builtin package has not been overridden 1392 */ 1393 public static boolean isBuiltinPackages() { 1394 final Global instance = Global.instance(); 1395 return instance.packages == instance.getBuiltinPackages(); 1396 } 1397 1398 private ScriptFunction getBuiltinRangeError() { 1399 return builtinRangeError; 1400 } 1401 1402 /** 1403 * Called from compiled script code to test if builtin has been overridden 1404 * 1405 * @return true if builtin range error has not been overridden 1406 */ 1407 public static boolean isBuiltinRangeError() { 1408 final Global instance = Global.instance(); 1409 return instance.rangeError == instance.getBuiltinRangeError(); 1410 } 1411 1412 private ScriptFunction getBuiltinReferenceError() { 1413 return builtinReferenceError; 1414 } 1415 1416 /** 1417 * Called from compiled script code to test if builtin has been overridden 1418 * 1419 * @return true if builtin reference error has not been overridden 1420 */ 1421 public static boolean isBuiltinReferenceError() { 1422 final Global instance = Global.instance(); 1423 return instance.referenceError == instance.getBuiltinReferenceError(); 1424 } 1425 1426 private ScriptFunction getBuiltinRegExp() { 1427 return builtinRegExp; 1428 } 1429 1430 /** 1431 * Called from compiled script code to test if builtin has been overridden 1432 * 1433 * @return true if builtin regexp has not been overridden 1434 */ 1435 public static boolean isBuiltinRegExp() { 1436 final Global instance = Global.instance(); 1437 return instance.regexp == instance.getBuiltinRegExp(); 1438 } 1439 1440 private ScriptFunction getBuiltinString() { 1441 return builtinString; 1442 } 1443 1444 /** 1445 * Called from compiled script code to test if builtin has been overridden 1446 * 1447 * @return true if builtin Java has not been overridden 1448 */ 1449 public static boolean isBuiltinString() { 1450 final Global instance = Global.instance(); 1451 return instance.string == instance.getBuiltinString(); 1452 } 1453 1454 private ScriptFunction getBuiltinSyntaxError() { 1455 return builtinSyntaxError; 1456 } 1457 1458 /** 1459 * Called from compiled script code to test if builtin has been overridden 1460 * 1461 * @return true if builtin syntax error has not been overridden 1462 */ 1463 public static boolean isBuiltinSyntaxError() { 1464 final Global instance = Global.instance(); 1465 return instance.syntaxError == instance.getBuiltinSyntaxError(); 1466 } 1467 1468 private ScriptFunction getBuiltinTypeError() { 1469 return builtinTypeError; 1470 } 1471 1472 /** 1473 * Called from compiled script code to test if builtin has been overridden 1474 * 1475 * @return true if builtin type error has not been overridden 1476 */ 1477 public static boolean isBuiltinTypeError() { 1478 final Global instance = Global.instance(); 1479 return instance.typeError == instance.getBuiltinTypeError(); 1480 } 1481 1482 private ScriptFunction getBuiltinURIError() { 1483 return builtinURIError; 1484 } 1485 1486 /** 1487 * Called from compiled script code to test if builtin has been overridden 1488 * 1489 * @return true if builtin URI error has not been overridden 1490 */ 1491 public static boolean isBuiltinURIError() { 1492 final Global instance = Global.instance(); 1493 return instance.uriError == instance.getBuiltinURIError(); 1494 } 1495 1496 @Override 1497 public String getClassName() { 1498 return "global"; 1499 } 1500 1501 /** 1502 * Copy function used to clone NativeRegExp objects. 1503 * 1504 * @param regexp a NativeRegExp to clone 1505 * 1506 * @return copy of the given regexp object 1507 */ 1508 public static Object regExpCopy(final Object regexp) { 1509 return new NativeRegExp((NativeRegExp)regexp); 1510 } 1511 1512 /** 1513 * Convert given object to NativeRegExp type. 1514 * 1515 * @param obj object to be converted 1516 * @return NativeRegExp instance 1517 */ 1518 public static NativeRegExp toRegExp(final Object obj) { 1519 if (obj instanceof NativeRegExp) { 1520 return (NativeRegExp)obj; 1521 } 1522 return new NativeRegExp(JSType.toString(obj)); 1523 } 1524 1525 /** 1526 * ECMA 9.9 ToObject implementation 1527 * 1528 * @param obj an item for which to run ToObject 1529 * @return ToObject version of given item 1530 */ 1531 public static Object toObject(final Object obj) { 1532 if (obj == null || obj == UNDEFINED) { 1533 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1534 } 1535 1536 if (obj instanceof ScriptObject) { 1537 return obj; 1538 } 1539 1540 return instance().wrapAsObject(obj); 1541 } 1542 1543 /** 1544 * Allocate a new object array. 1545 * 1546 * @param initial object values. 1547 * @return the new array 1548 */ 1549 public static NativeArray allocate(final Object[] initial) { 1550 ArrayData arrayData = ArrayData.allocate(initial); 1551 1552 for (int index = 0; index < initial.length; index++) { 1553 final Object value = initial[index]; 1554 1555 if (value == ScriptRuntime.EMPTY) { 1556 arrayData = arrayData.delete(index); 1557 } 1558 } 1559 1560 return new NativeArray(arrayData); 1561 } 1562 1563 /** 1564 * Allocate a new number array. 1565 * 1566 * @param initial number values. 1567 * @return the new array 1568 */ 1569 public static NativeArray allocate(final double[] initial) { 1570 return new NativeArray(ArrayData.allocate(initial)); 1571 } 1572 1573 /** 1574 * Allocate a new long array. 1575 * 1576 * @param initial number values. 1577 * @return the new array 1578 */ 1579 public static NativeArray allocate(final long[] initial) { 1580 return new NativeArray(ArrayData.allocate(initial)); 1581 } 1582 1583 /** 1584 * Allocate a new integer array. 1585 * 1586 * @param initial number values. 1587 * @return the new array 1588 */ 1589 public static NativeArray allocate(final int[] initial) { 1590 return new NativeArray(ArrayData.allocate(initial)); 1591 } 1592 1593 /** 1594 * Allocate a new object array for arguments. 1595 * 1596 * @param arguments initial arguments passed. 1597 * @param callee reference to the function that uses arguments object 1598 * @param numParams actual number of declared parameters 1599 * 1600 * @return the new array 1601 */ 1602 public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) { 1603 return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams); 1604 } 1605 1606 /** 1607 * Called from generated to check if given function is the builtin 'eval'. If 1608 * eval is used in a script, a lot of optimizations and assumptions cannot be done. 1609 * 1610 * @param fn function object that is checked 1611 * @return true if fn is the builtin eval 1612 */ 1613 public static boolean isEval(final Object fn) { 1614 return fn == Global.instance().builtinEval; 1615 } 1616 1617 /** 1618 * Called from generated to replace a location property placeholder with the actual location property value. 1619 * 1620 * @param placeholder the value tested for being a placeholder for a location property 1621 * @param locationProperty the actual value for the location property 1622 * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise 1623 */ 1624 public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) { 1625 return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder; 1626 } 1627 1628 /** 1629 * Called from runtime internals to check if the passed value is a location property placeholder. 1630 * @param placeholder the value tested for being a placeholder for a location property 1631 * @return true if the value is a placeholder, false otherwise. 1632 */ 1633 public static boolean isLocationPropertyPlaceholder(final Object placeholder) { 1634 return placeholder == LOCATION_PROPERTY_PLACEHOLDER; 1635 } 1636 1637 /** 1638 * Create a new RegExp object. 1639 * 1640 * @param expression Regular expression. 1641 * @param options Search options. 1642 * 1643 * @return New RegExp object. 1644 */ 1645 public static Object newRegExp(final String expression, final String options) { 1646 if (options == null) { 1647 return new NativeRegExp(expression); 1648 } 1649 return new NativeRegExp(expression, options); 1650 } 1651 1652 /** 1653 * Get the object prototype 1654 * 1655 * @return the object prototype 1656 */ 1657 public static ScriptObject objectPrototype() { 1658 return Global.instance().getObjectPrototype(); 1659 } 1660 1661 /** 1662 * Create a new empty object instance. 1663 * 1664 * @return New empty object. 1665 */ 1666 public static ScriptObject newEmptyInstance() { 1667 return Global.instance().newObject(); 1668 } 1669 1670 /** 1671 * Check if a given object is a ScriptObject, raises an exception if this is 1672 * not the case 1673 * 1674 * @param obj and object to check 1675 * @return the script object 1676 */ 1677 public static ScriptObject checkObject(final Object obj) { 1678 if (!(obj instanceof ScriptObject)) { 1679 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1680 } 1681 return (ScriptObject)obj; 1682 } 1683 1684 /** 1685 * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception 1686 * if this object is null or undefined. 1687 * 1688 * @param obj an object to check 1689 */ 1690 public static void checkObjectCoercible(final Object obj) { 1691 if (obj == null || obj == UNDEFINED) { 1692 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1693 } 1694 } 1695 1696 /** 1697 * Get the current split state. 1698 * 1699 * @return current split state 1700 */ 1701 @Override 1702 public int getSplitState() { 1703 return splitState; 1704 } 1705 1706 /** 1707 * Set the current split state. 1708 * 1709 * @param state current split state 1710 */ 1711 @Override 1712 public void setSplitState(final int state) { 1713 splitState = state; 1714 } 1715 1716 /** 1717 * Return the ES6 global scope for lexically declared bindings. 1718 * @return the ES6 lexical global scope. 1719 */ 1720 public final ScriptObject getLexicalScope() { 1721 assert context.getEnv()._es6; 1722 return lexicalScope; 1723 } 1724 1725 @Override 1726 public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { 1727 PropertyMap ownMap = getMap(); 1728 LexicalScope lexicalScope = null; 1729 PropertyMap lexicalMap = null; 1730 boolean hasLexicalDefinitions = false; 1731 1732 if (context.getEnv()._es6) { 1733 lexicalScope = (LexicalScope) getLexicalScope(); 1734 lexicalMap = lexicalScope.getMap(); 1735 1736 for (final jdk.nashorn.internal.runtime.Property property : properties) { 1737 if (property.isLexicalBinding()) { 1738 hasLexicalDefinitions = true; 1739 } 1740 // ES6 15.1.8 steps 6. and 7. 1741 final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); 1742 if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { 1743 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 1744 } 1745 final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); 1746 if (lexicalProperty != null && !property.isConfigurable()) { 1747 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 1748 } 1749 } 1750 } 1751 1752 for (final jdk.nashorn.internal.runtime.Property property : properties) { 1753 if (property.isLexicalBinding()) { 1754 assert lexicalScope != null; 1755 lexicalMap = lexicalScope.addBoundProperty(lexicalMap, source, property); 1756 1757 if (ownMap.findProperty(property.getKey()) != null) { 1758 // If property exists in the global object invalidate any global constant call sites. 1759 invalidateGlobalConstant(property.getKey()); 1760 } 1761 } else { 1762 ownMap = addBoundProperty(ownMap, source, property); 1763 } 1764 } 1765 1766 setMap(ownMap); 1767 1768 if (hasLexicalDefinitions) { 1769 lexicalScope.setMap(lexicalMap); 1770 invalidateLexicalSwitchPoint(); 1771 } 1772 } 1773 1774 @Override 1775 public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 1776 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1777 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 1778 1779 if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { 1780 if (lexicalScope.hasOwnProperty(name)) { 1781 return lexicalScope.findGetMethod(desc, request, operator); 1782 } 1783 } 1784 1785 final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); 1786 1787 // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, 1788 // because those are invalidated per-key in the addBoundProperties method above. 1789 // We therefor check if the invocation does already have a switchpoint and the property is non-inherited, 1790 // assuming this only applies to global constants. If other non-inherited properties will 1791 // start using switchpoints some time in the future we'll have to revisit this. 1792 if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { 1793 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 1794 } 1795 1796 return invocation; 1797 } 1798 1799 @Override 1800 public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 1801 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 1802 1803 if (lexicalScope != null && isScope) { 1804 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1805 if (lexicalScope.hasOwnProperty(name)) { 1806 return lexicalScope.findSetMethod(desc, request); 1807 } 1808 } 1809 1810 final GuardedInvocation invocation = super.findSetMethod(desc, request); 1811 1812 if (isScope && context.getEnv()._es6) { 1813 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 1814 } 1815 1816 return invocation; 1817 } 1818 1819 private synchronized SwitchPoint getLexicalScopeSwitchPoint() { 1820 SwitchPoint switchPoint = lexicalScopeSwitchPoint; 1821 if (switchPoint == null || switchPoint.hasBeenInvalidated()) { 1822 switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); 1823 } 1824 return switchPoint; 1825 } 1826 1827 private synchronized void invalidateLexicalSwitchPoint() { 1828 if (lexicalScopeSwitchPoint != null) { 1829 context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); 1830 SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); 1831 } 1832 } 1833 1834 1835 @SuppressWarnings("unused") 1836 private static Object lexicalScopeFilter(final Object self) { 1837 if (self instanceof Global) { 1838 return ((Global) self).getLexicalScope(); 1839 } 1840 return self; 1841 } 1842 1843 private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) { 1844 final T func = initConstructor(name, clazz); 1845 tagBuiltinProperties(name, func); 1846 return func; 1847 } 1848 1849 private void init(final ScriptEngine eng) { 1850 assert Context.getGlobal() == this : "this global is not set as current"; 1851 1852 final ScriptEnvironment env = getContext().getEnv(); 1853 1854 // initialize Function and Object constructor 1855 initFunctionAndObject(); 1856 1857 // Now fix Global's own proto. 1858 this.setInitialProto(getObjectPrototype()); 1859 1860 // initialize global function properties 1861 this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL); 1862 1863 this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT, 1864 new Specialization[] { 1865 new Specialization(GlobalFunctions.PARSEINT_Z), 1866 new Specialization(GlobalFunctions.PARSEINT_I), 1867 new Specialization(GlobalFunctions.PARSEINT_J), 1868 new Specialization(GlobalFunctions.PARSEINT_OI), 1869 new Specialization(GlobalFunctions.PARSEINT_O) }); 1870 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1871 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN, 1872 new Specialization[] { 1873 new Specialization(GlobalFunctions.IS_NAN_I), 1874 new Specialization(GlobalFunctions.IS_NAN_J), 1875 new Specialization(GlobalFunctions.IS_NAN_D) }); 1876 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1877 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN); 1878 this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE); 1879 this.encodeURI = ScriptFunctionImpl.makeFunction("encodeURI", GlobalFunctions.ENCODE_URI); 1880 this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); 1881 this.decodeURI = ScriptFunctionImpl.makeFunction("decodeURI", GlobalFunctions.DECODE_URI); 1882 this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); 1883 this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE); 1884 this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); 1885 this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); 1886 this.load = ScriptFunctionImpl.makeFunction("load", LOAD); 1887 this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); 1888 this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); 1889 this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); 1890 1891 // built-in constructors 1892 this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); 1893 this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); 1894 this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); 1895 this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); 1896 this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); 1897 this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); 1898 this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); 1899 this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); 1900 this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); 1901 1902 // initialize String.prototype.length to 0 1903 // add String.prototype.length 1904 final ScriptObject stringPrototype = getStringPrototype(); 1905 stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); 1906 1907 // set isArray flag on Array.prototype 1908 final ScriptObject arrayPrototype = getArrayPrototype(); 1909 arrayPrototype.setIsArray(); 1910 1911 this.DEFAULT_DATE = new NativeDate(Double.NaN, this); 1912 1913 // initialize default regexp object 1914 this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this); 1915 1916 // RegExp.prototype should behave like a RegExp object. So copy the 1917 // properties. 1918 final ScriptObject regExpProto = getRegExpPrototype(); 1919 regExpProto.addBoundProperties(DEFAULT_REGEXP); 1920 1921 // Error stuff 1922 initErrorObjects(); 1923 1924 // java access 1925 if (! env._no_java) { 1926 initJavaAccess(); 1927 } 1928 1929 if (! env._no_typed_arrays) { 1930 initTypedArray(); 1931 } 1932 1933 if (env._scripting) { 1934 initScripting(env); 1935 } 1936 1937 if (Context.DEBUG) { 1938 boolean debugOkay; 1939 final SecurityManager sm = System.getSecurityManager(); 1940 if (sm != null) { 1941 try { 1942 sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); 1943 debugOkay = true; 1944 } catch (final SecurityException ignored) { 1945 // if no permission, don't initialize Debug object 1946 debugOkay = false; 1947 } 1948 1949 } else { 1950 debugOkay = true; 1951 } 1952 1953 if (debugOkay) { 1954 initDebug(); 1955 } 1956 } 1957 1958 copyBuiltins(); 1959 1960 // expose script (command line) arguments as "arguments" property of global 1961 arguments = wrapAsObject(env.getArguments().toArray()); 1962 if (env._scripting) { 1963 // synonym for "arguments" in scripting mode 1964 addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); 1965 } 1966 1967 if (eng != null) { 1968 // default file name 1969 addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); 1970 // __noSuchProperty__ hook for ScriptContext search of missing variables 1971 final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); 1972 addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); 1973 } 1974 } 1975 1976 private void initErrorObjects() { 1977 // Error objects 1978 this.builtinError = initConstructor("Error", ScriptFunction.class); 1979 final ScriptObject errorProto = getErrorPrototype(); 1980 1981 // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName 1982 final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK); 1983 final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK); 1984 errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); 1985 final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER); 1986 final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER); 1987 errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); 1988 final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER); 1989 final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER); 1990 errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); 1991 final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME); 1992 final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("setFileName", NativeError.SET_FILENAME); 1993 errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); 1994 1995 // ECMA 15.11.4.2 Error.prototype.name 1996 // Error.prototype.name = "Error"; 1997 errorProto.set(NativeError.NAME, "Error", 0); 1998 // ECMA 15.11.4.3 Error.prototype.message 1999 // Error.prototype.message = ""; 2000 errorProto.set(NativeError.MESSAGE, "", 0); 2001 2002 tagBuiltinProperties("Error", builtinError); 2003 2004 this.builtinEvalError = initErrorSubtype("EvalError", errorProto); 2005 this.builtinRangeError = initErrorSubtype("RangeError", errorProto); 2006 this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); 2007 this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); 2008 this.builtinTypeError = initErrorSubtype("TypeError", errorProto); 2009 this.builtinURIError = initErrorSubtype("URIError", errorProto); 2010 } 2011 2012 private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { 2013 final ScriptFunction cons = initConstructor(name, ScriptFunction.class); 2014 final ScriptObject prototype = ScriptFunction.getPrototype(cons); 2015 prototype.set(NativeError.NAME, name, 0); 2016 prototype.set(NativeError.MESSAGE, "", 0); 2017 prototype.setInitialProto(errorProto); 2018 tagBuiltinProperties(name, cons); 2019 return cons; 2020 } 2021 2022 private void initJavaAccess() { 2023 final ScriptObject objectProto = getObjectPrototype(); 2024 this.builtinPackages = new NativeJavaPackage("", objectProto); 2025 this.builtinCom = new NativeJavaPackage("com", objectProto); 2026 this.builtinEdu = new NativeJavaPackage("edu", objectProto); 2027 this.builtinJava = new NativeJavaPackage("java", objectProto); 2028 this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); 2029 this.builtinJavax = new NativeJavaPackage("javax", objectProto); 2030 this.builtinOrg = new NativeJavaPackage("org", objectProto); 2031 this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); 2032 this.builtinJavaApi = initConstructor("Java", ScriptObject.class); 2033 } 2034 2035 private void initScripting(final ScriptEnvironment scriptEnv) { 2036 Object value; 2037 value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE); 2038 addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); 2039 2040 value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); 2041 addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); 2042 2043 final String execName = ScriptingFunctions.EXEC_NAME; 2044 value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); 2045 addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); 2046 2047 // Nashorn extension: global.echo (scripting-mode-only) 2048 // alias for "print" 2049 value = get("print"); 2050 addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); 2051 2052 // Nashorn extension: global.$OPTIONS (scripting-mode-only) 2053 final ScriptObject options = newObject(); 2054 copyOptions(options, scriptEnv); 2055 addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); 2056 2057 // Nashorn extension: global.$ENV (scripting-mode-only) 2058 if (System.getSecurityManager() == null) { 2059 // do not fill $ENV if we have a security manager around 2060 // Retrieve current state of ENV variables. 2061 final ScriptObject env = newObject(); 2062 env.putAll(System.getenv(), scriptEnv._strict); 2063 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); 2064 } else { 2065 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2066 } 2067 2068 // add other special properties for exec support 2069 addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2070 addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2071 addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2072 } 2073 2074 private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { 2075 for (final Field f : scriptEnv.getClass().getFields()) { 2076 try { 2077 options.set(f.getName(), f.get(scriptEnv), 0); 2078 } catch (final IllegalArgumentException | IllegalAccessException exp) { 2079 throw new RuntimeException(exp); 2080 } 2081 } 2082 } 2083 2084 private void initTypedArray() { 2085 this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); 2086 this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); 2087 this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); 2088 this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); 2089 this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); 2090 this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); 2091 this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); 2092 this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); 2093 this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); 2094 this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); 2095 this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); 2096 2097 } 2098 2099 private void copyBuiltins() { 2100 this.array = this.builtinArray; 2101 this._boolean = this.builtinBoolean; 2102 this.date = this.builtinDate; 2103 this.error = this.builtinError; 2104 this.evalError = this.builtinEvalError; 2105 this.function = this.builtinFunction; 2106 this.jsadapter = this.builtinJSAdapter; 2107 this.json = this.builtinJSON; 2108 this.com = this.builtinCom; 2109 this.edu = this.builtinEdu; 2110 this.java = this.builtinJava; 2111 this.javafx = this.builtinJavafx; 2112 this.javax = this.builtinJavax; 2113 this.org = this.builtinOrg; 2114 this.javaImporter = this.builtinJavaImporter; 2115 this.javaApi = this.builtinJavaApi; 2116 this.math = this.builtinMath; 2117 this.number = this.builtinNumber; 2118 this.object = this.builtinObject; 2119 this.packages = this.builtinPackages; 2120 this.rangeError = this.builtinRangeError; 2121 this.referenceError = this.builtinReferenceError; 2122 this.regexp = this.builtinRegExp; 2123 this.string = this.builtinString; 2124 this.syntaxError = this.builtinSyntaxError; 2125 this.typeError = this.builtinTypeError; 2126 this.uriError = this.builtinURIError; 2127 this.arrayBuffer = this.builtinArrayBuffer; 2128 this.dataView = this.builtinDataView; 2129 this.int8Array = this.builtinInt8Array; 2130 this.uint8Array = this.builtinUint8Array; 2131 this.uint8ClampedArray = this.builtinUint8ClampedArray; 2132 this.int16Array = this.builtinInt16Array; 2133 this.uint16Array = this.builtinUint16Array; 2134 this.int32Array = this.builtinInt32Array; 2135 this.uint32Array = this.builtinUint32Array; 2136 this.float32Array = this.builtinFloat32Array; 2137 this.float64Array = this.builtinFloat64Array; 2138 } 2139 2140 private void initDebug() { 2141 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); 2142 } 2143 2144 private Object printImpl(final boolean newLine, final Object... objects) { 2145 @SuppressWarnings("resource") 2146 final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut(); 2147 final StringBuilder sb = new StringBuilder(); 2148 2149 for (final Object obj : objects) { 2150 if (sb.length() != 0) { 2151 sb.append(' '); 2152 } 2153 2154 sb.append(JSType.toString(obj)); 2155 } 2156 2157 // Print all at once to ensure thread friendly result. 2158 if (newLine) { 2159 out.println(sb.toString()); 2160 } else { 2161 out.print(sb.toString()); 2162 } 2163 2164 out.flush(); 2165 2166 return UNDEFINED; 2167 } 2168 2169 private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) { 2170 try { 2171 // Assuming class name pattern for built-in JS constructors. 2172 final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); 2173 2174 sb.append("Native"); 2175 sb.append(name); 2176 sb.append("$Constructor"); 2177 2178 final Class<?> funcClass = Class.forName(sb.toString()); 2179 final T res = clazz.cast(funcClass.newInstance()); 2180 2181 if (res instanceof ScriptFunction) { 2182 // All global constructor prototypes are not-writable, 2183 // not-enumerable and not-configurable. 2184 final ScriptFunction func = (ScriptFunction)res; 2185 func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); 2186 } 2187 2188 if (res.getProto() == null) { 2189 res.setInitialProto(getObjectPrototype()); 2190 } 2191 2192 res.setIsBuiltin(); 2193 2194 return res; 2195 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { 2196 throw new RuntimeException(e); 2197 } 2198 } 2199 2200 private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) { 2201 final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>(); 2202 2203 list.addAll(Arrays.asList(func.getMap().getProperties())); 2204 2205 if (func instanceof ScriptFunction) { 2206 final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); 2207 if (proto != null) { 2208 list.addAll(Arrays.asList(proto.getMap().getProperties())); 2209 } 2210 } 2211 2212 final jdk.nashorn.internal.runtime.Property prop = getProperty(name); 2213 if (prop != null) { 2214 list.add(prop); 2215 } 2216 2217 return list; 2218 } 2219 2220 /** 2221 * Given a builtin object, traverse its properties recursively and associate them with a name that 2222 * will be a key to their invalidation switchpoint. 2223 * @param name name for key 2224 * @param func builtin script object 2225 */ 2226 private void tagBuiltinProperties(final String name, final ScriptObject func) { 2227 SwitchPoint sp = context.getBuiltinSwitchPoint(name); 2228 if (sp == null) { 2229 sp = context.newBuiltinSwitchPoint(name); 2230 } 2231 2232 //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, 2233 //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc 2234 for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { 2235 prop.setBuiltinSwitchPoint(sp); 2236 } 2237 } 2238 2239 // Function and Object constructors are inter-dependent. Also, 2240 // Function.prototype 2241 // functions are not properly initialized. We fix the references here. 2242 // NOTE: be careful if you want to re-order the operations here. You may 2243 // have 2244 // to play with object references carefully!! 2245 private void initFunctionAndObject() { 2246 // First-n-foremost is Function 2247 2248 this.builtinFunction = initConstructor("Function", ScriptFunction.class); 2249 2250 // create global anonymous function 2251 final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(); 2252 // need to copy over members of Function.prototype to anon function 2253 anon.addBoundProperties(getFunctionPrototype()); 2254 2255 // Function.prototype === Object.getPrototypeOf(Function) === 2256 // <anon-function> 2257 builtinFunction.setInitialProto(anon); 2258 builtinFunction.setPrototype(anon); 2259 anon.set("constructor", builtinFunction, 0); 2260 anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); 2261 2262 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 2263 this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0); 2264 typeErrorThrower.setPrototype(UNDEFINED); 2265 // Non-constructor built-in functions do not have "prototype" property 2266 typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype")); 2267 typeErrorThrower.preventExtensions(); 2268 2269 // now initialize Object 2270 this.builtinObject = initConstructor("Object", ScriptFunction.class); 2271 final ScriptObject ObjectPrototype = getObjectPrototype(); 2272 // Object.getPrototypeOf(Function.prototype) === Object.prototype 2273 anon.setInitialProto(ObjectPrototype); 2274 2275 // ES6 draft compliant __proto__ property of Object.prototype 2276 // accessors on Object.prototype for "__proto__" 2277 final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__); 2278 final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__); 2279 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 2280 2281 // Function valued properties of Function.prototype were not properly 2282 // initialized. Because, these were created before global.function and 2283 // global.object were not initialized. 2284 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); 2285 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2286 final Object key = property.getKey(); 2287 final Object value = builtinFunction.get(key); 2288 2289 if (value instanceof ScriptFunction && value != anon) { 2290 final ScriptFunction func = (ScriptFunction)value; 2291 func.setInitialProto(getFunctionPrototype()); 2292 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2293 if (prototype != null) { 2294 prototype.setInitialProto(ObjectPrototype); 2295 } 2296 } 2297 } 2298 2299 // For function valued properties of Object and Object.prototype, make 2300 // sure prototype's proto chain ends with Object.prototype 2301 for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { 2302 final Object key = property.getKey(); 2303 final Object value = builtinObject.get(key); 2304 2305 if (value instanceof ScriptFunction) { 2306 final ScriptFunction func = (ScriptFunction)value; 2307 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2308 if (prototype != null) { 2309 prototype.setInitialProto(ObjectPrototype); 2310 } 2311 } 2312 } 2313 2314 properties = getObjectPrototype().getMap().getProperties(); 2315 2316 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2317 final Object key = property.getKey(); 2318 if (key.equals("constructor")) { 2319 continue; 2320 } 2321 2322 final Object value = ObjectPrototype.get(key); 2323 if (value instanceof ScriptFunction) { 2324 final ScriptFunction func = (ScriptFunction)value; 2325 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2326 if (prototype != null) { 2327 prototype.setInitialProto(ObjectPrototype); 2328 } 2329 } 2330 } 2331 2332 tagBuiltinProperties("Object", builtinObject); 2333 tagBuiltinProperties("Function", builtinFunction); 2334 tagBuiltinProperties("Function", anon); 2335 } 2336 2337 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 2338 return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); 2339 } 2340 2341 RegExpResult getLastRegExpResult() { 2342 return lastRegExpResult; 2343 } 2344 2345 void setLastRegExpResult(final RegExpResult regExpResult) { 2346 this.lastRegExpResult = regExpResult; 2347 } 2348 2349 @Override 2350 protected boolean isGlobal() { 2351 return true; 2352 } 2353 2354 /** 2355 * A class representing the ES6 global lexical scope. 2356 */ 2357 private static class LexicalScope extends ScriptObject { 2358 2359 LexicalScope(final ScriptObject proto) { 2360 super(proto, PropertyMap.newMap()); 2361 } 2362 2363 @Override 2364 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 2365 return filterInvocation(super.findGetMethod(desc, request, operator)); 2366 } 2367 2368 @Override 2369 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2370 return filterInvocation(super.findSetMethod(desc, request)); 2371 } 2372 2373 @Override 2374 protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) { 2375 // We override this method just to make it callable by Global 2376 return super.addBoundProperty(propMap, source, property); 2377 } 2378 2379 private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { 2380 final MethodType type = invocation.getInvocation().type(); 2381 return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); 2382 } 2383 } 2384 2385 }