--- a/nashorn/make/build.xml Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/make/build.xml Thu Oct 10 13:41:19 2013 -0700
@@ -236,6 +236,10 @@
<fileset dir="${test.src.dir}/META-INF/services/"/>
</copy>
+ <copy todir="${build.test.classes.dir}/jdk/nashorn/internal/runtime/resources">
+ <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/resources"/>
+ </copy>
+
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
<fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
@@ -245,6 +249,7 @@
<jar jarfile="${nashorn.api.tests.jar}">
<fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
<fileset dir="${build.test.classes.dir}" includes="**/META-INF/**"/>
+ <fileset dir="${build.test.classes.dir}" includes="**/resources/*.js"/>
</jar>
</target>
--- a/nashorn/make/java.security.override Thu Oct 10 10:09:30 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-# We would like to avoid references from anywhere outside nashorn
-# to codegen, IR and parser packages, in particular script generated classes.
-# We ensure that by overriding "package.access" security property.
-
-# The following "package.access" value was copied from default java.security
-# of jre/lib/security and appended with nashorn sensitive packages.
-
-#
-# List of comma-separated packages that start with or equal this string
-# will cause a security exception to be thrown when
-# passed to checkPackageAccess unless the
-# corresponding RuntimePermission ("accessClassInPackage."+package) has
-# been granted.
-package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.,jdk.nashorn.tools.
--- a/nashorn/make/project.properties Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/make/project.properties Thu Oct 10 13:41:19 2013 -0700
@@ -234,7 +234,7 @@
#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
run.test.jvmargs.octane.main=${run.test.jvmargs.common}
-run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
+run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
# VM options for script tests with @fork option
test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs}
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Oct 10 13:41:19 2013 -0700
@@ -313,7 +313,7 @@
if (! Modifier.isPublic(clazz.getModifiers())) {
throw new SecurityException(getMessage("implementing.non.public.interface", clazz.getName()));
}
- Context.checkPackageAccess(clazz.getName());
+ Context.checkPackageAccess(clazz);
}
ScriptObject realSelf = null;
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Thu Oct 10 13:41:19 2013 -0700
@@ -480,6 +480,10 @@
}
//unknown parameters are promoted to object type.
+ if (newFunctionNode.hasLazyChildren()) {
+ //the final body has already been assigned as we have left the function node block body by now
+ objectifySymbols(body);
+ }
newFunctionNode = finalizeParameters(newFunctionNode);
newFunctionNode = finalizeTypes(newFunctionNode);
for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
@@ -489,11 +493,6 @@
}
}
- if (newFunctionNode.hasLazyChildren()) {
- //the final body has already been assigned as we have left the function node block body by now
- objectifySymbols(body);
- }
-
List<VarNode> syntheticInitializers = null;
if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
@@ -503,8 +502,8 @@
syntheticInitializers.add(createSyntheticInitializer(newFunctionNode.getIdent(), CALLEE, newFunctionNode));
}
- if(newFunctionNode.needsArguments()) {
- if(syntheticInitializers == null) {
+ if (newFunctionNode.needsArguments()) {
+ if (syntheticInitializers == null) {
syntheticInitializers = new ArrayList<>(1);
}
// "var arguments = :arguments"
@@ -512,12 +511,12 @@
ARGUMENTS, newFunctionNode));
}
- if(syntheticInitializers != null) {
- final List<Statement> stmts = body.getStatements();
+ if (syntheticInitializers != null) {
+ final List<Statement> stmts = newFunctionNode.getBody().getStatements();
final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
newStatements.addAll(syntheticInitializers);
newStatements.addAll(stmts);
- newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
+ newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setStatements(lc, newStatements));
}
if (returnTypes.peek().isUnknown()) {
@@ -558,12 +557,6 @@
}
@Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- assert false : "There should be no convert operators in IR during Attribution";
- return end(unaryNode);
- }
-
- @Override
public Node leaveIdentNode(final IdentNode identNode) {
final String name = identNode.getName();
@@ -991,7 +984,7 @@
@Override
public Node leaveNEW(final UnaryNode unaryNode) {
- return end(ensureSymbol(Type.OBJECT, unaryNode));
+ return end(ensureSymbol(Type.OBJECT, unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew())));
}
@Override
@@ -1082,24 +1075,6 @@
private boolean enterAssignmentNode(final BinaryNode binaryNode) {
start(binaryNode);
- final Node lhs = binaryNode.lhs();
-
- if (lhs instanceof IdentNode) {
- final Block block = lc.getCurrentBlock();
- final IdentNode ident = (IdentNode)lhs;
- final String name = ident.getName();
-
- Symbol symbol = findSymbol(block, name);
-
- if (symbol == null) {
- symbol = defineSymbol(block, name, IS_GLOBAL);
- } else {
- maybeForceScope(symbol);
- }
-
- addLocalDef(name);
- }
-
return true;
}
@@ -1112,20 +1087,33 @@
* @param binaryNode assignment node
*/
private Node leaveAssignmentNode(final BinaryNode binaryNode) {
- BinaryNode newBinaryNode = binaryNode;
-
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type type;
+ if (lhs instanceof IdentNode) {
+ final Block block = lc.getCurrentBlock();
+ final IdentNode ident = (IdentNode)lhs;
+ final String name = ident.getName();
+ final Symbol symbol = findSymbol(block, name);
+
+ if (symbol == null) {
+ defineSymbol(block, name, IS_GLOBAL);
+ } else {
+ maybeForceScope(symbol);
+ }
+
+ addLocalDef(name);
+ }
+
if (rhs.getType().isNumeric()) {
- type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ type = Type.widest(lhs.getType(), rhs.getType());
} else {
type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
}
newType(lhs.getSymbol(), type);
- return end(ensureSymbol(type, newBinaryNode));
+ return end(ensureSymbol(type, binaryNode));
}
private boolean isLocal(FunctionNode function, Symbol symbol) {
@@ -1292,7 +1280,9 @@
private Node leaveCmp(final BinaryNode binaryNode) {
ensureTypeNotUnknown(binaryNode.lhs());
ensureTypeNotUnknown(binaryNode.rhs());
-
+ Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ ensureSymbol(widest, binaryNode.lhs());
+ ensureSymbol(widest, binaryNode.rhs());
return end(ensureSymbol(Type.BOOLEAN, binaryNode));
}
@@ -1635,7 +1625,7 @@
if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
Symbol symbol = node.getSymbol();
- if(symbol.isShared() && symbol.wouldChangeType(to)) {
+ if (symbol.isShared() && symbol.wouldChangeType(to)) {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
}
newType(symbol, to);
@@ -1651,40 +1641,105 @@
return !node.isLazy();
}
- /**
- * Eg.
- *
- * var d = 17;
- * var e;
- * e = d; //initially typed as int for node type, should retype as double
- * e = object;
- *
- * var d = 17;
- * var e;
- * e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric
- * e = object;
- *
- */
+ //
+ // Eg.
+ //
+ // var d = 17;
+ // var e;
+ // e = d; //initially typed as int for node type, should retype as double
+ // e = object;
+ //
+ // var d = 17;
+ // var e;
+ // e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric
+ // e = object;
+ //
@SuppressWarnings("fallthrough")
@Override
public Node leaveBinaryNode(final BinaryNode binaryNode) {
final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
BinaryNode newBinaryNode = binaryNode;
- switch (binaryNode.tokenType()) {
- default:
- if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
+
+ if (isAdd(binaryNode)) {
+ newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
+ if (newBinaryNode.getType().isObject() && !isAddString(newBinaryNode)) {
+ return new RuntimeNode(newBinaryNode, Request.ADD);
+ }
+ } else if (binaryNode.isComparison()) {
+ final Expression lhs = newBinaryNode.lhs();
+ final Expression rhs = newBinaryNode.rhs();
+
+ Type cmpWidest = Type.widest(lhs.getType(), rhs.getType());
+
+ boolean newRuntimeNode = false, finalized = false;
+ switch (newBinaryNode.tokenType()) {
+ case EQ_STRICT:
+ case NE_STRICT:
+ if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
+ newRuntimeNode = true;
+ cmpWidest = Type.OBJECT;
+ finalized = true;
+ }
+ //fallthru
+ default:
+ if (newRuntimeNode || cmpWidest.isObject()) {
+ return new RuntimeNode(newBinaryNode, Request.requestFor(binaryNode)).setIsFinal(finalized);
+ }
break;
}
+
+ return newBinaryNode;
+ } else {
+ if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
+ return newBinaryNode;
+ }
+ checkThisAssignment(binaryNode);
newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest));
- case ADD:
newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
}
+
return newBinaryNode;
+
+ }
+
+ private boolean isAdd(final Node node) {
+ return node.isTokenType(TokenType.ADD);
+ }
+
+ /**
+ * Determine if the outcome of + operator is a string.
+ *
+ * @param node Node to test.
+ * @return true if a string result.
+ */
+ private boolean isAddString(final Node node) {
+ if (node instanceof BinaryNode && isAdd(node)) {
+ final BinaryNode binaryNode = (BinaryNode)node;
+ final Node lhs = binaryNode.lhs();
+ final Node rhs = binaryNode.rhs();
+
+ return isAddString(lhs) || isAddString(rhs);
+ }
+
+ return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString();
+ }
+
+ private void checkThisAssignment(final BinaryNode binaryNode) {
+ if (binaryNode.isAssignment()) {
+ if (binaryNode.lhs() instanceof AccessNode) {
+ final AccessNode accessNode = (AccessNode) binaryNode.lhs();
+
+ if (accessNode.getBase().getSymbol().isThis()) {
+ lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
+ }
+ }
+ }
}
});
lc.replace(currentFunctionNode, newFunctionNode);
currentFunctionNode = newFunctionNode;
} while (!changed.isEmpty());
+
return currentFunctionNode;
}
@@ -1697,7 +1752,6 @@
final Expression lhs = binaryNode.lhs();
newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
-// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
return end(ensureSymbol(destType, binaryNode));
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Thu Oct 10 13:41:19 2013 -0700
@@ -56,10 +56,6 @@
branchOptimizer(node, label, state);
}
- private void load(final Expression node) {
- codegen.load(node);
- }
-
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
final Expression rhs = unaryNode.rhs();
@@ -67,18 +63,16 @@
case NOT:
branchOptimizer(rhs, label, !state);
return;
- case CONVERT:
+ default:
if (unaryNode.getType().isBoolean()) {
branchOptimizer(rhs, label, state);
return;
}
break;
- default:
- break;
}
// convert to boolean
- load(unaryNode);
+ codegen.load(unaryNode);
method.convert(Type.BOOLEAN);
if (state) {
method.ifne(label);
@@ -90,6 +84,7 @@
private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
+ Type widest = Type.widest(lhs.getType(), rhs.getType());
switch (binaryNode.tokenType()) {
case AND:
@@ -118,45 +113,33 @@
case EQ:
case EQ_STRICT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? EQ : NE, true, label);
return;
case NE:
case NE_STRICT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? NE : EQ, true, label);
return;
case GE:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? GE : LT, !state, label);
return;
case GT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? GT : LE, !state, label);
return;
case LE:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? LE : GT, state, label);
return;
case LT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode;
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, widest);
method.conditionalJump(state ? LT : GE, state, label);
return;
@@ -164,7 +147,7 @@
break;
}
- load(binaryNode);
+ codegen.load(binaryNode);
method.convert(Type.BOOLEAN);
if (state) {
method.ifne(label);
@@ -187,7 +170,7 @@
}
}
- load(node);
+ codegen.load(node);
method.convert(Type.BOOLEAN);
if (state) {
method.ifne(label);
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Oct 10 13:41:19 2013 -0700
@@ -43,7 +43,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
@@ -60,7 +59,6 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
@@ -111,7 +109,6 @@
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.objects.Global;
@@ -217,12 +214,12 @@
* @param identNode an identity node to load
* @return the method generator used
*/
- private MethodEmitter loadIdent(final IdentNode identNode) {
+ private MethodEmitter loadIdent(final IdentNode identNode, final Type type) {
final Symbol symbol = identNode.getSymbol();
if (!symbol.isScope()) {
assert symbol.hasSlot() || symbol.isParam();
- return method.load(symbol);
+ return method.load(symbol).convert(type);
}
final String name = symbol.getName();
@@ -243,11 +240,11 @@
if (isFastScope(symbol)) {
// Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) {
- return loadSharedScopeVar(identNode.getType(), symbol, flags);
+ return loadSharedScopeVar(type, symbol, flags);
}
- return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction());
+ return loadFastScopeVar(type, symbol, flags, identNode.isFunction());
}
- return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction());
+ return method.dynamicGet(type, identNode.getName(), flags, identNode.isFunction());
}
}
@@ -313,9 +310,9 @@
return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod);
}
- private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) {
+ private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) {
loadFastScopeProto(symbol, true);
- method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE);
+ method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE);
return method;
}
@@ -359,14 +356,61 @@
* @return the method emitter used
*/
MethodEmitter load(final Expression node) {
- return load(node, false);
+ return load(node, node.hasType() ? node.getType() : null, false);
+ }
+
+ private static boolean safeLiteral(final Expression rhs) {
+ return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode);
+ }
+
+ MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) {
+ return loadBinaryOperands(lhs, rhs, type, false);
}
- private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) {
+ private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type, final boolean baseAlreadyOnStack) {
+ // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary
+ // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT
+ // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we
+ // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its
+ // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when
+ // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT.
+ // Basically, if we know that either LEFT is not an object, or RIGHT is a constant literal, then we can do the
+ // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly
+ // separate operations to preserve specification semantics.
+ final Type lhsType = lhs.getType();
+ if (lhsType.isObject() && !safeLiteral(rhs)) {
+ // Can't reorder. Load and convert separately.
+ load(lhs, lhsType, baseAlreadyOnStack);
+ load(rhs, rhs.getType(), false);
+ // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op
+ if (!lhsType.isEquivalentTo(type)) {
+ method.swap();
+ method.convert(type);
+ method.swap();
+ }
+ method.convert(type);
+ } else {
+ // Can reorder. Combine load and convert into single operations.
+ load(lhs, type, baseAlreadyOnStack);
+ load(rhs, type, false);
+ }
+
+ return method;
+ }
+
+ MethodEmitter loadBinaryOperands(final BinaryNode node) {
+ return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false);
+ }
+
+ private MethodEmitter load(final Expression node, final Type type) {
+ return load(node, type, false);
+ }
+
+ private MethodEmitter load(final Expression node, final Type type, final boolean baseAlreadyOnStack) {
final Symbol symbol = node.getSymbol();
// If we lack symbols, we just generate what we see.
- if (symbol == null) {
+ if (symbol == null || type == null) {
node.accept(this);
return method;
}
@@ -378,10 +422,10 @@
*/
final CodeGenerator codegen = this;
- node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ node.accept(new NodeVisitor<LexicalContext>(lc) {
@Override
public boolean enterIdentNode(final IdentNode identNode) {
- loadIdent(identNode);
+ loadIdent(identNode, type);
return false;
}
@@ -391,7 +435,7 @@
load(accessNode.getBase()).convert(Type.OBJECT);
}
assert method.peekType().isObject();
- method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
+ method.dynamicGet(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
return false;
}
@@ -401,7 +445,7 @@
load(indexNode.getBase()).convert(Type.OBJECT);
load(indexNode.getIndex());
}
- method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction());
+ method.dynamicGetIndex(type, getCallSiteFlags(), indexNode.isFunction());
return false;
}
@@ -410,13 +454,29 @@
// function nodes will always leave a constructed function object on stack, no need to load the symbol
// separately as in enterDefault()
functionNode.accept(codegen);
+ method.convert(type);
return false;
}
@Override
+ public boolean enterCallNode(CallNode callNode) {
+ return codegen.enterCallNode(callNode, type);
+ }
+
+ @Override
+ public boolean enterLiteralNode(LiteralNode<?> literalNode) {
+ return codegen.enterLiteralNode(literalNode, type);
+ }
+
+ @Override
public boolean enterDefault(final Node otherNode) {
+ final Node currentDiscard = codegen.lc.getCurrentDiscard();
otherNode.accept(codegen); // generate code for whatever we are looking at.
- method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
+ if(currentDiscard != otherNode) {
+ method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
+ assert method.peekType() != null;
+ method.convert(type);
+ }
return false;
}
});
@@ -583,15 +643,19 @@
return argCount;
}
+
@Override
public boolean enterCallNode(final CallNode callNode) {
+ return enterCallNode(callNode, callNode.getType());
+ }
+
+ private boolean enterCallNode(final CallNode callNode, final Type callNodeType) {
lineNumber(callNode.getLineNumber());
final List<Expression> args = callNode.getArgs();
final Expression function = callNode.getFunction();
final Block currentBlock = lc.getCurrentBlock();
final CodeGeneratorLexicalContext codegenLexicalContext = lc;
- final Type callNodeType = callNode.getType();
function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@@ -612,16 +676,14 @@
}
private void scopeCall(final IdentNode node, final int flags) {
- load(node);
- method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
+ load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
method.loadNull(); //the 'this'
method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
}
private void evalCall(final IdentNode node, final int flags) {
- load(node);
- method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
+ load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3
final Label not_eval = new Label("not_eval");
final Label eval_done = new Label("eval_done");
@@ -638,8 +700,7 @@
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
// load evaluated code
- load(evalArgs.getCode());
- method.convert(Type.OBJECT);
+ load(evalArgs.getCode(), Type.OBJECT);
// special/extra 'eval' arguments
load(evalArgs.getThis());
method.load(evalArgs.getLocation());
@@ -690,13 +751,11 @@
@Override
public boolean enterAccessNode(final AccessNode node) {
- load(node.getBase());
- method.convert(Type.OBJECT);
+ load(node.getBase(), Type.OBJECT);
method.dup();
method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true);
method.swap();
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
- assert method.peekType().equals(callNodeType);
return false;
}
@@ -727,18 +786,17 @@
@Override
public boolean enterIndexNode(final IndexNode node) {
- load(node.getBase());
- method.convert(Type.OBJECT);
+ load(node.getBase(), Type.OBJECT);
method.dup();
- load(node.getIndex());
final Type indexType = node.getIndex().getType();
if (indexType.isObject() || indexType.isBoolean()) {
- method.convert(Type.OBJECT); //TODO
+ load(node.getIndex(), Type.OBJECT); //TODO
+ } else {
+ load(node.getIndex());
}
method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true);
method.swap();
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
- assert method.peekType().equals(callNode.getType());
return false;
}
@@ -746,11 +804,9 @@
@Override
protected boolean enterDefault(final Node node) {
// Load up function.
- load(function);
- method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions
+ load(function, Type.OBJECT); //TODO, e.g. booleans can be used as functions
method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
- assert method.peekType().equals(callNode.getType());
return false;
}
@@ -853,8 +909,7 @@
final Expression init = forNode.getInit();
- load(modify);
- assert modify.getType().isObject();
+ load(modify, Type.OBJECT);
method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR);
method.store(iter);
method._goto(forNode.getContinueLabel());
@@ -1203,8 +1258,7 @@
if (element == null) {
method.loadEmpty(elementType);
} else {
- assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type";
- load(element);
+ load(element, elementType);
}
method.arraystore();
@@ -1274,7 +1328,7 @@
}
// literal values
- private MethodEmitter load(final LiteralNode<?> node) {
+ private MethodEmitter loadLiteral(final LiteralNode<?> node, final Type type) {
final Object value = node.getValue();
if (value == null) {
@@ -1294,15 +1348,26 @@
} else if (value instanceof Boolean) {
method.load((Boolean)value);
} else if (value instanceof Integer) {
- method.load((Integer)value);
+ if(type.isEquivalentTo(Type.NUMBER)) {
+ method.load(((Integer)value).doubleValue());
+ } else if(type.isEquivalentTo(Type.LONG)) {
+ method.load(((Integer)value).longValue());
+ } else {
+ method.load((Integer)value);
+ }
} else if (value instanceof Long) {
- method.load((Long)value);
+ if(type.isEquivalentTo(Type.NUMBER)) {
+ method.load(((Long)value).doubleValue());
+ } else {
+ method.load((Long)value);
+ }
} else if (value instanceof Double) {
method.load((Double)value);
} else if (node instanceof ArrayLiteralNode) {
- final ArrayType type = (ArrayType)node.getType();
- loadArray((ArrayLiteralNode)node, type);
- globalAllocateArray(type);
+ final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node;
+ final ArrayType atype = arrayLiteral.getArrayType();
+ loadArray(arrayLiteral, atype);
+ globalAllocateArray(atype);
} else {
assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value;
}
@@ -1346,8 +1411,12 @@
@Override
public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+ return enterLiteralNode(literalNode, literalNode.getType());
+ }
+
+ private boolean enterLiteralNode(final LiteralNode<?> literalNode, final Type type) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
- load(literalNode).store(literalNode.getSymbol());
+ loadLiteral(literalNode, type).convert(type).store(literalNode.getSymbol());
return false;
}
@@ -1622,10 +1691,8 @@
return enterCmp(lhs, rhs, Condition.GT, type, symbol);
case ADD:
Type widest = Type.widest(lhs.getType(), rhs.getType());
- load(lhs);
- method.convert(widest);
- load(rhs);
- method.convert(widest);
+ load(lhs, widest);
+ load(rhs, widest);
method.add();
method.convert(type);
method.store(symbol);
@@ -1638,15 +1705,15 @@
}
if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
- return false;
+ return false;
}
if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
- return false;
+ return false;
}
for (final Expression arg : args) {
- load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower
+ load(arg).convert(Type.OBJECT);
}
method.invokestatic(
@@ -1827,6 +1894,8 @@
}
if (cases.isEmpty()) {
+ // still evaluate expression for side-effects.
+ load(expression).pop();
method.label(breakLabel);
return false;
}
@@ -1901,24 +1970,15 @@
method.lookupswitch(defaultLabel, ints, labels);
}
} else {
- load(expression);
-
- if (expression.getType().isInteger()) {
- method.convert(Type.NUMBER).dup();
- method.store(tag);
- method.conditionalJump(Condition.NE, true, defaultLabel);
- } else {
- assert tag.getSymbolType().isObject();
- method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object
- method.store(tag);
- }
+ load(expression, Type.OBJECT);
+ method.store(tag);
for (final CaseNode caseNode : cases) {
final Expression test = caseNode.getTest();
if (test != null) {
method.load(tag);
- load(test);
+ load(test, Type.OBJECT);
method.invoke(ScriptRuntime.EQ_STRICT);
method.ifne(caseNode.getEntry());
}
@@ -1956,11 +2016,10 @@
final Expression expression = throwNode.getExpression();
final int position = throwNode.position();
- final int line = source.getLine(position);
+ final int line = throwNode.getLineNumber();
final int column = source.getColumn(position);
- load(expression);
- assert expression.getType().isObject();
+ load(expression, Type.OBJECT);
method.load(source.getName());
method.load(line);
@@ -2085,29 +2144,28 @@
lineNumber(varNode);
- final Symbol varSymbol = varNode.getName().getSymbol();
- assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol";
+ final IdentNode identNode = varNode.getName();
+ final Symbol identSymbol = identNode.getSymbol();
+ assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
assert method != null;
- final boolean needsScope = varSymbol.isScope();
+ final boolean needsScope = identSymbol.isScope();
if (needsScope) {
method.loadCompilerConstant(SCOPE);
}
- load(init);
if (needsScope) {
+ load(init);
int flags = CALLSITE_SCOPE | getCallSiteFlags();
- final IdentNode identNode = varNode.getName();
- final Type type = identNode.getType();
- if (isFastScope(varSymbol)) {
- storeFastScopeVar(type, varSymbol, flags);
+ if (isFastScope(identSymbol)) {
+ storeFastScopeVar(identSymbol, flags);
} else {
- method.dynamicSet(type, identNode.getName(), flags);
+ method.dynamicSet(identNode.getName(), flags);
}
} else {
- method.convert(varNode.getName().getType()); // aw: convert moved here
- method.store(varSymbol);
+ load(init, identNode.getType());
+ method.store(identSymbol);
}
return false;
@@ -2166,8 +2224,7 @@
tryLabel = null;
}
- load(expression);
- assert expression.getType().isObject() : "with expression needs to be object: " + expression;
+ load(expression, Type.OBJECT);
if (hasScope) {
// Construct a WithObject if we have a scope
@@ -2209,54 +2266,15 @@
@Override
public boolean enterADD(final UnaryNode unaryNode) {
- load(unaryNode.rhs());
- assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol();
+ load(unaryNode.rhs(), unaryNode.getType());
+ assert unaryNode.getType().isNumeric();
method.store(unaryNode.getSymbol());
-
return false;
}
@Override
public boolean enterBIT_NOT(final UnaryNode unaryNode) {
- load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol());
- return false;
- }
-
- // do this better with convert calls to method. TODO
- @Override
- public boolean enterCONVERT(final UnaryNode unaryNode) {
- final Expression rhs = unaryNode.rhs();
- final Type to = unaryNode.getType();
-
- if (to.isObject() && rhs instanceof LiteralNode) {
- final LiteralNode<?> literalNode = (LiteralNode<?>)rhs;
- final Object value = literalNode.getValue();
-
- if (value instanceof Number) {
- assert !to.isArray() : "type hygiene - cannot convert number to array: (" + to.getTypeClass().getSimpleName() + ')' + value;
- if (value instanceof Integer) {
- method.load((Integer)value);
- } else if (value instanceof Long) {
- method.load((Long)value);
- } else if (value instanceof Double) {
- method.load((Double)value);
- } else {
- assert false;
- }
- method.convert(Type.OBJECT);
- } else if (value instanceof Boolean) {
- method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class));
- } else {
- load(rhs);
- method.convert(unaryNode.getType());
- }
- } else {
- load(rhs);
- method.convert(unaryNode.getType());
- }
-
- method.store(unaryNode.getSymbol());
-
+ load(unaryNode.rhs(), Type.INT).load(-1).xor().store(unaryNode.getSymbol());
return false;
}
@@ -2274,9 +2292,7 @@
@Override
protected void evaluate() {
- load(rhs, true);
-
- method.convert(type);
+ load(rhs, type, true);
if (!isPostfix) {
if (type.isInteger()) {
method.load(isIncrement ? 1 : -1);
@@ -2342,12 +2358,11 @@
public boolean enterNOT(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.rhs();
- load(rhs);
+ load(rhs, Type.BOOLEAN);
final Label trueLabel = new Label("true");
final Label afterLabel = new Label("after");
- method.convert(Type.BOOLEAN);
method.ifne(trueLabel);
method.load(true);
method._goto(afterLabel);
@@ -2361,8 +2376,8 @@
@Override
public boolean enterSUB(final UnaryNode unaryNode) {
- load(unaryNode.rhs()).neg().store(unaryNode.getSymbol());
-
+ assert unaryNode.getType().isNumeric();
+ load(unaryNode.rhs()).convert(unaryNode.getType()).neg().store(unaryNode.getSymbol());
return false;
}
@@ -2375,9 +2390,7 @@
}
private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) {
- assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
- load(lhs);
- load(rhs);
+ loadBinaryOperands(lhs, rhs, type);
method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
method.store(symbol);
}
@@ -2391,8 +2404,7 @@
if (type.isNumeric()) {
enterNumericAdd(lhs, rhs, type, binaryNode.getSymbol());
} else {
- load(lhs).convert(Type.OBJECT);
- load(rhs).convert(Type.OBJECT);
+ loadBinaryOperands(binaryNode);
method.add();
method.store(binaryNode.getSymbol());
}
@@ -2437,13 +2449,16 @@
if (!lhsType.isEquivalentTo(rhsType)) {
//this is OK if scoped, only locals are wrong
- assert !(lhs instanceof IdentNode) || lhs.getSymbol().isScope() : new ASTWriter(binaryNode);
}
new Store<BinaryNode>(binaryNode, lhs) {
@Override
protected void evaluate() {
- load(rhs);
+ if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) {
+ load(rhs, lhsType);
+ } else {
+ load(rhs);
+ }
}
}.store();
@@ -2482,8 +2497,7 @@
@Override
protected void evaluate() {
- load(assignNode.lhs(), true).convert(opType);
- load(assignNode.rhs()).convert(opType);
+ loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), opType, true);
op();
method.convert(assignNode.getType());
}
@@ -2654,8 +2668,7 @@
protected abstract void op();
protected void evaluate(final BinaryNode node) {
- load(node.lhs());
- load(node.rhs());
+ loadBinaryOperands(node);
op();
method.store(node.getSymbol());
}
@@ -2737,11 +2750,7 @@
final Type widest = Type.widest(lhsType, rhsType);
assert widest.isNumeric() || widest.isBoolean() : widest;
- load(lhs);
- method.convert(widest);
- load(rhs);
- method.convert(widest);
-
+ loadBinaryOperands(lhs, rhs, widest);
final Label trueLabel = new Label("trueLabel");
final Label afterLabel = new Label("skip");
@@ -2860,6 +2869,12 @@
public boolean enterSHR(final BinaryNode binaryNode) {
new BinaryArith() {
@Override
+ protected void evaluate(final BinaryNode node) {
+ loadBinaryOperands(node.lhs(), node.rhs(), Type.INT);
+ op();
+ method.store(node.getSymbol());
+ }
+ @Override
protected void op() {
method.shr();
method.convert(Type.LONG).load(JSType.MAX_UINT).and();
@@ -2891,26 +2906,22 @@
final Label falseLabel = new Label("ternary_false");
final Label exitLabel = new Label("ternary_exit");
- Type widest = Type.widest(trueExpr.getType(), falseExpr.getType());
+ Type widest = Type.widest(ternaryNode.getType(), Type.widest(trueExpr.getType(), falseExpr.getType()));
if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
widest = Type.OBJECT;
}
- load(test);
- assert test.getType().isBoolean() : "lhs in ternary must be boolean";
-
+ load(test, Type.BOOLEAN);
// we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17
// will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the
// symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions
- // to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
+ // too early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
// do this property. Then we never need any conversions in CodeGenerator
method.ifeq(falseLabel);
- load(trueExpr);
- method.convert(widest);
+ load(trueExpr, widest);
method._goto(exitLabel);
method.label(falseLabel);
- load(falseExpr);
- method.convert(widest);
+ load(falseExpr, widest);
method.label(exitLabel);
method.store(symbol);
@@ -3042,8 +3053,7 @@
final BaseNode baseNode = (BaseNode)target;
final Expression base = baseNode.getBase();
- load(base);
- method.convert(Type.OBJECT);
+ load(base, Type.OBJECT);
depth += Type.OBJECT.getSlots();
if (isSelfModifying()) {
@@ -3062,10 +3072,11 @@
enterBaseNode();
final Expression index = node.getIndex();
- // could be boolean here as well
- load(index);
if (!index.getType().isNumeric()) {
- method.convert(Type.OBJECT);
+ // could be boolean here as well
+ load(index, Type.OBJECT);
+ } else {
+ load(index);
}
depth += index.getType().getSlots();
@@ -3134,8 +3145,6 @@
* need to do a conversion on non-equivalent types exists, but is
* very rare. See for example test/script/basic/access-specializer.js
*/
- method.convert(target.getType());
-
target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
protected boolean enterDefault(Node node) {
@@ -3143,24 +3152,17 @@
}
@Override
- public boolean enterUnaryNode(final UnaryNode node) {
- if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
- method.convert(node.rhs().getType());
- }
- return true;
- }
-
- @Override
public boolean enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
assert symbol != null;
if (symbol.isScope()) {
if (isFastScope(symbol)) {
- storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
+ storeFastScopeVar(symbol, CALLSITE_SCOPE | getCallSiteFlags());
} else {
- method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
+ method.dynamicSet(node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
}
} else {
+ method.convert(node.getType());
method.store(symbol);
}
return false;
@@ -3169,7 +3171,7 @@
@Override
public boolean enterAccessNode(final AccessNode node) {
- method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
+ method.dynamicSet(node.getProperty().getName(), getCallSiteFlags());
return false;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu Oct 10 13:41:19 2013 -0700
@@ -162,7 +162,7 @@
LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
- return (FunctionNode)fn.accept(new Lower());
+ return (FunctionNode)fn.accept(new Lower(compiler));
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java Thu Oct 10 13:41:19 2013 -0700
@@ -28,7 +28,7 @@
/**
* Used to track split class compilation.
*/
-public class CompileUnit {
+public class CompileUnit implements Comparable<CompileUnit> {
/** Current class name */
private final String className;
@@ -116,4 +116,9 @@
public String toString() {
return "[classname=" + className + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
}
+
+ @Override
+ public int compareTo(CompileUnit o) {
+ return className.compareTo(o.className);
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Thu Oct 10 13:41:19 2013 -0700
@@ -36,8 +36,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
-import jdk.nashorn.internal.ir.TemporarySymbols;
-
import java.io.File;
import java.lang.reflect.Field;
import java.security.AccessController;
@@ -48,18 +46,20 @@
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeSet;
import java.util.logging.Level;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import jdk.nashorn.internal.runtime.CodeInstaller;
@@ -256,8 +256,8 @@
this.sequence = sequence;
this.installer = installer;
this.constantData = new ConstantData();
- this.compileUnits = new HashSet<>();
- this.bytecode = new HashMap<>();
+ this.compileUnits = new TreeSet<>();
+ this.bytecode = new LinkedHashMap<>();
}
private void initCompiler(final FunctionNode functionNode) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu Oct 10 13:41:19 2013 -0700
@@ -28,49 +28,22 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.AccessNode;
-import jdk.nashorn.internal.ir.Assignment;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.CallNode;
-import jdk.nashorn.internal.ir.CaseNode;
-import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.IdentNode;
-import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReturnNode;
-import jdk.nashorn.internal.ir.RuntimeNode;
-import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TemporarySymbols;
-import jdk.nashorn.internal.ir.TernaryNode;
-import jdk.nashorn.internal.ir.ThrowNode;
-import jdk.nashorn.internal.ir.TypeOverride;
import jdk.nashorn.internal.ir.UnaryNode;
-import jdk.nashorn.internal.ir.VarNode;
-import jdk.nashorn.internal.ir.WhileNode;
-import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.DebugLogger;
-import jdk.nashorn.internal.runtime.JSType;
/**
* Lower to more primitive operations. After lowering, an AST has symbols and
@@ -97,272 +70,32 @@
}
@Override
- public Node leaveCallNode(final CallNode callNode) {
- // AccessSpecializer - call return type may change the access for this location
- final Node function = callNode.getFunction();
- if (function instanceof FunctionNode) {
- return setTypeOverride(callNode, ((FunctionNode)function).getReturnType());
- }
- return callNode;
- }
-
- private Node leaveUnary(final UnaryNode unaryNode) {
- return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
- }
-
- @Override
- public Node leaveADD(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- @Override
- public Node leaveBIT_NOT(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- @Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- assert unaryNode.rhs().tokenType() != TokenType.CONVERT : "convert(convert encountered. check its origin and remove it";
- return unaryNode;
- }
-
- @Override
- public Node leaveDECINC(final UnaryNode unaryNode) {
- return specialize(unaryNode).node;
- }
-
- @Override
- public Node leaveNEW(final UnaryNode unaryNode) {
- assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject();
- return unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew());
- }
-
- @Override
- public Node leaveSUB(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- /**
- * Add is a special binary, as it works not only on arithmetic, but for
- * strings etc as well.
- */
- @Override
- public Expression leaveADD(final BinaryNode binaryNode) {
- final Expression lhs = binaryNode.lhs();
- final Expression rhs = binaryNode.rhs();
-
- final Type type = binaryNode.getType();
-
- if (type.isObject()) {
- if (!isAddString(binaryNode)) {
- return new RuntimeNode(binaryNode, Request.ADD);
- }
+ public Node leaveForNode(final ForNode forNode) {
+ if (forNode.isForIn()) {
+ return forNode;
}
- return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type));
- }
-
- @Override
- public Node leaveAND(final BinaryNode binaryNode) {
- return binaryNode;
- }
-
- @Override
- public Node leaveASSIGN(final BinaryNode binaryNode) {
- final SpecializedNode specialized = specialize(binaryNode);
- final BinaryNode specBinaryNode = (BinaryNode)specialized.node;
- Type destType = specialized.type;
- if (destType == null) {
- destType = specBinaryNode.getType();
- }
- // Register assignments to this object in case this is used as constructor
- if (binaryNode.lhs() instanceof AccessNode) {
- AccessNode accessNode = (AccessNode) binaryNode.lhs();
-
- if (accessNode.getBase().getSymbol().isThis()) {
- lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
- }
- }
- return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
- }
-
- @Override
- public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
+ final Expression init = forNode.getInit();
+ final Expression test = forNode.getTest();
+ final Expression modify = forNode.getModify();
- @Override
- public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
+ assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction();
- @Override
- public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- private boolean symbolIsInteger(final Expression node) {
- final Symbol symbol = node.getSymbol();
- assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
- return true;
- }
-
- @Override
- public Node leaveBIT_AND(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveBIT_OR(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveBIT_XOR(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
+ return forNode.
+ setInit(lc, init == null ? null : discard(init)).
+ setModify(lc, modify == null ? null : discard(modify));
}
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
- // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
- // in that case, update the node type as well
- return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
+ return binaryNode.setRHS(discard(binaryNode.rhs()));
}
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
- // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
- // in that case, update the node type as well
- return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
- }
-
- @Override
- public Node leaveDIV(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
-
- @Override
- public Node leaveEQ(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ);
- }
-
- @Override
- public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ_STRICT);
- }
-
- @Override
- public Node leaveGE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GE);
- }
-
- @Override
- public Node leaveGT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GT);
- }
-
- @Override
- public Node leaveLE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LE);
- }
-
- @Override
- public Node leaveLT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LT);
- }
-
- @Override
- public Node leaveMOD(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
- @Override
- public Node leaveMUL(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
- @Override
- public Node leaveNE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE);
- }
-
- @Override
- public Node leaveNE_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE_STRICT);
- }
-
- @Override
- public Node leaveOR(final BinaryNode binaryNode) {
- return binaryNode;
- }
-
- @Override
- public Node leaveSAR(final BinaryNode binaryNode) {
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSHL(final BinaryNode binaryNode) {
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSHR(final BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol();
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSUB(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
+ return binaryNode.setLHS(discard(binaryNode.lhs()));
}
@Override
@@ -372,38 +105,12 @@
}
@Override
- public Node leaveCatchNode(final CatchNode catchNode) {
- final Expression exceptionCondition = catchNode.getExceptionCondition();
- if (exceptionCondition != null) {
- return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
- }
- return catchNode;
- }
-
- @Override
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
temporarySymbols.reuse();
return expressionStatement.setExpression(discard(expressionStatement.getExpression()));
}
@Override
- public Node leaveForNode(final ForNode forNode) {
- final Expression init = forNode.getInit();
- final Expression test = forNode.getTest();
- final Expression modify = forNode.getModify();
-
- if (forNode.isForIn()) {
- return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
- }
- assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction();
-
- return forNode.
- setInit(lc, init == null ? null : discard(init)).
- setTest(lc, test == null ? null : convert(test, Type.BOOLEAN)).
- setModify(lc, modify == null ? null : discard(modify));
- }
-
- @Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return false;
@@ -430,113 +137,6 @@
return functionNode.setState(lc, CompilationState.FINALIZED);
}
- @Override
- public Node leaveIfNode(final IfNode ifNode) {
- return ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public boolean enterLiteralNode(final LiteralNode literalNode) {
- if (literalNode instanceof ArrayLiteralNode) {
- final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
- final Expression[] array = arrayLiteralNode.getValue();
- final Type elementType = arrayLiteralNode.getElementType();
-
- for (int i = 0; i < array.length; i++) {
- final Node element = array[i];
- if (element != null) {
- array[i] = convert((Expression)element.accept(this), elementType);
- }
- }
- }
-
- return false;
- }
-
- @Override
- public Node leaveReturnNode(final ReturnNode returnNode) {
- final Expression expr = returnNode.getExpression();
- if (expr != null) {
- return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
- }
- return returnNode;
- }
-
- @Override
- public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
- final List<Expression> args = runtimeNode.getArgs();
- for (final Expression arg : args) {
- assert !arg.getType().isUnknown();
- }
- return runtimeNode;
- }
-
- @Override
- public Node leaveSwitchNode(final SwitchNode switchNode) {
- final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
-
- if (allInteger) {
- return switchNode;
- }
-
- final Expression expression = switchNode.getExpression();
- final List<CaseNode> cases = switchNode.getCases();
- final List<CaseNode> newCases = new ArrayList<>();
-
- for (final CaseNode caseNode : cases) {
- final Expression test = caseNode.getTest();
- newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
- }
-
- return switchNode.
- setExpression(lc, convert(expression, Type.OBJECT)).
- setCases(lc, newCases);
- }
-
- @Override
- public Node leaveTernaryNode(final TernaryNode ternaryNode) {
- return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN));
- }
-
- @Override
- public Node leaveThrowNode(final ThrowNode throwNode) {
- return throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
- }
-
- @Override
- public Node leaveVarNode(final VarNode varNode) {
- final Expression init = varNode.getInit();
- if (init != null) {
- final SpecializedNode specialized = specialize(varNode);
- final VarNode specVarNode = (VarNode)specialized.node;
- Type destType = specialized.type;
- if (destType == null) {
- destType = specVarNode.getName().getType();
- }
- assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type";
- final Expression convertedInit = convert(init, destType);
- temporarySymbols.reuse();
- return specVarNode.setInit(convertedInit);
- }
- temporarySymbols.reuse();
- return varNode;
- }
-
- @Override
- public Node leaveWhileNode(final WhileNode whileNode) {
- final Expression test = whileNode.getTest();
- if (test != null) {
- return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
- }
- return whileNode;
- }
-
- @Override
- public Node leaveWithNode(final WithNode withNode) {
- return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT));
- }
-
private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
if (LOG.isEnabled()) {
if (!symbol.isScope()) {
@@ -583,260 +183,6 @@
}
}
- /**
- * Exit a comparison node and do the appropriate replacements. We need to introduce runtime
- * nodes late for comparisons as types aren't known until the last minute
- *
- * Both compares and adds may turn into runtimes node at this level as when we first bump
- * into the op in Attr, we may type it according to what we know there, which may be wrong later
- *
- * e.g. i (int) < 5 -> normal compare
- * i = object
- * then the post pass that would add the conversion to the 5 needs to
- *
- * @param binaryNode binary node to leave
- * @param request runtime request
- * @return lowered cmp node
- */
- @SuppressWarnings("fallthrough")
- private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
- final Expression lhs = binaryNode.lhs();
- final Expression rhs = binaryNode.rhs();
-
- Type widest = Type.widest(lhs.getType(), rhs.getType());
-
- boolean newRuntimeNode = false, finalized = false;
- switch (request) {
- case EQ_STRICT:
- case NE_STRICT:
- if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
- newRuntimeNode = true;
- widest = Type.OBJECT;
- finalized = true;
- }
- //fallthru
- default:
- if (newRuntimeNode || widest.isObject()) {
- return new RuntimeNode(binaryNode, request).setIsFinal(finalized);
- }
- break;
- }
-
- return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest));
- }
-
- /**
- * Compute the binary arithmetic type given the lhs and an rhs of a binary expression
- * @param lhsType the lhs type
- * @param rhsType the rhs type
- * @return the correct binary type
- */
- private static Type binaryArithType(final Type lhsType, final Type rhsType) {
- if (!Compiler.shouldUseIntegerArithmetic()) {
- return Type.NUMBER;
- }
- return Type.widest(lhsType, rhsType, Type.NUMBER);
- }
-
- private Node leaveBinaryArith(final BinaryNode binaryNode) {
- final Type type = binaryArithType(binaryNode.lhs().getType(), binaryNode.rhs().getType());
- return leaveBinary(binaryNode, type, type);
- }
-
- private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
- Node b = binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
- return b;
- }
-
- /**
- * A symbol (and {@link jdk.nashorn.internal.runtime.Property}) can be tagged as "may be primitive".
- * This is used a hint for dual fields that it is even worth it to try representing this
- * field as something other than java.lang.Object.
- *
- * @param node node in which to tag symbols as primitive
- * @param to which primitive type to use for tagging
- */
- private static void setCanBePrimitive(final Node node, final Type to) {
- final HashSet<Node> exclude = new HashSet<>();
-
- node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- private void setCanBePrimitive(final Symbol symbol) {
- LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol));
- symbol.setCanBePrimitive(to);
- }
-
- @Override
- public boolean enterIdentNode(final IdentNode identNode) {
- if (!exclude.contains(identNode)) {
- setCanBePrimitive(identNode.getSymbol());
- }
- return false;
- }
-
- @Override
- public boolean enterAccessNode(final AccessNode accessNode) {
- setCanBePrimitive(accessNode.getProperty().getSymbol());
- return false;
- }
-
- @Override
- public boolean enterIndexNode(final IndexNode indexNode) {
- exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
- return true;
- }
- });
- }
-
- private static class SpecializedNode {
- final Node node;
- final Type type;
-
- SpecializedNode(Node node, Type type) {
- this.node = node;
- this.type = type;
- }
- }
-
- <T extends Expression> SpecializedNode specialize(final Assignment<T> assignment) {
- final Node node = ((Node)assignment);
- final T lhs = assignment.getAssignmentDest();
- final Expression rhs = assignment.getAssignmentSource();
-
- if (!canHaveCallSiteType(lhs)) {
- return new SpecializedNode(node, null);
- }
-
- final Type to;
- if (node.isSelfModifying()) {
- to = node.getWidestOperationType();
- } else {
- to = rhs.getType();
- }
-
- if (!isSupportedCallSiteType(to)) {
- //meaningless to specialize to boolean or object
- return new SpecializedNode(node, null);
- }
-
- final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
- final Node typePropagatedNode;
- if(newNode instanceof Expression) {
- typePropagatedNode = propagateType((Expression)newNode, to);
- } else if(newNode instanceof VarNode) {
- // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead.
- final VarNode varNode = (VarNode)newNode;
- typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to));
- } else {
- throw new AssertionError();
- }
- return new SpecializedNode(typePropagatedNode, to);
- }
-
-
- /**
- * Is this a node that can have its type overridden. This is true for
- * AccessNodes, IndexNodes and IdentNodes
- *
- * @param node the node to check
- * @return true if node can have a callsite type
- */
- private static boolean canHaveCallSiteType(final Node node) {
- return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType();
- }
-
- /**
- * Is the specialization type supported. Currently we treat booleans as objects
- * and have no special boolean type accessor, thus booleans are ignored.
- * TODO - support booleans? NASHORN-590
- *
- * @param castTo the type to check
- * @return true if call site type is supported
- */
- private static boolean isSupportedCallSiteType(final Type castTo) {
- return castTo.isNumeric(); // don't specializable for boolean
- }
-
- /**
- * Override the type of a node for e.g. access specialization of scope
- * objects. Normally a variable can only get a wider type and narrower type
- * sets are ignored. Not that a variable can still be on object type as
- * per the type analysis, but a specific access may be narrower, e.g. if it
- * is used in an arithmetic op. This overrides a type, regardless of
- * type environment and is used primarily by the access specializer
- *
- * @param node node for which to change type
- * @param to new type
- */
- @SuppressWarnings("unchecked")
- <T extends Expression> T setTypeOverride(final T node, final Type to) {
- final Type from = node.getType();
- if (!node.getType().equals(to)) {
- LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
- if (!to.isObject() && from.isObject()) {
- setCanBePrimitive(node, to);
- }
- }
- LOG.info("Type override for lhs in '", node, "' => ", to);
- return ((TypeOverride<T>)node).setType(temporarySymbols, lc, to);
- }
-
- /**
- * Add an explicit conversion. This is needed when attribution has created types
- * that do not mesh into an op type, e.g. a = b, where b is object and a is double
- * at the end of Attr, needs explicit conversion logic.
- *
- * An explicit conversion can be one of the following:
- * + Convert a literal - just replace it with another literal
- * + Convert a scope object - just replace the type of the access, e.g. get()D->get()I
- * + Explicit convert placement, e.g. a = (double)b - all other cases
- *
- * No other part of the world after {@link Attr} may introduce new symbols. This
- * is the only place.
- *
- * @param node node to convert
- * @param to destination type
- * @return conversion node
- */
- private Expression convert(final Expression node, final Type to) {
- assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
- assert node != null : "node is null";
- assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction();
- assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction();
-
- final Type from = node.getType();
-
- if (Type.areEquivalent(from, to)) {
- return node;
- }
-
- if (from.isObject() && to.isObject()) {
- return node;
- }
-
- Expression resultNode = node;
-
- if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
- final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
- if (newNode != null) {
- resultNode = newNode;
- }
- } else {
- if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
- assert node instanceof TypeOverride;
- return setTypeOverride(node, to);
- }
- resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node);
- }
-
- LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
-
- assert !node.isTerminal();
-
- //This is the only place in this file that can create new temporaries
- //FinalizeTypes may not introduce ANY node that is not a conversion.
- return temporarySymbols.ensureSymbol(lc, to, resultNode);
- }
-
private static Expression discard(final Expression node) {
if (node.getSymbol() != null) {
final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
@@ -849,82 +195,5 @@
return node;
}
- /**
- * Whenever an expression like an addition or an assignment changes type, it
- * may be that case that {@link Attr} created a symbol for an intermediate
- * result of the expression, say for an addition. This also has to be updated
- * if the expression type changes.
- *
- * Assignments use their lhs as node symbol, and in this case we can't modify
- * it. Then {@link CodeGenerator.Store} needs to do an explicit conversion.
- * This is happens very rarely.
- *
- * @param node
- * @param to
- */
- private Expression propagateType(final Expression node, final Type to) {
- Symbol symbol = node.getSymbol();
- if (symbol.isTemp() && symbol.getSymbolType() != to) {
- symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
- LOG.info("Type override for temporary in '", node, "' => ", to);
- }
- return node.setSymbol(lc, symbol);
- }
- /**
- * Determine if the outcome of + operator is a string.
- *
- * @param node Node to test.
- * @return true if a string result.
- */
- private boolean isAddString(final Node node) {
- if (node instanceof BinaryNode && node.isTokenType(TokenType.ADD)) {
- final BinaryNode binaryNode = (BinaryNode)node;
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
-
- return isAddString(lhs) || isAddString(rhs);
- }
-
- return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString();
- }
-
- /**
- * Whenever an explicit conversion is needed and the convertee is a literal, we can
- * just change the literal
- */
- class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
- private final Type type;
-
- LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
- super(parent);
- this.type = type;
- }
-
- @Override
- protected LiteralNode<?> eval() {
- final Object value = ((LiteralNode<?>)parent).getValue();
-
- LiteralNode<?> literalNode = null;
-
- if (type.isString()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
- } else if (type.isBoolean()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value));
- } else if (type.isInteger()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value));
- } else if (type.isLong()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value));
- } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value));
- }
-
- if (literalNode != null) {
- //inherit literal symbol for attr.
- literalNode = (LiteralNode<?>)literalNode.setSymbol(lc, parent.getSymbol());
- }
-
- return literalNode;
- }
- }
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Thu Oct 10 13:41:19 2013 -0700
@@ -25,6 +25,8 @@
package jdk.nashorn.internal.codegen;
+import java.util.ArrayList;
+import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
@@ -37,8 +39,10 @@
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
+import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
@@ -88,12 +92,22 @@
@Override
public Node leaveIfNode(final IfNode ifNode) {
final Node test = ifNode.getTest();
- if (test instanceof LiteralNode) {
- final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
- if (shortCut != null) {
- return new BlockStatement(ifNode.getLineNumber(), shortCut);
+ if (test instanceof LiteralNode.PrimitiveLiteralNode) {
+ final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue();
+ final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail();
+ final Block dropped = isTrue ? ifNode.getFail() : ifNode.getPass();
+ final List<Statement> statements = new ArrayList<>();
+
+ if (executed != null) {
+ statements.addAll(executed.getStatements()); // Get statements form executed branch
}
- return new EmptyNode(ifNode);
+ if (dropped != null) {
+ extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+ }
+ if (statements.isEmpty()) {
+ return new EmptyNode(ifNode);
+ }
+ return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements);
}
return ifNode;
}
@@ -101,8 +115,8 @@
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node test = ternaryNode.getTest();
- if (test instanceof LiteralNode) {
- return ((LiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
+ if (test instanceof LiteralNode.PrimitiveLiteralNode) {
+ return ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
}
return ternaryNode;
}
@@ -131,6 +145,17 @@
protected abstract LiteralNode<?> eval();
}
+ private static void extractVarNodes(final Block block, final List<Statement> statements) {
+ final LexicalContext lc = new LexicalContext();
+ block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+ @Override
+ public boolean enterVarNode(VarNode varNode) {
+ statements.add(varNode.setInit(null));
+ return false;
+ }
+ });
+ }
+
private static class UnaryNodeConstantEvaluator extends ConstantEvaluator<UnaryNode> {
UnaryNodeConstantEvaluator(final UnaryNode parent) {
super(parent);
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Thu Oct 10 13:41:19 2013 -0700
@@ -86,10 +86,13 @@
private static final DebugLogger LOG = new DebugLogger("lower");
+ // needed only to get unique eval id from code installer
+ private final Compiler compiler;
+
/**
* Constructor.
*/
- Lower() {
+ Lower(final Compiler compiler) {
super(new BlockLexicalContext() {
@Override
@@ -132,6 +135,7 @@
return block.setIsTerminal(this, false);
}
});
+ this.compiler = compiler;
}
@Override
@@ -529,11 +533,15 @@
*/
private String evalLocation(final IdentNode node) {
final Source source = lc.getCurrentFunction().getSource();
+ final int pos = node.position();
return new StringBuilder().
append(source.getName()).
append('#').
- append(source.getLine(node.position())).
- append("<eval>").
+ append(source.getLine(pos)).
+ append(':').
+ append(source.getColumn(pos)).
+ append("<eval>@").
+ append(compiler.getCodeInstaller().getUniqueEvalId()).
toString();
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Oct 10 13:41:19 2013 -0700
@@ -69,7 +69,6 @@
import java.lang.reflect.Array;
import java.util.EnumSet;
import java.util.List;
-
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -1560,7 +1559,7 @@
MethodEmitter convert(final Type to) {
final Type type = peekType().convert(method, to);
if (type != null) {
- if (peekType() != to) {
+ if (!peekType().isEquivalentTo(to)) {
debug("convert", peekType(), "->", to);
}
popType();
@@ -1790,15 +1789,14 @@
* @param name name of property
* @param flags call site flags
*/
- void dynamicSet(final Type valueType, final String name, final int flags) {
+ void dynamicSet(final String name, final int flags) {
debug("dynamic_set", name, peekType());
- Type type = valueType;
- if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
+ Type type = peekType();
+ if (type.isObject()) { //promote strings to objects etc
type = Type.OBJECT;
convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
}
-
popType(type);
popType(Type.SCOPE);
--- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Thu Oct 10 13:41:19 2013 -0700
@@ -297,11 +297,6 @@
}
@Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- return unaryNodeWeight(unaryNode);
- }
-
- @Override
public Node leaveDECINC(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java Thu Oct 10 13:41:19 2013 -0700
@@ -136,8 +136,7 @@
invokeStatic(method, JSType.TO_LONG);
} else if (to.isString()) {
invokeStatic(method, VALUE_OF);
- invokeStatic(method, JSType.TO_PRIMITIVE);
- invokeStatic(method, JSType.TO_STRING);
+ invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING);
} else if (to.isObject()) {
invokeStatic(method, VALUE_OF);
} else {
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java Thu Oct 10 13:41:19 2013 -0700
@@ -153,8 +153,7 @@
} else if (to.isBoolean()) {
invokeStatic(method, JSType.TO_BOOLEAN);
} else if (to.isString()) {
- invokeStatic(method, JSType.TO_PRIMITIVE);
- invokeStatic(method, JSType.TO_STRING);
+ invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING);
} else {
assert false : "Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Thu Oct 10 13:41:19 2013 -0700
@@ -441,7 +441,12 @@
if (type0.isArray() && type1.isArray()) {
return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
} else if (type0.isArray() != type1.isArray()) {
- return Type.OBJECT; //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
+ //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
+ return Type.OBJECT;
+ } else if (type0.isObject() && type1.isObject() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) {
+ // Object<type=String> and Object<type=ScriptFunction> will produce Object
+ // TODO: maybe find most specific common superclass?
+ return Type.OBJECT;
}
return type0.weight() > type1.weight() ? type0 : type1;
}
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -46,12 +45,12 @@
* @param property property
*/
public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) {
- super(token, finish, base, false, false);
+ super(token, finish, base, false);
this.property = property.setIsPropertyName();
}
- private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
- super(accessNode, base, isFunction, hasCallSiteType);
+ private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction) {
+ super(accessNode, base, isFunction);
this.property = property;
}
@@ -73,13 +72,6 @@
public void toString(final StringBuilder sb) {
final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true);
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
- sb.append('}');
- }
-
if (needsParen) {
sb.append('(');
}
@@ -107,21 +99,14 @@
if (this.base == base) {
return this;
}
- return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
+ return new AccessNode(this, base, property, isFunction());
}
private AccessNode setProperty(final IdentNode property) {
if (this.property == property) {
return this;
}
- return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
- }
-
- @Override
- public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- logTypeChange(type);
- final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
- return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
+ return new AccessNode(this, base, property, isFunction());
}
@Override
@@ -129,7 +114,7 @@
if (isFunction()) {
return this;
}
- return new AccessNode(this, base, property, true, hasCallSiteType());
+ return new AccessNode(this, base, property, true);
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -25,10 +25,6 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
/**
@@ -38,15 +34,13 @@
* @see IndexNode
*/
@Immutable
-public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride<BaseNode> {
+public abstract class BaseNode extends Expression implements FunctionCall {
/** Base Node. */
protected final Expression base;
private final boolean isFunction;
- private final boolean hasCallSiteType;
-
/**
* Constructor
*
@@ -54,13 +48,11 @@
* @param finish finish
* @param base base node
* @param isFunction is this a function
- * @param hasCallSiteType does this access have a callsite type
*/
- public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
+ public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) {
super(token, base.getStart(), finish);
this.base = base;
this.isFunction = isFunction;
- this.hasCallSiteType = hasCallSiteType;
}
/**
@@ -68,13 +60,11 @@
* @param baseNode node to inherit from
* @param base base
* @param isFunction is this a function
- * @param hasCallSiteType does this access have a callsite type
*/
- protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
+ protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction) {
super(baseNode);
this.base = base;
this.isFunction = isFunction;
- this.hasCallSiteType = hasCallSiteType;
}
/**
@@ -96,26 +86,4 @@
*/
public abstract BaseNode setIsFunction();
- @Override
- public boolean canHaveCallSiteType() {
- return true; //carried by the symbol and always the same nodetype==symboltype
- }
-
- /**
- * Does the access have a call site type override?
- * @return true if overridden
- */
- protected boolean hasCallSiteType() {
- return hasCallSiteType;
- }
-
- /**
- * Debug type change
- * @param type new type
- */
- protected final void logTypeChange(final Type type) {
- if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
- }
- }
}
--- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -36,9 +36,7 @@
* IR representation for a function call.
*/
@Immutable
-public final class CallNode extends LexicalContextExpression implements TypeOverride<CallNode> {
-
- private final Type type;
+public final class CallNode extends LexicalContextExpression {
/** Function identifier or function body. */
private final Expression function;
@@ -150,18 +148,16 @@
this.function = function;
this.args = args;
this.flags = 0;
- this.type = null;
this.evalArgs = null;
this.lineNumber = lineNumber;
}
- private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final Type type, final EvalArgs evalArgs) {
+ private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final EvalArgs evalArgs) {
super(callNode);
this.lineNumber = callNode.lineNumber;
this.function = function;
this.args = args;
this.flags = flags;
- this.type = type;
this.evalArgs = evalArgs;
}
@@ -175,29 +171,9 @@
@Override
public Type getType() {
- if (hasCallSiteType()) {
- return type;
- }
return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT;
}
- @Override
- public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- if (this.type == type) {
- return this;
- }
- return new CallNode(this, function, args, flags, type, evalArgs);
- }
-
- private boolean hasCallSiteType() {
- return this.type != null;
- }
-
- @Override
- public boolean canHaveCallSiteType() {
- return true;
- }
-
/**
* Assist in IR navigation.
*
@@ -212,7 +188,6 @@
setFunction((Expression)function.accept(visitor)).
setArgs(Node.accept(visitor, Expression.class, args)).
setFlags(flags).
- setType(null, lc, type).
setEvalArgs(evalArgs == null ?
null :
evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)).
@@ -229,13 +204,6 @@
@Override
public void toString(final StringBuilder sb) {
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor());
- sb.append('}');
- }
-
function.toString(sb);
sb.append('(');
@@ -271,7 +239,7 @@
if (this.args == args) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -293,7 +261,7 @@
if (this.evalArgs == evalArgs) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -321,7 +289,7 @@
if (this.function == function) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -344,6 +312,6 @@
if (this.flags == flags) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -28,9 +28,7 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -39,10 +37,11 @@
* IR representation for an identifier.
*/
@Immutable
-public final class IdentNode extends Expression implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
- private static final int PROPERTY_NAME = 1 << 0;
- private static final int INITIALIZED_HERE = 1 << 1;
- private static final int FUNCTION = 1 << 2;
+public final class IdentNode extends Expression implements PropertyKey, FunctionCall {
+ private static final int PROPERTY_NAME = 1 << 0;
+ private static final int INITIALIZED_HERE = 1 << 1;
+ private static final int FUNCTION = 1 << 2;
+ private static final int FUTURESTRICT_NAME = 1 << 3;
/** Identifier. */
private final String name;
@@ -100,19 +99,6 @@
return callSiteType != null;
}
- @Override
- public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
- if (this.callSiteType == type) {
- return this;
- }
- if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
- }
-
- return new IdentNode(this, name, type, flags);
- }
-
/**
* Assist in IR navigation.
*
@@ -153,31 +139,6 @@
}
/**
- * We can only override type if the symbol lives in the scope, as otherwise
- * it is strongly determined by the local variable already allocated.
- *
- * <p>We also return true if the symbol represents the return value of a function with a
- * non-generic return type as in this case we need to propagate the type instead of
- * converting to object, for example if the symbol is used as the left hand side of an
- * assignment such as in the code below.</p>
- *
- * <pre>
- * try {
- * return 2;
- * } finally {
- * return 3;
- * }
- * }
- * </pre>
- *
- * @return true if can have callsite type
- */
- @Override
- public boolean canHaveCallSiteType() {
- return getSymbol() != null && (getSymbol().isScope() || getSymbol().isNonGenericReturn());
- }
-
- /**
* Check if this IdentNode is a property name
* @return true if this is a property name
*/
@@ -197,6 +158,25 @@
}
/**
+ * Check if this IdentNode is a future strict name
+ * @return true if this is a future strict name
+ */
+ public boolean isFutureStrictName() {
+ return (flags & FUTURESTRICT_NAME) != 0;
+ }
+
+ /**
+ * Flag this IdentNode as a future strict name
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public IdentNode setIsFutureStrictName() {
+ if (isFutureStrictName()) {
+ return this;
+ }
+ return new IdentNode(this, name, callSiteType, flags | FUTURESTRICT_NAME);
+ }
+
+ /**
* Helper function for local def analysis.
* @return true if IdentNode is initialized on creation
*/
--- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -46,12 +45,12 @@
* @param index index for access
*/
public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
- super(token, finish, base, false, false);
+ super(token, finish, base, false);
this.index = index;
}
- private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final boolean hasCallSiteType) {
- super(indexNode, base, isFunction, hasCallSiteType);
+ private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction) {
+ super(indexNode, base, isFunction);
this.index = index;
}
@@ -69,13 +68,6 @@
public void toString(final StringBuilder sb) {
final boolean needsParen = tokenType().needsParens(base.tokenType(), true);
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
- sb.append('}');
- }
-
if (needsParen) {
sb.append('(');
}
@@ -103,7 +95,7 @@
if (this.base == base) {
return this;
}
- return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ return new IndexNode(this, base, index, isFunction());
}
/**
@@ -115,7 +107,7 @@
if(this.index == index) {
return this;
}
- return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ return new IndexNode(this, base, index, isFunction());
}
@Override
@@ -123,14 +115,7 @@
if (isFunction()) {
return this;
}
- return new IndexNode(this, base, index, true, hasCallSiteType());
- }
-
- @Override
- public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- logTypeChange(type);
- final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
- return new IndexNode(newIndexNode, base, index, isFunction(), true);
+ return new IndexNode(this, base, index, true);
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Thu Oct 10 13:41:19 2013 -0700
@@ -587,11 +587,11 @@
final FunctionNode fn = (FunctionNode)node;
final Source source = fn.getSource();
String src = source.toString();
- if (src.indexOf(File.pathSeparator) != -1) {
+ if (src.contains(File.pathSeparator)) {
src = src.substring(src.lastIndexOf(File.pathSeparator));
}
src += ' ';
- src += source.getLine(fn.getStart());
+ src += fn.getLineNumber();
sb.append(src);
}
sb.append(' ');
--- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -28,10 +28,13 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
import jdk.nashorn.internal.codegen.CompileUnit;
+import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.parser.Lexer.LexerToken;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
@@ -96,14 +99,6 @@
return value == null;
}
- /**
- * Check if the literal value is boolean true
- * @return true if literal value is boolean true
- */
- public boolean isTrue() {
- return JSType.toBoolean(value);
- }
-
@Override
public Type getType() {
return Type.typeFor(value.getClass());
@@ -259,8 +254,31 @@
return new NullLiteralNode(parent.getToken(), parent.getFinish());
}
+ /**
+ * Super class for primitive (side-effect free) literals.
+ *
+ * @param <T> the literal type
+ */
+ public static class PrimitiveLiteralNode<T> extends LiteralNode<T> {
+ private PrimitiveLiteralNode(final long token, final int finish, final T value) {
+ super(token, finish, value);
+ }
+
+ private PrimitiveLiteralNode(final PrimitiveLiteralNode<T> literalNode) {
+ super(literalNode);
+ }
+
+ /**
+ * Check if the literal value is boolean true
+ * @return true if literal value is boolean true
+ */
+ public boolean isTrue() {
+ return JSType.toBoolean(value);
+ }
+ }
+
@Immutable
- private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
+ private static final class BooleanLiteralNode extends PrimitiveLiteralNode<Boolean> {
private BooleanLiteralNode(final long token, final int finish, final boolean value) {
super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
@@ -312,7 +330,7 @@
}
@Immutable
- private static final class NumberLiteralNode extends LiteralNode<Number> {
+ private static final class NumberLiteralNode extends PrimitiveLiteralNode<Number> {
private final Type type = numberGetType(value);
@@ -374,7 +392,7 @@
return new NumberLiteralNode(parent.getToken(), parent.getFinish(), value);
}
- private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
+ private static class UndefinedLiteralNode extends PrimitiveLiteralNode<Undefined> {
private UndefinedLiteralNode(final long token, final int finish) {
super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
}
@@ -410,7 +428,7 @@
}
@Immutable
- private static class StringLiteralNode extends LiteralNode<String> {
+ private static class StringLiteralNode extends PrimitiveLiteralNode<String> {
private StringLiteralNode(final long token, final int finish, final String value) {
super(Token.recast(token, TokenType.STRING), finish, value);
}
@@ -511,18 +529,12 @@
return object;
} else if (object instanceof LiteralNode) {
return objectAsConstant(((LiteralNode<?>)object).getValue());
- } else if (object instanceof UnaryNode) {
- final UnaryNode unaryNode = (UnaryNode)object;
-
- if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) {
- return objectAsConstant(unaryNode.rhs());
- }
}
return POSTSET_MARKER;
}
- private static final class NullLiteralNode extends LiteralNode<Object> {
+ private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
private NullLiteralNode(final long token, final int finish) {
super(Token.recast(token, TokenType.OBJECT), finish, null);
@@ -767,8 +779,7 @@
return value;
}
- @Override
- public Type getType() {
+ public ArrayType getArrayType() {
if (elementType.isInteger()) {
return Type.INT_ARRAY;
} else if (elementType.isLong()) {
@@ -780,6 +791,11 @@
}
}
+ @Override
+ public Type getType() {
+ return Type.typeFor(NativeArray.class);
+ }
+
/**
* Get the element type of this array literal
* @return element type
--- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -38,7 +38,7 @@
* IR representation for a runtime call.
*/
@Immutable
-public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode> {
+public class RuntimeNode extends Expression {
/**
* Request enum used for meta-information about the runtime request
@@ -159,6 +159,36 @@
}
/**
+ * Derive a runtime node request type for a node
+ * @param node the node
+ * @return request type
+ */
+ public static Request requestFor(final Node node) {
+ assert node.isComparison();
+ switch (node.tokenType()) {
+ case EQ_STRICT:
+ return Request.EQ_STRICT;
+ case NE_STRICT:
+ return Request.NE_STRICT;
+ case EQ:
+ return Request.EQ;
+ case NE:
+ return Request.NE;
+ case LT:
+ return Request.LT;
+ case LE:
+ return Request.LE;
+ case GT:
+ return Request.GT;
+ case GE:
+ return Request.GE;
+ default:
+ assert false;
+ return null;
+ }
+ }
+
+ /**
* Is this an EQ or EQ_STRICT?
*
* @param request a request
@@ -268,9 +298,6 @@
/** Call arguments. */
private final List<Expression> args;
- /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
- private final Type callSiteType;
-
/** is final - i.e. may not be removed again, lower in the code pipeline */
private final boolean isFinal;
@@ -287,16 +314,14 @@
this.request = request;
this.args = args;
- this.callSiteType = null;
this.isFinal = false;
}
- private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Expression> args) {
+ private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final boolean isFinal, final List<Expression> args) {
super(runtimeNode);
this.request = request;
this.args = args;
- this.callSiteType = callSiteType;
this.isFinal = isFinal;
}
@@ -335,7 +360,6 @@
this.request = request;
this.args = args;
- this.callSiteType = null;
this.isFinal = false;
}
@@ -376,7 +400,7 @@
if (this.isFinal == isFinal) {
return this;
}
- return new RuntimeNode(this, request, callSiteType, isFinal, args);
+ return new RuntimeNode(this, request, isFinal, args);
}
/**
@@ -384,24 +408,7 @@
*/
@Override
public Type getType() {
- return hasCallSiteType() ? callSiteType : request.getReturnType();
- }
-
- @Override
- public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- if (this.callSiteType == type) {
- return this;
- }
- return new RuntimeNode(this, request, type, isFinal, args);
- }
-
- @Override
- public boolean canHaveCallSiteType() {
- return request == Request.ADD;
- }
-
- private boolean hasCallSiteType() {
- return callSiteType != null;
+ return request.getReturnType();
}
@Override
@@ -450,7 +457,7 @@
if (this.args == args) {
return this;
}
- return new RuntimeNode(this, request, callSiteType, isFinal, args);
+ return new RuntimeNode(this, request, isFinal, args);
}
/**
--- a/nashorn/src/jdk/nashorn/internal/ir/TypeOverride.java Thu Oct 10 10:09:30 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.ir;
-
-import jdk.nashorn.internal.codegen.types.Type;
-
-/**
- * A type override makes it possible to change the return type of a node, if we know
- * that the linker can provide it directly. For example, an identity node that is
- * in the scope, can very well look like an object to the compiler of the method it
- * is in, but if someone does (int)x, it make senses to ask for it directly
- * with an int getter instead of loading it as an object and explicitly converting it
- * by using JSType.toInt32. Especially in scenarios where the field is already stored
- * as a primitive, this will be much faster than the "object is all I see" scope
- * available in the method
- * @param <T> the type of the node implementing the interface
- */
-
-public interface TypeOverride<T extends Node> {
- /**
- * Set the override type
- *
- * @param ts temporary symbols
- * @param lc the current lexical context
- * @param type the type
- * @return a node equivalent to this one except for the requested change.
- */
- public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
-
- /**
- * Returns true if this node can have a callsite override, e.g. all scope ident nodes
- * which lead to dynamic getters can have it, local variable nodes (slots) can't.
- * Call nodes can have it unconditionally and so on
- *
- * @return true if it is possible to assign a type override to this node
- */
- public boolean canHaveCallSiteType();
-
-}
--- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Thu Oct 10 13:41:19 2013 -0700
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.parser.TokenType.BIT_NOT;
-import static jdk.nashorn.internal.parser.TokenType.CONVERT;
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
@@ -150,19 +149,10 @@
final TokenType type = tokenType();
final String name = type.getName();
final boolean isPostfix = type == DECPOSTFIX || type == INCPOSTFIX;
- final boolean isConvert = type == CONVERT && getSymbol() != null;
boolean rhsParen = type.needsParens(rhs().tokenType(), false);
- int convertPos = 0;
- if (isConvert) {
- convertPos = sb.length();
- sb.append("(");
- sb.append(getType());
- sb.append(")(");
- }
-
- if (!isPostfix && !isConvert) {
+ if (!isPostfix) {
if (name == null) {
sb.append(type.name());
rhsParen = true;
@@ -186,16 +176,6 @@
if (isPostfix) {
sb.append(type == DECPOSTFIX ? "--" : "++");
}
-
- if (isConvert) {
- // strip extra cast parenthesis which makes the printout harder to read
- final boolean endsWithParenthesis = sb.charAt(sb.length() - 1) == ')';
- if (!endsWithParenthesis) {
- sb.append(')');
- } else {
- sb.setCharAt(convertPos, ' ');
- }
- }
}
/**
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Thu Oct 10 13:41:19 2013 -0700
@@ -51,8 +51,6 @@
return enterADD(unaryNode);
case BIT_NOT:
return enterBIT_NOT(unaryNode);
- case CONVERT:
- return enterCONVERT(unaryNode);
case DELETE:
return enterDELETE(unaryNode);
case DISCARD:
@@ -84,8 +82,6 @@
return leaveADD(unaryNode);
case BIT_NOT:
return leaveBIT_NOT(unaryNode);
- case CONVERT:
- return leaveCONVERT(unaryNode);
case DELETE:
return leaveDELETE(unaryNode);
case DISCARD:
@@ -323,26 +319,6 @@
}
/**
- * Unary enter - callback for entering a conversion
- *
- * @param unaryNode the node
- * @return true if traversal should continue and node children be traversed, false otherwise
- */
- public boolean enterCONVERT(final UnaryNode unaryNode) {
- return enterDefault(unaryNode);
- }
-
- /**
- * Unary leave - callback for leaving a conversion
- *
- * @param unaryNode the node
- * @return processed node, which will replace the original one, or the original node
- */
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- return leaveDefault(unaryNode);
- }
-
- /**
* Unary enter - callback for entering a ++ or -- operator
*
* @param unaryNode the node
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Thu Oct 10 13:41:19 2013 -0700
@@ -819,8 +819,15 @@
if (bulkable(sobj)) {
sobj.getArray().shiftLeft(1);
} else {
+ boolean hasPrevious = true;
for (long k = 1; k < len; k++) {
- sobj.set(k - 1, sobj.get(k), true);
+ boolean hasCurrent = sobj.has(k);
+ if (hasCurrent) {
+ sobj.set(k - 1, sobj.get(k), true);
+ } else if (hasPrevious) {
+ sobj.delete(k - 1, true);
+ }
+ hasPrevious = hasCurrent;
}
}
sobj.delete(--len, true);
@@ -844,6 +851,10 @@
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object slice(final Object self, final Object start, final Object end) {
final Object obj = Global.toObject(self);
+ if (!(obj instanceof ScriptObject)) {
+ return ScriptRuntime.UNDEFINED;
+ }
+
final ScriptObject sobj = (ScriptObject)obj;
final long len = JSType.toUint32(sobj.getLength());
final long relativeStart = JSType.toLong(start);
@@ -860,9 +871,12 @@
return new NativeArray(sobj.getArray().slice(k, finale));
}
- final NativeArray copy = new NativeArray(0);
+ // Construct array with proper length to have a deleted filter on undefined elements
+ final NativeArray copy = new NativeArray(finale - k);
for (long n = 0; k < finale; n++, k++) {
- copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k));
+ if (sobj.has(k)) {
+ copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k));
+ }
}
return copy;
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java Thu Oct 10 13:41:19 2013 -0700
@@ -37,10 +37,12 @@
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
@@ -138,7 +140,10 @@
Global.checkObject(errorObj);
final ScriptObject sobj = (ScriptObject)errorObj;
final ECMAException exp = new ECMAException(sobj, null);
- sobj.set("stack", getScriptStackString(sobj, exp), false);
+ sobj.delete("stack", false);
+ final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
+ final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
+ sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
return UNDEFINED;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java Thu Oct 10 13:41:19 2013 -0700
@@ -221,6 +221,7 @@
final StringBuilder sb = new StringBuilder();
sb.append("(function (");
+ final String funcBody;
if (args.length > 0) {
final StringBuilder paramListBuf = new StringBuilder();
for (int i = 0; i < args.length - 1; i++) {
@@ -230,15 +231,20 @@
}
}
+ // now convert function body to a string
+ funcBody = JSType.toString(args[args.length - 1]);
+
final String paramList = paramListBuf.toString();
if (! paramList.isEmpty()) {
checkFunctionParameters(paramList);
sb.append(paramList);
}
+ } else {
+ funcBody = null;
}
+
sb.append(") {\n");
if (args.length > 0) {
- final String funcBody = JSType.toString(args[args.length - 1]);
checkFunctionBody(funcBody);
sb.append(funcBody);
sb.append('\n');
--- a/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java Thu Oct 10 13:41:19 2013 -0700
@@ -378,7 +378,7 @@
next();
// Create IDENT node.
- return new IdentNode(identToken, finish, ident);
+ return new IdentNode(identToken, finish, ident).setIsFutureStrictName();
}
// Get IDENT.
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java Thu Oct 10 13:41:19 2013 -0700
@@ -909,6 +909,10 @@
default:
break;
}
+
+ if (ident.isFutureStrictName()) {
+ throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
+ }
}
}
@@ -2436,7 +2440,7 @@
// name is null, generate anonymous name
boolean isAnonymous = false;
if (name == null) {
- final String tmpName = "_L" + source.getLine(Token.descPosition(token));
+ final String tmpName = "_L" + functionLine;
name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
isAnonymous = true;
}
--- a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java Thu Oct 10 13:41:19 2013 -0700
@@ -178,7 +178,6 @@
ARRAY (LITERAL, null),
COMMALEFT (IR, null),
- CONVERT (IR, null),
DISCARD (IR, null),
DECPOSTFIX (IR, null),
INCPOSTFIX (IR, null);
--- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Oct 10 13:41:19 2013 -0700
@@ -68,4 +68,10 @@
* @return unique script id
*/
public long getUniqueScriptId();
+
+ /**
+ * Get next unique eval id
+ * @return unique eval id
+ */
+ public long getUniqueEvalId();
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java Thu Oct 10 13:41:19 2013 -0700
@@ -48,6 +48,7 @@
}
CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) {
+ assert type != null;
this.type = type;
this.invoker = invoker;
this.constructor = constructor;
@@ -80,7 +81,37 @@
@Override
public int compareTo(final CompiledFunction o) {
- return weight() - o.weight();
+ return compareMethodTypes(type(), o.type());
+ }
+
+ private static int compareMethodTypes(final MethodType ownType, final MethodType otherType) {
+ // Comparable interface demands that compareTo() should only return 0 if objects are equal.
+ // Failing to meet this requirement causes same weight functions to replace each other in TreeSet,
+ // so we go some lengths to come up with an ordering between same weight functions,
+ // first falling back to parameter count and then to hash code.
+ if (ownType.equals(otherType)) {
+ return 0;
+ }
+
+ final int diff = weight(ownType) - weight(otherType);
+ if (diff != 0) {
+ return diff;
+ }
+ if (ownType.parameterCount() != otherType.parameterCount()) {
+ return ownType.parameterCount() - otherType.parameterCount();
+ }
+ // We're just interested in not returning 0 here, not correct ordering
+ return ownType.hashCode() - otherType.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof CompiledFunction && type().equals(((CompiledFunction)obj).type());
+ }
+
+ @Override
+ public int hashCode() {
+ return type().hashCode();
}
private int weight() {
@@ -119,14 +150,14 @@
* a semantically equivalent linkage can be performed.
*
* @param mt type to check against
- * @return
+ * @return true if types are compatible
*/
boolean typeCompatible(final MethodType mt) {
- final Class<?>[] wantedParams = mt.parameterArray();
- final Class<?>[] existingParams = type().parameterArray();
+ final int wantedParamCount = mt.parameterCount();
+ final int existingParamCount = type.parameterCount();
//if we are not examining a varargs type, the number of parameters must be the same
- if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) {
+ if (wantedParamCount != existingParamCount && !isVarArgsType(mt)) {
return false;
}
@@ -134,10 +165,10 @@
//parameters lengths do not match is if our type ends with a varargs argument.
//then every trailing parameter in the given callsite can be folded into it, making
//us compatible (albeit slower than a direct specialization)
- final int lastParamIndex = Math.min(wantedParams.length, existingParams.length);
+ final int lastParamIndex = Math.min(wantedParamCount, existingParamCount);
for (int i = 0; i < lastParamIndex; i++) {
- final Type w = Type.typeFor(wantedParams[i]);
- final Type e = Type.typeFor(existingParams[i]);
+ final Type w = Type.typeFor(mt.parameterType(i));
+ final Type e = Type.typeFor(type.parameterType(i));
//don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
//we also currently don't support boolean as a javascript function callsite type.
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Thu Oct 10 13:41:19 2013 -0700
@@ -91,6 +91,11 @@
*/
public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
+ // nashorn load psuedo URL prefixes
+ private static final String LOAD_CLASSPATH = "classpath:";
+ private static final String LOAD_FX = "fx:";
+ private static final String LOAD_NASHORN = "nashorn:";
+
/* Force DebuggerSupport to be loaded. */
static {
DebuggerSupport.FORCELOAD = true;
@@ -134,6 +139,11 @@
public long getUniqueScriptId() {
return context.getUniqueScriptId();
}
+
+ @Override
+ public long getUniqueEvalId() {
+ return context.getUniqueEvalId();
+ }
}
/** Is Context global debug mode enabled ? */
@@ -233,6 +243,9 @@
/** Unique id for script. Used only when --loader-per-compile=false */
private final AtomicLong uniqueScriptId;
+ /** Unique id for 'eval' */
+ private final AtomicLong uniqueEvalId;
+
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
@@ -315,6 +328,7 @@
this.uniqueScriptId = new AtomicLong();
}
this.errors = errors;
+ this.uniqueEvalId = new AtomicLong();
// if user passed -classpath option, make a class loader with that and set it as
// thread context class loader so that script can access classes from that path.
@@ -501,21 +515,26 @@
// or a ScriptObject that has "name" and "source" (string valued) properties.
if (src instanceof String) {
final String srcStr = (String)src;
- final File file = new File(srcStr);
- if (srcStr.indexOf(':') != -1) {
- if ((source = loadInternal(srcStr, "nashorn:", "resources/")) == null &&
- (source = loadInternal(srcStr, "fx:", "resources/fx/")) == null) {
- URL url;
- try {
- //check for malformed url. if malformed, it may still be a valid file
- url = new URL(srcStr);
- } catch (final MalformedURLException e) {
- url = file.toURI().toURL();
+ if (srcStr.startsWith(LOAD_CLASSPATH)) {
+ URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
+ source = (url != null)? new Source(url.toString(), url) : null;
+ } else {
+ final File file = new File(srcStr);
+ if (srcStr.indexOf(':') != -1) {
+ if ((source = loadInternal(srcStr, LOAD_NASHORN, "resources/")) == null &&
+ (source = loadInternal(srcStr, LOAD_FX, "resources/fx/")) == null) {
+ URL url;
+ try {
+ //check for malformed url. if malformed, it may still be a valid file
+ url = new URL(srcStr);
+ } catch (final MalformedURLException e) {
+ url = file.toURI().toURL();
+ }
+ source = new Source(url.toString(), url);
}
- source = new Source(url.toString(), url);
+ } else if (file.isFile()) {
+ source = new Source(srcStr, file);
}
- } else if (file.isFile()) {
- source = new Source(srcStr, file);
}
} else if (src instanceof File && ((File)src).isFile()) {
final File file = (File)src;
@@ -610,36 +629,53 @@
}
/**
- * Checks that the given package can be accessed from no permissions context.
+ * Checks that the given Class can be accessed from no permissions context.
*
- * @param fullName fully qualified package name
+ * @param clazz Class object
* @throw SecurityException if not accessible
*/
- public static void checkPackageAccess(final String fullName) {
- final int index = fullName.lastIndexOf('.');
- if (index != -1) {
- final SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- sm.checkPackageAccess(fullName.substring(0, index));
- return null;
- }
- }, NO_PERMISSIONS_ACC_CTXT);
+ public static void checkPackageAccess(final Class<?> clazz) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ Class<?> bottomClazz = clazz;
+ while (bottomClazz.isArray()) {
+ bottomClazz = bottomClazz.getComponentType();
}
+ checkPackageAccess(sm, bottomClazz.getName());
}
}
/**
* Checks that the given package can be accessed from no permissions context.
*
+ * @param sm current security manager instance
* @param fullName fully qualified package name
+ * @throw SecurityException if not accessible
+ */
+ private static void checkPackageAccess(final SecurityManager sm, final String fullName) {
+ sm.getClass(); // null check
+ final int index = fullName.lastIndexOf('.');
+ if (index != -1) {
+ final String pkgName = fullName.substring(0, index);
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ sm.checkPackageAccess(pkgName);
+ return null;
+ }
+ }, NO_PERMISSIONS_ACC_CTXT);
+ }
+ }
+
+ /**
+ * Checks that the given Class can be accessed from no permissions context.
+ *
+ * @param clazz Class object
* @return true if package is accessible, false otherwise
*/
- public static boolean isAccessiblePackage(final String fullName) {
+ private static boolean isAccessiblePackage(final Class<?> clazz) {
try {
- checkPackageAccess(fullName);
+ checkPackageAccess(clazz);
return true;
} catch (final SecurityException se) {
return false;
@@ -653,7 +689,7 @@
* @return true if Class is accessible, false otherwise
*/
public static boolean isAccessibleClass(final Class<?> clazz) {
- return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz.getName());
+ return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz);
}
/**
@@ -667,8 +703,16 @@
* @throws ClassNotFoundException if class cannot be resolved
*/
public Class<?> findClass(final String fullName) throws ClassNotFoundException {
+ if (fullName.indexOf('[') != -1 || fullName.indexOf('/') != -1) {
+ // don't allow array class names or internal names.
+ throw new ClassNotFoundException(fullName);
+ }
+
// check package access as soon as possible!
- checkPackageAccess(fullName);
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ checkPackageAccess(sm, fullName);
+ }
// try the script -classpath loader, if that is set
if (classPathLoader != null) {
@@ -803,6 +847,18 @@
return Context.getContextTrusted();
}
+ private URL getResourceURL(final String resName) {
+ // try the classPathLoader if we have and then
+ // try the appLoader if non-null.
+ if (classPathLoader != null) {
+ return classPathLoader.getResource(resName);
+ } else if (appLoader != null) {
+ return appLoader.getResource(resName);
+ }
+
+ return null;
+ }
+
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
ScriptFunction script = null;
@@ -907,6 +963,10 @@
}, CREATE_LOADER_ACC_CTXT);
}
+ private long getUniqueEvalId() {
+ return uniqueEvalId.getAndIncrement();
+ }
+
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Thu Oct 10 13:41:19 2013 -0700
@@ -104,14 +104,11 @@
/** JavaScript compliant conversion function from number to int64 */
public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class);
- /** JavaScript compliant conversion function from Object to String */
- public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class);
-
/** JavaScript compliant conversion function from number to String */
public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class);
- /** JavaScript compliant conversion function from Object to primitive */
- public static final Call TO_PRIMITIVE = staticCall(myLookup, JSType.class, "toPrimitive", Object.class, Object.class);
+ /** Combined call to toPrimitive followed by toString. */
+ public static final Call TO_PRIMITIVE_TO_STRING = staticCall(myLookup, JSType.class, "toPrimitiveToString", String.class, Object.class);
private static final double INT32_LIMIT = 4294967296.0;
@@ -273,6 +270,17 @@
}
/**
+ * Combines a hintless toPrimitive and a toString call.
+ *
+ * @param obj an object
+ *
+ * @return the string form of the primitive form of the object
+ */
+ public static String toPrimitiveToString(Object obj) {
+ return toString(toPrimitive(obj));
+ }
+
+ /**
* JavaScript compliant conversion of number to boolean
*
* @param num a number
@@ -874,7 +882,7 @@
if (obj instanceof ScriptObject) {
return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType);
} else if (obj instanceof JSObject) {
- final ArrayLikeIterator itr = ArrayLikeIterator.arrayLikeIterator(obj);
+ final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
final int len = (int) itr.getLength();
final Object[] res = new Object[len];
int idx = 0;
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Oct 10 13:41:19 2013 -0700
@@ -132,7 +132,7 @@
if (source != null) {
sb.append(source.getName())
.append(':')
- .append(source.getLine(Token.descPosition(token)))
+ .append(functionNode.getLineNumber())
.append(' ');
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java Thu Oct 10 13:41:19 2013 -0700
@@ -272,6 +272,10 @@
/**
* Return line number of character position.
+ *
+ * <p>This method can be expensive for large sources as it iterates through
+ * all characters up to {@code position}.</p>
+ *
* @param position Position of character in source content.
* @return Line number.
*/
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java Thu Oct 10 13:41:19 2013 -0700
@@ -77,4 +77,4 @@
public void remove() {
throw new UnsupportedOperationException("remove");
}
-}
\ No newline at end of file
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java Thu Oct 10 13:41:19 2013 -0700
@@ -55,4 +55,4 @@
protected long bumpIndex() {
return index--;
}
-}
\ No newline at end of file
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Thu Oct 10 13:41:19 2013 -0700
@@ -140,7 +140,7 @@
@SuppressWarnings("unused")
private static Object get(final Object jsobj, final Object key) {
if (key instanceof Integer) {
- return ((JSObject)jsobj).getSlot((int)(Integer)key);
+ return ((JSObject)jsobj).getSlot((Integer)key);
} else if (key instanceof Number) {
final int index = getIndex((Number)key);
if (index > -1) {
@@ -155,7 +155,7 @@
@SuppressWarnings("unused")
private static void put(final Object jsobj, final Object key, final Object value) {
if (key instanceof Integer) {
- ((JSObject)jsobj).setSlot((int)(Integer)key, value);
+ ((JSObject)jsobj).setSlot((Integer)key, value);
} else if (key instanceof Number) {
((JSObject)jsobj).setSlot(getIndex((Number)key), value);
} else if (key instanceof String) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Thu Oct 10 13:41:19 2013 -0700
@@ -109,7 +109,7 @@
if (sm != null) {
for (Class<?> type : types) {
// check for restricted package access
- Context.checkPackageAccess(type.getName());
+ Context.checkPackageAccess(type);
}
}
return getAdapterInfo(types).getAdapterClassFor(classOverrides);
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Thu Oct 10 13:41:19 2013 -0700
@@ -70,7 +70,7 @@
// We intercept "new" on StaticClass instances to provide additional capabilities
if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
// make sure new is on accessible Class
- Context.checkPackageAccess(receiverClass.getName());
+ Context.checkPackageAccess(receiverClass);
// Is the class abstract? (This includes interfaces.)
if (NashornLinker.isAbstractClass(receiverClass)) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/base.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/base.js Thu Oct 10 13:41:19 2013 -0700
@@ -33,7 +33,6 @@
var JFX_SWT_CLASSES = [];
function LOAD_FX_CLASSES(clsList) {
-
for each (var cls in clsList) {
// Ex. Stage = Java.type("javafx.stage.Stage");
this[cls[cls.length - 1]] = Java.type(cls.join("."));
@@ -146,3 +145,5 @@
}
}
})();
+
+LOAD_FX_CLASSES(JFX_BASE_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Thu Oct 10 13:41:19 2013 -0700
@@ -41,7 +41,12 @@
}
});
+
// importPackage
+// avoid unnecessary chaining of __noSuchProperty__ again
+// in case user loads this script more than once.
+if (typeof importPackage == 'undefined') {
+
Object.defineProperty(this, "importPackage", {
configurable: true, enumerable: false, writable: true,
value: (function() {
@@ -91,6 +96,8 @@
})()
});
+}
+
// Object.prototype.__defineGetter__
Object.defineProperty(Object.prototype, "__defineGetter__", {
configurable: true, enumerable: false, writable: true,
@@ -344,13 +351,16 @@
// Rhino: global.importClass
Object.defineProperty(this, "importClass", {
configurable: true, enumerable: false, writable: true,
- value: function(clazz) {
- if (Java.isType(clazz)) {
- var className = Java.typeName(clazz);
- var simpleName = className.substring(className.lastIndexOf('.') + 1);
- this[simpleName] = clazz;
- } else {
- throw new TypeError(clazz + " is not a Java class");
+ value: function() {
+ for (var arg in arguments) {
+ var clazz = arguments[arg];
+ if (Java.isType(clazz)) {
+ var className = Java.typeName(clazz);
+ var simpleName = className.substring(className.lastIndexOf('.') + 1);
+ this[simpleName] = clazz;
+ } else {
+ throw new TypeError(clazz + " is not a Java class");
+ }
}
}
});
--- a/nashorn/test/script/assert.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/assert.js Thu Oct 10 13:41:19 2013 -0700
@@ -61,3 +61,22 @@
}
}
});
+
+Object.defineProperty(this, "printError", {
+ configuable: true,
+ enumerable: false,
+ writable: true,
+ value: function (e) {
+ var msg = e.message;
+ var str = e.name + ':';
+ if (e.lineNumber > 0) {
+ str += e.lineNumber + ':';
+ }
+ if (e.columnNumber > 0) {
+ str += e.columnNumber + ':';
+ }
+ str += msg.substring(msg.indexOf(' ') + 1);
+ print(str);
+ }
+});
+
--- a/nashorn/test/script/basic/JDK-8019508.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019508.js Thu Oct 10 13:41:19 2013 -0700
@@ -36,7 +36,7 @@
if (! (e instanceof SyntaxError)) {
fail("expected SyntaxError, got " + e);
}
- print(e.message.replace(/\\/g, '/'));
+ printError(e);
}
}
--- a/nashorn/test/script/basic/JDK-8019508.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019508.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,12 +1,12 @@
-test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({,})
^
-test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({, a:2 })
^
-test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({a:3,,})
^
-test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected comma but found ident
+SyntaxError:33:Expected comma but found ident
({a:3 b:2}
^
--- a/nashorn/test/script/basic/JDK-8019553.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019553.js Thu Oct 10 13:41:19 2013 -0700
@@ -33,7 +33,7 @@
eval(str);
fail("SyntaxError expected for: " + str);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
}
--- a/nashorn/test/script/basic/JDK-8019553.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019553.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,12 +1,12 @@
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found +
+SyntaxError:33:Expected l-value but found +
++ +3
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
+SyntaxError:33:Expected l-value but found -
++ -7
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found +
+SyntaxError:33:Expected l-value but found +
-- +2
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
+SyntaxError:33:Expected l-value but found -
-- -8
^
--- a/nashorn/test/script/basic/JDK-8019791.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019791.js Thu Oct 10 13:41:19 2013 -0700
@@ -33,7 +33,7 @@
eval('"" ~ ""');
print("FAILED: SyntaxError expected for: \"\" ~ \"\"");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
// Used to crash instead of SyntaxError
@@ -41,7 +41,7 @@
eval("function() { if (1~0) return 0; return 1 }");
print("FAILED: SyntaxError expected for: if (1~0) ");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
// The following are valid, but used to crash
--- a/nashorn/test/script/basic/JDK-8019791.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019791.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/JDK-8019791.js#33<eval>:1:3 Expected ; but found ~
+SyntaxError:33:Expected ; but found ~
"" ~ ""
^
-SyntaxError: test/script/basic/JDK-8019791.js#41<eval>:1:18 Expected ) but found ~
+SyntaxError:41:Expected ) but found ~
function() { if (1~0) return 0; return 1 }
^
--- a/nashorn/test/script/basic/JDK-8019805.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019805.js Thu Oct 10 13:41:19 2013 -0700
@@ -32,5 +32,5 @@
eval("for each(var v=0;false;);");
print("FAILED: for each(var v=0; false;); should have thrown error");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
--- a/nashorn/test/script/basic/JDK-8019805.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8019805.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/JDK-8019805.js#32<eval>:1:16 for each can only be used with for..in
+SyntaxError:32:for each can only be used with for..in
for each(var v=0;false;);
^
--- a/nashorn/test/script/basic/JDK-8023026.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/JDK-8023026.js Thu Oct 10 13:41:19 2013 -0700
@@ -48,7 +48,7 @@
function(x) x*x));
}
-var array = new (Java.type("[I"))(4);
+var array = new (Java.type("int[]"))(4);
for (var i in array) {
array[i] = i;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025213.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025213: Assignment marks variable as defined too early
+ *
+ * @test
+ * @run
+ */
+
+function test() {
+ if (String("")) {
+ var foo = 42;
+ }
+ foo = foo + 1;
+ print(foo);
+}
+
+test();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025213.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,1 @@
+NaN
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025488.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025488: Error.captureStackTrace should not format error stack
+ *
+ * @test
+ * @run
+ */
+
+
+function MyError () {
+ Error.call(this);
+ Error.captureStackTrace(this);
+ this.arr = {};
+};
+
+MyError.prototype.toString = function() {
+ return this.arr.toString();
+}
+
+var e = new MyError();
+print(e.stack);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025488.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,3 @@
+[object Object]
+ at MyError (test/script/basic/JDK-8025488.js:34)
+ at <program> (test/script/basic/JDK-8025488.js:42)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025515.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025515: Performance issues with Source.getLine()
+ *
+ * @test
+ * @run
+ */
+
+// Make sure synthetic names of anonymous functions have correct line numbers
+
+function testMethodName(f, expected) {
+ try {
+ f();
+ fail("expected error");
+ } catch (e) {
+ var stack = e.getStackTrace();
+ if (stack[0].methodName !== expected) {
+ fail("got " + stack[0].methodName + ", expected " + expected);
+ }
+ }
+}
+
+testMethodName(function() {
+ return a.b.c;
+}, "_L45");
+
+testMethodName(function() { throw new Error() }, "_L49");
+
+var f = (function() {
+ return function() { a.b.c; };
+})();
+testMethodName(f, "_L51$_L52");
+
+testMethodName((function() {
+ return function() { return a.b.c; };
+})(), "_L56$_L57");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025520.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025520: Array.prototype.slice should only copy defined elements
+ *
+ * @test
+ * @run
+ */
+
+var s = Array.prototype.slice.call({length: 6, 3: 1}, 2, 5);
+
+if (s.length != 3) {
+ fail("s.length != 3");
+}
+if (0 in s) {
+ fail("0 in s");
+}
+if (s.hasOwnProperty(0)) {
+ fail("s.hasOwnProperty(0)");
+}
+if (s[1] !== 1) {
+ fail("s[1] !== 1");
+}
+if (2 in s) {
+ fail("2 in s");
+}
+if (s.hasOwnProperty(2)) {
+ fail("s.hasOwnProperty(2)");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8025589.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025589: Array.prototype.shift should only copy defined elements in generic mode
+ *
+ * @test
+ * @run
+ */
+
+var s = {length: 4, 2: 1};
+Array.prototype.shift.call(s);
+
+if (s.length != 3) {
+ fail("s.length != 3");
+}
+if (0 in s) {
+ fail("0 in s");
+}
+if (s.hasOwnProperty(0)) {
+ fail("s.hasOwnProperty(0)");
+}
+if (s[1] !== 1) {
+ fail("s[1] !== 1");
+}
+if (2 in s) {
+ fail("2 in s");
+}
+if (s.hasOwnProperty(2)) {
+ fail("s.hasOwnProperty(2)");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026008.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026008: Constant folding removes var statement
+ *
+ * @test
+ * @run
+ */
+
+if (false) {
+ var x1 = 10;
+ if (false) {
+ var x2;
+ }
+} else {
+ print(x1, x2);
+}
+
+if (undefined) {
+ var z1;
+ if (null) {
+ var z2;
+ }
+}
+
+print(z1, z2);
+
+if (1) {
+ print(y1, y2);
+} else if (0) {
+ var y1 = 1;
+} else {
+ var y2 = 2
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026008.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,3 @@
+undefined undefined
+undefined undefined
+undefined undefined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026033.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026033: Switch should load expression even when there are no cases in it
+ *
+ * @test
+ * @run
+ */
+
+try {
+ (function() { switch(x) {} })();
+ fail("Should have thrown ReferenceError");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("ReferenceError expected, got " + e);
+ }
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026033.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,1 @@
+ReferenceError: "x" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026042.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026042: FoldConstants need to guard against ArrayLiteralNode
+ *
+ * @test
+ * @run
+ */
+
+try {
+ if ([a]) {
+ print("fail");
+ }
+} catch (e) {
+ print(e);
+}
+
+try {
+ [a] ? print(1) : print(2);
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026042.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,2 @@
+ReferenceError: "a" is not defined
+ReferenceError: "a" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026048.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026048: Function constructor should convert arguments to String before performing any syntax checks
+ *
+ * @test
+ * @run
+ */
+
+try {
+ Function("-", {toString:function(){throw "err"}})
+} catch (e) {
+ if (e !== "err") {
+ fail("err xpected, got " + e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026112.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026112: Function("with(x ? 1e81 : (x2.constructor = 0.1)){}") throws AssertionError: double is not compatible with object
+ *
+ * @test
+ * @run
+ */
+
+Function("with(x ? 1e81 : (x2.constructor = 0.1)){}")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026125.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026125: Array.prototype.slice.call(Java.type("java.util.HashMap")) throws ClassCastException: jdk.internal.dynalink.beans.StaticClass cannot be cast to jdk.nashorn.internal.runtime.ScriptObject
+ *
+ * @test
+ * @run
+ */
+
+Array.prototype.splice.call(Java.type("java.util.HashMap"))
+Array.prototype.slice.call(Java.type("java.util.HashMap"))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026137.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026137: Binary evaluation order in JavaScript is load load
+ * convert convert, not load convert load convert.
+ *
+ * @test
+ * @run
+ */
+
+try {
+ (function f() { Object.defineProperty({},"x",{get: function(){return {valueOf:function(){throw 0}}}}).x - Object.defineProperty({},"x",{get: function(){throw 1}}).x })()
+}
+catch (e) {
+ print(e);
+}
+
+try {
+ ({valueOf: function(){throw 0}}) - ({valueOf: function(){throw 1}} - 1)
+} catch (e) {
+ print(e);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026137.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,2 @@
+1
+1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026167.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026167: Class cache/reuse of 'eval' scripts results in ClassCastException in some cases.
+ *
+ * @test
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName('js');
+
+// leave the whitespace - need both eval("e") at same column for this test!
+
+e.eval('function f(e) { eval("e") } f()');
+e.eval('function f() { var e = 33; eval("e") } f()');
+
+function f() {
+ Function.call.call(function x() { eval("x") }); eval("x")
+}
+
+try {
+ f();
+ fail("Should have thrown ReferenceError");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("ReferenceError expected but got " + e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026248.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026248: importClass has to be a varargs function
+ *
+ * @test
+ * @run
+ */
+
+load('nashorn:mozilla_compat.js')
+
+importClass(java.io.File, java.io.InputStream)
+
+print(File)
+print(InputStream)
+
+importClass(java.util.Map, java.util.HashMap, java.io.PrintStream)
+
+print(HashMap)
+print(Map)
+print(PrintStream)
+
+importClass.call(this, java.util.Collections, java.util.List);
+print(Collections)
+print(List)
+
+importClass.apply(this, [ java.util.Queue, java.math.BigInteger, java.math.BigDecimal ]);
+print(Queue)
+print(BigInteger)
+print(BigDecimal)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8026248.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,10 @@
+[JavaClass java.io.File]
+[JavaClass java.io.InputStream]
+[JavaClass java.util.HashMap]
+[JavaClass java.util.Map]
+[JavaClass java.io.PrintStream]
+[JavaClass java.util.Collections]
+[JavaClass java.util.List]
+[JavaClass java.util.Queue]
+[JavaClass java.math.BigInteger]
+[JavaClass java.math.BigDecimal]
--- a/nashorn/test/script/basic/NASHORN-100.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-100.js Thu Oct 10 13:41:19 2013 -0700
@@ -35,5 +35,5 @@
if (! (e instanceof SyntaxError)) {
fail("#2 expected SyntaxError got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
--- a/nashorn/test/script/basic/NASHORN-100.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-100.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/NASHORN-100.js#32<eval>:1:0 Invalid return statement
+SyntaxError:32:Invalid return statement
return;
^
--- a/nashorn/test/script/basic/NASHORN-293.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-293.js Thu Oct 10 13:41:19 2013 -0700
@@ -40,15 +40,13 @@
try {
eval(src);
} catch (e) {
- var location = e.fileName ? e.fileName.slice(-9) : "unknown source";
- print(e.name, "@", location);
+ printError(e);
}
}
for (var i = 0; i < 3; i++) {
try {
eval(src);
} catch (e) {
- var location = e.fileName ? e.fileName.slice(-9) : "unknown source";
- print(e.name, "@", location);
+ printError(e);
}
}
--- a/nashorn/test/script/basic/NASHORN-293.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-293.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,9 +1,9 @@
hello
hello
hello
-TypeError @ #41<eval>
-TypeError @ #41<eval>
-TypeError @ #41<eval>
-TypeError @ #49<eval>
-TypeError @ #49<eval>
-TypeError @ #49<eval>
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
--- a/nashorn/test/script/basic/NASHORN-40.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-40.js Thu Oct 10 13:41:19 2013 -0700
@@ -31,11 +31,11 @@
try {
eval("print(.foo)");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval(".bar = 3423;");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
--- a/nashorn/test/script/basic/NASHORN-40.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-40.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/NASHORN-40.js#32<eval>:1:6 Expected an operand but found .
+SyntaxError:32:Expected an operand but found .
print(.foo)
^
-SyntaxError: test/script/basic/NASHORN-40.js#38<eval>:1:0 Expected an operand but found .
+SyntaxError:38:Expected an operand but found .
.bar = 3423;
^
--- a/nashorn/test/script/basic/NASHORN-51.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-51.js Thu Oct 10 13:41:19 2013 -0700
@@ -35,28 +35,28 @@
eval(literals[i] + "++");
print("ERROR!! post increment : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval(literals[i] + "--");
print("ERROR!! post decrement : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval("++" + literals[i]);
print("ERROR!! pre increment : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval("--" + literals[i]);
print("ERROR!! pre decrement : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
}
--- a/nashorn/test/script/basic/NASHORN-51.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-51.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,72 +1,72 @@
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
1++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
1--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++1
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--1
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
0++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
0--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++0
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--0
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
3.14++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
3.14--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++3.14
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--3.14
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
true++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
true--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++true
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--true
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
false++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
false--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++false
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--false
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
null++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
null--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++null
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--null
^
--- a/nashorn/test/script/basic/NASHORN-98.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-98.js Thu Oct 10 13:41:19 2013 -0700
@@ -34,7 +34,7 @@
if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
@@ -43,5 +43,5 @@
if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
--- a/nashorn/test/script/basic/NASHORN-98.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/NASHORN-98.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/NASHORN-98.js#32<eval>:1:13 Expected comma but found decimal
+SyntaxError:32:Expected comma but found decimal
var x = [ 23 34 ]
^
-SyntaxError: test/script/basic/NASHORN-98.js#41<eval>:1:18 Expected comma but found ident
+SyntaxError:41:Expected comma but found ident
var x = { foo: 33 bar: 'hello' }
^
--- a/nashorn/test/script/basic/eval.js Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/eval.js Thu Oct 10 13:41:19 2013 -0700
@@ -69,5 +69,5 @@
eval("print('hello)");
} catch (e) {
print("is syntax error? " + (e instanceof SyntaxError));
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
--- a/nashorn/test/script/basic/eval.js.EXPECTED Thu Oct 10 10:09:30 2013 -0700
+++ b/nashorn/test/script/basic/eval.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -10,6 +10,6 @@
100
3300
is syntax error? true
-SyntaxError: test/script/basic/eval.js#69<eval>:1:13 Missing close quote
+SyntaxError:69:Missing close quote
print('hello)
^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8026039.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8026039: future strict names are allowed as function name and argument name of a strict function
+ *
+ * @test/compile-error
+ */
+
+function public() {"use strict"}
+
+function f(public) {"use strict"}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8026039.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,9 @@
+test/script/error/JDK-8026039.js:30:9 "public" cannot be used as function name in strict mode
+function public() {"use strict"}
+ ^
+test/script/error/JDK-8026039.js:32:11 Expected ident but found public
+function f(public) {"use strict"}
+ ^
+test/script/error/JDK-8026039.js:33:0 Expected } but found eof
+
+^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/sandbox/arrayclass.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * Try to access array class of a sensitive class like Unsafe.
+ *
+ * @test
+ * @security
+ * @run
+ */
+
+try {
+ var unsafeArr = Java.type("[Lsun.misc.Unsafe;");
+ fail("No Exception for [Lsun.misc.Unsafe;");
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/sandbox/arrayclass.js.EXPECTED Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,1 @@
+java.lang.ClassNotFoundException: [Lsun.misc.Unsafe;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8025629.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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-8025629: load function should support a way to load scripts from classpath
+ *
+ * @test
+ * @run
+ */
+
+load("classpath:jdk/nashorn/internal/runtime/resources/load_test.js")
+
+Assert.assertEquals(loadedFunc("hello"), "HELLO");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/resources/load_test.js Thu Oct 10 13:41:19 2013 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+function loadedFunc(arg) {
+ return arg.toUpperCase();
+}