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