diff options
Diffstat (limited to 'src/jdk/nashorn/internal/codegen/ClassEmitter.java')
-rw-r--r-- | src/jdk/nashorn/internal/codegen/ClassEmitter.java | 196 |
1 files changed, 144 insertions, 52 deletions
diff --git a/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/src/jdk/nashorn/internal/codegen/ClassEmitter.java index 09c6a065..80bb61dd 100644 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -49,25 +49,27 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; import static jdk.nashorn.internal.codegen.CompilerConstants.className; import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; -import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; +import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; -import java.util.Arrays; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Set; - -import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.ir.SplitNode; +import jdk.nashorn.internal.ir.debug.NashornClassReader; +import jdk.nashorn.internal.ir.debug.NashornTextifier; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptEnvironment; +import jdk.nashorn.internal.runtime.RewriteException; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Source; @@ -106,6 +108,8 @@ import jdk.nashorn.internal.runtime.Source; * @see Compiler */ public class ClassEmitter implements Emitter { + /** Default flags for class generation - public class */ + private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC); /** Sanity check flag - have we started on a class? */ private boolean classStarted; @@ -123,10 +127,7 @@ public class ClassEmitter implements Emitter { protected final ClassWriter cw; /** The script environment */ - protected final ScriptEnvironment env; - - /** Default flags for class generation - oublic class */ - private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC); + protected final Context context; /** Compile unit class name. */ private String unitClassName; @@ -134,6 +135,16 @@ public class ClassEmitter implements Emitter { /** Set of constants access methods required. */ private Set<Class<?>> constantMethodNeeded; + private int methodCount; + + private int initCount; + + private int clinitCount; + + private int fieldCount; + + private final Set<String> methodNames; + /** * Constructor - only used internally in this class as it breaks * abstraction towards ASM or other code generator below @@ -141,12 +152,19 @@ public class ClassEmitter implements Emitter { * @param env script environment * @param cw ASM classwriter */ - private ClassEmitter(final ScriptEnvironment env, final ClassWriter cw) { - assert env != null; - - this.env = env; + private ClassEmitter(final Context context, final ClassWriter cw) { + this.context = context; this.cw = cw; this.methodsStarted = new HashSet<>(); + this.methodNames = new HashSet<>(); + } + + /** + * Return the method names encountered + * @return method names + */ + public Set<String> getMethodNames() { + return Collections.unmodifiableSet(methodNames); } /** @@ -157,8 +175,8 @@ public class ClassEmitter implements Emitter { * @param superClassName super class name for class * @param interfaceNames names of interfaces implemented by this class, or null if none */ - ClassEmitter(final ScriptEnvironment env, final String className, final String superClassName, final String... interfaceNames) { - this(env, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); + ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { + this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames); } @@ -170,8 +188,8 @@ public class ClassEmitter implements Emitter { * @param unitClassName Compile unit class name. * @param strictMode Should we generate this method in strict mode */ - ClassEmitter(final ScriptEnvironment env, final String sourceName, final String unitClassName, final boolean strictMode) { - this(env, + ClassEmitter(final Context context, final String sourceName, final String unitClassName, final boolean strictMode) { + this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { private static final String OBJECT_CLASS = "java/lang/Object"; @@ -197,6 +215,10 @@ public class ClassEmitter implements Emitter { defineCommonStatics(strictMode); } + Context getContext() { + return context; + } + /** * Returns the name of the compile unit class name. * @return the name of the compile unit class name. @@ -206,6 +228,38 @@ public class ClassEmitter implements Emitter { } /** + * Get the method count, including init and clinit methods + * @return method count + */ + public int getMethodCount() { + return methodCount; + } + + /** + * Get the clinit count + * @return clinit count + */ + public int getClinitCount() { + return clinitCount; + } + + /** + * Get the init count + * @return init count + */ + public int getInitCount() { + return initCount; + } + + /** + * Get the field count + * @return field count + */ + public int getFieldCount() { + return fieldCount; + } + + /** * Convert a binary name to a package/class name. * * @param name Binary name. @@ -274,51 +328,51 @@ public class ClassEmitter implements Emitter { } // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. - for (final Class<?> cls : constantMethodNeeded) { - if (cls.isArray()) { - defineGetArrayMethod(cls); + for (final Class<?> clazz : constantMethodNeeded) { + if (clazz.isArray()) { + defineGetArrayMethod(clazz); } } } /** - * Constructs a primitive specific method for getting the ith entry from the constants table and cast. - * @param cls Array class. + * Constructs a primitive specific method for getting the ith entry from the constants table as an array. + * @param clazz Array class. */ - private void defineGetArrayMethod(final Class<?> cls) { + private void defineGetArrayMethod(final Class<?> clazz) { assert unitClassName != null; - final String methodName = getArrayMethodName(cls); - final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); + final String methodName = getArrayMethodName(clazz); + final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class); getArrayMethod.begin(); getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) .load(Type.INT, 0) .arrayload() - .checkcast(cls) - .dup() - .arraylength() - .invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class)) + .checkcast(clazz) + .invoke(virtualCallNoLookup(clazz, "clone", Object.class)) + .checkcast(clazz) ._return(); getArrayMethod.end(); } + /** * Generate the name of a get array from constant pool method. - * @param cls Name of array class. + * @param clazz Name of array class. * @return Method name. */ - static String getArrayMethodName(final Class<?> cls) { - assert cls.isArray(); - return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); + static String getArrayMethodName(final Class<?> clazz) { + assert clazz.isArray(); + return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); } /** * Ensure a get constant method is issued for the class. - * @param cls Class of constant. + * @param clazz Class of constant. */ - void needGetConstantMethod(final Class<?> cls) { - constantMethodNeeded.add(cls); + void needGetConstantMethod(final Class<?> clazz) { + constantMethodNeeded.add(clazz); } /** @@ -356,9 +410,16 @@ public class ClassEmitter implements Emitter { */ @Override public void end() { - assert classStarted; + assert classStarted : "class not started for " + unitClassName; if (unitClassName != null) { + final MethodEmitter initMethod = init(EnumSet.of(Flag.PRIVATE)); + initMethod.begin(); + initMethod.load(Type.OBJECT, 0); + initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class); + initMethod.returnVoid(); + initMethod.end(); + defineCommonUtilities(); } @@ -376,16 +437,19 @@ public class ClassEmitter implements Emitter { static String disassemble(final byte[] bytecode) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (final PrintWriter pw = new PrintWriter(baos)) { - new ClassReader(bytecode).accept(new TraceClassVisitor(pw), 0); + final NashornClassReader cr = new NashornClassReader(bytecode); + final Context ctx = AccessController.doPrivileged(new PrivilegedAction<Context>() { + @Override + public Context run() { + return Context.getContext(); + } + }); + final TraceClassVisitor tcv = new TraceClassVisitor(null, new NashornTextifier(ctx.getEnv(), cr), pw); + cr.accept(tcv, 0); } - return new String(baos.toByteArray()); - } - /** - * @return env used for class emission - */ - ScriptEnvironment getEnv() { - return env; + final String str = new String(baos.toByteArray()); + return str; } /** @@ -412,10 +476,6 @@ public class ClassEmitter implements Emitter { methodsStarted.remove(method); } - SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { - return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode); - } - /** * Add a new method to the class - defaults to public method * @@ -440,6 +500,8 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving this method */ MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { + methodCount++; + methodNames.add(methodName); return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes)); } @@ -465,6 +527,8 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving this method */ MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final String descriptor) { + methodCount++; + methodNames.add(methodName); return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null)); } @@ -475,10 +539,13 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving this method */ MethodEmitter method(final FunctionNode functionNode) { + methodCount++; + methodNames.add(functionNode.getName()); + final FunctionSignature signature = new FunctionSignature(functionNode); final MethodVisitor mv = cw.visitMethod( ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), functionNode.getName(), - new FunctionSignature(functionNode).toString(), + signature.toString(), null, null); @@ -486,11 +553,32 @@ public class ClassEmitter implements Emitter { } /** + * Add a new method to the class, representing a rest-of version of the function node + * + * @param functionNode the function node to generate a method for + * @return method emitter to use for weaving this method + */ + MethodEmitter restOfMethod(final FunctionNode functionNode) { + methodCount++; + methodNames.add(functionNode.getName()); + final MethodVisitor mv = cw.visitMethod( + ACC_PUBLIC | ACC_STATIC, + functionNode.getName(), + Type.getMethodDescriptor(functionNode.getReturnType().getTypeClass(), RewriteException.class), + null, + null); + + return new MethodEmitter(this, mv, functionNode); + } + + + /** * Start generating the <clinit> method in the class * * @return method emitter to use for weaving <clinit> */ MethodEmitter clinit() { + clinitCount++; return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class); } @@ -500,6 +588,7 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving <init>()V */ MethodEmitter init() { + initCount++; return method(INIT.symbolName(), void.class); } @@ -510,6 +599,7 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving <init>()V */ MethodEmitter init(final Class<?>... ptypes) { + initCount++; return method(INIT.symbolName(), void.class, ptypes); } @@ -522,6 +612,7 @@ public class ClassEmitter implements Emitter { * @return method emitter to use for weaving <init>(...)V */ MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) { + initCount++; return method(flags, INIT.symbolName(), void.class, ptypes); } @@ -536,6 +627,7 @@ public class ClassEmitter implements Emitter { * @see ClassEmitter.Flag */ final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType, final Object value) { + fieldCount++; cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd(); } @@ -636,7 +728,7 @@ public class ClassEmitter implements Emitter { } } - private MethodVisitor methodVisitor(EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { + private MethodVisitor methodVisitor(final EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null); } |