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.

Tue, 12 Mar 2013 15:30:53 +0100

author
lagergren
date
Tue, 12 Mar 2013 15:30:53 +0100
changeset 137
e15806b9d716
parent 136
c54e218333be
child 138
60684aeba89c

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

src/jdk/nashorn/internal/codegen/Attr.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/BranchOptimizer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompilationPhase.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompileUnit.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FinalizeTypes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FoldConstants.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FunctionSignature.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Lower.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Splitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/Type.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Block.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ObjectNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/UnaryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/annotations/ChildNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/annotations/ParentNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/annotations/Reference.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/ASTWriter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeArray.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeDebug.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeError.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/JSONParser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/AccessorProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CodeInstaller.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CompiledFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CompiledFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ECMAException.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptEnvironment.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/NashornGuards.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/options/OptionTemplate.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Options.properties file | annotate | diff | comparison | revisions
test/script/currently-failing/JDK-8006529.js file | annotate | diff | comparison | revisions
test/script/currently-failing/clone_ir.js file | annotate | diff | comparison | revisions
     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));

mercurial