Tue, 12 Mar 2013 15:30:53 +0100
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
Reviewed-by: attila, jlaskey
1.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Tue Mar 12 18:12:42 2013 +0530 1.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Tue Mar 12 15:30:53 2013 +0100 1.3 @@ -42,6 +42,7 @@ 1.4 1.5 import java.util.ArrayList; 1.6 import java.util.HashSet; 1.7 +import java.util.Iterator; 1.8 import java.util.LinkedList; 1.9 import java.util.List; 1.10 import java.util.Set; 1.11 @@ -51,6 +52,7 @@ 1.12 import jdk.nashorn.internal.ir.Block; 1.13 import jdk.nashorn.internal.ir.CallNode; 1.14 import jdk.nashorn.internal.ir.CallNode.EvalArgs; 1.15 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 1.16 import jdk.nashorn.internal.ir.CaseNode; 1.17 import jdk.nashorn.internal.ir.CatchNode; 1.18 import jdk.nashorn.internal.ir.ForNode; 1.19 @@ -332,8 +334,14 @@ 1.20 functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this)); 1.21 } 1.22 1.23 + if (functionNode.hasLazyChildren()) { 1.24 + objectifySymbols(functionNode); 1.25 + } 1.26 + 1.27 functionNode.popFrame(); 1.28 1.29 + functionNode.setState(CompilationState.ATTR); 1.30 + 1.31 end(functionNode, false); 1.32 1.33 return null; 1.34 @@ -957,20 +965,17 @@ 1.35 1.36 @Override 1.37 public Node leaveBIT_AND(final BinaryNode binaryNode) { 1.38 - newTemporary(Type.INT, binaryNode); 1.39 - return binaryNode; 1.40 + return end(coerce(binaryNode, Type.INT)); 1.41 } 1.42 1.43 @Override 1.44 public Node leaveBIT_OR(final BinaryNode binaryNode) { 1.45 - newTemporary(Type.INT, binaryNode); 1.46 - return binaryNode; 1.47 + return end(coerce(binaryNode, Type.INT)); 1.48 } 1.49 1.50 @Override 1.51 public Node leaveBIT_XOR(final BinaryNode binaryNode) { 1.52 - newTemporary(Type.INT, binaryNode); 1.53 - return binaryNode; 1.54 + return end(coerce(binaryNode, Type.INT)); 1.55 } 1.56 1.57 @Override 1.58 @@ -1002,14 +1007,28 @@ 1.59 return binaryNode; 1.60 } 1.61 1.62 + private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) { 1.63 + // TODO we currently don't support changing inferred type based on uses, only on 1.64 + // definitions. we would need some additional logic. We probably want to do that 1.65 + // in the future, if e.g. a specialized method gets parameter that is only used 1.66 + // as, say, an int : function(x) { return x & 4711 }, and x is not defined in 1.67 + // the function. to make this work, uncomment the following two type inferences 1.68 + // and debug. 1.69 + 1.70 + //newType(binaryNode.lhs().getSymbol(), operandType); 1.71 + //newType(binaryNode.rhs().getSymbol(), operandType); 1.72 + newTemporary(destType, binaryNode); 1.73 + return binaryNode; 1.74 + } 1.75 + 1.76 + private Node coerce(final BinaryNode binaryNode, final Type type) { 1.77 + return coerce(binaryNode, type, type); 1.78 + } 1.79 + 1.80 //leave a binary node and inherit the widest type of lhs , rhs 1.81 private Node leaveBinaryArithmetic(final BinaryNode binaryNode) { 1.82 - if (!Compiler.shouldUseIntegerArithmetic()) { 1.83 - newTemporary(Type.NUMBER, binaryNode); 1.84 - return binaryNode; 1.85 - } 1.86 - newTemporary(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType(), Type.NUMBER), binaryNode); 1.87 - return binaryNode; 1.88 + assert !Compiler.shouldUseIntegerArithmetic(); 1.89 + return end(coerce(binaryNode, Type.NUMBER)); 1.90 } 1.91 1.92 @Override 1.93 @@ -1089,23 +1108,17 @@ 1.94 1.95 @Override 1.96 public Node leaveSAR(final BinaryNode binaryNode) { 1.97 - newTemporary(Type.INT, binaryNode); 1.98 - end(binaryNode); 1.99 - return binaryNode; 1.100 + return end(coerce(binaryNode, Type.INT)); 1.101 } 1.102 1.103 @Override 1.104 public Node leaveSHL(final BinaryNode binaryNode) { 1.105 - newTemporary(Type.INT, binaryNode); 1.106 - end(binaryNode); 1.107 - return binaryNode; 1.108 + return end(coerce(binaryNode, Type.INT)); 1.109 } 1.110 1.111 @Override 1.112 public Node leaveSHR(final BinaryNode binaryNode) { 1.113 - newTemporary(Type.LONG, binaryNode); 1.114 - end(binaryNode); 1.115 - return binaryNode; 1.116 + return end(coerce(binaryNode, Type.LONG)); 1.117 } 1.118 1.119 @Override 1.120 @@ -1211,11 +1224,17 @@ 1.121 // type or its parameters with the widest (OBJECT) type for safety. 1.122 functionNode.setReturnType(Type.UNKNOWN); 1.123 1.124 - for (final IdentNode ident : functionNode.getParameters()) { 1.125 - addLocalDef(ident.getName()); 1.126 - final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident); 1.127 + for (final IdentNode param : functionNode.getParameters()) { 1.128 + addLocalDef(param.getName()); 1.129 + final Symbol paramSymbol = functionNode.defineSymbol(param.getName(), IS_PARAM, param); 1.130 if (paramSymbol != null) { 1.131 - newType(paramSymbol, Type.UNKNOWN); 1.132 + final Type callSiteParamType = functionNode.getSpecializedType(param); 1.133 + if (callSiteParamType != null) { 1.134 + LOG.info("Param " + paramSymbol + " has a callsite type " + callSiteParamType + ". Using that."); 1.135 + 1.136 + System.err.println("Param " + param + " has a callsite type " + callSiteParamType + ". Using that."); 1.137 + } 1.138 + newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); 1.139 } 1.140 1.141 LOG.info("Initialized param " + paramSymbol); 1.142 @@ -1229,36 +1248,29 @@ 1.143 * @param functionNode functionNode 1.144 */ 1.145 private static void finalizeParameters(final FunctionNode functionNode) { 1.146 - boolean nonObjectParams = false; 1.147 - List<Type> paramSpecializations = new ArrayList<>(); 1.148 + final boolean isVarArg = functionNode.isVarArg(); 1.149 1.150 for (final IdentNode ident : functionNode.getParameters()) { 1.151 final Symbol paramSymbol = ident.getSymbol(); 1.152 - if (paramSymbol != null) { 1.153 - Type type = paramSymbol.getSymbolType(); 1.154 - if (type.isUnknown()) { 1.155 - type = Type.OBJECT; 1.156 - } 1.157 - paramSpecializations.add(type); 1.158 - if (!type.isObject()) { 1.159 - nonObjectParams = true; 1.160 - } 1.161 - newType(paramSymbol, Type.OBJECT); 1.162 + 1.163 + assert paramSymbol != null; 1.164 + Type type = functionNode.getSpecializedType(ident); 1.165 + if (type == null) { 1.166 + type = Type.OBJECT; 1.167 } 1.168 - } 1.169 1.170 - if (!nonObjectParams) { 1.171 - paramSpecializations = null; 1.172 - // Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters 1.173 - // here. If the callee has parameter specializations, we can regenerate it with those particular types for speed. 1.174 - } else { 1.175 - LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations); 1.176 - } 1.177 + // if we know that a parameter is only used as a certain type throughout 1.178 + // this function, we can tell the runtime system that no matter what the 1.179 + // call site is, use this information. TODO 1.180 + if (!paramSymbol.getSymbolType().isObject()) { 1.181 + LOG.finest("Parameter " + ident + " could profit from specialization to " + paramSymbol.getSymbolType()); 1.182 + } 1.183 1.184 - // parameters should not be slots for a function that uses variable arity signature 1.185 - if (functionNode.isVarArg()) { 1.186 - for (final IdentNode param : functionNode.getParameters()) { 1.187 - param.getSymbol().setNeedsSlot(false); 1.188 + newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); 1.189 + 1.190 + // parameters should not be slots for a function that uses variable arity signature 1.191 + if (isVarArg) { 1.192 + paramSymbol.setNeedsSlot(false); 1.193 } 1.194 } 1.195 } 1.196 @@ -1548,6 +1560,39 @@ 1.197 localUses.add(name); 1.198 } 1.199 1.200 + /** 1.201 + * Pessimistically promote all symbols in current function node to Object types 1.202 + * This is done when the function contains unevaluated black boxes such as 1.203 + * lazy sub-function nodes that have not been compiled. 1.204 + * 1.205 + * @param functionNode function node in whose scope symbols should conservatively be made objects 1.206 + */ 1.207 + private static void objectifySymbols(final FunctionNode functionNode) { 1.208 + functionNode.accept(new NodeVisitor() { 1.209 + private void toObject(final Block block) { 1.210 + for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) { 1.211 + final Symbol symbol = iter.next(); 1.212 + newType(symbol, Type.OBJECT); 1.213 + } 1.214 + } 1.215 + 1.216 + @Override 1.217 + public Node enter(final Block block) { 1.218 + toObject(block); 1.219 + return block; 1.220 + } 1.221 + 1.222 + @Override 1.223 + public Node enter(final FunctionNode node) { 1.224 + toObject(node); 1.225 + if (node.isLazy()) { 1.226 + return null; 1.227 + } 1.228 + return node; 1.229 + } 1.230 + }); 1.231 + } 1.232 + 1.233 private static String name(final Node node) { 1.234 final String cn = node.getClass().getName(); 1.235 int lastDot = cn.lastIndexOf('.');
2.1 --- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Tue Mar 12 18:12:42 2013 +0530 2.2 +++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Tue Mar 12 15:30:53 2013 +0100 2.3 @@ -32,7 +32,6 @@ 2.4 import static jdk.nashorn.internal.codegen.Condition.LT; 2.5 import static jdk.nashorn.internal.codegen.Condition.NE; 2.6 2.7 -import jdk.nashorn.internal.codegen.Label; 2.8 import jdk.nashorn.internal.codegen.types.Type; 2.9 import jdk.nashorn.internal.ir.BinaryNode; 2.10 import jdk.nashorn.internal.ir.Node;
3.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Mar 12 18:12:42 2013 +0530 3.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Mar 12 15:30:53 2013 +0100 3.3 @@ -25,10 +25,8 @@ 3.4 3.5 package jdk.nashorn.internal.codegen; 3.6 3.7 -import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; 3.8 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; 3.9 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; 3.10 -import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; 3.11 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; 3.12 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; 3.13 import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; 3.14 @@ -50,7 +48,6 @@ 3.15 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; 3.16 3.17 import java.io.PrintWriter; 3.18 -import java.lang.invoke.MethodHandle; 3.19 import java.util.ArrayList; 3.20 import java.util.Arrays; 3.21 import java.util.EnumSet; 3.22 @@ -84,6 +81,7 @@ 3.23 import jdk.nashorn.internal.ir.IndexNode; 3.24 import jdk.nashorn.internal.ir.LineNumberNode; 3.25 import jdk.nashorn.internal.ir.LiteralNode; 3.26 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 3.27 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 3.28 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 3.29 import jdk.nashorn.internal.ir.Node; 3.30 @@ -108,14 +106,13 @@ 3.31 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 3.32 import jdk.nashorn.internal.parser.Lexer.RegexToken; 3.33 import jdk.nashorn.internal.parser.TokenType; 3.34 -import jdk.nashorn.internal.runtime.CodeInstaller; 3.35 import jdk.nashorn.internal.runtime.Context; 3.36 import jdk.nashorn.internal.runtime.ECMAException; 3.37 import jdk.nashorn.internal.runtime.Property; 3.38 import jdk.nashorn.internal.runtime.PropertyMap; 3.39 +import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 3.40 import jdk.nashorn.internal.runtime.Scope; 3.41 import jdk.nashorn.internal.runtime.ScriptFunction; 3.42 -import jdk.nashorn.internal.runtime.ScriptFunctionData; 3.43 import jdk.nashorn.internal.runtime.ScriptObject; 3.44 import jdk.nashorn.internal.runtime.ScriptRuntime; 3.45 import jdk.nashorn.internal.runtime.Source; 3.46 @@ -149,8 +146,6 @@ 3.47 /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ 3.48 private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; 3.49 3.50 - private static final String SCRIPTFUNCTION_TRAMPOLINE_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionTrampolineImpl"; 3.51 - 3.52 /** Constant data & installation. The only reason the compiler keeps this is because it is assigned 3.53 * by reflection in class installation */ 3.54 private final Compiler compiler; 3.55 @@ -982,6 +977,7 @@ 3.56 method.label(functionNode.getEntryLabel()); 3.57 3.58 initLocals(functionNode); 3.59 + functionNode.setState(CompilationState.EMITTED); 3.60 3.61 return functionNode; 3.62 } 3.63 @@ -3234,42 +3230,23 @@ 3.64 } 3.65 3.66 private void newFunctionObject(final FunctionNode functionNode) { 3.67 - final boolean isLazy = functionNode.isLazy(); 3.68 - final Class<?>[] cparams = new Class<?>[] { ScriptFunctionData.class, ScriptObject.class, MethodHandle.class }; 3.69 + final boolean isLazy = functionNode.isLazy(); 3.70 + final Class<?>[] cparams = new Class<?>[] { RecompilableScriptFunctionData.class, ScriptObject.class }; 3.71 3.72 new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) { 3.73 @Override 3.74 - protected void makeObject(final MethodEmitter method) { 3.75 - final String className = isLazy ? SCRIPTFUNCTION_TRAMPOLINE_OBJECT : SCRIPTFUNCTION_IMPL_OBJECT; 3.76 - 3.77 - method._new(className).dup(); 3.78 - if (isLazy) { 3.79 - loadConstant(compiler.getCodeInstaller()); 3.80 - loadConstant(functionNode); 3.81 + protected void makeObject(final MethodEmitter m) { 3.82 + final String className = SCRIPTFUNCTION_IMPL_OBJECT; 3.83 + 3.84 + m._new(className).dup(); 3.85 + loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap())); 3.86 + 3.87 + if (isLazy || functionNode.needsParentScope()) { 3.88 + m.loadScope(); 3.89 } else { 3.90 - final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); 3.91 - method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function 3.92 + m.loadNull(); 3.93 } 3.94 - loadConstant(new ScriptFunctionData(functionNode, makeMap())); 3.95 - 3.96 - if (isLazy || functionNode.needsParentScope()) { 3.97 - method.loadScope(); 3.98 - } else { 3.99 - method.loadNull(); 3.100 - } 3.101 - 3.102 - method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); 3.103 - 3.104 - final List<Class<?>> cparamList = new ArrayList<>(); 3.105 - if (isLazy) { 3.106 - cparamList.add(CodeInstaller.class); 3.107 - cparamList.add(FunctionNode.class); 3.108 - } else { 3.109 - cparamList.add(MethodHandle.class); 3.110 - } 3.111 - cparamList.addAll(Arrays.asList(cparams)); 3.112 - 3.113 - method.invoke(constructorNoLookup(className, cparamList.toArray(new Class<?>[cparamList.size()]))); 3.114 + m.invoke(constructorNoLookup(className, cparams)); 3.115 } 3.116 }.makeObject(method); 3.117 }
4.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Mar 12 18:12:42 2013 +0530 4.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Mar 12 15:30:53 2013 +0100 4.3 @@ -2,10 +2,10 @@ 4.4 4.5 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.ATTR; 4.6 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED; 4.7 -import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.EMITTED; 4.8 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED; 4.9 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED; 4.10 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED; 4.11 +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED; 4.12 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; 4.13 4.14 import java.io.File; 4.15 @@ -39,7 +39,7 @@ 4.16 * default policy. The will get trampolines and only be generated when 4.17 * called 4.18 */ 4.19 - LAZY_INITIALIZATION_PHASE(EnumSet.of(FunctionNode.CompilationState.INITIALIZED)) { 4.20 + LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { 4.21 @Override 4.22 void transform(final Compiler compiler, final FunctionNode fn) { 4.23 4.24 @@ -79,9 +79,11 @@ 4.25 if (node == outermostFunctionNode) { 4.26 return node; 4.27 } 4.28 - assert Compiler.LAZY_JIT; 4.29 + assert compiler.isLazy(); 4.30 lazy.add(node); 4.31 4.32 + //also needs scope, potentially needs arguments etc etc 4.33 + 4.34 return node; 4.35 } 4.36 }); 4.37 @@ -113,7 +115,7 @@ 4.38 * Constant folding pass 4.39 * Simple constant folding that will make elementary constructs go away 4.40 */ 4.41 - CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED), CONSTANT_FOLDED) { 4.42 + CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED, PARSED)) { 4.43 @Override 4.44 void transform(final Compiler compiler, final FunctionNode fn) { 4.45 fn.accept(new FoldConstants()); 4.46 @@ -134,7 +136,7 @@ 4.47 * as runtime nodes where applicable. 4.48 * 4.49 */ 4.50 - LOWERING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED), LOWERED) { 4.51 + LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) { 4.52 @Override 4.53 void transform(final Compiler compiler, final FunctionNode fn) { 4.54 fn.accept(new Lower()); 4.55 @@ -150,19 +152,10 @@ 4.56 * Attribution 4.57 * Assign symbols and types to all nodes. 4.58 */ 4.59 - ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED), ATTR) { 4.60 + ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { 4.61 @Override 4.62 void transform(final Compiler compiler, final FunctionNode fn) { 4.63 - final ScriptEnvironment env = compiler.getEnv(); 4.64 - 4.65 fn.accept(new Attr()); 4.66 - if (env._print_lower_ast) { 4.67 - env.getErr().println(new ASTWriter(fn)); 4.68 - } 4.69 - 4.70 - if (env._print_lower_parse) { 4.71 - env.getErr().println(new PrintVisitor(fn)); 4.72 - } 4.73 } 4.74 4.75 @Override 4.76 @@ -178,7 +171,7 @@ 4.77 * a + b a ScriptRuntime.ADD with call overhead or a dadd with much 4.78 * less). Split IR can lead to scope information being changed. 4.79 */ 4.80 - SPLITTING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR), SPLIT) { 4.81 + SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { 4.82 @Override 4.83 void transform(final Compiler compiler, final FunctionNode fn) { 4.84 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); 4.85 @@ -212,10 +205,20 @@ 4.86 * Contract: all variables must have slot assignments and scope assignments 4.87 * before type finalization. 4.88 */ 4.89 - TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT), FINALIZED) { 4.90 + TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT)) { 4.91 @Override 4.92 void transform(final Compiler compiler, final FunctionNode fn) { 4.93 + final ScriptEnvironment env = compiler.getEnv(); 4.94 + 4.95 fn.accept(new FinalizeTypes()); 4.96 + 4.97 + if (env._print_lower_ast) { 4.98 + env.getErr().println(new ASTWriter(fn)); 4.99 + } 4.100 + 4.101 + if (env._print_lower_parse) { 4.102 + env.getErr().println(new PrintVisitor(fn)); 4.103 + } 4.104 } 4.105 4.106 @Override 4.107 @@ -229,7 +232,7 @@ 4.108 * 4.109 * Generate the byte code class(es) resulting from the compiled FunctionNode 4.110 */ 4.111 - BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED), EMITTED) { 4.112 + BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) { 4.113 @Override 4.114 void transform(final Compiler compiler, final FunctionNode fn) { 4.115 final ScriptEnvironment env = compiler.getEnv(); 4.116 @@ -306,18 +309,12 @@ 4.117 }; 4.118 4.119 private final EnumSet<CompilationState> pre; 4.120 - private final CompilationState post; 4.121 private long startTime; 4.122 private long endTime; 4.123 private boolean isFinished; 4.124 4.125 private CompilationPhase(final EnumSet<CompilationState> pre) { 4.126 - this(pre, null); 4.127 - } 4.128 - 4.129 - private CompilationPhase(final EnumSet<CompilationState> pre, final CompilationState post) { 4.130 - this.pre = pre; 4.131 - this.post = post; 4.132 + this.pre = pre; 4.133 } 4.134 4.135 boolean isApplicable(final FunctionNode functionNode) { 4.136 @@ -343,10 +340,6 @@ 4.137 endTime = System.currentTimeMillis(); 4.138 Timing.accumulateTime(toString(), endTime - startTime); 4.139 4.140 - if (post != null) { 4.141 - functionNode.setState(post); 4.142 - } 4.143 - 4.144 isFinished = true; 4.145 } 4.146
5.1 --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java Tue Mar 12 18:12:42 2013 +0530 5.2 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java Tue Mar 12 15:30:53 2013 +0100 5.3 @@ -37,6 +37,8 @@ 5.4 5.5 private long weight; 5.6 5.7 + private Class<?> clazz; 5.8 + 5.9 CompileUnit(final String className, final ClassEmitter classEmitter) { 5.10 this(className, classEmitter, 0L); 5.11 } 5.12 @@ -48,6 +50,24 @@ 5.13 } 5.14 5.15 /** 5.16 + * Return the class that contains the code for this unit, null if not 5.17 + * generated yet 5.18 + * 5.19 + * @return class with compile unit code 5.20 + */ 5.21 + public Class<?> getCode() { 5.22 + return clazz; 5.23 + } 5.24 + 5.25 + /** 5.26 + * Set class when it exists. Only accessible from compiler 5.27 + * @param clazz class with code for this compile unit 5.28 + */ 5.29 + void setCode(final Class<?> clazz) { 5.30 + this.clazz = clazz; 5.31 + } 5.32 + 5.33 + /** 5.34 * Add weight to this compile unit 5.35 * @param w weight to add 5.36 */
6.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Tue Mar 12 18:12:42 2013 +0530 6.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Tue Mar 12 15:30:53 2013 +0100 6.3 @@ -45,11 +45,15 @@ 6.4 import java.util.Map; 6.5 import java.util.Map.Entry; 6.6 import java.util.Set; 6.7 +import java.util.logging.Level; 6.8 + 6.9 import jdk.internal.dynalink.support.NameCodec; 6.10 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 6.11 import jdk.nashorn.internal.codegen.types.Type; 6.12 import jdk.nashorn.internal.ir.FunctionNode; 6.13 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 6.14 +import jdk.nashorn.internal.ir.Node; 6.15 +import jdk.nashorn.internal.ir.visitor.NodeVisitor; 6.16 import jdk.nashorn.internal.runtime.CodeInstaller; 6.17 import jdk.nashorn.internal.runtime.DebugLogger; 6.18 import jdk.nashorn.internal.runtime.ScriptEnvironment; 6.19 @@ -71,8 +75,6 @@ 6.20 /** Name of the objects package */ 6.21 public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; 6.22 6.23 - static final boolean LAZY_JIT = Options.getBooleanProperty("nashorn.compiler.lazy"); 6.24 - 6.25 private final Map<String, byte[]> bytecode; 6.26 6.27 private final Set<CompileUnit> compileUnits; 6.28 @@ -164,7 +166,7 @@ 6.29 * and JIT it at once. This can lead to long startup time and fewer type 6.30 * specializations 6.31 */ 6.32 - final static CompilationSequence SEQUENCE_NORMAL = new CompilationSequence( 6.33 + final static CompilationSequence SEQUENCE_EAGER = new CompilationSequence( 6.34 CompilationPhase.CONSTANT_FOLDING_PHASE, 6.35 CompilationPhase.LOWERING_PHASE, 6.36 CompilationPhase.ATTRIBUTION_PHASE, 6.37 @@ -173,12 +175,15 @@ 6.38 CompilationPhase.BYTECODE_GENERATION_PHASE); 6.39 6.40 final static CompilationSequence SEQUENCE_LAZY = 6.41 - SEQUENCE_NORMAL.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE); 6.42 + SEQUENCE_EAGER.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE); 6.43 6.44 - final static CompilationSequence SEQUENCE_DEFAULT = 6.45 - LAZY_JIT ? 6.46 - SEQUENCE_LAZY : 6.47 - SEQUENCE_NORMAL; 6.48 + private static CompilationSequence sequence(final boolean lazy) { 6.49 + return lazy ? SEQUENCE_LAZY : SEQUENCE_EAGER; 6.50 + } 6.51 + 6.52 + boolean isLazy() { 6.53 + return sequence == SEQUENCE_LAZY; 6.54 + } 6.55 6.56 private static String lazyTag(final FunctionNode functionNode) { 6.57 if (functionNode.isLazy()) { 6.58 @@ -213,10 +218,7 @@ 6.59 6.60 this.scriptName = sb.toString(); 6.61 6.62 - LOG.info("Initializing compiler for '" + functionNode.getName() + "' scriptName = " + scriptName + ", root function: '" + functionNode.getName() + "'"); 6.63 - if (functionNode.isLazy()) { 6.64 - LOG.info(">>> This is a lazy recompilation triggered by a trampoline"); 6.65 - } 6.66 + LOG.info("Initializing compiler for '" + functionNode.getName() + "' scriptName = " + scriptName + ", root function: '" + functionNode.getName() + "' lazy=" + functionNode.isLazy()); 6.67 } 6.68 6.69 /** 6.70 @@ -227,7 +229,7 @@ 6.71 * @param strict should this compilation use strict mode semantics 6.72 */ 6.73 public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) { 6.74 - this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, strict); 6.75 + this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict); 6.76 } 6.77 6.78 /** 6.79 @@ -237,7 +239,7 @@ 6.80 * @param functionNode function node (in any available {@link CompilationState}) to compile 6.81 */ 6.82 public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) { 6.83 - this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, installer.getOwner()._strict); 6.84 + this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); 6.85 } 6.86 6.87 /** 6.88 @@ -247,28 +249,104 @@ 6.89 * @param functionNode functionNode to compile 6.90 */ 6.91 public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) { 6.92 - this(env, null, functionNode, SEQUENCE_DEFAULT, env._strict); 6.93 + this(env, null, functionNode, sequence(env._lazy_compilation), env._strict); 6.94 } 6.95 6.96 /** 6.97 * Execute the compilation this Compiler was created with 6.98 + * @params param types if known, for specialization 6.99 * @throws CompilationException if something goes wrong 6.100 + * @return this compiler, for possible chaining 6.101 */ 6.102 - public void compile() throws CompilationException { 6.103 + public Compiler compile() throws CompilationException { 6.104 + return compile(null); 6.105 + } 6.106 + 6.107 + /** 6.108 + * Execute the compilation this Compiler was created with 6.109 + * @param paramTypes param types if known, for specialization 6.110 + * @throws CompilationException if something goes wrong 6.111 + * @return this compiler, for possible chaining 6.112 + */ 6.113 + public Compiler compile(final Class<?> paramTypes) throws CompilationException { 6.114 for (final String reservedName : RESERVED_NAMES) { 6.115 functionNode.uniqueName(reservedName); 6.116 } 6.117 6.118 + final boolean fine = !LOG.levelAbove(Level.FINE); 6.119 + final boolean info = !LOG.levelAbove(Level.INFO); 6.120 + 6.121 + long time = 0L; 6.122 + 6.123 for (final CompilationPhase phase : sequence) { 6.124 phase.apply(this, functionNode); 6.125 - final String end = phase.toString() + " done for function '" + functionNode.getName() + "'"; 6.126 - if (Timing.isEnabled()) { 6.127 - final long duration = phase.getEndTime() - phase.getStartTime(); 6.128 - LOG.info(end + " in " + duration + " ms"); 6.129 - } else { 6.130 - LOG.info(end); 6.131 + 6.132 + final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; 6.133 + time += duration; 6.134 + 6.135 + if (fine) { 6.136 + final StringBuilder sb = new StringBuilder(); 6.137 + 6.138 + sb.append(phase.toString()). 6.139 + append(" done for function '"). 6.140 + append(functionNode.getName()). 6.141 + append('\''); 6.142 + 6.143 + if (duration > 0L) { 6.144 + sb.append(" in "). 6.145 + append(duration). 6.146 + append(" ms "); 6.147 + } 6.148 + 6.149 + LOG.fine(sb.toString()); 6.150 } 6.151 } 6.152 + 6.153 + if (info) { 6.154 + final StringBuilder sb = new StringBuilder(); 6.155 + sb.append("Compile job for '"). 6.156 + append(functionNode.getName()). 6.157 + append("' finished"); 6.158 + 6.159 + if (time > 0L) { 6.160 + sb.append(" in "). 6.161 + append(time). 6.162 + append(" ms"); 6.163 + } 6.164 + 6.165 + LOG.info(sb.toString()); 6.166 + } 6.167 + 6.168 + return this; 6.169 + } 6.170 + 6.171 + private Class<?> install(final String className, final byte[] code) { 6.172 + LOG.fine("Installing class " + className); 6.173 + 6.174 + final Class<?> clazz = installer.install(Compiler.binaryName(className), code); 6.175 + 6.176 + try { 6.177 + final Source source = getSource(); 6.178 + final Object[] constants = getConstantData().toArray(); 6.179 + // Need doPrivileged because these fields are private 6.180 + AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 6.181 + @Override 6.182 + public Void run() throws Exception { 6.183 + //use reflection to write source and constants table to installed classes 6.184 + final Field sourceField = clazz.getDeclaredField(SOURCE.tag()); 6.185 + final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag()); 6.186 + sourceField.setAccessible(true); 6.187 + constantsField.setAccessible(true); 6.188 + sourceField.set(null, source); 6.189 + constantsField.set(null, constants); 6.190 + return null; 6.191 + } 6.192 + }); 6.193 + } catch (final PrivilegedActionException e) { 6.194 + throw new RuntimeException(e); 6.195 + } 6.196 + 6.197 + return clazz; 6.198 } 6.199 6.200 /** 6.201 @@ -280,42 +358,38 @@ 6.202 6.203 assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; 6.204 6.205 - Class<?> rootClass = null; 6.206 + final Map<String, Class<?>> installedClasses = new HashMap<>(); 6.207 + 6.208 + final String rootClassName = firstCompileUnitName(); 6.209 + final Class<?> rootClass = install(rootClassName, bytecode.get(rootClassName)); 6.210 + 6.211 + installedClasses.put(rootClassName, rootClass); 6.212 6.213 for (final Entry<String, byte[]> entry : bytecode.entrySet()) { 6.214 - final String className = entry.getKey(); 6.215 - LOG.fine("Installing class " + className); 6.216 - 6.217 - final byte[] code = entry.getValue(); 6.218 - final Class<?> clazz = installer.install(Compiler.binaryName(className), code); 6.219 - 6.220 - if (rootClass == null && firstCompileUnitName().equals(className)) { 6.221 - rootClass = clazz; 6.222 + final String className = entry.getKey(); 6.223 + if (className.equals(rootClassName)) { 6.224 + continue; 6.225 } 6.226 - 6.227 - try { 6.228 - final Source source = getSource(); 6.229 - final Object[] constants = getConstantData().toArray(); 6.230 - // Need doPrivileged because these fields are private 6.231 - AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 6.232 - @Override 6.233 - public Void run() throws Exception { 6.234 - //use reflection to write source and constants table to installed classes 6.235 - final Field sourceField = clazz.getDeclaredField(SOURCE.tag()); 6.236 - final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag()); 6.237 - sourceField.setAccessible(true); 6.238 - constantsField.setAccessible(true); 6.239 - sourceField.set(null, source); 6.240 - constantsField.set(null, constants); 6.241 - return null; 6.242 - } 6.243 - }); 6.244 - } catch (final PrivilegedActionException e) { 6.245 - throw new RuntimeException(e); 6.246 - } 6.247 + installedClasses.put(className, install(className, entry.getValue())); 6.248 } 6.249 6.250 + for (final CompileUnit unit : compileUnits) { 6.251 + unit.setCode(installedClasses.get(unit.getUnitClassName())); 6.252 + } 6.253 + 6.254 + functionNode.accept(new NodeVisitor() { 6.255 + @Override 6.256 + public Node enter(final FunctionNode node) { 6.257 + if (node.isLazy()) { 6.258 + return null; 6.259 + } 6.260 + node.setState(CompilationState.INSTALLED); 6.261 + return node; 6.262 + } 6.263 + }); 6.264 + 6.265 LOG.info("Installed root class: " + rootClass + " and " + bytecode.size() + " compile unit classes"); 6.266 + 6.267 if (Timing.isEnabled()) { 6.268 final long duration = System.currentTimeMillis() - t0; 6.269 Timing.accumulateTime("[Code Installation]", duration); 6.270 @@ -444,8 +518,6 @@ 6.271 * TODO: We currently generate no overflow checks so this is 6.272 * disabled 6.273 * 6.274 - * @see #shouldUseIntegers() 6.275 - * 6.276 * @return true if arithmetic operations should not widen integer 6.277 * operands by default. 6.278 */ 6.279 @@ -460,4 +532,5 @@ 6.280 assert !USE_INT_ARITH : "Integer arithmetic is not enabled"; 6.281 } 6.282 6.283 + 6.284 }
7.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Mar 12 18:12:42 2013 +0530 7.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Mar 12 15:30:53 2013 +0100 7.3 @@ -34,6 +34,7 @@ 7.4 import jdk.nashorn.internal.ir.Block; 7.5 import jdk.nashorn.internal.ir.CallNode; 7.6 import jdk.nashorn.internal.ir.CallNode.EvalArgs; 7.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 7.8 import jdk.nashorn.internal.ir.CaseNode; 7.9 import jdk.nashorn.internal.ir.CatchNode; 7.10 import jdk.nashorn.internal.ir.DoWhileNode; 7.11 @@ -235,19 +236,19 @@ 7.12 7.13 @Override 7.14 public Node leaveBIT_AND(BinaryNode binaryNode) { 7.15 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : binaryNode.getSymbol(); 7.16 + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 7.17 return leaveBinary(binaryNode, Type.INT, Type.INT); 7.18 } 7.19 7.20 @Override 7.21 public Node leaveBIT_OR(BinaryNode binaryNode) { 7.22 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger(); 7.23 + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 7.24 return leaveBinary(binaryNode, Type.INT, Type.INT); 7.25 } 7.26 7.27 @Override 7.28 public Node leaveBIT_XOR(BinaryNode binaryNode) { 7.29 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger(); 7.30 + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 7.31 return leaveBinary(binaryNode, Type.INT, Type.INT); 7.32 } 7.33 7.34 @@ -255,7 +256,7 @@ 7.35 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 7.36 assert binaryNode.getSymbol() != null; 7.37 binaryNode.setRHS(discard(binaryNode.rhs())); 7.38 - // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed 7.39 + // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed 7.40 // in that case, update the node type as well 7.41 propagateType(binaryNode, binaryNode.lhs().getType()); 7.42 return binaryNode; 7.43 @@ -344,7 +345,7 @@ 7.44 7.45 @Override 7.46 public Node leaveSHR(final BinaryNode binaryNode) { 7.47 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong(); 7.48 + assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol(); 7.49 return leaveBinary(binaryNode, Type.INT, Type.INT); 7.50 } 7.51 7.52 @@ -432,6 +433,8 @@ 7.53 } 7.54 7.55 updateSymbols(functionNode); 7.56 + functionNode.setState(CompilationState.FINALIZED); 7.57 + 7.58 return functionNode; 7.59 } 7.60 7.61 @@ -511,7 +514,6 @@ 7.62 7.63 @Override 7.64 public Node leave(final VarNode varNode) { 7.65 - 7.66 final Node rhs = varNode.getInit(); 7.67 if (rhs != null) { 7.68 Type destType = specialize(varNode);
8.1 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Mar 12 18:12:42 2013 +0530 8.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Mar 12 15:30:53 2013 +0100 8.3 @@ -30,11 +30,13 @@ 8.4 import jdk.nashorn.internal.ir.Block; 8.5 import jdk.nashorn.internal.ir.EmptyNode; 8.6 import jdk.nashorn.internal.ir.ExecuteNode; 8.7 +import jdk.nashorn.internal.ir.FunctionNode; 8.8 import jdk.nashorn.internal.ir.IfNode; 8.9 import jdk.nashorn.internal.ir.LiteralNode; 8.10 import jdk.nashorn.internal.ir.Node; 8.11 import jdk.nashorn.internal.ir.TernaryNode; 8.12 import jdk.nashorn.internal.ir.UnaryNode; 8.13 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 8.14 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 8.15 import jdk.nashorn.internal.runtime.DebugLogger; 8.16 import jdk.nashorn.internal.runtime.JSType; 8.17 @@ -72,6 +74,20 @@ 8.18 } 8.19 8.20 @Override 8.21 + public Node enter(final FunctionNode functionNode) { 8.22 + if (functionNode.isLazy()) { 8.23 + return null; 8.24 + } 8.25 + return functionNode; 8.26 + } 8.27 + 8.28 + @Override 8.29 + public Node leave(final FunctionNode functionNode) { 8.30 + functionNode.setState(CompilationState.CONSTANT_FOLDED); 8.31 + return functionNode; 8.32 + } 8.33 + 8.34 + @Override 8.35 public Node leave(final IfNode ifNode) { 8.36 final Node test = ifNode.getTest(); 8.37 if (test instanceof LiteralNode) {
9.1 --- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java Tue Mar 12 18:12:42 2013 +0530 9.2 +++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java Tue Mar 12 15:30:53 2013 +0100 9.3 @@ -146,7 +146,7 @@ 9.4 9.5 /** 9.6 * Create a function signature given a function node, using as much 9.7 - * type information for parameters and return types that is availabe 9.8 + * type information for parameters and return types that is available 9.9 * 9.10 * @param functionNode the function node 9.11 */ 9.12 @@ -202,6 +202,14 @@ 9.13 return methodType; 9.14 } 9.15 9.16 + /** 9.17 + * Return the return type for this function signature 9.18 + * @return the return type 9.19 + */ 9.20 + public Type getReturnType() { 9.21 + return returnType; 9.22 + } 9.23 + 9.24 private static Type[] objectArgs(final int nArgs) { 9.25 final Type[] array = new Type[nArgs]; 9.26 for (int i = 0; i < nArgs; i++) {
10.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java Tue Mar 12 18:12:42 2013 +0530 10.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Tue Mar 12 15:30:53 2013 +0100 10.3 @@ -69,6 +69,7 @@ 10.4 import jdk.nashorn.internal.ir.VarNode; 10.5 import jdk.nashorn.internal.ir.WhileNode; 10.6 import jdk.nashorn.internal.ir.WithNode; 10.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 10.8 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 10.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 10.10 import jdk.nashorn.internal.parser.Token; 10.11 @@ -332,6 +333,8 @@ 10.12 LOG.info("END FunctionNode: " + functionNode.getName()); 10.13 unnest(functionNode); 10.14 10.15 + functionNode.setState(CompilationState.LOWERED); 10.16 + 10.17 return null; 10.18 } 10.19 10.20 @@ -636,7 +639,7 @@ 10.21 } else if (conservativeAlwaysTrue(test)) { 10.22 node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish()); 10.23 ((ForNode)node).setBody(body); 10.24 - ((ForNode)node).accept(this); 10.25 + node.accept(this); 10.26 setTerminal(node, !escapes); 10.27 } 10.28 }
11.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java Tue Mar 12 18:12:42 2013 +0530 11.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Tue Mar 12 15:30:53 2013 +0100 11.3 @@ -39,6 +39,7 @@ 11.4 import jdk.nashorn.internal.ir.DoWhileNode; 11.5 import jdk.nashorn.internal.ir.ForNode; 11.6 import jdk.nashorn.internal.ir.FunctionNode; 11.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 11.8 import jdk.nashorn.internal.ir.LabelNode; 11.9 import jdk.nashorn.internal.ir.LiteralNode; 11.10 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 11.11 @@ -92,15 +93,16 @@ 11.12 */ 11.13 void split() { 11.14 if (functionNode.isLazy()) { 11.15 - LOG.fine("Postponing split of '" + functionNode.getName() + "' as it's lazy"); 11.16 + LOG.finest("Postponing split of '" + functionNode.getName() + "' as it's lazy"); 11.17 return; 11.18 } 11.19 - LOG.fine("Initiating split of '" + functionNode.getName() + "'"); 11.20 + 11.21 + LOG.finest("Initiating split of '" + functionNode.getName() + "'"); 11.22 11.23 long weight = WeighNodes.weigh(functionNode); 11.24 11.25 if (weight >= SPLIT_THRESHOLD) { 11.26 - LOG.fine("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); 11.27 + LOG.finest("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); 11.28 11.29 functionNode.accept(this); 11.30 11.31 @@ -133,6 +135,8 @@ 11.32 for (final FunctionNode function : functionNode.getFunctions()) { 11.33 new Splitter(compiler, function, outermostCompileUnit).split(); 11.34 } 11.35 + 11.36 + functionNode.setState(CompilationState.SPLIT); 11.37 } 11.38 11.39 /**
12.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java Tue Mar 12 18:12:42 2013 +0530 12.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Tue Mar 12 15:30:53 2013 +0100 12.3 @@ -647,21 +647,20 @@ 12.4 } 12.5 12.6 private static void swap(final MethodVisitor method, final Type above, final Type below) { 12.7 - final MethodVisitor mv = method; 12.8 if (below.isCategory2()) { 12.9 if (above.isCategory2()) { 12.10 - mv.visitInsn(DUP2_X2); 12.11 - mv.visitInsn(POP2); 12.12 + method.visitInsn(DUP2_X2); 12.13 + method.visitInsn(POP2); 12.14 } else { 12.15 - mv.visitInsn(DUP_X2); 12.16 - mv.visitInsn(POP); 12.17 + method.visitInsn(DUP_X2); 12.18 + method.visitInsn(POP); 12.19 } 12.20 } else { 12.21 if (above.isCategory2()) { 12.22 - mv.visitInsn(DUP2_X1); 12.23 - mv.visitInsn(POP2); 12.24 + method.visitInsn(DUP2_X1); 12.25 + method.visitInsn(POP2); 12.26 } else { 12.27 - mv.visitInsn(SWAP); 12.28 + method.visitInsn(SWAP); 12.29 } 12.30 } 12.31
13.1 --- a/src/jdk/nashorn/internal/ir/Block.java Tue Mar 12 18:12:42 2013 +0530 13.2 +++ b/src/jdk/nashorn/internal/ir/Block.java Tue Mar 12 15:30:53 2013 +0100 13.3 @@ -38,26 +38,25 @@ 13.4 import java.util.Collections; 13.5 import java.util.Comparator; 13.6 import java.util.HashMap; 13.7 +import java.util.Iterator; 13.8 import java.util.List; 13.9 import jdk.nashorn.internal.codegen.Frame; 13.10 import jdk.nashorn.internal.codegen.Label; 13.11 -import jdk.nashorn.internal.ir.annotations.Ignore; 13.12 -import jdk.nashorn.internal.ir.annotations.ParentNode; 13.13 +import jdk.nashorn.internal.ir.annotations.Reference; 13.14 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 13.15 import jdk.nashorn.internal.runtime.Source; 13.16 13.17 /** 13.18 * IR representation for a list of statements and functions. All provides the 13.19 * basis for script body. 13.20 - * 13.21 */ 13.22 public class Block extends Node { 13.23 /** Parent context */ 13.24 - @ParentNode @Ignore 13.25 + @Reference 13.26 private Block parent; 13.27 13.28 - /** Owning function. */ 13.29 - @Ignore //don't print it, it is apparent in the tree 13.30 + /** Owning function - a FunctionNode has itself as function */ 13.31 + @Reference 13.32 protected FunctionNode function; 13.33 13.34 /** List of statements */ 13.35 @@ -274,6 +273,14 @@ 13.36 } 13.37 13.38 /** 13.39 + * Get an iterator for all the symbols defined in this block 13.40 + * @return symbol iterator 13.41 + */ 13.42 + public Iterator<Symbol> symbolIterator() { 13.43 + return symbols.values().iterator(); 13.44 + } 13.45 + 13.46 + /** 13.47 * Search for symbol. 13.48 * 13.49 * @param name Symbol name.
14.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Mar 12 18:12:42 2013 +0530 14.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Mar 12 15:30:53 2013 +0100 14.3 @@ -33,8 +33,10 @@ 14.4 import java.util.ArrayList; 14.5 import java.util.Collections; 14.6 import java.util.EnumSet; 14.7 +import java.util.HashMap; 14.8 import java.util.LinkedList; 14.9 import java.util.List; 14.10 +import java.util.Map; 14.11 import java.util.Stack; 14.12 import jdk.nashorn.internal.codegen.CompileUnit; 14.13 import jdk.nashorn.internal.codegen.Compiler; 14.14 @@ -45,13 +47,13 @@ 14.15 import jdk.nashorn.internal.ir.annotations.Ignore; 14.16 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 14.17 import jdk.nashorn.internal.parser.Parser; 14.18 +import jdk.nashorn.internal.runtime.Debug; 14.19 import jdk.nashorn.internal.runtime.Source; 14.20 import jdk.nashorn.internal.runtime.UserAccessorProperty; 14.21 import jdk.nashorn.internal.runtime.linker.LinkerCallSite; 14.22 14.23 /** 14.24 * IR representation for function (or script.) 14.25 - * 14.26 */ 14.27 public class FunctionNode extends Block { 14.28 14.29 @@ -86,7 +88,9 @@ 14.30 /** method has had its types finalized */ 14.31 FINALIZED, 14.32 /** method has been emitted to bytecode */ 14.33 - EMITTED 14.34 + EMITTED, 14.35 + /** code installed in a class loader */ 14.36 + INSTALLED 14.37 } 14.38 14.39 /** External function identifier. */ 14.40 @@ -173,6 +177,9 @@ 14.41 @Ignore 14.42 private final EnumSet<CompilationState> compilationState; 14.43 14.44 + /** Type hints, e.g based on parameters at call site */ 14.45 + private final Map<IdentNode, Type> specializedTypes; 14.46 + 14.47 /** Function flags. */ 14.48 private int flags; 14.49 14.50 @@ -256,22 +263,27 @@ 14.51 // constructed, so it can't be seen from other threads. 14.52 this.function = this; 14.53 this.compilationState = EnumSet.of(CompilationState.INITIALIZED); 14.54 + this.specializedTypes = new HashMap<>(); 14.55 } 14.56 14.57 @SuppressWarnings("LeakingThisInConstructor") 14.58 private FunctionNode(final FunctionNode functionNode, final CopyState cs) { 14.59 super(functionNode, cs); 14.60 14.61 + this.functions = new ArrayList<>(); 14.62 + for (final FunctionNode f : functionNode.getFunctions()) { 14.63 + this.functions.add((FunctionNode)cs.existingOrCopy(f)); 14.64 + } 14.65 + 14.66 this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident); 14.67 this.name = functionNode.name; 14.68 this.kind = functionNode.kind; 14.69 14.70 this.parameters = new ArrayList<>(); 14.71 for (final IdentNode param : functionNode.getParameters()) { 14.72 - this.parameters.add((IdentNode) cs.existingOrCopy(param)); 14.73 + this.parameters.add((IdentNode)cs.existingOrCopy(param)); 14.74 } 14.75 14.76 - this.functions = new ArrayList<>(); 14.77 this.firstToken = functionNode.firstToken; 14.78 this.lastToken = functionNode.lastToken; 14.79 this.namespace = functionNode.getNamespace(); 14.80 @@ -300,6 +312,7 @@ 14.81 this.function = this; 14.82 14.83 this.compilationState = EnumSet.copyOf(functionNode.compilationState); 14.84 + this.specializedTypes = new HashMap<>(); 14.85 } 14.86 14.87 @Override 14.88 @@ -710,10 +723,14 @@ 14.89 * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to 14.90 * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object 14.91 * (since it exposes {@code arguments.callee} property) will need to have a callee parameter. 14.92 + * 14.93 + * We also conservatively need a callee if we have lazy children, i.e. nested function nodes that have not yet 14.94 + * been evaluated. _They_ may need the callee and we don't know it 14.95 + * 14.96 * @return true if the function's generated Java method needs a {@code callee} parameter. 14.97 */ 14.98 public boolean needsCallee() { 14.99 - return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode()); 14.100 + return hasLazyChildren() || needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode()); 14.101 } 14.102 14.103 /** 14.104 @@ -919,6 +936,27 @@ 14.105 } 14.106 14.107 /** 14.108 + * Get a specialized type for an identity, if one exists 14.109 + * @param node node to check specialized type for 14.110 + * @return null if no specialization exists, otherwise type 14.111 + */ 14.112 + public Type getSpecializedType(final IdentNode node) { 14.113 + return specializedTypes.get(node); 14.114 + } 14.115 + 14.116 + /** 14.117 + * Set parameter type hints for specialization. 14.118 + * @param types types array of length equal to parameter list size 14.119 + */ 14.120 + public void setParameterTypes(final Class<?>[] types) { 14.121 + assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types"; 14.122 + //diff - skip the callee and this etc, they are not explicit params in the parse tree 14.123 + for (int i = 0; i < types.length ; i++) { 14.124 + specializedTypes.put(parameters.get(i), Type.typeFor(types[i])); 14.125 + } 14.126 + } 14.127 + 14.128 + /** 14.129 * Get the identifier for the variable in which the function return value 14.130 * should be stored 14.131 * @return an IdentNode representing the return value 14.132 @@ -1266,7 +1304,7 @@ 14.133 * @param parentBlock a block to remember as parent 14.134 */ 14.135 public void addReferencingParentBlock(final Block parentBlock) { 14.136 - assert parentBlock.getFunction() == function.findParentFunction(); // all parent blocks must be in the same function 14.137 + assert parentBlock.getFunction() == function.findParentFunction() : Debug.id(parentBlock.getFunction()) + "!=" + Debug.id(function.findParentFunction()); // all parent blocks must be in the same function 14.138 if (parentBlock != function.getParent()) { 14.139 if (referencingParentBlocks == null) { 14.140 referencingParentBlocks = new LinkedList<>();
15.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java Tue Mar 12 18:12:42 2013 +0530 15.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java Tue Mar 12 15:30:53 2013 +0100 15.3 @@ -28,7 +28,6 @@ 15.4 import java.util.ArrayList; 15.5 import java.util.Collections; 15.6 import java.util.List; 15.7 -import jdk.nashorn.internal.ir.annotations.Ignore; 15.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 15.9 import jdk.nashorn.internal.runtime.Source; 15.10 15.11 @@ -36,9 +35,6 @@ 15.12 * IR representation of an object literal. 15.13 */ 15.14 public class ObjectNode extends Node { 15.15 - /** Literal context. */ 15.16 - @Ignore 15.17 - private Block context; 15.18 15.19 /** Literal elements. */ 15.20 private final List<Node> elements; 15.21 @@ -49,13 +45,11 @@ 15.22 * @param source the source 15.23 * @param token token 15.24 * @param finish finish 15.25 - * @param context the block for this ObjectNode 15.26 * @param elements the elements used to initialize this ObjectNode 15.27 */ 15.28 - public ObjectNode(final Source source, final long token, final int finish, final Block context, final List<Node> elements) { 15.29 + public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) { 15.30 super(source, token, finish); 15.31 15.32 - this.context = context; 15.33 this.elements = elements; 15.34 } 15.35 15.36 @@ -68,7 +62,6 @@ 15.37 newElements.add(cs.existingOrCopy(element)); 15.38 } 15.39 15.40 - this.context = (Block)cs.existingOrCopy(objectNode.context); 15.41 this.elements = newElements; 15.42 } 15.43 15.44 @@ -80,10 +73,6 @@ 15.45 @Override 15.46 public Node accept(final NodeVisitor visitor) { 15.47 if (visitor.enter(this) != null) { 15.48 - if (context != null) { 15.49 - context = (Block)context.accept(visitor); 15.50 - } 15.51 - 15.52 for (int i = 0, count = elements.size(); i < count; i++) { 15.53 elements.set(i, elements.get(i).accept(visitor)); 15.54 } 15.55 @@ -117,14 +106,6 @@ 15.56 } 15.57 15.58 /** 15.59 - * Get the block that is this ObjectNode's literal context 15.60 - * @return the block 15.61 - */ 15.62 - public Block getContext() { 15.63 - return context; 15.64 - } 15.65 - 15.66 - /** 15.67 * Get the elements of this literal node 15.68 * @return a list of elements 15.69 */
16.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Mar 12 18:12:42 2013 +0530 16.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Mar 12 15:30:53 2013 +0100 16.3 @@ -152,9 +152,9 @@ 16.4 16.5 if (isConvert) { 16.6 convertPos = sb.length(); 16.7 - sb.append("(("); 16.8 + sb.append("("); 16.9 sb.append(getType()); 16.10 - sb.append(")"); 16.11 + sb.append(")("); 16.12 } 16.13 16.14 if (!isPostfix && !isConvert) { 16.15 @@ -191,8 +191,6 @@ 16.16 sb.setCharAt(convertPos, ' '); 16.17 } 16.18 } 16.19 - 16.20 - //TODO - conversions still have too many parenthesis - makes --print-lower-parse hard to read 16.21 } 16.22 16.23 /**
17.1 --- a/src/jdk/nashorn/internal/ir/annotations/ChildNode.java Tue Mar 12 18:12:42 2013 +0530 17.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 17.3 @@ -1,42 +0,0 @@ 17.4 -/* 17.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 17.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.7 - * 17.8 - * This code is free software; you can redistribute it and/or modify it 17.9 - * under the terms of the GNU General Public License version 2 only, as 17.10 - * published by the Free Software Foundation. Oracle designates this 17.11 - * particular file as subject to the "Classpath" exception as provided 17.12 - * by Oracle in the LICENSE file that accompanied this code. 17.13 - * 17.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 17.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17.17 - * version 2 for more details (a copy is included in the LICENSE file that 17.18 - * accompanied this code). 17.19 - * 17.20 - * You should have received a copy of the GNU General Public License version 17.21 - * 2 along with this work; if not, write to the Free Software Foundation, 17.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17.23 - * 17.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 17.25 - * or visit www.oracle.com if you need additional information or have any 17.26 - * questions. 17.27 - */ 17.28 - 17.29 -package jdk.nashorn.internal.ir.annotations; 17.30 - 17.31 -import java.lang.annotation.Retention; 17.32 -import java.lang.annotation.RetentionPolicy; 17.33 - 17.34 -/** 17.35 - * This is a child node, a real node, not a reference, to an IR node that should 17.36 - * be traversed. 17.37 - * <p> 17.38 - * TODO Currently not in use. Would make e.g. accept methods simple and unified 17.39 - * @see jdk.nashorn.internal.ir.Node 17.40 - */ 17.41 -@Retention(value=RetentionPolicy.RUNTIME) 17.42 -public @interface ChildNode { 17.43 - /** order of traversal compared to other children */ 17.44 - public int order() default -1; 17.45 -}
18.1 --- a/src/jdk/nashorn/internal/ir/annotations/ParentNode.java Tue Mar 12 18:12:42 2013 +0530 18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 18.3 @@ -1,44 +0,0 @@ 18.4 -/* 18.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 18.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.7 - * 18.8 - * This code is free software; you can redistribute it and/or modify it 18.9 - * under the terms of the GNU General Public License version 2 only, as 18.10 - * published by the Free Software Foundation. Oracle designates this 18.11 - * particular file as subject to the "Classpath" exception as provided 18.12 - * by Oracle in the LICENSE file that accompanied this code. 18.13 - * 18.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 18.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18.17 - * version 2 for more details (a copy is included in the LICENSE file that 18.18 - * accompanied this code). 18.19 - * 18.20 - * You should have received a copy of the GNU General Public License version 18.21 - * 2 along with this work; if not, write to the Free Software Foundation, 18.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18.23 - * 18.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 18.25 - * or visit www.oracle.com if you need additional information or have any 18.26 - * questions. 18.27 - */ 18.28 - 18.29 -package jdk.nashorn.internal.ir.annotations; 18.30 - 18.31 -import java.lang.annotation.Retention; 18.32 -import java.lang.annotation.RetentionPolicy; 18.33 - 18.34 -/** 18.35 - * Signifies a parent of a node, i.e. node that should not be traversed if we 18.36 - * go down the AST. In automatic parsing this can be handled by @Reference 18.37 - * annotations instead, as all parents are references. 18.38 - * <p> 18.39 - * TODO The use case is automating and creating one implementation of something like 18.40 - * Node.getParent() 18.41 - * 18.42 - * @see jdk.nashorn.internal.ir.Node 18.43 - */ 18.44 -@Retention(value=RetentionPolicy.RUNTIME) 18.45 -public @interface ParentNode { 18.46 - // EMPTY 18.47 -}
19.1 --- a/src/jdk/nashorn/internal/ir/annotations/Reference.java Tue Mar 12 18:12:42 2013 +0530 19.2 +++ b/src/jdk/nashorn/internal/ir/annotations/Reference.java Tue Mar 12 15:30:53 2013 +0100 19.3 @@ -33,7 +33,6 @@ 19.4 * AST traversal and cloning. Cloning currently as a rule uses 19.5 * existingOrSame for references and otherwise existingOrCopy 19.6 * <p> 19.7 - * TODO this could probably be automated using the @Reference annotation. 19.8 */ 19.9 19.10 @Retention(value=RetentionPolicy.RUNTIME)
20.1 --- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Tue Mar 12 18:12:42 2013 +0530 20.2 +++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Tue Mar 12 15:30:53 2013 +0100 20.3 @@ -27,6 +27,7 @@ 20.4 20.5 import java.lang.reflect.Field; 20.6 import java.util.ArrayDeque; 20.7 +import java.util.ArrayList; 20.8 import java.util.Collection; 20.9 import java.util.Deque; 20.10 import java.util.Iterator; 20.11 @@ -36,10 +37,10 @@ 20.12 import jdk.nashorn.internal.ir.Node; 20.13 import jdk.nashorn.internal.ir.TernaryNode; 20.14 import jdk.nashorn.internal.ir.annotations.Ignore; 20.15 -import jdk.nashorn.internal.ir.annotations.ParentNode; 20.16 import jdk.nashorn.internal.ir.annotations.Reference; 20.17 import jdk.nashorn.internal.parser.Token; 20.18 import jdk.nashorn.internal.runtime.Context; 20.19 +import jdk.nashorn.internal.runtime.Debug; 20.20 20.21 /** 20.22 * AST-as-text visualizer. Sometimes you want tree form and not source 20.23 @@ -47,7 +48,6 @@ 20.24 * 20.25 * see the flags --print-ast and --print-ast-lower 20.26 */ 20.27 - 20.28 public final class ASTWriter { 20.29 /** Root node from which to start the traversal */ 20.30 private final Node root; 20.31 @@ -71,12 +71,22 @@ 20.32 @Override 20.33 public String toString() { 20.34 final StringBuilder sb = new StringBuilder(); 20.35 - printAST(sb, null, "root", root, 0); 20.36 + printAST(sb, null, null, "root", root, 0); 20.37 return sb.toString(); 20.38 } 20.39 20.40 + /** 20.41 + * Return the visited nodes in an ordered list 20.42 + * @return the list of nodes in order 20.43 + */ 20.44 + public Node[] toArray() { 20.45 + final List<Node> preorder = new ArrayList<>(); 20.46 + printAST(new StringBuilder(), preorder, null, "root", root, 0); 20.47 + return preorder.toArray(new Node[preorder.size()]); 20.48 + } 20.49 + 20.50 @SuppressWarnings("unchecked") 20.51 - private void printAST(final StringBuilder sb, final Field field, final String name, final Node node, final int indent) { 20.52 + private void printAST(final StringBuilder sb, final List<Node> preorder, final Field field, final String name, final Node node, final int indent) { 20.53 ASTWriter.indent(sb, indent); 20.54 if (node == null) { 20.55 sb.append("[Object "); 20.56 @@ -85,13 +95,23 @@ 20.57 return; 20.58 } 20.59 20.60 + if (preorder != null) { 20.61 + preorder.add(node); 20.62 + } 20.63 + 20.64 final boolean isReference = field != null && field.getAnnotation(Reference.class) != null; 20.65 20.66 Class<?> clazz = node.getClass(); 20.67 String type = clazz.getName(); 20.68 20.69 type = type.substring(type.lastIndexOf('.') + 1, type.length()); 20.70 -// type += "@" + Debug.id(node) + "#" + node.getSymbol(); 20.71 + if (isReference) { 20.72 + type = "ref: " + type; 20.73 + } 20.74 + type += "@" + Debug.id(node); 20.75 + if (node.getSymbol() != null) { 20.76 + type += "#" + node.getSymbol(); 20.77 + } 20.78 20.79 final List<Field> children = new LinkedList<>(); 20.80 20.81 @@ -153,9 +173,7 @@ 20.82 append('\n'); 20.83 20.84 for (final Field child : children) { 20.85 - if (child.getAnnotation(ParentNode.class) != null) { 20.86 - continue; 20.87 - } else if (child.getAnnotation(Ignore.class) != null) { 20.88 + if (child.getAnnotation(Ignore.class) != null) { 20.89 continue; 20.90 } 20.91 20.92 @@ -168,7 +186,7 @@ 20.93 } 20.94 20.95 if (value instanceof Node) { 20.96 - printAST(sb, child, child.getName(), (Node)value, indent + 1); 20.97 + printAST(sb, preorder, child, child.getName(), (Node)value, indent + 1); 20.98 } else if (value instanceof Collection) { 20.99 int pos = 0; 20.100 ASTWriter.indent(sb, indent + 1); 20.101 @@ -180,7 +198,7 @@ 20.102 append('\n'); 20.103 20.104 for (final Node member : (Collection<Node>)value) { 20.105 - printAST(sb, child, child.getName() + "[" + pos++ + "]", member, indent + 2); 20.106 + printAST(sb, preorder, child, child.getName() + "[" + pos++ + "]", member, indent + 2); 20.107 } 20.108 } 20.109 }
21.1 --- a/src/jdk/nashorn/internal/objects/NativeArray.java Tue Mar 12 18:12:42 2013 +0530 21.2 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Tue Mar 12 15:30:53 2013 +0100 21.3 @@ -605,7 +605,7 @@ 21.4 final boolean strict = sobj.isStrictContext(); 21.5 21.6 if (bulkable(sobj)) { 21.7 - return ((NativeArray)sobj).getArray().pop(); 21.8 + return sobj.getArray().pop(); 21.9 } 21.10 21.11 final long len = JSType.toUint32(sobj.getLength()); 21.12 @@ -725,7 +725,7 @@ 21.13 first = sobj.get(0); 21.14 21.15 if (bulkable(sobj)) { 21.16 - ((NativeArray) sobj).getArray().shiftLeft(1); 21.17 + sobj.getArray().shiftLeft(1); 21.18 } else { 21.19 for (long k = 1; k < len; k++) { 21.20 sobj.set(k - 1, sobj.get(k), strict);
22.1 --- a/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Mar 12 18:12:42 2013 +0530 22.2 +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Mar 12 15:30:53 2013 +0100 22.3 @@ -162,21 +162,6 @@ 22.4 } 22.5 22.6 /** 22.7 - * Nashorn extension: get invocation handle from {@link ScriptFunction} 22.8 - * 22.9 - * @param self self reference 22.10 - * @param obj script function 22.11 - * @return the invocation handle for the given ScriptFunction 22.12 - */ 22.13 - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 22.14 - public static Object methodHandle(final Object self, final Object obj) { 22.15 - if (obj instanceof ScriptFunction) { 22.16 - return ((ScriptFunction)obj).getInvokeHandle(); 22.17 - } 22.18 - return UNDEFINED; 22.19 - } 22.20 - 22.21 - /** 22.22 * Check object identity comparison regardless of type 22.23 * 22.24 * @param self self reference
23.1 --- a/src/jdk/nashorn/internal/objects/NativeError.java Tue Mar 12 18:12:42 2013 +0530 23.2 +++ b/src/jdk/nashorn/internal/objects/NativeError.java Tue Mar 12 15:30:53 2013 +0100 23.3 @@ -317,7 +317,7 @@ 23.4 return name; 23.5 } 23.6 // Step 10 : return name + ": " + msg 23.7 - return (String)name + ": " + (String)msg; 23.8 + return name + ": " + msg; 23.9 } 23.10 23.11 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
24.1 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Mar 12 18:12:42 2013 +0530 24.2 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Mar 12 15:30:53 2013 +0100 24.3 @@ -31,6 +31,7 @@ 24.4 import jdk.nashorn.internal.runtime.GlobalFunctions; 24.5 import jdk.nashorn.internal.runtime.Property; 24.6 import jdk.nashorn.internal.runtime.PropertyMap; 24.7 +import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 24.8 import jdk.nashorn.internal.runtime.ScriptFunction; 24.9 import jdk.nashorn.internal.runtime.ScriptFunctionData; 24.10 import jdk.nashorn.internal.runtime.ScriptObject; 24.11 @@ -86,8 +87,8 @@ 24.12 * @param builtin is this a built-in function 24.13 * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted). 24.14 */ 24.15 - ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { 24.16 - super(name, methodHandle, getMap(strict), scope, specs, strict, builtin, isConstructor); 24.17 + ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 24.18 + super(name, methodHandle, getMap(isStrict), scope, specs, isStrict, isBuiltin, isConstructor); 24.19 init(); 24.20 } 24.21 24.22 @@ -95,14 +96,10 @@ 24.23 * Constructor called by (compiler) generated code for {@link ScriptObject}s. 24.24 * 24.25 * @param data static function data 24.26 - * @param methodHandle handle for invocation 24.27 * @param scope scope object 24.28 - * @param allocator instance constructor for function 24.29 */ 24.30 - public ScriptFunctionImpl(final MethodHandle methodHandle, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) { 24.31 + public ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope) { 24.32 super(data, getMap(data.isStrict()), scope); 24.33 - // Set method handles in script data 24.34 - data.setMethodHandles(methodHandle, allocator); 24.35 init(); 24.36 } 24.37
25.1 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java Tue Mar 12 18:12:42 2013 +0530 25.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 25.3 @@ -1,122 +0,0 @@ 25.4 -package jdk.nashorn.internal.objects; 25.5 - 25.6 -import static jdk.nashorn.internal.lookup.Lookup.MH; 25.7 - 25.8 -import java.lang.invoke.MethodHandle; 25.9 -import java.lang.invoke.MethodHandles; 25.10 -import java.lang.invoke.MethodType; 25.11 -import jdk.nashorn.internal.codegen.CompilationException; 25.12 -import jdk.nashorn.internal.codegen.Compiler; 25.13 -import jdk.nashorn.internal.codegen.FunctionSignature; 25.14 -import jdk.nashorn.internal.codegen.types.Type; 25.15 -import jdk.nashorn.internal.ir.FunctionNode; 25.16 -import jdk.nashorn.internal.runtime.CodeInstaller; 25.17 -import jdk.nashorn.internal.runtime.Context; 25.18 -import jdk.nashorn.internal.runtime.ScriptEnvironment; 25.19 -import jdk.nashorn.internal.runtime.ScriptFunction; 25.20 -import jdk.nashorn.internal.runtime.ScriptFunctionData; 25.21 -import jdk.nashorn.internal.runtime.ScriptObject; 25.22 - 25.23 -/** 25.24 - * A trampoline is a promise to compile a {@link ScriptFunction} later. It just looks like 25.25 - * the call to the script function, but when invoked it will compile the script function 25.26 - * (in a new compile unit) and invoke it 25.27 - */ 25.28 -public final class ScriptFunctionTrampolineImpl extends ScriptFunctionImpl { 25.29 - 25.30 - private CodeInstaller<ScriptEnvironment> installer; 25.31 - 25.32 - /** Function node to lazily recompile when trampoline is hit */ 25.33 - private FunctionNode functionNode; 25.34 - 25.35 - /** 25.36 - * Constructor 25.37 - * 25.38 - * @param installer opaque code installer from context 25.39 - * @param functionNode function node to lazily compile when trampoline is hit 25.40 - * @param data {@link ScriptFunctionData} for function 25.41 - * @param scope scope 25.42 - * @param allocator allocator 25.43 - */ 25.44 - public ScriptFunctionTrampolineImpl(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) { 25.45 - super(null, data, scope, allocator); 25.46 - 25.47 - this.installer = installer; 25.48 - this.functionNode = functionNode; 25.49 - 25.50 - data.setMethodHandles(makeTrampoline(), allocator); 25.51 - } 25.52 - 25.53 - private final MethodHandle makeTrampoline() { 25.54 - final MethodType mt = 25.55 - new FunctionSignature( 25.56 - true, 25.57 - functionNode.needsCallee(), 25.58 - Type.OBJECT, 25.59 - functionNode.getParameters().size()). 25.60 - getMethodType(); 25.61 - 25.62 - return 25.63 - MH.bindTo( 25.64 - MH.asCollector( 25.65 - findOwnMH( 25.66 - "trampoline", 25.67 - Object.class, 25.68 - Object[].class), 25.69 - Object[].class, 25.70 - mt.parameterCount()), 25.71 - this); 25.72 - } 25.73 - 25.74 - private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 25.75 - return MH.findVirtual(MethodHandles.lookup(), ScriptFunctionTrampolineImpl.class, name, MH.type(rtype, types)); 25.76 - } 25.77 - 25.78 - @Override 25.79 - protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) { 25.80 - //prevent trampoline recompilation cycle if a function is bound before use 25.81 - compile(); 25.82 - return super.makeBoundFunction(data); 25.83 - } 25.84 - 25.85 - private MethodHandle compile() throws CompilationException { 25.86 - final Compiler compiler = new Compiler(installer, functionNode); 25.87 - 25.88 - compiler.compile(); 25.89 - 25.90 - final Class<?> clazz = compiler.install(); 25.91 - /* compute function signature for lazy method. this can be done first after compilation, as only then do we know 25.92 - * the final state about callees, scopes and specialized parameter types */ 25.93 - final FunctionSignature signature = new FunctionSignature(true, functionNode.needsCallee(), Type.OBJECT, functionNode.getParameters().size()); 25.94 - final MethodType mt = signature.getMethodType(); 25.95 - 25.96 - MethodHandle mh = MH.findStatic(MethodHandles.publicLookup(), clazz, functionNode.getName(), mt); 25.97 - if (functionNode.needsCallee()) { 25.98 - mh = MH.bindTo(mh, this); 25.99 - } 25.100 - 25.101 - // now the invoker method looks like the one our superclass is expecting 25.102 - resetInvoker(mh); 25.103 - 25.104 - return mh; 25.105 - } 25.106 - 25.107 - @SuppressWarnings("unused") 25.108 - private Object trampoline(final Object... args) throws CompilationException { 25.109 - Compiler.LOG.info(">>> TRAMPOLINE: Hitting trampoline for '" + functionNode.getName() + "'"); 25.110 - MethodHandle mh = compile(); 25.111 - 25.112 - Compiler.LOG.info("<<< COMPILED TO: " + mh); 25.113 - // spread the array to invididual args of the correct type 25.114 - mh = MH.asSpreader(mh, Object[].class, mh.type().parameterCount()); 25.115 - 25.116 - try { 25.117 - //invoke the real method the trampoline points to. this only happens once 25.118 - return mh.invoke(args); 25.119 - } catch (final RuntimeException | Error e) { 25.120 - throw e; 25.121 - } catch (final Throwable t) { 25.122 - throw new RuntimeException(t); 25.123 - } 25.124 - } 25.125 -}
26.1 --- a/src/jdk/nashorn/internal/parser/JSONParser.java Tue Mar 12 18:12:42 2013 +0530 26.2 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java Tue Mar 12 15:30:53 2013 +0100 26.3 @@ -313,7 +313,7 @@ 26.4 } 26.5 26.6 // Construct new object literal. 26.7 - return new ObjectNode(source, objectToken, finish, null, elements); 26.8 + return new ObjectNode(source, objectToken, finish, elements); 26.9 } 26.10 26.11 /**
27.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Tue Mar 12 18:12:42 2013 +0530 27.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Tue Mar 12 15:30:53 2013 +0100 27.3 @@ -59,6 +59,7 @@ 27.4 import java.util.List; 27.5 import java.util.Map; 27.6 import java.util.Stack; 27.7 + 27.8 import jdk.nashorn.internal.codegen.CompilerConstants; 27.9 import jdk.nashorn.internal.codegen.Namespace; 27.10 import jdk.nashorn.internal.ir.AccessNode; 27.11 @@ -96,7 +97,7 @@ 27.12 import jdk.nashorn.internal.ir.VarNode; 27.13 import jdk.nashorn.internal.ir.WhileNode; 27.14 import jdk.nashorn.internal.ir.WithNode; 27.15 -import jdk.nashorn.internal.runtime.Context; 27.16 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 27.17 import jdk.nashorn.internal.runtime.DebugLogger; 27.18 import jdk.nashorn.internal.runtime.ErrorManager; 27.19 import jdk.nashorn.internal.runtime.JSErrorType; 27.20 @@ -116,9 +117,6 @@ 27.21 /** Is scripting mode. */ 27.22 private final boolean scripting; 27.23 27.24 - /** Top level script being parsed. */ 27.25 - private FunctionNode script; 27.26 - 27.27 /** Current function being parsed. */ 27.28 private FunctionNode function; 27.29 27.30 @@ -304,6 +302,7 @@ 27.31 final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name); 27.32 block = function = functionBlock; 27.33 function.setStrictMode(isStrictMode); 27.34 + function.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 27.35 27.36 return functionBlock; 27.37 } 27.38 @@ -312,7 +311,7 @@ 27.39 * Restore the current block. 27.40 */ 27.41 private void restoreBlock() { 27.42 - block = block.getParent(); 27.43 + block = block.getParent(); 27.44 function = block.getFunction(); 27.45 } 27.46 27.47 @@ -338,7 +337,7 @@ 27.48 popControlNode(); 27.49 } 27.50 27.51 - final int possibleEnd = Token.descPosition(token) + Token.descLength(token); 27.52 + final int possibleEnd = Token.descPosition(token) + Token.descLength(token); 27.53 27.54 // Block closing brace. 27.55 if (needsBraces) { 27.56 @@ -438,7 +437,7 @@ 27.57 } 27.58 27.59 if (lhs instanceof IdentNode) { 27.60 - if (! checkIdentLValue((IdentNode)lhs)) { 27.61 + if (!checkIdentLValue((IdentNode)lhs)) { 27.62 return referenceError(lhs, rhs); 27.63 } 27.64 verifyStrictIdent((IdentNode)lhs, "assignment"); 27.65 @@ -621,15 +620,13 @@ 27.66 // Make a fake token for the script. 27.67 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 27.68 // Set up the script to append elements. 27.69 - script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName)); 27.70 - // set kind to be SCRIPT 27.71 + 27.72 + final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName)); 27.73 + 27.74 script.setKind(FunctionNode.Kind.SCRIPT); 27.75 - // Set the first token of the script. 27.76 script.setFirstToken(functionToken); 27.77 - // Gather source elements. 27.78 sourceElements(); 27.79 expect(EOF); 27.80 - // Set the last token of the script. 27.81 script.setLastToken(token); 27.82 script.setFinish(source.getLength() - 1); 27.83 27.84 @@ -1231,7 +1228,7 @@ 27.85 } 27.86 27.87 if (init instanceof IdentNode) { 27.88 - if (! checkIdentLValue((IdentNode)init)) { 27.89 + if (!checkIdentLValue((IdentNode)init)) { 27.90 error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 27.91 } 27.92 verifyStrictIdent((IdentNode)init, "for-in iterator"); 27.93 @@ -2026,7 +2023,7 @@ 27.94 break; 27.95 27.96 default: 27.97 - if (! elision) { 27.98 + if (!elision) { 27.99 error(AbstractParser.message("expected.comma", type.getNameOrType())); 27.100 } 27.101 // Add expression element. 27.102 @@ -2067,15 +2064,11 @@ 27.103 next(); 27.104 27.105 // Object context. 27.106 - Block objectContext = null; 27.107 // Prepare to accumulate elements. 27.108 final List<Node> elements = new ArrayList<>(); 27.109 final Map<Object, PropertyNode> map = new HashMap<>(); 27.110 27.111 - try { 27.112 - // Create a block for the object literal. 27.113 - objectContext = newBlock(); 27.114 - 27.115 + // Create a block for the object literal. 27.116 boolean commaSeen = true; 27.117 loop: 27.118 while (true) { 27.119 @@ -2090,97 +2083,90 @@ 27.120 break; 27.121 27.122 default: 27.123 - if (! commaSeen) { 27.124 + if (!commaSeen) { 27.125 error(AbstractParser.message("expected.comma", type.getNameOrType())); 27.126 - } 27.127 - 27.128 - commaSeen = false; 27.129 - // Get and add the next property. 27.130 - final PropertyNode property = propertyAssignment(); 27.131 - final Object key = property.getKeyName(); 27.132 - final PropertyNode existingProperty = map.get(key); 27.133 - 27.134 - if (existingProperty != null) { 27.135 - // ECMA section 11.1.5 Object Initialiser 27.136 - // point # 4 on property assignment production 27.137 - final Node value = property.getValue(); 27.138 - final Node getter = property.getGetter(); 27.139 - final Node setter = property.getSetter(); 27.140 - 27.141 - final Node prevValue = existingProperty.getValue(); 27.142 - final Node prevGetter = existingProperty.getGetter(); 27.143 - final Node prevSetter = existingProperty.getSetter(); 27.144 - 27.145 - boolean redefinitionOk = true; 27.146 - // ECMA 11.1.5 strict mode restrictions 27.147 - if (isStrictMode) { 27.148 - if (value != null && prevValue != null) { 27.149 - redefinitionOk = false; 27.150 - } 27.151 - } 27.152 - 27.153 - final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 27.154 - final boolean isAccessor = getter != null || setter != null; 27.155 - 27.156 - // data property redefined as accessor property 27.157 - if (prevValue != null && isAccessor) { 27.158 + } 27.159 + 27.160 + commaSeen = false; 27.161 + // Get and add the next property. 27.162 + final PropertyNode property = propertyAssignment(); 27.163 + final Object key = property.getKeyName(); 27.164 + final PropertyNode existingProperty = map.get(key); 27.165 + 27.166 + if (existingProperty != null) { 27.167 + // ECMA section 11.1.5 Object Initialiser 27.168 + // point # 4 on property assignment production 27.169 + final Node value = property.getValue(); 27.170 + final Node getter = property.getGetter(); 27.171 + final Node setter = property.getSetter(); 27.172 + 27.173 + final Node prevValue = existingProperty.getValue(); 27.174 + final Node prevGetter = existingProperty.getGetter(); 27.175 + final Node prevSetter = existingProperty.getSetter(); 27.176 + 27.177 + boolean redefinitionOk = true; 27.178 + // ECMA 11.1.5 strict mode restrictions 27.179 + if (isStrictMode) { 27.180 + if (value != null && prevValue != null) { 27.181 redefinitionOk = false; 27.182 } 27.183 - 27.184 - // accessor property redefined as data 27.185 - if (isPrevAccessor && value != null) { 27.186 + } 27.187 + 27.188 + final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 27.189 + final boolean isAccessor = getter != null || setter != null; 27.190 + 27.191 + // data property redefined as accessor property 27.192 + if (prevValue != null && isAccessor) { 27.193 + redefinitionOk = false; 27.194 + } 27.195 + 27.196 + // accessor property redefined as data 27.197 + if (isPrevAccessor && value != null) { 27.198 + redefinitionOk = false; 27.199 + } 27.200 + 27.201 + if (isAccessor && isPrevAccessor) { 27.202 + if (getter != null && prevGetter != null || 27.203 + setter != null && prevSetter != null) { 27.204 redefinitionOk = false; 27.205 } 27.206 - 27.207 - if (isAccessor && isPrevAccessor) { 27.208 - if (getter != null && prevGetter != null || 27.209 - setter != null && prevSetter != null) { 27.210 - redefinitionOk = false; 27.211 - } 27.212 + } 27.213 + 27.214 + if (!redefinitionOk) { 27.215 + error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); 27.216 + } 27.217 + 27.218 + if (value != null) { 27.219 + final Node existingValue = existingProperty.getValue(); 27.220 + 27.221 + if (existingValue == null) { 27.222 + existingProperty.setValue(value); 27.223 + } else { 27.224 + final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT); 27.225 + existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value)); 27.226 } 27.227 27.228 - if (! redefinitionOk) { 27.229 - error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); 27.230 - } 27.231 - 27.232 - if (value != null) { 27.233 - final Node existingValue = existingProperty.getValue(); 27.234 - 27.235 - if (existingValue == null) { 27.236 - existingProperty.setValue(value); 27.237 - } else { 27.238 - final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT); 27.239 - existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value)); 27.240 - } 27.241 - 27.242 - existingProperty.setGetter(null); 27.243 - existingProperty.setSetter(null); 27.244 - } 27.245 - 27.246 - if (getter != null) { 27.247 - existingProperty.setGetter(getter); 27.248 - } 27.249 - 27.250 - if (setter != null) { 27.251 - existingProperty.setSetter(setter); 27.252 - } 27.253 - } else { 27.254 - map.put(key, property); 27.255 - elements.add(property); 27.256 + existingProperty.setGetter(null); 27.257 + existingProperty.setSetter(null); 27.258 } 27.259 27.260 - break; 27.261 + if (getter != null) { 27.262 + existingProperty.setGetter(getter); 27.263 + } 27.264 + 27.265 + if (setter != null) { 27.266 + existingProperty.setSetter(setter); 27.267 + } 27.268 + } else { 27.269 + map.put(key, property); 27.270 + elements.add(property); 27.271 } 27.272 + 27.273 + break; 27.274 } 27.275 - } finally { 27.276 - restoreBlock(); 27.277 } 27.278 27.279 - // Construct new object literal. 27.280 - objectContext.setFinish(finish); 27.281 - objectContext.setStart(Token.descPosition(objectToken)); 27.282 - 27.283 - return new ObjectNode(source, objectToken, finish, objectContext, elements); 27.284 + return new ObjectNode(source, objectToken, finish, elements); 27.285 } 27.286 27.287 /** 27.288 @@ -2845,7 +2831,7 @@ 27.289 } 27.290 27.291 if (lhs instanceof IdentNode) { 27.292 - if (! checkIdentLValue((IdentNode)lhs)) { 27.293 + if (!checkIdentLValue((IdentNode)lhs)) { 27.294 return referenceError(lhs, null); 27.295 } 27.296 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 27.297 @@ -2872,7 +2858,7 @@ 27.298 return referenceError(lhs, null); 27.299 } 27.300 if (lhs instanceof IdentNode) { 27.301 - if (! checkIdentLValue((IdentNode)lhs)) { 27.302 + if (!checkIdentLValue((IdentNode)lhs)) { 27.303 next(); 27.304 return referenceError(lhs, null); 27.305 }
28.1 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java Tue Mar 12 18:12:42 2013 +0530 28.2 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java Tue Mar 12 15:30:53 2013 +0100 28.3 @@ -164,7 +164,6 @@ 28.4 super(key, flags, slot); 28.5 28.6 /* 28.7 - * 28.8 * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also 28.9 * works in dual field mode, it only means that the property never has a primitive 28.10 * representation. 28.11 @@ -348,11 +347,10 @@ 28.12 28.13 private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) { 28.14 if (DEBUG_FIELDS) { 28.15 - final MethodHandle mhd = MethodHandleFactory.addDebugPrintout( 28.16 + return MethodHandleFactory.addDebugPrintout( 28.17 LOG, 28.18 mh, 28.19 tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", forType=" + stripName(forType) + ", type=" + stripName(type) + ')'); 28.20 - return mhd; 28.21 } 28.22 return mh; 28.23 }
29.1 --- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java Tue Mar 12 18:12:42 2013 +0530 29.2 +++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java Tue Mar 12 15:30:53 2013 +0100 29.3 @@ -25,6 +25,8 @@ 29.4 29.5 package jdk.nashorn.internal.runtime; 29.6 29.7 +import jdk.nashorn.internal.codegen.ClassEmitter; 29.8 + 29.9 /** 29.10 * Interface for installing classes passed to the compiler. 29.11 * As only the code generating package (i.e. Context) knows about 29.12 @@ -52,12 +54,12 @@ 29.13 */ 29.14 public Class<?> install(final String className, final byte[] bytecode); 29.15 29.16 - /* 29.17 + /** 29.18 * Verify generated bytecode before emission. This is called back from the 29.19 * {@link ClassEmitter} or the {@link Compiler}. If the "--verify-code" parameter 29.20 * hasn't been given, this is a nop 29.21 * 29.22 - * @param bytecode bytecode to verify 29.23 + * @param code bytecode to verify 29.24 */ 29.25 public void verify(final byte[] code); 29.26 }
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Mar 12 15:30:53 2013 +0100 30.3 @@ -0,0 +1,162 @@ 30.4 +/* 30.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 30.7 + * 30.8 + * This code is free software; you can redistribute it and/or modify it 30.9 + * under the terms of the GNU General Public License version 2 only, as 30.10 + * published by the Free Software Foundation. Oracle designates this 30.11 + * particular file as subject to the "Classpath" exception as provided 30.12 + * by Oracle in the LICENSE file that accompanied this code. 30.13 + * 30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 30.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30.17 + * version 2 for more details (a copy is included in the LICENSE file that 30.18 + * accompanied this code). 30.19 + * 30.20 + * You should have received a copy of the GNU General Public License version 30.21 + * 2 along with this work; if not, write to the Free Software Foundation, 30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 30.23 + * 30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 30.25 + * or visit www.oracle.com if you need additional information or have any 30.26 + * questions. 30.27 + */ 30.28 +package jdk.nashorn.internal.runtime; 30.29 + 30.30 +import java.lang.invoke.MethodHandle; 30.31 +import java.lang.invoke.MethodType; 30.32 + 30.33 +import jdk.nashorn.internal.codegen.types.Type; 30.34 + 30.35 +/** 30.36 + * An version of a JavaScript function, native or JavaScript. 30.37 + * Supports lazily generating a constructor version of the invocation. 30.38 + */ 30.39 +final class CompiledFunction implements Comparable<CompiledFunction> { 30.40 + 30.41 + private final MethodHandle invoker; 30.42 + private MethodHandle constructor; 30.43 + 30.44 + CompiledFunction(final MethodHandle invoker) { 30.45 + this(invoker, null); 30.46 + } 30.47 + 30.48 + CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) { 30.49 + this.invoker = invoker; 30.50 + this.constructor = constructor; //isConstructor 30.51 + } 30.52 + 30.53 + @Override 30.54 + public String toString() { 30.55 + return "<invoker=" + invoker + " ctor=" + constructor + ">"; 30.56 + } 30.57 + 30.58 + MethodHandle getInvoker() { 30.59 + return invoker; 30.60 + } 30.61 + 30.62 + MethodHandle getConstructor() { 30.63 + return constructor; 30.64 + } 30.65 + 30.66 + void setConstructor(final MethodHandle constructor) { 30.67 + this.constructor = constructor; 30.68 + } 30.69 + 30.70 + boolean hasConstructor() { 30.71 + return constructor != null; 30.72 + } 30.73 + 30.74 + MethodType type() { 30.75 + return invoker.type(); 30.76 + } 30.77 + 30.78 + @Override 30.79 + public int compareTo(final CompiledFunction o) { 30.80 + return weight() - o.weight(); 30.81 + } 30.82 + 30.83 + private int weight() { 30.84 + return weight(type()); 30.85 + } 30.86 + 30.87 + private static int weight(final MethodType type) { 30.88 + if (isVarArgsType(type)) { 30.89 + return Integer.MAX_VALUE; //if there is a varargs it should be the heavist and last fallback 30.90 + } 30.91 + 30.92 + int weight = Type.typeFor(type.returnType()).getWeight(); 30.93 + for (final Class<?> paramType : type.parameterArray()) { 30.94 + final int pweight = Type.typeFor(paramType).getWeight(); 30.95 + weight += pweight; 30.96 + } 30.97 + return weight; 30.98 + } 30.99 + 30.100 + private static boolean isVarArgsType(final MethodType type) { 30.101 + assert type.parameterCount() >= 1 : type; 30.102 + return type.parameterType(type.parameterCount() - 1) == Object[].class; 30.103 + } 30.104 + 30.105 + boolean moreGenericThan(final CompiledFunction o) { 30.106 + return weight() > o.weight(); 30.107 + } 30.108 + 30.109 + boolean moreGenericThan(final MethodType type) { 30.110 + return weight() > weight(type); 30.111 + } 30.112 + 30.113 + /** 30.114 + * Check whether a given method descriptor is compatible with this invocation. 30.115 + * It is compatible if the types are narrower than the invocation type so that 30.116 + * a semantically equivalent linkage can be performed. 30.117 + * 30.118 + * @param typesc 30.119 + * @return 30.120 + */ 30.121 + boolean typeCompatible(final MethodType type) { 30.122 + final Class<?>[] wantedParams = type.parameterArray(); 30.123 + final Class<?>[] existingParams = type().parameterArray(); 30.124 + 30.125 + //if we are not examining a varargs type, the number of parameters must be the same 30.126 + if (wantedParams.length != existingParams.length && !isVarArgsType(type)) { 30.127 + return false; 30.128 + } 30.129 + 30.130 + //we only go as far as the shortest array. the only chance to make this work if 30.131 + //parameters lengths do not match is if our type ends with a varargs argument. 30.132 + //then every trailing parameter in the given callsite can be folded into it, making 30.133 + //us compatible (albeit slower than a direct specialization) 30.134 + final int lastParamIndex = Math.min(wantedParams.length, existingParams.length); 30.135 + for (int i = 0; i < lastParamIndex; i++) { 30.136 + final Type w = Type.typeFor(wantedParams[i]); 30.137 + final Type e = Type.typeFor(existingParams[i]); 30.138 + 30.139 + //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution 30.140 + //we also currently don't support boolean as a javascript function callsite type. 30.141 + //it will always box. 30.142 + if (w.isBoolean()) { 30.143 + return false; 30.144 + } 30.145 + 30.146 + //This callsite type has a vararg here. it will swallow all remaining args. 30.147 + //for consistency, check that it's the last argument 30.148 + if (e.isArray()) { 30.149 + return true; 30.150 + } 30.151 + 30.152 + //Our arguments must be at least as wide as the wanted one, if not wider 30.153 + if (Type.widest(w, e) != e) { 30.154 + //e.g. this invocation takes double and callsite says "object". reject. won't fit 30.155 + //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine 30.156 + return false; 30.157 + } 30.158 + } 30.159 + 30.160 + return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic. 30.161 + } 30.162 + 30.163 + 30.164 + 30.165 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Tue Mar 12 15:30:53 2013 +0100 31.3 @@ -0,0 +1,73 @@ 31.4 +/* 31.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 31.7 + * 31.8 + * This code is free software; you can redistribute it and/or modify it 31.9 + * under the terms of the GNU General Public License version 2 only, as 31.10 + * published by the Free Software Foundation. Oracle designates this 31.11 + * particular file as subject to the "Classpath" exception as provided 31.12 + * by Oracle in the LICENSE file that accompanied this code. 31.13 + * 31.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 31.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 31.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31.17 + * version 2 for more details (a copy is included in the LICENSE file that 31.18 + * accompanied this code). 31.19 + * 31.20 + * You should have received a copy of the GNU General Public License version 31.21 + * 2 along with this work; if not, write to the Free Software Foundation, 31.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 31.23 + * 31.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 31.25 + * or visit www.oracle.com if you need additional information or have any 31.26 + * questions. 31.27 + */ 31.28 +package jdk.nashorn.internal.runtime; 31.29 + 31.30 +import java.lang.invoke.MethodType; 31.31 +import java.util.Iterator; 31.32 +import java.util.TreeSet; 31.33 + 31.34 +/** 31.35 + * This is a list of code versions of a function. 31.36 + * The list is sorted in ascending order of generic descriptors 31.37 + */ 31.38 +@SuppressWarnings("serial") 31.39 +final class CompiledFunctions extends TreeSet<CompiledFunction> { 31.40 + 31.41 + CompiledFunction best(final MethodType type) { 31.42 + final Iterator<CompiledFunction> iter = iterator(); 31.43 + while (iter.hasNext()) { 31.44 + final CompiledFunction next = iter.next(); 31.45 + if (next.typeCompatible(type)) { 31.46 + return next; 31.47 + } 31.48 + } 31.49 + return mostGeneric(); 31.50 + } 31.51 + 31.52 + boolean needsCallee() { 31.53 + for (final CompiledFunction inv : this) { 31.54 + assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); 31.55 + } 31.56 + return ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); 31.57 + } 31.58 + 31.59 + CompiledFunction mostGeneric() { 31.60 + return last(); 31.61 + } 31.62 + 31.63 + /** 31.64 + * Is the given type even more specific than this entire list? That means 31.65 + * we have an opportunity for more specific versions of the method 31.66 + * through lazy code generation 31.67 + * 31.68 + * @param type type to check against 31.69 + * @return true if the given type is more specific than all invocations available 31.70 + */ 31.71 + boolean isLessSpecificThan(final MethodType type) { 31.72 + return best(type).moreGenericThan(type); 31.73 + } 31.74 + 31.75 + 31.76 +}
32.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Tue Mar 12 18:12:42 2013 +0530 32.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Tue Mar 12 15:30:53 2013 +0100 32.3 @@ -80,7 +80,7 @@ 32.4 32.5 /** 32.6 * Return the context for this installer 32.7 - * @return context 32.8 + * @return ScriptEnvironment 32.9 */ 32.10 @Override 32.11 public ScriptEnvironment getOwner() {
33.1 --- a/src/jdk/nashorn/internal/runtime/ECMAException.java Tue Mar 12 18:12:42 2013 +0530 33.2 +++ b/src/jdk/nashorn/internal/runtime/ECMAException.java Tue Mar 12 15:30:53 2013 +0100 33.3 @@ -237,7 +237,7 @@ 33.4 return (String)name; 33.5 } 33.6 33.7 - return (String)name + ": " + (String)msg; 33.8 + return name + ": " + msg; 33.9 } 33.10 33.11 private static Throwable asThrowable(final Object obj) {
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Tue Mar 12 15:30:53 2013 +0100 34.3 @@ -0,0 +1,100 @@ 34.4 +/* 34.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 34.7 + * 34.8 + * This code is free software; you can redistribute it and/or modify it 34.9 + * under the terms of the GNU General Public License version 2 only, as 34.10 + * published by the Free Software Foundation. Oracle designates this 34.11 + * particular file as subject to the "Classpath" exception as provided 34.12 + * by Oracle in the LICENSE file that accompanied this code. 34.13 + * 34.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 34.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 34.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 34.17 + * version 2 for more details (a copy is included in the LICENSE file that 34.18 + * accompanied this code). 34.19 + * 34.20 + * You should have received a copy of the GNU General Public License version 34.21 + * 2 along with this work; if not, write to the Free Software Foundation, 34.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 34.23 + * 34.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 34.25 + * or visit www.oracle.com if you need additional information or have any 34.26 + * questions. 34.27 + */ 34.28 + 34.29 +package jdk.nashorn.internal.runtime; 34.30 + 34.31 +import static jdk.nashorn.internal.lookup.Lookup.MH; 34.32 + 34.33 +import java.lang.invoke.MethodHandle; 34.34 + 34.35 +/** 34.36 + * This is a subclass that represents a script function that may not be regenerated. 34.37 + * This is used for example for bound functions and builtins. 34.38 + */ 34.39 +public final class FinalScriptFunctionData extends ScriptFunctionData { 34.40 + 34.41 + /** 34.42 + * Constructor - used for bind 34.43 + * 34.44 + * @param name name 34.45 + * @param arity arity 34.46 + * @param list precompiled code 34.47 + * @param isStrict strict 34.48 + * @param isBuiltin builtin 34.49 + * @param isConstructor constructor 34.50 + */ 34.51 + FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 34.52 + super(name, arity, isStrict, isBuiltin, isConstructor); 34.53 + code.addAll(functions); 34.54 + } 34.55 + 34.56 + /** 34.57 + * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the 34.58 + * method (typically a native method) and possibly specializations. 34.59 + * 34.60 + * @param name name 34.61 + * @param mh method handle for generic version of method 34.62 + * @param specs specializations 34.63 + * @param isStrict strict 34.64 + * @param isBuiltin builtin 34.65 + * @param isConstructor constructor 34.66 + */ 34.67 + FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 34.68 + super(name, arity(mh), isStrict, isBuiltin, isConstructor); 34.69 + 34.70 + addInvoker(mh); 34.71 + if (specs != null) { 34.72 + for (final MethodHandle spec : specs) { 34.73 + addInvoker(spec); 34.74 + } 34.75 + } 34.76 + } 34.77 + 34.78 + private void addInvoker(final MethodHandle mh) { 34.79 + boolean needsCallee = needsCallee(mh); 34.80 + if (isConstructor(mh)) { 34.81 + //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor 34.82 + //is too conservative a check. However, isConstructor(mh) always implies isConstructor param 34.83 + assert isConstructor(); 34.84 + code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor 34.85 + } else { 34.86 + code.add(new CompiledFunction(mh)); 34.87 + } 34.88 + } 34.89 + 34.90 + private static int arity(final MethodHandle mh) { 34.91 + if (isVarArg(mh)) { 34.92 + return -1; 34.93 + } 34.94 + 34.95 + //drop self, callee and boolean constructor flag to get real arity 34.96 + return mh.type().parameterCount() - 1 - (needsCallee(mh) ? 1 : 0) - (isConstructor(mh) ? 1 : 0); 34.97 + } 34.98 + 34.99 + private static boolean isConstructor(final MethodHandle mh) { 34.100 + return mh.type().parameterCount() >= 1 && mh.type().parameterType(0) == boolean.class; 34.101 + } 34.102 + 34.103 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Mar 12 15:30:53 2013 +0100 35.3 @@ -0,0 +1,185 @@ 35.4 +/* 35.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 35.7 + * 35.8 + * This code is free software; you can redistribute it and/or modify it 35.9 + * under the terms of the GNU General Public License version 2 only, as 35.10 + * published by the Free Software Foundation. Oracle designates this 35.11 + * particular file as subject to the "Classpath" exception as provided 35.12 + * by Oracle in the LICENSE file that accompanied this code. 35.13 + * 35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 35.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 35.17 + * version 2 for more details (a copy is included in the LICENSE file that 35.18 + * accompanied this code). 35.19 + * 35.20 + * You should have received a copy of the GNU General Public License version 35.21 + * 2 along with this work; if not, write to the Free Software Foundation, 35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 35.23 + * 35.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 35.25 + * or visit www.oracle.com if you need additional information or have any 35.26 + * questions. 35.27 + */ 35.28 + 35.29 +package jdk.nashorn.internal.runtime; 35.30 + 35.31 +import java.lang.invoke.MethodHandle; 35.32 +import java.lang.invoke.MethodHandles; 35.33 +import java.lang.invoke.MethodType; 35.34 + 35.35 +import jdk.nashorn.internal.codegen.Compiler; 35.36 +import jdk.nashorn.internal.codegen.CompilerConstants; 35.37 +import jdk.nashorn.internal.codegen.FunctionSignature; 35.38 +import jdk.nashorn.internal.ir.FunctionNode; 35.39 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 35.40 +import jdk.nashorn.internal.parser.Token; 35.41 +import jdk.nashorn.internal.parser.TokenType; 35.42 + 35.43 +import static jdk.nashorn.internal.lookup.Lookup.MH; 35.44 + 35.45 +/** 35.46 + * This is a subclass that represents a script function that may be regenerated, 35.47 + * for example with specialization based on call site types, or lazily generated. 35.48 + * The common denominator is that it can get new invokers during its lifespan, 35.49 + * unlike {@link FinalScriptFunctionData} 35.50 + */ 35.51 +public final class RecompilableScriptFunctionData extends ScriptFunctionData { 35.52 + 35.53 + private final FunctionNode functionNode; 35.54 + private final PropertyMap allocatorMap; 35.55 + private final CodeInstaller<ScriptEnvironment> installer; 35.56 + private final String allocatorClassName; 35.57 + 35.58 + /** lazily generated allocator */ 35.59 + private MethodHandle allocator; 35.60 + 35.61 + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 35.62 + 35.63 + /** 35.64 + * Constructor - public as scripts use it 35.65 + * 35.66 + * @param functionNode functionNode that represents this function code 35.67 + * @param installer installer for code regeneration versions of this function 35.68 + * @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor 35.69 + * @param allocatorMap allocator map to seed instances with, when constructing 35.70 + */ 35.71 + public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller<ScriptEnvironment> installer, final String allocatorClassName, final PropertyMap allocatorMap) { 35.72 + super(functionNode.isAnonymous() ? 35.73 + "" : 35.74 + functionNode.getIdent().getName(), 35.75 + functionNode.getParameters().size(), 35.76 + functionNode.isStrictMode(), 35.77 + false, 35.78 + true); 35.79 + 35.80 + this.functionNode = functionNode; 35.81 + this.installer = installer; 35.82 + this.allocatorClassName = allocatorClassName; 35.83 + this.allocatorMap = allocatorMap; 35.84 + } 35.85 + 35.86 + @Override 35.87 + String toSource() { 35.88 + final Source source = functionNode.getSource(); 35.89 + final long token = tokenFor(functionNode); 35.90 + 35.91 + if (source != null && token != 0) { 35.92 + return source.getString(Token.descPosition(token), Token.descLength(token)); 35.93 + } 35.94 + 35.95 + return "function " + (name == null ? "" : name) + "() { [native code] }"; 35.96 + } 35.97 + 35.98 + @Override 35.99 + public String toString() { 35.100 + final StringBuilder sb = new StringBuilder(); 35.101 + final Source source = functionNode.getSource(); 35.102 + final long token = tokenFor(functionNode); 35.103 + 35.104 + if (source != null) { 35.105 + sb.append(source.getName()) 35.106 + .append(':') 35.107 + .append(source.getLine(Token.descPosition(token))) 35.108 + .append(' '); 35.109 + } 35.110 + 35.111 + return sb.toString() + super.toString(); 35.112 + } 35.113 + 35.114 + private static long tokenFor(final FunctionNode fn) { 35.115 + final int position = Token.descPosition(fn.getFirstToken()); 35.116 + final int length = Token.descPosition(fn.getLastToken()) - position + Token.descLength(fn.getLastToken()); 35.117 + 35.118 + return Token.toDesc(TokenType.FUNCTION, position, length); 35.119 + } 35.120 + 35.121 + @Override 35.122 + ScriptObject allocate() { 35.123 + try { 35.124 + ensureHasAllocator(); //if allocatorClass name is set to null (e.g. for bound functions) we don't even try 35.125 + return allocator == null ? null : (ScriptObject)allocator.invokeExact(allocatorMap); 35.126 + } catch (final RuntimeException | Error e) { 35.127 + throw e; 35.128 + } catch (final Throwable t) { 35.129 + throw new RuntimeException(t); 35.130 + } 35.131 + } 35.132 + 35.133 + private void ensureHasAllocator() throws ClassNotFoundException { 35.134 + if (allocator == null && allocatorClassName != null) { 35.135 + this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.tag(), MH.type(ScriptObject.class, PropertyMap.class)); 35.136 + } 35.137 + } 35.138 + 35.139 + @Override 35.140 + protected void ensureCodeGenerated() { 35.141 + if (!code.isEmpty()) { 35.142 + return; // nothing to do, we have code, at least some. 35.143 + } 35.144 + 35.145 + // check if function node is lazy, need to compile it. 35.146 + // note that currently function cloning is not working completely, which 35.147 + // means that the compiler will mutate the function node it has been given 35.148 + // once it has been compiled, it cannot be recompiled. This means that 35.149 + // lazy compilation works (not compiled yet) but e.g. specializations won't 35.150 + // until the copy-on-write changes for IR are in, making cloning meaningless. 35.151 + // therefore, currently method specialization is disabled. TODO 35.152 + 35.153 + if (functionNode.isLazy()) { 35.154 + Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '" + functionNode.getName() + "'"); 35.155 + new Compiler(installer, functionNode).compile().install(); 35.156 + 35.157 + // we don't need to update any flags - varArgs and needsCallee are instrincic 35.158 + // in the function world we need to get a destination node from the compile instead 35.159 + // and replace it with our function node. TODO 35.160 + } 35.161 + 35.162 + // we can't get here unless we have bytecode, either from eager compilation or from 35.163 + // running a lazy compile on the lines above 35.164 + 35.165 + assert functionNode.hasState(CompilationState.INSTALLED); 35.166 + 35.167 + // code exists - look it up and add it into the automatically sorted invoker list 35.168 + code.add( 35.169 + new CompiledFunction( 35.170 + MH.findStatic( 35.171 + LOOKUP, 35.172 + functionNode.getCompileUnit().getCode(), 35.173 + functionNode.getName(), 35.174 + new FunctionSignature(functionNode). 35.175 + getMethodType()))); 35.176 + } 35.177 + 35.178 + @Override 35.179 + MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { 35.180 + final MethodHandle mh = super.getBestInvoker(callSiteType, args); 35.181 + if (code.isLessSpecificThan(callSiteType)) { 35.182 + // opportunity for code specialization - we can regenerate a better version of this method 35.183 + } 35.184 + return mh; 35.185 + } 35.186 + 35.187 +} 35.188 +
36.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Tue Mar 12 18:12:42 2013 +0530 36.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Tue Mar 12 15:30:53 2013 +0100 36.3 @@ -82,6 +82,9 @@ 36.4 /** Show full Nashorn version */ 36.5 public final boolean _fullversion; 36.6 36.7 + /** Should lazy compilation take place */ 36.8 + public final boolean _lazy_compilation; 36.9 + 36.10 /** Create a new class loaded for each compilation */ 36.11 public final boolean _loader_per_compile; 36.12 36.13 @@ -155,6 +158,7 @@ 36.14 _early_lvalue_error = options.getBoolean("early.lvalue.error"); 36.15 _empty_statements = options.getBoolean("empty.statements"); 36.16 _fullversion = options.getBoolean("fullversion"); 36.17 + _lazy_compilation = options.getBoolean("lazy.compilation"); 36.18 _loader_per_compile = options.getBoolean("loader.per.compile"); 36.19 _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); 36.20 _package = options.getString("package");
37.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Mar 12 18:12:42 2013 +0530 37.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Mar 12 15:30:53 2013 +0100 37.3 @@ -33,11 +33,11 @@ 37.4 import java.lang.invoke.MethodHandle; 37.5 import java.lang.invoke.MethodHandles; 37.6 import java.lang.invoke.MethodType; 37.7 + 37.8 import jdk.internal.dynalink.CallSiteDescriptor; 37.9 import jdk.internal.dynalink.linker.GuardedInvocation; 37.10 import jdk.internal.dynalink.linker.LinkRequest; 37.11 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 37.12 -import jdk.nashorn.internal.objects.annotations.SpecializedFunction; 37.13 import jdk.nashorn.internal.lookup.MethodHandleFactory; 37.14 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 37.15 import jdk.nashorn.internal.runtime.linker.NashornGuards; 37.16 @@ -48,16 +48,16 @@ 37.17 public abstract class ScriptFunction extends ScriptObject { 37.18 37.19 /** Method handle for prototype getter for this ScriptFunction */ 37.20 - public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class); 37.21 + public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class); 37.22 37.23 /** Method handle for prototype setter for this ScriptFunction */ 37.24 - public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class); 37.25 + public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class); 37.26 37.27 /** Method handle for length getter for this ScriptFunction */ 37.28 - public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class); 37.29 + public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class); 37.30 37.31 /** Method handle for name getter for this ScriptFunction */ 37.32 - public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class); 37.33 + public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class); 37.34 37.35 /** Method handle for allocate function for this ScriptFunction */ 37.36 static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class); 37.37 @@ -67,7 +67,9 @@ 37.38 /** method handle to scope getter for this ScriptFunction */ 37.39 public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class); 37.40 37.41 - private final ScriptFunctionData data; 37.42 + private static final MethodHandle IS_FUNCTION_MH = findOwnMH("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class); 37.43 + 37.44 + private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class); 37.45 37.46 /** Reference to constructor prototype. */ 37.47 protected Object prototype; 37.48 @@ -75,6 +77,8 @@ 37.49 /** The parent scope. */ 37.50 private final ScriptObject scope; 37.51 37.52 + private final ScriptFunctionData data; 37.53 + 37.54 /** 37.55 * Constructor 37.56 * 37.57 @@ -97,7 +101,7 @@ 37.58 final boolean builtin, 37.59 final boolean isConstructor) { 37.60 37.61 - this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope); 37.62 + this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope); 37.63 } 37.64 37.65 /** 37.66 @@ -118,8 +122,8 @@ 37.67 constructorCount++; 37.68 } 37.69 37.70 - this.data = data; 37.71 - this.scope = scope; 37.72 + this.data = data; 37.73 + this.scope = scope; 37.74 } 37.75 37.76 @Override 37.77 @@ -295,20 +299,20 @@ 37.78 /** 37.79 * Return the most appropriate invoke handle if there are specializations 37.80 * @param type most specific method type to look for invocation with 37.81 + * @param callsite args for trampoline invocation 37.82 * @return invoke method handle 37.83 */ 37.84 - private final MethodHandle getBestInvoker(final MethodType type) { 37.85 - return data.getBestInvoker(type); 37.86 + private MethodHandle getBestInvoker(final MethodType type, final Object[] args) { 37.87 + return data.getBestInvoker(type, args); 37.88 } 37.89 37.90 /** 37.91 - * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation 37.92 - * method handle for this ScriptFunction 37.93 - * @see SpecializedFunction 37.94 - * @return invokeHandle 37.95 + * Return the most appropriate invoke handle if there are specializations 37.96 + * @param type most specific method type to look for invocation with 37.97 + * @return invoke method handle 37.98 */ 37.99 - public final MethodHandle getInvokeHandle() { 37.100 - return data.getInvoker(); 37.101 + public MethodHandle getBestInvoker(final MethodType type) { 37.102 + return getBestInvoker(type, null); 37.103 } 37.104 37.105 /** 37.106 @@ -319,7 +323,7 @@ 37.107 * @return bound invoke handle 37.108 */ 37.109 public final MethodHandle getBoundInvokeHandle(final ScriptObject self) { 37.110 - return MH.bindTo(bindToCalleeIfNeeded(getInvokeHandle()), self); 37.111 + return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self); 37.112 } 37.113 37.114 /** 37.115 @@ -329,7 +333,8 @@ 37.116 * @return the potentially bound method handle 37.117 */ 37.118 private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) { 37.119 - return data.needsCallee() ? MH.bindTo(methodHandle, this) : methodHandle; 37.120 + return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle; 37.121 + 37.122 } 37.123 37.124 /** 37.125 @@ -340,15 +345,6 @@ 37.126 return data.getName(); 37.127 } 37.128 37.129 - /** 37.130 - * Does this script function need to be compiled. This determined by 37.131 - * null checking invokeHandle 37.132 - * 37.133 - * @return true if this needs compilation 37.134 - */ 37.135 - public final boolean needsCompilation() { 37.136 - return data.getInvoker() == null; 37.137 - } 37.138 37.139 /** 37.140 * Get the scope for this function 37.141 @@ -359,15 +355,6 @@ 37.142 } 37.143 37.144 /** 37.145 - * Reset the invoker handle. This is used by trampolines for 37.146 - * lazy code generation 37.147 - * @param invoker new invoker 37.148 - */ 37.149 - protected void resetInvoker(final MethodHandle invoker) { 37.150 - data.resetInvoker(invoker); 37.151 - } 37.152 - 37.153 - /** 37.154 * Prototype getter for this ScriptFunction - follows the naming convention 37.155 * used by Nasgen and the code generator 37.156 * 37.157 @@ -464,7 +451,7 @@ 37.158 @Override 37.159 protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) { 37.160 final MethodType type = desc.getMethodType(); 37.161 - return new GuardedInvocation(pairArguments(data.getBestConstructor(type), type), null, NashornGuards.getFunctionGuard(this)); 37.162 + return new GuardedInvocation(pairArguments(data.getBestConstructor(type.changeParameterType(0, ScriptFunction.class), null), type), null, getFunctionGuard(this)); 37.163 } 37.164 37.165 @SuppressWarnings("unused") 37.166 @@ -472,7 +459,7 @@ 37.167 if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) { 37.168 return obj; 37.169 } 37.170 - return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj); 37.171 + return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj); 37.172 } 37.173 37.174 /** 37.175 @@ -506,8 +493,7 @@ 37.176 MethodHandle guard = null; 37.177 37.178 if (data.needsCallee()) { 37.179 - final MethodHandle callHandle = getBestInvoker(type); 37.180 - 37.181 + final MethodHandle callHandle = getBestInvoker(type, request.getArguments()); 37.182 if (NashornCallSiteDescriptor.isScope(desc)) { 37.183 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined 37.184 // (callee, this, args...) => (callee, args...) 37.185 @@ -525,13 +511,12 @@ 37.186 if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { 37.187 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); 37.188 } else { 37.189 - guard = NashornGuards.getNonStrictFunctionGuard(this); 37.190 + guard = getNonStrictFunctionGuard(this); 37.191 } 37.192 } 37.193 } 37.194 } else { 37.195 - final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1)); 37.196 - 37.197 + final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments()); 37.198 if (NashornCallSiteDescriptor.isScope(desc)) { 37.199 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined 37.200 // (this, args...) => (args...) 37.201 @@ -545,7 +530,8 @@ 37.202 } 37.203 37.204 boundHandle = pairArguments(boundHandle, type); 37.205 - return new GuardedInvocation(boundHandle, guard == null ? NashornGuards.getFunctionGuard(this) : guard); 37.206 + 37.207 + return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard); 37.208 } 37.209 37.210 /** 37.211 @@ -554,13 +540,50 @@ 37.212 * These don't want a callee parameter, so bind that. Name binding is optional. 37.213 */ 37.214 MethodHandle getCallMethodHandle(final MethodType type, final String bindName) { 37.215 - return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type)), bindName), type); 37.216 + return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type, null)), bindName), type); 37.217 } 37.218 37.219 private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { 37.220 return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName); 37.221 } 37.222 37.223 + /** 37.224 + * Get the guard that checks if a {@link ScriptFunction} is equal to 37.225 + * a known ScriptFunction, using reference comparison 37.226 + * 37.227 + * @param function The ScriptFunction to check against. This will be bound to the guard method handle 37.228 + * 37.229 + * @return method handle for guard 37.230 + */ 37.231 + private static MethodHandle getFunctionGuard(final ScriptFunction function) { 37.232 + assert function.data != null; 37.233 + return MH.insertArguments(IS_FUNCTION_MH, 1, function.data); 37.234 + } 37.235 + 37.236 + /** 37.237 + * Get a guard that checks if a {@link ScriptFunction} is equal to 37.238 + * a known ScriptFunction using reference comparison, and whether the type of 37.239 + * the second argument (this-object) is not a JavaScript primitive type. 37.240 + * 37.241 + * @param function The ScriptFunction to check against. This will be bound to the guard method handle 37.242 + * 37.243 + * @return method handle for guard 37.244 + */ 37.245 + private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) { 37.246 + assert function.data != null; 37.247 + return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data); 37.248 + } 37.249 + 37.250 + @SuppressWarnings("unused") 37.251 + private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) { 37.252 + return self instanceof ScriptFunction && ((ScriptFunction)self).data == data; 37.253 + } 37.254 + 37.255 + @SuppressWarnings("unused") 37.256 + private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) { 37.257 + return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject; 37.258 + } 37.259 + 37.260 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 37.261 final Class<?> own = ScriptFunction.class; 37.262 final MethodType mt = MH.type(rtype, types);
38.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Mar 12 18:12:42 2013 +0530 38.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Mar 12 15:30:53 2013 +0100 38.3 @@ -32,227 +32,94 @@ 38.4 import java.lang.invoke.MethodHandle; 38.5 import java.lang.invoke.MethodHandles; 38.6 import java.lang.invoke.MethodType; 38.7 -import jdk.nashorn.internal.ir.FunctionNode; 38.8 -import jdk.nashorn.internal.parser.Token; 38.9 -import jdk.nashorn.internal.parser.TokenType; 38.10 + 38.11 +import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; 38.12 38.13 /** 38.14 * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime. 38.15 * Instances of this class are created during codegen and stored in script classes' 38.16 * constants array to reduce function instantiation overhead during runtime. 38.17 */ 38.18 -public final class ScriptFunctionData { 38.19 +public abstract class ScriptFunctionData { 38.20 + 38.21 + /** Name of the function or "" for anonynous functions */ 38.22 + protected final String name; 38.23 + 38.24 + /** All versions of this function that have been generated to code */ 38.25 + protected final CompiledFunctions code; 38.26 + 38.27 + private int arity; 38.28 + 38.29 + private final boolean isStrict; 38.30 + 38.31 + private final boolean isBuiltin; 38.32 + 38.33 + private final boolean isConstructor; 38.34 + 38.35 + private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); 38.36 private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class); 38.37 - private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); 38.38 - 38.39 - // per-function object flags 38.40 - private static final int IS_STRICT = 0b0000_0001; 38.41 - private static final int IS_BUILTIN = 0b0000_0010; 38.42 - private static final int HAS_CALLEE = 0b0000_0100; 38.43 - private static final int IS_VARARGS = 0b0000_1000; 38.44 - private static final int IS_CONSTRUCTOR = 0b0001_0000; 38.45 - 38.46 - /** Name of the function or "" */ 38.47 - private final String name; 38.48 - /** Source of this function, or null */ 38.49 - private final Source source; 38.50 - /** Map for new instance constructor */ 38.51 - private PropertyMap allocatorMap; 38.52 - /** Start position and length in source */ 38.53 - private final long token; 38.54 - /** Number of expected arguments, either taken from FunctionNode or calculated from method handle signature*/ 38.55 - private int arity; 38.56 - private final int flags; 38.57 - 38.58 - /** Reference to code for this method. */ 38.59 - private MethodHandle invoker; 38.60 - /** Reference to code for this method when called to create "new" object. This must always be populated with a 38.61 - * result of calling {@link #composeConstructor(MethodHandle)} on the value of the {@link #invoker} field. */ 38.62 - private MethodHandle constructor; 38.63 - /** Constructor to create a new instance. */ 38.64 - private MethodHandle allocator; 38.65 - /** Generic invoker to used in {@link ScriptFunction#invoke(Object, Object...)}. */ 38.66 - private MethodHandle genericInvoker; 38.67 - /** Specializations - see @SpecializedFunction */ 38.68 - private MethodHandle[] invokeSpecializations; 38.69 - /** Specializations - see @SpecializedFunction. Same restrictions as for {@link #constructor} apply; only populate 38.70 - * with method handles returned from {@link #composeConstructor(MethodHandle)}. */ 38.71 - private MethodHandle[] constructSpecializations; 38.72 - 38.73 - /** 38.74 - * Constructor 38.75 - * @param fn the function node 38.76 - * @param allocatorMap the allocator property map 38.77 - */ 38.78 - public ScriptFunctionData(final FunctionNode fn, final PropertyMap allocatorMap) { 38.79 - 38.80 - final long firstToken = fn.getFirstToken(); 38.81 - final long lastToken = fn.getLastToken(); 38.82 - final int position = Token.descPosition(firstToken); 38.83 - final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken); 38.84 - 38.85 - this.name = fn.isAnonymous() ? "" : fn.getIdent().getName(); 38.86 - this.source = fn.getSource(); 38.87 - this.allocatorMap = allocatorMap; 38.88 - this.token = Token.toDesc(TokenType.FUNCTION, position, length); 38.89 - this.arity = fn.getParameters().size(); 38.90 - this.flags = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false, true); 38.91 - } 38.92 38.93 /** 38.94 * Constructor 38.95 * 38.96 - * @param name the function name 38.97 - * @param methodHandle the method handle 38.98 - * @param specs array of specialized method handles 38.99 - * @param strict strict flag 38.100 - * @param builtin builtin flag 38.101 - * @param isConstructor constructor flags 38.102 + * @param name script function name 38.103 + * @param arity arity 38.104 + * @param isStrict is the function strict 38.105 + * @param isBuiltin is the function built in 38.106 + * @param isConstructor is the function a constructor 38.107 */ 38.108 - public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { 38.109 - this(name, null, 0L, methodHandle, specs, strict, builtin, isConstructor); 38.110 + protected ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 38.111 + this.name = name; 38.112 + this.arity = arity; 38.113 + this.code = new CompiledFunctions(); 38.114 + this.isStrict = isStrict; 38.115 + this.isBuiltin = isBuiltin; 38.116 + this.isConstructor = isConstructor; 38.117 } 38.118 38.119 - private ScriptFunctionData(final String name, final Source source, final long token, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { 38.120 - this.name = name; 38.121 - this.source = source; 38.122 - this.token = token; 38.123 - 38.124 - final boolean isVarArg = isVarArg(methodHandle); 38.125 - final boolean needsCallee = needsCallee(methodHandle); 38.126 - 38.127 - this.flags = makeFlags(needsCallee, isVarArg, strict, builtin, isConstructor); 38.128 - int lArity = isVarArg ? -1 : methodHandle.type().parameterCount() - 1; //drop the self param for arity 38.129 - 38.130 - if (needsCallee && !isVarArg) { 38.131 - lArity--; 38.132 - } 38.133 - 38.134 - if (isConstructor(methodHandle)) { 38.135 - assert isConstructor; 38.136 - if (!isVarArg) { 38.137 - lArity--; // drop the boolean flag for arity 38.138 - } 38.139 - /* 38.140 - * We insert a boolean argument to tell if the method was invoked as constructor or not if the method 38.141 - * handle's first argument is boolean. 38.142 - */ 38.143 - this.invoker = MH.insertArguments(methodHandle, 0, false); 38.144 - this.constructor = composeConstructor(MH.insertArguments(methodHandle, 0, true)); 38.145 - 38.146 - if (specs != null) { 38.147 - this.invokeSpecializations = new MethodHandle[specs.length]; 38.148 - this.constructSpecializations = new MethodHandle[specs.length]; 38.149 - for (int i = 0; i < specs.length; i++) { 38.150 - this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false); 38.151 - this.constructSpecializations[i] = composeConstructor(MH.insertArguments(specs[i], 0, true)); 38.152 - } 38.153 - } 38.154 - } else { 38.155 - this.invoker = methodHandle; 38.156 - this.constructor = null; // delay composition of the constructor 38.157 - this.invokeSpecializations = specs; 38.158 - this.constructSpecializations = null; // delay composition of the constructors 38.159 - } 38.160 - this.arity = lArity; 38.161 - } 38.162 - 38.163 - /** 38.164 - * Get the arity of the function. 38.165 - * @return the arity 38.166 - */ 38.167 - int getArity() { 38.168 + final int getArity() { 38.169 return arity; 38.170 } 38.171 38.172 /** 38.173 - * Set the arity of the function. 38.174 - * @param arity the arity 38.175 + * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final 38.176 + * @param arity new arity 38.177 */ 38.178 - void setArity(int arity) { 38.179 + void setArity(final int arity) { 38.180 this.arity = arity; 38.181 } 38.182 38.183 - /** 38.184 - * Get the function name. 38.185 - * @return function name 38.186 - */ 38.187 - String getName() { 38.188 - return name; 38.189 + CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) { 38.190 + final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args); 38.191 + 38.192 + if (isConstructor()) { 38.193 + ensureConstructor(originalInv); 38.194 + return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args)); 38.195 + } 38.196 + 38.197 + return new CompiledFunction(boundInvoker); 38.198 } 38.199 38.200 /** 38.201 - * Get this function as a String containing its source code. If no source code 38.202 - * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} 38.203 - * @return string representation of this function's source 38.204 + * Is this a ScriptFunction generated with strict semantics? 38.205 + * @return true if strict, false otherwise 38.206 */ 38.207 - String toSource() { 38.208 - if (source != null && token != 0) { 38.209 - return source.getString(Token.descPosition(token), Token.descLength(token)); 38.210 - } 38.211 - 38.212 - return "function " + (name == null ? "" : name) + "() { [native code] }"; 38.213 + public boolean isStrict() { 38.214 + return isStrict; 38.215 } 38.216 38.217 - @Override 38.218 - public String toString() { 38.219 - final StringBuilder sb = new StringBuilder(); 38.220 - 38.221 - sb.append(super.toString()) 38.222 - .append(" [ ") 38.223 - .append(invoker) 38.224 - .append(", ") 38.225 - .append((name == null || name.isEmpty()) ? "<anonymous>" : name); 38.226 - 38.227 - if (source != null) { 38.228 - sb.append(" @ ") 38.229 - .append(source.getName()) 38.230 - .append(':') 38.231 - .append(source.getLine(Token.descPosition(token))); 38.232 - } 38.233 - sb.append(" ]"); 38.234 - 38.235 - return sb.toString(); 38.236 + boolean isBuiltin() { 38.237 + return isBuiltin; 38.238 } 38.239 38.240 - /** 38.241 - * Returns true if the function needs a callee argument. 38.242 - * @return the needsCallee flag 38.243 - */ 38.244 - boolean needsCallee() { 38.245 - return (flags & HAS_CALLEE) != 0; 38.246 + boolean isConstructor() { 38.247 + return isConstructor; 38.248 } 38.249 38.250 - /** 38.251 - * Returns true if this is a strict-mode function. 38.252 - * @return the strict flag 38.253 - */ 38.254 - public boolean isStrict() { 38.255 - return (flags & IS_STRICT) != 0; 38.256 - } 38.257 - 38.258 - /** 38.259 - * Returns true if this is a built-in function. 38.260 - * @return the built-in flag 38.261 - */ 38.262 - private boolean isBuiltin() { 38.263 - return (flags & IS_BUILTIN) != 0; 38.264 - } 38.265 - 38.266 - /** 38.267 - * Returns true if this function can be used as a constructor. 38.268 - * @return the constructor flag 38.269 - */ 38.270 - private boolean isConstructor() { 38.271 - return (flags & IS_CONSTRUCTOR) != 0; 38.272 - } 38.273 - 38.274 - /** 38.275 - * Returns true if this is a var-arg function. 38.276 - * @return the var-arg flag 38.277 - */ 38.278 - private boolean isVarArg() { 38.279 - return (flags & IS_VARARGS) != 0; 38.280 + boolean needsCallee() { 38.281 + // we don't know if we need a callee or not unless we are generated 38.282 + ensureCodeGenerated(); 38.283 + return code.needsCallee(); 38.284 } 38.285 38.286 /** 38.287 @@ -261,127 +128,408 @@ 38.288 * @return true if this argument must be an object 38.289 */ 38.290 boolean needsWrappedThis() { 38.291 - return (flags & (IS_STRICT | IS_BUILTIN)) == 0; 38.292 + return !isStrict && !isBuiltin; 38.293 + } 38.294 + 38.295 + String toSource() { 38.296 + return "function " + (name == null ? "" : name) + "() { [native code] }"; 38.297 + } 38.298 + 38.299 + String getName() { 38.300 + return name; 38.301 } 38.302 38.303 /** 38.304 - * Get the method handle used to invoke this function. 38.305 - * @return the invoke handle 38.306 + * Get this function as a String containing its source code. If no source code 38.307 + * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} 38.308 + * 38.309 + * @return string representation of this function 38.310 */ 38.311 - MethodHandle getInvoker() { 38.312 - return invoker; 38.313 - } 38.314 + @Override 38.315 + public String toString() { 38.316 + final StringBuilder sb = new StringBuilder(); 38.317 38.318 - MethodHandle getBestInvoker(final MethodType type) { 38.319 - return SpecializedMethodChooser.candidateWithLowestWeight(type, invoker, invokeSpecializations); 38.320 + sb.append("name='"). 38.321 + append(name.isEmpty() ? "<anonymous>" : name). 38.322 + append("' "). 38.323 + append(code.size()). 38.324 + append(" invokers="). 38.325 + append(code); 38.326 + 38.327 + return sb.toString(); 38.328 } 38.329 38.330 /** 38.331 - * Get the method handle used to invoke this function as a constructor. 38.332 - * @return the constructor handle 38.333 + * Pick the best invoker, i.e. the one version of this method with as narrow and specific 38.334 + * types as possible. If the call site arguments are objects, but boxed primitives we can 38.335 + * also try to get a primitive version of the method and do an unboxing filter, but then 38.336 + * we need to insert a guard that checks the argument is really always a boxed primitive 38.337 + * and not suddenly a "real" object 38.338 + * 38.339 + * @param callSiteType callsite type 38.340 + * @param args arguments at callsite on first trampoline invocation 38.341 + * @return method handle to best invoker 38.342 */ 38.343 - private MethodHandle getConstructor() { 38.344 - if (constructor == null) { 38.345 - constructor = composeConstructor(invoker); 38.346 - } 38.347 - 38.348 - return constructor; 38.349 + MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { 38.350 + return getBest(callSiteType).getInvoker(); 38.351 } 38.352 38.353 - MethodHandle getBestConstructor(MethodType descType) { 38.354 + MethodHandle getBestInvoker(final MethodType callSiteType) { 38.355 + return getBestInvoker(callSiteType, null); 38.356 + } 38.357 + 38.358 + MethodHandle getBestConstructor(final MethodType callSiteType, final Object[] args) { 38.359 if (!isConstructor()) { 38.360 throw typeError("not.a.constructor", toSource()); 38.361 } 38.362 - return SpecializedMethodChooser.candidateWithLowestWeight(descType, getConstructor(), getConstructSpecializations()); 38.363 + ensureCodeGenerated(); 38.364 + 38.365 + final CompiledFunction best = getBest(callSiteType); 38.366 + ensureConstructor(best); 38.367 + return best.getConstructor(); 38.368 } 38.369 38.370 - private MethodHandle composeConstructor(MethodHandle ctor) { 38.371 + MethodHandle getBestConstructor(final MethodType callSiteType) { 38.372 + return getBestConstructor(callSiteType, null); 38.373 + } 38.374 + 38.375 + /** 38.376 + * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that 38.377 + * code exists before performing an operation. 38.378 + */ 38.379 + protected void ensureCodeGenerated() { 38.380 + //empty 38.381 + } 38.382 + 38.383 + /** 38.384 + * Return a generic Object/Object invoker for this method. It will ensure code 38.385 + * is generated, get the most generic of all versions of this function and adapt it 38.386 + * to Objects. 38.387 + * 38.388 + * TODO this is only public because {@link JavaAdapterFactory} can't supply us with 38.389 + * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed 38.390 + * 38.391 + * @return generic invoker of this script function 38.392 + */ 38.393 + public final MethodHandle getGenericInvoker() { 38.394 + ensureCodeGenerated(); 38.395 + return composeGenericMethod(code.mostGeneric().getInvoker()); 38.396 + } 38.397 + 38.398 + private CompiledFunction getBest(final MethodType callSiteType) { 38.399 + ensureCodeGenerated(); 38.400 + return code.best(callSiteType); 38.401 + } 38.402 + 38.403 + /** 38.404 + * Allocates an object using this function's allocator. 38.405 + * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator. 38.406 + */ 38.407 + ScriptObject allocate() { 38.408 + return null; 38.409 + } 38.410 + 38.411 + /** 38.412 + * This method is used to create the immutable portion of a bound function. 38.413 + * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} 38.414 + * 38.415 + * @param fn the original function being bound 38.416 + * @param self this reference to bind. Can be null. 38.417 + * @param args additional arguments to bind. Can be null. 38.418 + */ 38.419 + ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { 38.420 + ensureCodeGenerated(); 38.421 + 38.422 + final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; 38.423 + final int length = args == null ? 0 : args.length; 38.424 + 38.425 + CompiledFunctions boundList = new CompiledFunctions(); 38.426 + for (final CompiledFunction inv : code) { 38.427 + boundList.add(bind(inv, fn, self, allArgs)); 38.428 + } 38.429 + ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor()); 38.430 + return boundData; 38.431 + } 38.432 + 38.433 + /** 38.434 + * Compose a constructor given a primordial constructor handle 38.435 + * 38.436 + * @param ctor primordial constructor handle 38.437 + * @param needsCallee do we need to pass a callee 38.438 + * 38.439 + * @return the composed constructor 38.440 + */ 38.441 + protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) { 38.442 // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having 38.443 // "this" in the first argument position is what allows the elegant folded composition of 38.444 // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor 38.445 // always returns Object. 38.446 - MethodHandle composedCtor = changeReturnTypeToObject(swapCalleeAndThis(ctor)); 38.447 + MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; 38.448 + 38.449 + composedCtor = changeReturnTypeToObject(composedCtor); 38.450 38.451 final MethodType ctorType = composedCtor.type(); 38.452 + 38.453 // Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually 38.454 // captured as "allocation" parameter of NEWFILTER after we fold the constructor into it. 38.455 // (this, [callee, ]args...) => ([callee, ]args...) 38.456 final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); 38.457 + 38.458 // Fold constructor into newFilter that replaces the return value from the constructor with the originally 38.459 // allocated value when the originally allocated value is a primitive. 38.460 // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...) 38.461 composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor); 38.462 38.463 // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject... 38.464 - if (needsCallee()) { 38.465 + if (needsCallee) { 38.466 // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and 38.467 // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...), 38.468 // or... 38.469 return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE); 38.470 } 38.471 + 38.472 // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee 38.473 // (this, args...) filter (callee) => (callee, args...) 38.474 return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE); 38.475 } 38.476 38.477 /** 38.478 - * Get an adapted version of the invoker handle that only uses {@code Object} as parameter and return types. 38.479 - * @return the generic invoke handle 38.480 + * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed 38.481 + * method handle. If this function's method handles don't need a callee parameter, returns the original method 38.482 + * handle unchanged. 38.483 + * 38.484 + * @param mh a method handle with order of arguments {@code (callee, this, args...)} 38.485 + * 38.486 + * @return a method handle with order of arguments {@code (this, callee, args...)} 38.487 */ 38.488 - private MethodHandle getGenericInvoker() { 38.489 - if (genericInvoker == null) { 38.490 - assert invoker != null : "invoker is null"; 38.491 - genericInvoker = makeGenericMethod(invoker); 38.492 + private static MethodHandle swapCalleeAndThis(final MethodHandle mh) { 38.493 + final MethodType type = mh.type(); 38.494 + assert type.parameterType(0) == ScriptFunction.class : type; 38.495 + assert type.parameterType(1) == Object.class : type; 38.496 + final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); 38.497 + final int[] reorder = new int[type.parameterCount()]; 38.498 + reorder[0] = 1; 38.499 + assert reorder[1] == 0; 38.500 + for (int i = 2; i < reorder.length; ++i) { 38.501 + reorder[i] = i; 38.502 } 38.503 - return genericInvoker; 38.504 + return MethodHandles.permuteArguments(mh, newType, reorder); 38.505 + } 38.506 + 38.507 + /** 38.508 + * Convert this argument for non-strict functions according to ES 10.4.3 38.509 + * 38.510 + * @param thiz the this argument 38.511 + * 38.512 + * @return the converted this object 38.513 + */ 38.514 + private Object convertThisObject(final Object thiz) { 38.515 + if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { 38.516 + if (JSType.nullOrUndefined(thiz)) { 38.517 + return Context.getGlobalTrusted(); 38.518 + } 38.519 + 38.520 + if (isPrimitiveThis(thiz)) { 38.521 + return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz); 38.522 + } 38.523 + } 38.524 + 38.525 + return thiz; 38.526 + } 38.527 + 38.528 + static boolean isPrimitiveThis(final Object obj) { 38.529 + return obj instanceof String || obj instanceof ConsString || 38.530 + obj instanceof Number || obj instanceof Boolean; 38.531 + } 38.532 + 38.533 + /** 38.534 + * Creates an invoker method handle for a bound function. 38.535 + * 38.536 + * @param targetFn the function being bound 38.537 + * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or 38.538 + * any of its specializations. 38.539 + * @param self the "this" value being bound 38.540 + * @param args additional arguments being bound 38.541 + * 38.542 + * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting 38.543 + * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting 38.544 + * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed 38.545 + * to the original invoker on invocation. 38.546 + */ 38.547 + private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) { 38.548 + // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound 38.549 + // in the target and will be ignored anyway. 38.550 + final boolean isTargetBound = targetFn.isBoundFunction(); 38.551 + 38.552 + final boolean needsCallee = needsCallee(originalInvoker); 38.553 + assert needsCallee == needsCallee() : "callee contract violation 2"; 38.554 + assert !(isTargetBound && needsCallee); // already bound functions don't need a callee 38.555 + 38.556 + final Object boundSelf = isTargetBound ? null : convertThisObject(self); 38.557 + final MethodHandle boundInvoker; 38.558 + 38.559 + if (isVarArg(originalInvoker)) { 38.560 + // First, bind callee and this without arguments 38.561 + final MethodHandle noArgBoundInvoker; 38.562 + 38.563 + if (isTargetBound) { 38.564 + // Don't bind either callee or this 38.565 + noArgBoundInvoker = originalInvoker; 38.566 + } else if (needsCallee) { 38.567 + // Bind callee and this 38.568 + noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf); 38.569 + } else { 38.570 + // Only bind this 38.571 + noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf); 38.572 + } 38.573 + // Now bind arguments 38.574 + if (args.length > 0) { 38.575 + boundInvoker = varArgBinder(noArgBoundInvoker, args); 38.576 + } else { 38.577 + boundInvoker = noArgBoundInvoker; 38.578 + } 38.579 + } else { 38.580 + final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))]; 38.581 + int next = 0; 38.582 + if (!isTargetBound) { 38.583 + if (needsCallee) { 38.584 + boundArgs[next++] = targetFn; 38.585 + } 38.586 + boundArgs[next++] = boundSelf; 38.587 + } 38.588 + // If more bound args were specified than the function can take, we'll just drop those. 38.589 + System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next); 38.590 + // If target is already bound, insert additional bound arguments after "this" argument, at position 1; 38.591 + // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions 38.592 + // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args 38.593 + // start at position 1. If the function is not bound, we start inserting arguments at position 0. 38.594 + boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs); 38.595 + } 38.596 + 38.597 + if (isTargetBound) { 38.598 + return boundInvoker; 38.599 + } 38.600 + 38.601 + // If the target is not already bound, add a dropArguments that'll throw away the passed this 38.602 + return MH.dropArguments(boundInvoker, 0, Object.class); 38.603 + } 38.604 + 38.605 + /** 38.606 + * Creates a constructor method handle for a bound function using the passed constructor handle. 38.607 + * 38.608 + * @param originalConstructor the constructor handle to bind. It must be a composed constructor. 38.609 + * @param fn the function being bound 38.610 + * @param args arguments being bound 38.611 + * 38.612 + * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never 38.613 + * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor 38.614 + * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if 38.615 + * this script function data object has no constructor handle, null is returned. 38.616 + */ 38.617 + private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) { 38.618 + assert originalConstructor != null; 38.619 + 38.620 + // If target function is already bound, don't bother binding the callee. 38.621 + final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor : 38.622 + MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class); 38.623 + 38.624 + if (args.length == 0) { 38.625 + return calleeBoundConstructor; 38.626 + } 38.627 + 38.628 + if (isVarArg(calleeBoundConstructor)) { 38.629 + return varArgBinder(calleeBoundConstructor, args); 38.630 + } 38.631 + 38.632 + final Object[] boundArgs; 38.633 + 38.634 + final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1; 38.635 + if (args.length <= maxArgCount) { 38.636 + boundArgs = args; 38.637 + } else { 38.638 + boundArgs = new Object[maxArgCount]; 38.639 + System.arraycopy(args, 0, boundArgs, 0, maxArgCount); 38.640 + } 38.641 + 38.642 + return MH.insertArguments(calleeBoundConstructor, 1, boundArgs); 38.643 + } 38.644 + 38.645 + /** 38.646 + * Takes a method handle, and returns a potentially different method handle that can be used in 38.647 + * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. 38.648 + * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into 38.649 + * {@code Object} as well, except for the following ones: 38.650 + * <ul> 38.651 + * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li> 38.652 + * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself 38.653 + * (callee) as an argument.</li> 38.654 + * </ul> 38.655 + * 38.656 + * @param mh the original method handle 38.657 + * 38.658 + * @return the new handle, conforming to the rules above. 38.659 + */ 38.660 + protected MethodHandle composeGenericMethod(final MethodHandle mh) { 38.661 + final MethodType type = mh.type(); 38.662 + MethodType newType = type.generic(); 38.663 + if (isVarArg(mh)) { 38.664 + newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); 38.665 + } 38.666 + if (needsCallee(mh)) { 38.667 + newType = newType.changeParameterType(0, ScriptFunction.class); 38.668 + } 38.669 + return type.equals(newType) ? mh : mh.asType(newType); 38.670 } 38.671 38.672 /** 38.673 * Execute this script function. 38.674 + * 38.675 * @param self Target object. 38.676 * @param arguments Call arguments. 38.677 * @return ScriptFunction result. 38.678 + * 38.679 * @throws Throwable if there is an exception/error with the invocation or thrown from it 38.680 */ 38.681 Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { 38.682 - final MethodHandle genInvoker = getGenericInvoker(); 38.683 - final Object selfObj = convertThisObject(self); 38.684 - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 38.685 + final MethodHandle mh = getGenericInvoker(); 38.686 38.687 - if (isVarArg()) { 38.688 - if (needsCallee()) { 38.689 - return genInvoker.invokeExact(fn, selfObj, args); 38.690 + final Object selfObj = convertThisObject(self); 38.691 + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 38.692 + 38.693 + if (isVarArg(mh)) { 38.694 + if (needsCallee(mh)) { 38.695 + return mh.invokeExact(fn, selfObj, args); 38.696 } 38.697 - return genInvoker.invokeExact(selfObj, args); 38.698 + return mh.invokeExact(selfObj, args); 38.699 } 38.700 38.701 - final int paramCount = genInvoker.type().parameterCount(); 38.702 - if (needsCallee()) { 38.703 + final int paramCount = mh.type().parameterCount(); 38.704 + if (needsCallee(mh)) { 38.705 switch (paramCount) { 38.706 case 2: 38.707 - return genInvoker.invokeExact(fn, selfObj); 38.708 + return mh.invokeExact(fn, selfObj); 38.709 case 3: 38.710 - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0)); 38.711 + return mh.invokeExact(fn, selfObj, getArg(args, 0)); 38.712 case 4: 38.713 - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); 38.714 + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); 38.715 case 5: 38.716 - return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 38.717 + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 38.718 default: 38.719 - return genInvoker.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); 38.720 + return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); 38.721 } 38.722 } 38.723 38.724 switch (paramCount) { 38.725 case 1: 38.726 - return genInvoker.invokeExact(selfObj); 38.727 + return mh.invokeExact(selfObj); 38.728 case 2: 38.729 - return genInvoker.invokeExact(selfObj, getArg(args, 0)); 38.730 + return mh.invokeExact(selfObj, getArg(args, 0)); 38.731 case 3: 38.732 - return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); 38.733 + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); 38.734 case 4: 38.735 - return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 38.736 + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 38.737 default: 38.738 - return genInvoker.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); 38.739 + return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); 38.740 } 38.741 } 38.742 38.743 @@ -389,15 +537,13 @@ 38.744 return i < args.length ? args[i] : UNDEFINED; 38.745 } 38.746 38.747 - private Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) { 38.748 + private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) { 38.749 final Object[] finalArgs = new Object[argCount]; 38.750 38.751 int nextArg = 0; 38.752 - if (needsCallee()) { 38.753 - assert fn != null; 38.754 + if (fn != null) { 38.755 + //needs callee 38.756 finalArgs[nextArg++] = fn; 38.757 - } else { 38.758 - assert fn == null; 38.759 } 38.760 finalArgs[nextArg++] = self; 38.761 38.762 @@ -413,255 +559,14 @@ 38.763 38.764 return finalArgs; 38.765 } 38.766 - 38.767 - /** 38.768 - * Get the specialized construct handles for this function. 38.769 - * @return array of specialized construct handles 38.770 - */ 38.771 - private MethodHandle[] getConstructSpecializations() { 38.772 - if(constructSpecializations == null && invokeSpecializations != null) { 38.773 - final MethodHandle[] ctors = new MethodHandle[invokeSpecializations.length]; 38.774 - for(int i = 0; i < ctors.length; ++i) { 38.775 - ctors[i] = composeConstructor(invokeSpecializations[i]); 38.776 - } 38.777 - constructSpecializations = ctors; 38.778 - } 38.779 - return constructSpecializations; 38.780 - } 38.781 - 38.782 - /** 38.783 - * Set the method handles for this function. 38.784 - * @param invoker the invoker handle 38.785 - * @param allocator the allocator handle 38.786 - */ 38.787 - public void setMethodHandles(final MethodHandle invoker, final MethodHandle allocator) { 38.788 - // We can't make method handle fields final because they're not available during codegen 38.789 - // and they're set when first called, so we enforce set-once here. 38.790 - if (this.invoker == null) { 38.791 - this.invoker = invoker; 38.792 - this.constructor = null; // delay constructor composition 38.793 - this.allocator = allocator; 38.794 - } 38.795 - } 38.796 - 38.797 - /** 38.798 - * Used by the trampoline. Must not be any wider than package 38.799 - * private 38.800 - * @param invoker new invoker 38.801 - */ 38.802 - void resetInvoker(final MethodHandle invoker) { 38.803 - this.invoker = invoker; 38.804 - this.constructor = null; //delay constructor composition 38.805 - } 38.806 - 38.807 - /** 38.808 - * Allocates an object using this function's allocator. 38.809 - * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator. 38.810 - */ 38.811 - ScriptObject allocate() { 38.812 - if (allocator == null) { 38.813 - return null; 38.814 - } 38.815 - 38.816 - try { 38.817 - return (ScriptObject)allocator.invokeExact(allocatorMap); 38.818 - } catch (final RuntimeException | Error e) { 38.819 - throw e; 38.820 - } catch (final Throwable t) { 38.821 - throw new RuntimeException(t); 38.822 - } 38.823 - } 38.824 - 38.825 - /** 38.826 - * This method is used to create the immutable portion of a bound function. 38.827 - * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} 38.828 - * 38.829 - * @param fn the original function being bound 38.830 - * @param self this reference to bind. Can be null. 38.831 - * @param args additional arguments to bind. Can be null. 38.832 - */ 38.833 - ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { 38.834 - final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; 38.835 - 38.836 - final boolean isConstructor = isConstructor(); 38.837 - // Note that the new ScriptFunctionData's method handle will not need a callee regardless of whether the 38.838 - // original did. 38.839 - final ScriptFunctionData boundData = new ScriptFunctionData(name, source, token, 38.840 - bindInvokeHandle(invoker, fn, self, allArgs), bindInvokeSpecializations(fn, self, allArgs), isStrict(), isBuiltin(), isConstructor); 38.841 - if(isConstructor) { 38.842 - // Can't just rely on bound invoke as a basis for constructor, as it ignores the passed "this" in favor of the 38.843 - // bound "this"; constructor on the other hand must see the actual "this" received from the allocator. 38.844 - 38.845 - // Binding a function will force constructor composition in getConstructor(); not really any way around that 38.846 - // as it's the composed constructor that has to be bound to the function. 38.847 - boundData.constructor = bindConstructHandle(getConstructor(), fn, allArgs); 38.848 - boundData.constructSpecializations = bindConstructorSpecializations(fn, allArgs); 38.849 - } 38.850 - assert boundData.allocator == null; 38.851 - final int thisArity = getArity(); 38.852 - if(thisArity != -1) { 38.853 - boundData.setArity(Math.max(0, thisArity - args.length)); 38.854 - } else { 38.855 - assert boundData.getArity() == -1; 38.856 - } 38.857 - return boundData; 38.858 - } 38.859 - 38.860 - /** 38.861 - * Convert this argument for non-strict functions according to ES 10.4.3 38.862 - * 38.863 - * @param thiz the this argument 38.864 - * 38.865 - * @return the converted this object 38.866 - */ 38.867 - Object convertThisObject(final Object thiz) { 38.868 - if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { 38.869 - if (JSType.nullOrUndefined(thiz)) { 38.870 - return Context.getGlobalTrusted(); 38.871 - } 38.872 - 38.873 - if (isPrimitiveThis(thiz)) { 38.874 - return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz); 38.875 - } 38.876 - } 38.877 - 38.878 - return thiz; 38.879 - } 38.880 - 38.881 - static boolean isPrimitiveThis(Object obj) { 38.882 - return obj instanceof String || obj instanceof ConsString || 38.883 - obj instanceof Number || obj instanceof Boolean; 38.884 - } 38.885 - 38.886 - /** 38.887 - * Creates an invoker method handle for a bound function. 38.888 - * @param targetFn the function being bound 38.889 - * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or 38.890 - * any of its specializations. 38.891 - * @param self the "this" value being bound 38.892 - * @param args additional arguments being bound 38.893 - * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting 38.894 - * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting 38.895 - * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed 38.896 - * to the original invoker on invocation. 38.897 - */ 38.898 - private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) { 38.899 - // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound 38.900 - // in the target and will be ignored anyway. 38.901 - final boolean isTargetBound = targetFn.isBoundFunction(); 38.902 - assert !(isTargetBound && needsCallee()); // already bound functions don't need a callee 38.903 - final Object boundSelf = isTargetBound ? null : convertThisObject(self); 38.904 - final MethodHandle boundInvoker; 38.905 - if(isVarArg(originalInvoker)) { 38.906 - // First, bind callee and this without arguments 38.907 - final MethodHandle noArgBoundInvoker; 38.908 - if(isTargetBound) { 38.909 - // Don't bind either callee or this 38.910 - noArgBoundInvoker = originalInvoker; 38.911 - } else if(needsCallee()) { 38.912 - // Bind callee and this 38.913 - noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf); 38.914 - } else { 38.915 - // Only bind this 38.916 - noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf); 38.917 - } 38.918 - // Now bind arguments 38.919 - if(args.length > 0) { 38.920 - boundInvoker = varArgBinder(noArgBoundInvoker, args); 38.921 - } else { 38.922 - boundInvoker = noArgBoundInvoker; 38.923 - } 38.924 - } else { 38.925 - final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), 38.926 - args.length + (isTargetBound ? 0 : (needsCallee() ? 2 : 1)))]; 38.927 - int next = 0; 38.928 - if(!isTargetBound) { 38.929 - if(needsCallee()) { 38.930 - boundArgs[next++] = targetFn; 38.931 - } 38.932 - boundArgs[next++] = boundSelf; 38.933 - } 38.934 - // If more bound args were specified than the function can take, we'll just drop those. 38.935 - System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next); 38.936 - // If target is already bound, insert additional bound arguments after "this" argument, at position 1; 38.937 - // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions 38.938 - // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args 38.939 - // start at position 1. If the function is not bound, we start inserting arguments at position 0. 38.940 - boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs); 38.941 - } 38.942 - if(isTargetBound) { 38.943 - return boundInvoker; 38.944 - } 38.945 - // If the target is not already bound, add a dropArguments that'll throw away the passed this 38.946 - return MH.dropArguments(boundInvoker, 0, Object.class); 38.947 - } 38.948 - 38.949 - private MethodHandle[] bindInvokeSpecializations(final ScriptFunction fn, final Object self, final Object[] args) { 38.950 - if(invokeSpecializations == null) { 38.951 - return null; 38.952 - } 38.953 - final MethodHandle[] boundSpecializations = new MethodHandle[invokeSpecializations.length]; 38.954 - for(int i = 0; i < invokeSpecializations.length; ++i) { 38.955 - boundSpecializations[i] = bindInvokeHandle(invokeSpecializations[i], fn, self, args); 38.956 - } 38.957 - return boundSpecializations; 38.958 - } 38.959 - 38.960 - /** 38.961 - * Creates a constructor method handle for a bound function using the passed constructor handle. 38.962 - * @param originalConstructor the constructor handle to bind. It must be a composed constructor. 38.963 - * @param fn the function being bound 38.964 - * @param args arguments being bound 38.965 - * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never 38.966 - * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor 38.967 - * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if 38.968 - * this script function data object has no constructor handle, null is returned. 38.969 - */ 38.970 - private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) { 38.971 - if(originalConstructor == null) { 38.972 - return null; 38.973 - } 38.974 - 38.975 - // If target function is already bound, don't bother binding the callee. 38.976 - final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor : 38.977 - MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class); 38.978 - if(args.length == 0) { 38.979 - return calleeBoundConstructor; 38.980 - } 38.981 - 38.982 - if(isVarArg(calleeBoundConstructor)) { 38.983 - return varArgBinder(calleeBoundConstructor, args); 38.984 - } 38.985 - 38.986 - final Object[] boundArgs; 38.987 - final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1; 38.988 - if (args.length <= maxArgCount) { 38.989 - boundArgs = args; 38.990 - } else { 38.991 - boundArgs = new Object[maxArgCount]; 38.992 - System.arraycopy(args, 0, boundArgs, 0, maxArgCount); 38.993 - } 38.994 - return MH.insertArguments(calleeBoundConstructor, 1, boundArgs); 38.995 - } 38.996 - 38.997 - private MethodHandle[] bindConstructorSpecializations(final ScriptFunction fn, final Object[] args) { 38.998 - final MethodHandle[] ctorSpecs = getConstructSpecializations(); 38.999 - if(ctorSpecs == null) { 38.1000 - return null; 38.1001 - } 38.1002 - final MethodHandle[] boundSpecializations = new MethodHandle[ctorSpecs.length]; 38.1003 - for(int i = 0; i < ctorSpecs.length; ++i) { 38.1004 - boundSpecializations[i] = bindConstructHandle(ctorSpecs[i], fn, args); 38.1005 - } 38.1006 - return boundSpecializations; 38.1007 - } 38.1008 - 38.1009 /** 38.1010 * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the 38.1011 * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on 38.1012 * invocation 38.1013 + * 38.1014 * @param mh the handle 38.1015 * @param args the bound arguments 38.1016 + * 38.1017 * @return the bound method handle 38.1018 */ 38.1019 private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) { 38.1020 @@ -671,41 +576,20 @@ 38.1021 } 38.1022 38.1023 /** 38.1024 - * Convert boolean flags to int. 38.1025 - * @param needsCallee needs-callee flag 38.1026 - * @param isVarArg var-arg flag 38.1027 - * @param isStrict strict flag 38.1028 - * @param isBuiltin builtin flag 38.1029 - * @return int flags 38.1030 + * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already 38.1031 + * {@code Object}, the handle is returned unchanged. 38.1032 + * 38.1033 + * @param mh the handle to adapt 38.1034 + * @return the adapted handle 38.1035 */ 38.1036 - private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 38.1037 - int flags = 0; 38.1038 - if (needsCallee) { 38.1039 - flags |= HAS_CALLEE; 38.1040 - } 38.1041 - if (isVarArg) { 38.1042 - flags |= IS_VARARGS; 38.1043 - } 38.1044 - if (isStrict) { 38.1045 - flags |= IS_STRICT; 38.1046 - } 38.1047 - if (isBuiltin) { 38.1048 - flags |= IS_BUILTIN; 38.1049 - } 38.1050 - if (isConstructor) { 38.1051 - flags |= IS_CONSTRUCTOR; 38.1052 - } 38.1053 - 38.1054 - return flags; 38.1055 + private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { 38.1056 + return MH.asType(mh, mh.type().changeReturnType(Object.class)); 38.1057 } 38.1058 38.1059 - /** 38.1060 - * Test if a methodHandle refers to a constructor. 38.1061 - * @param methodHandle MethodHandle to test. 38.1062 - * @return True if method is a constructor. 38.1063 - */ 38.1064 - private static boolean isConstructor(final MethodHandle methodHandle) { 38.1065 - return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class; 38.1066 + private void ensureConstructor(final CompiledFunction inv) { 38.1067 + if (!inv.hasConstructor()) { 38.1068 + inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker()))); 38.1069 + } 38.1070 } 38.1071 38.1072 /** 38.1073 @@ -713,102 +597,56 @@ 38.1074 * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has 38.1075 * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly 38.1076 * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore 38.1077 - * they also always receive a callee. 38.1078 - * @param methodHandle the examined method handle 38.1079 + * they also always receive a callee). 38.1080 + * 38.1081 + * @param mh the examined method handle 38.1082 + * 38.1083 * @return true if the method handle expects a callee, false otherwise 38.1084 */ 38.1085 - private static boolean needsCallee(MethodHandle methodHandle) { 38.1086 - final MethodType type = methodHandle.type(); 38.1087 - final int len = type.parameterCount(); 38.1088 - if(len == 0) { 38.1089 + protected static boolean needsCallee(final MethodHandle mh) { 38.1090 + final MethodType type = mh.type(); 38.1091 + final int length = type.parameterCount(); 38.1092 + 38.1093 + if (length == 0) { 38.1094 return false; 38.1095 } 38.1096 - if(type.parameterType(0) == boolean.class) { 38.1097 - return len > 1 && type.parameterType(1) == ScriptFunction.class; 38.1098 + 38.1099 + if (type.parameterType(0) == boolean.class) { 38.1100 + return length > 1 && type.parameterType(1) == ScriptFunction.class; 38.1101 } 38.1102 + 38.1103 return type.parameterType(0) == ScriptFunction.class; 38.1104 } 38.1105 38.1106 - private static boolean isVarArg(MethodHandle methodHandle) { 38.1107 - final MethodType type = methodHandle.type(); 38.1108 + /** 38.1109 + * Check if a javascript function methodhandle is a vararg handle 38.1110 + * 38.1111 + * @param mh method handle to check 38.1112 + * 38.1113 + * @return true if vararg 38.1114 + */ 38.1115 + protected static boolean isVarArg(final MethodHandle mh) { 38.1116 + final MethodType type = mh.type(); 38.1117 return type.parameterType(type.parameterCount() - 1).isArray(); 38.1118 } 38.1119 38.1120 - /** 38.1121 - * Takes a method handle, and returns a potentially different method handle that can be used in 38.1122 - * {@link ScriptFunction#invoke(Object, Object...)} or {@link ScriptFunction#construct(Object, Object...)}. 38.1123 - * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into 38.1124 - * {@code Object} as well, except for the following ones: 38.1125 - * <ul> 38.1126 - * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li> 38.1127 - * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself 38.1128 - * (callee) as an argument.</li> 38.1129 - * </ul> 38.1130 - * 38.1131 - * @param handle the original method handle 38.1132 - * @return the new handle, conforming to the rules above. 38.1133 - */ 38.1134 - private MethodHandle makeGenericMethod(final MethodHandle handle) { 38.1135 - final MethodType type = handle.type(); 38.1136 - MethodType newType = type.generic(); 38.1137 - if (isVarArg()) { 38.1138 - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); 38.1139 - } 38.1140 - if (needsCallee()) { 38.1141 - newType = newType.changeParameterType(0, ScriptFunction.class); 38.1142 - } 38.1143 - return type.equals(newType) ? handle : handle.asType(newType); 38.1144 - } 38.1145 - 38.1146 - /** 38.1147 - * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already 38.1148 - * {@code Object}, the handle is returned unchanged. 38.1149 - * @param mh the handle to adapt 38.1150 - * @return the adapted handle 38.1151 - */ 38.1152 - private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { 38.1153 - return MH.asType(mh, mh.type().changeReturnType(Object.class)); 38.1154 - } 38.1155 - 38.1156 - 38.1157 - /** 38.1158 - * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed 38.1159 - * method handle. If this function's method handles don't need a callee parameter, returns the original method 38.1160 - * handle unchanged. 38.1161 - * @param mh a method handle with order of arguments {@code (callee, this, args...)} 38.1162 - * @return a method handle with order of arguments {@code (this, callee, args...)} 38.1163 - */ 38.1164 - private MethodHandle swapCalleeAndThis(final MethodHandle mh) { 38.1165 - if (!needsCallee()) { 38.1166 - return mh; 38.1167 - } 38.1168 - final MethodType type = mh.type(); 38.1169 - assert type.parameterType(0) == ScriptFunction.class; 38.1170 - assert type.parameterType(1) == Object.class; 38.1171 - final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); 38.1172 - final int[] reorder = new int[type.parameterCount()]; 38.1173 - reorder[0] = 1; 38.1174 - assert reorder[1] == 0; 38.1175 - for (int i = 2; i < reorder.length; ++i) { 38.1176 - reorder[i] = i; 38.1177 - } 38.1178 - return MethodHandles.permuteArguments(mh, newType, reorder); 38.1179 - } 38.1180 - 38.1181 @SuppressWarnings("unused") 38.1182 private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) { 38.1183 - if(array2 == null) { 38.1184 + if (array2 == null) { 38.1185 // Must clone it, as we can't allow the receiving method to alter the array 38.1186 return array1.clone(); 38.1187 } 38.1188 + 38.1189 final int l2 = array2.length; 38.1190 - if(l2 == 0) { 38.1191 + if (l2 == 0) { 38.1192 return array1.clone(); 38.1193 } 38.1194 + 38.1195 final int l1 = array1.length; 38.1196 final Object[] concat = new Object[l1 + l2]; 38.1197 System.arraycopy(array1, 0, concat, 0, l1); 38.1198 System.arraycopy(array2, 0, concat, l1, l2); 38.1199 + 38.1200 return concat; 38.1201 } 38.1202 38.1203 @@ -820,5 +658,4 @@ 38.1204 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 38.1205 return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types)); 38.1206 } 38.1207 - 38.1208 }
39.1 --- a/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java Tue Mar 12 18:12:42 2013 +0530 39.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 39.3 @@ -1,99 +0,0 @@ 39.4 -/* 39.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 39.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 39.7 - * 39.8 - * This code is free software; you can redistribute it and/or modify it 39.9 - * under the terms of the GNU General Public License version 2 only, as 39.10 - * published by the Free Software Foundation. Oracle designates this 39.11 - * particular file as subject to the "Classpath" exception as provided 39.12 - * by Oracle in the LICENSE file that accompanied this code. 39.13 - * 39.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 39.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 39.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 39.17 - * version 2 for more details (a copy is included in the LICENSE file that 39.18 - * accompanied this code). 39.19 - * 39.20 - * You should have received a copy of the GNU General Public License version 39.21 - * 2 along with this work; if not, write to the Free Software Foundation, 39.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 39.23 - * 39.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 39.25 - * or visit www.oracle.com if you need additional information or have any 39.26 - * questions. 39.27 - */ 39.28 - 39.29 -package jdk.nashorn.internal.runtime; 39.30 - 39.31 -import java.lang.invoke.MethodHandle; 39.32 -import java.lang.invoke.MethodType; 39.33 -import jdk.nashorn.internal.codegen.types.Type; 39.34 -import jdk.nashorn.internal.runtime.options.Options; 39.35 - 39.36 -class SpecializedMethodChooser { 39.37 - /** Should specialized function and specialized constructors for the builtin be used if available? */ 39.38 - private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable"); 39.39 - 39.40 - static MethodHandle candidateWithLowestWeight(final MethodType descType, final MethodHandle initialCandidate, final MethodHandle[] specs) { 39.41 - if (DISABLE_SPECIALIZATION || specs == null) { 39.42 - return initialCandidate; 39.43 - } 39.44 - 39.45 - int minimumWeight = Integer.MAX_VALUE; 39.46 - MethodHandle candidate = initialCandidate; 39.47 - 39.48 - for (final MethodHandle spec : specs) { 39.49 - final MethodType specType = spec.type(); 39.50 - 39.51 - if (!typeCompatible(descType, specType)) { 39.52 - continue; 39.53 - } 39.54 - 39.55 - //return type is ok. we want a wider or equal one for our callsite. 39.56 - final int specWeight = weigh(specType); 39.57 - if (specWeight < minimumWeight) { 39.58 - candidate = spec; 39.59 - minimumWeight = specWeight; 39.60 - } 39.61 - } 39.62 - 39.63 - return candidate; 39.64 - } 39.65 - 39.66 - private static boolean typeCompatible(final MethodType desc, final MethodType spec) { 39.67 - //spec must fit in desc 39.68 - final Class<?>[] dparray = desc.parameterArray(); 39.69 - final Class<?>[] sparray = spec.parameterArray(); 39.70 - 39.71 - if (dparray.length != sparray.length) { 39.72 - return false; 39.73 - } 39.74 - 39.75 - for (int i = 0; i < dparray.length; i++) { 39.76 - final Type dp = Type.typeFor(dparray[i]); 39.77 - final Type sp = Type.typeFor(sparray[i]); 39.78 - 39.79 - if (dp.isBoolean()) { 39.80 - return false; //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution 39.81 - } 39.82 - 39.83 - //specialization arguments must be at least as wide as dp, if not wider 39.84 - if (Type.widest(dp, sp) != sp) { 39.85 - //e.g. specialization takes double and callsite says "object". reject. 39.86 - //but if specialization says double and callsite says "int" or "long" or "double", that's fine 39.87 - return false; 39.88 - } 39.89 - } 39.90 - 39.91 - return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic. 39.92 - } 39.93 - 39.94 - private static int weigh(final MethodType t) { 39.95 - int weight = Type.typeFor(t.returnType()).getWeight(); 39.96 - for (final Class<?> paramType : t.parameterArray()) { 39.97 - final int pweight = Type.typeFor(paramType).getWeight(); 39.98 - weight += pweight; 39.99 - } 39.100 - return weight; 39.101 - } 39.102 -}
40.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Tue Mar 12 18:12:42 2013 +0530 40.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Tue Mar 12 15:30:53 2013 +0100 40.3 @@ -39,7 +39,7 @@ 40.4 import jdk.nashorn.internal.runtime.ScriptObject; 40.5 40.6 /** 40.7 - * Utility class shared by {@link NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java 40.8 + * Utility class shared by {@code NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java 40.9 * types. 40.10 */ 40.11 public class JavaArgumentConverters {
41.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Tue Mar 12 18:12:42 2013 +0530 41.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Tue Mar 12 15:30:53 2013 +0100 41.3 @@ -40,8 +40,6 @@ 41.4 private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); 41.5 private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); 41.6 private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class); 41.7 - private static final MethodHandle IS_FUNCTION_MH = findOwnMH("isFunctionMH", boolean.class, Object.class, MethodHandle.class); 41.8 - private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, MethodHandle.class); 41.9 private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class); 41.10 41.11 // don't create me! 41.12 @@ -87,33 +85,6 @@ 41.13 return MH.insertArguments(IS_INSTANCEOF_2, 1, class1, class2); 41.14 } 41.15 41.16 - /** 41.17 - * Get the guard that checks if a {@link ScriptFunction} is equal to 41.18 - * a known ScriptFunction, using reference comparison 41.19 - * 41.20 - * @param function The ScriptFunction to check against. This will be bound to the guard method handle 41.21 - * 41.22 - * @return method handle for guard 41.23 - */ 41.24 - public static MethodHandle getFunctionGuard(final ScriptFunction function) { 41.25 - assert function.getInvokeHandle() != null; 41.26 - return MH.insertArguments(IS_FUNCTION_MH, 1, function.getInvokeHandle()); 41.27 - } 41.28 - 41.29 - /** 41.30 - * Get a guard that checks if a {@link ScriptFunction} is equal to 41.31 - * a known ScriptFunction using reference comparison, and whether the type of 41.32 - * the second argument (this-object) is not a JavaScript primitive type. 41.33 - * 41.34 - * @param function The ScriptFunction to check against. This will be bound to the guard method handle 41.35 - * 41.36 - * @return method handle for guard 41.37 - */ 41.38 - public static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) { 41.39 - assert function.getInvokeHandle() != null; 41.40 - return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.getInvokeHandle()); 41.41 - } 41.42 - 41.43 @SuppressWarnings("unused") 41.44 private static boolean isScriptObject(final Object self) { 41.45 return self instanceof ScriptObject; 41.46 @@ -130,16 +101,6 @@ 41.47 } 41.48 41.49 @SuppressWarnings("unused") 41.50 - private static boolean isFunctionMH(final Object self, final MethodHandle mh) { 41.51 - return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh; 41.52 - } 41.53 - 41.54 - @SuppressWarnings("unused") 41.55 - private static boolean isNonStrictFunction(final Object self, final Object arg, final MethodHandle mh) { 41.56 - return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh && arg instanceof ScriptObject; 41.57 - } 41.58 - 41.59 - @SuppressWarnings("unused") 41.60 private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) { 41.61 return class1.isInstance(self) || class2.isInstance(self); 41.62 }
42.1 --- a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Tue Mar 12 18:12:42 2013 +0530 42.2 +++ b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Tue Mar 12 15:30:53 2013 +0100 42.3 @@ -278,7 +278,7 @@ 42.4 this.valueNextArg = Boolean.parseBoolean(arg); 42.5 break; 42.6 default: 42.7 - throw new IllegalArgumentException(); 42.8 + throw new IllegalArgumentException(keyToken); 42.9 } 42.10 } 42.11
43.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Tue Mar 12 18:12:42 2013 +0530 43.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Tue Mar 12 15:30:53 2013 +0100 43.3 @@ -165,6 +165,12 @@ 43.4 desc="Generate local variable table in .class files." \ 43.5 } 43.6 43.7 +nashorn.option.lazy.compilation = { \ 43.8 + name="--lazy-compilation", \ 43.9 + is_undocumented=true, \ 43.10 + desc="EXPERIMENTAL: Use lazy code generation strategies - do not compile the entire script at once." \ 43.11 +} 43.12 + 43.13 nashorn.option.loader.per.compile = { \ 43.14 name="--loader-per-compile", \ 43.15 is_undocumented=true, \
44.1 --- a/test/script/currently-failing/JDK-8006529.js Tue Mar 12 18:12:42 2013 +0530 44.2 +++ b/test/script/currently-failing/JDK-8006529.js Tue Mar 12 15:30:53 2013 +0100 44.3 @@ -39,12 +39,13 @@ 44.4 * and FunctionNode because of package-access check and so reflective calls. 44.5 */ 44.6 44.7 -var Parser = Java.type("jdk.nashorn.internal.parser.Parser") 44.8 -var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") 44.9 -var Context = Java.type("jdk.nashorn.internal.runtime.Context") 44.10 +var Parser = Java.type("jdk.nashorn.internal.parser.Parser") 44.11 +var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") 44.12 +var Context = Java.type("jdk.nashorn.internal.runtime.Context") 44.13 var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment") 44.14 -var Source = Java.type("jdk.nashorn.internal.runtime.Source") 44.15 -var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") 44.16 +var Source = Java.type("jdk.nashorn.internal.runtime.Source") 44.17 +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") 44.18 +var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager"); 44.19 44.20 // Compiler class methods and fields 44.21 var parseMethod = Parser.class.getMethod("parse"); 44.22 @@ -90,7 +91,7 @@ 44.23 // representing it. 44.24 function compile(source) { 44.25 var source = new Source("<no name>", source); 44.26 - var parser = new Parser(Context.getContext().getEnv(), source, null); 44.27 + var parser = new Parser(Context.getContext().getEnv(), source, new ThrowErrorManager()); 44.28 var func = parseMethod.invoke(parser); 44.29 var compiler = new Compiler(Context.getContext().getEnv(), func); 44.30
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 45.2 +++ b/test/script/currently-failing/clone_ir.js Tue Mar 12 15:30:53 2013 +0100 45.3 @@ -0,0 +1,100 @@ 45.4 +/* 45.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 45.7 + * 45.8 + * This code is free software; you can redistribute it and/or modify it 45.9 + * under the terms of the GNU General Public License version 2 only, as 45.10 + * published by the Free Software Foundation. 45.11 + * 45.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 45.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 45.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 45.15 + * version 2 for more details (a copy is included in the LICENSE file that 45.16 + * accompanied this code). 45.17 + * 45.18 + * You should have received a copy of the GNU General Public License version 45.19 + * 2 along with this work; if not, write to the Free Software Foundation, 45.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 45.21 + * 45.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 45.23 + * or visit www.oracle.com if you need additional information or have any 45.24 + * questions. 45.25 + */ 45.26 + 45.27 +/** 45.28 + * clone_ir : Check that functionNode.clone copies all nodes and that they 45.29 + * are not the same references 45.30 + * 45.31 + * @test 45.32 + * @run 45.33 + */ 45.34 + 45.35 +var js1 = "var tuple = { func : function f(x) { if (x) { print('true'); { print('block_under-true'); } } else { print('false'); } } }"; 45.36 + 45.37 +var Parser = Java.type("jdk.nashorn.internal.parser.Parser"); 45.38 +var ASTWriter = Java.type("jdk.nashorn.internal.ir.debug.ASTWriter"); 45.39 +var Context = Java.type("jdk.nashorn.internal.runtime.Context"); 45.40 +var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment"); 45.41 +var Source = Java.type("jdk.nashorn.internal.runtime.Source"); 45.42 +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode"); 45.43 +var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager"); 45.44 +var System = Java.type("java.lang.System"); 45.45 + 45.46 +var toArrayMethod = ASTWriter.class.getMethod("toArray"); 45.47 +var parseMethod = Parser.class.getMethod("parse"); 45.48 + 45.49 +function toString(obj) { 45.50 + var output = "{ "; 45.51 + for (property in obj) { 45.52 + output += property + ': ' + obj[property]+'; '; 45.53 + } 45.54 + return output + '}' 45.55 +} 45.56 + 45.57 +function flatten(func) { 45.58 + var writer = new ASTWriter(func); 45.59 + var funcList = toArrayMethod.invoke(writer); 45.60 + 45.61 + var res = []; 45.62 + for each (x in funcList) { 45.63 + res.push({ name: x.getClass().getName(), id: System.identityHashCode(x) }); 45.64 + } 45.65 + return res; 45.66 +} 45.67 + 45.68 +function check(contents) { 45.69 + return check_src(new Source("<no name>", contents)); 45.70 +} 45.71 + 45.72 +function check_src(src) { 45.73 + var parser = new Parser(Context.getContext().getEnv(), src, new ThrowErrorManager()); 45.74 + 45.75 + var func = parseMethod.invoke(parser); 45.76 + print(func); 45.77 + var func2 = func.clone(); 45.78 + 45.79 + var f1 = flatten(func); 45.80 + var f2 = flatten(func2); 45.81 + 45.82 + print(f1.map(toString)); 45.83 + print(f2.map(toString)); 45.84 + 45.85 + if (f1.length != f2.length) { 45.86 + print("length difference between original and clone " + f1.length + " != " + f2.length); 45.87 + return false; 45.88 + } 45.89 + 45.90 + for (var i = 0; i < f1.length; i++) { 45.91 + if (f1[i].name !== f2[i].name) { 45.92 + print("name conflict at " + i + " " + f1[i].name + " != " + f2[i].name); 45.93 + return false; 45.94 + } else if (f1[i].id === f2[i].id) { 45.95 + print("id problem at " + i + " " + toString(f1[i]) + " was not deep copied to " + toString(f2[i]) + " became " + f1[i].id + " != " + f2[i].id); 45.96 + return false; 45.97 + } 45.98 + } 45.99 + 45.100 + return true; 45.101 +} 45.102 + 45.103 +print(check(js1));