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