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 import jdk.nashorn.tools.ShellFunctions; 81 82 /** 83 * Representation of global scope. 84 */ 85 @ScriptClass("Global") 86 public final class Global extends ScriptObject implements Scope { 87 // Placeholder value used in place of a location property (__FILE__, __DIR__, __LINE__) 88 private static final Object LOCATION_PROPERTY_PLACEHOLDER = new Object(); 89 private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); 90 private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); 91 92 /** 93 * Optimistic builtin names that require switchpoint invalidation 94 * upon assignment. Overly conservative, but works for now, to avoid 95 * any complicated scope checks and especially heavy weight guards 96 * like 97 * 98 * <pre> 99 * public boolean setterGuard(final Object receiver) { 100 * final Global global = Global.instance(); 101 * final ScriptObject sobj = global.getFunctionPrototype(); 102 * final Object apply = sobj.get("apply"); 103 * return apply == receiver; 104 * } 105 * </pre> 106 * 107 * Naturally, checking for builtin classes like NativeFunction is cheaper, 108 * it's when you start adding property checks for said builtins you have 109 * problems with guard speed. 110 */ 111 112 /** Nashorn extension: arguments array */ 113 @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) 114 public Object arguments; 115 116 /** ECMA 15.1.2.2 parseInt (string , radix) */ 117 @Property(attributes = Attribute.NOT_ENUMERABLE) 118 public Object parseInt; 119 120 /** ECMA 15.1.2.3 parseFloat (string) */ 121 @Property(attributes = Attribute.NOT_ENUMERABLE) 122 public Object parseFloat; 123 124 /** ECMA 15.1.2.4 isNaN (number) */ 125 @Property(attributes = Attribute.NOT_ENUMERABLE) 126 public Object isNaN; 127 128 /** ECMA 15.1.2.5 isFinite (number) */ 129 @Property(attributes = Attribute.NOT_ENUMERABLE) 130 public Object isFinite; 131 132 /** ECMA 15.1.3.3 encodeURI */ 133 @Property(attributes = Attribute.NOT_ENUMERABLE) 134 public Object encodeURI; 135 136 /** ECMA 15.1.3.4 encodeURIComponent */ 137 @Property(attributes = Attribute.NOT_ENUMERABLE) 138 public Object encodeURIComponent; 139 140 /** ECMA 15.1.3.1 decodeURI */ 141 @Property(attributes = Attribute.NOT_ENUMERABLE) 142 public Object decodeURI; 143 144 /** ECMA 15.1.3.2 decodeURIComponent */ 145 @Property(attributes = Attribute.NOT_ENUMERABLE) 146 public Object decodeURIComponent; 147 148 /** ECMA B.2.1 escape (string) */ 149 @Property(attributes = Attribute.NOT_ENUMERABLE) 150 public Object escape; 151 152 /** ECMA B.2.2 unescape (string) */ 153 @Property(attributes = Attribute.NOT_ENUMERABLE) 154 public Object unescape; 155 156 /** Nashorn extension: global.print */ 157 @Property(attributes = Attribute.NOT_ENUMERABLE) 158 public Object print; 159 160 /** Nashorn extension: global.load */ 161 @Property(attributes = Attribute.NOT_ENUMERABLE) 162 public Object load; 163 164 /** Nashorn extension: global.loadWithNewGlobal */ 165 @Property(attributes = Attribute.NOT_ENUMERABLE) 166 public Object loadWithNewGlobal; 167 168 /** Nashorn extension: global.exit */ 169 @Property(attributes = Attribute.NOT_ENUMERABLE) 170 public Object exit; 171 172 /** Nashorn extension: global.quit */ 173 @Property(attributes = Attribute.NOT_ENUMERABLE) 174 public Object quit; 175 176 /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */ 177 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 178 public final double NaN = Double.NaN; 179 180 /** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */ 181 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 182 public final double Infinity = Double.POSITIVE_INFINITY; 183 184 /** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */ 185 @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) 186 public final Object undefined = UNDEFINED; 187 188 /** ECMA 15.1.2.1 eval(x) */ 189 @Property(attributes = Attribute.NOT_ENUMERABLE) 190 public Object eval; 191 192 /** ECMA 15.1.4.1 Object constructor. */ 193 @Property(name = "Object", attributes = Attribute.NOT_ENUMERABLE) 194 public volatile Object object; 195 196 /** ECMA 15.1.4.2 Function constructor. */ 197 @Property(name = "Function", attributes = Attribute.NOT_ENUMERABLE) 198 public volatile Object function; 199 200 /** ECMA 15.1.4.3 Array constructor. */ 201 @Property(name = "Array", attributes = Attribute.NOT_ENUMERABLE) 202 public volatile Object array; 203 204 /** ECMA 15.1.4.4 String constructor */ 205 @Property(name = "String", attributes = Attribute.NOT_ENUMERABLE) 206 public volatile Object string; 207 208 /** ECMA 15.1.4.5 Boolean constructor */ 209 @Property(name = "Boolean", attributes = Attribute.NOT_ENUMERABLE) 210 public volatile Object _boolean; 211 212 /** ECMA 15.1.4.6 - Number constructor */ 213 @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE) 214 public volatile Object number; 215 216 /** ECMA 15.1.4.7 Date constructor */ 217 @Property(name = "Date", attributes = Attribute.NOT_ENUMERABLE) 218 public volatile Object date; 219 220 /** ECMA 15.1.4.8 RegExp constructor */ 221 @Property(name = "RegExp", attributes = Attribute.NOT_ENUMERABLE) 222 public volatile Object regexp; 223 224 /** ECMA 15.12 - The JSON object */ 225 @Property(name = "JSON", attributes = Attribute.NOT_ENUMERABLE) 226 public volatile Object json; 227 228 /** Nashorn extension: global.JSAdapter */ 229 @Property(name = "JSAdapter", attributes = Attribute.NOT_ENUMERABLE) 230 public volatile Object jsadapter; 231 232 /** ECMA 15.8 - The Math object */ 233 @Property(name = "Math", attributes = Attribute.NOT_ENUMERABLE) 234 public volatile Object math; 235 236 /** Error object */ 237 @Property(name = "Error", attributes = Attribute.NOT_ENUMERABLE) 238 public volatile Object error; 239 240 /** EvalError object */ 241 @Property(name = "EvalError", attributes = Attribute.NOT_ENUMERABLE) 242 public volatile Object evalError; 243 244 /** RangeError object */ 245 @Property(name = "RangeError", attributes = Attribute.NOT_ENUMERABLE) 246 public volatile Object rangeError; 247 248 /** ReferenceError object */ 249 @Property(name = "ReferenceError", attributes = Attribute.NOT_ENUMERABLE) 250 public volatile Object referenceError; 251 252 /** SyntaxError object */ 253 @Property(name = "SyntaxError", attributes = Attribute.NOT_ENUMERABLE) 254 public volatile Object syntaxError; 255 256 /** TypeError object */ 257 @Property(name = "TypeError", attributes = Attribute.NOT_ENUMERABLE) 258 public volatile Object typeError; 259 260 /** URIError object */ 261 @Property(name = "URIError", attributes = Attribute.NOT_ENUMERABLE) 262 public volatile Object uriError; 263 264 /** ArrayBuffer object */ 265 @Property(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE) 266 public volatile Object arrayBuffer; 267 268 /** DataView object */ 269 @Property(name = "DataView", attributes = Attribute.NOT_ENUMERABLE) 270 public volatile Object dataView; 271 272 /** TypedArray (int8) */ 273 @Property(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE) 274 public volatile Object int8Array; 275 276 /** TypedArray (uint8) */ 277 @Property(name = "Uint8Array", attributes = Attribute.NOT_ENUMERABLE) 278 public volatile Object uint8Array; 279 280 /** TypedArray (uint8) - Clamped */ 281 @Property(name = "Uint8ClampedArray", attributes = Attribute.NOT_ENUMERABLE) 282 public volatile Object uint8ClampedArray; 283 284 /** TypedArray (int16) */ 285 @Property(name = "Int16Array", attributes = Attribute.NOT_ENUMERABLE) 286 public volatile Object int16Array; 287 288 /** TypedArray (uint16) */ 289 @Property(name = "Uint16Array", attributes = Attribute.NOT_ENUMERABLE) 290 public volatile Object uint16Array; 291 292 /** TypedArray (int32) */ 293 @Property(name = "Int32Array", attributes = Attribute.NOT_ENUMERABLE) 294 public volatile Object int32Array; 295 296 /** TypedArray (uint32) */ 297 @Property(name = "Uint32Array", attributes = Attribute.NOT_ENUMERABLE) 298 public volatile Object uint32Array; 299 300 /** TypedArray (float32) */ 301 @Property(name = "Float32Array", attributes = Attribute.NOT_ENUMERABLE) 302 public volatile Object float32Array; 303 304 /** TypedArray (float64) */ 305 @Property(name = "Float64Array", attributes = Attribute.NOT_ENUMERABLE) 306 public volatile Object float64Array; 307 308 /** Nashorn extension: Java access - global.Packages */ 309 @Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE) 310 public volatile Object packages; 311 312 /** Nashorn extension: Java access - global.com */ 313 @Property(attributes = Attribute.NOT_ENUMERABLE) 314 public volatile Object com; 315 316 /** Nashorn extension: Java access - global.edu */ 317 @Property(attributes = Attribute.NOT_ENUMERABLE) 318 public volatile Object edu; 319 320 /** Nashorn extension: Java access - global.java */ 321 @Property(attributes = Attribute.NOT_ENUMERABLE) 322 public volatile Object java; 323 324 /** Nashorn extension: Java access - global.javafx */ 325 @Property(attributes = Attribute.NOT_ENUMERABLE) 326 public volatile Object javafx; 327 328 /** Nashorn extension: Java access - global.javax */ 329 @Property(attributes = Attribute.NOT_ENUMERABLE) 330 public volatile Object javax; 331 332 /** Nashorn extension: Java access - global.org */ 333 @Property(attributes = Attribute.NOT_ENUMERABLE) 334 public volatile Object org; 335 336 /** Nashorn extension: Java access - global.javaImporter */ 337 @Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE) 338 public volatile Object javaImporter; 339 340 /** Nashorn extension: global.Java Object constructor. */ 341 @Property(name = "Java", attributes = Attribute.NOT_ENUMERABLE) 342 public volatile Object javaApi; 343 344 /** Nashorn extension: current script's file name */ 345 @Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 346 public final Object __FILE__ = LOCATION_PROPERTY_PLACEHOLDER; 347 348 /** Nashorn extension: current script's directory */ 349 @Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 350 public final Object __DIR__ = LOCATION_PROPERTY_PLACEHOLDER; 351 352 /** Nashorn extension: current source line number being executed */ 353 @Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT) 354 public final Object __LINE__ = LOCATION_PROPERTY_PLACEHOLDER; 355 356 /** Used as Date.prototype's default value */ 357 public NativeDate DEFAULT_DATE; 358 359 /** Used as RegExp.prototype's default value */ 360 public NativeRegExp DEFAULT_REGEXP; 361 362 /* 363 * Built-in constructor objects: Even if user changes dynamic values of 364 * "Object", "Array" etc., we still want to keep original values of these 365 * constructors here. For example, we need to be able to create array, 366 * regexp literals even after user overwrites global "Array" or "RegExp" 367 * constructor - see also ECMA 262 spec. Annex D. 368 */ 369 private ScriptFunction builtinFunction; 370 private ScriptFunction builtinObject; 371 private ScriptFunction builtinArray; 372 private ScriptFunction builtinBoolean; 373 private ScriptFunction builtinDate; 374 private ScriptObject builtinJSON; 375 private ScriptFunction builtinJSAdapter; 376 private ScriptObject builtinMath; 377 private ScriptFunction builtinNumber; 378 private ScriptFunction builtinRegExp; 379 private ScriptFunction builtinString; 380 private ScriptFunction builtinError; 381 private ScriptFunction builtinEval; 382 private ScriptFunction builtinEvalError; 383 private ScriptFunction builtinRangeError; 384 private ScriptFunction builtinReferenceError; 385 private ScriptFunction builtinSyntaxError; 386 private ScriptFunction builtinTypeError; 387 private ScriptFunction builtinURIError; 388 private ScriptObject builtinPackages; 389 private ScriptObject builtinCom; 390 private ScriptObject builtinEdu; 391 private ScriptObject builtinJava; 392 private ScriptObject builtinJavafx; 393 private ScriptObject builtinJavax; 394 private ScriptObject builtinOrg; 395 private ScriptFunction builtinJavaImporter; 396 private ScriptObject builtinJavaApi; 397 private ScriptFunction builtinArrayBuffer; 398 private ScriptFunction builtinDataView; 399 private ScriptFunction builtinInt8Array; 400 private ScriptFunction builtinUint8Array; 401 private ScriptFunction builtinUint8ClampedArray; 402 private ScriptFunction builtinInt16Array; 403 private ScriptFunction builtinUint16Array; 404 private ScriptFunction builtinInt32Array; 405 private ScriptFunction builtinUint32Array; 406 private ScriptFunction builtinFloat32Array; 407 private ScriptFunction builtinFloat64Array; 408 409 /* 410 * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object 411 */ 412 private ScriptFunction typeErrorThrower; 413 414 // Flag to indicate that a split method issued a return statement 415 private int splitState = -1; 416 417 // Used to store the last RegExp result to support deprecated RegExp constructor properties 418 private RegExpResult lastRegExpResult; 419 420 private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); 421 private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); 422 private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); 423 private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); 424 private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); 425 private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); 426 private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); 427 private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); 428 429 // initialized by nasgen 430 private static PropertyMap $nasgenmap$; 431 432 // context to which this global belongs to 433 private final Context context; 434 435 // current ScriptContext to use - can be null. 436 private ScriptContext scontext; 437 // current ScriptEngine associated - can be null. 438 private ScriptEngine engine; 439 440 // ES6 global lexical scope. 441 private final LexicalScope lexicalScope; 442 443 // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. 444 private SwitchPoint lexicalScopeSwitchPoint; 445 446 /** 447 * Set the current script context 448 * @param scontext script context 449 */ 450 public void setScriptContext(final ScriptContext scontext) { 451 this.scontext = scontext; 452 } 453 454 @Override 455 protected Context getContext() { 456 return context; 457 } 458 459 // performs initialization checks for Global constructor and returns the 460 // PropertyMap, if everything is fine. 461 private static PropertyMap checkAndGetMap(final Context context) { 462 // security check first 463 final SecurityManager sm = System.getSecurityManager(); 464 if (sm != null) { 465 sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); 466 } 467 468 Objects.requireNonNull(context); 469 470 return $nasgenmap$; 471 } 472 473 /** 474 * Constructor 475 * 476 * @param context the context 477 */ 478 public Global(final Context context) { 479 super(checkAndGetMap(context)); 480 this.context = context; 481 this.setIsScope(); 482 this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; 483 } 484 485 /** 486 * Script access to "current" Global instance 487 * 488 * @return the global singleton 489 */ 490 public static Global instance() { 491 final Global global = Context.getGlobal(); 492 Objects.requireNonNull(global); 493 return global; 494 } 495 496 private static Global instanceFrom(final Object self) { 497 return self instanceof Global? (Global)self : instance(); 498 } 499 500 /** 501 * Check if we have a Global instance 502 * @return true if one exists 503 */ 504 public static boolean hasInstance() { 505 return Context.getGlobal() != null; 506 } 507 508 /** 509 * Script access to {@link ScriptEnvironment} 510 * 511 * @return the script environment 512 */ 513 static ScriptEnvironment getEnv() { 514 return instance().getContext().getEnv(); 515 } 516 517 /** 518 * Script access to {@link Context} 519 * 520 * @return the context 521 */ 522 static Context getThisContext() { 523 return instance().getContext(); 524 } 525 526 // Runtime interface to Global 527 528 /** 529 * Is there a class filter in the current Context? 530 * @return class filter 531 */ 532 public ClassFilter getClassFilter() { 533 return context.getClassFilter(); 534 } 535 536 /** 537 * Is this global of the given Context? 538 * @param ctxt the context 539 * @return true if this global belongs to the given Context 540 */ 541 public boolean isOfContext(final Context ctxt) { 542 return this.context == ctxt; 543 } 544 545 /** 546 * Does this global belong to a strict Context? 547 * @return true if this global belongs to a strict Context 548 */ 549 public boolean isStrictContext() { 550 return context.getEnv()._strict; 551 } 552 553 /** 554 * Initialize standard builtin objects like "Object", "Array", "Function" etc. 555 * as well as our extension builtin objects like "Java", "JSAdapter" as properties 556 * of the global scope object. 557 * 558 * @param eng ScriptEngine to initialize 559 */ 560 public void initBuiltinObjects(final ScriptEngine eng) { 561 if (this.builtinObject != null) { 562 // already initialized, just return 563 return; 564 } 565 566 this.engine = eng; 567 init(eng); 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 /** 1821 * Adds jjs shell interactive mode builtin functions to global scope. 1822 */ 1823 public void addShellBuiltins() { 1824 Object value = ScriptFunctionImpl.makeFunction("input", ShellFunctions.INPUT); 1825 addOwnProperty("input", Attribute.NOT_ENUMERABLE, value); 1826 1827 value = ScriptFunctionImpl.makeFunction("evalinput", ShellFunctions.EVALINPUT); 1828 addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value); 1829 } 1830 1831 private synchronized SwitchPoint getLexicalScopeSwitchPoint() { 1832 SwitchPoint switchPoint = lexicalScopeSwitchPoint; 1833 if (switchPoint == null || switchPoint.hasBeenInvalidated()) { 1834 switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); 1835 } 1836 return switchPoint; 1837 } 1838 1839 private synchronized void invalidateLexicalSwitchPoint() { 1840 if (lexicalScopeSwitchPoint != null) { 1841 context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); 1842 SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); 1843 } 1844 } 1845 1846 1847 @SuppressWarnings("unused") 1848 private static Object lexicalScopeFilter(final Object self) { 1849 if (self instanceof Global) { 1850 return ((Global) self).getLexicalScope(); 1851 } 1852 return self; 1853 } 1854 1855 private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) { 1856 final T func = initConstructor(name, clazz); 1857 tagBuiltinProperties(name, func); 1858 return func; 1859 } 1860 1861 private void init(final ScriptEngine eng) { 1862 assert Context.getGlobal() == this : "this global is not set as current"; 1863 1864 final ScriptEnvironment env = getContext().getEnv(); 1865 1866 // initialize Function and Object constructor 1867 initFunctionAndObject(); 1868 1869 // Now fix Global's own proto. 1870 this.setInitialProto(getObjectPrototype()); 1871 1872 // initialize global function properties 1873 this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL); 1874 1875 this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT, 1876 new Specialization[] { 1877 new Specialization(GlobalFunctions.PARSEINT_Z), 1878 new Specialization(GlobalFunctions.PARSEINT_I), 1879 new Specialization(GlobalFunctions.PARSEINT_J), 1880 new Specialization(GlobalFunctions.PARSEINT_OI), 1881 new Specialization(GlobalFunctions.PARSEINT_O) }); 1882 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1883 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN, 1884 new Specialization[] { 1885 new Specialization(GlobalFunctions.IS_NAN_I), 1886 new Specialization(GlobalFunctions.IS_NAN_J), 1887 new Specialization(GlobalFunctions.IS_NAN_D) }); 1888 this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); 1889 this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN); 1890 this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE); 1891 this.encodeURI = ScriptFunctionImpl.makeFunction("encodeURI", GlobalFunctions.ENCODE_URI); 1892 this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT); 1893 this.decodeURI = ScriptFunctionImpl.makeFunction("decodeURI", GlobalFunctions.DECODE_URI); 1894 this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); 1895 this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE); 1896 this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); 1897 this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); 1898 this.load = ScriptFunctionImpl.makeFunction("load", LOAD); 1899 this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); 1900 this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); 1901 this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); 1902 1903 // built-in constructors 1904 this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class); 1905 this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class); 1906 this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class); 1907 this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class); 1908 this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class); 1909 this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class); 1910 this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class); 1911 this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class); 1912 this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class); 1913 1914 // initialize String.prototype.length to 0 1915 // add String.prototype.length 1916 final ScriptObject stringPrototype = getStringPrototype(); 1917 stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0); 1918 1919 // set isArray flag on Array.prototype 1920 final ScriptObject arrayPrototype = getArrayPrototype(); 1921 arrayPrototype.setIsArray(); 1922 1923 this.DEFAULT_DATE = new NativeDate(Double.NaN, this); 1924 1925 // initialize default regexp object 1926 this.DEFAULT_REGEXP = new NativeRegExp("(?:)", this); 1927 1928 // RegExp.prototype should behave like a RegExp object. So copy the 1929 // properties. 1930 final ScriptObject regExpProto = getRegExpPrototype(); 1931 regExpProto.addBoundProperties(DEFAULT_REGEXP); 1932 1933 // Error stuff 1934 initErrorObjects(); 1935 1936 // java access 1937 if (! env._no_java) { 1938 initJavaAccess(); 1939 } 1940 1941 if (! env._no_typed_arrays) { 1942 initTypedArray(); 1943 } 1944 1945 if (env._scripting) { 1946 initScripting(env); 1947 } 1948 1949 if (Context.DEBUG) { 1950 boolean debugOkay; 1951 final SecurityManager sm = System.getSecurityManager(); 1952 if (sm != null) { 1953 try { 1954 sm.checkPermission(new RuntimePermission(Context.NASHORN_DEBUG_MODE)); 1955 debugOkay = true; 1956 } catch (final SecurityException ignored) { 1957 // if no permission, don't initialize Debug object 1958 debugOkay = false; 1959 } 1960 1961 } else { 1962 debugOkay = true; 1963 } 1964 1965 if (debugOkay) { 1966 initDebug(); 1967 } 1968 } 1969 1970 copyBuiltins(); 1971 1972 // expose script (command line) arguments as "arguments" property of global 1973 arguments = wrapAsObject(env.getArguments().toArray()); 1974 if (env._scripting) { 1975 // synonym for "arguments" in scripting mode 1976 addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); 1977 } 1978 1979 if (eng != null) { 1980 // default file name 1981 addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); 1982 // __noSuchProperty__ hook for ScriptContext search of missing variables 1983 final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY); 1984 addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp); 1985 } 1986 } 1987 1988 private void initErrorObjects() { 1989 // Error objects 1990 this.builtinError = initConstructor("Error", ScriptFunction.class); 1991 final ScriptObject errorProto = getErrorPrototype(); 1992 1993 // Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName 1994 final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK); 1995 final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK); 1996 errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); 1997 final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER); 1998 final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER); 1999 errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber); 2000 final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER); 2001 final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER); 2002 errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber); 2003 final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME); 2004 final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("setFileName", NativeError.SET_FILENAME); 2005 errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName); 2006 2007 // ECMA 15.11.4.2 Error.prototype.name 2008 // Error.prototype.name = "Error"; 2009 errorProto.set(NativeError.NAME, "Error", 0); 2010 // ECMA 15.11.4.3 Error.prototype.message 2011 // Error.prototype.message = ""; 2012 errorProto.set(NativeError.MESSAGE, "", 0); 2013 2014 tagBuiltinProperties("Error", builtinError); 2015 2016 this.builtinEvalError = initErrorSubtype("EvalError", errorProto); 2017 this.builtinRangeError = initErrorSubtype("RangeError", errorProto); 2018 this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto); 2019 this.builtinSyntaxError = initErrorSubtype("SyntaxError", errorProto); 2020 this.builtinTypeError = initErrorSubtype("TypeError", errorProto); 2021 this.builtinURIError = initErrorSubtype("URIError", errorProto); 2022 } 2023 2024 private ScriptFunction initErrorSubtype(final String name, final ScriptObject errorProto) { 2025 final ScriptFunction cons = initConstructor(name, ScriptFunction.class); 2026 final ScriptObject prototype = ScriptFunction.getPrototype(cons); 2027 prototype.set(NativeError.NAME, name, 0); 2028 prototype.set(NativeError.MESSAGE, "", 0); 2029 prototype.setInitialProto(errorProto); 2030 tagBuiltinProperties(name, cons); 2031 return cons; 2032 } 2033 2034 private void initJavaAccess() { 2035 final ScriptObject objectProto = getObjectPrototype(); 2036 this.builtinPackages = new NativeJavaPackage("", objectProto); 2037 this.builtinCom = new NativeJavaPackage("com", objectProto); 2038 this.builtinEdu = new NativeJavaPackage("edu", objectProto); 2039 this.builtinJava = new NativeJavaPackage("java", objectProto); 2040 this.builtinJavafx = new NativeJavaPackage("javafx", objectProto); 2041 this.builtinJavax = new NativeJavaPackage("javax", objectProto); 2042 this.builtinOrg = new NativeJavaPackage("org", objectProto); 2043 this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class); 2044 this.builtinJavaApi = initConstructor("Java", ScriptObject.class); 2045 } 2046 2047 private void initScripting(final ScriptEnvironment scriptEnv) { 2048 Object value; 2049 value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE); 2050 addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); 2051 2052 value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); 2053 addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); 2054 2055 final String execName = ScriptingFunctions.EXEC_NAME; 2056 value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); 2057 addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); 2058 2059 // Nashorn extension: global.echo (scripting-mode-only) 2060 // alias for "print" 2061 value = get("print"); 2062 addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); 2063 2064 // Nashorn extension: global.$OPTIONS (scripting-mode-only) 2065 final ScriptObject options = newObject(); 2066 copyOptions(options, scriptEnv); 2067 addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); 2068 2069 // Nashorn extension: global.$ENV (scripting-mode-only) 2070 if (System.getSecurityManager() == null) { 2071 // do not fill $ENV if we have a security manager around 2072 // Retrieve current state of ENV variables. 2073 final ScriptObject env = newObject(); 2074 env.putAll(System.getenv(), scriptEnv._strict); 2075 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); 2076 } else { 2077 addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2078 } 2079 2080 // add other special properties for exec support 2081 addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2082 addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2083 addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); 2084 } 2085 2086 private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { 2087 for (final Field f : scriptEnv.getClass().getFields()) { 2088 try { 2089 options.set(f.getName(), f.get(scriptEnv), 0); 2090 } catch (final IllegalArgumentException | IllegalAccessException exp) { 2091 throw new RuntimeException(exp); 2092 } 2093 } 2094 } 2095 2096 private void initTypedArray() { 2097 this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class); 2098 this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class); 2099 this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class); 2100 this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class); 2101 this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class); 2102 this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class); 2103 this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class); 2104 this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class); 2105 this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class); 2106 this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class); 2107 this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class); 2108 2109 } 2110 2111 private void copyBuiltins() { 2112 this.array = this.builtinArray; 2113 this._boolean = this.builtinBoolean; 2114 this.date = this.builtinDate; 2115 this.error = this.builtinError; 2116 this.evalError = this.builtinEvalError; 2117 this.function = this.builtinFunction; 2118 this.jsadapter = this.builtinJSAdapter; 2119 this.json = this.builtinJSON; 2120 this.com = this.builtinCom; 2121 this.edu = this.builtinEdu; 2122 this.java = this.builtinJava; 2123 this.javafx = this.builtinJavafx; 2124 this.javax = this.builtinJavax; 2125 this.org = this.builtinOrg; 2126 this.javaImporter = this.builtinJavaImporter; 2127 this.javaApi = this.builtinJavaApi; 2128 this.math = this.builtinMath; 2129 this.number = this.builtinNumber; 2130 this.object = this.builtinObject; 2131 this.packages = this.builtinPackages; 2132 this.rangeError = this.builtinRangeError; 2133 this.referenceError = this.builtinReferenceError; 2134 this.regexp = this.builtinRegExp; 2135 this.string = this.builtinString; 2136 this.syntaxError = this.builtinSyntaxError; 2137 this.typeError = this.builtinTypeError; 2138 this.uriError = this.builtinURIError; 2139 this.arrayBuffer = this.builtinArrayBuffer; 2140 this.dataView = this.builtinDataView; 2141 this.int8Array = this.builtinInt8Array; 2142 this.uint8Array = this.builtinUint8Array; 2143 this.uint8ClampedArray = this.builtinUint8ClampedArray; 2144 this.int16Array = this.builtinInt16Array; 2145 this.uint16Array = this.builtinUint16Array; 2146 this.int32Array = this.builtinInt32Array; 2147 this.uint32Array = this.builtinUint32Array; 2148 this.float32Array = this.builtinFloat32Array; 2149 this.float64Array = this.builtinFloat64Array; 2150 } 2151 2152 private void initDebug() { 2153 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug", ScriptObject.class)); 2154 } 2155 2156 private Object printImpl(final boolean newLine, final Object... objects) { 2157 @SuppressWarnings("resource") 2158 final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut(); 2159 final StringBuilder sb = new StringBuilder(); 2160 2161 for (final Object obj : objects) { 2162 if (sb.length() != 0) { 2163 sb.append(' '); 2164 } 2165 2166 sb.append(JSType.toString(obj)); 2167 } 2168 2169 // Print all at once to ensure thread friendly result. 2170 if (newLine) { 2171 out.println(sb.toString()); 2172 } else { 2173 out.print(sb.toString()); 2174 } 2175 2176 out.flush(); 2177 2178 return UNDEFINED; 2179 } 2180 2181 private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) { 2182 try { 2183 // Assuming class name pattern for built-in JS constructors. 2184 final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects."); 2185 2186 sb.append("Native"); 2187 sb.append(name); 2188 sb.append("$Constructor"); 2189 2190 final Class<?> funcClass = Class.forName(sb.toString()); 2191 final T res = clazz.cast(funcClass.newInstance()); 2192 2193 if (res instanceof ScriptFunction) { 2194 // All global constructor prototypes are not-writable, 2195 // not-enumerable and not-configurable. 2196 final ScriptFunction func = (ScriptFunction)res; 2197 func.modifyOwnProperty(func.getProperty("prototype"), Attribute.NON_ENUMERABLE_CONSTANT); 2198 } 2199 2200 if (res.getProto() == null) { 2201 res.setInitialProto(getObjectPrototype()); 2202 } 2203 2204 res.setIsBuiltin(); 2205 2206 return res; 2207 } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) { 2208 throw new RuntimeException(e); 2209 } 2210 } 2211 2212 private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) { 2213 final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>(); 2214 2215 list.addAll(Arrays.asList(func.getMap().getProperties())); 2216 2217 if (func instanceof ScriptFunction) { 2218 final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func); 2219 if (proto != null) { 2220 list.addAll(Arrays.asList(proto.getMap().getProperties())); 2221 } 2222 } 2223 2224 final jdk.nashorn.internal.runtime.Property prop = getProperty(name); 2225 if (prop != null) { 2226 list.add(prop); 2227 } 2228 2229 return list; 2230 } 2231 2232 /** 2233 * Given a builtin object, traverse its properties recursively and associate them with a name that 2234 * will be a key to their invalidation switchpoint. 2235 * @param name name for key 2236 * @param func builtin script object 2237 */ 2238 private void tagBuiltinProperties(final String name, final ScriptObject func) { 2239 SwitchPoint sp = context.getBuiltinSwitchPoint(name); 2240 if (sp == null) { 2241 sp = context.newBuiltinSwitchPoint(name); 2242 } 2243 2244 //get all builtin properties in this builtin object and register switchpoints keyed on the propery name, 2245 //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc 2246 for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) { 2247 prop.setBuiltinSwitchPoint(sp); 2248 } 2249 } 2250 2251 // Function and Object constructors are inter-dependent. Also, 2252 // Function.prototype 2253 // functions are not properly initialized. We fix the references here. 2254 // NOTE: be careful if you want to re-order the operations here. You may 2255 // have 2256 // to play with object references carefully!! 2257 private void initFunctionAndObject() { 2258 // First-n-foremost is Function 2259 2260 this.builtinFunction = initConstructor("Function", ScriptFunction.class); 2261 2262 // create global anonymous function 2263 final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(); 2264 // need to copy over members of Function.prototype to anon function 2265 anon.addBoundProperties(getFunctionPrototype()); 2266 2267 // Function.prototype === Object.getPrototypeOf(Function) === 2268 // <anon-function> 2269 builtinFunction.setInitialProto(anon); 2270 builtinFunction.setPrototype(anon); 2271 anon.set("constructor", builtinFunction, 0); 2272 anon.deleteOwnProperty(anon.getMap().findProperty("prototype")); 2273 2274 // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3 2275 this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0); 2276 typeErrorThrower.setPrototype(UNDEFINED); 2277 // Non-constructor built-in functions do not have "prototype" property 2278 typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype")); 2279 typeErrorThrower.preventExtensions(); 2280 2281 // now initialize Object 2282 this.builtinObject = initConstructor("Object", ScriptFunction.class); 2283 final ScriptObject ObjectPrototype = getObjectPrototype(); 2284 // Object.getPrototypeOf(Function.prototype) === Object.prototype 2285 anon.setInitialProto(ObjectPrototype); 2286 2287 // ES6 draft compliant __proto__ property of Object.prototype 2288 // accessors on Object.prototype for "__proto__" 2289 final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__); 2290 final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__); 2291 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 2292 2293 // Function valued properties of Function.prototype were not properly 2294 // initialized. Because, these were created before global.function and 2295 // global.object were not initialized. 2296 jdk.nashorn.internal.runtime.Property[] properties = getFunctionPrototype().getMap().getProperties(); 2297 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2298 final Object key = property.getKey(); 2299 final Object value = builtinFunction.get(key); 2300 2301 if (value instanceof ScriptFunction && value != anon) { 2302 final ScriptFunction func = (ScriptFunction)value; 2303 func.setInitialProto(getFunctionPrototype()); 2304 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2305 if (prototype != null) { 2306 prototype.setInitialProto(ObjectPrototype); 2307 } 2308 } 2309 } 2310 2311 // For function valued properties of Object and Object.prototype, make 2312 // sure prototype's proto chain ends with Object.prototype 2313 for (final jdk.nashorn.internal.runtime.Property property : builtinObject.getMap().getProperties()) { 2314 final Object key = property.getKey(); 2315 final Object value = builtinObject.get(key); 2316 2317 if (value instanceof ScriptFunction) { 2318 final ScriptFunction func = (ScriptFunction)value; 2319 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2320 if (prototype != null) { 2321 prototype.setInitialProto(ObjectPrototype); 2322 } 2323 } 2324 } 2325 2326 properties = getObjectPrototype().getMap().getProperties(); 2327 2328 for (final jdk.nashorn.internal.runtime.Property property : properties) { 2329 final Object key = property.getKey(); 2330 if (key.equals("constructor")) { 2331 continue; 2332 } 2333 2334 final Object value = ObjectPrototype.get(key); 2335 if (value instanceof ScriptFunction) { 2336 final ScriptFunction func = (ScriptFunction)value; 2337 final ScriptObject prototype = ScriptFunction.getPrototype(func); 2338 if (prototype != null) { 2339 prototype.setInitialProto(ObjectPrototype); 2340 } 2341 } 2342 } 2343 2344 tagBuiltinProperties("Object", builtinObject); 2345 tagBuiltinProperties("Function", builtinFunction); 2346 tagBuiltinProperties("Function", anon); 2347 } 2348 2349 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 2350 return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types)); 2351 } 2352 2353 RegExpResult getLastRegExpResult() { 2354 return lastRegExpResult; 2355 } 2356 2357 void setLastRegExpResult(final RegExpResult regExpResult) { 2358 this.lastRegExpResult = regExpResult; 2359 } 2360 2361 @Override 2362 protected boolean isGlobal() { 2363 return true; 2364 } 2365 2366 /** 2367 * A class representing the ES6 global lexical scope. 2368 */ 2369 private static class LexicalScope extends ScriptObject { 2370 2371 LexicalScope(final ScriptObject proto) { 2372 super(proto, PropertyMap.newMap()); 2373 } 2374 2375 @Override 2376 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 2377 return filterInvocation(super.findGetMethod(desc, request, operator)); 2378 } 2379 2380 @Override 2381 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 2382 return filterInvocation(super.findSetMethod(desc, request)); 2383 } 2384 2385 @Override 2386 protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) { 2387 // We override this method just to make it callable by Global 2388 return super.addBoundProperty(propMap, source, property); 2389 } 2390 2391 private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { 2392 final MethodType type = invocation.getInvocation().type(); 2393 return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); 2394 } 2395 } 2396 2397 }