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