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