Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.codelibs.sai.internal.runtime;
import static org.codelibs.sai.internal.codegen.CompilerConstants.staticCall;
import static org.codelibs.sai.internal.codegen.CompilerConstants.staticCallNoLookup;
import static org.codelibs.sai.internal.runtime.ECMAErrors.rangeError;
import static org.codelibs.sai.internal.runtime.ECMAErrors.referenceError;
import static org.codelibs.sai.internal.runtime.ECMAErrors.syntaxError;
import static org.codelibs.sai.internal.runtime.ECMAErrors.typeError;
import static org.codelibs.sai.internal.runtime.JSType.isRepresentableAsInt;
import static org.codelibs.sai.internal.runtime.JSType.isString;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import org.codelibs.sai.api.scripting.JSObject;
import org.codelibs.sai.api.scripting.ScriptObjectMirror;
import org.codelibs.sai.internal.codegen.ApplySpecialization;
import org.codelibs.sai.internal.codegen.CompilerConstants;
import org.codelibs.sai.internal.codegen.CompilerConstants.Call;
import org.codelibs.sai.internal.dynalink.beans.StaticClass;
import org.codelibs.sai.internal.ir.debug.JSONWriter;
import org.codelibs.sai.internal.objects.Global;
import org.codelibs.sai.internal.objects.NativeObject;
import org.codelibs.sai.internal.parser.Lexer;
import org.codelibs.sai.internal.runtime.linker.Bootstrap;
/**
* Utilities to be called by JavaScript runtime API and generated classes.
*/
public final class ScriptRuntime {
private ScriptRuntime() {
}
/** Singleton representing the empty array object '[]' */
public static final Object[] EMPTY_ARRAY = new Object[0];
/** Unique instance of undefined. */
public static final Undefined UNDEFINED = Undefined.getUndefined();
/**
* Unique instance of undefined used to mark empty array slots.
* Can't escape the array.
*/
public static final Undefined EMPTY = Undefined.getEmpty();
/** Method handle to generic + operator, operating on objects */
public static final Call ADD = staticCallNoLookup(ScriptRuntime.class, "ADD", Object.class, Object.class, Object.class);
/** Method handle to generic === operator, operating on objects */
public static final Call EQ_STRICT = staticCallNoLookup(ScriptRuntime.class, "EQ_STRICT", boolean.class, Object.class, Object.class);
/** Method handle used to enter a {@code with} scope at runtime. */
public static final Call OPEN_WITH = staticCallNoLookup(ScriptRuntime.class, "openWith", ScriptObject.class, ScriptObject.class,
Object.class);
/**
* Method used to place a scope's variable into the Global scope, which has to be done for the
* properties declared at outermost script level.
*/
public static final Call MERGE_SCOPE = staticCallNoLookup(ScriptRuntime.class, "mergeScope", ScriptObject.class, ScriptObject.class);
/**
* Return an appropriate iterator for the elements in a for-in construct
*/
public static final Call TO_PROPERTY_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toPropertyIterator", Iterator.class,
Object.class);
/**
* Return an appropriate iterator for the elements in a for-each construct
*/
public static final Call TO_VALUE_ITERATOR = staticCallNoLookup(ScriptRuntime.class, "toValueIterator", Iterator.class, Object.class);
/**
* Method handle for apply. Used from {@link ScriptFunction} for looking up calls to
* call sites that are known to be megamorphic. Using an invoke dynamic here would
* lead to the JVM deoptimizing itself to death
*/
public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class,
Object.class, Object[].class);
/**
* Throws a reference error for an undefined variable.
*/
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError",
void.class, String.class);
/**
* Throws a reference error for an undefined variable.
*/
public static final Call THROW_CONST_TYPE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwConstTypeError",
void.class, String.class);
/**
* Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
*/
public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName",
void.class, String.class);
/**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
* @param deflt default to use if not convertible.
* @return int tag value (or deflt.)
*/
public static int switchTagAsInt(final Object tag, final int deflt) {
if (tag instanceof Number) {
final double d = ((Number) tag).doubleValue();
if (isRepresentableAsInt(d)) {
return (int) d;
}
}
return deflt;
}
/**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
* @param deflt default to use if not convertible.
* @return int tag value (or deflt.)
*/
public static int switchTagAsInt(final boolean tag, final int deflt) {
return deflt;
}
/**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
* @param deflt default to use if not convertible.
* @return int tag value (or deflt.)
*/
public static int switchTagAsInt(final long tag, final int deflt) {
return isRepresentableAsInt(tag) ? (int) tag : deflt;
}
/**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
* @param deflt default to use if not convertible.
* @return int tag value (or deflt.)
*/
public static int switchTagAsInt(final double tag, final int deflt) {
return isRepresentableAsInt(tag) ? (int) tag : deflt;
}
/**
* This is the builtin implementation of {@code Object.prototype.toString}
* @param self reference
* @return string representation as object
*/
public static String builtinObjectToString(final Object self) {
String className;
// Spec tells us to convert primitives by ToObject..
// But we don't need to -- all we need is the right class name
// of the corresponding primitive wrapper type.
final JSType type = JSType.ofNoFunction(self);
switch (type) {
case BOOLEAN:
className = "Boolean";
break;
case NUMBER:
className = "Number";
break;
case STRING:
className = "String";
break;
// special case of null and undefined
case NULL:
className = "Null";
break;
case UNDEFINED:
className = "Undefined";
break;
case OBJECT:
if (self instanceof ScriptObject) {
className = ((ScriptObject) self).getClassName();
} else if (self instanceof JSObject) {
className = ((JSObject) self).getClassName();
} else {
className = self.getClass().getName();
}
break;
default:
// Sai extension: use Java class name
className = self.getClass().getName();
break;
}
final StringBuilder sb = new StringBuilder();
sb.append("[object ");
sb.append(className);
sb.append(']');
return sb.toString();
}
/**
* This is called whenever runtime wants to throw an error and wants to provide
* meaningful information about an object. We don't want to call toString which
* ends up calling "toString" from script world which may itself throw error.
* When we want to throw an error, we don't additional error from script land
* -- which may sometimes lead to infinite recursion.
*
* @param obj Object to converted to String safely (without calling user script)
* @return safe String representation of the given object
*/
public static String safeToString(final Object obj) {
return JSType.toStringImpl(obj, true);
}
/**
* Returns an iterator over property identifiers used in the {@code for...in} statement. Note that the ECMAScript
* 5.1 specification, chapter 12.6.4. uses the terminology "property names", which seems to imply that the property
* identifiers are expected to be strings, but this is not actually spelled out anywhere, and Sai will in some
* cases deviate from this. Namely, we guarantee to always return an iterator over {@link String} values for any
* built-in JavaScript object. We will however return an iterator over {@link Integer} objects for native Java
* arrays and {@link List} objects, as well as arbitrary objects representing keys of a {@link Map}. Therefore, the
* expression {@code typeof i} within a {@code for(i in obj)} statement can return something other than
* {@code string} when iterating over native Java arrays, {@code List}, and {@code Map} objects.
* @param obj object to iterate on.
* @return iterator over the object's property names.
*/
public static Iterator> toPropertyIterator(final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject) obj).propertyIterator();
}
if (obj != null && obj.getClass().isArray()) {
return new RangeIterator(Array.getLength(obj));
}
if (obj instanceof JSObject) {
return ((JSObject) obj).keySet().iterator();
}
if (obj instanceof List) {
return new RangeIterator(((List>) obj).size());
}
if (obj instanceof Map) {
return ((Map, ?>) obj).keySet().iterator();
}
final Object wrapped = Global.instance().wrapAsObject(obj);
if (wrapped instanceof ScriptObject) {
return ((ScriptObject) wrapped).propertyIterator();
}
return Collections.emptyIterator();
}
private static final class RangeIterator implements Iterator {
private final int length;
private int index;
RangeIterator(final int length) {
this.length = length;
}
@Override
public boolean hasNext() {
return index < length;
}
@Override
public Integer next() {
return index++;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
/**
* Returns an iterator over property values used in the {@code for each...in} statement. Aside from built-in JS
* objects, it also operates on Java arrays, any {@link Iterable}, as well as on {@link Map} objects, iterating over
* map values.
* @param obj object to iterate on.
* @return iterator over the object's property values.
*/
public static Iterator> toValueIterator(final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject) obj).valueIterator();
}
if (obj != null && obj.getClass().isArray()) {
final Object array = obj;
final int length = Array.getLength(obj);
return new Iterator