/* * @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/InstanceCreation.java -- * a part of JCGO translator. ** * Project: JCGO (http://www.ivmaisoft.com/jcgo/) * Copyright (C) 2001-2012 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software 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 (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package com.ivmaisoft.jcgo; /** * Grammar production for a constructor call. ** * Formats: NEW ClassOrIfaceType LPAREN [ArgumentList] RPAREN [ClassBody] * Primary DOT NEW ID LPAREN [ArgumentList] RPAREN [ClassBody] */ final class InstanceCreation extends LexNode { private boolean analysisDone; private Term classBody; private ClassDefinition cd; private MethodDefinition md; private boolean isClinitSafe; private int primaryIndex; private boolean forceCheck; private LeftBrace noLeaksScope; private boolean isConditional; private boolean insideAssertStmt; private String stackObjCode; private boolean needsLocalVolatile; private ExpressionType reflectedClass; private String reflectedMethodId; private ObjVector reflectedParmSig; InstanceCreation(Term b, Term d, Term f) { super(Empty.newTerm(), b, d); classBody = f; } InstanceCreation(Term a, Term d, Term f, Term h) { super(a, d, f); classBody = h; } void processPass0(Context c) { terms[0].processPass0(c); terms[2].processPass0(c); if (classBody.notEmpty()) { String id = c.currentClass.nextAnonymousId(); cd = Main.dict.get(c.currentClass.name() + "$" + id); cd.definePass0(c, c.modifiers & AccModifier.STATIC, id, terms[0] .notEmpty() ? new ClassOrIfaceType(new LexTerm(LexTerm.ID, terms[1].dottedName())) : terms[1], Empty.newTerm(), classBody, false); } } void processPass1(Context c) { if (!analysisDone) { assertCond(c.currentClass != null); analysisDone = true; primaryIndex = -1; if ((c.forceVmExc & ClassDefinition.NULL_PTR_EXC) != 0) { forceCheck = true; } insideAssertStmt = c.insideAssertStmt; terms[2].processPass1(c); Term param; ExpressionType exprType0; ClassDefinition aclass; if (terms[0].notEmpty()) { param = new Argument(terms[0]); param.processPass1(c); exprType0 = terms[0].exprType(); if (exprType0.objectSize() != Type.CLASSINTERFACE) { fatalError(c, "Illegal type of expression for qualified 'new'"); } String name = exprType0.receiverClass().resolveInnerClass( terms[1].dottedName(), false, c.forClass); aclass = name != null ? Main.dict.get(name) : c.resolveClass( terms[1].dottedName(), true, false); terms[0] = Empty.newTerm(); } else { terms[1].processPass1(c); aclass = c.typeClassDefinition; param = null; exprType0 = null; } if (cd != null) { cd.changeExtendsTerm(aclass, exprType0 != null); if (aclass.isInterface()) { aclass = Main.dict.get(Names.JAVA_LANG_OBJECT); } } Term paramList; do { paramList = Empty.newTerm(); ObjVector locals = aclass.outerLocals(c.forClass); for (int i = locals.size() - 1; i >= 0; i--) { Term t = new Argument(new Expression((new QualifiedName( new LexTerm(LexTerm.ID, ((VariableDefinition) locals.elementAt(i)) .id()))).setLineInfoFrom(this))); t.processPass1(c); paramList = ParameterList.prepend(t, paramList); } paramList = terms[2].joinParamLists(paramList); if (cd == aclass) { if (exprType0 != null) { paramList = ParameterList.prepend(param, paramList); primaryIndex = 0; } param = null; } if (!aclass.isStaticClass() && param == null) { ClassDefinition outerClass = aclass.outerClass(); if (cd != null) { for (ClassDefinition cdOuter = cd.outerClass(); cdOuter != null; cdOuter = cdOuter .outerClass()) { if (outerClass.isAssignableFrom(cdOuter, 0, c.forClass)) { outerClass = cdOuter; break; } } } param = new Argument((new This(new ClassOrIfaceType( outerClass))).setLineInfoFrom(this)); param.processPass1(c); } if (param != null) { paramList = ParameterList.prepend(param, paramList); if (exprType0 != null) { primaryIndex++; } } ObjVector parmSig = paramList.getSignature(); if (cd == null && aclass.isAbstractOrInterface()) { fatalError(c, "Cannot create an instance of an abstract class: " + aclass.name()); } md = aclass.matchConstructor(parmSig, c.forClass); if (md == null) { undefinedConstructor(aclass, parmSig, c); terms[2] = paramList; return; } if (cd == null || cd == aclass) break; aclass = cd; cd.setConstrSuperExpr(exprType0, md, param != null ? 1 : 0, locals.size()); cd.processPass1(c); } while (true); terms[2] = paramList; md.markNew(); if (!c.currentClass.name().equals(Names.JAVA_LANG_STRING) || md.definingClass().used() || !aclass.name().equals( Names.JAVA_LANG_STRINGINDEXOUTOFBOUNDSEXCEPTION) || (paramList.notEmpty() && !md.methodSignature() .signatureString().equals(Names.SIGN_INIT_INT))) { isClinitSafe = c.addAccessedClass(aclass); md.markUsed(aclass, isClinitSafe); if (!c.currentClass.name().equals( Names.JAVAX_SWING_UIDEFAULTS_PROXYLAZYVALUE)) { processReflection(c.forClass); } md.processBranch(c, false); isConditional = c.isConditional; noLeaksScope = c.localScope; } else { Main.dict.markStrIndexOutInit = true; } md.incCallsCount(c.currentMethod); md.setArgsFormalType(paramList, md.used() ? c : null); } } ExpressionType exprType() { assertCond(analysisDone); return md != null ? md.exprType() : Main.dict .get(Names.JAVA_LANG_OBJECT); } ExpressionType actualExprType() { return md != null ? md.exprType().receiverClass().asExactClassType() : Main.dict.get(Names.JAVA_LANG_OBJECT); } boolean isNotNull() { return md != null && md.used(); } int tokenCount() { return terms[2].tokenCount() + 3; } void allocRcvr(int[] curRcvrs) { if (md == null || md.used()) { Term t2 = terms[2]; if (primaryIndex >= 0) { Term t0 = (primaryIndex > 0 ? t2.getTermAt(1) : t2) .getTermAt(0); if (t0.isNotNull()) { primaryIndex = -1; } else { if (t0 == t2) { int[] curRcvrs2 = OutputContext.copyRcvrs(curRcvrs); t2.markParamRcvr(-2, curRcvrs2); t2.allocParamRcvr(curRcvrs, OutputContext.copyRcvrs(curRcvrs), curRcvrs2); return; } t0.markParamRcvr(-2, new int[Type.VOID]); } } t2.allocRcvr(curRcvrs); } } void discoverObjLeaks() { assertCond(analysisDone); if (md != null && md.used()) { md.copyObjLeaksTo(terms[2]); ClassDefinition ourClass = md.definingClass(); MethodDefinition mf = ourClass.getMethod(Names.SIGN_FINALIZE); ClassDefinition vrtmClass; if ((mf != null && mf.definingClass().superClass() != null && (vrtmClass = Main.dict.get(Names.JAVA_LANG_VMRUNTIME)) .used() && (mf = vrtmClass.getMethod(Names.SIGN_FINALIZEOBJECT0X)) != null && mf .isClassMethod()) || md.hasThisObjLeak(false) || !ourClass.discoverInstanceObjLeaks()) { noLeaksScope = null; } else if (md.isThisStackObjVolatile() || ourClass.isInitThisStackObjVolatile()) { needsLocalVolatile = true; } } terms[2].discoverObjLeaks(); } void setStackObjVolatile() { needsLocalVolatile = true; } void setObjLeaks(VariableDefinition v) { if (v == VariableDefinition.RETURN_VAR && md != null && !isClinitSafe && md.needsTrigClinit() && md.definingClass().classInitializerNotCalledYet()) { v = null; } noLeaksScope = VariableDefinition.addSetObjLeaksTerm(noLeaksScope, v, this, isConditional); } static String writeStackObjectDefn(OutputContext oc, ClassDefinition ourClass, boolean needsTrigClinit, boolean insideAssertStmt, boolean needsLocalVolatile) { assertCond(ourClass != null); String stackObjName = oc.nextStackObjName(); if (insideAssertStmt) { oc.cPrint("\n#ifdef JCGO_ASSERTION\010"); } oc.cPrint("struct "); oc.cPrint(ourClass.castName()); oc.cPrint("_s "); oc.cPrint(stackObjName); oc.cPrint(";"); if (insideAssertStmt) { oc.cPrint("\n#endif\010"); } return "JCGO_STACKOBJ" + (needsLocalVolatile ? "VLT" : "") + "_NEW" + (needsTrigClinit && ourClass.classInitializerNotCalledYet() ? "TRIG(" : "(") + stackObjName + ", " + ourClass.vTableCName() + ")"; } String writeStackObjDefn(OutputContext oc, boolean needsLocalVolatile) { assertCond(md != null); return writeStackObjectDefn(oc, md.definingClass(), false, insideAssertStmt, needsLocalVolatile || this.needsLocalVolatile); } void writeStackObjs(OutputContext oc, Term scopeTerm) { terms[2].writeStackObjs(oc, scopeTerm); if (noLeaksScope == scopeTerm && md != null && md.used()) { assertCond(scopeTerm != null); stackObjCode = writeStackObjectDefn(oc, md.definingClass(), !isClinitSafe && md.needsTrigClinit(), insideAssertStmt, needsLocalVolatile); } } void writeStackObjTrigClinit(OutputContext oc) { if (!isClinitSafe && md != null && md.used() && md.needsTrigClinit()) { md.definingClass().writeTrigClinit(oc); } } ExpressionType writeStackObjRetCode(OutputContext oc) { assertCond(md != null && noLeaksScope == null); stackObjCode = MethodDefinition.STACKOBJ_RETNAME; oc.cPrint(md.definingClass().cNewObjectCode()); return exprType(); } boolean isAtomary() { return true; } static void writeNewRoutineCall(OutputContext oc, MethodDefinition md, String stackObjCode) { oc.cPrint(md != null ? (stackObjCode != null ? md.routineCName() : md .newRoutineCName()) : MethodDefinition.UNKNOWN_NAME); oc.cPrint("("); if (stackObjCode != null) { oc.cPrint("\010 "); oc.cPrint(stackObjCode); if (md.hasParameters()) { oc.cPrint(", "); } } else if (md.hasParameters()) { oc.cPrint("\010 "); } Main.dict.normalCalls++; } void processOutput(OutputContext oc) { assertCond(analysisDone); Term t2 = terms[2]; if (md == null || md.used()) { if (t2.notEmpty()) { oc.cPrint("("); t2.produceRcvr(oc); if (primaryIndex >= 0) { oc.cPrint(forceCheck ? "JCGO_CALL_EFINALF" : "JCGO_CALL_FINALF"); oc.cPrint("("); OutputContext oc2 = new OutputContext(); (primaryIndex > 0 ? t2.getTermAt(1) : t2).getTermAt(0) .parameterOutput(oc2, true, Type.CLASSINTERFACE); oc.cPrint(oc2.instanceToString().substring(2)); oc.cPrint(") "); } } ClassDefinition ourClass; writeNewRoutineCall( oc, md, stackObjCode != null || md == null ? stackObjCode : (ourClass = md.definingClass()) .classInitializerNotCalledYet() && isClinitSafe && md.needsTrigClinit() ? ourClass .cNewObjectCode() : null); oc.cPrint(OutputContext.paramStringOutputNoComma(t2, true)); oc.cPrint(")"); if (t2.notEmpty()) { oc.cPrint(")"); } } else { oc.cPrint(LexTerm.NULL_STR); } } private void processReflection(ClassDefinition forClass) { if (!md.isPublic()) return; if (md.definingClass().name() .equals(Names.JAVAX_SWING_UIDEFAULTS_PROXYLAZYVALUE)) { String sigString = md.methodSignature().signatureString(); if (sigString.equals(Names.SIGN_INIT_STRING) || sigString.equals(Names.SIGN_INIT_STRING_OBJECTS)) { ExpressionType exprType = MethodInvocation .decodeClassForNameArg(decodeArgAsString(0), null); if (exprType != null) { ClassDefinition aclass = exprType.receiverClass(); aclass.markUsed(); reflectConstructors( aclass, sigString.equals(Names.SIGN_INIT_STRING) ? new ObjVector() : decodeArgAsValuesArray(1)); } return; } if (sigString.equals(Names.SIGN_INIT_STRING_STRING) || sigString.equals(Names.SIGN_INIT_STRING_STRING_OBJECTS)) { ExpressionType exprType = MethodInvocation .decodeClassForNameArg(decodeArgAsString(0), null); if (exprType != null) { ClassDefinition aclass = exprType.receiverClass(); aclass.markUsed(); Term t = terms[2].getArgumentTerm(1); ObjVector parmSig = sigString .equals(Names.SIGN_INIT_STRING_STRING) ? new ObjVector() : decodeArgAsValuesArray(2); if (t != null && t.actualExprType().objectSize() == Type.NULLREF) { reflectConstructors(aclass, parmSig); } else { reflectMethods(aclass, decodeArgAsString(1), parmSig); } } } } } private String decodeArgAsString(int index) { Term t = terms[2].getArgumentTerm(index); return t != null ? t.strLiteralValueGuess() : null; } private ObjVector decodeArgAsValuesArray(int index) { Term t = terms[2].getArgumentTerm(index); if (t == null) return null; ObjVector parmSig = new ObjVector(); return t.storeClassLiteralsGuess(parmSig, true) || t.actualExprType().objectSize() == Type.NULLREF ? parmSig : null; } private void reflectConstructors(ClassDefinition literalClass, ObjVector parmSig) { if (reflectedMethodId == null) { literalClass.reflectConstructors( false, parmSig != null ? (new MethodSignature("<init>", parmSig)) .signatureString() : null, true); reflectedClass = literalClass.asExactClassType(); reflectedMethodId = "<init>"; reflectedParmSig = parmSig; } } private void reflectMethods(ClassDefinition literalClass, String id, ObjVector parmSig) { if (reflectedMethodId == null) { if (id != null && id.length() == 0) { id = null; } literalClass.reflectMethods(id, false, parmSig, true); reflectedClass = literalClass; reflectedMethodId = id != null ? id : ""; reflectedParmSig = parmSig; } } ExpressionType traceClassInit() { terms[2].traceClassInit(); if (md != null) { ObjVector parmTraceSig = null; if (terms[2].notEmpty()) { parmTraceSig = new ObjVector(); terms[2].getTraceSignature(parmTraceSig); } md.methodTraceClassInit(false, null, parmTraceSig); ClassDefinition ourClass = md.definingClass(); MethodDefinition mf = ourClass.getMethod(Names.SIGN_FINALIZE); if (mf != null && mf.definingClass().superClass() != null) { ClassDefinition vrtmClass = Main.dict .get(Names.JAVA_LANG_VMRUNTIME); MethodDefinition mr; if (vrtmClass.used() && (mr = vrtmClass .getMethod(Names.SIGN_FINALIZEOBJECT0X)) != null && mr.isClassMethod()) { mr.methodTraceClassInit(true, null, null); } mf.methodTraceClassInit(true, ourClass.asExactClassType(), null); } if (reflectedClass != null) { ClassDefinition aclass = reflectedClass.signatureClass(); if (reflectedMethodId.equals("<init>")) { aclass.traceReflectedConstructor( false, reflectedParmSig != null ? (new MethodSignature( "<init>", reflectedParmSig)) .signatureString() : null, reflectedClass != aclass); } else { aclass.traceReflectedMethod( reflectedMethodId.length() > 0 ? reflectedMethodId : null, false, reflectedParmSig); } } } return null; } }