Merge
This commit is contained in:
commit
6a5adc81a0
@ -26,3 +26,5 @@ jcov2/*
|
||||
test/lib/testng.jar
|
||||
test/script/external/*
|
||||
.project
|
||||
.externalToolBuilders/*
|
||||
.settings/*
|
||||
|
137
nashorn/bin/runopt.sh
Normal file
137
nashorn/bin/runopt.sh
Normal file
@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2010, 2014, 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
###########################################################################################
|
||||
# This is a helper script to evaluate nashorn with optimistic types
|
||||
# it produces a flight recording for every run, and uses the best
|
||||
# known flags for performance for the current configration
|
||||
###########################################################################################
|
||||
|
||||
# Flags to enable assertions, we need the system assertions too, since
|
||||
# this script runs Nashorn in the BCP to override any nashorn.jar that might
|
||||
# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
|
||||
#
|
||||
ENABLE_ASSERTIONS_FLAGS="-ea -esa"
|
||||
|
||||
# Flags to instrument lambdaform computation, caching, interpretation and compilation
|
||||
# Default compile threshold for lambdaforms is 30
|
||||
#
|
||||
#LAMBDAFORM_FLAGS="\
|
||||
# -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
|
||||
# -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
|
||||
# -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
|
||||
# -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
|
||||
|
||||
# Flags to run trusted tests from the Nashorn test suite
|
||||
#
|
||||
#TRUSTED_TEST_FLAGS="\
|
||||
#-Djava.security.manager \
|
||||
#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
|
||||
|
||||
# Testing out new code optimizations using the generic hotspot "new code" parameter
|
||||
#
|
||||
#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
|
||||
|
||||
#
|
||||
#-Dnashorn.typeInfo.disabled=false \
|
||||
# and for Nashorn options:
|
||||
# --class-cache-size=0 --persistent-code-cache=false
|
||||
|
||||
# Unique timestamped file name for JFR recordings. For JFR, we also have to
|
||||
# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
|
||||
# stack traces.
|
||||
#
|
||||
# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
|
||||
# set the "method-sampling-interval" Normal and Maximum sample time as low as you
|
||||
# can go (10 ms on most platforms). The default is normally higher. The increased
|
||||
# sampling overhead is usually negligible for Nashorn runs, but the data is better
|
||||
|
||||
if [ -z $JFR_FILENAME ]; then
|
||||
JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
|
||||
echo "Using default JFR filename: ${JFR_FILENAME}..."
|
||||
fi
|
||||
|
||||
# Flight recorder
|
||||
#
|
||||
# see above - already in place, copy the flags down here to disable
|
||||
ENABLE_FLIGHT_RECORDER_FLAGS="\
|
||||
-XX:+UnlockCommercialFeatures \
|
||||
-XX:+FlightRecorder \
|
||||
-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
|
||||
|
||||
# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
|
||||
# keeping this flag around for experimental reasons. Replace + with - to switch it off
|
||||
#
|
||||
#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
|
||||
|
||||
# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
|
||||
# this disables them if needed
|
||||
#
|
||||
#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
|
||||
|
||||
# Add timing to time the compilation phases.
|
||||
#ENABLE_TIME_FLAGS=--log=time
|
||||
|
||||
# Add ShowHiddenFrames to get lambda form internals on the stack traces
|
||||
#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
|
||||
|
||||
# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
|
||||
# That tired compilation is switched off, for C2 only output and that the number of
|
||||
# compiler threads is set to 1 for determinsm.
|
||||
#
|
||||
#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
|
||||
|
||||
# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
|
||||
#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
|
||||
|
||||
# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
|
||||
# that we run the script from the make dir
|
||||
DIR=..
|
||||
NASHORN_JAR=$DIR/dist/nashorn.jar
|
||||
|
||||
|
||||
# The built Nashorn jar is placed first in the bootclasspath to override the JDK
|
||||
# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
|
||||
# nashorn count as system assertions in this configuration
|
||||
|
||||
# Type profiling default level is 111, 222 adds some compile time, but is faster
|
||||
|
||||
$JAVA_HOME/bin/java \
|
||||
$ENABLE_ASSERTIONS_FLAGS \
|
||||
$LAMBDAFORM_FLAGS \
|
||||
$TRUSTED_FLAGS \
|
||||
$USE_NEW_CODE_FLAGS \
|
||||
$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
|
||||
$ENABLE_FLIGHT_RECORDER_FLAGS \
|
||||
$ENABLE_TYPE_SPECIALIZATION_FLAGS \
|
||||
$TIERED_COMPILATION_THRESOLD_FLAGS \
|
||||
$DISABLE_MATH_INTRINSICS_FLAGS \
|
||||
$PRINT_ASM_FLAGS \
|
||||
-Xbootclasspath/p:$NASHORN_JAR \
|
||||
-Xms2G -Xmx2G \
|
||||
-XX:TypeProfileLevel=222 \
|
||||
-cp $CLASSPATH:../build/test/classes/ \
|
||||
jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}
|
||||
|
||||
|
@ -408,7 +408,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||
<fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}">
|
||||
<include name="**/framework/ScriptTest.class"/>
|
||||
</fileset>
|
||||
<testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes"
|
||||
<testng outputdir="${build.nosecurity.test.results.dir}/${testResultsSubDir}" classfilesetref="test.nosecurity.classes"
|
||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} -Dbuild.dir=${build.dir}"/>
|
||||
@ -431,7 +431,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||
<target name="-test-security">
|
||||
<delete dir="${build.dir}/nashorn_code_cache"/>
|
||||
<property name="debug.test.jvmargs" value=""/>
|
||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||
<testng outputdir="${build.test.results.dir}/${testResultsSubDir}" classfilesetref="test.classes"
|
||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
|
||||
@ -457,9 +457,11 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||
<echo message="Running test suite in OPTIMISTIC mode..."/>
|
||||
<antcall target="-test-nosecurity" inheritRefs="true">
|
||||
<param name="optimistic" value="true"/>
|
||||
<param name="testResultsSubDir" value="optimistic"/>
|
||||
</antcall>
|
||||
<antcall target="-test-security" inheritRefs="true">
|
||||
<param name="optimistic" value="true"/>
|
||||
<param name="testResultsSubDir" value="optimistic"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
@ -467,9 +469,11 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||
<echo message="Running test suite in PESSIMISTIC mode..."/>
|
||||
<antcall target="-test-nosecurity" inheritRefs="true">
|
||||
<param name="optimistic" value="false"/>
|
||||
<param name="testResultsSubDir" value="pessimistic"/>
|
||||
</antcall>
|
||||
<antcall target="-test-security" inheritRefs="true">
|
||||
<param name="optimistic" value="false"/>
|
||||
<param name="testResultsSubDir" value="pessimistic"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
|
@ -229,6 +229,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
|
||||
private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
|
||||
assert !(thiz instanceof ScriptObject) : "raw ScriptObject not expected here";
|
||||
|
||||
if (clazz == null || !clazz.isInterface()) {
|
||||
throw new IllegalArgumentException(getMessage("interface.class.expected"));
|
||||
}
|
||||
@ -251,17 +253,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz;
|
||||
realSelf = mirror.getScriptObject();
|
||||
realGlobal = mirror.getHomeGlobal();
|
||||
if (! isOfContext(realGlobal, nashornContext)) {
|
||||
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
|
||||
}
|
||||
} else if (thiz instanceof ScriptObject) {
|
||||
// called from script code.
|
||||
realSelf = (ScriptObject)thiz;
|
||||
realGlobal = Context.getGlobal();
|
||||
if (realGlobal == null) {
|
||||
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
|
||||
}
|
||||
|
||||
if (! isOfContext(realGlobal, nashornContext)) {
|
||||
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
|
||||
}
|
||||
@ -368,6 +359,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
|
||||
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
name.getClass(); // null check
|
||||
assert !(selfObject instanceof ScriptObject) : "raw ScriptObject not expected here";
|
||||
|
||||
Global invokeGlobal = null;
|
||||
ScriptObjectMirror selfMirror = null;
|
||||
@ -377,20 +369,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
|
||||
}
|
||||
invokeGlobal = selfMirror.getHomeGlobal();
|
||||
} else if (selfObject instanceof ScriptObject) {
|
||||
// invokeMethod called from script code - in which case we may get 'naked' ScriptObject
|
||||
// Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
|
||||
final Global oldGlobal = Context.getGlobal();
|
||||
invokeGlobal = oldGlobal;
|
||||
if (oldGlobal == null) {
|
||||
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
|
||||
}
|
||||
|
||||
if (! isOfContext(oldGlobal, nashornContext)) {
|
||||
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
|
||||
}
|
||||
|
||||
selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
|
||||
} else if (selfObject == null) {
|
||||
// selfObject is null => global function call
|
||||
final Global ctxtGlobal = getNashornGlobalFrom(context);
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
@ -75,11 +73,8 @@ public final class ScriptUtils {
|
||||
* @param sync the object to synchronize on
|
||||
* @return a synchronizing wrapper function
|
||||
*/
|
||||
public static Object makeSynchronizedFunction(final Object func, final Object sync) {
|
||||
if (func instanceof ScriptFunction) {
|
||||
return ((ScriptFunction)func).makeSynchronizedFunction(sync);
|
||||
}
|
||||
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
|
||||
public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
|
||||
return func.makeSynchronizedFunction(unwrap(sync));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,12 +83,8 @@ public final class ScriptUtils {
|
||||
* @param obj object to be wrapped
|
||||
* @return wrapped object
|
||||
*/
|
||||
public static Object wrap(final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ScriptObjectMirror.wrap(obj, Context.getGlobal());
|
||||
}
|
||||
|
||||
return obj;
|
||||
public static ScriptObjectMirror wrap(final ScriptObject obj) {
|
||||
return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,14 +151,15 @@ public final class ScriptUtils {
|
||||
}
|
||||
|
||||
final LinkerServices linker = Bootstrap.getLinkerServices();
|
||||
final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz);
|
||||
final Object objToConvert = unwrap(obj);
|
||||
final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(), clazz);
|
||||
if (converter == null) {
|
||||
// no supported conversion!
|
||||
throw new UnsupportedOperationException("conversion not supported");
|
||||
}
|
||||
|
||||
try {
|
||||
return converter.invoke(obj);
|
||||
return converter.invoke(objToConvert);
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
|
@ -511,16 +511,6 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
|
||||
thisProperties.push(new HashSet<String>());
|
||||
|
||||
if (functionNode.isDeclared()) {
|
||||
// Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
|
||||
// is not a program - it is a function being compiled on-demand.
|
||||
final Iterator<Block> blocks = lc.getBlocks();
|
||||
if (blocks.hasNext()) {
|
||||
final IdentNode ident = functionNode.getIdent();
|
||||
defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Every function has a body, even the ones skipped on reparse (they have an empty one). We're
|
||||
// asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
|
||||
// are used in them.
|
||||
@ -532,16 +522,36 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
@Override
|
||||
public boolean enterVarNode(final VarNode varNode) {
|
||||
start(varNode);
|
||||
// Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
|
||||
// declarations as VarNodes, they are exception to the rule, as they need to have the symbol visible to the
|
||||
// body of the declared function for self-reference.
|
||||
if (varNode.isFunctionDeclaration()) {
|
||||
defineVarIdent(varNode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
final IdentNode ident = varNode.getName();
|
||||
defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
|
||||
if (!varNode.isFunctionDeclaration()) {
|
||||
defineVarIdent(varNode);
|
||||
}
|
||||
return super.leaveVarNode(varNode);
|
||||
}
|
||||
|
||||
private void defineVarIdent(final VarNode varNode) {
|
||||
final IdentNode ident = varNode.getName();
|
||||
final int flags;
|
||||
if (varNode.isAnonymousFunctionDeclaration()) {
|
||||
flags = IS_INTERNAL;
|
||||
} else if (lc.getCurrentFunction().isProgram()) {
|
||||
flags = IS_SCOPE;
|
||||
} else {
|
||||
flags = 0;
|
||||
}
|
||||
defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
|
||||
}
|
||||
|
||||
private Symbol exceptionSymbol() {
|
||||
return newObjectInternal(EXCEPTION_PREFIX);
|
||||
}
|
||||
|
@ -410,10 +410,29 @@ public final class Compiler implements Loggable {
|
||||
baseName = baseName + installer.getUniqueScriptId();
|
||||
}
|
||||
|
||||
final String mangled = NameCodec.encode(baseName);
|
||||
// ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char.
|
||||
// While ASM accepts such escapes for method names, field names, it enforces Java identifier
|
||||
// for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_'
|
||||
// rather than safe encoding using '\'.
|
||||
final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName);
|
||||
return mangled != null ? mangled : baseName;
|
||||
}
|
||||
|
||||
private static final String DANGEROUS_CHARS = "\\/.;:$[]<>";
|
||||
private static String replaceDangerChars(final String name) {
|
||||
final int len = name.length();
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < len; i++) {
|
||||
final char ch = name.charAt(i);
|
||||
if (DANGEROUS_CHARS.indexOf(ch) != -1) {
|
||||
buf.append('_');
|
||||
} else {
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String firstCompileUnitName() {
|
||||
final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE).
|
||||
append('/').
|
||||
|
@ -98,6 +98,7 @@ import jdk.nashorn.internal.ir.LocalVariableConversion;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.TryNode;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
import jdk.nashorn.internal.runtime.ArgumentSetter;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
@ -2125,7 +2126,14 @@ public class MethodEmitter implements Emitter {
|
||||
|
||||
int pos = 0;
|
||||
for (int i = argCount - 1; i >= 0; i--) {
|
||||
paramTypes[i] = stack.peek(pos++);
|
||||
Type pt = stack.peek(pos++);
|
||||
// "erase" specific ScriptObject subtype info - except for NativeArray.
|
||||
// NativeArray is used for array/List/Deque conversion for Java calls.
|
||||
if (ScriptObject.class.isAssignableFrom(pt.getTypeClass()) &&
|
||||
!NativeArray.class.isAssignableFrom(pt.getTypeClass())) {
|
||||
pt = Type.SCRIPT_OBJECT;
|
||||
}
|
||||
paramTypes[i] = pt;
|
||||
}
|
||||
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
|
@ -29,16 +29,22 @@ import static jdk.nashorn.internal.runtime.Property.NOT_CONFIGURABLE;
|
||||
import static jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
|
||||
import static jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
import jdk.nashorn.internal.ir.CallNode;
|
||||
import jdk.nashorn.internal.ir.Expression;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.Optimistic;
|
||||
import jdk.nashorn.internal.objects.ArrayBufferView;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
import jdk.nashorn.internal.runtime.FindProperty;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
@ -47,6 +53,13 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
* Used during recompilation.
|
||||
*/
|
||||
final class TypeEvaluator {
|
||||
/**
|
||||
* Type signature for invocation of functions without parameters: we must pass (callee, this) of type
|
||||
* (ScriptFunction, Object) respectively. We also use Object as the return type (we must pass something,
|
||||
* but it'll be ignored; it can't be void, though).
|
||||
*/
|
||||
private static final MethodType EMPTY_INVOCATION_TYPE = MethodType.methodType(Object.class, ScriptFunction.class, Object.class);
|
||||
|
||||
private final Compiler compiler;
|
||||
private final ScriptObject runtimeScope;
|
||||
|
||||
@ -190,30 +203,46 @@ final class TypeEvaluator {
|
||||
return null;
|
||||
}
|
||||
return getPropertyType(runtimeScope, ((IdentNode)expr).getName());
|
||||
}
|
||||
|
||||
if (expr instanceof AccessNode) {
|
||||
} else if (expr instanceof AccessNode) {
|
||||
final AccessNode accessNode = (AccessNode)expr;
|
||||
final Object base = evaluateSafely(accessNode.getBase());
|
||||
if (!(base instanceof ScriptObject)) {
|
||||
return null;
|
||||
}
|
||||
return getPropertyType((ScriptObject)base, accessNode.getProperty());
|
||||
}
|
||||
|
||||
if (expr instanceof IndexNode) {
|
||||
} else if (expr instanceof IndexNode) {
|
||||
final IndexNode indexNode = (IndexNode)expr;
|
||||
final Object base = evaluateSafely(indexNode.getBase());
|
||||
if(!(base instanceof NativeArray)) {
|
||||
// We only know how to deal with NativeArray. TODO: maybe manage buffers too
|
||||
return null;
|
||||
if(base instanceof NativeArray || base instanceof ArrayBufferView) {
|
||||
// NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their
|
||||
// underlying array storage, not based on values of individual elements. Thus, a LongArrayData will
|
||||
// throw UOE for every optimistic int linkage attempt, even if the long value being returned in the
|
||||
// first invocation would be representable as int. That way, we can presume that the array's optimistic
|
||||
// type is the most optimistic type for which an element getter has a chance of executing successfully.
|
||||
return ((ScriptObject)base).getArray().getOptimisticType();
|
||||
}
|
||||
} else if (expr instanceof CallNode) {
|
||||
// Currently, we'll only try to guess the return type of immediately invoked function expressions with no
|
||||
// parameters, that is (function() { ... })(). We could do better, but these are all heuristics and we can
|
||||
// gradually introduce them as needed. An easy one would be to do the same for .call(this) idiom.
|
||||
final CallNode callExpr = (CallNode)expr;
|
||||
final Expression fnExpr = callExpr.getFunction();
|
||||
if (fnExpr instanceof FunctionNode) {
|
||||
final FunctionNode fn = (FunctionNode)fnExpr;
|
||||
if (callExpr.getArgs().isEmpty()) {
|
||||
final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
|
||||
if (data != null) {
|
||||
final Type returnType = Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
|
||||
if (returnType == Type.BOOLEAN) {
|
||||
// We don't have optimistic booleans. In fact, optimistic call sites getting back boolean
|
||||
// currently deoptimize all the way to Object.
|
||||
return Type.OBJECT;
|
||||
}
|
||||
assert returnType == Type.INT || returnType == Type.LONG || returnType == Type.NUMBER || returnType == Type.OBJECT;
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their underlying
|
||||
// array storage, not based on values of individual elements. Thus, a LongArrayData will throw UOE for every
|
||||
// optimistic int linkage attempt, even if the long value being returned in the first invocation would be
|
||||
// representable as int. That way, we can presume that the array's optimistic type is the most optimistic
|
||||
// type for which an element getter has a chance of executing successfully.
|
||||
return ((NativeArray)base).getArray().getOptimisticType();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -80,11 +80,12 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param statements statements
|
||||
* @param token The first token of the block
|
||||
* @param finish The index of the last character
|
||||
* @param flags The flags of the block
|
||||
* @param statements All statements in the block
|
||||
*/
|
||||
public Block(final long token, final int finish, final Statement... statements) {
|
||||
public Block(final long token, final int finish, final int flags, final Statement... statements) {
|
||||
super(token, finish);
|
||||
|
||||
this.statements = Arrays.asList(statements);
|
||||
@ -92,29 +93,52 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
|
||||
this.entryLabel = new Label("block_entry");
|
||||
this.breakLabel = new Label("block_break");
|
||||
final int len = statements.length;
|
||||
this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
|
||||
final int terminalFlags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
|
||||
this.flags = terminalFlags | flags;
|
||||
this.conversion = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new block
|
||||
*
|
||||
* @param token The first token of the block
|
||||
* @param finish The index of the last character
|
||||
* @param statements All statements in the block
|
||||
*/
|
||||
public Block(final long token, final int finish, final Statement...statements){
|
||||
this(token, finish, 0, statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new block
|
||||
*
|
||||
* @param token The first token of the block
|
||||
* @param finish The index of the last character
|
||||
* @param statements All statements in the block
|
||||
*/
|
||||
public Block(final long token, final int finish, final List<Statement> statements){
|
||||
this(token, finish, 0, statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param statements statements
|
||||
* @param token The first token of the block
|
||||
* @param finish The index of the last character
|
||||
* @param flags The flags of the block
|
||||
* @param statements All statements in the block
|
||||
*/
|
||||
public Block(final long token, final int finish, final List<Statement> statements) {
|
||||
this(token, finish, statements.toArray(new Statement[statements.size()]));
|
||||
public Block(final long token, final int finish, final int flags, final List<Statement> statements) {
|
||||
this(token, finish, flags, statements.toArray(new Statement[statements.size()]));
|
||||
}
|
||||
|
||||
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols, final LocalVariableConversion conversion) {
|
||||
super(block);
|
||||
super(block, finish);
|
||||
this.statements = statements;
|
||||
this.flags = flags;
|
||||
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
|
||||
this.entryLabel = new Label(block.entryLabel);
|
||||
this.breakLabel = new Label(block.breakLabel);
|
||||
this.finish = finish;
|
||||
this.conversion = conversion;
|
||||
}
|
||||
|
||||
|
@ -54,20 +54,37 @@ public final class ForNode extends LoopNode {
|
||||
|
||||
private final int flags;
|
||||
|
||||
/**
|
||||
* Constructs a ForNode
|
||||
*
|
||||
* @param lineNumber The line number of header
|
||||
* @param token The for token
|
||||
* @param finish The last character of the for node
|
||||
* @param body The body of the for node
|
||||
* @param flags The flags
|
||||
*/
|
||||
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
|
||||
this(lineNumber, token, finish, body, flags, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param body body
|
||||
* @param flags flags
|
||||
* @param lineNumber The line number of header
|
||||
* @param token The for token
|
||||
* @param finish The last character of the for node
|
||||
* @param body The body of the for node
|
||||
* @param flags The flags
|
||||
* @param init The initial expression
|
||||
* @param test The test expression
|
||||
* @param modify The modify expression
|
||||
*/
|
||||
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags) {
|
||||
super(lineNumber, token, finish, body, false);
|
||||
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags, final Expression init, final JoinPredecessorExpression test, final JoinPredecessorExpression modify) {
|
||||
super(lineNumber, token, finish, body, test, false);
|
||||
this.flags = flags;
|
||||
this.init = null;
|
||||
this.modify = null;
|
||||
this.init = init;
|
||||
this.modify = modify;
|
||||
|
||||
}
|
||||
|
||||
private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
|
||||
@ -166,16 +183,6 @@ public final class ForNode extends LoopNode {
|
||||
public boolean isForIn() {
|
||||
return (flags & IS_FOR_IN) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this to be a for in construct
|
||||
* @param lc lexical context
|
||||
* @return new for node if changed or existing if not
|
||||
*/
|
||||
public ForNode setIsForIn(final LexicalContext lc) {
|
||||
return setFlags(lc, flags | IS_FOR_IN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a for each construct, known from e.g. Rhino. This will be a for of construct
|
||||
* in ECMAScript 6
|
||||
@ -185,15 +192,6 @@ public final class ForNode extends LoopNode {
|
||||
return (flags & IS_FOR_EACH) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this to be a for each construct
|
||||
* @param lc lexical context
|
||||
* @return new for node if changed or existing if not
|
||||
*/
|
||||
public ForNode setIsForEach(final LexicalContext lc) {
|
||||
return setFlags(lc, flags | IS_FOR_EACH);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a for in or for each construct, there is an iterator symbol
|
||||
* @return the symbol for the iterator to be used, or null if none exists
|
||||
@ -260,13 +258,6 @@ public final class ForNode extends LoopNode {
|
||||
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
|
||||
}
|
||||
|
||||
private ForNode setFlags(final LexicalContext lc, final int flags) {
|
||||
if (this.flags == flags) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
|
||||
}
|
||||
|
||||
@Override
|
||||
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
|
||||
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
|
||||
|
@ -31,7 +31,6 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
@ -46,6 +45,7 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Ignore;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
@ -299,12 +299,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param firstToken first token of the function node (including the function declaration)
|
||||
* @param lastToken lastToken
|
||||
* @param namespace the namespace
|
||||
* @param ident the identifier
|
||||
* @param name the name of the function
|
||||
* @param parameters parameter list
|
||||
* @param kind kind of function as in {@link FunctionNode.Kind}
|
||||
* @param flags initial flags
|
||||
* @param body body of the function
|
||||
* @param state The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
|
||||
* @param endParserState The parser state at the end of the parsing.
|
||||
*/
|
||||
public FunctionNode(
|
||||
final Source source,
|
||||
@ -312,12 +316,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
final long token,
|
||||
final int finish,
|
||||
final long firstToken,
|
||||
final long lastToken,
|
||||
final Namespace namespace,
|
||||
final IdentNode ident,
|
||||
final String name,
|
||||
final List<IdentNode> parameters,
|
||||
final FunctionNode.Kind kind,
|
||||
final int flags) {
|
||||
final int flags,
|
||||
final Block body,
|
||||
final CompilationState state,
|
||||
final Object endParserState) {
|
||||
super(token, finish);
|
||||
|
||||
this.source = source;
|
||||
@ -327,15 +335,15 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
this.kind = kind;
|
||||
this.parameters = parameters;
|
||||
this.firstToken = firstToken;
|
||||
this.lastToken = token;
|
||||
this.lastToken = lastToken;
|
||||
this.namespace = namespace;
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
|
||||
this.flags = flags;
|
||||
this.compileUnit = null;
|
||||
this.body = null;
|
||||
this.body = body;
|
||||
this.thisProperties = 0;
|
||||
this.rootClass = null;
|
||||
this.endParserState = null;
|
||||
this.endParserState = endParserState;
|
||||
}
|
||||
|
||||
private FunctionNode(
|
||||
@ -439,7 +447,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
* @return the id
|
||||
*/
|
||||
public int getId() {
|
||||
return position();
|
||||
return isProgram() ? -1: Token.descPosition(firstToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -902,34 +910,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
return lastToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last token for this function's code
|
||||
* @param lc lexical context
|
||||
* @param lastToken the last token
|
||||
* @return function node or a new one if state was changed
|
||||
*/
|
||||
public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
|
||||
if (this.lastToken == lastToken) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(
|
||||
lc,
|
||||
this,
|
||||
new FunctionNode(
|
||||
this,
|
||||
lastToken,
|
||||
endParserState,
|
||||
flags,
|
||||
name,
|
||||
returnType,
|
||||
compileUnit,
|
||||
compilationState,
|
||||
body,
|
||||
parameters,
|
||||
thisProperties,
|
||||
rootClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end parser state for this function.
|
||||
* @return the end parser state for this function.
|
||||
@ -938,33 +918,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
return endParserState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the end parser state for this function.
|
||||
* @param lc lexical context
|
||||
* @param endParserState the parser state to set
|
||||
* @return function node or a new one if state was changed
|
||||
*/
|
||||
public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
|
||||
if (this.endParserState == endParserState) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(
|
||||
lc,
|
||||
this,
|
||||
new FunctionNode(
|
||||
this,
|
||||
lastToken,
|
||||
endParserState,
|
||||
flags,
|
||||
name,
|
||||
returnType,
|
||||
compileUnit,
|
||||
compilationState,
|
||||
body,
|
||||
parameters,
|
||||
thisProperties, rootClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this function
|
||||
* @return the name
|
||||
|
@ -53,14 +53,15 @@ public abstract class LoopNode extends BreakableStatement {
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param body loop body
|
||||
* @param test test
|
||||
* @param controlFlowEscapes controlFlowEscapes
|
||||
*/
|
||||
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final boolean controlFlowEscapes) {
|
||||
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
|
||||
super(lineNumber, token, finish, new Label("while_break"));
|
||||
this.continueLabel = new Label("while_continue");
|
||||
this.test = null;
|
||||
this.body = body;
|
||||
this.controlFlowEscapes = controlFlowEscapes;
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,7 +39,7 @@ public abstract class Node implements Cloneable {
|
||||
protected final int start;
|
||||
|
||||
/** End of source range. */
|
||||
protected int finish;
|
||||
protected final int finish;
|
||||
|
||||
/** Token descriptor. */
|
||||
private final long token;
|
||||
@ -80,6 +80,18 @@ public abstract class Node implements Cloneable {
|
||||
this.finish = node.finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor that overrides finish
|
||||
*
|
||||
* @param node source node
|
||||
* @param finish Last character
|
||||
*/
|
||||
protected Node(final Node node, final int finish) {
|
||||
this.token = node.token;
|
||||
this.start = node.start;
|
||||
this.finish = finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a loop node?
|
||||
*
|
||||
@ -151,14 +163,6 @@ public abstract class Node implements Cloneable {
|
||||
return finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set finish position for this node in the source string
|
||||
* @param finish finish
|
||||
*/
|
||||
public void setFinish(final int finish) {
|
||||
this.finish = finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get start position for node
|
||||
* @return start position
|
||||
|
@ -272,4 +272,12 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
public boolean isFunctionDeclaration() {
|
||||
return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is an anonymous function declaration.
|
||||
* @return true if this is an anonymous function declaration.
|
||||
*/
|
||||
public boolean isAnonymousFunctionDeclaration() {
|
||||
return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +45,11 @@ public final class WhileNode extends LoopNode {
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param isDoWhile is this a do while loop?
|
||||
* @param test test expression
|
||||
* @param body body of the while loop
|
||||
*/
|
||||
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
|
||||
super(lineNumber, token, finish, null, false);
|
||||
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile, final JoinPredecessorExpression test, final Block body) {
|
||||
super(lineNumber, token, finish, body, test, false);
|
||||
this.isDoWhile = isDoWhile;
|
||||
}
|
||||
|
||||
@ -55,10 +57,10 @@ public final class WhileNode extends LoopNode {
|
||||
* Internal copy constructor
|
||||
*
|
||||
* @param whileNode while node
|
||||
* @param test test
|
||||
* @param body body
|
||||
* @param test Test expression
|
||||
* @param body body of the while loop
|
||||
* @param controlFlowEscapes control flow escapes?
|
||||
* @param conversion TODO
|
||||
* @param conversion local variable conversion info
|
||||
*/
|
||||
private WhileNode(final WhileNode whileNode, final JoinPredecessorExpression test, final Block body, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
|
||||
super(whileNode, test, body, controlFlowEscapes, conversion);
|
||||
|
@ -42,14 +42,16 @@ public final class WithNode extends LexicalContextStatement {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param lineNumber Line number of the header
|
||||
* @param token First token
|
||||
* @param finish Character index of the last token
|
||||
* @param expression With expression
|
||||
* @param body Body of with node
|
||||
*/
|
||||
public WithNode(final int lineNumber, final long token, final int finish) {
|
||||
public WithNode(final int lineNumber, final long token, final int finish, final Expression expression, final Block body) {
|
||||
super(lineNumber, token, finish);
|
||||
this.expression = null;
|
||||
this.body = null;
|
||||
this.expression = expression;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
private WithNode(final WithNode node, final Expression expression, final Block body) {
|
||||
|
@ -31,7 +31,6 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
@ -46,7 +45,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
|
||||
import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
|
||||
|
||||
@ScriptClass("ArrayBufferView")
|
||||
abstract class ArrayBufferView extends ScriptObject {
|
||||
public abstract class ArrayBufferView extends ScriptObject {
|
||||
private final NativeArrayBuffer buffer;
|
||||
private final int byteOffset;
|
||||
|
||||
|
@ -561,7 +561,6 @@ public final class Global extends ScriptObject implements Scope {
|
||||
*
|
||||
* @param engine ScriptEngine to initialize
|
||||
*/
|
||||
@SuppressWarnings("hiding")
|
||||
public void initBuiltinObjects(final ScriptEngine engine) {
|
||||
if (this.builtinObject != null) {
|
||||
// already initialized, just return
|
||||
@ -1718,7 +1717,6 @@ public final class Global extends ScriptObject implements Scope {
|
||||
return func;
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
private void init(final ScriptEngine engine) {
|
||||
assert Context.getGlobal() == this : "this global is not set as current";
|
||||
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import jdk.nashorn.api.scripting.NashornException;
|
||||
@ -131,7 +130,6 @@ public final class NativeError extends ScriptObject {
|
||||
|
||||
// This is called NativeError, NativeTypeError etc. to
|
||||
// associate a ECMAException with the ECMA Error object.
|
||||
@SuppressWarnings("unused")
|
||||
static void initException(final ScriptObject self) {
|
||||
// ECMAException constructor has side effects
|
||||
new ECMAException(self, null);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -140,6 +141,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getDouble(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -140,6 +141,11 @@ public final class NativeFloat64Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getDouble(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -123,16 +124,31 @@ public final class NativeInt16Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -121,16 +122,31 @@ public final class NativeInt32Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -121,16 +122,31 @@ public final class NativeInt8Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
@ -36,7 +35,6 @@ import java.util.List;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.support.TypeUtilities;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
@ -90,7 +88,11 @@ public final class NativeJava {
|
||||
*/
|
||||
@Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
|
||||
return ScriptUtils.makeSynchronizedFunction(func, obj);
|
||||
if (func instanceof ScriptFunction) {
|
||||
return ((ScriptFunction)func).makeSynchronizedFunction(obj);
|
||||
}
|
||||
|
||||
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
@ -36,9 +37,11 @@ import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.NativeJavaPackage;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
|
||||
|
||||
/**
|
||||
@ -94,33 +97,30 @@ public final class NativeJavaImporter extends ScriptObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* "No such property" call placeholder.
|
||||
*
|
||||
* This can never be called as we override {@link ScriptObject#noSuchProperty}. We do declare it here as it's a signal
|
||||
* to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a {@code noSuchProperty} on this object.
|
||||
* "No such property" handler.
|
||||
*
|
||||
* @param self self reference
|
||||
* @param name property name
|
||||
* @return never returns
|
||||
* @return value of the missing property
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE)
|
||||
public static Object __noSuchProperty__(final Object self, final Object name) {
|
||||
throw new AssertionError("__noSuchProperty__ placeholder called");
|
||||
if (! (self instanceof NativeJavaImporter)) {
|
||||
throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
|
||||
}
|
||||
return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* "No such method call" placeholder
|
||||
*
|
||||
* This can never be called as we override {@link ScriptObject#noSuchMethod}. We do declare it here as it's a signal
|
||||
* to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a noSuchProperty on this object.
|
||||
* "No such method call" handler
|
||||
*
|
||||
* @param self self reference
|
||||
* @param args arguments to method
|
||||
* @return never returns
|
||||
* @return never returns always throw TypeError
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE)
|
||||
public static Object __noSuchMethod__(final Object self, final Object... args) {
|
||||
throw new AssertionError("__noSuchMethod__ placeholder called");
|
||||
throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -127,16 +128,31 @@ public final class NativeUint16Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -128,7 +129,7 @@ public final class NativeUint32Array extends ArrayBufferView {
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
return long.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,11 +142,21 @@ public final class NativeUint32Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getLong(index);
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -127,16 +128,31 @@ public final class NativeUint8Array extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -157,16 +158,31 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(final int index) {
|
||||
return getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleOptimistic(final int index, final int programPoint) {
|
||||
return getElem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(final int index) {
|
||||
return getInt(index);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
|
||||
/**
|
||||
* A class that tracks the current lexical context of node visitation as a stack of {@code ParserContextNode} nodes. Has special
|
||||
* methods to retrieve useful subsets of the context.
|
||||
*
|
||||
* This is implemented with a primitive array and a stack pointer, because it really makes a difference
|
||||
* performance wise. None of the collection classes were optimal
|
||||
*/
|
||||
|
||||
class ParserContext {
|
||||
|
||||
private ParserContextNode[] stack;
|
||||
private int sp;
|
||||
|
||||
private static final int INITIAL_DEPTH = 16;
|
||||
|
||||
/**
|
||||
* Constructs a ParserContext,
|
||||
* initializes the stack
|
||||
*/
|
||||
public ParserContext(){
|
||||
this.sp = 0;
|
||||
this.stack = new ParserContextNode[INITIAL_DEPTH];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a new block on top of the context, making it the innermost open block.
|
||||
* @param node the new node
|
||||
* @return The node that was pushed
|
||||
*/
|
||||
public <T extends ParserContextNode> T push(final T node) {
|
||||
assert !contains(node);
|
||||
if (sp == stack.length) {
|
||||
final ParserContextNode[] newStack = new ParserContextNode[sp * 2];
|
||||
System.arraycopy(stack, 0, newStack, 0, sp);
|
||||
stack = newStack;
|
||||
}
|
||||
stack[sp] = node;
|
||||
sp++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* The topmost node on the stack
|
||||
* @return The topmost node on the stack
|
||||
*/
|
||||
public ParserContextNode peek() {
|
||||
return stack[sp - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the topmost Node from the stack.
|
||||
* @param node The node expected to be popped, used for sanity check
|
||||
* @return The removed node
|
||||
*/
|
||||
public <T extends ParserContextNode> T pop(final T node) {
|
||||
--sp;
|
||||
@SuppressWarnings("unchecked")
|
||||
final T popped = (T)stack[sp];
|
||||
stack[sp] = null;
|
||||
assert node == popped;
|
||||
|
||||
return popped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a node is on the stack.
|
||||
* @param node The node to test
|
||||
* @return true if stack contains node, false otherwise
|
||||
*/
|
||||
public boolean contains(final ParserContextNode node) {
|
||||
for (int i = 0; i < sp; i++) {
|
||||
if (stack[i] == node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
|
||||
* @return Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
|
||||
*/
|
||||
private ParserContextBreakableNode getBreakable() {
|
||||
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
|
||||
final ParserContextBreakableNode next = iter.next();
|
||||
if (next.isBreakableWithoutLabel()) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find the breakable node corresponding to this label.
|
||||
* @param labelName name of the label to search for. If null, the closest breakable node will be returned
|
||||
* unconditionally, e.g. a while loop with no label
|
||||
* @return closest breakable node
|
||||
*/
|
||||
public ParserContextBreakableNode getBreakable(final String labelName) {
|
||||
if (labelName != null) {
|
||||
final ParserContextLabelNode foundLabel = findLabel(labelName);
|
||||
if (foundLabel != null) {
|
||||
// iterate to the nearest breakable to the foundLabel
|
||||
ParserContextBreakableNode breakable = null;
|
||||
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, foundLabel); iter.hasNext(); ) {
|
||||
breakable = iter.next();
|
||||
}
|
||||
return breakable;
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return getBreakable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loop node of the current loop, or null if not inside a loop
|
||||
* @return loop noder
|
||||
*/
|
||||
public ParserContextLoopNode getCurrentLoop() {
|
||||
final Iterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, getCurrentFunction());
|
||||
return iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
|
||||
private ParserContextLoopNode getContinueTo() {
|
||||
return getCurrentLoop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the continue target node corresponding to this label.
|
||||
* @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a
|
||||
* while loop with no label
|
||||
* @return closest continue target node
|
||||
*/
|
||||
public ParserContextLoopNode getContinueTo(final String labelName) {
|
||||
if (labelName != null) {
|
||||
final ParserContextLabelNode foundLabel = findLabel(labelName);
|
||||
if (foundLabel != null) {
|
||||
// iterate to the nearest loop to the foundLabel
|
||||
ParserContextLoopNode loop = null;
|
||||
for (final NodeIterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, foundLabel); iter.hasNext(); ) {
|
||||
loop = iter.next();
|
||||
}
|
||||
return loop;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return getContinueTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function body of a function node on the stack.
|
||||
* This will trigger an assertion if node isn't present
|
||||
* @param functionNode function node
|
||||
* @return body of function node
|
||||
*/
|
||||
public ParserContextBlockNode getFunctionBody(final ParserContextFunctionNode functionNode) {
|
||||
for (int i = sp - 1; i >= 0 ; i--) {
|
||||
if (stack[i] == functionNode) {
|
||||
return (ParserContextBlockNode)stack[i + 1];
|
||||
}
|
||||
}
|
||||
throw new AssertionError(functionNode.getName() + " not on context stack");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the stack for a given label node by name
|
||||
* @param name name of the label
|
||||
* @return LabelNode if found, null otherwise
|
||||
*/
|
||||
public ParserContextLabelNode findLabel(final String name) {
|
||||
for (final Iterator<ParserContextLabelNode> iter = new NodeIterator<>(ParserContextLabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
|
||||
final ParserContextLabelNode next = iter.next();
|
||||
if (next.getLabelName().equals(name)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a statement to the current node.
|
||||
* @param statement The statement to prepend
|
||||
*/
|
||||
public void prependStatementToCurrentNode(final Statement statement) {
|
||||
assert statement != null;
|
||||
stack[sp - 1].prependStatement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a statement to the current Node.
|
||||
* @param statement The statement to append
|
||||
*/
|
||||
public void appendStatementToCurrentNode(final Statement statement) {
|
||||
assert statement != null;
|
||||
stack[sp - 1].appendStatement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the innermost function in the context.
|
||||
* @return the innermost function in the context.
|
||||
*/
|
||||
public ParserContextFunctionNode getCurrentFunction() {
|
||||
for (int i = sp - 1; i >= 0; i--) {
|
||||
if (stack[i] instanceof ParserContextFunctionNode) {
|
||||
return (ParserContextFunctionNode) stack[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
|
||||
* @return an iterator over all blocks in the context.
|
||||
*/
|
||||
public Iterator<ParserContextBlockNode> getBlocks() {
|
||||
return new NodeIterator<>(ParserContextBlockNode.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the innermost block in the context.
|
||||
* @return the innermost block in the context.
|
||||
*/
|
||||
public ParserContextBlockNode getCurrentBlock() {
|
||||
return getBlocks().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* The last statement added to the context
|
||||
* @return The last statement added to the context
|
||||
*/
|
||||
public Statement getLastStatement() {
|
||||
if (sp == 0) {
|
||||
return null;
|
||||
}
|
||||
final ParserContextNode top = stack[sp - 1];
|
||||
final int s = top.getStatements().size();
|
||||
return s == 0 ? null : top.getStatements().get(s - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all functions in the context, with the top (innermost open) function first.
|
||||
* @return an iterator over all functions in the context.
|
||||
*/
|
||||
public Iterator<ParserContextFunctionNode> getFunctions() {
|
||||
return new NodeIterator<>(ParserContextFunctionNode.class);
|
||||
}
|
||||
|
||||
private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
|
||||
private int index;
|
||||
private T next;
|
||||
private final Class<T> clazz;
|
||||
private ParserContextNode until;
|
||||
|
||||
NodeIterator(final Class<T> clazz) {
|
||||
this(clazz, null);
|
||||
}
|
||||
|
||||
NodeIterator(final Class<T> clazz, final ParserContextNode until) {
|
||||
this.index = sp - 1;
|
||||
this.clazz = clazz;
|
||||
this.until = until;
|
||||
this.next = findNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (next == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
final T lnext = next;
|
||||
next = findNext();
|
||||
return lnext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T findNext() {
|
||||
for (int i = index; i >= 0; i--) {
|
||||
final Object node = stack[i];
|
||||
if (node == until) {
|
||||
return null;
|
||||
}
|
||||
if (clazz.isAssignableFrom(node.getClass())) {
|
||||
index = i - 1;
|
||||
return (T)node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
|
||||
/**
|
||||
* Base class for parser context nodes
|
||||
*/
|
||||
abstract class ParserContextBaseNode implements ParserContextNode {
|
||||
/**
|
||||
* Flags for this node
|
||||
*/
|
||||
protected int flags;
|
||||
|
||||
private List<Statement> statements;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ParserContextBaseNode() {
|
||||
this.statements = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The flags for this node
|
||||
*/
|
||||
@Override
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single flag
|
||||
* @param flag
|
||||
* @return A single flag
|
||||
*/
|
||||
protected int getFlag(final int flag) {
|
||||
return (flags & flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flag
|
||||
* @return the new flags
|
||||
*/
|
||||
@Override
|
||||
public int setFlag(final int flag) {
|
||||
flags |= flag;
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of statements that belongs to this node
|
||||
*/
|
||||
@Override
|
||||
public List<Statement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param statements
|
||||
*/
|
||||
@Override
|
||||
public void setStatements(final List<Statement> statements) {
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Statement at the end of the Statementlist
|
||||
* @param statement The statement to add
|
||||
*/
|
||||
@Override
|
||||
public void appendStatement(final Statement statement) {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement at the begining of the statementlist
|
||||
* @param statement The statement to add
|
||||
*/
|
||||
@Override
|
||||
public void prependStatement(final Statement statement) {
|
||||
this.statements.add(0, statement);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
/**
|
||||
* A ParserContextNode that represents a block that is currently being parsed
|
||||
*/
|
||||
class ParserContextBlockNode extends ParserContextBaseNode implements ParserContextBreakableNode {
|
||||
|
||||
private final long token;
|
||||
|
||||
/**
|
||||
* Constructs a ParserContextBlockNode
|
||||
*
|
||||
* @param token The first token of the block
|
||||
*/
|
||||
public ParserContextBlockNode(final long token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBreakableWithoutLabel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token
|
||||
* @return The first token of the block
|
||||
*/
|
||||
public long getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
import jdk.nashorn.internal.ir.BreakNode;
|
||||
|
||||
/**
|
||||
* An interface that is implemented by ParserContextNodes that can
|
||||
* contain a {@link BreakNode}
|
||||
*/
|
||||
interface ParserContextBreakableNode extends ParserContextNode {
|
||||
|
||||
/**
|
||||
* Returns true if not i breakable without label, false otherwise
|
||||
* @return Returns true if not i breakable without label, false otherwise
|
||||
*/
|
||||
boolean isBreakableWithoutLabel();
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.Namespace;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IdentNode;
|
||||
|
||||
/**
|
||||
* ParserContextNode that represents a function that is currently being parsed
|
||||
*/
|
||||
class ParserContextFunctionNode extends ParserContextBaseNode {
|
||||
|
||||
/** Function name */
|
||||
private final String name;
|
||||
|
||||
/** Function identifier node */
|
||||
private final IdentNode ident;
|
||||
|
||||
/** Name space for function */
|
||||
private final Namespace namespace;
|
||||
|
||||
/** Line number for function declaration */
|
||||
private final int line;
|
||||
|
||||
/** Function node kind, see {@link FunctionNode#Kind} */
|
||||
private final FunctionNode.Kind kind;
|
||||
|
||||
/** List of parameter identifiers for function */
|
||||
private final List<IdentNode> parameters;
|
||||
|
||||
/** Token for function start */
|
||||
private final long token;
|
||||
|
||||
/** Last function token */
|
||||
private long lastToken;
|
||||
|
||||
/** Opaque node for parser end state, see {@link Parser} */
|
||||
private Object endParserState;
|
||||
|
||||
/**
|
||||
* @param token The token for the function
|
||||
* @param ident External function name
|
||||
* @param name Internal name of the function
|
||||
* @param namespace Function's namespace
|
||||
* @param line The source line of the function
|
||||
* @param kind Function kind
|
||||
* @param parameters The parameters of the function
|
||||
*/
|
||||
public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
|
||||
this.ident = ident;
|
||||
this.namespace = namespace;
|
||||
this.line = line;
|
||||
this.kind = kind;
|
||||
this.name = name;
|
||||
this.parameters = parameters;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Internal name of the function
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The external identifier for the function
|
||||
*/
|
||||
public IdentNode getIdent() {
|
||||
return ident;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if function is the program function
|
||||
*/
|
||||
public boolean isProgram() {
|
||||
return getFlag(FunctionNode.IS_PROGRAM) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if function in strict mode
|
||||
*/
|
||||
public boolean isStrict() {
|
||||
return getFlag(FunctionNode.IS_STRICT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the function has nested evals
|
||||
*/
|
||||
public boolean hasNestedEval() {
|
||||
return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any of the blocks in this function create their own scope.
|
||||
* @return true if any of the blocks in this function create their own scope.
|
||||
*/
|
||||
public boolean hasScopeBlock() {
|
||||
return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique name in the namespace of this FunctionNode
|
||||
* @param base prefix for name
|
||||
* @return base if no collision exists, otherwise a name prefix with base
|
||||
*/
|
||||
public String uniqueName(final String base) {
|
||||
return namespace.uniqueName(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return line number of the function
|
||||
*/
|
||||
public int getLineNumber() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The kind if function
|
||||
*/
|
||||
public FunctionNode.Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parameters
|
||||
* @return The parameters of the function
|
||||
*/
|
||||
public List<IdentNode> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set last token
|
||||
* @param token New last token
|
||||
*/
|
||||
public void setLastToken(final long token) {
|
||||
this.lastToken = token;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return lastToken Function's last token
|
||||
*/
|
||||
public long getLastToken() {
|
||||
return lastToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ParserState of when the parsing of this function was ended
|
||||
* @return endParserState The end parser state
|
||||
*/
|
||||
public Object getEndParserState() {
|
||||
return endParserState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ParserState of when the parsing of this function was ended
|
||||
* @param endParserState The end parser state
|
||||
*/
|
||||
public void setEndParserState(final Object endParserState) {
|
||||
this.endParserState = endParserState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the if of this function
|
||||
* @return The function id
|
||||
*/
|
||||
public int getId() {
|
||||
return isProgram() ? -1 : Token.descPosition(token);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
/**
|
||||
* ParserContextNode that represents a LabelNode
|
||||
*/
|
||||
class ParserContextLabelNode extends ParserContextBaseNode {
|
||||
|
||||
/** Name for label */
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name The name of the label
|
||||
*/
|
||||
public ParserContextLabelNode(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the label
|
||||
* @return name of label
|
||||
*/
|
||||
public String getLabelName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
/**
|
||||
* A ParserContextNode that represents a loop that is being parsed
|
||||
*/
|
||||
class ParserContextLoopNode extends ParserContextBaseNode implements ParserContextBreakableNode {
|
||||
|
||||
@Override
|
||||
public boolean isBreakableWithoutLabel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
|
||||
/**
|
||||
* Used for keeping state when needed in the parser.
|
||||
*/
|
||||
interface ParserContextNode {
|
||||
/**
|
||||
* @return The flags for this node
|
||||
*/
|
||||
public int getFlags();
|
||||
|
||||
/**
|
||||
* @param flag The flag to set
|
||||
* @return All current flags after update
|
||||
*/
|
||||
public int setFlag(final int flag);
|
||||
|
||||
/**
|
||||
* @return The list of statements that belongs to this node
|
||||
*/
|
||||
public List<Statement> getStatements();
|
||||
|
||||
/**
|
||||
* @param statements The statement list
|
||||
*/
|
||||
public void setStatements(final List<Statement> statements);
|
||||
|
||||
/**
|
||||
* Adds a Statement at the end of the Statementlist
|
||||
* @param statement The statement to add
|
||||
*/
|
||||
public void appendStatement(final Statement statement);
|
||||
|
||||
/**
|
||||
* Adds a statement at the begining of the statementlist
|
||||
* @param statement The statement to add
|
||||
*/
|
||||
public void prependStatement(final Statement statement);
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 jdk.nashorn.internal.parser;
|
||||
|
||||
/**
|
||||
* A ParserContextNode that represents a SwithcNode that is currently being parsed
|
||||
*/
|
||||
class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
|
||||
|
||||
@Override
|
||||
public boolean isBreakableWithoutLabel() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -483,7 +483,7 @@ public final class Context {
|
||||
|
||||
final int cacheSize = env._class_cache_size;
|
||||
if (cacheSize > 0) {
|
||||
classCache = new ClassCache(cacheSize);
|
||||
classCache = new ClassCache(this, cacheSize);
|
||||
}
|
||||
|
||||
if (env._persistent_cache) {
|
||||
@ -1261,17 +1261,23 @@ public final class Context {
|
||||
* Cache for compiled script classes.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
|
||||
@Logger(name="classcache")
|
||||
private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
|
||||
private final int size;
|
||||
private final ReferenceQueue<Class<?>> queue;
|
||||
private final DebugLogger log;
|
||||
|
||||
ClassCache(final int size) {
|
||||
ClassCache(final Context context, final int size) {
|
||||
super(size, 0.75f, true);
|
||||
this.size = size;
|
||||
this.queue = new ReferenceQueue<>();
|
||||
this.log = initLogger(context);
|
||||
}
|
||||
|
||||
void cache(final Source source, final Class<?> clazz) {
|
||||
if (log.isEnabled()) {
|
||||
log.info("Caching ", source, " in class cache");
|
||||
}
|
||||
put(source, new ClassReference(clazz, queue, source));
|
||||
}
|
||||
|
||||
@ -1283,9 +1289,28 @@ public final class Context {
|
||||
@Override
|
||||
public ClassReference get(final Object key) {
|
||||
for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
|
||||
remove(ref.source);
|
||||
final Source source = ref.source;
|
||||
if (log.isEnabled()) {
|
||||
log.info("Evicting ", source, " from class cache.");
|
||||
}
|
||||
remove(source);
|
||||
}
|
||||
return super.get(key);
|
||||
|
||||
final ClassReference ref = super.get(key);
|
||||
if (ref != null && log.isEnabled()) {
|
||||
log.info("Retrieved class reference for ", ref.source, " from class cache");
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugLogger initLogger(final Context context) {
|
||||
return context.getLogger(getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugLogger getLogger() {
|
||||
return log;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
|
||||
import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
@ -328,7 +327,9 @@ public final class GlobalConstants implements Loggable {
|
||||
}
|
||||
|
||||
if (!acc.mayRetry()) {
|
||||
log.info("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
|
||||
if (log.isEnabled()) {
|
||||
log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -404,7 +405,9 @@ public final class GlobalConstants implements Loggable {
|
||||
}
|
||||
|
||||
if (acc.hasBeenInvalidated() || acc.guardFailed()) {
|
||||
log.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
|
||||
if (log.isEnabled()) {
|
||||
log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -676,6 +676,22 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type of a function specialization for particular parameter types.<br>
|
||||
* <b>Be aware that the way this is implemented, it forces full materialization (compilation and installation) of
|
||||
* code for that specialization.</b>
|
||||
* @param callSiteType the parameter types at the call site. It must include the mandatory {@code callee} and
|
||||
* {@code this} parameters, so it needs to start with at least {@code ScriptFunction.class} and
|
||||
* {@code Object.class} class. Since the return type of the function is calculated from the code itself, it is
|
||||
* irrelevant and should be set to {@code Object.class}.
|
||||
* @param runtimeScope a current runtime scope. Can be null but when it's present it will be used as a source of
|
||||
* current runtime values that can improve the compiler's type speculations (and thus reduce the need for later
|
||||
* recompilations) if the specialization is not already present and thus needs to be freshly compiled.
|
||||
* @return the return type of the function specialization.
|
||||
*/
|
||||
public Class<?> getReturnType(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
return getBest(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS).type().returnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
|
||||
|
@ -209,6 +209,19 @@ public final class WithObject extends ScriptObject implements Scope {
|
||||
return super.findProperty(key, deep, start);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object invokeNoSuchProperty(final String name, final int programPoint) {
|
||||
FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
|
||||
if (find != null) {
|
||||
final Object func = find.getObjectValue();
|
||||
if (func instanceof ScriptFunction) {
|
||||
return ScriptRuntime.apply((ScriptFunction)func, expression, name);
|
||||
}
|
||||
}
|
||||
|
||||
return getProto().invokeNoSuchProperty(name, programPoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSplitState(final int state) {
|
||||
getNonWithParent().setSplitState(state);
|
||||
|
@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
@ -37,6 +38,7 @@ import java.lang.invoke.SwitchPoint;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.lookup.Lookup;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
|
||||
@ -120,6 +122,11 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
*/
|
||||
public abstract Class<?> getElementType();
|
||||
|
||||
@Override
|
||||
public Type getOptimisticType() {
|
||||
return Type.typeFor(getElementType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a continuous array element getter
|
||||
* @param get getter, sometimes combined with a has check that throws CCE on failure for relink
|
||||
|
@ -66,9 +66,9 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
|
||||
public Object[] asObjectArray() {
|
||||
final Object[] value = super.asObjectArray();
|
||||
|
||||
if (lo <= Integer.MAX_VALUE) {
|
||||
final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
|
||||
for (int i = (int)lo; i <= intHi; i++) {
|
||||
if (lo < Integer.MAX_VALUE) {
|
||||
final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
|
||||
for (int i = (int)lo; i < end; i++) {
|
||||
value[i] = ScriptRuntime.UNDEFINED;
|
||||
}
|
||||
}
|
||||
@ -81,9 +81,9 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
|
||||
final Object value = super.asArrayOfType(componentType);
|
||||
final Object undefValue = convertUndefinedValue(componentType);
|
||||
|
||||
if (lo <= Integer.MAX_VALUE) {
|
||||
final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
|
||||
for (int i = (int)lo; i <= intHi; i++) {
|
||||
if (lo < Integer.MAX_VALUE) {
|
||||
final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
|
||||
for (int i = (int)lo; i < end; i++) {
|
||||
Array.set(value, i, undefValue);
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,10 @@
|
||||
package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
@ -73,7 +73,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
|
||||
@Override
|
||||
public Object[] asObjectArray() {
|
||||
return toObjectArray();
|
||||
return toObjectArray(true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -116,9 +116,9 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
return super.asArrayOfType(componentType);
|
||||
}
|
||||
|
||||
private Object[] toObjectArray() {
|
||||
private Object[] toObjectArray(final boolean trim) {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final Object[] oarray = new Object[array.length];
|
||||
final Object[] oarray = new Object[trim ? (int)length : array.length];
|
||||
|
||||
for (int index = 0; index < length; index++) {
|
||||
oarray[index] = Integer.valueOf(array[index]);
|
||||
@ -158,7 +158,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
}
|
||||
|
||||
private ObjectArrayData convertToObject() {
|
||||
return new ObjectArrayData(toObjectArray(), (int)length);
|
||||
return new ObjectArrayData(toObjectArray(false), (int)length);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -256,11 +256,6 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
return convert(Double.class).set(index, value, strict);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOptimisticType() {
|
||||
return Type.INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(final int index) {
|
||||
return array[index];
|
||||
|
@ -27,10 +27,10 @@ package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
@ -67,12 +67,12 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
|
||||
|
||||
@Override
|
||||
public Object[] asObjectArray() {
|
||||
return toObjectArray(array, (int)length);
|
||||
return toObjectArray(true);
|
||||
}
|
||||
|
||||
private static Object[] toObjectArray(final long[] array, final int length) {
|
||||
private Object[] toObjectArray(final boolean trim) {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final Object[] oarray = new Object[array.length];
|
||||
final Object[] oarray = new Object[trim ? (int)length : array.length];
|
||||
|
||||
for (int index = 0; index < length; index++) {
|
||||
oarray[index] = Long.valueOf(array[index]);
|
||||
@ -89,7 +89,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
|
||||
return super.asArrayOfType(componentType);
|
||||
}
|
||||
|
||||
private static double[] toDoubleArray(final long[] array, final int length) {
|
||||
private double[] toDoubleArray() {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final double[] darray = new double[array.length];
|
||||
|
||||
@ -107,9 +107,9 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
|
||||
}
|
||||
final int len = (int)length;
|
||||
if (type == Double.class) {
|
||||
return new NumberArrayData(LongArrayData.toDoubleArray(array, len), len);
|
||||
return new NumberArrayData(toDoubleArray(), len);
|
||||
}
|
||||
return new ObjectArrayData(LongArrayData.toObjectArray(array, len), len);
|
||||
return new ObjectArrayData(toObjectArray(false), len);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -186,11 +186,6 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
|
||||
return convert(Double.class).set(index, value, strict);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOptimisticType() {
|
||||
return Type.LONG;
|
||||
}
|
||||
|
||||
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle();
|
||||
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle();
|
||||
|
||||
|
@ -28,10 +28,10 @@ package jdk.nashorn.internal.runtime.arrays;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ArrayData} as soon as a double has been
|
||||
@ -66,12 +66,12 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
|
||||
|
||||
@Override
|
||||
public Object[] asObjectArray() {
|
||||
return toObjectArray(array, (int)length);
|
||||
return toObjectArray(true);
|
||||
}
|
||||
|
||||
private static Object[] toObjectArray(final double[] array, final int length) {
|
||||
private Object[] toObjectArray(final boolean trim) {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final Object[] oarray = new Object[array.length];
|
||||
final Object[] oarray = new Object[trim ? (int)length : array.length];
|
||||
|
||||
for (int index = 0; index < length; index++) {
|
||||
oarray[index] = Double.valueOf(array[index]);
|
||||
@ -91,7 +91,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
|
||||
public ArrayData convert(final Class<?> type) {
|
||||
if (type != Double.class && type != Integer.class && type != Long.class) {
|
||||
final int len = (int)length;
|
||||
return new ObjectArrayData(NumberArrayData.toObjectArray(array, len), len);
|
||||
return new ObjectArrayData(toObjectArray(false), len);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -166,11 +166,6 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOptimisticType() {
|
||||
return Type.NUMBER;
|
||||
}
|
||||
|
||||
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "getElem", double.class, int.class).methodHandle();
|
||||
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
|
||||
|
||||
|
@ -26,10 +26,10 @@
|
||||
package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
@ -155,15 +155,11 @@ final class ObjectArrayData extends ContinuousArrayData {
|
||||
|
||||
@Override
|
||||
public ArrayData setEmpty(final long lo, final long hi) {
|
||||
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
|
||||
// hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive
|
||||
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOptimisticType() {
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle();
|
||||
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle();
|
||||
|
||||
|
@ -78,7 +78,7 @@ class SparseArrayData extends ArrayData {
|
||||
|
||||
for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
|
||||
final long key = entry.getKey();
|
||||
if (key <= Integer.MAX_VALUE) {
|
||||
if (key < Integer.MAX_VALUE) {
|
||||
objArray[(int)key] = entry.getValue();
|
||||
} else {
|
||||
break; // ascending key order
|
||||
|
@ -152,6 +152,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
|
||||
static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
|
||||
|
||||
private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
|
||||
private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
|
||||
private static final Type STRING_TYPE = Type.getType(String.class);
|
||||
private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
|
||||
@ -536,8 +537,8 @@ final class JavaAdapterBytecodeGenerator {
|
||||
final int argLen = originalArgTypes.length;
|
||||
final Type[] newArgTypes = new Type[argLen + 1];
|
||||
|
||||
// Insert ScriptFunction|Object as the last argument to the constructor
|
||||
final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE;
|
||||
// Insert ScriptFunction|ScriptObject as the last argument to the constructor
|
||||
final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
|
||||
newArgTypes[argLen] = extraArgumentType;
|
||||
System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
|
||||
|
||||
@ -588,6 +589,34 @@ final class JavaAdapterBytecodeGenerator {
|
||||
// Initialize converters
|
||||
generateConverterInit(mv, fromFunction);
|
||||
endInitMethod(mv);
|
||||
|
||||
if (! fromFunction) {
|
||||
newArgTypes[argLen] = OBJECT_TYPE;
|
||||
final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
|
||||
Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
|
||||
generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
// Object additional param accepting constructor - generated to handle null and undefined value
|
||||
// for script adapters. This is effectively to throw TypeError on such script adapters. See
|
||||
// JavaAdapterServices.getHandle as well.
|
||||
private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) {
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
final Class<?>[] argTypes = ctor.getParameterTypes();
|
||||
int offset = 1; // First arg is at position 1, after this.
|
||||
for (int i = 0; i < argTypes.length; ++i) {
|
||||
final Type argType = Type.getType(argTypes[i]);
|
||||
mv.load(offset, argType);
|
||||
offset += argType.getSize();
|
||||
}
|
||||
mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
|
||||
mv.visitVarInsn(ALOAD, offset);
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
|
||||
endInitMethod(mv);
|
||||
}
|
||||
|
||||
private static void endInitMethod(final InstructionAdapter mv) {
|
||||
|
@ -39,6 +39,7 @@ import jdk.nashorn.internal.codegen.DumpBytecode;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
|
||||
/**
|
||||
* This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
|
||||
@ -51,7 +52,7 @@ final class JavaAdapterClassLoader {
|
||||
private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
|
||||
private static final AccessControlContext GET_CONTEXT_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_GET_CONTEXT);
|
||||
private static final Collection<String> VISIBLE_INTERNAL_CLASS_NAMES = Collections.unmodifiableCollection(new HashSet<>(
|
||||
Arrays.asList(JavaAdapterServices.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
|
||||
Arrays.asList(JavaAdapterServices.class.getName(), ScriptObject.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
|
||||
|
||||
private final String className;
|
||||
private final byte[] classBytes;
|
||||
|
@ -47,7 +47,6 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
@ -220,7 +219,7 @@ public final class JavaAdapterServices {
|
||||
* @return the filtered return value.
|
||||
*/
|
||||
public static Object exportReturnValue(final Object obj) {
|
||||
return ScriptUtils.wrap(NashornBeansLinker.exportArgument(obj));
|
||||
return NashornBeansLinker.exportArgument(obj, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,17 +35,28 @@ import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
import jdk.nashorn.internal.runtime.ConsString;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
|
||||
/**
|
||||
* This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
|
||||
* {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
|
||||
* observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
|
||||
* observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
|
||||
* this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
|
||||
* the target method handle parameter signature is {@code Object}.
|
||||
*/
|
||||
public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
// System property to control whether to wrap ScriptObject->ScriptObjectMirror for
|
||||
// Object type arguments of Java method calls, field set and array set.
|
||||
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
|
||||
|
||||
private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
|
||||
private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
|
||||
private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
|
||||
private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
|
||||
|
||||
private final BeansLinker beansLinker = new BeansLinker();
|
||||
|
||||
@ -67,8 +78,39 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
|
||||
}
|
||||
|
||||
static Object exportArgument(final Object arg) {
|
||||
return arg instanceof ConsString ? arg.toString() : arg;
|
||||
@SuppressWarnings("unused")
|
||||
private static Object exportArgument(final Object arg) {
|
||||
return exportArgument(arg, MIRROR_ALWAYS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object exportNativeArray(final NativeArray arg) {
|
||||
return exportArgument(arg, MIRROR_ALWAYS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object exportScriptObject(final ScriptObject arg) {
|
||||
return exportArgument(arg, MIRROR_ALWAYS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object exportScriptArray(final NativeArray arg) {
|
||||
return exportArgument(arg, MIRROR_ALWAYS);
|
||||
}
|
||||
|
||||
static Object exportArgument(final Object arg, final boolean mirrorAlways) {
|
||||
if (arg instanceof ConsString) {
|
||||
return arg.toString();
|
||||
} else if (mirrorAlways && arg instanceof ScriptObject) {
|
||||
return ScriptUtils.wrap((ScriptObject)arg);
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object importResult(final Object arg) {
|
||||
return ScriptUtils.unwrap(arg);
|
||||
}
|
||||
|
||||
private static class NashornBeansLinkerServices implements LinkerServices {
|
||||
@ -80,23 +122,50 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
|
||||
@Override
|
||||
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
|
||||
final MethodHandle typed = linkerServices.asType(handle, fromType);
|
||||
|
||||
final MethodType handleType = handle.type();
|
||||
final int paramCount = handleType.parameterCount();
|
||||
assert fromType.parameterCount() == handleType.parameterCount();
|
||||
|
||||
MethodType newFromType = fromType;
|
||||
MethodHandle[] filters = null;
|
||||
for(int i = 0; i < paramCount; ++i) {
|
||||
if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
|
||||
if(filters == null) {
|
||||
final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
|
||||
if (filter != null) {
|
||||
if (filters == null) {
|
||||
filters = new MethodHandle[paramCount];
|
||||
}
|
||||
filters[i] = EXPORT_ARGUMENT;
|
||||
// "erase" specific type with Object type or else we'll get filter mismatch
|
||||
newFromType = newFromType.changeParameterType(i, Object.class);
|
||||
filters[i] = filter;
|
||||
}
|
||||
}
|
||||
|
||||
return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
|
||||
final MethodHandle typed = linkerServices.asType(handle, newFromType);
|
||||
MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
|
||||
// Filter Object typed return value for possible ScriptObjectMirror. We convert
|
||||
// ScriptObjectMirror as ScriptObject (if it is mirror from current global).
|
||||
if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
|
||||
result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
|
||||
if (handleType == Object.class) {
|
||||
if (fromType == Object.class) {
|
||||
return EXPORT_ARGUMENT;
|
||||
} else if (fromType == NativeArray.class) {
|
||||
return EXPORT_NATIVE_ARRAY;
|
||||
} else if (fromType == ScriptObject.class) {
|
||||
return EXPORT_SCRIPT_OBJECT;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
|
||||
return handleType == Object.class && fromType == Object.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,10 +173,6 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
return Implementation.asTypeLosslessReturn(this, handle, fromType);
|
||||
}
|
||||
|
||||
private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
|
||||
return handleType == Object.class && fromType == Object.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
|
||||
return linkerServices.getTypeConverter(sourceType, targetType);
|
||||
|
@ -292,7 +292,7 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object createMirror(final Object obj) {
|
||||
return ScriptUtils.wrap(obj);
|
||||
return obj instanceof ScriptObject? ScriptUtils.wrap((ScriptObject)obj) : obj;
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
|
@ -73,6 +73,7 @@ type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "
|
||||
type.error.not.an.object={0} is not an Object
|
||||
type.error.not.a.boolean={0} is not a Boolean
|
||||
type.error.not.a.date={0} is not a Date
|
||||
type.error.not.a.java.importer={0} is not a JavaImporter object
|
||||
type.error.not.a.number={0} is not a Number
|
||||
type.error.not.a.regexp={0} is not a RegExp
|
||||
type.error.not.a.string={0} is not a String
|
||||
|
@ -105,7 +105,7 @@ Object.defineProperty(this, "sync", {
|
||||
if (arguments.length < 1 || arguments.length > 2 ) {
|
||||
throw "sync(function [,object]) parameter count mismatch";
|
||||
}
|
||||
return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
|
||||
return Java.synchronized(func, syncobj);
|
||||
}
|
||||
});
|
||||
|
||||
@ -160,7 +160,7 @@ Object.defineProperty(Object.prototype, "toSource", {
|
||||
configurable: true, enumerable: false, writable: true,
|
||||
value: function(state) {
|
||||
if (! state) {
|
||||
state = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap());
|
||||
state = java.util.Collections.newSetFromMap(new java.util.HashMap());
|
||||
}
|
||||
if (state.contains(this)) {
|
||||
return "{}";
|
||||
|
58
nashorn/test/script/basic/JDK-8060011.js
Normal file
58
nashorn/test/script/basic/JDK-8060011.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8060011: Concatenating an array and converting it to Java gives wrong result
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
|
||||
function compareAsJavaArrays(a1, a2) {
|
||||
var ja1 = Java.to(a1);
|
||||
var ja2 = Java.to(a2);
|
||||
if (ja1.length !== ja2.length) {
|
||||
throw "different length";
|
||||
}
|
||||
for (var i = 0; i < ja1.length; i++) {
|
||||
if (ja1[i] !== ja2[i]) {
|
||||
throw "different element at " + i;
|
||||
}
|
||||
}
|
||||
if (java.util.Arrays.toString(ja1) !== java.util.Arrays.toString(ja2)) {
|
||||
throw "different string representation";
|
||||
}
|
||||
}
|
||||
|
||||
compareAsJavaArrays([0, 1, 2, 3],
|
||||
[0].concat([1, 2, 3]));
|
||||
compareAsJavaArrays([1000000000, 2000000000, 3000000000, 4000000000],
|
||||
[1000000000].concat([2000000000, 3000000000, 4000000000]));
|
||||
compareAsJavaArrays([0.5, 1.5, 2.5, 3.5],
|
||||
[0.5].concat([1.5, 2.5, 3.5]));
|
||||
compareAsJavaArrays(["0", "1", "2", "3"],
|
||||
["0"].concat(["1", "2", "3"]));
|
||||
|
||||
|
||||
|
54
nashorn/test/script/basic/JDK-8060101.js
Normal file
54
nashorn/test/script/basic/JDK-8060101.js
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8060101: AssertionError: __noSuchProperty__ placeholder called from NativeJavaImporter
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var constant = 0.50;
|
||||
var ind = 0.0;
|
||||
|
||||
// make sure callsites are exercised quite a few times
|
||||
// to induce megamorphic callsite for with/JavaImporter
|
||||
// combo - which triggered that AssertionError.
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var math = new JavaImporter(java.lang.StrictMath);
|
||||
ind += 10.0;
|
||||
with (math) {
|
||||
StrictMath.exp(-constant*ind);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var math = new JavaImporter(java.lang.StrictMath);
|
||||
try {
|
||||
math.Foo();
|
||||
} catch (e) {
|
||||
if (! (e instanceof TypeError)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
35
nashorn/test/script/basic/JDK-8061113.js
Normal file
35
nashorn/test/script/basic/JDK-8061113.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8061113: Boolean used as optimistic call return type
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
function testcase() {
|
||||
var a = {x:0};
|
||||
return (function () {return a.x === 0})();
|
||||
}
|
||||
print(testcase());
|
1
nashorn/test/script/basic/JDK-8061113.js.EXPECTED
Normal file
1
nashorn/test/script/basic/JDK-8061113.js.EXPECTED
Normal file
@ -0,0 +1 @@
|
||||
true
|
@ -42,7 +42,7 @@ print(list);
|
||||
|
||||
// object to Map
|
||||
obj = { foo: 333, bar: 'hello'};
|
||||
var map = ScriptUtils.convert(obj, java.util.Map.class);
|
||||
var map = ScriptUtils.wrap(obj);
|
||||
print(map instanceof java.util.Map);
|
||||
for (m in map) {
|
||||
print(m + " " + map[m]);
|
||||
|
@ -25,6 +25,8 @@
|
||||
* JDK-8044798: API for debugging Nashorn
|
||||
*
|
||||
* @test
|
||||
* @option -Dnashorn.mirror.always=false
|
||||
* @fork
|
||||
* @run
|
||||
*/
|
||||
|
||||
|
56
nashorn/test/script/nosecurity/JDK-8060688.js
Normal file
56
nashorn/test/script/nosecurity/JDK-8060688.js
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8060688: Nashorn: Generated script class name fails --verify-code for names with special chars
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var NashornEngineFactory = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
|
||||
var ScriptEngine = Java.type("javax.script.ScriptEngine");
|
||||
var ScriptContext = Java.type("javax.script.ScriptContext");
|
||||
|
||||
var factory = new NashornEngineFactory();
|
||||
|
||||
var e = factory.getScriptEngine("--verify-code");
|
||||
|
||||
function evalAndCheck(code) {
|
||||
try {
|
||||
e.eval(code);
|
||||
} catch (exp) {
|
||||
exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// check default name
|
||||
evalAndCheck("var a = 3");
|
||||
// check few names with special chars
|
||||
var scontext = e.context;
|
||||
scontext.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
|
||||
evalAndCheck("var h = 'hello'");
|
||||
scontext.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
|
||||
evalAndCheck("var foo = 'world'");
|
||||
scontext.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
|
||||
evalAndCheck("var foo = 'helloworld'");
|
@ -168,42 +168,6 @@ public class ScriptEngineSecurityTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Check that script can't implement sensitive package interfaces.
|
||||
*/
|
||||
public void checkSensitiveInterfaceImplTest() throws ScriptException {
|
||||
if (System.getSecurityManager() == null) {
|
||||
// pass vacuously
|
||||
return;
|
||||
}
|
||||
|
||||
final ScriptEngineManager m = new ScriptEngineManager();
|
||||
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||
final Object[] holder = new Object[1];
|
||||
e.put("holder", holder);
|
||||
// put an empty script object into array
|
||||
e.eval("holder[0] = {}");
|
||||
// holder[0] is an object of some subclass of ScriptObject
|
||||
final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass();
|
||||
final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
|
||||
// implementation methods for PropertyAccess class
|
||||
e.eval("function set() {}; function get() {}; function getInt(){} " +
|
||||
"function getDouble(){}; function getLong() {}; " +
|
||||
"this.delete = function () {}; function has() {}; " +
|
||||
"function hasOwnProperty() {}");
|
||||
|
||||
// get implementation of a restricted package interface
|
||||
try {
|
||||
log(Objects.toString(((Invocable)e).getInterface((Class<?>)PropertyAccessClass)));
|
||||
fail("should have thrown SecurityException");
|
||||
} catch (final Exception exp) {
|
||||
if (! (exp instanceof SecurityException)) {
|
||||
fail("SecurityException expected, got " + exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @bug 8032948: Nashorn linkages awry
|
||||
public static class FakeProxy extends Proxy {
|
||||
public FakeProxy(final InvocationHandler ih) {
|
||||
|
@ -38,6 +38,7 @@ import java.lang.reflect.Proxy;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
@ -629,6 +630,40 @@ public class ScriptEngineTest {
|
||||
assertEquals(enumerable, Boolean.FALSE);
|
||||
}
|
||||
|
||||
public static class Context {
|
||||
private Object myobj;
|
||||
|
||||
public void set(Object o) {
|
||||
myobj = o;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return myobj;
|
||||
}
|
||||
}
|
||||
|
||||
// @bug 8050977: Java8 Javascript Nashorn exception:
|
||||
// no current Global instance for nashorn
|
||||
@Test
|
||||
public void currentGlobalMissingTest() throws Exception {
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine e = manager.getEngineByName("nashorn");
|
||||
|
||||
final Context ctx = new Context();
|
||||
e.put("ctx", ctx);
|
||||
e.eval("var obj = { foo: function(str) { return str.toUpperCase() } }");
|
||||
e.eval("ctx.set(obj)");
|
||||
final Invocable inv = (Invocable)e;
|
||||
assertEquals("HELLO", inv.invokeMethod(ctx.get(), "foo", "hello"));
|
||||
// try object literal
|
||||
e.eval("ctx.set({ bar: function(str) { return str.toLowerCase() } })");
|
||||
assertEquals("hello", inv.invokeMethod(ctx.get(), "bar", "HELLO"));
|
||||
// try array literal
|
||||
e.eval("var arr = [ 'hello', 'world' ]");
|
||||
e.eval("ctx.set(arr)");
|
||||
assertEquals("helloworld", inv.invokeMethod(ctx.get(), "join", ""));
|
||||
}
|
||||
|
||||
private static void checkProperty(final ScriptEngine e, final String name)
|
||||
throws ScriptException {
|
||||
final String value = System.getProperty(name);
|
||||
|
@ -72,6 +72,7 @@ public class CompilerTest {
|
||||
options.set("print.parse", true);
|
||||
options.set("scripting", true);
|
||||
options.set("const.as.var", true);
|
||||
options.set("verify.code", true);
|
||||
|
||||
final ErrorManager errors = new ErrorManager() {
|
||||
@Override
|
||||
|
@ -325,4 +325,29 @@ public class TrustedScriptEngineTest {
|
||||
);
|
||||
assertEquals(ret, 10, "Parsed and executed OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evalDefaultFileNameTest() throws ScriptException {
|
||||
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
|
||||
final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
|
||||
// default FILENAME being "<eval>" make sure generated code bytecode verifies.
|
||||
engine.eval("var a = 3;");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evalFileNameWithSpecialCharsTest() throws ScriptException {
|
||||
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
|
||||
final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
|
||||
final ScriptContext ctxt = new SimpleScriptContext();
|
||||
// use file name with "dangerous" chars.
|
||||
ctxt.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
|
||||
engine.eval("var a = 3;");
|
||||
ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
|
||||
engine.eval("var h = 'hello';");
|
||||
ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
|
||||
engine.eval("var foo = 'world';");
|
||||
// name used by jjs shell tool for the interactive mode
|
||||
ctxt.setAttribute(ScriptEngine.FILENAME, "<shell>", ScriptContext.ENGINE_SCOPE);
|
||||
engine.eval("var foo = 'world';");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user