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