ClassGenerator.java revision 379:80c66d3fd872
1145519Sdarrenr/* 2145510Sdarrenr * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3145510Sdarrenr * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4255332Scy * 5145510Sdarrenr * This code is free software; you can redistribute it and/or modify it 6145510Sdarrenr * under the terms of the GNU General Public License version 2 only, as 7145510Sdarrenr * published by the Free Software Foundation. Oracle designates this 8255332Scy * particular file as subject to the "Classpath" exception as provided 9145510Sdarrenr * by Oracle in the LICENSE file that accompanied this code. 10145510Sdarrenr * 11145510Sdarrenr * This code is distributed in the hope that it will be useful, but WITHOUT 12255332Scy * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13145510Sdarrenr * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14145510Sdarrenr * version 2 for more details (a copy is included in the LICENSE file that 15145510Sdarrenr * accompanied this code). 16145510Sdarrenr * 17145510Sdarrenr * You should have received a copy of the GNU General Public License version 18145510Sdarrenr * 2 along with this work; if not, write to the Free Software Foundation, 19145510Sdarrenr * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20145510Sdarrenr * 21145510Sdarrenr * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22145510Sdarrenr * or visit www.oracle.com if you need additional information or have any 23145510Sdarrenr * questions. 24145510Sdarrenr */ 25255332Scy 26145510Sdarrenrpackage jdk.nashorn.internal.tools.nasgen; 27145510Sdarrenr 28145547Sdarrenrimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 29145547Sdarrenrimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 30145510Sdarrenrimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 31145510Sdarrenrimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 32145510Sdarrenrimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; 33145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; 34145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; 35145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.GETTER_PREFIX; 36145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME; 37145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC; 38145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; 39255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY; 40255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC; 41255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE; 42145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; 43145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; 44145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP; 45145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC; 46145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; 47145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; 48255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION; 49255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC; 50145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC; 51255332Scyimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE; 52145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; 53145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; 54145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; 55145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX; 56145510Sdarrenrimport static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT; 57145510Sdarrenr 58145510Sdarrenrimport java.io.BufferedInputStream; 59255332Scyimport java.io.FileInputStream; 60145510Sdarrenrimport java.io.IOException; 61145510Sdarrenrimport java.util.List; 62145510Sdarrenrimport jdk.internal.org.objectweb.asm.ClassReader; 63145510Sdarrenrimport jdk.internal.org.objectweb.asm.ClassVisitor; 64255332Scyimport jdk.internal.org.objectweb.asm.ClassWriter; 65145510Sdarrenrimport jdk.internal.org.objectweb.asm.FieldVisitor; 66145510Sdarrenrimport jdk.internal.org.objectweb.asm.Handle; 67145510Sdarrenrimport jdk.internal.org.objectweb.asm.MethodVisitor; 68145510Sdarrenrimport jdk.internal.org.objectweb.asm.Type; 69145510Sdarrenrimport jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; 70145510Sdarrenr 71145510Sdarrenr/** 72145510Sdarrenr * Base class for class generator classes. 73255332Scy * 74145510Sdarrenr */ 75161357Sguidopublic class ClassGenerator { 76145510Sdarrenr /** ASM class writer used to output bytecode for this class */ 77145510Sdarrenr protected final ClassWriter cw; 78145510Sdarrenr 79161357Sguido /** 80145510Sdarrenr * Constructor 81161357Sguido */ 82161357Sguido protected ClassGenerator() { 83161357Sguido this.cw = makeClassWriter(); 84145510Sdarrenr } 85145510Sdarrenr 86145510Sdarrenr MethodGenerator makeStaticInitializer() { 87145510Sdarrenr return makeStaticInitializer(cw); 88255332Scy } 89145510Sdarrenr 90145510Sdarrenr MethodGenerator makeConstructor() { 91145510Sdarrenr return makeConstructor(cw); 92145510Sdarrenr } 93145510Sdarrenr 94145510Sdarrenr MethodGenerator makeMethod(final int access, final String name, final String desc) { 95145510Sdarrenr return makeMethod(cw, access, name, desc); 96145510Sdarrenr } 97145510Sdarrenr 98145510Sdarrenr void addMapField() { 99145510Sdarrenr addMapField(cw); 100145510Sdarrenr } 101145510Sdarrenr 102145510Sdarrenr void addField(final String name, final String desc) { 103145510Sdarrenr addField(cw, name, desc); 104145510Sdarrenr } 105145510Sdarrenr 106145510Sdarrenr void addFunctionField(final String name) { 107145510Sdarrenr addFunctionField(cw, name); 108145510Sdarrenr } 109145510Sdarrenr 110145510Sdarrenr void addGetter(final String owner, final MemberInfo memInfo) { 111145510Sdarrenr addGetter(cw, owner, memInfo); 112145510Sdarrenr } 113145510Sdarrenr 114145510Sdarrenr void addSetter(final String owner, final MemberInfo memInfo) { 115145510Sdarrenr addSetter(cw, owner, memInfo); 116255332Scy } 117255332Scy 118255332Scy void emitGetClassName(final String name) { 119255332Scy final MethodGenerator mi = makeMethod(ACC_PUBLIC, GET_CLASS_NAME, GET_CLASS_NAME_DESC); 120145510Sdarrenr mi.loadLiteral(name); 121145510Sdarrenr mi.returnValue(); 122145510Sdarrenr mi.computeMaxs(); 123170268Sdarrenr mi.visitEnd(); 124255332Scy } 125255332Scy 126145510Sdarrenr static ClassWriter makeClassWriter() { 127255332Scy return new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { 128255332Scy @Override 129255332Scy protected String getCommonSuperClass(final String type1, final String type2) { 130145510Sdarrenr try { 131145510Sdarrenr return super.getCommonSuperClass(type1, type2); 132145510Sdarrenr } catch (final RuntimeException | LinkageError e) { 133145510Sdarrenr return StringConstants.OBJECT_TYPE; 134145510Sdarrenr } 135145510Sdarrenr } 136145510Sdarrenr }; 137145510Sdarrenr } 138145510Sdarrenr 139145510Sdarrenr static MethodGenerator makeStaticInitializer(final ClassVisitor cv) { 140153881Sguido return makeStaticInitializer(cv, CLINIT); 141145510Sdarrenr } 142145510Sdarrenr 143145510Sdarrenr static MethodGenerator makeStaticInitializer(final ClassVisitor cv, final String name) { 144170268Sdarrenr final int access = ACC_PUBLIC | ACC_STATIC; 145170268Sdarrenr final String desc = DEFAULT_INIT_DESC; 146255332Scy final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); 147255332Scy return new MethodGenerator(mv, access, name, desc); 148255332Scy } 149255332Scy 150255332Scy static MethodGenerator makeConstructor(final ClassVisitor cv) { 151255332Scy final int access = ACC_PUBLIC; 152255332Scy final String name = INIT; 153255332Scy final String desc = DEFAULT_INIT_DESC; 154255332Scy final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); 155255332Scy return new MethodGenerator(mv, access, name, desc); 156255332Scy } 157170268Sdarrenr 158145510Sdarrenr static MethodGenerator makeMethod(final ClassVisitor cv, final int access, final String name, final String desc) { 159153881Sguido final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); 160153881Sguido return new MethodGenerator(mv, access, name, desc); 161145510Sdarrenr } 162145510Sdarrenr 163145510Sdarrenr static void emitStaticInitPrefix(final MethodGenerator mi, final String className) { 164145510Sdarrenr mi.visitCode(); 165255332Scy mi.pushNull(); 166255332Scy mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); 167255332Scy mi.loadClass(className); 168255332Scy mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC); 169145510Sdarrenr // stack: PropertyMap 170145510Sdarrenr } 171145510Sdarrenr 172145510Sdarrenr static void emitStaticInitSuffix(final MethodGenerator mi, final String className) { 173145510Sdarrenr // stack: PropertyMap 174145510Sdarrenr mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); 175145510Sdarrenr mi.returnVoid(); 176145510Sdarrenr mi.computeMaxs(); 177145510Sdarrenr mi.visitEnd(); 178145510Sdarrenr } 179145510Sdarrenr 180145510Sdarrenr @SuppressWarnings("fallthrough") 181145510Sdarrenr private static Type memInfoType(final MemberInfo memInfo) { 182145510Sdarrenr switch (memInfo.getJavaDesc().charAt(0)) { 183255332Scy case 'I': return Type.INT_TYPE; 184145510Sdarrenr case 'J': return Type.LONG_TYPE; 185145510Sdarrenr case 'D': return Type.DOUBLE_TYPE; 186145510Sdarrenr default: assert false : memInfo.getJavaDesc(); 187145510Sdarrenr case 'L': return TYPE_OBJECT; 188145510Sdarrenr } 189145510Sdarrenr } 190145510Sdarrenr 191145510Sdarrenr private static String getterDesc(final MemberInfo memInfo) { 192145510Sdarrenr return Type.getMethodDescriptor(memInfoType(memInfo)); 193145510Sdarrenr } 194145510Sdarrenr 195145510Sdarrenr private static String setterDesc(final MemberInfo memInfo) { 196255332Scy return Type.getMethodDescriptor(Type.VOID_TYPE, memInfoType(memInfo)); 197255332Scy } 198255332Scy 199255332Scy static void addGetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { 200255332Scy final int access = ACC_PUBLIC; 201255332Scy final String name = GETTER_PREFIX + memInfo.getJavaName(); 202255332Scy final String desc = getterDesc(memInfo); 203145510Sdarrenr final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); 204145510Sdarrenr final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); 205145510Sdarrenr mi.visitCode(); 206145510Sdarrenr if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { 207145510Sdarrenr mi.getStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); 208145510Sdarrenr } else { 209145510Sdarrenr mi.loadLocal(0); 210145510Sdarrenr mi.getField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); 211145510Sdarrenr } 212145510Sdarrenr mi.returnValue(); 213145510Sdarrenr mi.computeMaxs(); 214145510Sdarrenr mi.visitEnd(); 215145510Sdarrenr } 216145510Sdarrenr 217145510Sdarrenr static void addSetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { 218145510Sdarrenr final int access = ACC_PUBLIC; 219145510Sdarrenr final String name = SETTER_PREFIX + memInfo.getJavaName(); 220145510Sdarrenr final String desc = setterDesc(memInfo); 221145510Sdarrenr final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); 222145510Sdarrenr final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); 223145510Sdarrenr mi.visitCode(); 224145510Sdarrenr if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { 225145510Sdarrenr mi.loadLocal(1); 226145510Sdarrenr mi.putStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); 227145510Sdarrenr } else { 228145510Sdarrenr mi.loadLocal(0); 229145510Sdarrenr mi.loadLocal(1); 230145510Sdarrenr mi.putField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); 231145510Sdarrenr } 232145510Sdarrenr mi.returnVoid(); 233145510Sdarrenr mi.computeMaxs(); 234145510Sdarrenr mi.visitEnd(); 235145510Sdarrenr } 236145510Sdarrenr 237145510Sdarrenr static void addMapField(final ClassVisitor cv) { 238145510Sdarrenr // add a MAP static field 239145510Sdarrenr final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC, 240145510Sdarrenr MAP_FIELD_NAME, MAP_DESC, null, null); 241145510Sdarrenr if (fv != null) { 242145510Sdarrenr fv.visitEnd(); 243145510Sdarrenr } 244145510Sdarrenr } 245145510Sdarrenr 246145510Sdarrenr static void addField(final ClassVisitor cv, final String name, final String desc) { 247145510Sdarrenr final FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, desc, null, null); 248145510Sdarrenr if (fv != null) { 249145510Sdarrenr fv.visitEnd(); 250145510Sdarrenr } 251145510Sdarrenr } 252145510Sdarrenr 253145510Sdarrenr static void addFunctionField(final ClassVisitor cv, final String name) { 254145510Sdarrenr addField(cv, name, OBJECT_DESC); 255145510Sdarrenr } 256145510Sdarrenr 257145510Sdarrenr static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) { 258145510Sdarrenr final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY); 259145510Sdarrenr 260145510Sdarrenr mi.loadLiteral(memInfo.getName()); 261145510Sdarrenr mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc())); 262145510Sdarrenr 263145510Sdarrenr assert specs != null; 264145510Sdarrenr if (!specs.isEmpty()) { 265145510Sdarrenr mi.memberInfoArray(className, specs); 266145510Sdarrenr mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC); 267145510Sdarrenr } else { 268145510Sdarrenr mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC); 269145510Sdarrenr } 270145510Sdarrenr 271145510Sdarrenr if (arityFound) { 272145510Sdarrenr mi.dup(); 273145510Sdarrenr mi.push(memInfo.getArity()); 274145510Sdarrenr mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC); 275145510Sdarrenr } 276172776Sdarrenr 277172776Sdarrenr } 278172776Sdarrenr 279145510Sdarrenr static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) { 280172776Sdarrenr final String propertyName = memInfo.getName(); 281172776Sdarrenr // stack: PropertyMap 282172776Sdarrenr mi.loadLiteral(propertyName); 283172776Sdarrenr // setup flags 284172776Sdarrenr mi.push(memInfo.getAttributes()); 285172776Sdarrenr // setup getter method handle 286172776Sdarrenr String javaName = GETTER_PREFIX + memInfo.getJavaName(); 287172776Sdarrenr mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, getterDesc(memInfo))); 288145510Sdarrenr // setup setter method handle 289145510Sdarrenr if (memInfo.isFinal()) { 290172776Sdarrenr mi.pushNull(); 291172776Sdarrenr } else { 292172776Sdarrenr javaName = SETTER_PREFIX + memInfo.getJavaName(); 293172776Sdarrenr mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo))); 294172776Sdarrenr } 295172776Sdarrenr mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); 296172776Sdarrenr // stack: PropertyMap 297172776Sdarrenr } 298172776Sdarrenr 299172776Sdarrenr static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) { 300145510Sdarrenr final String propertyName = getter.getName(); 301255332Scy // stack: PropertyMap 302145510Sdarrenr mi.loadLiteral(propertyName); 303153881Sguido // setup flags 304153881Sguido mi.push(getter.getAttributes()); 305153881Sguido // setup getter method handle 306153881Sguido mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, 307255332Scy getter.getJavaName(), getter.getJavaDesc())); 308153881Sguido // setup setter method handle 309255332Scy if (setter == null) { 310255332Scy mi.pushNull(); 311255332Scy } else { 312255332Scy mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, 313255332Scy setter.getJavaName(), setter.getJavaDesc())); 314255332Scy } 315255332Scy mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); 316153881Sguido // stack: PropertyMap 317145510Sdarrenr } 318145510Sdarrenr 319145510Sdarrenr static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException { 320145510Sdarrenr try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { 321145510Sdarrenr return getScriptClassInfo(new ClassReader(bis)); 322145510Sdarrenr } 323145510Sdarrenr } 324145510Sdarrenr 325145510Sdarrenr static ScriptClassInfo getScriptClassInfo(final byte[] classBuf) { 326145510Sdarrenr return getScriptClassInfo(new ClassReader(classBuf)); 327255332Scy } 328145510Sdarrenr 329145510Sdarrenr private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) { 330145510Sdarrenr final ScriptClassInfoCollector scic = new ScriptClassInfoCollector(); 331145510Sdarrenr reader.accept(scic, 0); 332145510Sdarrenr return scic.getScriptClassInfo(); 333145510Sdarrenr } 334145510Sdarrenr} 335145510Sdarrenr