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((Object[])obj); 584 } else if (obj instanceof double[]) { // extension 585 return new NativeArray((double[])obj); 586 } else if (obj instanceof long[]) { 587 return new NativeArray((long[])obj); 588 } else if (obj instanceof int[]) { 589 return new NativeArray((int[])obj); 590 } else { 591 // FIXME: more special cases? Map? List? 592 return obj; 593 } 594 } 595 596 /** 597 * Lookup helper for JS primitive types 598 * 599 * @param request the link request for the dynamic call site. 600 * @param self self reference 601 * 602 * @return guarded invocation 603 */ 604 public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) { 605 if (self instanceof String || self instanceof ConsString) { 606 return NativeString.lookupPrimitive(request, self); 607 } else if (self instanceof Number) { 608 return NativeNumber.lookupPrimitive(request, self); 609 } else if (self instanceof Boolean) { 610 return NativeBoolean.lookupPrimitive(request, self); 611 } 612 throw new IllegalArgumentException("Unsupported primitive: " + self); 613 } 614 615 /** 616 * Returns a method handle that creates a wrapper object for a JS primitive value. 617 * 618 * @param self receiver object 619 * @return method handle to create wrapper objects for primitive receiver 620 */ 621 public static MethodHandle getPrimitiveWrapFilter(final Object self) { 622 if (self instanceof String || self instanceof ConsString) { 623 return NativeString.WRAPFILTER; 624 } else if (self instanceof Number) { 625 return NativeNumber.WRAPFILTER; 626 } else if (self instanceof Boolean) { 627 return NativeBoolean.WRAPFILTER; 628 } 629 throw new IllegalArgumentException("Unsupported primitive: " + self); 630 } 631 632 633 /** 634 * Create a new empty script object 635 * 636 * @return the new ScriptObject 637 */ 638 public ScriptObject newObject() { 639 return new JO(getObjectPrototype(), JO.getInitialMap()); 640 } 641 642 /** 643 * Default value of given type 644 * 645 * @param sobj script object 646 * @param typeHint type hint 647 * 648 * @return default value 649 */ 650 public Object getDefaultValue(final ScriptObject sobj, final Class<?> typeHint) { 651 // When the [[DefaultValue]] internal method of O is called with no hint, 652 // then it behaves as if the hint were Number, unless O is a Date object 653 // in which case it behaves as if the hint were String. 654 Class<?> hint = typeHint; 655 if (hint == null) { 656 hint = Number.class; 657 } 658 659 try { 660 if (hint == String.class) { 661 662 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 663 664 if (Bootstrap.isCallable(toString)) { 665 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 666 if (JSType.isPrimitive(value)) { 667 return value; 668 } 669 } 670 671 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 672 if (Bootstrap.isCallable(valueOf)) { 673 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 674 if (JSType.isPrimitive(value)) { 675 return value; 676 } 677 } 678 throw typeError(this, "cannot.get.default.string"); 679 } 680 681 if (hint == Number.class) { 682 final Object valueOf = VALUE_OF.getGetter().invokeExact(sobj); 683 if (Bootstrap.isCallable(valueOf)) { 684 final Object value = VALUE_OF.getInvoker().invokeExact(valueOf, sobj); 685 if (JSType.isPrimitive(value)) { 686 return value; 687 } 688 } 689 690 final Object toString = TO_STRING.getGetter().invokeExact(sobj); 691 if (Bootstrap.isCallable(toString)) { 692 final Object value = TO_STRING.getInvoker().invokeExact(toString, sobj); 693 if (JSType.isPrimitive(value)) { 694 return value; 695 } 696 } 697 698 throw typeError(this, "cannot.get.default.number"); 699 } 700 } catch (final RuntimeException | Error e) { 701 throw e; 702 } catch (final Throwable t) { 703 throw new RuntimeException(t); 704 } 705 706 return UNDEFINED; 707 } 708 709 /** 710 * Is the given ScriptObject an ECMAScript Error object? 711 * 712 * @param sobj the object being checked 713 * @return true if sobj is an Error object 714 */ 715 public boolean isError(final ScriptObject sobj) { 716 final ScriptObject errorProto = getErrorPrototype(); 717 ScriptObject proto = sobj.getProto(); 718 while (proto != null) { 719 if (proto == errorProto) { 720 return true; 721 } 722 proto = proto.getProto(); 723 } 724 return false; 725 } 726 727 /** 728 * Create a new ECMAScript Error object. 729 * 730 * @param msg error message 731 * @return newly created Error object 732 */ 733 public ScriptObject newError(final String msg) { 734 return new NativeError(msg, this); 735 } 736 737 /** 738 * Create a new ECMAScript EvalError object. 739 * 740 * @param msg error message 741 * @return newly created EvalError object 742 */ 743 public ScriptObject newEvalError(final String msg) { 744 return new NativeEvalError(msg, this); 745 } 746 747 /** 748 * Create a new ECMAScript RangeError object. 749 * 750 * @param msg error message 751 * @return newly created RangeError object 752 */ 753 public ScriptObject newRangeError(final String msg) { 754 return new NativeRangeError(msg, this); 755 } 756 757 /** 758 * Create a new ECMAScript ReferenceError object. 759 * 760 * @param msg error message 761 * @return newly created ReferenceError object 762 */ 763 public ScriptObject newReferenceError(final String msg) { 764 return new NativeReferenceError(msg, this); 765 } 766 767 /** 768 * Create a new ECMAScript SyntaxError object. 769 * 770 * @param msg error message 771 * @return newly created SyntaxError object 772 */ 773 public ScriptObject newSyntaxError(final String msg) { 774 return new NativeSyntaxError(msg, this); 775 } 776 777 /** 778 * Create a new ECMAScript TypeError object. 779 * 780 * @param msg error message 781 * @return newly created TypeError object 782 */ 783 public ScriptObject newTypeError(final String msg) { 784 return new NativeTypeError(msg, this); 785 } 786 787 /** 788 * Create a new ECMAScript URIError object. 789 * 790 * @param msg error message 791 * @return newly created URIError object 792 */ 793 public ScriptObject newURIError(final String msg) { 794 return new NativeURIError(msg, this); 795 } 796 797 /** 798 * Create a new ECMAScript GenericDescriptor object. 799 * 800 * @param configurable is the property configurable? 801 * @param enumerable is the property enumerable? 802 * @return newly created GenericDescriptor object 803 */ 804 public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) { 805 return new GenericPropertyDescriptor(configurable, enumerable, this); 806 } 807 808 /** 809 * Create a new ECMAScript DatePropertyDescriptor object. 810 * 811 * @param value of the data property 812 * @param configurable is the property configurable? 813 * @param enumerable is the property enumerable? 814 * @param writable is the property writable? 815 * @return newly created DataPropertyDescriptor object 816 */ 817 public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) { 818 return new DataPropertyDescriptor(configurable, enumerable, writable, value, this); 819 } 820 821 /** 822 * Create a new ECMAScript AccessorPropertyDescriptor object. 823 * 824 * @param get getter function of the user accessor property 825 * @param set setter function of the user accessor property 826 * @param configurable is the property configurable? 827 * @param enumerable is the property enumerable? 828 * @return newly created AccessorPropertyDescriptor object 829 */ 830 public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { 831 final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this); 832 833 if (get == null) { 834 desc.delete(PropertyDescriptor.GET, false); 835 } 836 837 if (set == null) { 838 desc.delete(PropertyDescriptor.SET, false); 839 } 840 841 return desc; 842 } 843 844 private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) { 845 final T obj = map.get(key); 846 if (obj != null) { 847 return obj; 848 } 849 850 try { 851 final T newObj = creator.call(); 852 final T existingObj = map.putIfAbsent(key, newObj); 853 return existingObj != null ? existingObj : newObj; 854 } catch (final Exception exp) { 855 throw new RuntimeException(exp); 856 } 857 } 858 859 private final Map<Object, InvokeByName> namedInvokers = new ConcurrentHashMap<>(); 860 861 862 /** 863 * Get cached InvokeByName object for the given key 864 * @param key key to be associated with InvokeByName object 865 * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) 866 * @return InvokeByName object associated with the key. 867 */ 868 public InvokeByName getInvokeByName(final Object key, final Callable<InvokeByName> creator) { 869 return getLazilyCreatedValue(key, creator, namedInvokers); 870 } 871 872 private final Map<Object, MethodHandle> dynamicInvokers = new ConcurrentHashMap<>(); 873 874 /** 875 * Get cached dynamic method handle for the given key 876 * @param key key to be associated with dynamic method handle 877 * @param creator if method handle is absent 'creator' is called to make one (lazy init) 878 * @return dynamic method handle associated with the key. 879 */ 880 public MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { 881 return getLazilyCreatedValue(key, creator, dynamicInvokers); 882 } 883 884 /** 885 * Hook to search missing variables in ScriptContext if available 886 * @param self used to detect if scope call or not (this function is 'strict') 887 * @param name name of the variable missing 888 * @return value of the missing variable or undefined (or TypeError for scope search) 889 */ 890 public static Object __noSuchProperty__(final Object self, final Object name) { 891 final Global global = Global.instance(); 892 final ScriptContext sctxt = global.scontext; 893 final String nameStr = name.toString(); 894 895 if (sctxt != null) { 896 final int scope = sctxt.getAttributesScope(nameStr); 897 if (scope != -1) { 898 return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global); 899 } 900 } 901 902 switch (nameStr) { 903 case "context": 904 return sctxt; 905 case "engine": 906 return global.engine; 907 default: 908 break; 909 } 910 911 if (self == UNDEFINED) { 912 // scope access and so throw ReferenceError 913 throw referenceError(global, "not.defined", nameStr); 914 } 915 916 return UNDEFINED; 917 } 918 919 /** 920 * This is the eval used when 'indirect' eval call is made. 921 * 922 * var global = this; 923 * global.eval("print('hello')"); 924 * 925 * @param self eval scope 926 * @param str eval string 927 * 928 * @return the result of eval 929 */ 930 public static Object eval(final Object self, final Object str) { 931 return directEval(self, str, UNDEFINED, UNDEFINED, false); 932 } 933 934 /** 935 * Direct eval 936 * 937 * @param self The scope of eval passed as 'self' 938 * @param str Evaluated code 939 * @param callThis "this" to be passed to the evaluated code 940 * @param location location of the eval call 941 * @param strict is eval called a strict mode code? 942 * 943 * @return the return value of the eval 944 * 945 * This is directly invoked from generated when eval(code) is called in user code 946 */ 947 public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) { 948 if (!(str instanceof String || str instanceof ConsString)) { 949 return str; 950 } 951 final Global global = Global.instanceFrom(self); 952 final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global; 953 954 return global.getContext().eval(scope, str.toString(), callThis, location, strict, true); 955 } 956 957 /** 958 * Global print implementation - Nashorn extension 959 * 960 * @param self scope 961 * @param objects arguments to print 962 * 963 * @return result of print (undefined) 964 */ 965 public static Object print(final Object self, final Object... objects) { 966 return Global.instanceFrom(self).printImpl(false, objects); 967 } 968 969 /** 970 * Global println implementation - Nashorn extension 971 * 972 * @param self scope 973 * @param objects arguments to print 974 * 975 * @return result of println (undefined) 976 */ 977 public static Object println(final Object self, final Object... objects) { 978 return Global.instanceFrom(self).printImpl(true, objects); 979 } 980 981 /** 982 * Global load implementation - Nashorn extension 983 * 984 * @param self scope 985 * @param source source to load 986 * 987 * @return result of load (undefined) 988 * 989 * @throws IOException if source could not be read 990 */ 991 public static Object load(final Object self, final Object source) throws IOException { 992 final Global global = Global.instanceFrom(self); 993 final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global; 994 return global.getContext().load(scope, source); 995 } 996 997 /** 998 * Global loadWithNewGlobal implementation - Nashorn extension 999 * 1000 * @param self scope 1001 * @param args from plus (optional) arguments to be passed to the loaded script 1002 * 1003 * @return result of load (may be undefined) 1004 * 1005 * @throws IOException if source could not be read 1006 */ 1007 public static Object loadWithNewGlobal(final Object self, final Object...args) throws IOException { 1008 final Global global = Global.instanceFrom(self); 1009 final int length = args.length; 1010 final boolean hasArgs = 0 < length; 1011 final Object from = hasArgs ? args[0] : UNDEFINED; 1012 final Object[] arguments = hasArgs ? Arrays.copyOfRange(args, 1, length) : args; 1013 1014 return global.getContext().loadWithNewGlobal(from, arguments); 1015 } 1016 1017 /** 1018 * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script 1019 * 1020 * @param self self reference 1021 * @param code exit code 1022 * 1023 * @return undefined (will never be reached) 1024 */ 1025 public static Object exit(final Object self, final Object code) { 1026 System.exit(JSType.toInt32(code)); 1027 return UNDEFINED; 1028 } 1029 1030 // builtin prototype accessors 1031 ScriptObject getFunctionPrototype() { 1032 return ScriptFunction.getPrototype(builtinFunction); 1033 } 1034 1035 ScriptObject getObjectPrototype() { 1036 return ScriptFunction.getPrototype(builtinObject); 1037 } 1038 1039 ScriptObject getArrayPrototype() { 1040 return ScriptFunction.getPrototype(builtinArray); 1041 } 1042 1043 ScriptObject getBooleanPrototype() { 1044 return ScriptFunction.getPrototype(builtinBoolean); 1045 } 1046 1047 ScriptObject getNumberPrototype() { 1048 return ScriptFunction.getPrototype(builtinNumber); 1049 } 1050 1051 ScriptObject getDatePrototype() { 1052 return ScriptFunction.getPrototype(builtinDate); 1053 } 1054 1055 ScriptObject getRegExpPrototype() { 1056 return ScriptFunction.getPrototype(builtinRegExp); 1057 } 1058 1059 ScriptObject getStringPrototype() { 1060 return ScriptFunction.getPrototype(builtinString); 1061 } 1062 1063 ScriptObject getErrorPrototype() { 1064 return ScriptFunction.getPrototype(builtinError); 1065 } 1066 1067 ScriptObject getEvalErrorPrototype() { 1068 return ScriptFunction.getPrototype(builtinEvalError); 1069 } 1070 1071 ScriptObject getRangeErrorPrototype() { 1072 return ScriptFunction.getPrototype(builtinRangeError); 1073 } 1074 1075 ScriptObject getReferenceErrorPrototype() { 1076 return ScriptFunction.getPrototype(builtinReferenceError); 1077 } 1078 1079 ScriptObject getSyntaxErrorPrototype() { 1080 return ScriptFunction.getPrototype(builtinSyntaxError); 1081 } 1082 1083 ScriptObject getTypeErrorPrototype() { 1084 return ScriptFunction.getPrototype(builtinTypeError); 1085 } 1086 1087 ScriptObject getURIErrorPrototype() { 1088 return ScriptFunction.getPrototype(builtinURIError); 1089 } 1090 1091 ScriptObject getJavaImporterPrototype() { 1092 return ScriptFunction.getPrototype(builtinJavaImporter); 1093 } 1094 1095 ScriptObject getJSAdapterPrototype() { 1096 return ScriptFunction.getPrototype(builtinJSAdapter); 1097 } 1098 1099 ScriptObject getArrayBufferPrototype() { 1100 return ScriptFunction.getPrototype(builtinArrayBuffer); 1101 } 1102 1103 ScriptObject getDataViewPrototype() { 1104 return ScriptFunction.getPrototype(builtinDataView); 1105 } 1106 1107 ScriptObject getInt8ArrayPrototype() { 1108 return ScriptFunction.getPrototype(builtinInt8Array); 1109 } 1110 1111 ScriptObject getUint8ArrayPrototype() { 1112 return ScriptFunction.getPrototype(builtinUint8Array); 1113 } 1114 1115 ScriptObject getUint8ClampedArrayPrototype() { 1116 return ScriptFunction.getPrototype(builtinUint8ClampedArray); 1117 } 1118 1119 ScriptObject getInt16ArrayPrototype() { 1120 return ScriptFunction.getPrototype(builtinInt16Array); 1121 } 1122 1123 ScriptObject getUint16ArrayPrototype() { 1124 return ScriptFunction.getPrototype(builtinUint16Array); 1125 } 1126 1127 ScriptObject getInt32ArrayPrototype() { 1128 return ScriptFunction.getPrototype(builtinInt32Array); 1129 } 1130 1131 ScriptObject getUint32ArrayPrototype() { 1132 return ScriptFunction.getPrototype(builtinUint32Array); 1133 } 1134 1135 ScriptObject getFloat32ArrayPrototype() { 1136 return ScriptFunction.getPrototype(builtinFloat32Array); 1137 } 1138 1139 ScriptObject getFloat64ArrayPrototype() { 1140 return ScriptFunction.getPrototype(builtinFloat64Array); 1141 } 1142 1143 private ScriptFunction getBuiltinArray() { 1144 return builtinArray; 1145 } 1146 1147 ScriptFunction getTypeErrorThrower() { 1148 return typeErrorThrower; 1149 } 1150 1151 /** 1152 * Called from compiled script code to test if builtin has been overridden 1153 * 1154 * @return true if builtin array has not been overridden 1155 */ 1156 public static boolean isBuiltinArray() { 1157 final Global instance = Global.instance(); 1158 return instance.array == instance.getBuiltinArray(); 1159 } 1160 1161 private ScriptFunction getBuiltinBoolean() { 1162 return builtinBoolean; 1163 } 1164 1165 /** 1166 * Called from compiled script code to test if builtin has been overridden 1167 * 1168 * @return true if builtin boolean has not been overridden 1169 */ 1170 public static boolean isBuiltinBoolean() { 1171 final Global instance = Global.instance(); 1172 return instance._boolean == instance.getBuiltinBoolean(); 1173 } 1174 1175 private ScriptFunction getBuiltinDate() { 1176 return builtinDate; 1177 } 1178 1179 /** 1180 * Called from compiled script code to test if builtin has been overridden 1181 * 1182 * @return true if builtin date has not been overridden 1183 */ 1184 public static boolean isBuiltinDate() { 1185 final Global instance = Global.instance(); 1186 return instance.date == instance.getBuiltinDate(); 1187 } 1188 1189 private ScriptFunction getBuiltinError() { 1190 return builtinError; 1191 } 1192 1193 /** 1194 * Called from compiled script code to test if builtin has been overridden 1195 * 1196 * @return true if builtin error has not been overridden 1197 */ 1198 public static boolean isBuiltinError() { 1199 final Global instance = Global.instance(); 1200 return instance.error == instance.getBuiltinError(); 1201 } 1202 1203 private ScriptFunction getBuiltinEvalError() { 1204 return builtinEvalError; 1205 } 1206 1207 /** 1208 * Called from compiled script code to test if builtin has been overridden 1209 * 1210 * @return true if builtin eval error has not been overridden 1211 */ 1212 public static boolean isBuiltinEvalError() { 1213 final Global instance = Global.instance(); 1214 return instance.evalError == instance.getBuiltinEvalError(); 1215 } 1216 1217 private ScriptFunction getBuiltinFunction() { 1218 return builtinFunction; 1219 } 1220 1221 /** 1222 * Called from compiled script code to test if builtin has been overridden 1223 * 1224 * @return true if builtin function has not been overridden 1225 */ 1226 public static boolean isBuiltinFunction() { 1227 final Global instance = Global.instance(); 1228 return instance.function == instance.getBuiltinFunction(); 1229 } 1230 1231 /** 1232 * Get the switchpoint used to check property changes for Function.prototype.apply 1233 * @return the switchpoint guarding apply (same as guarding call, and everything else in function) 1234 */ 1235 public static SwitchPoint getBuiltinFunctionApplySwitchPoint() { 1236 return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint(); 1237 } 1238 1239 private static boolean isBuiltinFunctionProperty(final String name) { 1240 final Global instance = Global.instance(); 1241 final ScriptFunction builtinFunction = instance.getBuiltinFunction(); 1242 if (builtinFunction == null) { 1243 return false; //conservative for compile-only mode 1244 } 1245 final boolean isBuiltinFunction = instance.function == builtinFunction; 1246 return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin(); 1247 } 1248 1249 /** 1250 * Check if the Function.prototype.apply has not been replaced 1251 * @return true if Function.prototype.apply has been replaced 1252 */ 1253 public static boolean isBuiltinFunctionPrototypeApply() { 1254 return isBuiltinFunctionProperty("apply"); 1255 } 1256 1257 /** 1258 * Check if the Function.prototype.apply has not been replaced 1259 * @return true if Function.prototype.call has been replaced 1260 */ 1261 public static boolean isBuiltinFunctionPrototypeCall() { 1262 return isBuiltinFunctionProperty("call"); 1263 } 1264 1265 private ScriptFunction getBuiltinJSAdapter() { 1266 return builtinJSAdapter; 1267 } 1268 1269 /** 1270 * Called from compiled script code to test if builtin has been overridden 1271 * 1272 * @return true if builtin JSAdapter has not been overridden 1273 */ 1274 public static boolean isBuiltinJSAdapter() { 1275 final Global instance = Global.instance(); 1276 return instance.jsadapter == instance.getBuiltinJSAdapter(); 1277 } 1278 1279 private ScriptObject getBuiltinJSON() { 1280 return builtinJSON; 1281 } 1282 1283 /** 1284 * Called from compiled script code to test if builtin has been overridden 1285 * 1286 * @return true if builtin JSON has has not been overridden 1287 */ 1288 public static boolean isBuiltinJSON() { 1289 final Global instance = Global.instance(); 1290 return instance.json == instance.getBuiltinJSON(); 1291 } 1292 1293 private ScriptObject getBuiltinJava() { 1294 return builtinJava; 1295 } 1296 1297 /** 1298 * Called from compiled script code to test if builtin has been overridden 1299 * 1300 * @return true if builtin Java has not been overridden 1301 */ 1302 public static boolean isBuiltinJava() { 1303 final Global instance = Global.instance(); 1304 return instance.java == instance.getBuiltinJava(); 1305 } 1306 1307 private ScriptObject getBuiltinJavax() { 1308 return builtinJavax; 1309 } 1310 1311 /** 1312 * Called from compiled script code to test if builtin has been overridden 1313 * 1314 * @return true if builtin Javax has not been overridden 1315 */ 1316 public static boolean isBuiltinJavax() { 1317 final Global instance = Global.instance(); 1318 return instance.javax == instance.getBuiltinJavax(); 1319 } 1320 1321 private ScriptObject getBuiltinJavaImporter() { 1322 return builtinJavaImporter; 1323 } 1324 1325 /** 1326 * Called from compiled script code to test if builtin has been overridden 1327 * 1328 * @return true if builtin Java importer has not been overridden 1329 */ 1330 public static boolean isBuiltinJavaImporter() { 1331 final Global instance = Global.instance(); 1332 return instance.javaImporter == instance.getBuiltinJavaImporter(); 1333 } 1334 1335 private ScriptObject getBuiltinMath() { 1336 return builtinMath; 1337 } 1338 1339 /** 1340 * Called from compiled script code to test if builtin has been overridden 1341 * 1342 * @return true if builtin math has not been overridden 1343 */ 1344 public static boolean isBuiltinMath() { 1345 final Global instance = Global.instance(); 1346 return instance.math == instance.getBuiltinMath(); 1347 } 1348 1349 private ScriptFunction getBuiltinNumber() { 1350 return builtinNumber; 1351 } 1352 1353 /** 1354 * Called from compiled script code to test if builtin has been overridden 1355 * 1356 * @return true if builtin number has not been overridden 1357 */ 1358 public static boolean isBuiltinNumber() { 1359 final Global instance = Global.instance(); 1360 return instance.number == instance.getBuiltinNumber(); 1361 } 1362 1363 private ScriptFunction getBuiltinObject() { 1364 return builtinObject; 1365 } 1366 1367 /** 1368 * Called from compiled script code to test if builtin has been overridden 1369 * 1370 * @return true if builtin object has not been overridden 1371 */ 1372 public static boolean isBuiltinObject() { 1373 final Global instance = Global.instance(); 1374 return instance.object == instance.getBuiltinObject(); 1375 } 1376 1377 private ScriptObject getBuiltinPackages() { 1378 return builtinPackages; 1379 } 1380 1381 /** 1382 * Called from compiled script code to test if builtin has been overridden 1383 * 1384 * @return true if builtin package has not been overridden 1385 */ 1386 public static boolean isBuiltinPackages() { 1387 final Global instance = Global.instance(); 1388 return instance.packages == instance.getBuiltinPackages(); 1389 } 1390 1391 private ScriptFunction getBuiltinRangeError() { 1392 return builtinRangeError; 1393 } 1394 1395 /** 1396 * Called from compiled script code to test if builtin has been overridden 1397 * 1398 * @return true if builtin range error has not been overridden 1399 */ 1400 public static boolean isBuiltinRangeError() { 1401 final Global instance = Global.instance(); 1402 return instance.rangeError == instance.getBuiltinRangeError(); 1403 } 1404 1405 private ScriptFunction getBuiltinReferenceError() { 1406 return builtinReferenceError; 1407 } 1408 1409 /** 1410 * Called from compiled script code to test if builtin has been overridden 1411 * 1412 * @return true if builtin reference error has not been overridden 1413 */ 1414 public static boolean isBuiltinReferenceError() { 1415 final Global instance = Global.instance(); 1416 return instance.referenceError == instance.getBuiltinReferenceError(); 1417 } 1418 1419 private ScriptFunction getBuiltinRegExp() { 1420 return builtinRegExp; 1421 } 1422 1423 /** 1424 * Called from compiled script code to test if builtin has been overridden 1425 * 1426 * @return true if builtin regexp has not been overridden 1427 */ 1428 public static boolean isBuiltinRegExp() { 1429 final Global instance = Global.instance(); 1430 return instance.regexp == instance.getBuiltinRegExp(); 1431 } 1432 1433 private ScriptFunction getBuiltinString() { 1434 return builtinString; 1435 } 1436 1437 /** 1438 * Called from compiled script code to test if builtin has been overridden 1439 * 1440 * @return true if builtin Java has not been overridden 1441 */ 1442 public static boolean isBuiltinString() { 1443 final Global instance = Global.instance(); 1444 return instance.string == instance.getBuiltinString(); 1445 } 1446 1447 private ScriptFunction getBuiltinSyntaxError() { 1448 return builtinSyntaxError; 1449 } 1450 1451 /** 1452 * Called from compiled script code to test if builtin has been overridden 1453 * 1454 * @return true if builtin syntax error has not been overridden 1455 */ 1456 public static boolean isBuiltinSyntaxError() { 1457 final Global instance = Global.instance(); 1458 return instance.syntaxError == instance.getBuiltinSyntaxError(); 1459 } 1460 1461 private ScriptFunction getBuiltinTypeError() { 1462 return builtinTypeError; 1463 } 1464 1465 /** 1466 * Called from compiled script code to test if builtin has been overridden 1467 * 1468 * @return true if builtin type error has not been overridden 1469 */ 1470 public static boolean isBuiltinTypeError() { 1471 final Global instance = Global.instance(); 1472 return instance.typeError == instance.getBuiltinTypeError(); 1473 } 1474 1475 private ScriptFunction getBuiltinURIError() { 1476 return builtinURIError; 1477 } 1478 1479 /** 1480 * Called from compiled script code to test if builtin has been overridden 1481 * 1482 * @return true if builtin URI error has not been overridden 1483 */ 1484 public static boolean isBuiltinURIError() { 1485 final Global instance = Global.instance(); 1486 return instance.uriError == instance.getBuiltinURIError(); 1487 } 1488 1489 @Override 1490 public String getClassName() { 1491 return "global"; 1492 } 1493 1494 /** 1495 * Copy function used to clone NativeRegExp objects. 1496 * 1497 * @param regexp a NativeRegExp to clone 1498 * 1499 * @return copy of the given regexp object 1500 */ 1501 public static Object regExpCopy(final Object regexp) { 1502 return new NativeRegExp((NativeRegExp)regexp); 1503 } 1504 1505 /** 1506 * Convert given object to NativeRegExp type. 1507 * 1508 * @param obj object to be converted 1509 * @return NativeRegExp instance 1510 */ 1511 public static NativeRegExp toRegExp(final Object obj) { 1512 if (obj instanceof NativeRegExp) { 1513 return (NativeRegExp)obj; 1514 } 1515 return new NativeRegExp(JSType.toString(obj)); 1516 } 1517 1518 /** 1519 * ECMA 9.9 ToObject implementation 1520 * 1521 * @param obj an item for which to run ToObject 1522 * @return ToObject version of given item 1523 */ 1524 public static Object toObject(final Object obj) { 1525 if (obj == null || obj == UNDEFINED) { 1526 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1527 } 1528 1529 if (obj instanceof ScriptObject) { 1530 return obj; 1531 } 1532 1533 return instance().wrapAsObject(obj); 1534 } 1535 1536 /** 1537 * Allocate a new object array. 1538 * 1539 * @param initial object values. 1540 * @return the new array 1541 */ 1542 public static NativeArray allocate(final Object[] initial) { 1543 ArrayData arrayData = ArrayData.allocate(initial); 1544 1545 for (int index = 0; index < initial.length; index++) { 1546 final Object value = initial[index]; 1547 1548 if (value == ScriptRuntime.EMPTY) { 1549 arrayData = arrayData.delete(index); 1550 } 1551 } 1552 1553 return new NativeArray(arrayData); 1554 } 1555 1556 /** 1557 * Allocate a new number array. 1558 * 1559 * @param initial number values. 1560 * @return the new array 1561 */ 1562 public static NativeArray allocate(final double[] initial) { 1563 return new NativeArray(ArrayData.allocate(initial)); 1564 } 1565 1566 /** 1567 * Allocate a new long array. 1568 * 1569 * @param initial number values. 1570 * @return the new array 1571 */ 1572 public static NativeArray allocate(final long[] initial) { 1573 return new NativeArray(ArrayData.allocate(initial)); 1574 } 1575 1576 /** 1577 * Allocate a new integer array. 1578 * 1579 * @param initial number values. 1580 * @return the new array 1581 */ 1582 public static NativeArray allocate(final int[] initial) { 1583 return new NativeArray(ArrayData.allocate(initial)); 1584 } 1585 1586 /** 1587 * Allocate a new object array for arguments. 1588 * 1589 * @param arguments initial arguments passed. 1590 * @param callee reference to the function that uses arguments object 1591 * @param numParams actual number of declared parameters 1592 * 1593 * @return the new array 1594 */ 1595 public static ScriptObject allocateArguments(final Object[] arguments, final Object callee, final int numParams) { 1596 return NativeArguments.allocate(arguments, (ScriptFunction)callee, numParams); 1597 } 1598 1599 /** 1600 * Called from generated to check if given function is the builtin 'eval'. If 1601 * eval is used in a script, a lot of optimizations and assumptions cannot be done. 1602 * 1603 * @param fn function object that is checked 1604 * @return true if fn is the builtin eval 1605 */ 1606 public static boolean isEval(final Object fn) { 1607 return fn == Global.instance().builtinEval; 1608 } 1609 1610 /** 1611 * Called from generated to replace a location property placeholder with the actual location property value. 1612 * 1613 * @param placeholder the value tested for being a placeholder for a location property 1614 * @param locationProperty the actual value for the location property 1615 * @return locationProperty if placeholder is indeed a placeholder for a location property, the placeholder otherwise 1616 */ 1617 public static Object replaceLocationPropertyPlaceholder(final Object placeholder, final Object locationProperty) { 1618 return isLocationPropertyPlaceholder(placeholder) ? locationProperty : placeholder; 1619 } 1620 1621 /** 1622 * Called from runtime internals to check if the passed value is a location property placeholder. 1623 * @param placeholder the value tested for being a placeholder for a location property 1624 * @return true if the value is a placeholder, false otherwise. 1625 */ 1626 public static boolean isLocationPropertyPlaceholder(final Object placeholder) { 1627 return placeholder == LOCATION_PROPERTY_PLACEHOLDER; 1628 } 1629 1630 /** 1631 * Create a new RegExp object. 1632 * 1633 * @param expression Regular expression. 1634 * @param options Search options. 1635 * 1636 * @return New RegExp object. 1637 */ 1638 public static Object newRegExp(final String expression, final String options) { 1639 if (options == null) { 1640 return new NativeRegExp(expression); 1641 } 1642 return new NativeRegExp(expression, options); 1643 } 1644 1645 /** 1646 * Get the object prototype 1647 * 1648 * @return the object prototype 1649 */ 1650 public static ScriptObject objectPrototype() { 1651 return Global.instance().getObjectPrototype(); 1652 } 1653 1654 /** 1655 * Create a new empty object instance. 1656 * 1657 * @return New empty object. 1658 */ 1659 public static ScriptObject newEmptyInstance() { 1660 return Global.instance().newObject(); 1661 } 1662 1663 /** 1664 * Check if a given object is a ScriptObject, raises an exception if this is 1665 * not the case 1666 * 1667 * @param obj and object to check 1668 * @return the script object 1669 */ 1670 public static ScriptObject checkObject(final Object obj) { 1671 if (!(obj instanceof ScriptObject)) { 1672 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1673 } 1674 return (ScriptObject)obj; 1675 } 1676 1677 /** 1678 * ECMA 9.10 - implementation of CheckObjectCoercible, i.e. raise an exception 1679 * if this object is null or undefined. 1680 * 1681 * @param obj an object to check 1682 */ 1683 public static void checkObjectCoercible(final Object obj) { 1684 if (obj == null || obj == UNDEFINED) { 1685 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 1686 } 1687 } 1688 1689 /** 1690 * Get the current split state. 1691 * 1692 * @return current split state 1693 */ 1694 @Override 1695 public int getSplitState() { 1696 return splitState; 1697 } 1698 1699 /** 1700 * Set the current split state. 1701 * 1702 * @param state current split state 1703 */ 1704 @Override 1705 public void setSplitState(final int state) { 1706 splitState = state; 1707 } 1708 1709 /** 1710 * Return the ES6 global scope for lexically declared bindings. 1711 * @return the ES6 lexical global scope. 1712 */ 1713 public final ScriptObject getLexicalScope() { 1714 assert context.getEnv()._es6; 1715 return lexicalScope; 1716 } 1717 1718 @Override 1719 public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { 1720 PropertyMap ownMap = getMap(); 1721 LexicalScope lexicalScope = null; 1722 PropertyMap lexicalMap = null; 1723 boolean hasLexicalDefinitions = false; 1724 1725 if (context.getEnv()._es6) { 1726 lexicalScope = (LexicalScope) getLexicalScope(); 1727 lexicalMap = lexicalScope.getMap(); 1728 1729 for (final jdk.nashorn.internal.runtime.Property property : properties) { 1730 if (property.isLexicalBinding()) { 1731 hasLexicalDefinitions = true; 1732 } 1733 // ES6 15.1.8 steps 6. and 7. 1734 final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); 1735 if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { 1736 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 1737 } 1738 final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); 1739 if (lexicalProperty != null && !property.isConfigurable()) { 1740 throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); 1741 } 1742 } 1743 } 1744 1745 for (final jdk.nashorn.internal.runtime.Property property : properties) { 1746 if (property.isLexicalBinding()) { 1747 assert lexicalScope != null; 1748 lexicalMap = lexicalScope.addBoundProperty(lexicalMap, source, property); 1749 1750 if (ownMap.findProperty(property.getKey()) != null) { 1751 // If property exists in the global object invalidate any global constant call sites. 1752 invalidateGlobalConstant(property.getKey()); 1753 } 1754 } else { 1755 ownMap = addBoundProperty(ownMap, source, property); 1756 } 1757 } 1758 1759 setMap(ownMap); 1760 1761 if (hasLexicalDefinitions) { 1762 lexicalScope.setMap(lexicalMap); 1763 invalidateLexicalSwitchPoint(); 1764 } 1765 } 1766 1767 @Override 1768 public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 1769 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1770 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 1771 1772 if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { 1773 if (lexicalScope.hasOwnProperty(name)) { 1774 return lexicalScope.findGetMethod(desc, request, operator); 1775 } 1776 } 1777 1778 final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); 1779 1780 // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, 1781 // because those are invalidated per-key in the addBoundProperties method above. 1782 // We therefor check if the invocation does already have a switchpoint and the property is non-inherited, 1783 // assuming this only applies to global constants. If other non-inherited properties will 1784 // start using switchpoints some time in the future we'll have to revisit this. 1785 if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { 1786 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 1787 } 1788 1789 return invocation; 1790 } 1791 1792 @Override 1793 public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 1794 final boolean isScope = NashornCallSiteDescriptor.isScope(desc); 1795 1796 if (lexicalScope != null && isScope) { 1797 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 1798 if (lexicalScope.hasOwnProperty(name)) { 1799 return lexicalScope.findSetMethod(desc, request); 1800 } 1801 } 1802 1803 final GuardedInvocation invocation = super.findSetMethod(desc, request); 1804 1805 if (isScope && context.getEnv()._es6) { 1806 return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); 1807 } 1808 1809 return invocation; 1810 } 1811 1812 private synchronized SwitchPoint getLexicalScopeSwitchPoint() { 1813 SwitchPoint switchPoint = lexicalScopeSwitchPoint; 1814 if (switchPoint == null || switchPoint.hasBeenInvalidated()) { 1815 switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); 1816 } 1817 return switchPoint; 1818 } 1819 1820 private synchronized void invalidateLexicalSwitchPoint() { 1821 if (lexicalScopeSwitchPoint != null) { 1822 context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); 1823 SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); 1824 } 1825 } 1826 1827 1828 @SuppressWarnings("unused") 1829 private static Object lexicalScopeFilter(final Object self) { 1830 if (self instanceof Global) { 1831 return ((Global) self).getLexicalScope(); 1832 } 1833 return self; 1834 } 1835 1836 private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) { 1837 final T func = initConstructor(name, clazz); 1838 tagBuiltinProperties(name, func); 1839 return func; 1840 } 1841 1842 private void init(final ScriptEngine eng) { 1843 assert Context.getGlobal() == this : "this global is not set as current"; 1844 1845 final ScriptEnvironment env = getContext().getEnv(); 1846 1847 // initialize Function and Object constructor 1848 initFunctionAndObject(); 1849 1850 // Now fix Global's own proto. 1851 this.setInitialProto(getObjectPrototype()); 1852 1853 // initialize global function properties 1854 this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL); 1855 1856 this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT, 1857 new Specialization[] { 1858 new Specialization(GlobalFunctions.PARSEINT_Z), 1859 new Specialization(GlobalFunctions.PARSEINT_I), 1860 new Specialization(GlobalFunctions.PARSEINT_J), 1861 new Specialization(GlobalFunctions.PARSEINT_OI), 1862 new Specialization(GlobalFunctions.PARSEINT_O) }); 1863 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1864 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN, 1865 new Specialization[] { 1866 new Specialization(GlobalFunctions.IS_NAN_I), 1867 new Specialization(GlobalFunctions.IS_NAN_J), 1868 new Specialization(GlobalFunctions.IS_NAN_D) }); 1869 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1870 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN); 1871 this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE); 1872 this.encodeURI = ScriptFunctionImpl.makeFunction("encodeURI", GlobalFunctions.ENCODE_URI); 1873 this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); 1874 this.decodeURI = ScriptFunctionImpl.makeFunction("decodeURI", GlobalFunctions.DECODE_URI); 1875 this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); 1876 this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE); 1877 this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); 1878 this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); 1879 this.load = ScriptFunctionImpl.makeFunction("load", LOAD); 1880 this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); 1881 this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); 1882 this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); 1883 1884 // built-in constructors 1885 this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); 1886 this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); 1887 this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); 1888 this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); 1889 this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); 1890 this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); 1891 this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); 1892 this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); 1893 this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); 1894 1895 // initialize String.prototype.length to 0 1896 // add String.prototype.length 1897 final ScriptObject stringPrototype = getStringPrototype(); 1898 stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); 1899 1900 // set isArray flag on Array.prototype 1901 final ScriptObject arrayPrototype = getArrayPrototype(); 1902 arrayPrototype.setIsArray(); 1903 1904 this.DEFAULT_DATE = new NativeDate(Double.NaN, this); 1905 1906 // initialize default regexp object 1907 this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this); 1908 1909 // RegExp.prototype should behave like a RegExp object. So copy the 1910 // properties. 1911 final ScriptObject regExpProto = getRegExpPrototype(); 1912 regExpProto.addBoundProperties(DEFAULT_REGEXP); 1913 1914 // Error stuff 1915 initErrorObjects(); 1916 1917 // java access 1918 if (! env._no_java) { 1919 initJavaAccess(); 1920 } 1921 1922 if (! env._no_typed_arrays) { 1923 initTypedArray(); 1924 } 1925 1926 if (env._scripting) { 1927 initScripting(env); 1928 } 1929 1930 if (Context.DEBUG) { 1931 boolean debugOkay; 1932 final SecurityManager sm = System.getSecurityManager(); 1933 if (sm != null) { 1934 try { 1935 sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); 1936 debugOkay = true; 1937 } catch (final SecurityException ignored) { 1938 // if no permission, don't initialize Debug object 1939 debugOkay = false; 1940 } 1941 1942 } else { 1943 debugOkay = true; 1944 } 1945 1946 if (debugOkay) { 1947 initDebug(); 1948 } 1949 } 1950 1951 copyBuiltins(); 1952 1953 // expose script (command line) arguments as "arguments" property of global 1954 arguments = wrapAsObject(env.getArguments().toArray()); 1955 if (env._scripting) { 1956 // synonym for "arguments" in scripting mode 1957 addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); 1958 } 1959 1960 if (eng != null) { 1961 // default file name 1962 addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); 1963 // __noSuchProperty__ hook for ScriptContext search of missing variables 1964 final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); 1965 addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); 1966 } 1967 } 1968 1969 private void initErrorObjects() { 1970 // Error objects 1971 this.builtinError = initConstructor("Error", ScriptFunction.class); 1972 final ScriptObject errorProto = getErrorPrototype(); 1973 1974 // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName 1975 final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK); 1976 final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK); 1977 errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); 1978 final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER); 1979 final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER); 1980 errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); 1981 final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER); 1982 final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER); 1983 errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); 1984 final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME); 1985 final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("setFileName", NativeError.SET_FILENAME); 1986 errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); 1987 1988 // ECMA 15.11.4.2 Error.prototype.name 1989 // Error.prototype.name = "Error"; 1990 errorProto.set(NativeError.NAME, "Error", 0); 1991 // ECMA 15.11.4.3 Error.prototype.message 1992 // Error.prototype.message = ""; 1993 errorProto.set(NativeError.MESSAGE, "", 0); 1994 1995 tagBuiltinProperties("Error", builtinError); 1996 1997 this.builtinEvalError = initErrorSubtype("EvalError", errorProto); 1998 this.builtinRangeError = initErrorSubtype("RangeError", errorProto); 1999 this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); 2000 this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); 2001 this.builtinTypeError = initErrorSubtype("TypeError", errorProto); 2002 this.builtinURIError = initErrorSubtype("URIError", errorProto); 2003 } 2004 2005 private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { 2006 final ScriptFunction cons = initConstructor(name, ScriptFunction.class); 2007 final ScriptObject prototype = ScriptFunction.getPrototype(cons); 2008 prototype.set(NativeError.NAME, name, 0); 2009 prototype.set(NativeError.MESSAGE, "", 0); 2010 prototype.setInitialProto(errorProto); 2011 tagBuiltinProperties(name, cons); 2012 return cons; 2013 } 2014 2015 private void initJavaAccess() { 2016 final ScriptObject objectProto = getObjectPrototype(); 2017 this.builtinPackages = new NativeJavaPackage("", objectProto); 2018 this.builtinCom = new NativeJavaPackage("com", objectProto); 2019 this.builtinEdu = new NativeJavaPackage("edu", objectProto); 2020 this.builtinJava = new NativeJavaPackage("java", objectProto); 2021 this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); 2022 this.builtinJavax = new NativeJavaPackage("javax", objectProto); 2023 this.builtinOrg = new NativeJavaPackage("org", objectProto); 2024 this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); 2025 this.builtinJavaApi = initConstructor("Java", ScriptObject.class); 2026 } 2027 2028 private void initScripting(final ScriptEnvironment scriptEnv) { 2029 Object value; 2030 value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE); 2031 addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); 2032 2033 value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); 2034 addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); 2035 2036 final String execName = ScriptingFunctions.EXEC_NAME; 2037 value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); 2038 addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); 2039 2040 // Nashorn extension: global.echo (scripting-mode-only) 2041 // alias for "print" 2042 value = get("print"); 2043 addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); 2044 2045 // Nashorn extension: global.$OPTIONS (scripting-mode-only) 2046 final ScriptObject options = newObject(); 2047 copyOptions(options, scriptEnv); 2048 addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); 2049 2050 // Nashorn extension: global.$ENV (scripting-mode-only) 2051 if (System.getSecurityManager() == null) { 2052 // do not fill $ENV if we have a security manager around 2053 // Retrieve current state of ENV variables. 2054 final ScriptObject env = newObject(); 2055 env.putAll(System.getenv(), scriptEnv._strict); 2056 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); 2057 } else { 2058 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2059 } 2060 2061 // add other special properties for exec support 2062 addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2063 addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2064 addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2065 } 2066 2067 private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { 2068 for (final Field f : scriptEnv.getClass().getFields()) { 2069 try { 2070 options.set(f.getName(), f.get(scriptEnv), 0); 2071 } catch (final IllegalArgumentException | IllegalAccessException exp) { 2072 throw new RuntimeException(exp); 2073 } 2074 } 2075 } 2076 2077 private void initTypedArray() { 2078 this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); 2079 this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); 2080 this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); 2081 this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); 2082 this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); 2083 this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); 2084 this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); 2085 this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); 2086 this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); 2087 this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); 2088 this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); 2089 2090 } 2091 2092 private void copyBuiltins() { 2093 this.array = this.builtinArray; 2094 this._boolean = this.builtinBoolean; 2095 this.date = this.builtinDate; 2096 this.error = this.builtinError; 2097 this.evalError = this.builtinEvalError; 2098 this.function = this.builtinFunction; 2099 this.jsadapter = this.builtinJSAdapter; 2100 this.json = this.builtinJSON; 2101 this.com = this.builtinCom; 2102 this.edu = this.builtinEdu; 2103 this.java = this.builtinJava; 2104 this.javafx = this.builtinJavafx; 2105 this.javax = this.builtinJavax; 2106 this.org = this.builtinOrg; 2107 this.javaImporter = this.builtinJavaImporter; 2108 this.javaApi = this.builtinJavaApi; 2109 this.math = this.builtinMath; 2110 this.number = this.builtinNumber; 2111 this.object = this.builtinObject; 2112 this.packages = this.builtinPackages; 2113 this.rangeError = this.builtinRangeError; 2114 this.referenceError = this.builtinReferenceError; 2115 this.regexp = this.builtinRegExp; 2116 this.string = this.builtinString; 2117 this.syntaxError = this.builtinSyntaxError; 2118 this.typeError = this.builtinTypeError; 2119 this.uriError = this.builtinURIError; 2120 this.arrayBuffer = this.builtinArrayBuffer; 2121 this.dataView = this.builtinDataView; 2122 this.int8Array = this.builtinInt8Array; 2123 this.uint8Array = this.builtinUint8Array; 2124 this.uint8ClampedArray = this.builtinUint8ClampedArray; 2125 this.int16Array = this.builtinInt16Array; 2126 this.uint16Array = this.builtinUint16Array; 2127 this.int32Array = this.builtinInt32Array; 2128 this.uint32Array = this.builtinUint32Array; 2129 this.float32Array = this.builtinFloat32Array; 2130 this.float64Array = this.builtinFloat64Array; 2131 } 2132 2133 private void initDebug() { 2134 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); 2135 } 2136 2137 private Object printImpl(final boolean newLine, final Object... objects) { 2138 @SuppressWarnings("resource") 2139 final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut(); 2140 final StringBuilder sb = new StringBuilder(); 2141 2142 for (final Object obj : objects) { 2143 if (sb.length() != 0) { 2144 sb.append(' '); 2145 } 2146 2147 sb.append(JSType.toString(obj)); 2148 } 2149 2150 // Print all at once to ensure thread friendly result. 2151 if (newLine) { 2152 out.println(sb.toString()); 2153 } else { 2154 out.print(sb.toString()); 2155 } 2156 2157 out.flush(); 2158 2159 return UNDEFINED; 2160 } 2161 2162 private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) { 2163 try { 2164 // Assuming class name pattern for built-in JS constructors. 2165 final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); 2166 2167 sb.append("Native"); 2168 sb.append(name); 2169 sb.append("$Constructor"); 2170 2171 final Class<?> funcClass = Class.forName(sb.toString()); 2172 final T res = clazz.cast(funcClass.newInstance()); 2173 2174 if (res instanceof ScriptFunction) { 2175 // All global constructor prototypes are not-writable, 2176 // not-enumerable and not-configurable. 2177 final ScriptFunction func = (ScriptFunction)res; 2178 func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); 2179 } 2180 2181 if (res.getProto() == null) { 2182 res.setInitialProto(getObjectPrototype()); 2183 } 2184 2185 res.setIsBuiltin(); 2186 2187 return res; 2188 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { 2189 throw new RuntimeException(e); 2190 } 2191 } 2192 2193 private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) { 2194 final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>(); 2195 2196 list.addAll(Arrays.asList(func.getMap().getProperties())); 2197 2198 if (func instanceof ScriptFunction) { 2199 final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); 2200 if (proto != null) { 2201 list.addAll(Arrays.asList(proto.getMap().getProperties())); 2202 } 2203 } 2204 2205 final jdk.nashorn.internal.runtime.Property prop = getProperty(name); 2206 if (prop != null) { 2207 list.add(prop); 2208 } 2209 2210 return list; 2211 } 2212 2213 /** 2214 * Given a builtin object, traverse its properties recursively and associate them with a name that 2215 * will be a key to their invalidation switchpoint. 2216 * @param name name for key 2217 * @param func builtin script object 2218 */ 2219 private void tagBuiltinProperties(final String name, final ScriptObject func) { 2220 SwitchPoint sp = context.getBuiltinSwitchPoint(name); 2221 if (sp == null) { 2222 sp = context.newBuiltinSwitchPoint(name); 2223 } 2224 2225 //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, 2226 //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc 2227 for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { 2228 prop.setBuiltinSwitchPoint(sp); 2229 } 2230 } 2231 2232 // Function and Object constructors are inter-dependent. Also, 2233 // Function.prototype 2234 // functions are not properly initialized. We fix the references here. 2235 // NOTE: be careful if you want to re-order the operations here. You may 2236 // have 2237 // to play with object references carefully!! 2238 private void initFunctionAndObject() { 2239 // First-n-foremost is Function 2240 2241 this.builtinFunction = initConstructor("Function", ScriptFunction.class); 2242 2243 // create global anonymous function 2244 final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(); 2245 // need to copy over members of Function.prototype to anon function 2246 anon.addBoundProperties(getFunctionPrototype()); 2247 2248 // Function.prototype === Object.getPrototypeOf(Function) === 2249 // <anon-function> 2250 builtinFunction.setInitialProto(anon); 2251 builtinFunction.setPrototype(anon); 2252 anon.set("constructor", builtinFunction, 0); 2253 anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); 2254 2255 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 2256 this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0); 2257 typeErrorThrower.setPrototype(UNDEFINED); 2258 // Non-constructor built-in functions do not have "prototype" property 2259 typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype")); 2260 typeErrorThrower.preventExtensions(); 2261 2262 // now initialize Object 2263 this.builtinObject = initConstructor("Object", ScriptFunction.class); 2264 final ScriptObject ObjectPrototype = getObjectPrototype(); 2265 // Object.getPrototypeOf(Function.prototype) === Object.prototype 2266 anon.setInitialProto(ObjectPrototype); 2267 2268 // ES6 draft compliant __proto__ property of Object.prototype 2269 // accessors on Object.prototype for "__proto__" 2270 final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__); 2271 final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__); 2272 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 2273 2274 // Function valued properties of Function.prototype were not properly 2275 // initialized. Because, these were created before global.function and 2276 // global.object were not initialized. 2277 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); 2278 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2279 final Object key = property.getKey(); 2280 final Object value = builtinFunction.get(key); 2281 2282 if (value instanceof ScriptFunction && value != anon) { 2283 final ScriptFunction func = (ScriptFunction)value; 2284 func.setInitialProto(getFunctionPrototype()); 2285 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2286 if (prototype != null) { 2287 prototype.setInitialProto(ObjectPrototype); 2288 } 2289 } 2290 } 2291 2292 // For function valued properties of Object and Object.prototype, make 2293 // sure prototype's proto chain ends with Object.prototype 2294 for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { 2295 final Object key = property.getKey(); 2296 final Object value = builtinObject.get(key); 2297 2298 if (value instanceof ScriptFunction) { 2299 final ScriptFunction func = (ScriptFunction)value; 2300 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2301 if (prototype != null) { 2302 prototype.setInitialProto(ObjectPrototype); 2303 } 2304 } 2305 } 2306 2307 properties = getObjectPrototype().getMap().getProperties(); 2308 2309 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2310 final Object key = property.getKey(); 2311 if (key.equals("constructor")) { 2312 continue; 2313 } 2314 2315 final Object value = ObjectPrototype.get(key); 2316 if (value instanceof ScriptFunction) { 2317 final ScriptFunction func = (ScriptFunction)value; 2318 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2319 if (prototype != null) { 2320 prototype.setInitialProto(ObjectPrototype); 2321 } 2322 } 2323 } 2324 2325 tagBuiltinProperties("Object", builtinObject); 2326 tagBuiltinProperties("Function", builtinFunction); 2327 tagBuiltinProperties("Function", anon); 2328 } 2329 2330 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 2331 return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); 2332 } 2333 2334 RegExpResult getLastRegExpResult() { 2335 return lastRegExpResult; 2336 } 2337 2338 void setLastRegExpResult(final RegExpResult regExpResult) { 2339 this.lastRegExpResult = regExpResult; 2340 } 2341 2342 @Override 2343 protected boolean isGlobal() { 2344 return true; 2345 } 2346 2347 /** 2348 * A class representing the ES6 global lexical scope. 2349 */ 2350 private static class LexicalScope extends ScriptObject { 2351 2352 LexicalScope(final ScriptObject proto) { 2353 super(proto, PropertyMap.newMap()); 2354 } 2355 2356 @Override 2357 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 2358 return filterInvocation(super.findGetMethod(desc, request, operator)); 2359 } 2360 2361 @Override 2362 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2363 return filterInvocation(super.findSetMethod(desc, request)); 2364 } 2365 2366 @Override 2367 protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) { 2368 // We override this method just to make it callable by Global 2369 return super.addBoundProperty(propMap, source, property); 2370 } 2371 2372 private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { 2373 final MethodType type = invocation.getInvocation().type(); 2374 return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); 2375 } 2376 } 2377 2378 }