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