// Copyright (c) 1995 David Engberg All rights reserved // $Id: Statement.C,v 1.16 1998/04/12 22:17:13 geppetto Exp $ #pragma implementation #include "Statement.h" #include "Expression.h" #include "VariableDeclaration.h" #include "JavaAccessFlags.h" #include "parser_decls.h" #include "CompileError.h" #include "JavaClassFile.h" #include "JavaMethodInfo.h" #include "JavaCodeAttribute.h" #include "Compiler.h" #include "CompileContext.h" #include "CodeSequence.h" #include // // Method name : CStatement // Description : Default constructor. Read the comment for CExpression() for // my lame attempt at justifying accessing the 'yylineno' variable like // this. // CStatement::CStatement() : fLineNumber(yylineno) { } // // Method name : ~CStatement // Description : Destructor // CStatement::~CStatement() { } // // Method name : MakeError // Description : This provides a convenient hook for children of CStatement // to create compiler errors from just a string. // CCompileError* CStatement::MakeError(const unicode_string& message) { return new CCompileError(message, fLineNumber); } // // Method name : MakeError // Description : This provides a convenient hook for children of CStatement // to create compiler errors from just a string. // CCompileError* CStatement::MakeError(const string& message) { return new CCompileError(::StringToUnicode(message), fLineNumber); } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CStatement::GenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; if (context.IsReachable()) { error = HandleGenerateCode(code, context, stackUsed); } else { error = MakeError("Code cannot be reached."); } return error; } //=========================== CExpressionStatement ============================ // // Method name : CExpressionStatement // Description : Constructs a CExpressionStatement out of an adopted // expression. // CExpressionStatement::CExpressionStatement(CExpression* adoptExpression) : fExpression(adoptExpression) { } // // Method name : ~CExpressionStatement // Description : Destructor. // CExpressionStatement::~CExpressionStatement() { delete fExpression; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CExpressionStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fExpression != 0); stackUsed = 0; CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fExpression, context, type); if (error == 0) { error = fExpression->GenerateCode(code, context, stackUsed, true); } return error; } //============================ CCompoundStatement ============================= // // Method name : CCompoundStatement // Description : Constructs a CCompoundStatement from an adopted list of // sub-statements. // CCompoundStatement::CCompoundStatement(StatementList* adoptStatements) : fChildren(adoptStatements) { if (fChildren == 0) { fChildren = new StatementList; } } // // Method name : ~CCompoundStatement // Description : Destructor. // CCompoundStatement::~CCompoundStatement() { for (StatementList::iterator i = fChildren->begin(); i != fChildren->end(); ++i) { delete *i; } delete fChildren; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CCompoundStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fChildren != 0); CCompileError* error = 0; stackUsed = 0; for (StatementList::iterator i = fChildren->begin(); error == 0 && i != fChildren->end(); ++i) { unsigned short childStack; assert(*i != 0); error = (*i)->GenerateCode(code, context, childStack); if (childStack > stackUsed) { stackUsed = childStack; } } return error; } //=========================== CDeclarationStatement =========================== // // Method name : CDeclarationStatement // Description : Constructs a CDeclarationStatement out of a list of single // variable declarations. // CDeclarationStatement::CDeclarationStatement( deque* adoptDeclarations, CJavaAccessFlags* modifiers, bool deprecated) : fDeclarations(adoptDeclarations), fModifiers(modifiers), fDeprecated(deprecated) { if (fDeclarations == 0) { fDeclarations = new deque; } if (fModifiers == 0) { fModifiers = new CJavaAccessFlags; } } // // Method name : ~CDeclarationStatement // Description : Destructor. // CDeclarationStatement::~CDeclarationStatement() { for (deque::iterator i = fDeclarations->begin(); i != fDeclarations->end(); ++i) { delete *i; } delete fDeclarations; delete fModifiers; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CDeclarationStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fDeclarations != 0 && fModifiers != 0); CCompileError* error = 0; stackUsed = 0; CJavaTypeSignature type; for (deque::iterator i = fDeclarations->begin(); error == 0 && i != fDeclarations->end(); ++i) { unsigned short stack; error = (*i)->GenerateCode(code, context, *fModifiers, stack); stackUsed = ::max(stackUsed, stack); } return error; } //=============================== CIfStatement ================================ // // Method name : CIfStatement // Description : Constructs a CIfStatement from its parts // CIfStatement::CIfStatement(CExpression* condition, CStatement* thenClause, CStatement* elseClause) : fCondition(condition), fThenClause(thenClause), fElseClause(elseClause) { } // // Method name : ~CIfStatement // Description : Destructor. // CIfStatement::~CIfStatement() { delete fCondition; delete fThenClause; delete fElseClause; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CIfStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fCondition != 0); CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fCondition, context, type); if (error == 0 && type != CJavaTypeSignature::kBoolean) { error = MakeError("Non-boolean value used as 'if' conditional."); } COrdinalLiteral* literal = DYNAMIC_CAST(COrdinalLiteral, fCondition); if (error == 0 && literal != 0) { stackUsed = 0; if (literal->GetBoolean()) { if (fThenClause != 0) { error = fThenClause->GenerateCode(code, context, stackUsed); } } else if (fElseClause != 0) { error = fElseClause->GenerateCode(code, context, stackUsed); } } else if (error == 0) { error = fCondition->GenerateCode(code, context, stackUsed, false); if (error == 0) { unsigned long branchInstruction = code.size(); unsigned short stack = 0; CCompileContext elseContext = context; if (fThenClause == 0 && fElseClause == 0) { code.Append(CJavaCodeAttribute::pop, fLineNumber); } else if (fThenClause != 0 && fElseClause != 0) { // Have both a non-empty 'then' and 'else' part. code.Append(CJavaCodeAttribute::ifeq, fCondition->GetLineNumber()); error = fThenClause->GenerateCode(code, context, stack); stackUsed = ::max(stack, stackUsed); unsigned long thenBranchInstruction = 0; if (context.IsReachable()) { thenBranchInstruction = code.size(); code.Append(CJavaCodeAttribute::op_goto, fThenClause->GetLineNumber()); } code[branchInstruction].fArguments.u4 = code.CreateBlockLabel(); if (error == 0) { error = fElseClause->GenerateCode(code, elseContext, stack); if (context.IsReachable()) { code[thenBranchInstruction].fArguments.u4 = code.CreateBlockLabel(); } } } else { CStatement* onlyClause = 0; if (fThenClause != 0) { // only has a non-empty 'then' part onlyClause = fThenClause; code.Append(CJavaCodeAttribute::ifeq, fCondition->GetLineNumber()); } else { // only has a non-empty 'else' part onlyClause = fElseClause; code.Append(CJavaCodeAttribute::ifne, fCondition->GetLineNumber()); } error = onlyClause->GenerateCode(code, context, stack); code[branchInstruction].fArguments.u4 = code.CreateBlockLabel(); } stackUsed = ::max(stack, stackUsed); context.Merge(elseContext); } } return error; } //============================== CWhileStatement ============================== // // Method name : CWhileStatement // Description : Constructs a CWhileStatement // CWhileStatement::CWhileStatement(CStatement* adoptLoop, CExpression* adoptCondition) : fLoopStatement(adoptLoop), fCondition(adoptCondition) { } // // Method name : ~CWhileStatement // Description : Destructor. // CWhileStatement::~CWhileStatement() { delete fLoopStatement; delete fCondition; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CWhileStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; assert(fCondition != 0); CJavaTypeSignature type; error = CExpression::EvaluateType(fCondition, context, type); if (error == 0) { if (type != CJavaTypeSignature::kBoolean) { error = MakeError("Non-boolean value used as 'while' conditional."); } else { COrdinalLiteral* boolLiteral = DYNAMIC_CAST(COrdinalLiteral, fCondition); unsigned long conditionalBase = code.CreateBlockLabel(); unsigned long branchInstruction; stackUsed = 0; bool reachableBody = true; if (boolLiteral != 0) { if (!boolLiteral->GetBoolean()) { reachableBody = false; } } else { error = fCondition->GenerateCode(code, context, stackUsed); branchInstruction = code.size(); code.Append(CJavaCodeAttribute::ifeq, fCondition->GetLineNumber()); } if (error == 0 && fLoopStatement != 0 && reachableBody) { CCompileContext bodyContext = context; unsigned short bodyStack; bodyContext.GetCompiler().PushStatementContext(this); error = fLoopStatement->GenerateCode(code, bodyContext, bodyStack); stackUsed = ::max(stackUsed, bodyStack); bodyContext.GetCompiler().PopStatementContext(); } if (error == 0 && reachableBody) { code.Append(CJavaCodeAttribute::op_goto, conditionalBase, fCondition->GetLineNumber()); } unsigned long endLabel = code.CreateBlockLabel(); if (boolLiteral != 0) { if (boolLiteral->GetBoolean()) { context.SetUnreachable(); } } else { code[branchInstruction].fArguments.u4 = endLabel; } for (list::iterator i = fNestedContinues.begin(); !(i == fNestedContinues.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = conditionalBase; } for (list::iterator i = fNestedBreaks.begin(); !(i == fNestedBreaks.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = endLabel; context.Merge((*i).GetContext()); } } } return error; } // // Method name : RegisterContinueBranch // Description : This method tells the loop construct that a continue // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CWhileStatement::RegisterContinueBranch(const CNonlocalBranch& instruction) { fNestedContinues.push_front(instruction); } // // Method name : RegisterBreakBranch // Description : This method tells the loop construct that a break // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CWhileStatement::RegisterBreakBranch(const CNonlocalBranch& instruction) { fNestedBreaks.push_front(instruction); } //============================== CDoStatement ============================== // // Method name : CDoStatement // Description : Constructs a CDoStatement // CDoStatement::CDoStatement(CStatement* adoptLoop, CExpression* adoptCondition) : fLoopStatement(adoptLoop), fCondition(adoptCondition) { } // // Method name : ~CDoStatement // Description : Destructor. // CDoStatement::~CDoStatement() { delete fLoopStatement; delete fCondition; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CDoStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; assert(fCondition != 0); unsigned long baseBodyInstruction = code.CreateBlockLabel(); if (fLoopStatement != 0) { context.GetCompiler().PushStatementContext(this); error = fLoopStatement->GenerateCode(code, context, stackUsed); context.GetCompiler().PopStatementContext(); } if (error == 0) { CJavaTypeSignature type; error = CExpression::EvaluateType(fCondition, context, type); if (error == 0 && type != CJavaTypeSignature::kBoolean) { error = MakeError("Non-boolean value used as 'do-while' conditional."); } } if (!fNestedContinues.empty()) { unsigned long beforeCondition = code.CreateBlockLabel(); for (list::iterator i = fNestedContinues.begin(); !(i == fNestedContinues.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = beforeCondition; } } if (error == 0) { unsigned short conditionStack; error = fCondition->GenerateCode(code, context, conditionStack); stackUsed = ::max(stackUsed, conditionStack); code.Append(CJavaCodeAttribute::ifne, baseBodyInstruction, fCondition->GetLineNumber()); } if (!fNestedBreaks.empty()) { unsigned long afterLoop = code.CreateBlockLabel(); for (list::iterator i = fNestedBreaks.begin(); !(i == fNestedBreaks.end()); ++i) { context.Merge((*i).GetContext()); unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = afterLoop; } } return error; } // // Method name : RegisterContinueBranch // Description : This method tells the loop construct that a continue // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CDoStatement::RegisterContinueBranch(const CNonlocalBranch& instruction) { fNestedContinues.push_front(instruction); } // // Method name : RegisterBreakBranch // Description : This method tells the loop construct that a break // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CDoStatement::RegisterBreakBranch(const CNonlocalBranch& instruction) { fNestedBreaks.push_front(instruction); } //============================== CReturnStatement ============================= // // Method name : CReturnStatement // Description : Constructs a CReturnStatement that will return the given // value (if one is provided). // CReturnStatement::CReturnStatement(CExpression* returnValue) : fValue(returnValue) { } // // Method name : ~CReturnStatement // Description : Destructor. // CReturnStatement::~CReturnStatement() { delete fValue; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CReturnStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; CCompiler::FinallyHandlerStack::iterator finallyIterator = context.GetCompiler().GetHandlerBegin(); CCompiler::FinallyHandlerStack::iterator finallyEnd = context.GetCompiler().GetHandlerEnd(); for (; finallyIterator != finallyEnd; ++finallyIterator) { code.Append(CJavaCodeAttribute::jsr, *finallyIterator, fLineNumber); } CJavaTypeSignature returnType = context.GetMethod().GetSignature().GetType(); if (fValue == 0) { if (returnType != CJavaTypeSignature::kVoid) { error = MakeError("Invalid empty return from non-void function."); } else { code.Append(CJavaCodeAttribute::op_return, fLineNumber); } stackUsed = 0; } else { CJavaTypeSignature type; error = CExpression::EvaluateType(fValue, context, type); if (error == 0) { if (!context.GetCompiler().SameType(returnType, type)) { error = CCastExpression::ImplicitCastPointer(fValue, returnType, context); } if (error == 0) { error = fValue->GenerateCode(code, context, stackUsed, false); } if (error == 0) { if (returnType.IsReference()) { code.Append(CJavaCodeAttribute::areturn, fValue->GetLineNumber()); } else { switch (returnType.GetBaseType()) { case CJavaTypeSignature::Double: code.Append(CJavaCodeAttribute::dreturn, fValue->GetLineNumber()); break; case CJavaTypeSignature::LongInteger: code.Append(CJavaCodeAttribute::lreturn, fValue->GetLineNumber()); break; case CJavaTypeSignature::Float: code.Append(CJavaCodeAttribute::freturn, fValue->GetLineNumber()); break; case CJavaTypeSignature::Integer: case CJavaTypeSignature::Byte: case CJavaTypeSignature::Character: case CJavaTypeSignature::Short: case CJavaTypeSignature::Boolean: code.Append(CJavaCodeAttribute::ireturn, fValue->GetLineNumber()); break; case CJavaTypeSignature::Void: error = MakeError("Invalid value returned from method declared 'void'"); break; default: assert(0); } } } } } context.SetUnreachable(); return error; } //============================== CBranchStatement ============================= // // Method name : CBranchStatement // Description : Constructs a CBranchStatement // CBranchStatement::CBranchStatement(CBranchStatement::Type type, unicode_string* label) : fBranchType(type), fToLabel(label) { } // // Method name : ~CBranchStatement // Description : Destructor. // CBranchStatement::~CBranchStatement() { delete fToLabel; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CBranchStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& compileContext, unsigned short& stackUsed) { stackUsed = 0; CCompileError* error = 0; StatementList::iterator context = compileContext.GetCompiler().GetContextBegin(); StatementList::iterator contextEnd = compileContext.GetCompiler().GetContextEnd(); for (; error == 0 && context != contextEnd; ++context) { CTryStatement* tryStatement = DYNAMIC_CAST(CTryStatement, *context); if (tryStatement != 0) { tryStatement->EmitFinallyCall(code); } CSynchronized* synchronized = DYNAMIC_CAST(CSynchronized, *context); if (synchronized != 0) { synchronized->EmitMonitorExitCode(code); } CNonlocalBranch thisBranch(code.size(), compileContext); if (fToLabel != 0) { CLabelStatement* label = DYNAMIC_CAST(CLabelStatement, *context); if (label != 0 && label->GetLabel() != 0 && *label->GetLabel() == *fToLabel) { code.Append(CJavaCodeAttribute::op_goto, fLineNumber); if (fBranchType == kBreak) { label->RegisterBreakBranch(thisBranch); break; } else { CStatement* labelChild = label->GetChildStatement(); assert(labelChild != 0); CWhileStatement* whileStatement = DYNAMIC_CAST(CWhileStatement, labelChild); CDoStatement* doStatement = DYNAMIC_CAST(CDoStatement, labelChild); CForStatement* forStatement = DYNAMIC_CAST(CForStatement, labelChild); if (whileStatement != 0) { whileStatement->RegisterContinueBranch(thisBranch); break; } else if (doStatement != 0) { doStatement->RegisterContinueBranch(thisBranch); break; } else if (forStatement != 0) { forStatement->RegisterContinueBranch(thisBranch); break; } else { error = MakeError("Invalid 'continue' to non-loop statement."); } } } } else { if (fBranchType == kBreak) { CSwitch* switchStatement = DYNAMIC_CAST(CSwitch, *context); if (switchStatement != 0) { switchStatement->RegisterBreakBranch(thisBranch); code.Append(CJavaCodeAttribute::op_goto, fLineNumber); break; } } CWhileStatement* whileStatement = DYNAMIC_CAST(CWhileStatement, *context); if (whileStatement != 0) { if (fBranchType == kBreak) { whileStatement->RegisterBreakBranch(thisBranch); } else { whileStatement->RegisterContinueBranch(thisBranch); } code.Append(CJavaCodeAttribute::op_goto, fLineNumber); break; } CDoStatement* doStatement = DYNAMIC_CAST(CDoStatement, *context); if (doStatement != 0) { if (fBranchType == kBreak) { doStatement->RegisterBreakBranch(thisBranch); } else { doStatement->RegisterContinueBranch(thisBranch); } code.Append(CJavaCodeAttribute::op_goto, fLineNumber); break; } CForStatement* forStatement = DYNAMIC_CAST(CForStatement, *context); if (forStatement != 0) { if (fBranchType == kBreak) { forStatement->RegisterBreakBranch(thisBranch); } else { forStatement->RegisterContinueBranch(thisBranch); } code.Append(CJavaCodeAttribute::op_goto, fLineNumber); break; } } } if (error == 0 && context == contextEnd) { if (fBranchType == kBreak) { error = MakeError("Invalid 'break' statement without matching loop."); } else { error = MakeError("Invalid 'continue' statement outside loop."); } } compileContext.SetUnreachable(); return error; } //=============================== CForStatement =============================== // // Method name : CForStatement // Description : Constructs a CForStatement // CForStatement::CForStatement(CStatement* initializer, CExpression* conditional, ExpressionList* incrementor, CStatement* body) : fInitializer(initializer), fConditional(conditional), fIncrementor(incrementor), fBody(body) { } // // Method name : ~CForStatement // Description : Destructor. // CForStatement::~CForStatement() { delete fInitializer; delete fConditional; delete fBody; if (fIncrementor != 0) { for (ExpressionList::iterator i = fIncrementor->begin(); i != fIncrementor->end(); ++i) { delete *i; } delete fIncrementor; } } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CForStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; stackUsed = 0; if (fInitializer != 0) { error = fInitializer->GenerateCode(code, context, stackUsed); } if (error == 0 && fConditional != 0) { CJavaTypeSignature type; error = CExpression::EvaluateType(fConditional, context, type); if (error == 0 && type != CJavaTypeSignature::kBoolean) { error = MakeError("Non-boolean value used as 'for' conditional."); } } unsigned long conditionalBase = code.CreateBlockLabel(); unsigned long branchInstruction; if (error == 0 && fConditional != 0) { unsigned short conditionStack; error = fConditional->GenerateCode(code, context, conditionStack); stackUsed = ::max(stackUsed, conditionStack); branchInstruction = code.size(); code.Append(CJavaCodeAttribute::ifeq, fConditional->GetLineNumber()); } CCompileContext bodyContext = context; if (error == 0 && fBody != 0) { unsigned short bodyStack; bodyContext.GetCompiler().PushStatementContext(this); error = fBody->GenerateCode(code, bodyContext, bodyStack); stackUsed = ::max(stackUsed, bodyStack); bodyContext.GetCompiler().PopStatementContext(); } if (!fNestedContinues.empty()) { unsigned long beforeIncrementor = code.CreateBlockLabel(); for (list::iterator i = fNestedContinues.begin(); !(i == fNestedContinues.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = beforeIncrementor; bodyContext.Merge((*i).GetContext()); } } if (error == 0 && fIncrementor != 0) { for (ExpressionList::iterator i = fIncrementor->begin(); error == 0 && i != fIncrementor->end(); ++i) { CJavaTypeSignature type; error = CExpression::EvaluateType(*i, bodyContext, type); if (error == 0) { unsigned short incrementorStack; error = (*i)->GenerateCode(code, bodyContext, incrementorStack, true); stackUsed = ::max(stackUsed, incrementorStack); } } } code.Append(CJavaCodeAttribute::op_goto, conditionalBase, fLineNumber); unsigned long endLabel = code.CreateBlockLabel(); if (error == 0) { if (fConditional != 0) { code[branchInstruction].fArguments.u4 = endLabel; } else { context.SetUnreachable(); } } for (list::iterator i = fNestedBreaks.begin(); !(i == fNestedBreaks.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = endLabel; context.Merge((*i).GetContext()); } return error; } // // Method name : RegisterContinueBranch // Description : This method tells the loop construct that a continue // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CForStatement::RegisterContinueBranch(const CNonlocalBranch& instruction) { fNestedContinues.push_front(instruction); } // // Method name : RegisterBreakBranch // Description : This method tells the loop construct that a break // statement was found in its body and gives the loop the location of the // 'goto' code in the instruction block. The loop is then responsible for // adjusting the target of the 'goto' to jump to the right location. // void CForStatement::RegisterBreakBranch(const CNonlocalBranch& instruction) { fNestedBreaks.push_front(instruction); } //============================== CThrowStatement ============================= // // Method name : CThrowStatement // Description : Constructs a CThrowStatement that will throw the given // value. // CThrowStatement::CThrowStatement(CExpression* throwValue) : fValue(throwValue) { } // // Method name : ~CThrowStatement // Description : Destructor. // CThrowStatement::~CThrowStatement() { delete fValue; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CThrowStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fValue, context, type); if (error == 0 && !context.GetCompiler().IsThrowable(type)) { error = MakeError("Attempt to throw a non-throwable value."); } else if (!context.Throwable(type)) { unicode_string message = type.Disassemble(); message += ::UTFToUnicode(" must be caught or declared in this method's " " 'throws' list."); error = MakeError(message); } if (error == 0) { error = fValue->GenerateCode(code, context, stackUsed, false); } code.Append(CJavaCodeAttribute::athrow, fValue->GetLineNumber()); context.SetUnreachable(); return error; } //=============================== CSynchronized =============================== // // Method name : CSynchronized // Description : Constructs a CSynchronized statement block. // CSynchronized::CSynchronized(CExpression* adoptCondition, CStatement* adoptBlock, unsigned short synchronizeVariable) : fCondition(adoptCondition), fBlock(adoptBlock), fSynchronizeVariable(synchronizeVariable) { } // // Method name : ~CSynchronized // Description : Destructor. // CSynchronized::~CSynchronized() { delete fCondition; delete fBlock; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CSynchronized::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fCondition != 0 && fBlock != 0); CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fCondition, context, type); if (error == 0 && !type.IsReference()) { error = MakeError("'synchronized' used with non-reference expression"); } if (error == 0) { error = fCondition->GenerateCode(code, context, stackUsed, false); } if (error == 0) { code.Append(CJavaCodeAttribute::astore, fSynchronizeVariable, fLineNumber); code.Append(CJavaCodeAttribute::aload, fSynchronizeVariable, fLineNumber); code.Append(CJavaCodeAttribute::monitorenter, fLineNumber); CJavaCodeAttribute::ExceptionInfo* tempException = new CJavaCodeAttribute::ExceptionInfo(); tempException->fStartPC = code.CreateBlockLabel(); unsigned short blockStack; context.GetCompiler().PushStatementContext(this); error = fBlock->GenerateCode(code, context, blockStack); stackUsed = ::max(stackUsed, blockStack); context.GetCompiler().PopStatementContext(); tempException->fEndPC = code.CreateBlockLabel(); EmitMonitorExitCode(code); unsigned long gotoInstruction = code.size(); code.Append(CJavaCodeAttribute::op_goto, fLineNumber); CJavaCodeAttribute* codeAttribute = context.GetMethod().GetCode(); assert(codeAttribute != 0); tempException->fHandlerPC = code.CreateBlockLabel(); tempException->fCatchType = 0; codeAttribute->AddExceptionHandler(tempException); EmitMonitorExitCode(code); code.Append(CJavaCodeAttribute::athrow, fLineNumber); code[gotoInstruction].fArguments.u4 = code.CreateBlockLabel(); } return error; } // // Method name : EmitMonitorExitCode // Description : This method is used to append code necessary to clean up // the monitor created by this synchronized statement. // void CSynchronized::EmitMonitorExitCode(CCodeSequence& code) { code.Append(CJavaCodeAttribute::aload, fSynchronizeVariable, fLineNumber); code.Append(CJavaCodeAttribute::monitorexit, fLineNumber); } //============================== CLabelStatement ============================== // // Method name : CLabelStatement // Description : Constructs a CLabelStatement for a labelled jump. // CLabelStatement::CLabelStatement(unicode_string* label, CStatement* adoptStatement) : fLabel(label), fCaseExpression(0), fStatement(adoptStatement), fType(kLabel) { } // // Method name : CLabelStatement // Description : Constructs a CLabelStatement for a 'default' statement // CLabelStatement::CLabelStatement(CStatement* adoptDefault) : fLabel(0), fCaseExpression(0), fStatement(adoptDefault), fType(kDefault) { } // // Method name : CLabelStatement // Description : Constructs a CLabelStatement for a 'case' statement // CLabelStatement::CLabelStatement(CExpression* caseExpression, CStatement* adoptCase) : fLabel(0), fCaseExpression(caseExpression), fStatement(adoptCase), fType(kCase) { } // // Method name : ~CLabelStatement // Description : Destructor. // CLabelStatement::~CLabelStatement() { delete fLabel; delete fCaseExpression; delete fStatement; } // // Method name : GetLabel // Description : Retrieves the label that is applied using this label // statement and returns it to the user. If this is a case or default // label, 0 is returned. // const unicode_string* CLabelStatement::GetLabel() const { return fLabel; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CLabelStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { CCompileError* error = 0; stackUsed = 0; if (fStatement != 0) { context.GetCompiler().PushStatementContext(this); error = fStatement->GenerateCode(code, context, stackUsed); context.GetCompiler().PopStatementContext(); } if (!fNestedBreaks.empty()) { unsigned long endLabel = code.CreateBlockLabel(); for (list::iterator i = fNestedBreaks.begin(); !(i == fNestedBreaks.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = endLabel; context.Merge((*i).GetContext()); } } return error; } // // Method name : RegisterBreakBranch // Description : This method tells the label construct that a break // statement was found in its body and gives this statement the location // of the 'goto' code in the instruction block. The label is then // responsible for adjusting the target of the 'goto' to jump to the right // location. // void CLabelStatement::RegisterBreakBranch(const CNonlocalBranch& instruction) { fNestedBreaks.push_front(instruction); } //============================== CTryStatement ============================== // // Method name : CTryStatement // Description : Constructs a CTryStatement // CTryStatement::CTryStatement(CCompoundStatement* TryBlock, deque* catchClauses, CCompoundStatement* finally, unsigned short finallyHandlerVariable, unsigned short finallySubroutineVariable) : fTryBlock(TryBlock), fCatchList(catchClauses), fFinally(finally), fFinallyHandlerVariable(finallyHandlerVariable), fFinallySubroutineVariable(finallySubroutineVariable), fFinallySubroutineLocation(0) { if (fCatchList == 0) { fCatchList = new deque; } } // // Method name : ~CTryStatement // Description : Destructor. // CTryStatement::~CTryStatement() { delete fTryBlock; delete fFinally; for (deque::iterator i = fCatchList->begin(); i != fCatchList->end(); ++i) { delete *i; } delete fCatchList; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CTryStatement::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fTryBlock != 0 && fCatchList != 0); stackUsed = 0; CCompileError* error = 0; CCompileContext inContext = context; unsigned long handlerInstruction; if (fFinally != 0) { // goto to skip over the 'finally' handler & subroutine unsigned long gotoInstruction = code.size(); code.Append(CJavaCodeAttribute::op_goto, fLineNumber); // exception handler code to call 'finally' handlerInstruction = code.CreateBlockLabel(); code.Append(CJavaCodeAttribute::astore, fFinallyHandlerVariable, fLineNumber); unsigned long jsrInstruction = code.size(); code.Append(CJavaCodeAttribute::jsr, fLineNumber); code.Append(CJavaCodeAttribute::aload, fFinallyHandlerVariable, fLineNumber); code.Append(CJavaCodeAttribute::athrow, fLineNumber); // 'finally' subroutine code fFinallySubroutineLocation = code.CreateBlockLabel(); code[jsrInstruction].fArguments.u4 = fFinallySubroutineLocation; context.GetCompiler().PushFinallyHandler(fFinallySubroutineLocation); code.Append(CJavaCodeAttribute::astore, fFinallySubroutineVariable, fLineNumber); error = fFinally->GenerateCode(code, context, stackUsed); stackUsed = ::max(stackUsed, (unsigned short)1); code.Append(CJavaCodeAttribute::ret, fFinallySubroutineVariable, fLineNumber); code[gotoInstruction].fArguments.u4 = code.CreateBlockLabel(); } // stick in the part of the code enclosed by the try { ... } clause inContext.GetCompiler().PushStatementContext(this); unsigned long startTryBlock = code.CreateBlockLabel(); if (error == 0) { for (deque::iterator i = fCatchList->begin(); !(i == fCatchList->end()); ++i) { context.PushThrowable(inContext.GetCompiler().FixType((*i)->fCatchType)); } unsigned short tryStack; error = fTryBlock->GenerateCode(code, context, tryStack); for (int i = 0; i < fCatchList->size(); ++i) { context.PopThrowable(); } stackUsed = ::max(tryStack, stackUsed); } unsigned long endTryBlock = code.CreateBlockLabel(); if (context.IsReachable()) { EmitFinallyCall(code); } // now stick in the code needed for each of the 'catch' clauses... CJavaCodeAttribute* codeAttribute = context.GetMethod().GetCode(); assert(codeAttribute != 0); if (fCatchList->size() > 0) { stackUsed = ::max(stackUsed, (unsigned short)1); unsigned long gotoInstruction = code.size(); code.Append(CJavaCodeAttribute::op_goto, fLineNumber); for (deque::iterator i = fCatchList->begin(); error == 0 && !(i == fCatchList->end()); ++i) { assert((*i) != 0 && (*i)->fBlock != 0); assert((*i)->fCatchType.IsReference()); unicode_string className; inContext.GetCompiler().FixType((*i)->fCatchType).GetBaseClassName( className); unsigned short exceptionClassIndex = inContext.GetClass().AddClassConstant(className); CJavaCodeAttribute::ExceptionInfo* tempException = new CJavaCodeAttribute::ExceptionInfo(); tempException->fStartPC = startTryBlock; tempException->fEndPC = endTryBlock; tempException->fHandlerPC = code.CreateBlockLabel(); tempException->fCatchType = exceptionClassIndex; codeAttribute->AddExceptionHandler(tempException); unsigned short variable = (*i)->fExceptionVariable; code.Append(CJavaCodeAttribute::astore, variable, fLineNumber); unsigned short catchStack; CCompileContext catchContext = inContext; catchContext.InitializeVariable((*i)->fExceptionVariable); error = (*i)->fBlock->GenerateCode(code, catchContext, catchStack); stackUsed = ::max(stackUsed, catchStack); if (catchContext.IsReachable()) { EmitFinallyCall(code); code.Append(CJavaCodeAttribute::op_goto, endTryBlock, fLineNumber); } context.Merge(catchContext); } code[gotoInstruction].fArguments.u4 = code.CreateBlockLabel(); } context.GetCompiler().PopStatementContext(); if (fFinally != 0) { context.GetCompiler().PopFinallyHandler(); CJavaCodeAttribute::ExceptionInfo* tempException = new CJavaCodeAttribute::ExceptionInfo(); tempException->fStartPC = startTryBlock; tempException->fEndPC = code.CreateBlockLabel(); tempException->fHandlerPC = handlerInstruction; tempException->fCatchType = 0; codeAttribute->AddExceptionHandler(tempException); } return error; } // // Method name : EmitFinallyCall // Description : This method is used to append a call to the 'finally' clause // for this 'try' statement onto the end of the provided string. If // this try block doesn't contain a 'finally', then no code is emitted. // void CTryStatement::EmitFinallyCall(CCodeSequence& code) { if (fFinally != 0) { code.Append(CJavaCodeAttribute::jsr, fFinallySubroutineLocation, fLineNumber); } } // // Method name : CCatchClause // Description : Constructs a catch clause for a Try statement // CCatchClause::CCatchClause(unsigned short variableIndex, const CJavaTypeSignature& catchType, CCompoundStatement* block) : fExceptionVariable(variableIndex), fCatchType(catchType), fBlock(block) { } // // Method name : ~CCatchClause // Description : Destructor. // CCatchClause::~CCatchClause() { delete fBlock; } //================================== CSwitch ================================== // // Method name : CSwitch // Description : Constructs a CSwitch statement from the expression that // forms the basis for the jump and the block of statements to jump into. // CSwitch::CSwitch(CExpression* adoptSwitch, CCompoundStatement* block) : fSwitchExpression(adoptSwitch), fBlock(block) { } // // Method name : ~CSwitch // Description : Destructor. // CSwitch::~CSwitch() { delete fSwitchExpression; delete fBlock; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CSwitch::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fSwitchExpression != 0 && fBlock != 0 && fBlock->fChildren != 0); CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fSwitchExpression, context, type); if (error == 0) { error = fSwitchExpression->GenerateCode(code, context, stackUsed, false); } unsigned long switchBase = code.size(); long highKey = INT_MIN, lowKey = INT_MAX; vector keys; bool foundDefault = false; context.GetCompiler().PushStatementContext(this); for (StatementList::iterator i = fBlock->fChildren->begin(); error == 0 && i != fBlock->fChildren->end(); ++i) { error = ScanStatementForLabels(*(*i), keys, foundDefault, highKey, lowKey, context); } if (error == 0) { unsigned long switchLine = fSwitchExpression->GetLineNumber(); long numKeys = highKey - lowKey + 1; unsigned long keyCount = keys.size(); if (keyCount > 0 && numKeys <= keyCount * 2) { // use a tableswitch code.Append(CJavaCodeAttribute::tableswitch, numKeys, switchLine); code.Append(CJavaCodeAttribute::nop, 0, switchLine); code.Append(CJavaCodeAttribute::nop, lowKey, switchLine); code.Append(CJavaCodeAttribute::nop, highKey, switchLine); for (int i = 0; i < numKeys; ++i) { code.Append(CJavaCodeAttribute::nop, (unsigned long)-1, switchLine); } unsigned long defaultLocation = 0; bool defaultFound = false; CCompileContext currentContext = context; currentContext.SetUnreachable(); for (StatementList::iterator i = fBlock->fChildren->begin(); error == 0 && i != fBlock->fChildren->end(); ++i) { CLabelStatement* statement = DYNAMIC_CAST(CLabelStatement, *i); if (statement != 0) { switch (statement->fType) { case CLabelStatement::kDefault: defaultFound = true; case CLabelStatement::kCase: currentContext.Merge(context); TableswitchLabel(*statement, code, switchBase + 4, lowKey, defaultLocation); } } unsigned short childStack; error = (*i)->GenerateCode(code, currentContext, childStack); if (childStack > stackUsed) { stackUsed = childStack; } } if (!defaultFound) { defaultLocation = code.CreateBlockLabel(); context.Merge(currentContext); } else { context = currentContext; } code[switchBase + 1].fArguments.u4 = defaultLocation; for (int i = 0; i < numKeys; ++i) { if (code[switchBase + i + 4].fArguments.u4 == (unsigned long)-1) { code[switchBase + i + 4].fArguments.u4 = defaultLocation; } } } else { // use a lookupswitch code.Append(CJavaCodeAttribute::lookupswitch, numKeys, switchLine); code.Append(CJavaCodeAttribute::nop, 0, switchLine); code.Append(CJavaCodeAttribute::nop, keyCount, switchLine); for (int i = 0; i < keyCount * 2; ++i) { code.Append(CJavaCodeAttribute::nop, 0, switchLine); } unsigned long startKey = switchBase + 3; unsigned long endKey = startKey; unsigned long defaultLocation = 0; bool defaultFound = false; CCompileContext currentContext = context; currentContext.SetUnreachable(); for (StatementList::iterator i = fBlock->fChildren->begin(); error == 0 && i != fBlock->fChildren->end(); ++i) { CLabelStatement* statement = DYNAMIC_CAST(CLabelStatement, *i); if (statement != 0) { switch (statement->fType) { case CLabelStatement::kDefault: defaultFound = true; case CLabelStatement::kCase: currentContext.Merge(context); LookupswitchLabel(*statement, code, startKey, endKey, defaultLocation); } } unsigned short childStack; error = (*i)->GenerateCode(code, currentContext, childStack); if (childStack > stackUsed) { stackUsed = childStack; } } if (!defaultFound) { defaultLocation = code.CreateBlockLabel(); context.Merge(currentContext); } else { context = currentContext; } code[switchBase + 1].fArguments.u4 = defaultLocation; } } context.GetCompiler().PopStatementContext(); if (!fNestedBreaks.empty()) { unsigned long afterSwitch = code.CreateBlockLabel(); for (list::iterator i = fNestedBreaks.begin(); !(i == fNestedBreaks.end()); ++i) { unsigned long address = (*i).GetAddress(); code[address].fArguments.u4 = afterSwitch; context.Merge((*i).GetContext()); } } return error; } // // Method name : ScanStatementForLabels // Description : This is a little helper function used by CSwitch to go // through a statement to try to find the top-level 'case' and 'default' // labels which it needs to know about. In the process, it figures out // the highest and lowest 'case' labels as well as a count of all case // labels found. If this evaluation leads to an error, this method returns // a newly-allocated compile error. // CCompileError* CSwitch::ScanStatementForLabels(CStatement& statement, vector& keys, bool& foundDefault, long& highKey, long& lowKey, CCompileContext& context) { CCompileError* error = 0; CLabelStatement* label = DYNAMIC_CAST(CLabelStatement, &statement); if (label != 0) { switch (label->fType) { case CLabelStatement::kCase: { CJavaTypeSignature caseType; error = CExpression::EvaluateType(label->fCaseExpression, context, caseType); if (error == 0) { COrdinalLiteral* key = DYNAMIC_CAST(COrdinalLiteral, label->fCaseExpression); if (key == 0) { error = new CCompileError("Invalid 'case' label.", label->fCaseExpression->GetLineNumber()); } else { long keyValue = key->GetInteger(); for (vector::iterator i = keys.begin(); i != keys.end(); ++i) { if (*i == (unsigned long)keyValue) { error = new CCompileError("Duplicate 'case' label.", label->fCaseExpression->GetLineNumber()); break; } } if (error == 0) { keys.push_back((unsigned long)keyValue); highKey = (keyValue > highKey) ? keyValue : highKey; lowKey = (keyValue < lowKey) ? keyValue : lowKey; error = ScanStatementForLabels(*label->fStatement, keys, foundDefault, highKey, lowKey, context); } } } } break; case CLabelStatement::kDefault: if (foundDefault) { error = MakeError("Two 'default' tags found in body of 'switch'"); } else { foundDefault = true; error = ScanStatementForLabels(*label->fStatement, keys, foundDefault, highKey, lowKey, context); } break; } } return error; } // // Method name : TableswitchLabel // Description : This is used to process a label found at the top-level of the // statement block in a switch statement. Each of the labels must be // registered in the switch lookup table, and this call makes sure that this // gets done even in cases where there are nested labels that need to be // recognized. case 1: case 2: ... // void CSwitch::TableswitchLabel(CLabelStatement& label, CCodeSequence& code, unsigned long keyBase, long lowKey, unsigned long& defaultLocation) { switch (label.fType) { case CLabelStatement::kCase: { COrdinalLiteral* key = DYNAMIC_CAST(COrdinalLiteral, label.fCaseExpression); assert(key != 0); unsigned long startKey = keyBase + (((long)key->GetInteger()) - lowKey); code[startKey].fArguments.u4 = code.CreateBlockLabel(); } break; case CLabelStatement::kDefault: defaultLocation = code.CreateBlockLabel(); } CLabelStatement* childLabel = DYNAMIC_CAST(CLabelStatement, label.fStatement); if (childLabel != 0) { TableswitchLabel(*childLabel, code, keyBase, lowKey, defaultLocation); } } // // Method name : LookupswitchLabel // Description : This is used to process a label found at the top-level of the // statement block in a switch statement. Each of the labels must be // registered in the switch lookup table, and this call makes sure that this // gets done even in cases where there are nested labels that need to be // recognized. case 1: case 2: ... // void CSwitch::LookupswitchLabel(CLabelStatement& label, CCodeSequence& code, unsigned long keyBase, unsigned long& endKey, unsigned long& defaultLocation) { switch (label.fType) { case CLabelStatement::kCase: { COrdinalLiteral* key = DYNAMIC_CAST(COrdinalLiteral, label.fCaseExpression); assert(key != 0); // have to insert in ascending order as of JDK 1.1, apparently. int insertPoint = endKey; for (; insertPoint > keyBase; insertPoint -= 2) { if ((long)code[insertPoint - 2].fArguments.u4 <= (long)key->GetInteger()) { break; } code[insertPoint].fArguments.u4 = code[insertPoint - 2].fArguments.u4; code[insertPoint + 1].fArguments.u4 = code[insertPoint - 1].fArguments.u4; } code[insertPoint].fArguments.u4 = key->GetInteger(); code[insertPoint + 1].fArguments.u4 = code.CreateBlockLabel(); endKey += 2; } break; case CLabelStatement::kDefault: defaultLocation = code.CreateBlockLabel(); } CLabelStatement* childLabel = DYNAMIC_CAST(CLabelStatement, label.fStatement); if (childLabel != 0) { LookupswitchLabel(*childLabel, code, keyBase, endKey, defaultLocation); } } // // Method name : RegisterBreakBranch // Description : This method tells the switch construct that a break // statement was found in its body. This gives the switch the location of // the 'goto' code in the instruction block. The loop is then responsible // for adjusting the target of the 'goto' to jump to the right location. // void CSwitch::RegisterBreakBranch(const CNonlocalBranch& instruction) { fNestedBreaks.push_front(instruction); } //========================= CExplicitConstructorCall ========================== // // Method name : CExplicitConstructorCall // Description : Constructs a CExplicitConstructorCall // CExplicitConstructorCall::CExplicitConstructorCall(Type type, ExpressionList* adoptArguments) : fType(type) { CExpression* target = (type == kThis) ? new CSpecialExpression(CSpecialExpression::kThis) : new CSpecialExpression(CSpecialExpression::kSuper); fExpression = new CMethodCall(target, CCompiler::kConstructorName, adoptArguments, true); } // // Method name : ~CExplicitConstructorCall // Description : Destructor. // CExplicitConstructorCall::~CExplicitConstructorCall() { delete fExpression; } // // Method name : GenerateCode // Description : Appends the generated bytecode for this statement onto the // code parameter, using the other parameters to help get the // needed information. In addition, the 'stackUsed' parameter is set to // the maximum expression stack depth incurred by this statement. // If this operation is successful, 0 is returned, otherwise a compile // error structure is created and returned to the caller to explain what // went wrong. // CCompileError* CExplicitConstructorCall::HandleGenerateCode(CCodeSequence& code, CCompileContext& context, unsigned short& stackUsed) { assert(fExpression != 0); stackUsed = 0; CJavaTypeSignature type; CCompileError* error = CExpression::EvaluateType(fExpression, context, type); if (error == 0) { error = fExpression->GenerateCode(code, context, stackUsed, true); } return error; }