# HG changeset patch
# User jlaskey
# Date 1367282288 10800
# Node ID f4480af133643190b208d4eda8f4ce711d3b971d
# Parent dcd15316ca8162d57d14dcb418626cf55cc8f6b6# Parent a2232050cd8f16e903d69ae1067ee8e654c0af33
Merge
diff -r dcd15316ca81 -r f4480af13364 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Mon Apr 29 21:38:08 2013 -0300
@@ -38,7 +38,6 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
@@ -47,6 +46,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
@@ -238,7 +239,7 @@
mi.loadThis();
mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR,
PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC);
- mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC);
+ mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETPROTOTYPE, SCRIPTFUNCTION_SETPROTOTYPE_DESC);
}
}
diff -r dcd15316ca81 -r f4480af13364 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Mon Apr 29 21:38:08 2013 -0300
@@ -55,7 +55,6 @@
static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
- static final String PROTOTYPE = "prototype";
static final String PROTOTYPE_SUFFIX = "$Prototype";
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
// This field name is known to Nashorn runtime (Context).
@@ -88,6 +87,8 @@
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
static final String SCRIPTFUNCTION_SETARITY = "setArity";
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+ static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
+ static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
diff -r dcd15316ca81 -r f4480af13364 nashorn/make/build-nasgen.xml
--- a/nashorn/make/build-nasgen.xml Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/make/build-nasgen.xml Mon Apr 29 21:38:08 2013 -0300
@@ -37,6 +37,7 @@
+
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Mon Apr 29 21:38:08 2013 -0300
@@ -106,7 +106,11 @@
@Override
MethodHandle editMethodHandle(MethodHandle mh) {
- MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, Object.class);
+ return dropReceiver(mh, Object.class);
+ }
+
+ static MethodHandle dropReceiver(final MethodHandle mh, final Class> receiverClass) {
+ MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
// NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
final MethodType type = mh.type();
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Mon Apr 29 21:38:08 2013 -0300
@@ -144,7 +144,7 @@
}
private static MethodHandle drop(MethodHandle mh) {
- return MethodHandles.dropArguments(mh, 0, StaticClass.class);
+ return StaticClassIntrospector.dropReceiver(mh, StaticClass.class);
}
@Override
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/Attr.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Mon Apr 29 21:38:08 2013 -0300
@@ -48,10 +48,8 @@
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet;
-import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
@@ -81,6 +79,7 @@
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
+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.TokenType;
@@ -91,6 +90,7 @@
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
@@ -126,8 +126,6 @@
private final Deque returnTypes;
- private final Map selfSymbolToFunction = new IdentityHashMap<>();
-
private static final DebugLogger LOG = new DebugLogger("attr");
private static final boolean DEBUG = LOG.isEnabled();
@@ -173,23 +171,26 @@
if (functionNode.isProgram()) {
initFromPropertyMap(body);
- }
+ } else if(!functionNode.isDeclared()) {
+ // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
- // Add function name as local symbol
- if (!functionNode.isDeclared() && !functionNode.isProgram()) {
if (functionNode.getSymbol() != null) {
// a temporary left over from an earlier pass when the function was lazy
assert functionNode.getSymbol().isTemp();
// remove it
functionNode.setSymbol(null);
}
- final Symbol selfSymbol;
- if (functionNode.isAnonymous()) {
- selfSymbol = ensureSymbol(functionNode, Type.OBJECT, functionNode);
+ final boolean anonymous = functionNode.isAnonymous();
+ final String name = anonymous ? null : functionNode.getIdent().getName();
+ if (anonymous || body.getExistingSymbol(name) != null) {
+ // The function is either anonymous, or another local identifier already trumps its name on entry:
+ // either it has the same name as one of its parameters, or is named "arguments" and also references the
+ // "arguments" identifier in its body.
+ ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode);
} else {
- selfSymbol = defineSymbol(body, functionNode.getIdent().getName(), IS_VAR | IS_FUNCTION_SELF, functionNode);
+ final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode);
+ assert selfSymbol.isFunctionSelf();
newType(selfSymbol, Type.OBJECT);
- selfSymbolToFunction.put(selfSymbol, functionNode);
}
}
@@ -495,10 +496,8 @@
}
identNode.setSymbol(symbol);
- // non-local: we need to put symbol in scope (if it isn't already)
- if (!isLocal(lc.getCurrentFunction(), symbol) && !symbol.isScope()) {
- Symbol.setSymbolIsScope(lc, symbol);
- }
+ // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
+ maybeForceScope(symbol);
} else {
LOG.info("No symbol exists. Declare undefined: ", symbol);
symbol = defineSymbol(block, name, IS_GLOBAL, identNode);
@@ -520,6 +519,50 @@
return false;
}
+ /**
+ * If the symbol isn't already a scope symbol, and it is either not local to the current function, or it is being
+ * referenced from within a with block, we force it to be a scope symbol.
+ * @param symbol the symbol that might be scoped
+ */
+ private void maybeForceScope(final Symbol symbol) {
+ if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
+ Symbol.setSymbolIsScope(getLexicalContext(), symbol);
+ }
+ }
+
+ private boolean symbolNeedsToBeScope(Symbol symbol) {
+ if(symbol.isThis() || symbol.isInternal()) {
+ return false;
+ }
+ boolean previousWasBlock = false;
+ for(final Iterator it = getLexicalContext().getAllNodes(); it.hasNext();) {
+ final LexicalContextNode node = it.next();
+ if(node instanceof FunctionNode) {
+ // We reached the function boundary without seeing a definition for the symbol - it needs to be in
+ // scope.
+ return true;
+ } else if(node instanceof WithNode) {
+ if(previousWasBlock) {
+ // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately
+ // preceded by a block, this means we're currently processing its expression, not its body,
+ // therefore it doesn't count.
+ return true;
+ }
+ previousWasBlock = false;
+ } else if(node instanceof Block) {
+ if(((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
+ // We reached the block that defines the symbol without reaching either the function boundary, or a
+ // WithNode. The symbol need not be scoped.
+ return false;
+ }
+ previousWasBlock = true;
+ } else {
+ previousWasBlock = false;
+ }
+ }
+ throw new AssertionError();
+ }
+
private void setBlockScope(final String name, final Symbol symbol) {
assert symbol != null;
if (symbol.isGlobal()) {
@@ -963,18 +1006,17 @@
final Node lhs = binaryNode.lhs();
if (lhs instanceof IdentNode) {
- final LexicalContext lc = getLexicalContext();
- final Block block = lc.getCurrentBlock();
- final IdentNode ident = (IdentNode)lhs;
- final String name = ident.getName();
+ final Block block = getLexicalContext().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, ident);
binaryNode.setSymbol(symbol);
- } else if (!isLocal(lc.getCurrentFunction(), symbol)) {
- Symbol.setSymbolIsScope(lc, symbol);
+ } else {
+ maybeForceScope(symbol);
}
addLocalDef(name);
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Apr 29 21:38:08 2013 -0300
@@ -87,6 +87,7 @@
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -117,6 +118,7 @@
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ECMAException;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
@@ -200,6 +202,7 @@
* @param compiler
*/
CodeGenerator(final Compiler compiler) {
+ super(new DynamicScopeTrackingLexicalContext());
this.compiler = compiler;
this.callSiteFlags = compiler.getEnv()._callsite_flags;
}
@@ -284,23 +287,99 @@
}
/**
+ * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
+ * variables introduced into them at run time - a with block or a function directly containing an eval call.
+ */
+ private static class DynamicScopeTrackingLexicalContext extends LexicalContext {
+ int dynamicScopeCount = 0;
+
+ @Override
+ public T push(T node) {
+ if(isDynamicScopeBoundary(node)) {
+ ++dynamicScopeCount;
+ }
+ return super.push(node);
+ }
+
+ @Override
+ public T pop(T node) {
+ final T popped = super.pop(node);
+ if(isDynamicScopeBoundary(popped)) {
+ --dynamicScopeCount;
+ }
+ return popped;
+ }
+
+ private boolean isDynamicScopeBoundary(LexicalContextNode node) {
+ if(node instanceof Block) {
+ // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
+ // processing of WithNode.expression too, but it should be unaffected.
+ return !isEmpty() && peek() instanceof WithNode;
+ } else if(node instanceof FunctionNode) {
+ // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
+ // variable into the function's scope), and it isn't strict (as evals in strict functions get an
+ // isolated scope).
+ return isFunctionDynamicScope((FunctionNode)node);
+ }
+ return false;
+ }
+ }
+
+ boolean inDynamicScope() {
+ return ((DynamicScopeTrackingLexicalContext)getLexicalContext()).dynamicScopeCount > 0;
+ }
+
+ static boolean isFunctionDynamicScope(FunctionNode fn) {
+ return fn.hasEval() && !fn.isStrict();
+ }
+
+ /**
* Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
*
* @param function function to check for fast scope
* @return true if fast scope
*/
private boolean isFastScope(final Symbol symbol) {
- if (!symbol.isScope() || !getLexicalContext().getDefiningBlock(symbol).needsScope()) {
+ if(!symbol.isScope()) {
+ return false;
+ }
+ final LexicalContext lc = getLexicalContext();
+ if(!inDynamicScope()) {
+ // If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a
+ // symbol must either be global, or its defining block must need scope.
+ assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName();
+ return true;
+ }
+ if(symbol.isGlobal()) {
+ // Shortcut: if there's a with or eval in context, globals can't be fast scoped
return false;
}
- // Allow fast scope access if no function contains with or eval
- for (final Iterator it = getLexicalContext().getFunctions(); it.hasNext();) {
- final FunctionNode func = it.next();
- if (func.hasWith() || func.hasEval()) {
- return false;
+ // Otherwise, check if there's a dynamic scope between use of the symbol and its definition
+ final String name = symbol.getName();
+ boolean previousWasBlock = false;
+ for (final Iterator it = lc.getAllNodes(); it.hasNext();) {
+ final LexicalContextNode node = it.next();
+ if(node instanceof Block) {
+ // If this block defines the symbol, then we can fast scope the symbol.
+ final Block block = (Block)node;
+ if(block.getExistingSymbol(name) == symbol) {
+ assert block.needsScope();
+ return true;
+ }
+ previousWasBlock = true;
+ } else {
+ if((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && isFunctionDynamicScope((FunctionNode)node))) {
+ // If we hit a scope that can have symbols introduced into it at run time before finding the defining
+ // block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block
+ // before - its block. Otherwise, we are currently processing the WithNode's expression, and that's
+ // obviously not subjected to introducing new symbols.
+ return false;
+ }
+ previousWasBlock = false;
}
}
- return true;
+ // Should've found the symbol defined in a block
+ throw new AssertionError();
}
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
@@ -664,13 +743,13 @@
final int useCount = symbol.getUseCount();
// Threshold for generating shared scope callsite is lower for fast scope symbols because we know
- // we can dial in the correct scope. However, we als need to enable it for non-fast scopes to
+ // we can dial in the correct scope. However, we also need to enable it for non-fast scopes to
// support huge scripts like mandreel.js.
if (callNode.isEval()) {
evalCall(node, flags);
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
|| (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
- || callNode.inWithBlock()) {
+ || CodeGenerator.this.inDynamicScope()) {
scopeCall(node, flags);
} else {
sharedScopeCall(node, flags);
@@ -1119,7 +1198,7 @@
@Override
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getLexicalContext().getCurrentFunction().getName() + ")");
+ final Label label = new Label((String)null);
method.label(label);
method.lineNumber(lineNumberNode.getLineNumber(), label);
return false;
@@ -2113,9 +2192,11 @@
}
private void closeWith() {
- method.loadCompilerConstant(SCOPE);
- method.invoke(ScriptRuntime.CLOSE_WITH);
- method.storeCompilerConstant(SCOPE);
+ if(method.hasScope()) {
+ method.loadCompilerConstant(SCOPE);
+ method.invoke(ScriptRuntime.CLOSE_WITH);
+ method.storeCompilerConstant(SCOPE);
+ }
}
@Override
@@ -2123,38 +2204,58 @@
final Node expression = withNode.getExpression();
final Node body = withNode.getBody();
- final Label tryLabel = new Label("with_try");
- final Label endLabel = new Label("with_end");
- final Label catchLabel = new Label("with_catch");
- final Label exitLabel = new Label("with_exit");
-
- method.label(tryLabel);
-
- method.loadCompilerConstant(SCOPE);
+ // It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's
+ // pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the
+ // scope object, its' possible that it won't have a slot assigned. In this case we'll only evaluate expression
+ // for its side effect and visit the body, and not bother opening and closing a WithObject.
+ final boolean hasScope = method.hasScope();
+
+ final Label tryLabel;
+ if(hasScope) {
+ tryLabel = new Label("with_try");
+ method.label(tryLabel);
+ method.loadCompilerConstant(SCOPE);
+ } else {
+ tryLabel = null;
+ }
+
load(expression);
-
assert expression.getType().isObject() : "with expression needs to be object: " + expression;
- method.invoke(ScriptRuntime.OPEN_WITH);
- method.storeCompilerConstant(SCOPE);
-
+ if(hasScope) {
+ // Construct a WithObject if we have a scope
+ method.invoke(ScriptRuntime.OPEN_WITH);
+ method.storeCompilerConstant(SCOPE);
+ } else {
+ // We just loaded the expression for its side effect; discard it
+ method.pop();
+ }
+
+
+ // Always process body
body.accept(this);
- if (!body.isTerminal()) {
+ if(hasScope) {
+ // Ensure we always close the WithObject
+ final Label endLabel = new Label("with_end");
+ final Label catchLabel = new Label("with_catch");
+ final Label exitLabel = new Label("with_exit");
+
+ if (!body.isTerminal()) {
+ closeWith();
+ method._goto(exitLabel);
+ }
+
+ method.label(endLabel);
+
+ method._catch(catchLabel);
closeWith();
- method._goto(exitLabel);
+ method.athrow();
+
+ method.label(exitLabel);
+
+ method._try(tryLabel, endLabel, catchLabel);
}
-
- method.label(endLabel);
-
- method._catch(catchLabel);
- closeWith();
- method.athrow();
-
- method.label(exitLabel);
-
- method._try(tryLabel, endLabel, catchLabel);
-
return false;
}
@@ -2572,7 +2673,7 @@
@Override
protected void op() {
method.shr();
- method.convert(Type.LONG).load(0xffff_ffffL).and();
+ method.convert(Type.LONG).load(JSType.MAX_UINT).and();
}
}.store();
@@ -2807,7 +2908,7 @@
@Override
protected void op() {
method.shr();
- method.convert(Type.LONG).load(0xffff_ffffL).and();
+ method.convert(Type.LONG).load(JSType.MAX_UINT).and();
}
}.evaluate(binaryNode);
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Mon Apr 29 21:38:08 2013 -0300
@@ -87,55 +87,55 @@
THIS("this"),
/** this debugger symbol */
- THIS_DEBUGGER("__this__"),
+ THIS_DEBUGGER(":this"),
/** scope name, type and slot */
- SCOPE("__scope__", ScriptObject.class, 2),
+ SCOPE(":scope", ScriptObject.class, 2),
/** the return value variable name were intermediate results are stored for scripts */
- RETURN("__return__"),
+ RETURN(":return"),
/** the callee value variable when necessary */
- CALLEE("__callee__", ScriptFunction.class),
+ CALLEE(":callee", ScriptFunction.class),
/** the varargs variable when necessary */
- VARARGS("__varargs__"),
+ VARARGS(":varargs"),
/** the arguments vector when necessary and the slot */
ARGUMENTS("arguments", Object.class, 2),
/** prefix for iterators for for (x in ...) */
- ITERATOR_PREFIX("$iter"),
+ ITERATOR_PREFIX(":iter"),
/** prefix for tag variable used for switch evaluation */
- SWITCH_TAG_PREFIX("$tag"),
+ SWITCH_TAG_PREFIX(":tag"),
/** prefix for all exceptions */
- EXCEPTION_PREFIX("$exception"),
+ EXCEPTION_PREFIX(":exception"),
/** prefix for quick slots generated in Store */
- QUICK_PREFIX("$quick"),
+ QUICK_PREFIX(":quick"),
/** prefix for temporary variables */
- TEMP_PREFIX("$temp"),
+ TEMP_PREFIX(":temp"),
/** prefix for literals */
- LITERAL_PREFIX("$lit"),
-
- /** prefix for map */
- MAP("$map", 1),
+ LITERAL_PREFIX(":lit"),
/** prefix for regexps */
- REGEX_PREFIX("$regex"),
+ REGEX_PREFIX(":regex"),
/** "this" used in non-static Java methods; always in slot 0 */
- JAVA_THIS("this", 0),
+ JAVA_THIS(null, 0),
+
+ /** Map parameter in scope object constructors; always in slot 1 */
+ INIT_MAP(null, 1),
- /** init scope */
- INIT_SCOPE("$scope", 2),
+ /** Parent scope parameter in scope object constructors; always in slot 2 */
+ INIT_SCOPE(null, 2),
- /** init arguments */
- INIT_ARGUMENTS("$arguments", 3),
+ /** Arguments parameter in scope object constructors; in slot 3 when present */
+ INIT_ARGUMENTS(null, 3),
/** prefix for all ScriptObject subclasses with fields, @see ObjectGenerator */
JS_OBJECT_PREFIX("JO"),
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Mon Apr 29 21:38:08 2013 -0300
@@ -32,7 +32,6 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.Assignment;
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Mon Apr 29 21:38:08 2013 -0300
@@ -247,7 +247,7 @@
value = lhs.getNumber() - rhs.getNumber();
break;
case SHR:
- return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & 0xffff_ffffL);
+ return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
case SAR:
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
case SHL:
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Mon Apr 29 21:38:08 2013 -0300
@@ -71,7 +71,6 @@
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
-
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -674,7 +673,7 @@
* @return the method emitter
*/
MethodEmitter loadUndefined(final Type type) {
- debug("load undefined " + type);
+ debug("load undefined ", type);
pushType(type.loadUndefined(method));
return this;
}
@@ -686,7 +685,7 @@
* @return the method emitter
*/
MethodEmitter loadEmpty(final Type type) {
- debug("load empty " + type);
+ debug("load empty ", type);
pushType(type.loadEmpty(method));
return this;
}
@@ -819,7 +818,7 @@
}
/**
- * Push an local variable to the stack. If the symbol representing
+ * Push a local variable to the stack. If the symbol representing
* the local variable doesn't have a slot, this is a NOP
*
* @param symbol the symbol representing the local variable.
@@ -901,6 +900,15 @@
return functionNode.getBody().getExistingSymbol(cc.symbolName());
}
+ /**
+ * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
+ * the scope).
+ * @return if this method has a slot allocated for the scope variable.
+ */
+ boolean hasScope() {
+ return compilerConstant(SCOPE).hasSlot();
+ }
+
MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
final Symbol symbol = compilerConstant(cc);
if (cc == SCOPE && peekType() == Type.SCOPE) {
@@ -1076,7 +1084,7 @@
* @return the method emitter
*/
MethodEmitter newarray(final ArrayType arrayType) {
- debug("newarray ", "arrayType=" + arrayType);
+ debug("newarray ", "arrayType=", arrayType);
popType(Type.INT); //LENGTH
pushType(arrayType.newarray(method));
return this;
@@ -1155,7 +1163,7 @@
* @return the method emitter
*/
MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
- debug("invokespecial", className + "." + methodName + methodDescriptor);
+ debug("invokespecial", className, ".", methodName, methodDescriptor);
return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
}
@@ -1169,7 +1177,7 @@
* @return the method emitter
*/
MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
- debug("invokevirtual", className + "." + methodName + methodDescriptor + " " + stack);
+ debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
}
@@ -1183,7 +1191,7 @@
* @return the method emitter
*/
MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
- debug("invokestatic", className + "." + methodName + methodDescriptor);
+ debug("invokestatic", className, ".", methodName, methodDescriptor);
invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
return this;
}
@@ -1216,7 +1224,7 @@
* @return the method emitter
*/
MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
- debug("invokeinterface", className + "." + methodName + methodDescriptor);
+ debug("invokeinterface", className, ".", methodName, methodDescriptor);
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
}
@@ -1268,11 +1276,11 @@
*/
void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
if (peekType().isCategory2()) {
- debug("[ld]cmp isCmpG=" + isCmpG);
+ debug("[ld]cmp isCmpG=", isCmpG);
pushType(get2n().cmp(method, isCmpG));
jump(Condition.toUnary(cond), trueLabel, 1);
} else {
- debug("if" + cond);
+ debug("if", cond);
jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
}
}
@@ -1517,7 +1525,7 @@
*/
private void mergeStackTo(final Label label) {
final ArrayDeque labelStack = label.getStack();
- //debug(labelStack == null ? " >> Control flow - first visit " + label : " >> Control flow - JOIN with " + labelStack + " at " + label);
+ //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
if (labelStack == null) {
assert stack != null;
label.setStack(stack.clone());
@@ -1710,7 +1718,7 @@
* @return the method emitter
*/
MethodEmitter dynamicNew(final int argCount, final int flags) {
- debug("dynamic_new", "argcount=" + argCount);
+ debug("dynamic_new", "argcount=", argCount);
final String signature = getDynamicSignature(Type.OBJECT, argCount);
method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
pushType(Type.OBJECT); //TODO fix result type
@@ -1727,7 +1735,7 @@
* @return the method emitter
*/
MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
- debug("dynamic_call", "args=" + argCount, "returnType=" + returnType);
+ debug("dynamic_call", "args=", argCount, "returnType=", returnType);
final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
debug(" signature", signature);
method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
@@ -1746,7 +1754,7 @@
* @return the method emitter
*/
MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
- debug("dynamic_runtime_call", name, "args=" + request.getArity(), "returnType=" + returnType);
+ debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
final String signature = getDynamicSignature(returnType, request.getArity());
debug(" signature", signature);
method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
@@ -1817,7 +1825,7 @@
* @return the method emitter
*/
MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
- debug("dynamic_get_index", peekType(1) + "[" + peekType() + "]");
+ debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
Type resultType = result;
if (result.isBoolean()) {
@@ -1853,7 +1861,7 @@
* @param flags call site flags for setter
*/
void dynamicSetIndex(final int flags) {
- debug("dynamic_set_index", peekType(2) + "[" + peekType(1) + "] =", peekType());
+ debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
Type value = peekType();
if (value.isObject() || value.isBoolean()) {
@@ -1953,7 +1961,7 @@
* @return the method emitter
*/
MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
- debug("getfield", "receiver=" + peekType(), className + "." + fieldName + fieldDescriptor);
+ debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
final Type receiver = popType();
assert receiver.isObject();
method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
@@ -1971,7 +1979,7 @@
* @return the method emitter
*/
MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
- debug("getstatic", className + "." + fieldName + "." + fieldDescriptor);
+ debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
pushType(fieldType(fieldDescriptor));
return this;
@@ -1985,7 +1993,7 @@
* @param fieldDescriptor field descriptor
*/
void putField(final String className, final String fieldName, final String fieldDescriptor) {
- debug("putfield", "receiver=" + peekType(1), "value=" + peekType());
+ debug("putfield", "receiver=", peekType(1), "value=", peekType());
popType(fieldType(fieldDescriptor));
popType(Type.OBJECT);
method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
@@ -1999,7 +2007,7 @@
* @param fieldDescriptor field descriptor
*/
void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
- debug("putfield", "value=" + peekType());
+ debug("putfield", "value=", peekType());
popType(fieldType(fieldDescriptor));
method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
}
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Mon Apr 29 21:38:08 2013 -0300
@@ -28,10 +28,10 @@
import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_MAP;
import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX;
-import static jdk.nashorn.internal.codegen.CompilerConstants.MAP;
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.lookup.Lookup.MH;
@@ -222,6 +222,22 @@
}
/**
+ * Returns the number of fields in the JavaScript scope class. Its name had to be generated using either
+ * {@link #getClassName(int)} or {@link #getClassName(int, int)}.
+ * @param clazz the JavaScript scope class.
+ * @return the number of fields in the scope class.
+ */
+ public static int getFieldCount(Class> clazz) {
+ final String name = clazz.getSimpleName();
+ final String prefix = JS_OBJECT_PREFIX.symbolName();
+ if(prefix.equals(name)) {
+ return 0;
+ }
+ final int scopeMarker = name.indexOf(SCOPE_MARKER);
+ return Integer.parseInt(scopeMarker == -1 ? name.substring(prefix.length()) : name.substring(prefix.length(), scopeMarker));
+ }
+
+ /**
* Returns the name of a field based on number and type.
*
* @param fieldIndex Ordinal of field.
@@ -387,7 +403,7 @@
final MethodEmitter init = classEmitter.init(PropertyMap.class);
init.begin();
init.load(Type.OBJECT, JAVA_THIS.slot());
- init.load(Type.OBJECT, MAP.slot());
+ init.load(Type.OBJECT, INIT_MAP.slot());
init.invoke(constructorNoLookup(ScriptObject.class, PropertyMap.class));
return init;
@@ -402,7 +418,7 @@
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class);
init.begin();
init.load(Type.OBJECT, JAVA_THIS.slot());
- init.load(Type.OBJECT, MAP.slot());
+ init.load(Type.OBJECT, INIT_MAP.slot());
init.load(Type.OBJECT, INIT_SCOPE.slot());
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class));
@@ -418,7 +434,7 @@
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
init.begin();
init.load(Type.OBJECT, JAVA_THIS.slot());
- init.load(Type.OBJECT, MAP.slot());
+ init.load(Type.OBJECT, INIT_MAP.slot());
init.load(Type.OBJECT, INIT_SCOPE.slot());
init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/ir/CallNode.java
--- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Mon Apr 29 21:38:08 2013 -0300
@@ -50,9 +50,6 @@
/** Is this a "new" operation */
public static final int IS_NEW = 0x1;
- /** Is this call tagged as inside a with block */
- public static final int IN_WITH_BLOCK = 0x2;
-
private final int flags;
/**
@@ -145,14 +142,13 @@
* @param finish finish
* @param function the function to call
* @param args args to the call
- * @param flags flags
*/
- public CallNode(final Source source, final long token, final int finish, final Node function, final List args, final int flags) {
+ public CallNode(final Source source, final long token, final int finish, final Node function, final List args) {
super(source, token, finish);
this.function = function;
this.args = args;
- this.flags = flags;
+ this.flags = 0;
this.type = null;
this.evalArgs = null;
}
@@ -333,14 +329,6 @@
return setFlags(IS_NEW);
}
- /**
- * Check if this call is inside a {@code with} block
- * @return true if the call is inside a {@code with} block
- */
- public boolean inWithBlock() {
- return (flags & IN_WITH_BLOCK) == IN_WITH_BLOCK;
- }
-
private CallNode setFlags(final int flags) {
if (this.flags == flags) {
return this;
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Mon Apr 29 21:38:08 2013 -0300
@@ -145,14 +145,12 @@
/** Has this node been split because it was too large? */
public static final int IS_SPLIT = 1 << 4;
- /** Does the function call eval? */
+ /** Does the function call eval? If it does, then all variables in this function might be get/set by it and it can
+ * introduce new variables into this function's scope too.*/
public static final int HAS_EVAL = 1 << 5;
- /** Does the function contain a with block ? */
- public static final int HAS_WITH = 1 << 6;
-
- /** Does a descendant function contain a with or eval? */
- public static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 7;
+ /** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
+ public static final int HAS_NESTED_EVAL = 1 << 6;
/**
* Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
@@ -178,18 +176,18 @@
/** Does this function have nested declarations? */
public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13;
- /** Does this function or any nested functions contain a with or an eval? */
- private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
+ /** Does this function or any nested functions contain an eval? */
+ private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
/** Does this function need to store all its variables in scope? */
- private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
+ private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
/** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
- /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval.
+ /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval.
* We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
- private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN;
+ private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | HAS_LAZY_CHILDREN;
/** What is the return type of this function? */
private Type returnType = Type.UNKNOWN;
@@ -406,15 +404,6 @@
}
/**
- * Check if the {@code with} keyword is used in this function
- *
- * @return true if {@code with} is used
- */
- public boolean hasWith() {
- return getFlag(HAS_WITH);
- }
-
- /**
* Check if the {@code eval} keyword is used in this function
*
* @return true if {@code eval} is used
@@ -424,18 +413,6 @@
}
/**
- * Test whether this function or any of its nested functions contains a with statement
- * or an eval call.
- *
- * @see #hasWith()
- * @see #hasEval()
- * @return true if this or a nested function contains with or eval
- */
- public boolean hasDeepWithOrEval() {
- return getFlag(HAS_DEEP_WITH_OR_EVAL);
- }
-
- /**
* Get the first token for this function
* @return the first token
*/
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java
--- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Mon Apr 29 21:38:08 2013 -0300
@@ -27,7 +27,6 @@
import java.io.File;
import java.util.Iterator;
import java.util.NoSuchElementException;
-
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.Source;
@@ -171,6 +170,7 @@
public T pop(final T node) {
--sp;
final LexicalContextNode popped = stack[sp];
+ stack[sp] = null;
if (popped instanceof Flags) {
return (T)((Flags>)popped).setFlag(this, flags[sp]);
}
@@ -420,14 +420,6 @@
}
/**
- * Check if lexical context is currently inside a with block
- * @return true if in a with block
- */
- public boolean inWith() {
- return getScopeNestingLevelTo(null) > 0;
- }
-
- /**
* Count the number of with scopes until a given node
* @param until node to stop counting at, or null if all nodes should be counted
* @return number of with scopes encountered in the context
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
--- a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java Mon Apr 29 21:38:08 2013 -0300
@@ -40,7 +40,7 @@
BoundScriptFunctionImpl(ScriptFunctionData data, ScriptFunction targetFunction) {
super(data);
- this.prototype = ScriptRuntime.UNDEFINED;
+ setPrototype(ScriptRuntime.UNDEFINED);
this.targetFunction = targetFunction;
}
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Mon Apr 29 21:38:08 2013 -0300
@@ -418,7 +418,7 @@
long length;
if (len instanceof Integer || len instanceof Long) {
length = ((Number) len).longValue();
- if (length >= 0 && length < 0xffff_ffffL) {
+ if (length >= 0 && length < JSType.MAX_UINT) {
return new NativeArray(length);
}
}
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/NativeDate.java
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Mon Apr 29 21:38:08 2013 -0300
@@ -182,7 +182,8 @@
@Override
public String safeToString() {
- return "[Date " + toISOStringImpl(this) + "]";
+ final String str = isValidDate() ? toISOStringImpl(this) : INVALID_DATE;
+ return "[Date " + str + "]";
}
@Override
@@ -518,7 +519,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object getTimezoneOffset(final Object self) {
final NativeDate nd = getNativeDate(self);
- if (nd != null) {
+ if (nd != null && nd.isValidDate()) {
final long msec = (long) nd.getTime();
return - nd.getTimeZone().getOffset(msec) / msPerMinute;
}
@@ -534,8 +535,8 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object setTime(final Object self, final Object time) {
+ final NativeDate nd = getNativeDate(self);
final double num = timeClip(JSType.toNumber(time));
- final NativeDate nd = getNativeDate(self);
nd.setTime(num);
return num;
}
@@ -550,9 +551,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object setMilliseconds(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MILLISECOND, args, true);
- }
+ setFields(nd, MILLISECOND, args, true);
return nd.getTime();
}
@@ -566,9 +565,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object setUTCMilliseconds(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MILLISECOND, args, false);
- }
+ setFields(nd, MILLISECOND, args, false);
return nd.getTime();
}
@@ -582,9 +579,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
public static Object setSeconds(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, SECOND, args, true);
- }
+ setFields(nd, SECOND, args, true);
return nd.getTime();
}
@@ -598,9 +593,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
public static Object setUTCSeconds(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, SECOND, args, false);
- }
+ setFields(nd, SECOND, args, false);
return nd.getTime();
}
@@ -614,9 +607,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
public static Object setMinutes(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MINUTE, args, true);
- }
+ setFields(nd, MINUTE, args, true);
return nd.getTime();
}
@@ -630,9 +621,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
public static Object setUTCMinutes(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MINUTE, args, false);
- }
+ setFields(nd, MINUTE, args, false);
return nd.getTime();
}
@@ -646,9 +635,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
public static Object setHours(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, HOUR, args, true);
- }
+ setFields(nd, HOUR, args, true);
return nd.getTime();
}
@@ -662,9 +649,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
public static Object setUTCHours(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, HOUR, args, false);
- }
+ setFields(nd, HOUR, args, false);
return nd.getTime();
}
@@ -678,9 +663,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object setDate(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, DAY, args, true);
- }
+ setFields(nd, DAY, args, true);
return nd.getTime();
}
@@ -694,9 +677,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object setUTCDate(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, DAY, args, false);
- }
+ setFields(nd, DAY, args, false);
return nd.getTime();
}
@@ -710,9 +691,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
public static Object setMonth(final Object self, final Object... args) {
final NativeDate nd = getNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MONTH, args, true);
- }
+ setFields(nd, MONTH, args, true);
return nd.getTime();
}
@@ -726,9 +705,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
public static Object setUTCMonth(final Object self, final Object... args) {
final NativeDate nd = ensureNativeDate(self);
- if (nd.isValidDate()) {
- setFields(nd, MONTH, args, false);
- }
+ setFields(nd, MONTH, args, false);
return nd.getTime();
}
@@ -746,7 +723,11 @@
setFields(nd, YEAR, args, true);
} else {
final double[] d = convertArgs(args, 0, YEAR, YEAR, 3);
- nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone())));
+ if (d != null) {
+ nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone())));
+ } else {
+ nd.setTime(NaN);
+ }
}
return nd.getTime();
}
@@ -781,13 +762,13 @@
public static Object setYear(final Object self, final Object year) {
final NativeDate nd = getNativeDate(self);
if (isNaN(nd.getTime())) {
- return null;
+ nd.setTime(utc(0, nd.getTimeZone()));
}
final double yearNum = JSType.toNumber(year);
if (isNaN(yearNum)) {
nd.setTime(NaN);
- return nd;
+ return nd.getTime();
}
int yearInt = JSType.toInteger(yearNum);
if (0 <= yearInt && yearInt <= 99) {
@@ -795,7 +776,7 @@
}
setFields(nd, YEAR, new Object[] {yearInt}, true);
- return nd;
+ return nd.getTime();
}
/**
@@ -1297,6 +1278,10 @@
final double time = local ? nd.getLocalTime() : nd.getTime();
final double d[] = convertArgs(args, time, fieldId, start, length);
+ if (! nd.isValidDate()) {
+ return;
+ }
+
double newTime;
if (d == null) {
newTime = NaN;
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java Mon Apr 29 21:38:08 2013 -0300
@@ -247,7 +247,6 @@
out.println("Scope count " + ScriptObject.getScopeCount());
out.println("ScriptObject listeners added " + PropertyListenerManager.getListenersAdded());
out.println("ScriptObject listeners removed " + PropertyListenerManager.getListenersRemoved());
- out.println("ScriptObject listeners dead " + PropertyListenerManager.getListenersDead());
out.println("ScriptFunction count " + ScriptObject.getCount());
out.println("ScriptFunction invokes " + ScriptFunction.getInvokes());
out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java Mon Apr 29 21:38:08 2013 -0300
@@ -229,7 +229,7 @@
final JSType type = JSType.of(value);
if (type == JSType.OBJECT) {
if (isArray(value)) {
- return JA((NativeArray)value, state);
+ return JA((ScriptObject)value, state);
} else if (value instanceof ScriptObject) {
return JO((ScriptObject)value, state);
}
@@ -315,7 +315,7 @@
}
// Spec: The abstract operation JA(value) serializes an array.
- private static Object JA(final NativeArray value, final StringifyState state) {
+ private static Object JA(final ScriptObject value, final StringifyState state) {
if (state.stack.containsKey(value)) {
throw typeError("JSON.stringify.cyclic");
}
diff -r dcd15316ca81 -r f4480af13364 nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Tue Apr 23 15:09:23 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Mon Apr 29 21:38:08 2013 -0300
@@ -523,23 +523,28 @@
}
private RegExpResult execInner(final String string) {
+ final boolean isGlobal = regexp.isGlobal();
int start = getLastIndex();
- if (! regexp.isGlobal()) {
+ if (!isGlobal) {
start = 0;
}
if (start < 0 || start > string.length()) {
- setLastIndex(0);
+ if (isGlobal) {
+ setLastIndex(0);
+ }
return null;
}
final RegExpMatcher matcher = regexp.match(string);
if (matcher == null || !matcher.search(start)) {
- setLastIndex(0);
+ if (isGlobal) {
+ setLastIndex(0);
+ }
return null;
}
- if (regexp.isGlobal()) {
+ if (isGlobal) {
setLastIndex(matcher.end());
}
@@ -548,6 +553,22 @@
return match;
}
+ // String.prototype.split method ignores the global flag and should not update lastIndex property.
+ private RegExpResult execSplit(final String string, int start) {
+ if (start < 0 || start > string.length()) {
+ return null;
+ }
+
+ final RegExpMatcher matcher = regexp.match(string);
+ if (matcher == null || !matcher.search(start)) {
+ return null;
+ }
+
+ final RegExpResult match = new RegExpResult(string, matcher.start(), groups(matcher));
+ globalObject.setLastRegExpResult(match);
+ return match;
+ }
+
/**
* Convert java.util.regex.Matcher groups to JavaScript groups.
* That is, replace null and groups that didn't match with undefined.
@@ -600,7 +621,7 @@
* @return True if a match is found.
*/
public Object test(final String string) {
- return exec(string) != null;
+ return execInner(string) != null;
}
/**
@@ -765,35 +786,31 @@
* @return Array of substrings.
*/
Object split(final String string, final long limit) {
- return split(this, string, limit);
- }
-
- private static Object split(final NativeRegExp regexp0, final String input, final long limit) {
- final List