Logo Search packages:      
Sourcecode: janino version File versions  Download package

void org::codehaus::janino::UnitCompiler::invokeConstructor ( Locatable  l,
Java.Scope  scope,
Java.Rvalue  optionalEnclosingInstance,
IClass  targetClass,
Java.Rvalue[]  arguments 
) throws CompileException [inline, private]

Expects the object to initialize on the stack.

Notice: This method is used both for explicit constructor invocation (first statement of a constructor body) and implicit constructor invocation (right after NEW).

Parameters:
optionalEnclosingInstance Used if the target class is an inner class

Definition at line 4824 of file UnitCompiler.java.

References org::codehaus::janino::IClass::getDeclaredIConstructors(), org::codehaus::janino::IClass::getDescriptor(), org::codehaus::janino::IClass::getOuterIClass(), org::codehaus::janino::IClass::getSyntheticIFields(), and org::codehaus::janino::IClass::isAssignableFrom().

                              {

        // Find constructors.
        IClass.IConstructor[] iConstructors = targetClass.getDeclaredIConstructors();
        if (iConstructors.length == 0) throw new RuntimeException("SNO: Target class \"" + targetClass.getDescriptor() + "\" has no constructors");

        IClass.IConstructor iConstructor = (IClass.IConstructor) this.findMostSpecificIInvocable(
            l,
            iConstructors, // iInvocables
            arguments      // arguments
        );

        // Check exceptions that the constructor may throw.
        IClass[] thrownExceptions = iConstructor.getThrownExceptions();
        for (int i = 0; i < thrownExceptions.length; ++i) {
            this.checkThrownException(
                l,
                thrownExceptions[i],
                scope
            );
        }

        // Pass enclosing instance as a synthetic parameter.
        if (optionalEnclosingInstance != null) {
            IClass outerIClass = targetClass.getOuterIClass();
            if (outerIClass != null) {
                IClass eiic = this.compileGetValue(optionalEnclosingInstance);
                if (!outerIClass.isAssignableFrom(eiic)) this.compileError("Type of enclosing instance (\"" + eiic + "\") is not assignable to \"" + outerIClass + "\"", l.getLocation());
            }
        }

        // Pass local variables to constructor as synthetic parameters.
        {
            IClass.IField[] syntheticFields = targetClass.getSyntheticIFields();

            // Determine enclosing function declarator and type declaration.
            Java.TypeBodyDeclaration scopeTBD;
            Java.TypeDeclaration     scopeTypeDeclaration;
            {
                Java.Scope s = scope;
                for (; !(s instanceof Java.TypeBodyDeclaration); s = s.getEnclosingScope());
                scopeTBD             = (Java.TypeBodyDeclaration) s;
                scopeTypeDeclaration = scopeTBD.getDeclaringType();
            }

            if (!(scopeTypeDeclaration instanceof Java.ClassDeclaration)) {
                if (syntheticFields.length > 0) throw new RuntimeException("SNO: Target class has synthetic fields");
            } else {
                Java.ClassDeclaration scopeClassDeclaration = (Java.ClassDeclaration) scopeTypeDeclaration;
                for (int i = 0; i < syntheticFields.length; ++i) {
                    IClass.IField sf = syntheticFields[i];
                    if (!sf.getName().startsWith("val$")) continue;
                    IClass.IField eisf = (IClass.IField) scopeClassDeclaration.syntheticFields.get(sf.getName());
                    if (eisf != null) {
                        if (scopeTBD instanceof Java.MethodDeclarator) {
                            this.load(l, this.resolve(scopeClassDeclaration), 0);
                            this.writeOpcode(l, Opcode.GETFIELD);
                            this.writeConstantFieldrefInfo(
                                this.resolve(scopeClassDeclaration).getDescriptor(),
                                sf.getName(), // classFD
                                sf.getDescriptor()                                   // fieldFD
                            );
                        } else
                        if (scopeTBD instanceof Java.ConstructorDeclarator) {
                            Java.ConstructorDeclarator constructorDeclarator = (Java.ConstructorDeclarator) scopeTBD;
                            Java.LocalVariable syntheticParameter = (Java.LocalVariable) constructorDeclarator.syntheticParameters.get(sf.getName());
                            if (syntheticParameter == null) {
                                this.compileError("Compiler limitation: Constructor cannot access local variable \"" + sf.getName().substring(4) + "\" declared in an enclosing block because none of the methods accesses it. As a workaround, declare a dummy method that accesses the local variable.", l.getLocation());
                                this.writeOpcode(l, Opcode.ACONST_NULL);
                            } else {
                                this.load(l, syntheticParameter);
                            }
                        } else {
                            this.compileError("Compiler limitation: Initializers cannot access local variables declared in an enclosing block.", l.getLocation());
                            this.writeOpcode(l, Opcode.ACONST_NULL);
                        }
                    } else {
                        String localVariableName = sf.getName().substring(4);
                        Java.LocalVariable lv;
                        DETERMINE_LV: {
                            Java.Scope s;

                            // Does one of the enclosing blocks declare a local variable with that name?
                            for (s = scope; s instanceof Java.BlockStatement; s = s.getEnclosingScope()) {
                                Java.BlockStatement bs = (Java.BlockStatement) s;
                                Java.Scope es = bs.getEnclosingScope();
                                if (!(es instanceof Java.Block)) continue;
                                Java.Block b = (Java.Block) es;
    
                                for (Iterator it = b.statements.iterator();;) {
                                    Java.BlockStatement bs2 = (Java.BlockStatement) it.next();
                                    if (bs2 == bs) break;
                                    if (bs2 instanceof Java.LocalVariableDeclarationStatement) {
                                        Java.LocalVariableDeclarationStatement lvds = ((Java.LocalVariableDeclarationStatement) bs2);
                                        Java.VariableDeclarator[] vds = lvds.variableDeclarators;
                                        for (int j = 0; j < vds.length; ++j) {
                                            if (vds[j].name.equals(localVariableName)) {
                                                lv = this.getLocalVariable(lvds, vds[j]);
                                                break DETERMINE_LV;
                                            }
                                        }
                                    }
                                }
                            }

                            // Does the declaring function declare a parameter with that name?
                            while (!(s instanceof Java.FunctionDeclarator)) s = s.getEnclosingScope();
                            Java.FunctionDeclarator fd = (Java.FunctionDeclarator) s;
                            for (int j = 0; j < fd.formalParameters.length; ++j) {
                                Java.FunctionDeclarator.FormalParameter fp = fd.formalParameters[j];
                                if (fp.name.equals(localVariableName)) {
                                    lv = this.getLocalVariable(fp);
                                    break DETERMINE_LV;
                                }
                            }
                            throw new RuntimeException("SNO: Synthetic field \"" + sf.getName() + "\" neither maps a synthetic field of an enclosing instance nor a local variable");
                        }
                        this.load(l, lv);
                    }
                }
            }
        }

        // Evaluate constructor arguments.
        IClass[] parameterTypes = iConstructor.getParameterTypes();
        for (int i = 0; i < arguments.length; ++i) {
            this.assignmentConversion(
                l,                                  // l
                this.compileGetValue(arguments[i]), // sourceType
                parameterTypes[i],                  // targetType
                this.getConstantValue(arguments[i]) // optionalConstantValue
            );
        }

        // Invoke!
        // Notice that the method descriptor is "iConstructor.getDescriptor()" prepended with the
        // synthetic parameters.
        this.writeOpcode(l, Opcode.INVOKESPECIAL);
        this.writeConstantMethodrefInfo(
            targetClass.getDescriptor(),
            "<init>", // classFD
            iConstructor.getDescriptor() // methodMD
        );
    }


Generated by  Doxygen 1.6.0   Back to index