--- old/make/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java 2020-04-15 18:45:04.000000000 +0530 +++ /dev/null 2020-04-15 18:45:04.000000000 +0530 @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.tools.nasgen; - -import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; -import static jdk.internal.org.objectweb.asm.Opcodes.DUP; -import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; -import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; -import static jdk.internal.org.objectweb.asm.Opcodes.NEW; -import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; -import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.$CLINIT$; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.FieldVisitor; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; -import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; - -/** - * This class instruments the java class annotated with @ScriptClass. - * - * Changes done are: - * - * 1) remove all jdk.nashorn.internal.objects.annotations.* annotations. - * 2) static final @Property fields stay here. Other @Property fields moved to - * respective classes depending on 'where' value of annotation. - * 2) add "Map" type static field named "$map". - * 3) add static initializer block to initialize map. - */ -public class ScriptClassInstrumentor extends ClassVisitor { - private final ScriptClassInfo scriptClassInfo; - private final int memberCount; - private boolean staticInitFound; - - ScriptClassInstrumentor(final ClassVisitor visitor, final ScriptClassInfo sci) { - super(Main.ASM_VERSION, visitor); - if (sci == null) { - throw new IllegalArgumentException("Null ScriptClassInfo, is the class annotated?"); - } - this.scriptClassInfo = sci; - this.memberCount = scriptClassInfo.getInstancePropertyCount(); - } - - @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (ScriptClassInfo.annotations.containsKey(desc)) { - // ignore @ScriptClass - return null; - } - - return super.visitAnnotation(desc, visible); - } - - @Override - public FieldVisitor visitField(final int fieldAccess, final String fieldName, - final String fieldDesc, final String signature, final Object value) { - final MemberInfo memInfo = scriptClassInfo.find(fieldName, fieldDesc, fieldAccess); - if (memInfo != null && memInfo.getKind() == Kind.PROPERTY && - memInfo.getWhere() != Where.INSTANCE && !memInfo.isStaticFinal()) { - // non-instance @Property fields - these have to go elsewhere unless 'static final' - return null; - } - - final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, - signature, value); - return new FieldVisitor(Main.ASM_VERSION, delegateFV) { - @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (ScriptClassInfo.annotations.containsKey(desc)) { - // ignore script field annotations - return null; - } - - return fv.visitAnnotation(desc, visible); - } - - @Override - public void visitAttribute(final Attribute attr) { - fv.visitAttribute(attr); - } - - @Override - public void visitEnd() { - fv.visitEnd(); - } - }; - } - - @Override - public MethodVisitor visitMethod(final int methodAccess, final String methodName, - final String methodDesc, final String signature, final String[] exceptions) { - - final boolean isConstructor = INIT.equals(methodName); - final boolean isStaticInit = CLINIT.equals(methodName); - - if (isStaticInit) { - staticInitFound = true; - } - - final MethodGenerator delegateMV = new MethodGenerator(super.visitMethod(methodAccess, methodName, methodDesc, - signature, exceptions), methodAccess, methodName, methodDesc); - - return new MethodVisitor(Main.ASM_VERSION, delegateMV) { - @Override - public void visitInsn(final int opcode) { - // call $clinit$ just before return from - if (isStaticInit && opcode == RETURN) { - super.visitMethodInsn(INVOKESTATIC, scriptClassInfo.getJavaName(), - $CLINIT$, DEFAULT_INIT_DESC, false); - } - super.visitInsn(opcode); - } - - @Override - public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { - if (isConstructor && opcode == INVOKESPECIAL && - INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) { - super.visitMethodInsn(opcode, owner, name, desc, false); - - if (memberCount > 0) { - // initialize @Property fields if needed - for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { - if (memInfo.isInstanceProperty() && !memInfo.getInitClass().isEmpty()) { - final String clazz = memInfo.getInitClass(); - super.visitVarInsn(ALOAD, 0); - super.visitTypeInsn(NEW, clazz); - super.visitInsn(DUP); - super.visitMethodInsn(INVOKESPECIAL, clazz, - INIT, DEFAULT_INIT_DESC, false); - super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), - memInfo.getJavaName(), memInfo.getJavaDesc()); - } - - if (memInfo.isInstanceFunction()) { - super.visitVarInsn(ALOAD, 0); - ClassGenerator.newFunction(delegateMV, scriptClassInfo.getName(), scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); - super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), - memInfo.getJavaName(), OBJECT_DESC); - } - } - } - } else { - super.visitMethodInsn(opcode, owner, name, desc, itf); - } - } - - @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - if (ScriptClassInfo.annotations.containsKey(desc)) { - // ignore script method annotations - return null; - } - return super.visitAnnotation(desc, visible); - } - }; - } - - @Override - public void visitEnd() { - emitFields(); - emitStaticInitializer(); - emitGettersSetters(); - super.visitEnd(); - } - - private void emitFields() { - // introduce "Function" type instance fields for each - // instance @Function in script class info - final String className = scriptClassInfo.getJavaName(); - for (MemberInfo memInfo : scriptClassInfo.getMembers()) { - if (memInfo.isInstanceFunction()) { - ClassGenerator.addFunctionField(cv, memInfo.getJavaName()); - memInfo = (MemberInfo)memInfo.clone(); - memInfo.setJavaDesc(OBJECT_DESC); - ClassGenerator.addGetter(cv, className, memInfo); - ClassGenerator.addSetter(cv, className, memInfo); - } - } - // omit addMapField() since instance classes already define a static PropertyMap field - } - - void emitGettersSetters() { - if (memberCount > 0) { - for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { - final String className = scriptClassInfo.getJavaName(); - if (memInfo.isInstanceProperty()) { - ClassGenerator.addGetter(cv, className, memInfo); - if (! memInfo.isFinal()) { - ClassGenerator.addSetter(cv, className, memInfo); - } - } - } - } - } - - private void emitStaticInitializer() { - final String className = scriptClassInfo.getJavaName(); - if (! staticInitFound) { - // no user written and so create one - final MethodVisitor mv = ClassGenerator.makeStaticInitializer(this); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(Short.MAX_VALUE, 0); - mv.visitEnd(); - } - // Now generate $clinit$ - final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$); - ClassGenerator.emitStaticInitPrefix(mi, className, memberCount); - if (memberCount > 0) { - for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { - if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) { - ClassGenerator.linkerAddGetterSetter(mi, className, memInfo); - } else if (memInfo.isInstanceGetter()) { - final MemberInfo setter = scriptClassInfo.findSetter(memInfo); - ClassGenerator.linkerAddGetterSetter(mi, className, memInfo, setter); - } - } - } - ClassGenerator.emitStaticInitSuffix(mi, className); - } - - /** - * External entry point for ScriptClassInfoCollector if run from the command line - * - * @param args arguments - one argument is needed, the name of the class to collect info from - * - * @throws IOException if there are problems reading class - */ - public static void main(final String[] args) throws IOException { - if (args.length != 1) { - System.err.println("Usage: " + ScriptClassInstrumentor.class.getName() + " "); - System.exit(1); - } - - final String fileName = args[0].replace('.', '/') + ".class"; - final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(fileName); - if (sci == null) { - System.err.println("No @ScriptClass in " + fileName); - System.exit(2); - throw new AssertionError(); //guard against warning that sci is null below - } - - try { - sci.verify(); - } catch (final Exception e) { - System.err.println(e.getMessage()); - System.exit(3); - } - - final ClassWriter writer = ClassGenerator.makeClassWriter(); - try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { - final ClassReader reader = new ClassReader(bis); - final CheckClassAdapter checker = new CheckClassAdapter(writer); - final ScriptClassInstrumentor instr = new ScriptClassInstrumentor(checker, sci); - reader.accept(instr, 0); - } - - try (FileOutputStream fos = new FileOutputStream(fileName)) { - fos.write(writer.toByteArray()); - } - } -}