ConstructorGenerator.java revision 1574:1597de0e19e3
14Srgrimes/* 24Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 34Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 44Srgrimes * 54Srgrimes * This code is free software; you can redistribute it and/or modify it 64Srgrimes * under the terms of the GNU General Public License version 2 only, as 74Srgrimes * published by the Free Software Foundation. Oracle designates this 84Srgrimes * particular file as subject to the "Classpath" exception as provided 94Srgrimes * by Oracle in the LICENSE file that accompanied this code. 104Srgrimes * 114Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 124Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 134Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 144Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 154Srgrimes * accompanied this code). 164Srgrimes * 174Srgrimes * You should have received a copy of the GNU General Public License version 184Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 194Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 204Srgrimes * 214Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 224Srgrimes * or visit www.oracle.com if you need additional information or have any 234Srgrimes * questions. 244Srgrimes */ 254Srgrimes 264Srgrimespackage jdk.nashorn.internal.tools.nasgen; 274Srgrimes 284Srgrimesimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 294Srgrimesimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 304Srgrimesimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 314Srgrimesimport static jdk.internal.org.objectweb.asm.Opcodes.V1_7; 324Srgrimesimport static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX; 334Srgrimesimport static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; 34593Srgrimesimport static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; 3550477Speterimport static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; 364Srgrimesimport static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; 374Srgrimesimport static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; 3832929Seivindimport static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR; 3913290Speterimport static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC; 4013225Swollmanimport static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE; 412056Swollmanimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC3; 422056Swollmanimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4; 4345720Speterimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; 4467365Sjhbimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; 4511865Sphkimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION; 4633281Sbdeimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC; 4745720Speterimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE; 4811865Sphkimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC; 492056Swollmanimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; 5071287Sjakeimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; 5145720Speterimport static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; 5245720Speter 5322093Sbdeimport java.io.FileOutputStream; 544478Sbdeimport java.io.IOException; 5522093Sbdeimport java.util.List; 564478Sbdeimport jdk.internal.org.objectweb.asm.Handle; 573816Swollman 5831255Sbde/** 5925083Sjdp * This class generates constructor class for a @ScriptClass annotated class. 6031255Sbde * 6130805Sbde */ 6230805Sbdepublic class ConstructorGenerator extends ClassGenerator { 6326309Speter private final ScriptClassInfo scriptClassInfo; 642056Swollman private final String className; 6530805Sbde private final MemberInfo constructor; 6631255Sbde private final int memberCount; 674478Sbde private final List<MemberInfo> specs; 6831255Sbde 6945720Speter ConstructorGenerator(final ScriptClassInfo sci) { 702056Swollman this.scriptClassInfo = sci; 7130805Sbde 723816Swollman this.className = scriptClassInfo.getConstructorClassName(); 7331255Sbde this.constructor = scriptClassInfo.getConstructor(); 742056Swollman this.memberCount = scriptClassInfo.getConstructorMemberCount(); 7526373Sdfr this.specs = scriptClassInfo.getSpecializedConstructors(); 762056Swollman } 7731255Sbde 7860008Swollman byte[] getClassBytes() { 794Srgrimes // new class extending from ScriptObject 804Srgrimes final String superClass = (constructor != null)? SCRIPTFUNCTION_TYPE : SCRIPTOBJECT_TYPE; 814Srgrimes cw.visit(V1_7, ACC_FINAL, className, null, superClass, null); 824Srgrimes if (memberCount > 0) { 834Srgrimes // add fields 8419653Sbde emitFields(); 8519653Sbde // add <clinit> 8619653Sbde emitStaticInitializer(); 8719653Sbde } 8849081Scracauer // add <init> 8919653Sbde emitConstructor(); 904Srgrimes 914Srgrimes if (constructor == null) { 925351Sbde emitGetClassName(scriptClassInfo.getName()); 934Srgrimes } 944Srgrimes 955351Sbde cw.visitEnd(); 9635215Sbde return cw.toByteArray(); 9735215Sbde } 9835215Sbde 995351Sbde // --Internals only below this point 1005351Sbde private void emitFields() { 1014Srgrimes // Introduce "Function" type instance fields for each 1024Srgrimes // constructor @Function in script class and introduce instance 1034Srgrimes // fields for each constructor @Property in the script class. 1044Srgrimes for (MemberInfo memInfo : scriptClassInfo.getMembers()) { 1054Srgrimes if (memInfo.isConstructorFunction()) { 1064Srgrimes addFunctionField(memInfo.getJavaName()); 1074Srgrimes memInfo = (MemberInfo)memInfo.clone(); 1084Srgrimes memInfo.setJavaDesc(OBJECT_DESC); 1094Srgrimes memInfo.setJavaAccess(ACC_PUBLIC); 1105351Sbde addGetter(className, memInfo); 1114Srgrimes addSetter(className, memInfo); 1124Srgrimes } else if (memInfo.isConstructorProperty()) { 1134Srgrimes if (memInfo.isStaticFinal()) { 1144Srgrimes addGetter(scriptClassInfo.getJavaName(), memInfo); 1154Srgrimes } else { 1164Srgrimes addField(memInfo.getJavaName(), memInfo.getJavaDesc()); 1174Srgrimes memInfo = (MemberInfo)memInfo.clone(); 1184Srgrimes memInfo.setJavaAccess(ACC_PUBLIC); 1194Srgrimes addGetter(className, memInfo); 1204Srgrimes addSetter(className, memInfo); 1214Srgrimes } 1224Srgrimes } 12345720Speter } 12445720Speter 12550181Speter addMapField(); 12645720Speter } 12745720Speter 12845100Sdt private void emitStaticInitializer() { 12933281Sbde final MethodGenerator mi = makeStaticInitializer(); 13033281Sbde emitStaticInitPrefix(mi, className, memberCount); 13145100Sdt 1324Srgrimes for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { 1335351Sbde if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) { 13411865Sphk linkerAddGetterSetter(mi, className, memInfo); 13511865Sphk } else if (memInfo.isConstructorGetter()) { 13611865Sphk final MemberInfo setter = scriptClassInfo.findSetter(memInfo); 13711865Sphk linkerAddGetterSetter(mi, scriptClassInfo.getJavaName(), memInfo, setter); 13811865Sphk } 13941591Sarchie } 14066698Sjhb emitStaticInitSuffix(mi, className); 14141591Sarchie } 14241797Sbde 14341591Sarchie private void emitConstructor() { 14441591Sarchie final MethodGenerator mi = makeConstructor(); 14541591Sarchie mi.visitCode(); 14626812Speter callSuper(mi); 1474Srgrimes 1484Srgrimes if (memberCount > 0) { 1494Srgrimes // initialize Function type fields 15047226Speter initFunctionFields(mi); 1514Srgrimes // initialize data fields 15227567Sfsmp initDataFields(mi); 1534Srgrimes } 1544Srgrimes 1554Srgrimes if (constructor != null) { 1565351Sbde initPrototype(mi); 1574Srgrimes final int arity = constructor.getArity(); 15825164Speter if (arity != MemberInfo.DEFAULT_ARITY) { 15935302Sbde mi.loadThis(); 16035302Sbde mi.push(arity); 16135302Sbde mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, 16246548Sbde SCRIPTFUNCTION_SETARITY_DESC); 16335302Sbde } 16435302Sbde final String doc = constructor.getDocumentation(); 16535302Sbde if (doc != null) { 16635302Sbde mi.loadThis(); 16735302Sbde mi.loadLiteral(doc); 16835302Sbde mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION, 16935302Sbde SCRIPTFUNCTION_SETDOCUMENTATION_DESC); 17035302Sbde } 17135302Sbde } 17235302Sbde mi.returnVoid(); 17335302Sbde mi.computeMaxs(); 1744Srgrimes mi.visitEnd(); 1754Srgrimes } 1764478Sbde 17735302Sbde private void loadMap(final MethodGenerator mi) { 17835302Sbde if (memberCount > 0) { 17935302Sbde mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC); 18046548Sbde } 18135302Sbde } 18235302Sbde 18335302Sbde private void callSuper(final MethodGenerator mi) { 18435302Sbde String superClass, superDesc; 18535302Sbde mi.loadThis(); 1864Srgrimes if (constructor == null) { 18727567Sfsmp // call ScriptObject.<init> 1884Srgrimes superClass = SCRIPTOBJECT_TYPE; 1894Srgrimes superDesc = (memberCount > 0) ? SCRIPTOBJECT_INIT_DESC : DEFAULT_INIT_DESC; 19050181Speter loadMap(mi); 19150181Speter } else { 19250181Speter // call Function.<init> 19350181Speter superClass = SCRIPTFUNCTION_TYPE; 19450181Speter superDesc = (memberCount > 0) ? SCRIPTFUNCTION_INIT_DESC4 : SCRIPTFUNCTION_INIT_DESC3; 19550181Speter mi.loadLiteral(constructor.getName()); 19650181Speter mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc())); 19750181Speter loadMap(mi); 19850181Speter mi.memberInfoArray(scriptClassInfo.getJavaName(), specs); //pushes null if specs empty 19950181Speter } 20050181Speter 20150181Speter mi.invokeSpecial(superClass, INIT, superDesc); 20250181Speter } 20350181Speter 20450181Speter private void initFunctionFields(final MethodGenerator mi) { 2054Srgrimes assert memberCount > 0; 2064Srgrimes for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { 2074Srgrimes if (!memInfo.isConstructorFunction()) { 2084Srgrimes continue; 2094Srgrimes } 2104Srgrimes mi.loadThis(); 21145720Speter newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); 21245720Speter mi.putField(className, memInfo.getJavaName(), OBJECT_DESC); 2134Srgrimes } 21446555Speter } 21527567Sfsmp 21647226Speter private void initDataFields(final MethodGenerator mi) { 21747226Speter assert memberCount > 0; 21845720Speter for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { 21927567Sfsmp if (!memInfo.isConstructorProperty() || memInfo.isFinal()) { 22027567Sfsmp continue; 22127567Sfsmp } 2224Srgrimes final Object value = memInfo.getValue(); 2234Srgrimes if (value != null) { 2244Srgrimes mi.loadThis(); 2254Srgrimes mi.loadLiteral(value); 2264Srgrimes mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); 2274Srgrimes } else if (!memInfo.getInitClass().isEmpty()) { 2284Srgrimes final String clazz = memInfo.getInitClass(); 2294Srgrimes mi.loadThis(); 2304Srgrimes mi.newObject(clazz); 2314Srgrimes mi.dup(); 2324Srgrimes mi.invokeSpecial(clazz, INIT, DEFAULT_INIT_DESC); 2334Srgrimes mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); 2344Srgrimes } 23547226Speter } 23647226Speter } 23747226Speter 2384Srgrimes private void initPrototype(final MethodGenerator mi) { 2394Srgrimes assert constructor != null; 2404Srgrimes mi.loadThis(); 2414Srgrimes final String protoName = scriptClassInfo.getPrototypeClassName(); 2424Srgrimes mi.newObject(protoName); 2434Srgrimes mi.dup(); 24445720Speter mi.invokeSpecial(protoName, INIT, DEFAULT_INIT_DESC); 24547226Speter mi.dup(); 24612929Sdg mi.loadThis(); 24712929Sdg mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR, 2484Srgrimes PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC); 24965557Sjasone mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETPROTOTYPE, SCRIPTFUNCTION_SETPROTOTYPE_DESC); 25065557Sjasone } 25165557Sjasone 25265557Sjasone /** 25365557Sjasone * Entry point for ConstructorGenerator run separately as an application. Will display 25465557Sjasone * usage. Takes one argument, a class name. 2554Srgrimes * @param args args vector 25645720Speter * @throws IOException if class can't be read 2574Srgrimes */ 2584Srgrimes public static void main(final String[] args) throws IOException { 2594Srgrimes if (args.length != 1) { 2604Srgrimes System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>"); 2614Srgrimes System.exit(1); 2624Srgrimes } 2634Srgrimes 26427567Sfsmp final String className = args[0].replace('.', '/'); 26527567Sfsmp final ScriptClassInfo sci = getScriptClassInfo(className + ".class"); 2664Srgrimes if (sci == null) { 2674Srgrimes System.err.println("No @ScriptClass in " + className); 2684Srgrimes System.exit(2); 26945720Speter throw new IOException(); // get rid of warning for sci.verify() below - may be null 27045720Speter } 2714Srgrimes 27241591Sarchie try { 2735351Sbde sci.verify(); 2745351Sbde } catch (final Exception e) { 27541591Sarchie System.err.println(e.getMessage()); 2765351Sbde System.exit(3); 2774Srgrimes } 2784Srgrimes final ConstructorGenerator gen = new ConstructorGenerator(sci); 2794Srgrimes try (FileOutputStream fos = new FileOutputStream(className + CONSTRUCTOR_SUFFIX + ".class")) { 2804Srgrimes fos.write(gen.getClassBytes()); 2814Srgrimes } 2824Srgrimes } 2834Srgrimes} 2844Srgrimes