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