8068784: Halve the function object creation code size
authorattila
Mon, 12 Jan 2015 14:32:32 +0100
changeset 28320 bbf9cfde97f6
parent 28319 95bed8b1847f
child 28321 167aecd0161e
8068784: Halve the function object creation code size Reviewed-by: hannesw, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Jan 12 11:29:42 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Jan 12 14:32:32 2015 +0100
@@ -38,7 +38,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
-import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
@@ -186,9 +185,6 @@
 
     private static final String GLOBAL_OBJECT = Type.getInternalName(Global.class);
 
-    private static final String SCRIPTFUNCTION_IMPL_NAME = Type.getInternalName(ScriptFunctionImpl.class);
-    private static final Type   SCRIPTFUNCTION_IMPL_TYPE   = Type.typeFor(ScriptFunction.class);
-
     private static final Call CREATE_REWRITE_EXCEPTION = CompilerConstants.staticCallNoLookup(RewriteException.class,
             "create", RewriteException.class, UnwarrantedOptimismException.class, Object[].class, String[].class);
     private static final Call CREATE_REWRITE_EXCEPTION_REST_OF = CompilerConstants.staticCallNoLookup(RewriteException.class,
@@ -201,6 +197,11 @@
     private static final Call ENSURE_NUMBER = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
             "ensureNumber", double.class, Object.class, int.class);
 
+    private static final Call CREATE_FUNCTION_OBJECT = CompilerConstants.staticCallNoLookup(ScriptFunctionImpl.class,
+            "create", ScriptFunction.class, Object[].class, int.class, ScriptObject.class);
+    private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunctionImpl.class,
+            "create", ScriptFunction.class, Object[].class, int.class);
+
     private static final Class<?> ITERATOR_CLASS = Iterator.class;
     static {
         assert ITERATOR_CLASS == CompilerConstants.ITERATOR_PREFIX.type();
@@ -2242,7 +2243,6 @@
         } else {
             methodEmitter.loadConstants().load(index).arrayload();
             if (object instanceof ArrayData) {
-                // avoid cast to non-public ArrayData subclass
                 methodEmitter.checkcast(ArrayData.class);
                 methodEmitter.invoke(virtualCallNoLookup(ArrayData.class, "copy", ArrayData.class));
             } else if (cls != Object.class) {
@@ -2251,6 +2251,10 @@
         }
     }
 
+    private void loadConstantsAndIndex(final Object object, final MethodEmitter methodEmitter) {
+        methodEmitter.loadConstants().load(compiler.getConstantData().add(object));
+    }
+
     // literal values
     private void loadLiteral(final LiteralNode<?> node, final TypeBounds resultBounds) {
         final Object value = node.getValue();
@@ -4323,15 +4327,13 @@
         final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(functionNode.getId());
 
         if (functionNode.isProgram() && !compiler.isOnDemandCompilation()) {
-            final CompileUnit fnUnit = functionNode.getCompileUnit();
-            final MethodEmitter createFunction = fnUnit.getClassEmitter().method(
+            final MethodEmitter createFunction = functionNode.getCompileUnit().getClassEmitter().method(
                     EnumSet.of(Flag.PUBLIC, Flag.STATIC), CREATE_PROGRAM_FUNCTION.symbolName(),
                     ScriptFunction.class, ScriptObject.class);
             createFunction.begin();
-            createFunction._new(SCRIPTFUNCTION_IMPL_NAME, SCRIPTFUNCTION_IMPL_TYPE).dup();
-            loadConstant(data, fnUnit, createFunction);
+            loadConstantsAndIndex(data, createFunction);
             createFunction.load(SCOPE_TYPE, 0);
-            createFunction.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class));
+            createFunction.invoke(CREATE_FUNCTION_OBJECT);
             createFunction._return();
             createFunction.end();
         }
@@ -4346,15 +4348,14 @@
             return;
         }
 
-        method._new(SCRIPTFUNCTION_IMPL_NAME, SCRIPTFUNCTION_IMPL_TYPE).dup();
-        loadConstant(data);
+        loadConstantsAndIndex(data, method);
 
         if (functionNode.needsParentScope()) {
             method.loadCompilerConstant(SCOPE);
+            method.invoke(CREATE_FUNCTION_OBJECT);
         } else {
-            method.loadNull();
-        }
-        method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class));
+            method.invoke(CREATE_FUNCTION_OBJECT_NO_SCOPE);
+        }
     }
 
     // calls on Global class.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Mon Jan 12 11:29:42 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Mon Jan 12 14:32:32 2015 +0100
@@ -118,13 +118,26 @@
     }
 
     /**
-     * Constructor called by (compiler) generated code for {@link ScriptObject}s.
+     * Factory method called by compiler generated code for functions that need parent scope.
      *
-     * @param data static function data
-     * @param scope scope object
+     * @param constants the generated class' constant array
+     * @param index the index of the {@code RecompilableScriptFunctionData} object in the constants array.
+     * @param scope the parent scope object
+     * @return a newly created function object
      */
-    public ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope) {
-        this(data, scope, Global.instance());
+    public static ScriptFunction create(final Object[] constants, final int index, final ScriptObject scope) {
+        return new ScriptFunctionImpl((RecompilableScriptFunctionData)constants[index], scope, Global.instance());
+    }
+
+    /**
+     * Factory method called by compiler generated code for functions that don't need parent scope.
+     *
+     * @param constants the generated class' constant array
+     * @param index the index of the {@code RecompilableScriptFunctionData} object in the constants array.
+     * @return a newly created function object
+     */
+    public static ScriptFunction create(final Object[] constants, final int index) {
+        return create(constants, index, null);
     }
 
     /**