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