// $Id: bytecode.h,v 1.71 2004/03/05 13:10:53 ericb Exp $ -*- c++ -*- // // License Agreement available at the following URL: // http://ibm.com/developerworks/opensource/jikes. // Copyright (C) 1996, 2004 IBM Corporation and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #ifndef bytecode_INCLUDED #define bytecode_INCLUDED #include "platform.h" #include "tuple.h" #include "ast.h" #include "class.h" #include "op.h" #include "segment.h" #include "control.h" #ifdef HAVE_JIKES_NAMESPACE namespace Jikes { // Open namespace Jikes block #endif class TypeSymbol; class Control; class Semantic; class Label { public: class LabelUse { public: int use_length; // length of use (2 or 4 bytes) int op_offset; // length of use from opcode starting instruction int use_offset; // offset in code stream of use LabelUse() : use_length(0), op_offset(0), use_offset(0) {} LabelUse(int _length, int _op_offset, int _use) : use_length(_length), op_offset(_op_offset), use_offset(_use) {} }; bool defined; // boolean, set when value is known u2 definition; // offset of definition point of label Tuple uses; Label() : defined(false), definition(0) {} // // All used labels should have been completed and reset, otherwise a goto // will cause an infinite loop because it was emitted with an offset of 0. // ~Label() { assert(! uses.Length()); } void Reset() { uses.Reset(); defined = false; definition = 0; } }; // // // class MethodStack { public: void Push(AstBlock* block) { assert(block -> nesting_level < stack_size && (top_index == 0 || (block -> nesting_level > nesting_level[top_index - 1]))); nesting_level[top_index] = block -> nesting_level; break_labels[block -> nesting_level].uses.Reset(); continue_labels[block -> nesting_level].uses.Reset(); finally_labels[block -> nesting_level].uses.Reset(); handler_range_start[block -> nesting_level].Reset(); handler_range_end[block -> nesting_level].Reset(); blocks[block -> nesting_level] = block; if (size) memset(local_variables_start_pc[block -> nesting_level], 0xFF, size * sizeof(u2)); top_index++; } void Pop() { if (top_index > 0) { top_index--; #ifdef JIKES_DEBUG unsigned level = nesting_level[top_index]; nesting_level[top_index] = 0; break_labels[level].Reset(); continue_labels[level].Reset(); finally_labels[level].Reset(); handler_range_start[level].Reset(); handler_range_end[level].Reset(); blocks[level] = NULL; if (size) memset(local_variables_start_pc[level], 0xFF, size * sizeof(u2)); #endif // ! JIKES_DEBUG } else assert(false); } unsigned Size() { return top_index; } #ifdef JIKES_DEBUG void AssertIndex(unsigned k) { for (unsigned i = 0; i < top_index; i++) if (nesting_level[i] == k) return; assert(false && "missing method stack level"); } #else # define AssertIndex(x) /* nop */ #endif // ! JIKES_DEBUG unsigned TopNestingLevel() { assert(top_index > 0); return nesting_level[top_index - 1]; } unsigned NestingLevel(unsigned i) { assert(i < top_index); return nesting_level[i]; } Label& TopBreakLabel() { return break_labels[TopNestingLevel()]; } Label& BreakLabel(unsigned i) { AssertIndex(i); return break_labels[i]; } Label& TopContinueLabel() { return continue_labels[TopNestingLevel()]; } Label& ContinueLabel(unsigned i) { AssertIndex(i); return continue_labels[i]; } Label& TopFinallyLabel() { return finally_labels[TopNestingLevel()]; } Label& FinallyLabel(unsigned i) { AssertIndex(i); return finally_labels[i]; } Tuple& TopHandlerRangeStart() { return handler_range_start[TopNestingLevel()]; } Tuple& HandlerRangeStart(unsigned i) { AssertIndex(i); return handler_range_start[i]; } Tuple& TopHandlerRangeEnd() { return handler_range_end[TopNestingLevel()]; } Tuple& HandlerRangeEnd(unsigned i) { AssertIndex(i); return handler_range_end[i]; } AstBlock* TopBlock() { return blocks[TopNestingLevel()]; } AstBlock* Block(unsigned i) { AssertIndex(i); return blocks[i]; } u2* TopLocalVariablesStartPc() { return (u2*) local_variables_start_pc[TopNestingLevel()]; } u2& StartPc(VariableSymbol* variable) { assert(variable -> LocalVariableIndex() >= 0 && variable -> LocalVariableIndex() < (int) size); return TopLocalVariablesStartPc()[variable -> LocalVariableIndex()]; } MethodStack(unsigned stack_size_, unsigned size_) : stack_size(stack_size_), size(size_), top_index(0) { nesting_level = new unsigned[stack_size]; break_labels = new Label[stack_size]; continue_labels = new Label[stack_size]; finally_labels = new Label[stack_size]; handler_range_start = new Tuple[stack_size]; handler_range_end = new Tuple[stack_size]; blocks = new AstBlock*[stack_size]; local_variables_start_pc = new u2*[stack_size]; for (unsigned i = 0; i < stack_size; i++) local_variables_start_pc[i] = new u2[size]; } ~MethodStack() { delete [] nesting_level; delete [] break_labels; delete [] continue_labels; delete [] finally_labels; delete [] handler_range_start; delete [] handler_range_end; delete [] blocks; for (unsigned i = 0; i < stack_size; i++) delete [] local_variables_start_pc[i]; delete [] local_variables_start_pc; } private: unsigned* nesting_level; Label* break_labels; Label* continue_labels; Label* finally_labels; Tuple* handler_range_start; Tuple* handler_range_end; AstBlock** blocks; // block symbols for current block u2** local_variables_start_pc; unsigned stack_size; unsigned size; unsigned top_index; }; class ByteCode : public ClassFile, public StringConstant, public Operators { // // A heuristic level for generating code to handle conditional branches // crossing more than 32767 bytes of code. In one test case, 54616 was // required to generate that much code, so 10000 seems like a conservative // value. // enum { TOKEN_WIDTH_REQUIRING_GOTOW = 10000 }; Control& control; Semantic& semantic; TypeSymbol* unit_type; int line_number, last_label_pc, // pc for last (closest to end) label last_op_pc, // pc of last operation emitted stack_depth, // current stack depth; max_stack, max_block_depth; MethodStack* method_stack; bool string_overflow, library_method_not_found, last_op_goto; // set if last operation was GOTO or GOTO_W. // // This variable is non-zero only in constructors of local classes; it // gives the offset where variable shadow parameters begin. // u2 shadow_parameter_offset; CodeAttribute* code_attribute; // code for current method LineNumberTableAttribute* line_number_table_attribute; LocalVariableTableAttribute* local_variable_table_attribute; InnerClassesAttribute* inner_classes_attribute; void MethodInitialization() { last_label_pc = 0; last_op_pc = 0; last_op_goto = false; stack_depth = 0; max_stack = 0; } bool ProcessAbruptExit(unsigned, u2, TypeSymbol* = NULL); void CompleteLabel(Label& lab); void DefineLabel(Label& lab); void UseLabel(Label& lab, int length, int op_offset); bool IsLabelUsed(Label& lab) { return lab.uses.Length() > 0; } // // Does p refer to a non-null reference type? // bool IsReferenceType(TypeSymbol* p) { return ! p -> Primitive() && p != control.null_type; } // // Does p refer to an array type that can be assigned arrays? // bool IsMultiDimensionalArray(TypeSymbol* p) { return p -> num_dimensions > 1 || p -> base_type == control.Object() || p -> base_type == control.Cloneable() || p -> base_type == control.Serializable(); } // // See if operand is constant zero (including -0.0). // bool IsZero(AstExpression* p) { TypeSymbol* type = p -> Type(); if (p -> IsConstant() && type != control.String()) { if (control.IsSimpleIntegerValueType(type) || type == control.boolean_type) { return (DYNAMIC_CAST (p -> value)) -> value == 0; } else if (type == control.long_type) { return (DYNAMIC_CAST (p -> value)) -> value == 0; } else if (type == control.float_type) { return (DYNAMIC_CAST (p -> value)) -> value == 0; } else { assert(type == control.double_type); return (DYNAMIC_CAST (p -> value)) -> value == 0; } } return false; } // // See if operand is constant one. // bool IsOne(AstExpression* p) { TypeSymbol* type = p -> Type(); if (p -> IsConstant() && type != control.String()) { if (control.IsSimpleIntegerValueType(type) || type == control.boolean_type) { return (DYNAMIC_CAST (p -> value)) -> value == 1; } else if (type == control.long_type) { return (DYNAMIC_CAST (p -> value)) -> value == 1; } else if (type == control.float_type) { return (DYNAMIC_CAST (p -> value)) -> value == 1; } else { assert(type == control.double_type); return (DYNAMIC_CAST (p -> value)) -> value == 1; } } return false; } // // memory access: reference either // constant (literal) // name (includes local varable, or class variable, or field access) // array // enum VariableCategory { LOCAL_VAR = 0, // local variable ARRAY_VAR = 1, // array (of any kind) FIELD_VAR = 2, // instance variable STATIC_VAR = 3, // class variable ACCESSED_VAR = 4 // enclosing class field via accessor method }; VariableCategory GetVariableKind(AstExpression* expression) { AstAssignmentExpression* assignment = expression -> AssignmentExpressionCast(); AstPreUnaryExpression* pre = expression -> PreUnaryExpressionCast(); AstPostUnaryExpression* post = expression -> PostUnaryExpressionCast(); // // Get the expression containing the variable (avoid accessor methods). // AstExpression* lhs = (assignment ? (assignment -> write_method ? (AstExpression*) NULL : assignment -> left_hand_side) : pre ? (pre -> write_method ? (AstExpression*) NULL : pre -> expression) : post ? (post -> write_method ? (AstExpression*) NULL : post -> expression) : expression); // // Find symbol that is associated with expression. If the // subexpression has to be referenced via an access method then the // symbol is null. // if (lhs && lhs -> CastExpressionCast()) lhs = ((AstCastExpression*) lhs) -> expression; while (lhs && lhs -> ParenthesizedExpressionCast()) lhs = ((AstParenthesizedExpression*) lhs) -> expression; Symbol* sym = lhs ? lhs -> symbol : (Symbol*) NULL; // // If the expression associated with the left-hand side is null, // then we have an access method. Otherwise, a left-hand side is // either an array access, a field access or a name. In the case of // a FieldAccess or name, the left-hand side is resolved into a // variable. For an array access, it is resolved into a type. // VariableSymbol* var = (sym ? sym -> VariableCast() : (VariableSymbol*) NULL); return (! lhs ? ACCESSED_VAR : ! var ? ARRAY_VAR : var -> owner -> MethodCast() ? LOCAL_VAR : var -> ACC_STATIC() ? STATIC_VAR : FIELD_VAR); } int GetTypeWords(const TypeSymbol* type) { return control.IsDoubleWordType(type) ? 2 : 1; } // // methods to load and store values // void LoadLocal(int varno, const TypeSymbol*); void StoreLocal(int varno, const TypeSymbol*); void LoadLiteral(LiteralValue*, const TypeSymbol*); void LoadImmediateInteger(i4); int LoadVariable(VariableCategory, AstExpression*, bool = true); int LoadArrayElement(const TypeSymbol*); void StoreArrayElement(const TypeSymbol*); void StoreField(AstExpression*); void StoreVariable(VariableCategory, AstExpression*); void LoadConstantAtIndex(u2 index) { if (index <= 255) { PutOp(OP_LDC); PutU1((u1) index); } else { PutOp(OP_LDC_W); PutU2(index); } } // // These pools are sets that keep track of elements that have // already been inserted in the constant pool. // SegmentPool segment_pool; Pair* double_constant_pool_index; Pair* integer_constant_pool_index; Pair* long_constant_pool_index; Pair* float_constant_pool_index; Pair* string_constant_pool_index; Pair utf8_constant_pool_index; Pair class_constant_pool_index; Triplet* name_and_type_constant_pool_index; Triplet* fieldref_constant_pool_index; Triplet* methodref_constant_pool_index; u2 RegisterNameAndType(Utf8LiteralValue* name, Utf8LiteralValue* type_name) { assert(name && type_name && "null argument to RegisterNameAndType"); if (! name_and_type_constant_pool_index) name_and_type_constant_pool_index = new Triplet(segment_pool, control.Utf8_pool.symbol_pool.Length()); u2 index = name_and_type_constant_pool_index -> Image(name -> index, type_name -> index); if (index == 0) { // // Either the triplet is not in the constant pool, or the constant // pool overflowed. // u2 name_index = RegisterUtf8(name); u2 type_index = RegisterUtf8(type_name); index = (u2) constant_pool.Length(); name_and_type_constant_pool_index -> Image(name -> index, type_name -> index) = index; constant_pool.SetNext(new CPNameAndTypeInfo(name_index, type_index)); } return index; } // // Register a variable, including full control over the qualifying type // emitted (which is not necessarily the variable's owner). // u2 RegisterFieldref(const TypeSymbol* type, const VariableSymbol* variable) { Utf8LiteralValue* class_name = type -> fully_qualified_name; Utf8LiteralValue* field_name = variable -> ExternalIdentity() -> Utf8_literal; Utf8LiteralValue* field_type_name = variable -> signature; assert(variable -> owner -> TypeCast()); assert(class_name && field_name && field_type_name && "null argument to RegisterFieldref"); if (! fieldref_constant_pool_index) fieldref_constant_pool_index = new Triplet(segment_pool, control.Utf8_pool.symbol_pool.Length()); u2 name_type_index = RegisterNameAndType(field_name, field_type_name); u2 index = fieldref_constant_pool_index -> Image(class_name -> index, name_type_index); if (index == 0) { // // Either the triplet is not in the constant pool, or the constant // pool overflowed. // u2 class_index = RegisterClass(type); index = (u2) constant_pool.Length(); fieldref_constant_pool_index -> Image(class_name -> index, name_type_index) = index; constant_pool.SetNext(new CPMemberInfo(CPInfo::CONSTANT_Fieldref, class_index, name_type_index)); } return index; } // // Shortcut when we want the variable's containing type. // u2 RegisterFieldref(const VariableSymbol* variable) { return RegisterFieldref(variable -> ContainingType(), variable); } u2 RegisterMethodref(const TypeSymbol* type, const MethodSymbol* method) { CPInfo::ConstantPoolTag kind = type -> ACC_INTERFACE() ? CPInfo::CONSTANT_InterfaceMethodref : CPInfo::CONSTANT_Methodref; Utf8LiteralValue* class_name = type -> fully_qualified_name; Utf8LiteralValue* method_name = method -> ExternalIdentity() -> Utf8_literal; Utf8LiteralValue* method_type = method -> signature; assert(class_name && method_name && method_type && "null argument to RegisterMethodref"); if (! methodref_constant_pool_index) methodref_constant_pool_index = new Triplet(segment_pool, control.Utf8_pool.symbol_pool.Length()); u2 name_type_index = RegisterNameAndType(method_name, method_type); u2 index = methodref_constant_pool_index -> Image(class_name -> index, name_type_index); if (index == 0) { // // Either the triplet is not in the constant pool, or the constant // pool overflowed. // u2 class_name_index = RegisterClass(type); index = (u2) constant_pool.Length(); methodref_constant_pool_index -> Image(class_name -> index, name_type_index) = index; constant_pool.SetNext(new CPMemberInfo(kind, class_name_index, name_type_index)); } return index; } u2 RegisterLibraryMethodref(const MethodSymbol* method) { // // The library method must exist. If it does not, flag an error. // if (method) return RegisterMethodref(method -> containing_type, method); library_method_not_found = true; return 0; } u2 RegisterDouble(DoubleLiteralValue* lit) { assert((lit != NULL) && "null argument to RegisterDouble"); if (! double_constant_pool_index) double_constant_pool_index = new Pair(segment_pool, control.double_pool.symbol_pool.Length()); u2 index = (*double_constant_pool_index)[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // index = (u2) constant_pool.Length(); (*double_constant_pool_index)[lit -> index] = index; constant_pool.SetNext(new CPDoubleInfo(lit -> value.HighWord(), lit -> value.LowWord())); } return index; } u2 RegisterInteger(IntLiteralValue* lit) { assert((lit != NULL) && "null argument to RegisterInteger"); if (! integer_constant_pool_index) integer_constant_pool_index = new Pair(segment_pool, control.int_pool.symbol_pool.Length()); u2 index = (*integer_constant_pool_index)[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // index = (u2) constant_pool.Length(); (*integer_constant_pool_index)[lit -> index] = index; constant_pool.SetNext(new CPIntegerInfo((u4) lit -> value)); } return index; } u2 FindInteger(IntLiteralValue* lit) { return (lit && integer_constant_pool_index ? (*integer_constant_pool_index)[lit -> index] : 0); } u2 RegisterLong(LongLiteralValue* lit) { assert((lit != NULL) && "null argument to RegisterLong"); if (! long_constant_pool_index) long_constant_pool_index = new Pair(segment_pool, control.long_pool.symbol_pool.Length()); u2 index = (*long_constant_pool_index)[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // index = (u2) constant_pool.Length(); (*long_constant_pool_index)[lit -> index] = index; constant_pool.SetNext(new CPLongInfo(lit -> value.HighWord(), lit -> value.LowWord())); } return index; } u2 RegisterFloat(FloatLiteralValue* lit) { assert((lit != NULL) && "null argument to RegisterFloat"); if (! float_constant_pool_index) float_constant_pool_index = new Pair(segment_pool, control.float_pool.symbol_pool.Length()); u2 index = (*float_constant_pool_index)[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // index = (u2) constant_pool.Length(); (*float_constant_pool_index)[lit -> index] = index; constant_pool.SetNext(new CPFloatInfo(lit -> value.Word())); } return index; } u2 RegisterUtf8(Utf8LiteralValue* lit) { assert(lit != NULL && "null argument to RegisterUtf8"); u2 index = utf8_constant_pool_index[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // index = (u2) constant_pool.Length(); utf8_constant_pool_index[lit -> index] = index; constant_pool.SetNext(new CPUtf8Info(lit -> value, lit -> length)); if (lit -> length > 0xffff) string_overflow = true; } return index; } u2 RegisterName(const NameSymbol* sym) { return RegisterUtf8(sym -> Utf8_literal); } u2 RegisterString(Utf8LiteralValue* lit) { assert(lit && "null argument to RegisterString"); if (! string_constant_pool_index) string_constant_pool_index = new Pair(segment_pool, control.Utf8_pool.symbol_pool.Length()); u2 index = (*string_constant_pool_index)[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // u2 utf_index = RegisterUtf8(lit); index = (u2) constant_pool.Length(); (*string_constant_pool_index)[lit -> index] = index; constant_pool.SetNext(new CPStringInfo(utf_index)); } return index; } u2 RegisterClass(const TypeSymbol* type) { Utf8LiteralValue* lit = type -> num_dimensions ? type -> signature : type -> fully_qualified_name; assert(type && lit && "null argument to RegisterClass"); u2 index = class_constant_pool_index[lit -> index]; if (index == 0) { // // Either the pair is not in the constant pool, or the constant // pool overflowed. // u2 utf_index = RegisterUtf8(lit); index = (u2) constant_pool.Length(); class_constant_pool_index[lit -> index] = index; constant_pool.SetNext(new CPClassInfo(utf_index)); // // All nested classes must appear in the InnerClasses attribute, as // well. // if (type -> IsNested()) { if (! inner_classes_attribute) { inner_classes_attribute = new InnerClassesAttribute (RegisterUtf8(control.InnerClasses_literal)); AddAttribute(inner_classes_attribute); } AccessFlags flags = type -> Flags(); // // Types are never marked strictfp in .class files. This can be // reverse engineered from and methods; the // only time when these methods don't exist is in interfaces // that have no runtime expression evaluations, so no // information is lost by clearing the flag. // flags.ResetACC_STRICTFP(); inner_classes_attribute -> AddInnerClass(index, type -> IsLocal() ? 0 : RegisterClass(type -> ContainingType()), type -> Anonymous() ? 0 : RegisterName(type -> name_symbol), flags); } } return index; } // // Methods to write out the byte code // DeprecatedAttribute* CreateDeprecatedAttribute() { return new DeprecatedAttribute(RegisterUtf8 (control.Deprecated_literal)); } SyntheticAttribute* CreateSyntheticAttribute() { return new SyntheticAttribute(RegisterUtf8(control.Synthetic_literal)); } EnclosingMethodAttribute* CreateEnclosingMethodAttribute(MethodSymbol* sym) { u2 attr_name = RegisterUtf8(control.EnclosingMethod_literal); u2 type_index = RegisterClass(sym -> containing_type); u2 name_type_index = (sym -> name_symbol == control.block_init_name_symbol || sym -> name_symbol == control.clinit_name_symbol) ? 0 : RegisterNameAndType(sym -> ExternalIdentity() -> Utf8_literal, sym -> signature); return new EnclosingMethodAttribute(attr_name, type_index, name_type_index); } // // Methods to generate expressions. // int EmitExpression(AstExpression*, bool = true); int EmitName(AstName*, bool); int EmitArrayCreationExpression(AstArrayCreationExpression*, bool = true); int EmitAssignmentExpression(AstAssignmentExpression*, bool); int EmitBinaryExpression(AstBinaryExpression*, bool); int EmitInstanceofExpression(AstInstanceofExpression*, bool); int EmitCastExpression(AstCastExpression*, bool); void EmitCast(TypeSymbol*, TypeSymbol*); int EmitClassCreationExpression(AstClassCreationExpression*, bool); int EmitConditionalExpression(AstConditionalExpression*, bool); int EmitFieldAccess(AstFieldAccess*, bool = true); AstExpression* VariableExpressionResolution(AstExpression*); TypeSymbol* VariableTypeResolution(AstExpression*, VariableSymbol*); TypeSymbol* MethodTypeResolution(AstExpression*, MethodSymbol*); void EmitFieldAccessLhsBase(AstExpression*); void EmitFieldAccessLhs(AstExpression*); int EmitMethodInvocation(AstMethodInvocation*, bool); void EmitNewArray(unsigned, const TypeSymbol*); int EmitPostUnaryExpression(AstPostUnaryExpression*, bool); void EmitPostUnaryExpressionArray(AstPostUnaryExpression*, bool); void EmitPostUnaryExpressionField(VariableCategory, AstPostUnaryExpression*, bool); void EmitPostUnaryExpressionSimple(VariableCategory, AstPostUnaryExpression*, bool); int EmitPreUnaryExpression(AstPreUnaryExpression*, bool); void EmitPreUnaryIncrementExpression(AstPreUnaryExpression*, bool); void EmitPreUnaryIncrementExpressionArray(AstPreUnaryExpression*, bool); void EmitPreUnaryIncrementExpressionField(VariableCategory, AstPreUnaryExpression*, bool); void EmitPreUnaryIncrementExpressionSimple(VariableCategory, AstPreUnaryExpression*, bool); void EmitThisInvocation(AstThisCall*); void EmitSuperInvocation(AstSuperCall*); void ConcatenateString(AstBinaryExpression*, bool); void AppendString(AstExpression*, bool); void EmitStringAppendMethod(TypeSymbol*); void ChangeStack(int); void ResolveAccess(AstExpression*); int GenerateClassAccess(AstClassLiteral*, bool); void GenerateClassAccessMethod(); void GenerateAssertVariableInitializer(TypeSymbol*, VariableSymbol*); void EmitCheckForNull(AstExpression* expr, bool = true); // // Methods to process statements // void CompileConstructor(AstConstructorDeclaration*, Tuple&, bool); void BeginMethod(int, MethodSymbol*); void EndMethod(int, MethodSymbol*); void DeclareField(VariableSymbol*); void InitializeVariable(AstVariableDeclarator*); void InitializeArray(const TypeSymbol*, AstArrayInitializer*, bool = true); void DeclareLocalVariable(AstVariableDeclarator*); bool EmitStatement(AstStatement*); void EmitReturnStatement(AstReturnStatement*); bool EmitSynchronizedStatement(AstSynchronizedStatement*); bool EmitBlockStatement(AstBlock*); void EmitStatementExpression(AstExpression*); bool EmitSwitchStatement(AstSwitchStatement*); bool EmitSwitchBlockStatement(AstSwitchBlockStatement*, bool); void CloseSwitchLocalVariables(AstBlock*, u2 op_start); void EmitTryStatement(AstTryStatement*); void EmitAssertStatement(AstAssertStatement*); void EmitForeachStatement(AstForeachStatement*); void EmitBranchIfExpression(AstExpression*, bool, Label&, AstStatement* = NULL); void EmitBranch(Opcode, Label&, AstStatement* = NULL); int CompleteCall(MethodSymbol*, int, bool = true, TypeSymbol* = NULL); AstExpression* StripNops(AstExpression*); bool IsNop(AstBlock*); void EmitArrayAccessLhs(AstArrayAccess* expression); int EmitArrayAccessRhs(AstArrayAccess* expression) { EmitArrayAccessLhs(expression); // get array address and index return LoadArrayElement(expression -> Type()); } // Return the OP_IF... bytecode that has the opposite meaning Opcode InvertIfOpCode(Opcode opc) { // // Unfortunately, the JVMS does not nicely specify symmetric opcodes; // we must treat even-odd and odd-even pairs differently. // if (opc >= OP_IFNULL) { assert(opc <= OP_IFNONNULL); return (Opcode) (opc ^ 1); } assert(OP_IFEQ <= opc && opc <= OP_IF_ACMPNE); return (Opcode) (((opc + 1) ^ 1) - 1); } void GenerateReturn(TypeSymbol* type) { PutOp((control.IsSimpleIntegerValueType(type) || type == control.boolean_type) ? OP_IRETURN : type == control.long_type ? OP_LRETURN : type == control.float_type ? OP_FRETURN : type == control.double_type ? OP_DRETURN : OP_ARETURN); } void PutOp(Opcode); void PutOpWide(Opcode, u2 var); void PutOpIINC(u2 var, int val); // // Methods to insert values into byte code // void PutI1(i1 i) { code_attribute -> AddCode(i & 0xff); } void PutI2(i2 i) { code_attribute -> AddCode((i >> 8) & 0xff); code_attribute -> AddCode(i & 0xff); } void PutU1(u1 u) { code_attribute -> AddCode(u & 0xff); } void PutU2(u2 u) { code_attribute -> AddCode((u >> 8) & 0xff); code_attribute -> AddCode(u & 0xff); } void PutU4(u4 u) { code_attribute -> AddCode((u >> 24)); code_attribute -> AddCode((u >> 16) & 0xff); code_attribute -> AddCode((u >> 8) & 0xff); code_attribute -> AddCode(u & 0xff); } void FinishCode(); void Reset() { constant_pool.Reset(); fields.Reset(); methods.Reset(); attributes.Reset(); this_class = super_class = 0; } public: ByteCode(TypeSymbol*); ~ByteCode() { delete double_constant_pool_index; delete integer_constant_pool_index; delete long_constant_pool_index; delete float_constant_pool_index; delete string_constant_pool_index; delete name_and_type_constant_pool_index; delete fieldref_constant_pool_index; delete methodref_constant_pool_index; } void GenerateCode(); }; #ifdef HAVE_JIKES_NAMESPACE } // Close namespace Jikes block #endif #endif // bytecode_INCLUDED