/** Code generation for a array allocation expression */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { int pc = codeStream.position; if (initializer != null) { initializer.generateCode(currentScope, codeStream, valueRequired); return; } int nonNullDimensionsLength = 0; for (int i = 0, max = dimensions.length; i < max; i++) if (dimensions[i] != null) { dimensions[i].generateCode(currentScope, codeStream, true); nonNullDimensionsLength++; } // Generate a sequence of bytecodes corresponding to an array allocation if (this.resolvedType.dimensions() == 1) { // Mono-dimensional array codeStream.newArray((ArrayBinding) this.resolvedType); } else { // Multi-dimensional array codeStream.multianewarray(this.resolvedType, nonNullDimensionsLength); } if (valueRequired) { codeStream.generateImplicitConversion(implicitConversion); } else { codeStream.pop(); } codeStream.recordPositionsFrom(pc, this.sourceStart); }
/** * Code generation for instanceOfExpression * * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream * @param valueRequired boolean */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { int pc = codeStream.position; this.expression.generateCode(currentScope, codeStream, true); codeStream.instance_of(this.type.resolvedType); if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); } else { codeStream.pop(); } codeStream.recordPositionsFrom(pc, this.sourceStart); }
/** * Try statement code generation with or without jsr bytecode use post 1.5 target level, cannot * use jsr bytecode, must instead inline finally block returnAddress is only allocated if jsr is * allowed */ public void generateCode(BlockScope currentScope, CodeStream codeStream) { if ((bits & IsReachableMASK) == 0) { return; } // in case the labels needs to be reinitialized // when the code generation is restarted in wide mode if (this.anyExceptionLabelsCount > 0) { this.anyExceptionLabels = NO_EXCEPTION_HANDLER; this.anyExceptionLabelsCount = 0; } int pc = codeStream.position; final int NO_FINALLY = 0; // no finally block final int FINALLY_SUBROUTINE = 1; // finally is generated as a subroutine (using jsr/ret bytecodes) final int FINALLY_DOES_NOT_COMPLETE = 2; // non returning finally is optimized with only one instance of finally block final int FINALLY_MUST_BE_INLINED = 3; // finally block must be inlined since cannot use jsr/ret bytecodes >1.5 int finallyMode; if (subRoutineStartLabel == null) { finallyMode = NO_FINALLY; } else { if (this.isSubRoutineEscaping) { finallyMode = FINALLY_DOES_NOT_COMPLETE; } else if (scope.compilerOptions().inlineJsrBytecode) { finallyMode = FINALLY_MUST_BE_INLINED; } else { finallyMode = FINALLY_SUBROUTINE; } } boolean requiresNaturalExit = false; // preparing exception labels int maxCatches; ExceptionLabel[] exceptionLabels = new ExceptionLabel[maxCatches = catchArguments == null ? 0 : catchArguments.length]; for (int i = 0; i < maxCatches; i++) { exceptionLabels[i] = new ExceptionLabel(codeStream, catchArguments[i].binding.type); } if (subRoutineStartLabel != null) { subRoutineStartLabel.initialize(codeStream); this.enterAnyExceptionHandler(codeStream); } // generate the try block tryBlock.generateCode(scope, codeStream); boolean tryBlockHasSomeCode = codeStream.position != pc; // flag telling if some bytecodes were issued inside the try block // place end positions of user-defined exception labels if (tryBlockHasSomeCode) { // natural exit may require subroutine invocation (if finally != null) Label naturalExitLabel = new Label(codeStream); if (!tryBlockExit) { int position = codeStream.position; switch (finallyMode) { case FINALLY_SUBROUTINE: case FINALLY_MUST_BE_INLINED: requiresNaturalExit = true; // fall through case NO_FINALLY: codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE: codeStream.goto_(subRoutineStartLabel); break; } codeStream.updateLastRecordedEndPC(tryBlock.scope, position); // goto is tagged as part of the try block } for (int i = 0; i < maxCatches; i++) { exceptionLabels[i].placeEnd(); } /* generate sequence of handler, all starting by storing the TOS (exception thrown) into their own catch variables, the one specified in the source that must denote the handled exception. */ if (catchArguments != null) { for (int i = 0; i < maxCatches; i++) { // May loose some local variable initializations : affecting the local variable attributes if (preTryInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, preTryInitStateIndex); } exceptionLabels[i].place(); codeStream.incrStackSize(1); // optimizing the case where the exception variable is not actually used LocalVariableBinding catchVar; int varPC = codeStream.position; if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) { codeStream.store(catchVar, false); catchVar.recordInitializationStartPC(codeStream.position); codeStream.addVisibleLocalVariable(catchVar); } else { codeStream.pop(); } codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart); // Keep track of the pcs at diverging point for computing the local attribute // since not passing the catchScope, the block generation will exitUserScope(catchScope) catchBlocks[i].generateCode(scope, codeStream); if (!catchExits[i]) { switch (finallyMode) { case FINALLY_SUBROUTINE: case FINALLY_MUST_BE_INLINED: requiresNaturalExit = true; // fall through case NO_FINALLY: codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE: codeStream.goto_(subRoutineStartLabel); break; } } } } this.exitAnyExceptionHandler(); // extra handler for trailing natural exit (will be fixed up later on when natural exit is // generated below) ExceptionLabel naturalExitExceptionHandler = finallyMode == FINALLY_SUBROUTINE && requiresNaturalExit ? new ExceptionLabel(codeStream, null) : null; // addition of a special handler so as to ensure that any uncaught exception (or exception // thrown // inside catch blocks) will run the finally block int finallySequenceStartPC = codeStream.position; if (subRoutineStartLabel != null) { this.placeAllAnyExceptionHandlers(); if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); if (preTryInitStateIndex != -1) { // reset initialization state, as for a normal catch block codeStream.removeNotDefinitelyAssignedVariables(currentScope, preTryInitStateIndex); } codeStream.incrStackSize(1); switch (finallyMode) { case FINALLY_SUBROUTINE: codeStream.store(anyExceptionVariable, false); codeStream.jsr(subRoutineStartLabel); codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); int position = codeStream.position; codeStream.load(anyExceptionVariable); codeStream.athrow(); codeStream.recordPositionsFrom(position, finallyBlock.sourceEnd); subRoutineStartLabel.place(); codeStream.incrStackSize(1); position = codeStream.position; codeStream.store(returnAddressVariable, false); codeStream.recordPositionsFrom(position, finallyBlock.sourceStart); finallyBlock.generateCode(scope, codeStream); position = codeStream.position; codeStream.ret(returnAddressVariable.resolvedPosition); // codeStream.updateLastRecordedEndPC(position); codeStream.recordPositionsFrom(position, finallyBlock.sourceEnd); // the ret bytecode is part of the subroutine break; case FINALLY_MUST_BE_INLINED: codeStream.store(anyExceptionVariable, false); codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); this.finallyBlock.generateCode(currentScope, codeStream); position = codeStream.position; codeStream.load(anyExceptionVariable); codeStream.athrow(); subRoutineStartLabel.place(); codeStream.recordPositionsFrom(position, finallyBlock.sourceEnd); break; case FINALLY_DOES_NOT_COMPLETE: codeStream.pop(); subRoutineStartLabel.place(); codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock.sourceStart); finallyBlock.generateCode(scope, codeStream); break; } // will naturally fall into subsequent code after subroutine invocation naturalExitLabel.place(); if (requiresNaturalExit) { switch (finallyMode) { case FINALLY_SUBROUTINE: int position = codeStream.position; // fix up natural exit handler naturalExitExceptionHandler.placeStart(); codeStream.jsr(subRoutineStartLabel); naturalExitExceptionHandler.placeEnd(); codeStream.recordPositionsFrom(position, finallyBlock.sourceEnd); break; case FINALLY_MUST_BE_INLINED: // May loose some local variable initializations : affecting the local variable // attributes // needed since any exception handler got inlined subroutine if (preTryInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, preTryInitStateIndex); } // entire sequence for finally is associated to finally block finallyBlock.generateCode(scope, codeStream); break; case FINALLY_DOES_NOT_COMPLETE: break; } } } else { // no subroutine, simply position end label (natural exit == end) naturalExitLabel.place(); } } else { // try block had no effect, only generate the body of the finally block if any if (subRoutineStartLabel != null) { finallyBlock.generateCode(scope, codeStream); } } // May loose some local variable initializations : affecting the local variable attributes if (mergedInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); } codeStream.recordPositionsFrom(pc, this.sourceStart); }
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { if (!valueRequired) currentScope.problemReporter().unusedObjectAllocation(this); int pc = codeStream.position; MethodBinding codegenBinding = this.binding.original(); ReferenceBinding allocatedType = codegenBinding.declaringClass; codeStream.new_(allocatedType); boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; if (valueRequired || isUnboxing) { codeStream.dup(); } // better highlight for allocation: display the type individually if (this.type != null) { // null for enum constant body codeStream.recordPositionsFrom(pc, this.type.sourceStart); } else { // push enum constant name and ordinal codeStream.ldc(String.valueOf(this.enumConstant.name)); codeStream.generateInlinedValue(this.enumConstant.binding.id); } // handling innerclass instance allocation - enclosing instance arguments if (allocatedType.isNestedType()) { codeStream.generateSyntheticEnclosingInstanceValues( currentScope, allocatedType, enclosingInstance(), this); } // generate the arguments for constructor generateArguments(this.binding, this.arguments, currentScope, codeStream); // handling innerclass instance allocation - outer local arguments if (allocatedType.isNestedType()) { codeStream.generateSyntheticOuterArgumentValues(currentScope, allocatedType, this); } // invoke constructor if (this.syntheticAccessor == null) { codeStream.invoke( Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */); } else { // synthetic accessor got some extra arguments appended to its signature, which need values for (int i = 0, max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length; i < max; i++) { codeStream.aconst_null(); } codeStream.invoke( Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */); } if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); } else if (isUnboxing) { // conversion only generated if unboxing codeStream.generateImplicitConversion(this.implicitConversion); switch (postConversionType(currentScope).id) { case T_long: case T_double: codeStream.pop2(); break; default: codeStream.pop(); } } codeStream.recordPositionsFrom(pc, this.sourceStart); }
/** Code generation for a array initializer */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { // Flatten the values and compute the dimensions, by iterating in depth into nested array // initializers int pc = codeStream.position; int expressionLength = (this.expressions == null) ? 0 : this.expressions.length; codeStream.generateInlinedValue(expressionLength); codeStream.newArray(this.binding); if (this.expressions != null) { // binding is an ArrayType, so I can just deal with the dimension int elementsTypeID = this.binding.dimensions > 1 ? -1 : this.binding.leafComponentType.id; for (int i = 0; i < expressionLength; i++) { Expression expr; if ((expr = this.expressions[i]).constant != Constant.NotAConstant) { switch (elementsTypeID) { // filter out initializations to default values case T_int: case T_short: case T_byte: case T_char: case T_long: if (expr.constant.longValue() != 0) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; case T_float: case T_double: double constantValue = expr.constant.doubleValue(); if (constantValue == -0.0 || constantValue != 0) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; case T_boolean: if (expr.constant.booleanValue() != false) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } break; default: if (!(expr instanceof NullLiteral)) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } } else if (!(expr instanceof NullLiteral)) { codeStream.dup(); codeStream.generateInlinedValue(i); expr.generateCode(currentScope, codeStream, true); codeStream.arrayAtPut(elementsTypeID, false); } } } if (valueRequired) { codeStream.generateImplicitConversion(this.implicitConversion); } else { codeStream.pop(); } codeStream.recordPositionsFrom(pc, this.sourceStart); }
/** * Try statement code generation with or without jsr bytecode use post 1.5 target level, cannot * use jsr bytecode, must instead inline finally block returnAddress is only allocated if jsr is * allowed */ public void generateCode(BlockScope currentScope, CodeStream codeStream) { if ((this.bits & ASTNode.IsReachable) == 0) { return; } boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; // in case the labels needs to be reinitialized // when the code generation is restarted in wide mode this.anyExceptionLabel = null; this.reusableJSRTargets = null; this.reusableJSRSequenceStartLabels = null; this.reusableJSRTargetsCount = 0; int pc = codeStream.position; int finallyMode = finallyMode(); boolean requiresNaturalExit = false; // preparing exception labels int maxCatches = this.catchArguments == null ? 0 : this.catchArguments.length; ExceptionLabel[] exceptionLabels; if (maxCatches > 0) { exceptionLabels = new ExceptionLabel[maxCatches]; for (int i = 0; i < maxCatches; i++) { ExceptionLabel exceptionLabel = new ExceptionLabel(codeStream, this.catchArguments[i].binding.type); exceptionLabel.placeStart(); exceptionLabels[i] = exceptionLabel; } } else { exceptionLabels = null; } if (this.subRoutineStartLabel != null) { this.subRoutineStartLabel.initialize(codeStream); enterAnyExceptionHandler(codeStream); } // generate the try block try { this.declaredExceptionLabels = exceptionLabels; this.tryBlock.generateCode(this.scope, codeStream); } finally { this.declaredExceptionLabels = null; } boolean tryBlockHasSomeCode = codeStream.position != pc; // flag telling if some bytecodes were issued inside the try block // place end positions of user-defined exception labels if (tryBlockHasSomeCode) { // natural exit may require subroutine invocation (if finally != null) BranchLabel naturalExitLabel = new BranchLabel(codeStream); BranchLabel postCatchesFinallyLabel = null; for (int i = 0; i < maxCatches; i++) { exceptionLabels[i].placeEnd(); } if ((this.bits & ASTNode.IsTryBlockExiting) == 0) { int position = codeStream.position; switch (finallyMode) { case FINALLY_SUBROUTINE: case FINALLY_INLINE: requiresNaturalExit = true; if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; case NO_FINALLY: if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE: codeStream.goto_(this.subRoutineStartLabel); break; } codeStream.updateLastRecordedEndPC(this.tryBlock.scope, position); // goto is tagged as part of the try block } /* generate sequence of handler, all starting by storing the TOS (exception thrown) into their own catch variables, the one specified in the source that must denote the handled exception. */ exitAnyExceptionHandler(); if (this.catchArguments != null) { postCatchesFinallyLabel = new BranchLabel(codeStream); for (int i = 0; i < maxCatches; i++) { /* * This should not happen. For consistency purpose, if the exception label is never used * we also don't generate the corresponding catch block, otherwise we have some * unreachable bytecodes */ if (exceptionLabels[i].count == 0) continue; enterAnyExceptionHandler(codeStream); // May loose some local variable initializations : affecting the local variable attributes if (this.preTryInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.preTryInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); } codeStream.pushExceptionOnStack(exceptionLabels[i].exceptionType); exceptionLabels[i].place(); // optimizing the case where the exception variable is not actually used LocalVariableBinding catchVar; int varPC = codeStream.position; if ((catchVar = this.catchArguments[i].binding).resolvedPosition != -1) { codeStream.store(catchVar, false); catchVar.recordInitializationStartPC(codeStream.position); codeStream.addVisibleLocalVariable(catchVar); } else { codeStream.pop(); } codeStream.recordPositionsFrom(varPC, this.catchArguments[i].sourceStart); // Keep track of the pcs at diverging point for computing the local attribute // since not passing the catchScope, the block generation will exitUserScope(catchScope) this.catchBlocks[i].generateCode(this.scope, codeStream); exitAnyExceptionHandler(); if (!this.catchExits[i]) { switch (finallyMode) { case FINALLY_INLINE: // inlined finally here can see all merged variables if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream) .pushStateIndex(this.naturalExitMergeInitStateIndex); } if (this.catchExitInitStateIndexes[i] != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.catchExitInitStateIndexes[i]); codeStream.addDefinitelyAssignedVariables( currentScope, this.catchExitInitStateIndexes[i]); } // entire sequence for finally is associated to finally block this.finallyBlock.generateCode(this.scope, codeStream); codeStream.goto_(postCatchesFinallyLabel); if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream).popStateIndex(); } break; case FINALLY_SUBROUTINE: requiresNaturalExit = true; // $FALL-THROUGH$ case NO_FINALLY: if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE: codeStream.goto_(this.subRoutineStartLabel); break; } } } } // extra handler for trailing natural exit (will be fixed up later on when natural exit is // generated below) ExceptionLabel naturalExitExceptionHandler = requiresNaturalExit && (finallyMode == FINALLY_SUBROUTINE) ? new ExceptionLabel(codeStream, null) : null; // addition of a special handler so as to ensure that any uncaught exception (or exception // thrown // inside catch blocks) will run the finally block int finallySequenceStartPC = codeStream.position; if (this.subRoutineStartLabel != null && this.anyExceptionLabel.count != 0) { codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); if (this.preTryInitStateIndex != -1) { // reset initialization state, as for a normal catch block codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); } placeAllAnyExceptionHandler(); if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); switch (finallyMode) { case FINALLY_SUBROUTINE: // any exception handler codeStream.store(this.anyExceptionVariable, false); codeStream.jsr(this.subRoutineStartLabel); codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); int position = codeStream.position; codeStream.throwAnyException(this.anyExceptionVariable); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); // subroutine this.subRoutineStartLabel.place(); codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); position = codeStream.position; codeStream.store(this.returnAddressVariable, false); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceStart); this.finallyBlock.generateCode(this.scope, codeStream); position = codeStream.position; codeStream.ret(this.returnAddressVariable.resolvedPosition); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); // the ret bytecode is part of the subroutine break; case FINALLY_INLINE: // any exception handler codeStream.store(this.anyExceptionVariable, false); codeStream.addVariable(this.anyExceptionVariable); codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); // subroutine this.finallyBlock.generateCode(currentScope, codeStream); position = codeStream.position; codeStream.throwAnyException(this.anyExceptionVariable); codeStream.removeVariable(this.anyExceptionVariable); if (this.preTryInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.preTryInitStateIndex); } this.subRoutineStartLabel.place(); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); break; case FINALLY_DOES_NOT_COMPLETE: // any exception handler codeStream.pop(); this.subRoutineStartLabel.place(); codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); // subroutine this.finallyBlock.generateCode(this.scope, codeStream); break; } // will naturally fall into subsequent code after subroutine invocation if (requiresNaturalExit) { switch (finallyMode) { case FINALLY_SUBROUTINE: naturalExitLabel.place(); int position = codeStream.position; naturalExitExceptionHandler.placeStart(); codeStream.jsr(this.subRoutineStartLabel); naturalExitExceptionHandler.placeEnd(); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); break; case FINALLY_INLINE: // inlined finally here can see all merged variables if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream) .pushStateIndex(this.naturalExitMergeInitStateIndex); } if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables( currentScope, this.naturalExitMergeInitStateIndex); } naturalExitLabel.place(); // entire sequence for finally is associated to finally block this.finallyBlock.generateCode(this.scope, codeStream); if (postCatchesFinallyLabel != null) { position = codeStream.position; // entire sequence for finally is associated to finally block codeStream.goto_(postCatchesFinallyLabel); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); } if (isStackMapFrameCodeStream) { ((StackMapFrameCodeStream) codeStream).popStateIndex(); } break; case FINALLY_DOES_NOT_COMPLETE: break; default: naturalExitLabel.place(); break; } } if (postCatchesFinallyLabel != null) { postCatchesFinallyLabel.place(); } } else { // no subroutine, simply position end label (natural exit == end) naturalExitLabel.place(); } } else { // try block had no effect, only generate the body of the finally block if any if (this.subRoutineStartLabel != null) { this.finallyBlock.generateCode(this.scope, codeStream); } } // May loose some local variable initializations : affecting the local variable attributes if (this.mergedInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); } codeStream.recordPositionsFrom(pc, this.sourceStart); }