// $Id: bytecode.cpp,v 1.12 1999/03/10 19:59:20 shields Exp $ copyright notice #include "assert.h" #include "config.h" #include "ast.h" #include "bytecode.h" #include "class.h" #include "control.h" #include "semantic.h" #include "stream.h" #include "symbol.h" #include "table.h" #include <iostream.h> #include <string.h> #include <wchar.h> #ifdef WIN32_FILE_SYSTEM #include <windows.h> #endif /* TODO: see if actually need call to ChangeStack, marked CHECK_THIS, in AssigmnentExpression */ void ByteCode::CompileClass(TypeSymbol * type) { AstClassDeclaration * class_decl = type -> declaration -> ClassDeclarationCast(); AstClassBody * class_body = (class_decl ? class_decl -> class_body : ((AstClassInstanceCreationExpression *) type -> declaration) -> class_body_opt);; int i; int mi,pi; AstConstructorDeclaration *constructor; AstMethodDeclaration *method; int super_init=0; u2 name; int descriptor; int need_init=0; // see if need to generate <init> method int need_clinit=0; // set if need <clinit> method Tuple<AstVariableDeclarator *> initialized_fields(type -> NumVariableSymbols()); // fields needing code to initialize int method_index; AstFieldDeclaration * field_decl; AstList * declarators; AstList * block_statements; int fi; int si; AstConstructorBlock * constructor_block; VariableSymbol * vsym; MethodSymbol * msym; AstStaticInitializer * static_initializer; class_literal_method = type -> outermost_type -> ClassLiteralMethod(); // // Make sure there is an entry in the constant pool for all types on which // this type depends. This code is necessary because in the case of a dependence // on a type from which we only access a static final constant, the constant is // inlined and no other information about it is otherwise recorded. // for (TypeSymbol *parent = (TypeSymbol *) type -> parents -> FirstElement(); parent; parent = (TypeSymbol *) type -> parents -> NextElement()) { RegisterUtf8(parent -> signature); } // // Process static variables. // for (i=0; i < class_body -> NumClassVariables(); i++) { field_decl = class_body -> ClassVariable(i); for (int vi=0;vi<field_decl -> NumVariableDeclarators();vi++) { AstVariableDeclarator * vd = field_decl -> VariableDeclarator(vi); vsym = vd -> symbol; // // We need a static constructor-initializer if we encounter at least one class // variable that is declared with an initialization expression that is not a // constant expression. // need_clinit = need_clinit || (vd -> variable_initializer_opt && !(vsym -> ACC_FINAL() && vsym -> initial_value)); DeclareField(vsym); } } // supply needed field declaration for this$0 (if there is one) for (pi = 0; pi < type -> NumConstructorParameters(); pi++) { DeclareField(type -> ConstructorParameter(pi)); } // // supply needed field declaration for enclosing instances (this$n) if present // for (pi = 1; pi < type -> NumEnclosingInstances(); pi++) { DeclareField(type -> EnclosingInstance(pi)); } // supply needed field declarations for "class " identifiers (used for X.class literals) if present for (int ri = 0; ri < type -> NumClassLiterals(); ri++) { DeclareField(type -> ClassLiteral(ri)); } for (i=0; i < class_body -> NumInstanceVariables(); i++) { field_decl = class_body -> InstanceVariable(i); for (int vi=0;vi<field_decl -> NumVariableDeclarators();vi++) { AstVariableDeclarator * vd = field_decl -> VariableDeclarator(vi); DeclareField(vd -> symbol); // must set Constant attribute if initial value if (vd -> variable_initializer_opt) { // if initialization needed need_init=1; initialized_fields.Next() = vd; } } } // compile method bodies and constructors for (i=0; i < class_body -> NumMethods(); i++) { method = class_body -> Method(i); if (method -> method_symbol){ method_index = BeginMethod(METHOD_KIND_ORDINARY, method -> method_symbol); // not constructor AstBlock *method_block = method -> method_body -> BlockCast(); if (method_block) // not an abstract method ? (void) EmitStatement(method_block); EndMethod(METHOD_KIND_ORDINARY,method_index, method -> method_symbol); // not constructor } } // // NOTE that an abstract class that requires this patch may become out-of-date // and cause spurious messages to be emitted if any abstract method inherited // from an interface is later removed from that interface. // if (type -> ACC_ABSTRACT()) { for (int i = 0; i < type -> expanded_method_table -> symbol_pool.Length(); i++) { MethodShadowSymbol *method_shadow_symbol = type -> expanded_method_table -> symbol_pool[i]; MethodSymbol *method_symbol = method_shadow_symbol -> method_symbol; if (method_symbol -> ACC_ABSTRACT() && method_symbol -> containing_type != type && method_symbol -> containing_type -> ACC_INTERFACE()) { if (! method_symbol -> IsTyped()) method_symbol -> ProcessMethodSignature(&this_semantic, class_decl -> identifier_token); method_symbol -> ProcessMethodThrows(&this_semantic, class_decl -> identifier_token); method_index = BeginMethod(METHOD_KIND_ORDINARY, method_symbol); EndMethod(METHOD_KIND_ORDINARY,method_index, method_symbol); } } } // compile any private access methods for (i = 0; i < type -> NumPrivateAccessMethods(); i++) { MethodSymbol * method_sym = type -> PrivateAccessMethod(i); // AstMethodDeclaration * method_decl = method_sym -> method_or_constructor_declaration -> MethodDeclarationCast(); method_index = BeginMethod(METHOD_KIND_ACCESS, method_sym); GenerateAccessMethod(method_sym); EndMethod(METHOD_KIND_ACCESS,method_index, method_sym); } if (type -> ClassLiteralMethod()) { MethodSymbol * class_literal_sym = type -> ClassLiteralMethod(); // generate the class$ identity method used for class literal-related garbage mumbo-jumbo initialization method_index = BeginMethod(METHOD_KIND_ACCESS_CLASS, class_literal_sym); GenerateClassAccessMethod(class_literal_sym); EndMethod(METHOD_KIND_ACCESS_CLASS,method_index, class_literal_sym); } if (type -> block_initializer_method) { MethodSymbol * block_init_method = type -> block_initializer_method; method_index = BeginMethod(METHOD_KIND_ORDINARY, block_init_method); int fi=0, bi=0; while (fi < initialized_fields.Length() && bi < class_body -> NumBlocks()) { if (initialized_fields[fi] -> LeftToken() < class_body -> Block(bi) -> left_brace_token) { InitializeInstanceVariable(initialized_fields[fi++]); } else { (void) EmitStatement((AstStatement *) (class_body -> Block(bi++))); } } while (fi<initialized_fields.Length()) { InitializeInstanceVariable(initialized_fields[fi++]); } // compile any initialization blocks while (bi < class_body -> NumBlocks()) { (void) EmitStatement((AstStatement *) (class_body -> Block(bi++))); } PutOp(OP_RETURN); EndMethod(METHOD_KIND_ORDINARY,method_index,block_init_method); // is constructor } if (type -> NumGeneratedConstructors() == 0) { if (class_body -> default_constructor) { CompileConstructor(class_body -> default_constructor, initialized_fields); } else { for (i=0; i < class_body -> NumConstructors(); i++) { constructor = class_body -> Constructor(i); CompileConstructor(constructor, initialized_fields); } for (i = 0; i < type -> NumPrivateAccessConstructors(); i++) { MethodSymbol *constructor_sym = type -> PrivateAccessConstructor(i); AstConstructorDeclaration *constructor = constructor_sym -> method_or_constructor_declaration -> ConstructorDeclarationCast(); CompileConstructor(constructor, initialized_fields); } } } else { for (i=0; i < type -> NumGeneratedConstructors(); i++) { MethodSymbol * this_constructor_symbol = type -> GeneratedConstructor(i); AstConstructorDeclaration * constructor = this_constructor_symbol -> method_or_constructor_declaration -> ConstructorDeclarationCast(); constructor_block = constructor -> constructor_body -> ConstructorBlockCast(); // compile generated constructor method_index = BeginMethod(METHOD_KIND_CONSTRUCTOR, this_constructor_symbol); // is constructor methods[method_index].name_index = RegisterUtf8(U8S_LT_init_GT_, strlen(U8S_LT_init_GT_)); UpdateBlockInfo(this_constructor_symbol -> block_symbol); if (! constructor_block -> explicit_constructor_invocation_opt) { PutOp(OP_ALOAD_0); PutOp(OP_INVOKENONVIRTUAL); // no args, hence no need to call ChangeStack() PutU2(BuildMethodref(super_class, BuildNameAndType(RegisterUtf8(U8S_LT_init_GT_, strlen(U8S_LT_init_GT_)), RegisterUtf8(U8S_LP_RP_V, strlen(U8S_LP_RP_V))))); } else { (void) EmitStatement((AstStatement *) constructor_block -> explicit_constructor_invocation_opt); } for (si = 0;si < constructor_block -> NumLocalInitStatements();si++) { (void) EmitStatement((AstStatement *) constructor_block -> LocalInitStatement(si)); } // supply needed field initialization unless constructor // starts with explicit 'this' call to another constructor if (! (constructor_block -> explicit_constructor_invocation_opt && constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast())) { if (type -> NumEnclosingInstances()) { VariableSymbol * this0_parameter = type -> EnclosingInstance(0); PutOp(OP_ALOAD_0); // load address of object on which method is to be invoked LoadLocal(1, this0_parameter -> Type()); PutOp(OP_PUTFIELD); PutU2(GenerateFieldReference(this0_parameter)); } if (class_body -> this_block) { // compile explicit 'this' call if present AstBlock * block = (AstBlock *) class_body -> this_block; for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) block -> Statement(si)); } } if (! type -> block_initializer_method) { int fi=0,bi=0; while (fi < initialized_fields.Length() && bi < class_body -> NumBlocks()) { if (initialized_fields[fi] -> LeftToken() < class_body -> Block(bi) -> left_brace_token) { InitializeInstanceVariable(initialized_fields[fi++]); } else { AstBlock * block = (AstBlock *) (class_body -> Block(bi++)); for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) block -> Statement(si)); } } } while (fi<initialized_fields.Length()) { InitializeInstanceVariable(initialized_fields[fi++]); } // compile any initialization blocks while (bi < class_body -> NumBlocks()) { AstBlock * block = (AstBlock *) (class_body -> Block(bi++)); for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) block -> Statement(si)); } } } else { // generate a call to the parameterless function block_initializer_function PutOp(OP_ALOAD_0); // load address of object on which method is to be invoked PutOp(OP_INVOKENONVIRTUAL); CompleteCall(type -> block_initializer_method, 0, 0); } } (void) EmitStatement(constructor_block -> original_constructor_invocation); PutOp(OP_RETURN); EndMethod(METHOD_KIND_CONSTRUCTOR,method_index, this_constructor_symbol); // is constructor // compile method associated with generated constructor MethodSymbol * local_constructor_symbol = this_constructor_symbol -> LocalConstructor(); method_index = BeginMethod(METHOD_KIND_CONSTRUCTOR, local_constructor_symbol); // is constructor methods[method_index].name_index = RegisterUtf8(local_constructor_symbol -> ExternalIdentity() -> Utf8_literal); for (si = 0;si < constructor_block -> block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) constructor_block -> block -> Statement(si)); } EndMethod(METHOD_KIND_CONSTRUCTOR,method_index,local_constructor_symbol); // is constructor } } if (class_body -> NumStaticInitializers() > 0 || need_clinit) { msym = type -> static_initializer_method; method_index = BeginMethod(METHOD_KIND_GENERATED_CONSTRUCTOR, msym); code_attribute -> max_locals = 0; // revisit members that are part of class initialization for (mi = 0; mi < class_body -> NumClassBodyDeclarations(); mi++) { static_initializer = class_body -> ClassBodyDeclaration(mi) -> StaticInitializerCast(); if (static_initializer) { (void) EmitStatement((AstStatement *) static_initializer -> block); } else if (class_body -> ClassBodyDeclaration(mi) -> FieldDeclarationCast()) { field_decl = class_body -> ClassBodyDeclaration(mi) -> FieldDeclarationCast(); // field declaration for (int vi=0;vi<field_decl -> NumVariableDeclarators();vi++) { AstVariableDeclarator * vd = field_decl -> VariableDeclarator(vi);; vsym = vd -> symbol; if (!vsym -> ACC_STATIC()) continue; // skip non-static fields InitializeClassVariable(vd); } } } PutOp(OP_RETURN); EndMethod(METHOD_KIND_GENERATED_CONSTRUCTOR,method_index,msym); } FinishCode(type); Write(); #ifdef TEST if (this_control.option.debug_dump_class) PrintCode(); #endif } // // initialized_fields is a list of fields needing code to initialize. // void ByteCode::CompileConstructor(AstConstructorDeclaration * constructor, Tuple<AstVariableDeclarator *> &initialized_fields) { MethodSymbol * method_symbol = constructor -> constructor_symbol; TypeSymbol * type = method_symbol -> containing_type; AstClassDeclaration * class_decl = type -> declaration -> ClassDeclarationCast(); AstClassBody * class_body = (class_decl ? class_decl -> class_body : ((AstClassInstanceCreationExpression *) type -> declaration) -> class_body_opt);; AstBlock * block; int is_this=0; // set if start with this() call. int method_index; int fi; int si; int descriptor; AstConstructorBlock * constructor_block; AstList * block_statements; method_index = BeginMethod(METHOD_KIND_CONSTRUCTOR, method_symbol); // is constructor methods[method_index].name_index = RegisterUtf8(U8S_LT_init_GT_, strlen(U8S_LT_init_GT_)); UpdateBlockInfo(method_symbol -> block_symbol); constructor_block = constructor -> constructor_body -> ConstructorBlockCast(); if (! constructor_block -> explicit_constructor_invocation_opt) { if (super_class) { PutOp(OP_ALOAD_0); PutOp(OP_INVOKENONVIRTUAL); // no args, hence no need to call ChangeStack() PutU2(BuildMethodref(super_class, BuildNameAndType(RegisterUtf8(U8S_LT_init_GT_, strlen(U8S_LT_init_GT_)), RegisterUtf8(U8S_LP_RP_V, strlen(U8S_LP_RP_V))))); } } else { if (constructor_block -> explicit_constructor_invocation_opt -> ThisCallCast()) is_this=1; (void) EmitStatement((AstStatement *) constructor_block -> explicit_constructor_invocation_opt); } // supply needed field initialization unless constructor // starts with explicit 'this' call to another constructor if (!is_this) { if (type -> NumEnclosingInstances()) { VariableSymbol * this0_parameter = type -> EnclosingInstance(0); PutOp(OP_ALOAD_0); // load address of object on which method is to be invoked LoadLocal(1, this0_parameter -> Type()); PutOp(OP_PUTFIELD); PutU2(GenerateFieldReference(this0_parameter)); } if (class_body -> this_block) { // compile explicit 'this' call if present block = (AstBlock *) class_body -> this_block; for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *)block -> Statement(si)); } } if (!type -> block_initializer_method) { int fi=0,bi=0; while (fi < initialized_fields.Length() && bi < class_body -> NumBlocks()) { if (initialized_fields[fi] -> LeftToken() < class_body -> Block(bi) -> left_brace_token) { InitializeInstanceVariable(initialized_fields[fi++]); } else { AstBlock * block = (AstBlock *) (class_body -> Block(bi++)); for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) block -> Statement(si)); } } } while (fi<initialized_fields.Length()) { InitializeInstanceVariable(initialized_fields[fi++]); } // compile any initialization blocks while (bi < class_body -> NumBlocks()) { AstBlock * block = (AstBlock *) (class_body -> Block(bi++)); for (si = 0;si < block -> NumStatements();si++) { (void) EmitStatement((AstStatement *) block -> Statement(si)); } } } else { // generate a call to the parameterless function block_initializer_function PutOp(OP_ALOAD_0); // load address of object on which method is to be invoked PutOp(OP_INVOKENONVIRTUAL); CompleteCall(type -> block_initializer_method, 0, 0); } } (void) EmitStatement(constructor_block -> block); EndMethod(METHOD_KIND_CONSTRUCTOR,method_index, method_symbol); } void ByteCode::CompileInterface(TypeSymbol * type) { AstInterfaceDeclaration * interface_decl = type -> declaration -> InterfaceDeclarationCast(); AstMethodDeclaration * method; int method_index; int i; int vi; int need_clinit=0; // set if need <clinit> method VariableSymbol * vsym; AstFieldDeclaration * field_decl; AstVariableDeclarator * vd; u2 name; AstList * declarators; for (i=0; i < interface_decl -> NumClassVariables(); i++) { field_decl = interface_decl -> ClassVariable(i); for (vi=0;vi<field_decl -> NumVariableDeclarators();vi++) { AstVariableDeclarator * vd = field_decl -> VariableDeclarator(vi); vsym = vd -> symbol; // // We need a static constructor-initializer if we encounter at least one class // variable that is declared with an initialization expression that is not a // constant expression. // need_clinit = need_clinit || (vd -> variable_initializer_opt && !(vsym -> ACC_FINAL() && vsym -> initial_value)); DeclareField(vsym); } } for (i=0; i < interface_decl -> NumMethods(); i++) { method = interface_decl -> Method(i); if (method -> method_symbol){ method_index = BeginMethod(METHOD_KIND_INTERFACE, method -> method_symbol); // not constructor EndMethod(METHOD_KIND_INTERFACE,method_index, method -> method_symbol); } } if (need_clinit) { method_index = BeginMethod(METHOD_KIND_GENERATED_CONSTRUCTOR, (MethodSymbol *) 0); code_attribute -> max_locals = 0; methods[method_index].SetACC_FINAL(); // revisit members that are part of class initialization for (int mi = 0; mi < interface_decl -> NumClassVariables(); mi++) { // field declaration field_decl = interface_decl -> ClassVariable(mi); for (int vi2=0;vi2<field_decl -> NumVariableDeclarators();vi2++) { vd = field_decl -> VariableDeclarator(vi2); vsym = vd -> symbol; if (!vsym -> ACC_STATIC()) continue; // skip non-static fields InitializeClassVariable(vd); } } PutOp(OP_RETURN); EndMethod(METHOD_KIND_GENERATED_CONSTRUCTOR,method_index, (MethodSymbol *)0); } FinishCode(type); Write(); #ifdef TEST if (this_control.option.debug_dump_class) PrintCode(); #endif } void ByteCode::DeclareField(VariableSymbol * symbol) { int field_index = fields.NextIndex(); // index for field fields[field_index].access_flags = symbol -> access_flags; fields[field_index].name_index = RegisterUtf8(symbol -> ExternalIdentity() -> Utf8_literal); fields[field_index].descriptor_index = RegisterUtf8(symbol -> Type() -> signature); TypeSymbol *type = symbol -> Type(); if (symbol -> ACC_FINAL() && symbol -> initial_value && (type -> Primitive() || type == this_control.String())) { u4 constant_value_attribute_length = 2; int lit_index = GetConstant(symbol -> initial_value, symbol -> Type()); u2 name = RegisterUtf8(U8S_ConstantValue, strlen(U8S_ConstantValue)); ConstantValue_attribute *constant_value_attribute = new ConstantValue_attribute(name, constant_value_attribute_length); constant_value_attribute -> constantvalue_index = lit_index; fields[field_index].attributes.Next() = constant_value_attribute; } if (symbol -> IsSynthetic()) { fields[field_index].attributes.Next() = CreateSyntheticAttribute(); } return; } void ByteCode::GenerateAccessMethod(MethodSymbol * method_symbol) { // generate code for access method to private member of containing class int stack_words = 0; int argument_offset = 0; // offset to start of argument code_attribute -> max_locals = 1; // DS fix this 01 dec 97 TypeSymbol * parameter_type; VariableSymbol * field_sym = method_symbol -> accessed_member -> VariableCast(); // generate code according to type of method if (method_symbol -> accessed_member -> MethodCast()) { // if accessing another method // copy arguments if (! method_symbol -> ACC_STATIC()) { PutOp(OP_ALOAD_0); // load address of object on which method is to be invoked } for (int i = 0; i < method_symbol -> NumFormalParameters(); i++) { TypeSymbol * local_type = method_symbol -> FormalParameter(i) -> Type(); code_attribute -> max_locals += GetTypeWords(local_type); stack_words += GetTypeWords(local_type); LoadLocal(method_symbol -> ACC_STATIC() ? argument_offset: argument_offset+1, local_type); argument_offset += GetTypeWords(local_type); // update position in stack } PutOp(method_symbol -> ACC_STATIC() ? OP_INVOKESTATIC // must be static or private : OP_INVOKENONVIRTUAL); CompleteCall(method_symbol -> accessed_member -> MethodCast(), stack_words, 0); } else { // accessing field if (method_type == this_control.void_type) { // need method to assign value to field if (method_symbol -> NumFormalParameters()== 0) { chaos("assignment access method requires parameter"); } parameter_type = method_symbol -> FormalParameter(0) -> Type(); code_attribute -> max_locals += GetTypeWords(parameter_type); if (method_symbol -> ACC_STATIC()) { LoadLocal(0, parameter_type); PutOp(OP_PUTSTATIC); } else { PutOp(OP_ALOAD_0); // get this for field access LoadLocal(1, parameter_type); PutOp(OP_PUTFIELD); } ChangeStack(this_control.IsDoubleWordType(parameter_type) ? -2: -1); PutU2(GenerateFieldReference(method_symbol -> accessed_member -> VariableCast())); } else { // need method to retrieve value of field if (field_sym -> ACC_STATIC()) { PutOp(OP_GETSTATIC); ChangeStack(this_control.IsDoubleWordType(method_type) ? 2: 1); } else { PutOp(OP_ALOAD_0); // get this for field access PutOp(OP_GETFIELD); ChangeStack(this_control.IsDoubleWordType(method_type) ? 1: 0); } PutU2(GenerateFieldReference(field_sym)); } } // method returns void, generate return unless last statement is return if (method_type == this_control.void_type) { // int line_index; // line_index = line_number_table_attribute -> line_number_table.NextIndex(); // line_number_table_attribute -> line_number_table[line_index] PutOp(OP_RETURN);// guarantee return at end of body } else GenerateReturn(method_type); if (last_label_pc >= code_attribute -> code.Length()) { // here to emit noop if would otherwise EmitBranch past end PutNop(0); } } void ByteCode::GenerateReturn(TypeSymbol * type) { if (this_control.IsSimpleIntegerValueType(type)|| type==this_control.boolean_type) { PutOp(OP_IRETURN); } else if (type==this_control.long_type) { PutOp(OP_LRETURN); } else if (type==this_control.float_type) { PutOp(OP_FRETURN); } else if (type==this_control.double_type) { PutOp(OP_DRETURN); } else {// must be reference expression PutOp(OP_ARETURN); } } int ByteCode::BeginMethod(int method_kind, MethodSymbol * msym) { // is_constructor is set if this is constructor, is_generated_constructor is set is need to compile // default (no argument) constructor. BlockSymbol * block_symbol; TypeSymbol * throw_symbol; u4 length_code=0; // dummy value, will supply real value after code generated. int i; u4 line_number_table_attribute_length = 0; u4 exceptions_attribute_length = 0; u4 local_variable_table_attribute_length = 0; stack_depth = 0; last_label_pc = 0; last_op_pc = 0; last_op_nop = 0; this_block_depth = 0; int method_index = methods.NextIndex(); // index for method u2 name; switch (method_kind) { case METHOD_KIND_ORDINARY: case METHOD_KIND_ACCESS: case METHOD_KIND_ACCESS_CLASS: case METHOD_KIND_INTERFACE: methods[method_index].name_index = RegisterUtf8(msym -> ExternalIdentity() -> Utf8_literal); methods[method_index].descriptor_index = RegisterUtf8(msym -> signature); break; case METHOD_KIND_CONSTRUCTOR: // caller sets name methods[method_index].descriptor_index = RegisterUtf8(msym -> signature); break; case METHOD_KIND_GENERATED_CONSTRUCTOR: methods[method_index].name_index = RegisterUtf8(U8S_LT_clinit_GT_, strlen(U8S_LT_clinit_GT_)); methods[method_index].descriptor_index = RegisterUtf8(U8S_LP_RP_V, strlen(U8S_LP_RP_V)); methods[method_index].SetACC_STATIC(); break; } if (method_kind==METHOD_KIND_CONSTRUCTOR || method_kind == METHOD_KIND_GENERATED_CONSTRUCTOR) { method_type = this_control.Object(); if (msym == (MethodSymbol *) 0) { max_block_depth = 2; } else { max_block_depth = msym -> max_block_depth; } } else { // normal method declaration max_block_depth = msym -> max_block_depth; block_symbol = msym -> block_symbol; method_type = msym -> Type(); } // set access flags for non-generated constructor. If we have // generated the constructore, then the access flags have been // set to be the same as those of the containing class. if (method_kind != METHOD_KIND_GENERATED_CONSTRUCTOR) { methods[method_index].access_flags = msym -> access_flags; } #ifdef MAKE_FINAL_PUBLIC if (method_kind==METHOD_KIND_ACCESS) { // DS debug 01 dec 97 AccessFlags flags; flags.access_flags = methods[method_index].access_flags; flags.SetACC_PUBLIC(); flags.SetACC_FINAL(); methods[method_index].access_flags = flags.access_flags; } #endif if (msym) { if (msym -> IsSynthetic()) { methods[method_index].attributes.Next() = CreateSyntheticAttribute(); } // // Generate throws attribute if method throws any exceptions // if (msym -> NumThrows()) { exceptions_attribute_length = 2 * (1 + msym -> NumThrows()); name = RegisterUtf8(U8S_Exceptions, strlen(U8S_Exceptions)); Exceptions_attribute * exceptions_attribute = new Exceptions_attribute(name, exceptions_attribute_length); for (int i = 0; i < msym -> NumThrows(); i++) { throw_symbol = (TypeSymbol *) msym -> Throws(i); exceptions_attribute -> exception_index_table.Next() = RegisterClass(throw_symbol -> fully_qualified_name); } methods[method_index].attributes.Next() = exceptions_attribute; } } if (method_kind==METHOD_KIND_INTERFACE) return method_index; // here if need code and associated attributes. if (this_control.option.g) { name = RegisterUtf8(U8S_LocalVariableTable, strlen(U8S_LocalVariableTable)); local_variable_table_attribute= new LocalVariableTable_attribute(name, local_variable_table_attribute_length); } begin_labels = new Label[max_block_depth + 1]; break_labels = new Label[max_block_depth + 1]; continue_labels = new Label[max_block_depth + 1]; test_labels = new Label[max_block_depth + 1]; final_labels = new Label[max_block_depth + 1]; monitor_labels = new Label[max_block_depth + 1]; has_finally_clause = new int[max_block_depth+1]; is_synchronized = new int[max_block_depth+1]; block_symbols = new BlockSymbol *[max_block_depth+1]; for (i=0;i<max_block_depth;i++) { has_finally_clause[i]=0; // reset has_finally_clause is_synchronized[i]=0; // reset has_finally_clause } if (! (msym && (msym -> ACC_ABSTRACT() || msym -> ACC_NATIVE()))) { name = RegisterUtf8(U8S_Code, strlen(U8S_Code)); code_attribute = new Code_attribute(name,length_code); code_attribute -> max_stack = 0; code_attribute -> max_locals = 0; if (method_kind==METHOD_KIND_CONSTRUCTOR || method_kind==METHOD_KIND_GENERATED_CONSTRUCTOR) { if (method_kind!=METHOD_KIND_GENERATED_CONSTRUCTOR) { block_symbol = msym -> block_symbol; if (block_symbol && block_symbol -> max_variable_index > code_attribute -> max_locals) { code_attribute -> max_locals = msym -> block_symbol -> max_variable_index; } } } else { block_symbol = msym -> block_symbol; if(block_symbol && block_symbol -> max_variable_index>code_attribute -> max_locals){ code_attribute -> max_locals = block_symbol -> max_variable_index; } } code_attribute -> attribute_name_index = RegisterUtf8(U8S_Code, strlen(U8S_Code)); line_number=0; // temporary until PC name = RegisterUtf8(U8S_LineNumberTable, strlen(U8S_LineNumberTable)); line_number_table_attribute = new LineNumberTable_attribute(name, line_number_table_attribute_length); line_number_table_attribute -> attribute_name_index = name; } if (msym && msym -> NumFormalParameters()) { VariableSymbol * last_sym = (VariableSymbol *) msym -> FormalParameter(msym -> NumFormalParameters() - 1); last_parameter_index = last_sym -> LocalVariableIndex(); } else { last_parameter_index = -1; } return method_index; } void ByteCode::EndMethod(int method_kind,int method_index, MethodSymbol *method_sym) { int i; u4 length_line_number_table_attribute = 0; this_block_depth=0; TypeSymbol * ptype; int has_code = 1; // Assume Code Attribute needed if (method_kind==METHOD_KIND_INTERFACE) return; if (method_kind==METHOD_KIND_CONSTRUCTOR || method_kind==METHOD_KIND_GENERATED_CONSTRUCTOR) { ptype= this_control.void_type; } else { ptype = method_sym -> Type(); if (method_sym -> ACC_ABSTRACT() || method_sym -> ACC_NATIVE()) has_code = 0; } #ifdef NONO if (has_code && ptype==this_control.void_type) { // method returns void, generate return unless last statement is return // int line_index; // line_index = line_number_table_attribute -> line_number_table.NextIndex(); // line_number_table_attribute -> line_number_table[line_index] PutOp(OP_RETURN);// guarantee return at end of body } #endif if (has_code) { if (last_label_pc >= code_attribute -> code.Length()) { // here to emit noop if would otherwise branch past end PutNop(0); } // attribute length: // need to review how to make attribute_name and attribute_length // only write line number attribute if -O not specified and there // are line numbers to write. if (!this_control.option.O && line_number_table_attribute -> line_number_table.Length()) { line_number_table_attribute -> attribute_length = line_number_table_attribute -> line_number_table.Length()*4 + 2; code_attribute -> attributes.Next() = line_number_table_attribute; } else { // line_number_table_attribute not needed, so delete it now delete line_number_table_attribute; } if (this_control.option.g) { if (method_kind==METHOD_KIND_ORDINARY) { if (! method_sym -> ACC_STATIC()) { // add 'this' to local variable table AddLocalVariableTableEntry(0, code_attribute -> code.Length(), RegisterUtf8(U8S_this, strlen(U8S_this)), RegisterUtf8(method_sym -> containing_type -> signature), 0); } } else if (method_kind==METHOD_KIND_CONSTRUCTOR && method_sym) { AddLocalVariableTableEntry(0, code_attribute -> code.Length(), RegisterUtf8(U8S_this, strlen(U8S_this)), RegisterUtf8(method_sym -> containing_type -> signature), 0); } if (method_kind==METHOD_KIND_ORDINARY || method_kind == METHOD_KIND_CONSTRUCTOR) { for (i = 0; i < method_sym -> NumFormalParameters(); i++) { VariableSymbol * parameter = method_sym -> FormalParameter(i); AddLocalVariableTableEntry(0, code_attribute -> code.Length(), RegisterUtf8(parameter -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(parameter -> Type() -> signature), parameter -> LocalVariableIndex()); } } if (local_variable_table_attribute -> local_variable_table.Length()) { local_variable_table_attribute -> attribute_length = local_variable_table_attribute -> local_variable_table.Length()*10 + 2; code_attribute -> attributes.Next() = local_variable_table_attribute; } } // std. fields of attribute_info int attribute_info_length = 0; for (i = 0; i < code_attribute -> attributes.Length(); i++) { if (code_attribute -> attributes[i] -> attribute_length) attribute_info_length += (code_attribute -> attributes[i] -> attribute_length+6); } code_attribute -> attribute_length = + 2 // for max_stack + 2 // for max_locals + 4 // for code_length + code_attribute -> code.Length() // for code + 2 // for exception_table_length + code_attribute -> exception_table.Length() * 8 // for exception table + 2 // for attributes_count + attribute_info_length ; methods[method_index].attributes.Next() = code_attribute; } delete [] begin_labels; delete [] break_labels; delete [] continue_labels; delete [] final_labels; delete [] monitor_labels; delete [] test_labels; delete [] has_finally_clause; delete [] is_synchronized; delete [] block_symbols; } void ByteCode::InitializeClassVariable(AstVariableDeclarator * vd) { VariableSymbol * symbol = vd -> symbol; AstExpression * expression; TypeSymbol * expression_type; if (vd -> variable_initializer_opt) { // field needs initialization expression = (AstExpression *) vd -> variable_initializer_opt; if (expression -> ArrayInitializerCast()) { InitializeArray(vd -> symbol ->Type(), expression -> ArrayInitializerCast()); } else if (symbol -> ACC_FINAL() && expression -> IsConstant()) return; // if already initialized else if (!initialize_statics_in_clinit && expression -> IsConstant()) return; // if already initialized else { expression_type = expression -> Type(); EmitExpression(expression); } PutOp(OP_PUTSTATIC); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -2: -1); PutU2(GenerateFieldReference(symbol)); } } void ByteCode::InitializeInstanceVariable(AstVariableDeclarator * vd) { VariableSymbol * symbol = vd -> symbol; TypeSymbol * type = symbol -> Type(); AstExpression * expression; TypeSymbol * expression_type; if (vd -> variable_initializer_opt) { // field needs initialization expression = (AstExpression *) vd -> variable_initializer_opt; if (expression -> ArrayInitializerCast()) { PutOp(OP_ALOAD_0); // load 'this' InitializeArray(vd -> symbol ->Type(), expression -> ArrayInitializerCast()); } else { expression_type = expression -> Type(); PutOp(OP_ALOAD_0); // load 'this' EmitExpression(expression); } PutOp(OP_PUTFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -2: -1); PutU2(GenerateFieldReference(symbol)); } } void ByteCode::InitializeArray(TypeSymbol *type, AstArrayInitializer * array_initializer) { int i; AstExpression * expr; Ast * entry; TypeSymbol * subtype = type -> ArraySubtype(); int num_ent = array_initializer -> NumVariableInitializers(); LoadInteger(num_ent); EmitNewArray(1,type); // make the array for (i=0;i<num_ent;i++) { entry = array_initializer -> VariableInitializer(i); PutOp(OP_DUP); LoadInteger(i); expr=entry -> ExpressionCast(); if (expr) { EmitExpression(expr); } else if (entry -> ArrayInitializerCast()) { InitializeArray(subtype, entry -> ArrayInitializerCast()); } else chaos("wrong array initializer list element type"); StoreArrayElement(subtype); } } void ByteCode::DeclareLocalVariable(AstVariableDeclarator * declarator) { AstArrayCreationExpression * ace; // generate code for local variable declaration. if (this_control.option.g) { declarator -> symbol -> local_program_counter = code_attribute -> code.Length(); } if (declarator -> symbol -> initial_value) { (void) LoadLiteral(declarator -> symbol -> initial_value,declarator -> symbol -> Type()); // Is LiteralValue * } else if (declarator -> variable_initializer_opt) { ace = declarator -> variable_initializer_opt -> ArrayCreationExpressionCast(); if (ace) { (void) EmitArrayCreationExpression(ace); } else if (declarator -> variable_initializer_opt -> ArrayInitializerCast()) { InitializeArray(declarator -> symbol ->Type(), declarator -> variable_initializer_opt -> ArrayInitializerCast()); } else { // evaluation as expression EmitExpression(declarator -> variable_initializer_opt -> ExpressionCast()); } } else return; // if nothing to initialize StoreLocalVariable(declarator -> symbol); } // JLS Chapter 13: Blocks and Statements // Statements control the sequence of evaluation of Java programs, // are executed for their effects and do not have values. // // Processing of loops requires a loop stack, especially to hangle // break and continue statements. // Loops have three labels, LABEL_BEGIN for start of loop body, // LABEL_BREAK to leave the loop, and LABEL_CONTINUE to continue the iteration. // Each loop requires a break label; other labels are defined and used // as needed. // Labels allocated but never used incur no extra cost in the generated // byte code, only in additional execution expense during compilation. int ByteCode::EmitStatement(AstStatement *statement) { // generate code for statement (JLS 13.4). The list of statement kinds // are those used in grammar, not precisely those used in JLS.. // return 1 if execution of statement causes abrupt exit, 0 otherwise. LexStream::TokenIndex start; int abrupt = 0; if (statement -> kind !=Ast::BLOCK) { int line_number_index = line_number_table_attribute -> line_number_table.NextIndex(); start = statement -> LeftToken(); line_number_table_attribute -> line_number_table[line_number_index].line_number = this_semantic.lex_stream -> Line(start); line_number_table_attribute -> line_number_table[line_number_index].start_pc = code_attribute -> code.Length(); // pc at start of statement } stack_depth = 0; // stack empty at start of statement switch (statement -> kind) { case Ast::BLOCK: // JLS 13.2 return EmitBlockStatement((AstBlock *) statement, 0); case Ast::LOCAL_VARIABLE_DECLARATION:// JLS 13.3 { // generate code for local variable declaration. AstLocalVariableDeclarationStatement * lvds = statement -> LocalVariableDeclarationStatementCast(); for (int i=0; i<lvds -> NumVariableDeclarators();i++) { DeclareLocalVariable(lvds -> VariableDeclarator(i)); } } break; case Ast::EMPTY_STATEMENT: // JLS 13.5 break; case Ast::EXPRESSION_STATEMENT: // JLS 13.7 EmitStatementExpression(statement -> ExpressionStatementCast() -> expression); break; case Ast::IF: // JLS 13.8 { AstIfStatement * ifStatement = (AstIfStatement *) statement; if (ifStatement -> expression -> IsConstant()) { IntLiteralValue *if_constant_expr = (IntLiteralValue *) ifStatement -> expression -> value; // Open question (DS, 20 Jan 97): Should be we setting abrupt here? If we weren't // doing this optimization, then we wouldn't be setting abrupt. Note that if expression // is, for example, non-zero and then-block terminates abruptly, then the following // statement is unreachable. if (if_constant_expr -> value) EmitStatement(ifStatement -> true_statement); else if (ifStatement -> false_statement_opt) // if there is false part EmitStatement(ifStatement -> false_statement_opt); } else { if (ifStatement -> false_statement_opt) { // if true and false parts Label label1; Label label2; int true_abrupt; // set if last statement in true block is abrupt exit int false_abrupt; // set if last statement in false block is abrupt exit EmitBranchIfExpression(ifStatement -> expression, false, label1); stack_depth = 0; true_abrupt = EmitStatement(ifStatement -> true_statement); if (!true_abrupt) { EmitBranch(OP_GOTO,label2); } DefineLabel(label1); false_abrupt = EmitStatement(ifStatement -> false_statement_opt); if (!true_abrupt) { DefineLabel(label2); } CompleteLabel(label1); CompleteLabel(label2); // if terminates abruptly only if both clauses terminate abruptly abrupt = true_abrupt ? false_abrupt : 0; } else { // if no false part Label label1; EmitBranchIfExpression(ifStatement -> expression, false, label1); stack_depth=0; (void) EmitStatement(ifStatement -> true_statement); DefineLabel(label1); CompleteLabel(label1); } } } break; case Ast::SWITCH: // JLS 13.9 EmitSwitchStatement(statement -> SwitchStatementCast()); break; case Ast::SWITCH_BLOCK: // JLS 13.9 case Ast::CASE: // JLS 13.9 case Ast::DEFAULT: // JLS 13.9 // these nodes handled by SwitchStatement and // are not directly visited break; case Ast::WHILE: { // JLS 13.10 AstWhileStatement * wp = statement -> WhileStatementCast(); // branch to continuation test. This test is placed after the // body of the loop we can fall through into it after each // loop iteration without the need for an additional branch. int while_depth = this_block_depth; EmitBranch(OP_GOTO,continue_labels[while_depth]); DefineLabel(begin_labels[while_depth]); (void) EmitStatement(wp -> statement); DefineLabel(continue_labels[while_depth]); stack_depth=0; EmitBranchIfExpression(wp -> expression,true, begin_labels[while_depth]); CompleteLabel(begin_labels[while_depth]); CompleteLabel(continue_labels[while_depth]); } break; case Ast::DO: // JLS 13.11 { AstDoStatement * sp = statement -> DoStatementCast(); int do_depth=this_block_depth; DefineLabel(begin_labels[do_depth]); (void) EmitStatement(sp -> statement); DefineLabel(continue_labels[do_depth]); stack_depth=0; EmitBranchIfExpression(sp -> expression,true, begin_labels[do_depth]); CompleteLabel(begin_labels[do_depth]); CompleteLabel(continue_labels[do_depth]); } break; case Ast::FOR: // JLS 13.12 { int i; int for_depth; AstForStatement * forStatement = statement -> ForStatementCast(); for_depth=this_block_depth; for (i=0; i<forStatement -> NumForInitStatements();i++) { EmitStatement((AstStatement *) forStatement -> ForInitStatement(i)); } EmitBranch(OP_GOTO,test_labels[for_depth]); DefineLabel(begin_labels[for_depth]); (void) EmitStatement(forStatement -> statement); DefineLabel(continue_labels[for_depth]); for (i=0; i<forStatement -> NumForUpdateStatements();i++) { (void) EmitStatement((AstStatement *) forStatement -> ForUpdateStatement(i)); } DefineLabel(test_labels[for_depth]); if (forStatement -> end_expression_opt) { stack_depth=0; EmitBranchIfExpression(forStatement -> end_expression_opt,true, begin_labels[for_depth]); } else { EmitBranch(OP_GOTO,begin_labels[for_depth]); } CompleteLabel(begin_labels[for_depth]); CompleteLabel(test_labels[for_depth]); CompleteLabel(continue_labels[for_depth]); } break; case Ast::BREAK: // JLS 13.13 ProcessAbruptExit(statement -> BreakStatementCast() -> nesting_level); EmitBranch(OP_GOTO,break_labels[statement -> BreakStatementCast() -> nesting_level]); abrupt = 1; break; case Ast::CONTINUE: // JLS 13.14 ProcessAbruptExit(statement -> ContinueStatementCast() -> nesting_level); EmitBranch(OP_GOTO,continue_labels[statement -> ContinueStatementCast() -> nesting_level]); abrupt = 1; break; case Ast::RETURN: // JLS 13.15 EmitReturnStatement(statement -> ReturnStatementCast()); abrupt = 1; break; case Ast::SUPER_CALL: EmitSuperInvocation((AstSuperCall *) statement); break; case Ast::THIS_CALL: EmitThisInvocation((AstThisCall *) statement); break; case Ast::THROW: // JLS 13.16 EmitExpression(statement -> ThrowStatementCast() -> expression); PutOp(OP_ATHROW); abrupt = 1; break; case Ast::SYNCHRONIZED_STATEMENT: // JLS 13.17 EmitSynchronizedStatement(statement -> SynchronizedStatementCast()); break; case Ast::TRY: // JLS 13.18 EmitTryStatement(statement -> TryStatementCast()); break; case Ast::CLASS: // Class Declaration case Ast::INTERFACE: // InterfaceDeclaration // these are factored out by the front end; and so must be skipped here break; case Ast::CATCH: // JLS 13.18 case Ast::FINALLY: // JLS 13.18 // handled by TryStatement default: chaos("unknown statement kind"); break; } return abrupt; } void ByteCode::EmitReturnStatement(AstReturnStatement * statement) { int var_index=-1; int i; if (statement -> expression_opt == NULL) { // no return value ProcessAbruptExit(0); PutOp(OP_RETURN); return; } TypeSymbol * return_type = statement -> expression_opt-> Type(); EmitExpression(statement -> expression_opt); if (method_type != return_type) { // no need to cast from reference to Object -- always ok if (method_type == this_control.Object() && IsReferenceType(return_type)) { } else { EmitCast(method_type, return_type); } } if (synchronized_blocks) { // if any outstanding synchronized blocks // find the index of the innermost enclosing block that is // synchronized. This block will have the variables allocated // for saving synchronization information. int synch_block=this_block_depth; for (i=this_block_depth;;i--) { if (is_synchronized[i]) { synch_block = i; break; } else if (i==0) { chaos("unable to find synchronization block"); } } var_index=block_symbols[synch_block] -> synchronized_variable_index+2;; // if (this_control.IsDoubleWordType(return_type)) var_index--; } else if (finally_blocks) { for (i=this_block_depth;;i--) { if (has_finally_clause[i]) { var_index = has_finally_clause[i] - 1; var_index += 2; // move to start of area to save value break; } else if (i==0) { chaos("unable to find finally block"); } } } if (var_index >= 0) { // if need to save before abrupt exit StoreLocal(var_index, method_type); ProcessAbruptExit(0); LoadLocal(var_index, method_type); } if (method_type != this_control.void_type) GenerateReturn(method_type); } int ByteCode::EmitBlockStatement(AstBlock *block, int synchronized) { BlockSymbol *block_symbol = block -> block_symbol; int nesting_level = block -> nesting_level; int length=0; int start_pc; int save_depth = this_block_depth; int this_depth = nesting_level; #ifdef TBSL AstStatement * last_statement; #endif int i; int last_kind=0; this_block_depth = nesting_level; is_synchronized[this_depth] = synchronized; synchronized_blocks += synchronized; block_symbols[this_depth] = block_symbol; start_pc = code_attribute -> code.Length(); stack_depth = 0; // stack empty at start of statement if (this_depth>max_block_depth) { cout << "this_depth " << this_depth << "max " << max_block_depth << "\n"; chaos("loops too deeply nested"); } if (block -> NumStatements() > 0) { for (i=0; i<block -> NumStatements();i++){ last_kind = EmitStatement((AstStatement *) block -> Statement(i)); } if (this_block_depth != this_depth) { chaos("block depth out of synch!"); } // this_block_depth = this_depth; // in case altered by one of above blocks } // if last statement is if_statement, must supply NOP to serve // as target for branch from true part // TODO - must refine this test so detect other cases where may // need following code, such as Switch, For, While; but // not if procedure returns void // code to end block (former end_block()) // always define LABEL_BREAK at this point, and complete definition // of other labels if (IsLabelUsed(break_labels[this_depth])) { // need define only if used DefineLabel(break_labels[this_depth]); } CompleteLabel(begin_labels[this_depth]); CompleteLabel(break_labels[this_depth]); CompleteLabel(continue_labels[this_depth]); CompleteLabel(test_labels[this_depth]); CompleteLabel(begin_labels[this_depth]); if (is_synchronized[this_depth]) synchronized_blocks--; // if (this_block_depth) this_block_depth--; #ifdef TBSL if (block_statements) { if (block -> NumStatements()) { last_statement = (AstStatement *) block -> Statement(block -> NumStatements()-1); if (last_statement -> IfStatementCast()) { PutNop(1); } } } #endif // compute local variable table and max variable number UpdateBlockInfo(block_symbol); this_block_depth = save_depth; return last_kind; } void ByteCode::EmitStatementExpression(AstExpression * expression) { switch (expression -> kind) { case Ast::PARENTHESIZED_EXPRESSION: { AstParenthesizedExpression * pe = (AstParenthesizedExpression *) expression; EmitStatementExpression(pe -> expression); } break; case Ast::CALL: (void) EmitMethodInvocation((AstMethodInvocation *)expression, 0); if (expression-> Type()!=this_control.void_type) { if (this_control.IsDoubleWordType(expression-> Type())) { PutOp(OP_POP2); } else { PutOp(OP_POP); // discard value if used as statement } } break; case Ast::POST_UNARY: (void) EmitPostUnaryExpression((AstPostUnaryExpression *)expression,0); break; case Ast::PRE_UNARY: (void) EmitPreUnaryExpression((AstPreUnaryExpression *)expression,0); break; case Ast::ASSIGNMENT: EmitAssignmentExpression((AstAssignmentExpression *)expression,0); break; case Ast::CLASS_CREATION: (void) EmitClassInstanceCreationExpression((AstClassInstanceCreationExpression *) expression, 0); break; default: chaos("invalid statement expression kind"); } } void ByteCode::EmitSwitchStatement(AstSwitchStatement * sws) { // generate code for switch statement. Good code generation requires // detailed knowledge of the target machine. Lacking this, we simply // choose between LOOKUPSWITCH and TABLESWITCH by picking that // opcode that takes the least number of bytes in the byte code. int use_lookup=0; // set if using LOOKUPSWITCH opcode // compare sizes os generated opcodes, ignoring size of common // header (opcode through default bytes). int high,low,ncases,switch_depth; int has_default; int op_start; int i; int nlabels; int map_index; int label_index; int start_pc; int ci; int di; AstBlock *switch_block=sws -> switch_block; BlockSymbol * block_symbol = switch_block -> block_symbol; switch_depth = sws -> switch_block -> nesting_level; EmitBlockStatement(switch_block, 0); // We need only worry about the presence of a default case if there // is code for it. start_pc = code_attribute -> code.Length(); has_default = sws -> default_case.switch_block_statement!=NULL ? 1 : 0; ncases = sws -> map.Length(); // Use tableswitch if have exact match or size of tableswitch // case is no more than 30 bytes more code than lookup case use_lookup=1; nlabels=ncases; if (ncases) { low = sws -> map[0] -> Value(); high = sws -> map[ncases-1] -> Value(); // want to compute // (2+high-low+1)<(1+ncases*2+30 // but must guard against overflow, so factor out // high - low < ncases*2 + 28 // but can't have number of labels < number of cases if ((high-low) < (ncases*2+28)) { use_lookup = 0; // use tableswitch nlabels = high-low + 1; } // correct estimate in case above computation gave ridiculous number // for the number of labels. (This is problem 096) if (nlabels < ncases) { use_lookup = 1; nlabels = ncases; } } EmitExpression(sws -> expression); stack_depth=0; PutOp(use_lookup ? OP_LOOKUPSWITCH : OP_TABLESWITCH); op_start = last_op_pc; // pc at start of instruction // supply any needed padding while(code_attribute -> code.Length() % 4) { PutNop(0); } // note that if no default clause in switch statement, must allocate // one that corresponds to do nothing and branches to start of next // statement. Label default_label; UseLabel(has_default ? default_label : break_labels[switch_depth], 4,code_attribute -> code.Length()-op_start); if (use_lookup) PutU4(ncases); else { PutU4(low); PutU4(high); } // how to allocate for proper length Label *case_labels = new Label[(use_lookup ? ncases : nlabels) + 1]; if (use_lookup == 0) { int *has_tag = new int[nlabels + 1]; for (i = 0; i < nlabels; i++) has_tag[i] = 0; // mark cases for which no case tag available, i.e., default cases for (i=0;i<sws -> switch_block -> NumStatements();i++) { int li; AstSwitchBlockStatement * sbs = (AstSwitchBlockStatement *) sws -> switch_block -> Statement(i); // process labels for this block for (li=0;li<sbs -> NumSwitchLabels();li++) { if (sbs -> SwitchLabel(li) -> CaseLabelCast()) { map_index =sbs -> SwitchLabel(li) -> CaseLabelCast() -> map_index; di =sws -> map[map_index] -> index; // label_index = sws -> map[di] -> Value() - low; label_index = sws -> map[map_index] -> Value() - low; has_tag[label_index]=1; } } } // now emit labels in instruction, using appropriate index for (i=0;i<nlabels;i++) { UseLabel(has_tag[i] ? case_labels[i] : has_default ? default_label : break_labels[switch_depth], 4,code_attribute -> code.Length()-op_start); } delete [] has_tag; } else { for (i=0;i<ncases;i++) { PutU4(sws -> map[i] -> Value()); UseLabel(case_labels[sws -> map[i] -> index],4,code_attribute -> code.Length()-op_start); } } // march through switch block statements, compiling blocks in // proper order. We must respect order in which blocks seen // so that blocks lacking a terminal break fall through to the // proper place. for (i=0;i<sws -> switch_block -> NumStatements();i++) { int li; AstSwitchBlockStatement * sbs = (AstSwitchBlockStatement *) sws -> switch_block -> Statement(i); // process labels for this block for (li=0;li<sbs -> NumSwitchLabels();li++) { if (sbs -> SwitchLabel(li) -> CaseLabelCast()) { map_index =sbs -> SwitchLabel(li) -> CaseLabelCast() -> map_index; if (use_lookup) { DefineLabel(case_labels[map_index]); } else { int found=0; // look for case with same index and // use its value to find label index. for (int di2=0;di2<sws -> map.Length();di2++) { if (sws -> map[di2] -> index==map_index) { ci = sws -> map[di2] -> Value()-low; DefineLabel(case_labels[ci]); found=1; break; } } if (found==0) chaos("unable to find case label"); } } else { if (sbs -> SwitchLabel(li) -> DefaultLabelCast()) { if (has_default) { DefineLabel(default_label); } else { chaos("error in processing default label"); } } } } // compile code for this case for (li=0;li<sbs -> NumStatements();li++) { (void) EmitStatement(sbs -> Statement(li) -> StatementCast()); } } UpdateBlockInfo(block_symbol); for (i=0;i<nlabels;i++) { if (case_labels[i].uses.Length() && case_labels[i].defined==0) { case_labels[i].defined=1; if (has_default) { case_labels[i].definition=default_label.definition; } else { case_labels[i].definition = break_labels[switch_depth].definition; } } CompleteLabel(case_labels[i]); } if (has_default) { CompleteLabel(default_label); } // define target of break label if (IsLabelUsed(break_labels[switch_depth])) { // need define only if used DefineLabel(break_labels[switch_depth]); } for (i=0;i<nlabels;i++) { if (case_labels[i].uses.Length() && case_labels[i].defined==0) { case_labels[i].defined=1; if (has_default) { case_labels[i].definition=default_label.definition; } else { case_labels[i].definition = break_labels[switch_depth].definition; } } CompleteLabel(case_labels[i]); } if (has_default) { CompleteLabel(default_label); } // define target of break label if (IsLabelUsed(break_labels[switch_depth])) { // need define only if used CompleteLabel(break_labels[switch_depth]); } // note that if using table, then must provide slot for every // entry in the range low..high, even though the user may not // have provided an explicit entry, in which case the default // action is to be taken. For example // switch (e) { // case 1:2:3: act1; break; // case 5:6: act2; break; // default: defact; break; // } // translated as // switch (e) // switch (e) { // case 1:2:3: act1; break; // case 4: goto defa: // case 5:6: act2; break; // defa: // default: defact; // } delete [] case_labels; } // 13.18 The try statement void ByteCode::EmitTryStatement(AstTryStatement * statement) { AstFinallyClause * finally_clause; int start_pc,end_pc; int exception_index,handler_pc; Label end_label; AstCatchClause * catch_clause; int last_abrupt=0; // set if last statement in try block is abrupt exit int try_depth = statement -> block -> nesting_level - 1;; int final_depth = try_depth + 1; BlockSymbol * block_symbol; start_pc = code_attribute -> code.Length(); // start pc if (statement -> finally_clause_opt) { // call finally block if have finally handler assert(block_symbols[try_depth]); block_symbol = block_symbols[try_depth] -> BlockCast(); finally_clause = statement -> finally_clause_opt; has_finally_clause[final_depth]=1 + block_symbol -> try_variable_index; finally_blocks++; } last_abrupt = EmitStatement(statement -> block); // increment max_stack in case exception thrown while stack at greatest depth code_attribute -> max_stack++; if (statement -> finally_clause_opt) { // call finally block if have finally handler PutOp(OP_JSR); UseLabel(final_labels[final_depth], 2, 1); } if (!last_abrupt) { EmitBranch(OP_GOTO,end_label); } PutNop(0); // emit NOP so end_pc will come out right end_pc = last_op_pc; // process catch clauses int catch_abrupt=0; for (int i = 0; i<statement -> NumCatchClauses();i++) { catch_clause = statement -> CatchClause(i); VariableSymbol * parameter_symbol = catch_clause -> parameter_symbol; handler_pc = code_attribute -> code.Length(); StoreLocalVariable(parameter_symbol); catch_abrupt = EmitStatement(catch_clause -> block); exception_index = code_attribute -> exception_table.NextIndex(); code_attribute -> exception_table[exception_index].start_pc = start_pc; // add 1 to end_pc since it is exclusive, while start_pc // is inclusive. See footnote in 4.4.4 of JVM Specification //code_attribute -> exception_table[exception_index].end_pc = end_pc + 1; // DS 11 feb code_attribute -> exception_table[exception_index].end_pc = end_pc; // DS 11 feb code_attribute -> exception_table[exception_index].handler_pc = handler_pc; code_attribute -> exception_table[exception_index].catch_type = RegisterClass(parameter_symbol-> Type() -> fully_qualified_name); if (statement -> finally_clause_opt) { // call finally block if have finally handler PutOp(OP_JSR); UseLabel(final_labels[final_depth], 2, 1); } if (! catch_abrupt) { EmitBranch(OP_GOTO,end_label); } } if (statement -> finally_clause_opt) { handler_pc = code_attribute -> code.Length(); has_finally_clause[final_depth] = 0; // reset once finally clause processed finally_blocks--; // handler for finally() // push thrown value StoreLocal(block_symbol -> try_variable_index, this_control.Object()); PutOp(OP_JSR); UseLabel(final_labels[final_depth], 2, 1); LoadLocal(block_symbol -> try_variable_index, this_control.Object()); PutOp(OP_ATHROW); // and rethrow the value to the invoker DefineLabel(final_labels[final_depth]); CompleteLabel(final_labels[final_depth]); StoreLocal(block_symbol -> try_variable_index+1, this_control.Object()); // save return address (void) EmitStatement(statement -> finally_clause_opt -> block); PutOp(OP_RET); PutU1(block_symbol -> try_variable_index + 1); // return using saved address exception_index = code_attribute -> exception_table.NextIndex(); code_attribute -> exception_table[exception_index].start_pc = start_pc; code_attribute -> exception_table[exception_index].end_pc = handler_pc; code_attribute -> exception_table[exception_index].handler_pc = handler_pc; code_attribute -> exception_table[exception_index].catch_type = 0; } if (IsLabelUsed(end_label)) { DefineLabel(end_label); CompleteLabel(end_label); PutNop(1); // to make sure have code after end of try statement } else { CompleteLabel(end_label); } } void ByteCode::UpdateBlockInfo(BlockSymbol * block_symbol) { int i; if (code_attribute -> max_locals<block_symbol -> max_variable_index) { code_attribute -> max_locals = block_symbol -> max_variable_index; } if (block_symbol == (BlockSymbol *) 0) { chaos("null block symbol"); } if (this_control.option.g) { // compute local variable table for (i = 0; i < block_symbol -> NumVariableSymbols();i++) { VariableSymbol * sym = block_symbol -> VariableSym(i); // only make entry if defined within range if (last_op_pc > sym -> local_program_counter) { AddLocalVariableTableEntry(sym -> local_program_counter, last_op_pc - sym -> local_program_counter, RegisterUtf8(sym -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(sym-> Type() -> signature), sym -> LocalVariableIndex()); } } } } void ByteCode::ProcessAbruptExit(int to_lev) { // exit to block at level lev, freeing monitor locks and invoking finally clauses as appropriate for (int lev=this_block_depth;lev>to_lev;lev--) { if (has_finally_clause[lev]) { PutOp(OP_JSR); UseLabel(final_labels[lev], 2, 1); } else if (is_synchronized[lev]) { PutOp(OP_JSR); UseLabel(monitor_labels[lev], 2, 1); } } } void ByteCode::EmitBranch(unsigned int opc, Label& lab) { // generate branch PutOp(opc); UseLabel(lab,2,1); } void ByteCode::EmitBranchIfExpression(AstExpression *p, bool cond,Label &lab) { // java provides a variety of conditional branch instructions, so // that a number of operators merit special handling: // constant operand // negation (we eliminate it) // equality // && and || (partial evaluation) // comparisons // Other expressions are just evaluated and the appropriate // branch emitted. AstExpression *left,*right,*temp; AstPreUnaryExpression *pre; TypeSymbol *left_type, *right_type; if (p -> ParenthesizedExpressionCast()) { p = UnParenthesize(p); } if (p -> IsConstant()) { if (IsZero(p)) { if (cond == false) EmitBranch(OP_GOTO,lab); } else { if (cond == true) EmitBranch(OP_GOTO,lab); } return; } pre = p -> PreUnaryExpressionCast(); if (pre) { // must be !, though should probably // branch_if(!e,c,l) => branch_if(e,!c,l) // test opcode // call again with complementary control expression to show // effect of negation if (pre -> pre_unary_tag == AstPreUnaryExpression::NOT) { EmitBranchIfExpression(pre -> expression,cond == true ? false : true, lab); return; } else { chaos("branch_if expects ! in this context"); } } // dispose of non-binary expression case by just evaluating // operand and emitting appropiate test. if (!(p -> BinaryExpressionCast())) { EmitExpression(p); EmitBranch(cond == true ? OP_IFNE : OP_IFEQ,lab); return; } // Here if binary expression, so extract operands AstBinaryExpression * bp = (AstBinaryExpression *) p; left = bp -> left_expression; if (left -> ParenthesizedExpressionCast()) { left = UnParenthesize(left); } right = bp -> right_expression; if (right -> ParenthesizedExpressionCast()) { right = UnParenthesize(right); } left_type = left-> Type(); right_type = right-> Type(); switch (bp -> binary_tag) { case AstBinaryExpression::INSTANCEOF: { EmitExpression(left); PutOp(OP_INSTANCEOF); TypeSymbol * instanceof_type = bp -> right_expression-> Type(); if (instanceof_type -> num_dimensions) { PutU2(RegisterClass(instanceof_type -> signature)); } else { PutU2(RegisterClass(instanceof_type -> fully_qualified_name)); } EmitBranch(cond == true? OP_IFNE : OP_IFEQ,lab); } return; case AstBinaryExpression::AND_AND: /* branch_if(a&&b, true, lab) => branch_if(a,false,skip); branch_if(b,true,lab); skip: branch_if(a&&b, false, lab) => branch_if(a,false,lab); branch_if(b,false,lab); */ if (cond == true) { Label skip; EmitBranchIfExpression(left, false, skip); EmitBranchIfExpression(right, true, lab); DefineLabel(skip); CompleteLabel(skip); } else { EmitBranchIfExpression(left, false, lab); EmitBranchIfExpression(right, false, lab); } return; case AstBinaryExpression::OR_OR: /* branch_if(a||b,true,lab) => branch_if(a,true,lab); branch_if(b,true,lab); branch_if(a||b,false,lab) => branch_if(a,true,skip); branch_if(b,false,lab); There is additional possibility of one of the operands being constant that should be dealt with at some point. */ if (cond == true) { EmitBranchIfExpression(left, true, lab); EmitBranchIfExpression(right, true, lab); } else { Label skip; EmitBranchIfExpression(left, true, skip); EmitBranchIfExpression(right, false, lab); DefineLabel(skip); CompleteLabel(skip); } return; case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: // see if test against null if (left_type == this_control.null_type || right_type==this_control.null_type) { // arrange so right operand is null if (left_type == this_control.null_type) { temp = left;left = right;right = temp; left_type = left-> Type(); right_type = right-> Type(); } EmitExpression(left); if (bp -> binary_tag == AstBinaryExpression::EQUAL_EQUAL) { EmitBranch(cond == true? OP_IFNULL : OP_IFNONNULL,lab); } else { EmitBranch(cond == true ? OP_IFNONNULL : OP_IFNULL,lab); } return; } // see if test against integer zero if (IsZero(left) || IsZero(right)) { // arrange so right operand is zero if (IsZero(left)) { temp = left;left = right;right = temp; left_type = left-> Type();right_type = right-> Type(); } EmitExpression(left); if (bp -> binary_tag == AstBinaryExpression::EQUAL_EQUAL) { EmitBranch(cond == true? OP_IFEQ : OP_IFNE,lab); return; } else { EmitBranch(cond == true ? OP_IFNE : OP_IFEQ,lab); } return; } // see if test of integers if ((this_control.IsSimpleIntegerValueType(left_type)||left_type==this_control.boolean_type) && (this_control.IsSimpleIntegerValueType(right_type) || right_type == this_control.boolean_type) ) { EmitExpression(left); EmitExpression(right); if (bp -> binary_tag == AstBinaryExpression::EQUAL_EQUAL) { EmitBranch(cond ? OP_IF_ICMPEQ : OP_IF_ICMPNE,lab); return; } else { EmitBranch(cond ? OP_IF_ICMPNE : OP_IF_ICMPEQ,lab); } return; } else if (IsReferenceType(left_type) && IsReferenceType(right_type)) { // else just do the comparison EmitExpression(left); EmitExpression(right); if (bp -> binary_tag == AstBinaryExpression::EQUAL_EQUAL) { EmitBranch(cond ? OP_IF_ACMPEQ : OP_IF_ACMPNE,lab); } else { EmitBranch(cond ? OP_IF_ACMPNE : OP_IF_ACMPEQ,lab); } return; } } // here if not comparison, comparison for non-integral numeric types, or // integral comparison for which no special casing needed. // Begin by dealing with non-comparisons switch(bp -> binary_tag) { case AstBinaryExpression::LESS: case AstBinaryExpression::LESS_EQUAL: case AstBinaryExpression::GREATER: case AstBinaryExpression::GREATER_EQUAL: case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: break; // break to continue comparison processing default: // not a comparison, get the (necessarily boolean) value // of the expression and branch on the result EmitExpression(p); EmitBranch(cond ? OP_IFNE : OP_IFEQ, lab); return; } unsigned opcode = 0; unsigned int op_true, op_false; if (this_control.IsSimpleIntegerValueType(left_type) || left_type == this_control.boolean_type) { // we have already dealt with EQUAL_EQUAL and NOT_EQUAL for // integers, but still need to look for comparisons for which // one operand may be zero. if (IsZero(left)) { EmitExpression(right); switch(bp -> binary_tag) { case AstBinaryExpression::LESS: // if (0<x) same as if (x>0) op_true = OP_IFGT; op_false = OP_IFLE; break; case AstBinaryExpression::LESS_EQUAL: // if (0<=x) same as if (x>=0) op_true = OP_IFGE; op_false = OP_IFLT; break; case AstBinaryExpression::GREATER: // if (0>x) same as if (x<0) op_true = OP_IFLT; op_false = OP_IFGE; break; case AstBinaryExpression::GREATER_EQUAL: // if (0>=x) same as if (x<=0) op_true = OP_IFLE; op_false = OP_IFGT; break; } } else if (IsZero(right)) { EmitExpression(left); switch(bp -> binary_tag) { case AstBinaryExpression::LESS: op_true = OP_IFLT; op_false = OP_IFGE; break; case AstBinaryExpression::LESS_EQUAL: op_true = OP_IFLE; op_false = OP_IFGT; break; case AstBinaryExpression::GREATER: op_true = OP_IFGT; op_false = OP_IFLE; break; case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IFGE; op_false = OP_IFLT; break; } } else { EmitExpression(left); EmitExpression(right); switch(bp -> binary_tag) { case AstBinaryExpression::LESS: op_true = OP_IF_ICMPLT; op_false = OP_IF_ICMPGE; break; case AstBinaryExpression::LESS_EQUAL: op_true = OP_IF_ICMPLE; op_false = OP_IF_ICMPGT; break; case AstBinaryExpression::GREATER: op_true = OP_IF_ICMPGT; op_false = OP_IF_ICMPLE; break; case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IF_ICMPGE; op_false = OP_IF_ICMPLT; break; } } } else if (left_type == this_control.long_type) { EmitExpression(left); EmitExpression(right); opcode = OP_LCMP; // branch according to result value on stack switch (bp -> binary_tag) { case AstBinaryExpression::EQUAL_EQUAL: op_true = OP_IFEQ; op_false = OP_IFNE; break; case AstBinaryExpression::NOT_EQUAL: op_true = OP_IFNE; op_false = OP_IFEQ; break; case AstBinaryExpression::LESS: op_true = OP_IFLT; op_false = OP_IFGE; break; case AstBinaryExpression::LESS_EQUAL: op_true = OP_IFLE; op_false = OP_IFGT; break; case AstBinaryExpression::GREATER: op_true = OP_IFGT; op_false = OP_IFLE; break; case AstBinaryExpression::GREATER_EQUAL: op_true = OP_IFGE; op_false = OP_IFLT; break; } } else if (left_type == this_control.float_type) { EmitExpression(left); EmitExpression(right); switch (bp -> binary_tag) { case AstBinaryExpression::EQUAL_EQUAL: opcode = OP_FCMPL; op_true = OP_IFEQ; op_false = OP_IFNE; break; case AstBinaryExpression::NOT_EQUAL: opcode = OP_FCMPL; op_true = OP_IFNE; op_false = OP_IFEQ; break; case AstBinaryExpression::LESS: opcode = OP_FCMPG; op_true = OP_IFLT; op_false = OP_IFGE; break; case AstBinaryExpression::LESS_EQUAL: opcode = OP_FCMPG; op_true = OP_IFLE; op_false = OP_IFGT; break; case AstBinaryExpression::GREATER: opcode = OP_FCMPL; op_true = OP_IFGT; op_false = OP_IFLE; break; case AstBinaryExpression::GREATER_EQUAL: opcode = OP_FCMPL; op_true = OP_IFGE; op_false = OP_IFLT; break; } } else if (left_type == this_control.double_type) { EmitExpression(left); EmitExpression(right); switch (bp -> binary_tag) { case AstBinaryExpression::EQUAL_EQUAL: opcode = OP_DCMPL; op_true = OP_IFEQ; op_false = OP_IFNE; break; case AstBinaryExpression::NOT_EQUAL: opcode = OP_DCMPL; op_true = OP_IFNE; op_false = OP_IFEQ; break; case AstBinaryExpression::LESS: opcode = OP_DCMPG; op_true = OP_IFLT; op_false = OP_IFGE; break; case AstBinaryExpression::LESS_EQUAL: opcode = OP_DCMPG; op_true = OP_IFLE; op_false = OP_IFGT; break; case AstBinaryExpression::GREATER: opcode = OP_DCMPL; op_true = OP_IFGT; op_false = OP_IFLE; break; case AstBinaryExpression::GREATER_EQUAL: opcode = OP_DCMPL; op_true = OP_IFGE; op_false = OP_IFLT; break; } } else { chaos("comparison of unsupported type"); } if (opcode) PutOp(opcode); // if need to emit comparison before branch EmitBranch (cond ? op_true: op_false, lab); } void ByteCode::EmitSynchronizedStatement(AstSynchronizedStatement * statement) { int var_index; // local variable index to save address of object int loc_index; // local variable index to save address int start_pc,end_pc; int exception_index,handler_pc; Label end_label; var_index = statement -> block -> block_symbol -> synchronized_variable_index; loc_index = var_index+1; EmitExpression(statement -> expression); StoreLocal(var_index, this_control.Object()); // save address of object LoadLocal(var_index, this_control.Object()); // load address of object onto stack PutOp(OP_MONITORENTER); // enter monitor associated with object start_pc = code_attribute -> code.Length(); // start pc (void) EmitBlockStatement(statement -> block, 1); LoadLocal(var_index, this_control.Object()); // load address of object onto stack PutOp(OP_MONITOREXIT); if (statement -> block -> NumStatements() > 0) { end_pc = last_op_pc; EmitBranch(OP_GOTO,end_label); // branch around exception handler // reach here if any // increment max_stack in case exception thrown while stack at greatest depth code_attribute -> max_stack++; handler_pc = code_attribute -> code.Length(); LoadLocal(var_index, this_control.Object()); // load address of object onto stack PutOp(OP_MONITOREXIT); PutOp(OP_ATHROW); exception_index = code_attribute -> exception_table.NextIndex(); code_attribute -> exception_table[exception_index].start_pc = start_pc; code_attribute -> exception_table[exception_index].end_pc = handler_pc; code_attribute -> exception_table[exception_index].handler_pc = handler_pc; code_attribute -> exception_table[exception_index].catch_type = 0; DefineLabel(monitor_labels[statement -> block -> nesting_level]); CompleteLabel(monitor_labels[statement -> block -> nesting_level]); StoreLocal(loc_index, this_control.Object()); // save return address LoadLocal(var_index, this_control.Object()); // load address of object onto stack PutOp(OP_MONITOREXIT); PutOp(OP_RET); PutU1(loc_index); // return using saved address DefineLabel(end_label); CompleteLabel(end_label); // EmitNop(1); // guarantee some PutOp after block in case // the synchronized statement is the last in the procedure. } } // JLS is Java Language Specification // JVM is Java Virtual Machine // // Expressions: Chapter 14 of JLS int ByteCode::EmitExpression(AstExpression *expression) { if (expression -> IsConstant()) { return LoadConstant(expression); } switch (expression -> kind) { case Ast::IDENTIFIER: if (expression -> SimpleNameCast() && expression -> SimpleNameCast() -> resolution_opt) { return EmitExpression(expression -> SimpleNameCast() -> resolution_opt); } return LoadSimple(GetLHSKind(expression, (MethodSymbol *)0),expression); case Ast::INTEGER_LITERAL: case Ast::LONG_LITERAL: case Ast::FLOATING_POINT_LITERAL: case Ast::DOUBLE_LITERAL: case Ast::TRUE_LITERAL: case Ast::FALSE_LITERAL: case Ast::STRING_LITERAL: case Ast::CHARACTER_LITERAL: return LoadConstant(expression); case Ast::THIS_EXPRESSION: case Ast::SUPER_EXPRESSION: PutOp(OP_ALOAD_0); // must be use return 1; case Ast::PARENTHESIZED_EXPRESSION: { AstParenthesizedExpression * pe = (AstParenthesizedExpression *) expression; return EmitExpression(expression -> ParenthesizedExpressionCast() -> expression); } case Ast::CLASS_CREATION: return EmitClassInstanceCreationExpression((AstClassInstanceCreationExpression *)expression, 1); case Ast::ARRAY_CREATION: return EmitArrayCreationExpression((AstArrayCreationExpression *)expression); case Ast::DIM: return EmitExpression(expression -> DimExprCast() -> expression); case Ast::DOT: { AstFieldAccess * field_access =(AstFieldAccess *)expression; return ((field_access -> IsClassAccess()) && (field_access -> resolution_opt)) ? (ClassFile::type -> outermost_type -> ACC_INTERFACE() ? EmitExpression(field_access -> resolution_opt) : GenerateClassAccess(field_access)) : EmitFieldAccess(field_access); } case Ast::CALL: return EmitMethodInvocation((AstMethodInvocation *)expression, 0); case Ast::ARRAY_ACCESS: // if seen alone this will be as RHS return EmitArrayAccessRHS((AstArrayAccess *) expression); case Ast::POST_UNARY: return EmitPostUnaryExpression((AstPostUnaryExpression *)expression,1); case Ast::PRE_UNARY: return EmitPreUnaryExpression((AstPreUnaryExpression *)expression,1); case Ast::CAST: { AstCastExpression * cast_expression = expression -> CastExpressionCast(); if (cast_expression -> expression-> Type() -> Primitive()) { // primitive types require casting return EmitCastExpression(cast_expression); } else { // not need to cast, just evaluate operand return EmitExpression(cast_expression -> expression); } } case Ast::CHECK_AND_CAST: return EmitCastExpression((AstCastExpression *)expression); case Ast::BINARY: return EmitBinaryExpression((AstBinaryExpression *)expression); case Ast::CONDITIONAL: return EmitConditionalExpression((AstConditionalExpression *)expression); case Ast::ASSIGNMENT: return EmitAssignmentExpression((AstAssignmentExpression *)expression,1); case Ast::NULL_LITERAL: PutOp(OP_ACONST_NULL); return 1; default: chaos("unknown expression kind"); return 0; // even tho will not reach here } } void ByteCode::EmitArrayAccessLHS(AstArrayAccess *expression) { LoadReference(expression -> base); EmitExpression(expression -> expression); } int ByteCode::EmitArrayAccessRHS(AstArrayAccess *expression) { EmitArrayAccessLHS(expression); // get array address and index return LoadArrayElement(expression-> Type()); } void ByteCode::EmitFieldAccessLHSBase(AstExpression * expression) { AstFieldAccess * field; AstSimpleName * simple_name; field = expression -> FieldAccessCast(); if (field){ if (field -> resolution_opt) { expression = field -> resolution_opt; } } else if (expression -> SimpleNameCast()) { simple_name = expression -> SimpleNameCast(); if (simple_name -> resolution_opt) { expression = simple_name -> resolution_opt; } } VariableSymbol * sym = (VariableSymbol *) expression -> symbol; field = expression -> FieldAccessCast(); if (field){ EmitExpression(field -> base); } else if (expression -> SimpleNameCast()) { PutOp(OP_ALOAD_0); // get address of "this" } else { chaos("unexpected AssignmentExpressionField operand base type"); } } void ByteCode::EmitFieldAccessLHS(AstExpression * expression) { EmitFieldAccessLHSBase(expression); PutOp(OP_DUP); // save base address of field for later store PutOp(OP_GETFIELD); ChangeStack(this_control.IsDoubleWordType(expression-> Type()) ? 1: 0); PutU2(GenerateFieldReference((VariableSymbol *) expression -> symbol)); } void ByteCode::GenerateClassAccessMethod(MethodSymbol * msym) { // generate code for access method used to set class literal fields /* The code takes the form aload_0 load this invokestatic java/lang/Class.forName(String)java/lang/Class areturn return Class object for the class named by string // exception handler if forName fails astore_1 save exception new java.lang.NoClassDefFoundError dup save so can return aload_1 recover exception invokevirtual java.lang.Throwable.getMessage() to get error message invokenonvirtual <init> // invoke initializer athrow rethrow the exception */ code_attribute -> max_locals = 2; PutOp(OP_ALOAD_0); PutOp(OP_INVOKESTATIC); ChangeStack(-1); PutU2(BuildMethodref(RegisterClass(U8S_java_SL_lang_SL_Class, strlen(U8S_java_SL_lang_SL_Class)), BuildNameAndType(RegisterUtf8(U8S_forName, strlen(U8S_forName)), RegisterUtf8(U8S_LP_Ljava_SL_lang_SL_String_SC_RP_Ljava_SL_lang_SL_Class_SC, strlen(U8S_LP_Ljava_SL_lang_SL_String_SC_RP_Ljava_SL_lang_SL_Class_SC))))); ChangeStack(1); PutOp(OP_ARETURN); PutOp(OP_ASTORE_1); PutOp(OP_NEW); PutU2(RegisterClass(U8S_java_SL_lang_SL_NoClassDefFoundError, strlen(U8S_java_SL_lang_SL_NoClassDefFoundError))); PutOp(OP_DUP); PutOp(OP_ALOAD_1); PutOp(OP_INVOKEVIRTUAL); ChangeStack(-1); PutU2(BuildMethodref(RegisterClass(U8S_java_SL_lang_SL_Throwable, strlen(U8S_java_SL_lang_SL_Throwable)), BuildNameAndType( RegisterUtf8(U8S_getMessage, strlen(U8S_getMessage)), RegisterUtf8(U8S_LP_RP_Ljava_SL_lang_SL_String_SC, strlen(U8S_LP_RP_Ljava_SL_lang_SL_String_SC))))); ChangeStack(1); PutOp(OP_INVOKENONVIRTUAL); ChangeStack(-1); PutU2(BuildMethodref(RegisterClass(U8S_java_SL_lang_SL_NoClassDefFoundError, strlen(U8S_java_SL_lang_SL_NoClassDefFoundError)), BuildNameAndType( RegisterUtf8(U8S_LT_init_GT_, strlen(U8S_LT_init_GT_)), RegisterUtf8(U8S_LP_Ljava_SL_lang_SL_String_SC_RP_V, strlen(U8S_LP_Ljava_SL_lang_SL_String_SC_RP_V))))); ChangeStack(1); PutOp(OP_ATHROW); code_attribute -> max_stack = 3; int exception_index = code_attribute -> exception_table.NextIndex(); code_attribute -> exception_table[exception_index].start_pc = 0; code_attribute -> exception_table[exception_index].end_pc = 5; // DS 11 feb code_attribute -> exception_table[exception_index].handler_pc = 5; code_attribute -> exception_table[exception_index].catch_type = RegisterClass(U8S_java_SL_lang_SL_ClassNotFoundException, strlen(U8S_java_SL_lang_SL_ClassNotFoundException)); } int ByteCode::GenerateClassAccess(AstFieldAccess * field_access) { // here to generate code to dymanically initialize the field for a class literal and then return its value Label lab1,lab2; if (field_access -> symbol -> VariableCast()) { // simple case in immediate environment, can use field on both left and right //(TypeSymbol * type) // evaluate X.class literal. If X is a primitive type, this is a predefined field; // otherwise, we must create a new synthetic field to hold the desired result and // initialize it at runtime. /* generate getstatic class_field load class field ifnull lab1 branch if not yet set get class_field here if set, return value goto lab2 lab1: here to initialize the field load class_constant get name of class invokestatic invoke generated method to get class_field desired value dup save value so can return it put class_field initialize the field lab2: */ VariableSymbol * sym = field_access -> symbol -> VariableCast(); PutOp(OP_GETSTATIC); PutU2(GenerateFieldReference(sym)); ChangeStack(1); EmitBranch(OP_IFNULL, lab1); PutOp(OP_GETSTATIC); PutU2(GenerateFieldReference(sym)); ChangeStack(1); EmitBranch(OP_GOTO, lab2); DefineLabel(lab1); // generate load of constant naming the class LoadLiteral(field_access -> base-> Type() -> ClassLiteralName(), this_control.String()); PutOp(OP_INVOKESTATIC); CompleteCall(class_literal_method, 1, 0); PutOp(OP_DUP); PutOp(OP_PUTSTATIC); PutU2(GenerateFieldReference(sym)); ChangeStack(-1); } else { // here in nested case, where must invoke access methods for the field VariableSymbol * sym = field_access -> symbol -> VariableCast(); MethodSymbol * read_symbol = field_access -> symbol -> MethodCast(); MethodSymbol * write_symbol = field_access -> resolution_opt -> symbol -> MethodCast(); AstMethodInvocation * resolve = field_access -> resolution_opt -> MethodInvocationCast(); u2 read_ref, write_ref; // need load this for class with method // if the next statement read field_access -> resolution_opt -> symbol = read_method, then // generating code for that expression tree would give us what we want field_access -> resolution_opt -> symbol = read_symbol; PutOp(OP_INVOKESTATIC); read_ref = BuildMethodref(RegisterClass(read_symbol -> containing_type -> fully_qualified_name), BuildNameAndType( RegisterUtf8(read_symbol -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(read_symbol -> signature))); PutU2(read_ref); ChangeStack(1); EmitBranch(OP_IFNULL, lab1); PutOp(OP_INVOKESTATIC); PutU2(read_ref); ChangeStack(1); EmitBranch(OP_GOTO, lab2); DefineLabel(lab1); // generate load of constant naming the class LoadLiteral(field_access -> base-> Type() -> ClassLiteralName(), this_control.String()); PutOp(OP_INVOKESTATIC); CompleteCall(class_literal_method, 1, 0); PutOp(OP_DUP); PutOp(OP_INVOKESTATIC); write_ref = BuildMethodref(RegisterClass(write_symbol -> containing_type -> fully_qualified_name), BuildNameAndType( RegisterUtf8(write_symbol -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(write_symbol -> signature))); PutU2(write_ref); ChangeStack(-1); // to indicate argument popped } DefineLabel(lab2); CompleteLabel(lab1); CompleteLabel(lab2); return 1; // return one-word (reference) result } int ByteCode::EmitArrayCreationExpression(AstArrayCreationExpression *expression) { // see also OP_MULTINEWARRAY int dims; if (expression -> array_initializer_opt) { InitializeArray(expression-> Type(), expression -> array_initializer_opt); } else { dims = expression -> NumDimExprs(); // need to push value of dimension(s) for (int i = 0;i < dims;i++) { AstDimExpr *d_expr = expression -> DimExpr(i); EmitExpression(d_expr -> expression); } EmitNewArray(dims, expression-> Type()); } return 1; } int ByteCode::EmitAssignmentExpression(AstAssignmentExpression *expression,int need_value) { // ASSIGNMENT int kind; int opc; int need_cast=0; VariableSymbol * sym; AstExpression * left_hand_side; TypeSymbol * expression_type = expression-> Type(); TypeSymbol * expression_expression_type = expression -> expression-> Type(); TypeSymbol * left_type; TypeSymbol * dest_type; TypeSymbol * cast_type; TypeSymbol * op_type; int stack_words = 0; if (expression -> left_hand_side -> CastExpressionCast()) { need_cast = 1; cast_type = expression -> left_hand_side -> CastExpressionCast()-> Type(); left_hand_side = expression -> left_hand_side -> CastExpressionCast() -> expression; op_type = cast_type; dest_type = expression -> left_hand_side-> Type();; } else { left_hand_side = expression -> left_hand_side; op_type = expression_type; } left_type = left_hand_side-> Type(); kind = GetLHSKind(expression -> left_hand_side, expression -> write_method); if (expression -> assignment_tag == AstAssignmentExpression::EQUAL) { switch(kind) { case LHS_ARRAY: EmitArrayAccessLHS(left_hand_side -> ArrayAccessCast()); // lhs must be array access break; case LHS_FIELD: EmitFieldAccessLHSBase(left_hand_side); // load base for field access break; case LHS_CLASS_METHOD: // need to load address of object, obtained from resolution ResolveAccess(left_hand_side, 0); // just get address break; case LHS_STATIC_METHOD: // nothing to do for static method at this point break; } EmitExpression(expression -> expression); } else { // here for compound assignment. Get the left operand, saving any information necessary to // update its value on the stack below the value. switch(kind) { case LHS_ARRAY: EmitArrayAccessLHS(left_hand_side -> ArrayAccessCast()); // lhs must be array access PutOp(OP_DUP2); // save base and index for later store // load current value (void) LoadArrayElement(expression_type); break; case LHS_FIELD: EmitFieldAccessLHS(left_hand_side); break; case LHS_LOCAL: case LHS_STATIC: (void) LoadSimple(kind,left_hand_side); ChangeStack(this_control.IsDoubleWordType(left_type) ? 1: 0); // CHECK_THIS? Is this really necessary break; case LHS_CLASS_METHOD: // need to load address of object, obtained from resolution, saving a copy on the stack ResolveAccess(left_hand_side, 1); // get address and value break; case LHS_STATIC_METHOD: // get value by invoking the appropriate resolution EmitExpression(left_hand_side -> SimpleNameCast() -> resolution_opt); // get value break; } if (expression -> assignment_tag ==AstAssignmentExpression::PLUS_EQUAL && left_type == this_control.String()) { // Here for string concatenation. EmitStringBuffer(); PutOp(OP_SWAP); // swap address if buffer and string to update. EmitStringAppendMethod(this_control.String()); AppendString(expression -> expression); EmitCallStringToString(); } else { // Here for operation other than string concatenation. Determine the opcode to use. if (this_control.IsSimpleIntegerValueType(op_type)|| op_type == this_control.boolean_type){ switch (expression -> assignment_tag) { case AstAssignmentExpression::STAR_EQUAL: opc = OP_IMUL; break; case AstAssignmentExpression::SLASH_EQUAL: opc = OP_IDIV; break; case AstAssignmentExpression::MOD_EQUAL: opc = OP_IREM; break; case AstAssignmentExpression::PLUS_EQUAL: opc = OP_IADD; break; case AstAssignmentExpression::MINUS_EQUAL: opc = OP_ISUB; break; case AstAssignmentExpression::LEFT_SHIFT_EQUAL: opc = OP_ISHL; break; case AstAssignmentExpression::RIGHT_SHIFT_EQUAL: opc = OP_ISHR; break; case AstAssignmentExpression::UNSIGNED_RIGHT_SHIFT_EQUAL: opc = OP_IUSHR; break; case AstAssignmentExpression::AND_EQUAL: opc = OP_IAND; break; case AstAssignmentExpression::IOR_EQUAL: opc = OP_IOR; break; case AstAssignmentExpression::XOR_EQUAL: opc = OP_IXOR; break; } } else if (op_type == this_control.long_type){ switch (expression -> assignment_tag) { case AstAssignmentExpression::STAR_EQUAL: opc = OP_LMUL; break; case AstAssignmentExpression::SLASH_EQUAL: opc = OP_LDIV; break; case AstAssignmentExpression::MOD_EQUAL: opc = OP_LREM; break; case AstAssignmentExpression::PLUS_EQUAL: opc = OP_LADD; break; case AstAssignmentExpression::MINUS_EQUAL: opc = OP_LSUB; break; case AstAssignmentExpression::LEFT_SHIFT_EQUAL: opc = OP_LSHL; break; case AstAssignmentExpression::RIGHT_SHIFT_EQUAL: opc = OP_LSHR; break; case AstAssignmentExpression::UNSIGNED_RIGHT_SHIFT_EQUAL: opc = OP_LUSHR; break; case AstAssignmentExpression::AND_EQUAL: opc = OP_LAND; break; case AstAssignmentExpression::IOR_EQUAL: opc = OP_LOR; break; case AstAssignmentExpression::XOR_EQUAL: opc = OP_LXOR; break; } } else if (op_type == this_control.float_type) { switch (expression -> assignment_tag) { case AstAssignmentExpression::STAR_EQUAL: opc = OP_FMUL; break; case AstAssignmentExpression::SLASH_EQUAL: opc = OP_FDIV; break; case AstAssignmentExpression::MOD_EQUAL: opc = OP_FREM; break; case AstAssignmentExpression::PLUS_EQUAL: opc = OP_FADD; break; case AstAssignmentExpression::MINUS_EQUAL: opc = OP_FSUB; break; } } else if (op_type == this_control.double_type) { switch (expression -> assignment_tag) { case AstAssignmentExpression::STAR_EQUAL: opc = OP_DMUL; break; case AstAssignmentExpression::SLASH_EQUAL: opc = OP_DDIV; break; case AstAssignmentExpression::MOD_EQUAL: opc = OP_DREM; break; case AstAssignmentExpression::PLUS_EQUAL: opc = OP_DADD; break; case AstAssignmentExpression::MINUS_EQUAL: opc = OP_DSUB; break; } } // convert value to desired type if necessary if (need_cast) { EmitCast(cast_type,left_type); } EmitExpression(expression -> expression); PutOp(opc); if (need_cast) { // now cast result back to type of result EmitCast(left_type, cast_type); } } } // Update left operand, saving value of right operand if it is needed. switch(kind) { case LHS_ARRAY: if (need_value) { if (this_control.IsDoubleWordType(left_type)) { PutOp(OP_DUP2_X2); } else PutOp(OP_DUP_X2); } StoreArrayElement(expression_type); break; case LHS_FIELD: case LHS_CLASS_METHOD: if (need_value) { if (this_control.IsDoubleWordType(left_type)) { PutOp(OP_DUP2_X1); } else PutOp(OP_DUP_X1); } if (kind==LHS_CLASS_METHOD) { stack_words = this_control.IsDoubleWordType(left_type) ? 2: 1; PutOp(OP_INVOKEVIRTUAL); CompleteCall(expression -> write_method, stack_words, 0); } else { StoreField(left_hand_side); } break; case LHS_LOCAL: case LHS_STATIC: case LHS_STATIC_METHOD: if (need_value) { if (this_control.IsDoubleWordType(left_type)) { PutOp(OP_DUP2); } else PutOp(OP_DUP); } if (kind==LHS_STATIC_METHOD) { stack_words = this_control.IsDoubleWordType(left_type) ? 2: 1; PutOp(OP_INVOKESTATIC); CompleteCall(expression -> write_method, stack_words, 0); } else { StoreSimple(kind,left_hand_side); } break; } return GetTypeWords(expression_type); } // Similar code patterns are used for the ordered comparisons int ByteCode::EmitBinaryExpression(AstBinaryExpression *expression) { // BINARY switch (expression -> binary_tag) { // process boolean-results first case AstBinaryExpression::OR_OR: case AstBinaryExpression::AND_AND: case AstBinaryExpression::LESS: case AstBinaryExpression::LESS_EQUAL: case AstBinaryExpression::GREATER: case AstBinaryExpression::GREATER_EQUAL: case AstBinaryExpression::EQUAL_EQUAL: case AstBinaryExpression::NOT_EQUAL: { Label lab1,lab2; EmitBranchIfExpression(expression,true,lab1); PutOp(OP_ICONST_0); // push false EmitBranch(OP_GOTO,lab2); DefineLabel(lab1); PutOp(OP_ICONST_1); // push false DefineLabel(lab2); CompleteLabel(lab1); CompleteLabel(lab2); } return 1; } if (expression -> binary_tag == AstBinaryExpression::INSTANCEOF) { TypeSymbol * instanceof_type = expression -> right_expression-> Type(); EmitExpression(expression -> left_expression); PutOp(OP_INSTANCEOF); if (instanceof_type -> num_dimensions) { PutU2(RegisterClass(instanceof_type -> signature)); } else { PutU2(RegisterClass(instanceof_type -> fully_qualified_name)); } return 1; } // special case string concatenation if (expression -> binary_tag == AstBinaryExpression::PLUS && (IsReferenceType(expression -> left_expression-> Type())) || IsReferenceType(expression -> right_expression-> Type())) { ConcatenateString(expression); return 1; } #ifdef TBSL // debug this later (DS 19 nov 96) // try to simplify if one operand known to be zero. if (isZero(expression -> left_expression)) { TypeSymbol * right_type = expression -> right_expression-> Type(); switch (expression -> binary_tag) { case AstBinaryExpression::PLUS: case AstBinaryExpression::IOR: case AstBinaryExpression::XOR: // here for cases that simplify to the right operand EmitExpression(expression -> right_expression); return; case AstBinaryExpression::STAR: case AstBinaryExpression::AND: case AstBinaryExpression::LEFT_SHIFT: case AstBinaryExpression::RIGHT_SHIFT: case AstBinaryExpression::UNSIGNED_RIGHT_SHIFT: // here for cases that evaluate to zero if (this_control.IsSimpleIntegerValueType(right_type)) { LoadShort(0); } else if (right_type == this_control.long_type) { PutOp(OP_LCONST_0); } else if (right_type == this_control.float_type) { PutOp(OP_FCONST_0); } else if (right_type == this_control.double_type) { PutOp(OP_DCONST_0); } else chaos("unexpected type in expression simplification"); return GetTypeWords(right_type); case AstBinaryExpression::MINUS: // 0 - x is negation of x EmitExpression(expression -> right_expression); if (this_control.IsSimpleIntegerValueType(right_type)) { PutOp(OP_INEG); } else if (right_type == this_control.long_type) { PutOp(OP_LNEG); } else if (right_type == this_control.float_type) { PutOp(OP_FNEG); } else if (right_type == this_control.double_type) { PutOp(OP_DNEG); } else chaos("unexpected type in expression simplification"); return 1; } } if (isZero(expression -> right_expression)) { TypeSymbol * left_type = expression -> left_expression-> Type(); switch (expression->binary_tag) { case AstBinaryExpression::PLUS: case AstBinaryExpression::MINUS: case AstBinaryExpression::IOR: case AstBinaryExpression::XOR: case AstBinaryExpression::LEFT_SHIFT: case AstBinaryExpression::RIGHT_SHIFT: case AstBinaryExpression::UNSIGNED_RIGHT_SHIFT: // here for cases that simplify to the left operand EmitExpression(expression->left_expression); return; case AstBinaryExpression::STAR: case AstBinaryExpression::AND: // here for cases that evaluate to zero if (this_control.IsSimpleIntegerValueType(left_type)) { LoadShort(0); } else if (left_type == this_control.long_type) { PutOp(OP_LCONST_0); } else if (left_type == this_control.float_type) { PutOp(OP_FCONST_0); } else if (left_type == this_control.double_type) { PutOp(OP_DCONST_0); } else chaos("unexpected type in expression simplification"); return; } } #endif EmitExpression(expression -> left_expression); EmitExpression(expression -> right_expression); switch (expression -> binary_tag) { case AstBinaryExpression::STAR: EmitBinaryOp(expression, OP_IMUL, OP_LMUL, OP_FMUL, OP_DMUL); break; case AstBinaryExpression::SLASH: EmitBinaryOp(expression, OP_IDIV, OP_LDIV, OP_FDIV, OP_DDIV); break; case AstBinaryExpression::MOD: EmitBinaryOp(expression, OP_IREM, OP_LREM, OP_FREM, OP_DREM); break; case AstBinaryExpression::PLUS: EmitBinaryOp(expression, OP_IADD, OP_LADD, OP_FADD, OP_DADD); break; case AstBinaryExpression::MINUS: EmitBinaryOp(expression, OP_ISUB, OP_LSUB, OP_FSUB, OP_DSUB); break; case AstBinaryExpression::LEFT_SHIFT: EmitBinaryOp(expression, OP_ISHL, OP_LSHL, 0, 0); break; case AstBinaryExpression::RIGHT_SHIFT: EmitBinaryOp(expression, OP_ISHR, OP_LSHR, 0, 0); break; case AstBinaryExpression::UNSIGNED_RIGHT_SHIFT: EmitBinaryOp(expression, OP_IUSHR, OP_LUSHR, 0, 0); break; // case AstBinaryExpression::INSTANCEOF: // EmitInstanceofExpression((AstInstanceofExpression *)expression); // break; case AstBinaryExpression::AND: EmitBinaryOp(expression, OP_IAND, OP_LAND, 0, 0); break; case AstBinaryExpression::XOR: EmitBinaryOp(expression, OP_IXOR, OP_LXOR, 0, 0); break; case AstBinaryExpression::IOR: EmitBinaryOp(expression, OP_IOR, OP_LOR, 0, 0); break; default: chaos("binary unknown tag"); } return GetTypeWords(expression-> Type()); } void ByteCode::EmitBinaryOp(AstBinaryExpression *expression, int iop, int lop, int fop, int dop) { int opc = 0; TypeSymbol * type = expression -> left_expression-> Type(); // binary PutOp if (this_control.IsSimpleIntegerValueType(type) || type == this_control.boolean_type) opc = iop; else if (type == this_control.long_type) opc = lop; else if (type == this_control.float_type) opc = fop; else if (type == this_control.double_type) opc = dop; if (opc == 0) chaos(" * undefined on this type"); PutOp(opc); } int ByteCode::EmitCastExpression(AstCastExpression *expression) { TypeSymbol * dest_type = expression-> Type(); TypeSymbol * source_type = expression -> expression-> Type(); // convert from numeric type src to destination type dest EmitExpression(expression -> expression); EmitCast(dest_type,source_type); return GetTypeWords(dest_type); } void ByteCode::EmitCast(TypeSymbol * dest_type, TypeSymbol * source_type) { if (dest_type == source_type) return; // done if nothing to do if (this_control.IsSimpleIntegerValueType(source_type)) { if (dest_type == this_control.long_type) PutOp(OP_I2L); else if (dest_type == this_control.float_type) PutOp(OP_I2F); else if (dest_type == this_control.double_type) PutOp(OP_I2D); else if (dest_type == this_control.char_type) PutOp(OP_I2C); else if (dest_type == this_control.byte_type) PutOp(OP_I2B); else if (dest_type == this_control.short_type) PutOp(OP_I2S); else if (dest_type == this_control.int_type); // no conversion needed else chaos("unsupported conversion"); } else if (source_type == this_control.long_type) { if (this_control.IsSimpleIntegerValueType(dest_type)) { PutOp(OP_L2I); if (dest_type == this_control.char_type) PutOp(OP_I2C); else if (dest_type == this_control.byte_type) PutOp(OP_I2B); else if (dest_type == this_control.short_type) PutOp(OP_I2S); } else if (dest_type == this_control.float_type) PutOp(OP_L2F); else if (dest_type == this_control.double_type) PutOp(OP_L2D); else chaos("unsupported conversion"); } else if (source_type == this_control.float_type) { if (this_control.IsSimpleIntegerValueType(dest_type)) { PutOp(OP_F2I); if (dest_type == this_control.char_type) PutOp(OP_I2C); else if (dest_type == this_control.byte_type) PutOp(OP_I2B); else if (dest_type == this_control.short_type) PutOp(OP_I2S); } else if (dest_type == this_control.long_type) PutOp(OP_F2L); else if (dest_type == this_control.double_type) PutOp(OP_F2D); else chaos("unsupported conversion"); } else if (source_type == this_control.double_type) { if (this_control.IsSimpleIntegerValueType(dest_type)) { PutOp(OP_D2I); if (dest_type == this_control.char_type) PutOp(OP_I2C); else if (dest_type == this_control.byte_type) PutOp(OP_I2B); else if (dest_type == this_control.short_type) PutOp(OP_I2S); } else if (dest_type == this_control.long_type) PutOp(OP_D2L); else if (dest_type == this_control.float_type) PutOp(OP_D2F); else chaos("unsupported conversion"); } else if (source_type == this_control.null_type) { //op(OP_ACONST_NULL); } else { // generate check cast instruction // it is possible to evaluate many of these at compile time if (dest_type -> num_dimensions) { PutOp(OP_CHECKCAST); PutU2(RegisterClass(dest_type -> signature)); } else { PutOp(OP_CHECKCAST); PutU2(RegisterClass(dest_type -> fully_qualified_name)); } } } int ByteCode::EmitClassInstanceCreationExpression(AstClassInstanceCreationExpression *expression, int need_value) { MethodSymbol * constructor = (MethodSymbol *) expression -> class_type -> symbol; TypeSymbol * type = expression-> Type(); int stack_words = 0; Label lab1; PutOp(OP_NEW); PutU2(RegisterClass(type -> fully_qualified_name)); if (need_value) PutOp(OP_DUP); // save address of new object for constructor // call constructor // pass address of object explicitly passed to new if specified. if (expression -> base_opt) { stack_words += EmitExpression(expression -> base_opt); PutOp(OP_DUP); EmitBranch(OP_IFNONNULL, lab1); // need to test for null, raising NullPointerException if so. So just do athrow PutOp(OP_ACONST_NULL); PutOp(OP_ATHROW); DefineLabel(lab1); CompleteLabel(lab1); } for (int i=0; i < expression -> NumLocalArguments();i++) { stack_words += EmitExpression((AstExpression *) expression -> LocalArgument(i)); } for (int k=0; k < expression -> NumArguments();k++) { stack_words += EmitExpression((AstExpression *) expression -> Argument(k)); } PutOp(OP_INVOKENONVIRTUAL); ChangeStack(-stack_words); if (constructor -> constant_pool_index == 0 || constructor -> constant_pool_class!=class_id) { // build method ref for method constructor -> constant_pool_index = BuildMethodref( RegisterClass(type -> fully_qualified_name), BuildNameAndType( RegisterUtf8(this_control.init_name_symbol -> Utf8_literal), RegisterUtf8(constructor -> signature))); constructor -> constant_pool_class = class_id; } PutU2(constructor -> constant_pool_index); return 1; } int ByteCode::EmitConditionalExpression(AstConditionalExpression *expression) { Label lab1,lab2; EmitBranchIfExpression(expression -> test_expression, false, lab1); EmitExpression(expression -> true_expression); EmitBranch(OP_GOTO,lab2); DefineLabel(lab1); EmitExpression(expression -> false_expression); DefineLabel(lab2); CompleteLabel(lab1); CompleteLabel(lab2); return GetTypeWords(expression -> true_expression-> Type()); } int ByteCode::EmitFieldAccess(AstFieldAccess *expression) { AstExpression * p = expression -> base; VariableSymbol * sym = expression -> symbol -> VariableCast(); TypeSymbol * expression_type = expression-> Type(); if (expression -> IsConstant()) { if (sym -> ACC_STATIC()) { if (!( p -> symbol -> TypeCast() || p -> symbol -> VariableCast())) { EmitExpression(p); PutOp(OP_POP); } } return LoadConstant(expression); } if (expression -> resolution_opt) { // resolve reference to private field in parent return EmitExpression(expression -> resolution_opt); } if (p-> Type() -> IsArray() && sym -> ExternalIdentity() == this_control.length_name_symbol){ EmitExpression(p); PutOp(OP_ARRAYLENGTH); return 1; } if (sym -> ACC_STATIC()) { if (!( p -> symbol -> TypeCast() || p -> symbol -> VariableCast())) { EmitExpression(p); PutOp(OP_POP); } PutOp(OP_GETSTATIC); ChangeStack(this_control.IsDoubleWordType(expression_type) ? 2: 1); } else { EmitExpression(p); // get base PutOp(OP_GETFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? 1: 0); } PutU2(GenerateFieldReference(sym)); return GetTypeWords(expression_type); } void ByteCode::EmitCloneArray(AstMethodInvocation *expression) { // generate code corresponding to // try { // evaluate super.clone(); // } catch (CloneNotSupportedException e) { // throw new InternalError(e.getMessage()); // } MethodSymbol * msym = (MethodSymbol *) expression -> symbol; TypeSymbol * res_type = expression-> Type(); // result type AstFieldAccess * field; int start_pc,end_pc; Label end_label; int exception_index; // msym is clone_name_symbol, indicating array clone // use clone() in java/lang/Object. start_pc = code_attribute -> code.Length(); field = expression -> method -> FieldAccessCast(); if (field) { EmitExpression(field -> base); } else { chaos("field access expected in array clone"); } PutOp(OP_INVOKEVIRTUAL); // ChangeStack(-stack_words); PutU2(RegisterMethod(METHOD_CLONE)); EmitBranch(OP_GOTO, end_label); end_pc = code_attribute -> code.Length(); // indicate that we use at least 2 local variables (this and the exception) if (code_attribute -> max_locals < 2) code_attribute -> max_locals = 2; // CSA fix 08-dec-1998 for PR 294 // start handler // can't count next StoreLocal as pop since in handler ChangeStack(1); StoreLocal(1, this_control.Object()); PutOp(OP_NEW); PutU2(RegisterClass(U8S_java_SL_lang_SL_InternalError, strlen(U8S_java_SL_lang_SL_InternalError))); PutOp(OP_DUP); LoadLocal(1, this_control.Object()); PutOp(OP_INVOKEVIRTUAL); PutU2(RegisterMethod(METHOD_CLONE_GETMESSAGE)); PutOp(OP_INVOKENONVIRTUAL); PutU2(RegisterMethod(METHOD_CLONE_INIT)); PutOp(OP_ATHROW); DefineLabel(end_label); CompleteLabel(end_label); exception_index = code_attribute -> exception_table.NextIndex(); code_attribute -> exception_table[exception_index].start_pc = start_pc; code_attribute -> exception_table[exception_index].end_pc = end_pc; code_attribute -> exception_table[exception_index].handler_pc = end_pc; // "java/lang/CloneNotSupportedException" code_attribute -> exception_table[exception_index].catch_type = RegisterClass(U8S_java_SL_lang_SL_CloneNotSupportedException, strlen(U8S_java_SL_lang_SL_CloneNotSupportedException)); } int ByteCode::EmitMethodInvocation(AstMethodInvocation *expression, int copy_base) { MethodSymbol * msym = (MethodSymbol *) expression -> symbol; AstSimpleName * simple_name; TypeSymbol * res_type = expression-> Type(); // result type int is_private = msym -> ACC_PRIVATE(); int is_static = msym -> ACC_STATIC(); int is_super=0; // set if super call int is_interface = msym -> containing_type -> ACC_INTERFACE(); AstFieldAccess * field; int stack_words = 0; // words on stack needed for arguments if (msym -> ExternalIdentity() == this_control.clone_name_symbol) { if (msym -> containing_type -> IsArray()) { EmitCloneArray(expression); return GetTypeWords(res_type); } #ifdef TBSL else { chaos(" clone not yet supported"); } #endif } if (is_static) { if (expression -> method -> FieldAccessCast()) { field = expression -> method -> FieldAccessCast(); if (field -> base -> MethodInvocationCast()) { (void) EmitMethodInvocation(field -> base -> MethodInvocationCast(), 0); PutOp(OP_POP); // discard value (only evaluating for side effect) } } } else { field = expression -> method -> FieldAccessCast(); if (field) { AstFieldAccess *sub_field_access = field -> base -> FieldAccessCast(); if (field -> base -> SuperExpressionCast() || (sub_field_access && sub_field_access -> IsSuperAccess())) { is_super=1; } if (field -> base -> MethodInvocationCast()) { (void) EmitMethodInvocation(field -> base -> MethodInvocationCast(), 0); } else { EmitExpression(field -> base); } } else if (expression -> method -> SimpleNameCast()) { simple_name = expression -> method -> SimpleNameCast(); if (simple_name -> resolution_opt) { // use resolution if available (void) EmitExpression(simple_name -> resolution_opt); } else { // must be field of current object, so load this PutOp(OP_ALOAD_0); } } else { chaos("unexpected argument to field access"); } } if (!is_static && copy_base) { // if need to save object ref for method invocation PutOp(OP_DUP); } for (int i=0; i < expression -> NumArguments();i++) { stack_words += EmitExpression((AstExpression *) expression -> Argument(i)); } PutOp(msym -> ACC_STATIC() ? OP_INVOKESTATIC : (is_super | is_private) ? OP_INVOKENONVIRTUAL : is_interface ? OP_INVOKEINTERFACE : OP_INVOKEVIRTUAL); CompleteCall(msym,stack_words, is_interface); return GetTypeWords(res_type); } void ByteCode::CompleteCall(MethodSymbol * msym,int stack_words, int is_interface) { TypeSymbol * res_type = msym-> Type(); ChangeStack(-stack_words); // need to get method index, the constant_pool index for a // reference to this method (a Methodref); if (msym -> constant_pool_index == 0 || msym -> constant_pool_class != class_id) { // build method ref for method if (is_interface) { msym -> constant_pool_index = BuildInterfaceMethodref( RegisterClass(msym -> containing_type -> fully_qualified_name), BuildNameAndType( RegisterUtf8(msym -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(msym -> signature))); msym -> constant_pool_class = class_id; } else { msym -> constant_pool_index = BuildMethodref( RegisterClass(msym -> containing_type -> fully_qualified_name), BuildNameAndType( RegisterUtf8(msym -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(msym -> signature))); msym -> constant_pool_class = class_id; } } PutU2(msym -> constant_pool_index); if (is_interface) { PutU1(stack_words+1); PutU1(0); } // must account for value returned by method. Assume it places one // word on stack and correct this assumption if wrong. stack_words=1; if (this_control.IsDoubleWordType(res_type)) { stack_words = 2; } else if (res_type == this_control.void_type) { // no return value stack_words = 0; } ChangeStack(stack_words); } void ByteCode::EmitNewArray(int dims,TypeSymbol * type) { int i; TypeSymbol * element_type = type -> ArraySubtype(); if (dims==0 || (dims == 1 && type -> num_dimensions == dims)) { if (this_control.IsNumeric(element_type) || element_type == this_control.boolean_type) { // if one-dimensional primitive if (element_type == this_control.boolean_type) i = 4; // T_BOOLEAN else if (element_type == this_control.char_type) i = 5; // T_CHAR else if (element_type == this_control.float_type) i = 6; // T_FLOAT else if (element_type == this_control.double_type) i = 7;// T_DOUBLE else if (element_type == this_control.byte_type) i = 8; // T_BYTE else if (element_type == this_control.short_type) i = 9;// T_SHORT else if (element_type == this_control.int_type) i = 10; // T_INT else if (element_type == this_control.long_type) i = 11; // T_LONG else chaos("new array unsupported type"); PutOp(OP_NEWARRAY); PutU1(i); return; } else { // must be reference type PutOp(OP_ANEWARRAY); PutU2(RegisterClass(element_type -> fully_qualified_name)); } } else { PutOp(OP_MULTIANEWARRAY); PutU2(RegisterClass(type -> signature)); PutU1(dims); // load dims count ChangeStack(dims-1); // dims -1 } } int ByteCode::EmitPostUnaryExpression(AstPostUnaryExpression *expression,int need_value) { // POST_UNARY int kind; switch(kind=GetLHSKind(expression -> expression, expression -> write_method)) { case LHS_LOCAL: case LHS_STATIC: case LHS_STATIC_METHOD: EmitPostUnaryExpressionSimple(kind,expression,need_value); break; case LHS_ARRAY: EmitPostUnaryExpressionArray(expression, need_value); break; case LHS_FIELD: case LHS_CLASS_METHOD: EmitPostUnaryExpressionField(kind,expression,need_value); break; default: chaos("unknown lhs kind for assignment"); } return GetTypeWords(expression-> Type()); } void ByteCode::EmitPostUnaryExpressionField(int kind,AstPostUnaryExpression *expression,int need_value) { // AstExpression *expression; // POST_UNARY on instance variable // load value of field, duplicate, do increment or decrement, then store back, leaving original value // on top of stack. VariableSymbol * sym = (VariableSymbol *) expression -> symbol; TypeSymbol * type = (TypeSymbol *) sym -> owner; TypeSymbol * expression_type = expression-> Type(); bool plus = (expression -> post_unary_tag == AstPostUnaryExpression::PLUSPLUS) ? true : false; if (kind==LHS_FIELD) { EmitFieldAccessLHS(expression -> expression); } else { ResolveAccess(expression -> expression, 1); // get address and value } if (need_value) { if (this_control.IsDoubleWordType(expression_type)) { PutOp(OP_DUP2_X1); } else PutOp(OP_DUP_X1); } if (this_control.IsSimpleIntegerValueType(expression_type)) { // TBSL: use iinc eventually PutOp(OP_ICONST_1); PutOp(plus ? OP_IADD : OP_ISUB); } else if (expression_type == this_control.long_type) { PutOp(OP_LCONST_1); PutOp(plus ? OP_LADD : OP_LSUB); } else if (expression_type == this_control.float_type) { PutOp(OP_FCONST_1); PutOp(plus ? OP_FADD : OP_FSUB); } else if (expression_type == this_control.double_type) { PutOp(OP_DCONST_1); // load 1.0 PutOp(plus ? OP_DADD : OP_DSUB); } if (kind==LHS_FIELD) { PutOp(OP_PUTFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -3: -2); PutU2(GenerateFieldReference(sym)); } else { int stack_words = this_control.IsDoubleWordType(expression_type) ? 2: 1; PutOp(OP_INVOKEVIRTUAL); CompleteCall(expression -> write_method, stack_words, 0); } } void ByteCode::EmitPostUnaryExpressionSimple(int kind, AstPostUnaryExpression *expression, int need_value) { // AstExpression *expression; // POST_UNARY on local variable // load value of variable, duplicate, do increment or decrement, then store back, leaving original value // on top of stack. bool plus = (expression -> post_unary_tag == AstPostUnaryExpression::PLUSPLUS) ? true : false; TypeSymbol * expression_type = expression-> Type(); if (expression_type == this_control.int_type) { // see if can use IINC if (IsLocal(expression)) { if (need_value) (void) LoadSimple(kind, expression); PutOp(OP_IINC); PutU1(expression -> symbol -> VariableCast() -> LocalVariableIndex()); PutI1(plus ? 1 : -1); return; } } LoadSimple(kind,expression -> expression); // this will also load value needing resolution if (need_value) { if (this_control.IsDoubleWordType(expression_type)) { PutOp(OP_DUP2); } else PutOp(OP_DUP); } if (this_control.IsSimpleIntegerValueType(expression_type)) { // TBSL: use iinc eventually PutOp(OP_ICONST_1); PutOp(plus ? OP_IADD : OP_ISUB); EmitCast(expression_type, this_control.int_type); } else if (expression_type == this_control.long_type) { PutOp(OP_LCONST_1); PutOp(plus ? OP_LADD : OP_LSUB); } else if (expression_type == this_control.float_type) { PutOp(OP_FCONST_1); PutOp(plus ? OP_FADD : OP_FSUB); } else if (expression_type == this_control.double_type) { PutOp(OP_DCONST_1); // load 1.0 PutOp(plus ? OP_DADD : OP_DSUB); } if (kind==LHS_STATIC_METHOD) { int stack_words = this_control.IsDoubleWordType(expression_type) ? 2: 1; PutOp(OP_INVOKESTATIC); CompleteCall(expression -> write_method, stack_words, 0); } else { StoreSimple(kind,expression -> expression); } } void ByteCode::EmitPostUnaryExpressionArrayCode(int load_op, int need_value, int dup_op, int const_op, int plus, int add_op, int sub_op, int store_op, int conv_op) { PutOp(load_op); if (need_value)PutOp(dup_op); // save value below saved array base and index PutOp(const_op); PutOp(plus ? add_op : sub_op); if (conv_op) PutOp(conv_op); // if need to convert back to desired type PutOp(store_op); } void ByteCode::EmitPostUnaryExpressionArray(AstPostUnaryExpression *expression, int need_value) { // Post Unary for which operand is array element // assignment for which lhs is array element // AstExpression *expression; bool plus = (expression -> post_unary_tag == AstPostUnaryExpression::PLUSPLUS) ? true : false; TypeSymbol * expression_type = expression-> Type(); EmitArrayAccessLHS((AstArrayAccess *)expression -> expression); // lhs must be array access PutOp(OP_DUP2); // save array base and index for later store if (expression_type == this_control.int_type) { EmitPostUnaryExpressionArrayCode(OP_IALOAD, need_value, OP_DUP_X2, OP_ICONST_1, plus, OP_IADD, OP_ISUB, OP_IASTORE, 0); } else if (expression_type == this_control.byte_type ) { EmitPostUnaryExpressionArrayCode(OP_BALOAD, need_value, OP_DUP_X2, OP_ICONST_1, plus, OP_IADD, OP_ISUB, OP_BASTORE, OP_I2B); } else if (expression_type == this_control.char_type ) { EmitPostUnaryExpressionArrayCode(OP_CALOAD, need_value, OP_DUP_X2, OP_ICONST_1, plus, OP_IADD, OP_ISUB, OP_CASTORE, OP_I2C); } else if (expression_type == this_control.short_type) { EmitPostUnaryExpressionArrayCode(OP_SALOAD, need_value, OP_DUP_X2, OP_ICONST_1, plus, OP_IADD, OP_ISUB, OP_SASTORE, OP_I2S); } else if (expression_type == this_control.long_type) { EmitPostUnaryExpressionArrayCode(OP_LALOAD, need_value, OP_DUP2_X2, OP_LCONST_1, plus, OP_LADD, OP_LSUB, OP_LASTORE, 0); } else if (expression_type == this_control.float_type) { EmitPostUnaryExpressionArrayCode(OP_FALOAD, need_value, OP_DUP_X2, OP_FCONST_1, plus, OP_FADD, OP_FSUB, OP_FASTORE, 0); } else if (expression_type == this_control.double_type) { EmitPostUnaryExpressionArrayCode(OP_DALOAD, need_value, OP_DUP2_X2, OP_DCONST_1, plus, OP_DADD, OP_DSUB, OP_DASTORE, 0); } else chaos("unsupported postunary type"); } int ByteCode::EmitPreUnaryExpression(AstPreUnaryExpression *expression,int need_value) { // PRE_UNARY TypeSymbol * type = expression-> Type(); if (expression -> pre_unary_tag == AstPreUnaryExpression::PLUSPLUS || expression -> pre_unary_tag == AstPreUnaryExpression::MINUSMINUS) { EmitPreUnaryIncrementExpression(expression,need_value); } else { // here for ordinary unary operator without side effects. switch (expression -> pre_unary_tag) { case AstPreUnaryExpression::PLUS: // nothing to do (front-end will have done any needed conversions) EmitExpression(expression -> expression); break; case AstPreUnaryExpression::MINUS: EmitExpression(expression -> expression); if (this_control.IsSimpleIntegerValueType(type)) PutOp(OP_INEG); else if (type == this_control.long_type) PutOp(OP_LNEG); else if (type == this_control.float_type) PutOp(OP_FNEG); else if (type == this_control.double_type) PutOp(OP_DNEG); else chaos("unary minus on unsupported type"); break; case AstPreUnaryExpression::TWIDDLE: if (this_control.IsSimpleIntegerValueType(type)) { EmitExpression(expression -> expression); PutOp(OP_ICONST_M1); // -1 PutOp(OP_IXOR); // exclusive or to get result } else if (type == this_control.long_type) { EmitExpression(expression -> expression); PutOp(OP_LCONST_1); // make -1 PutOp(OP_LNEG); PutOp(OP_LXOR); // exclusive or to get result } else chaos("unary ~ on unsupported type"); break; case AstPreUnaryExpression::NOT: if (type == this_control.boolean_type) { Label lab1,lab2; EmitExpression(expression -> expression); EmitBranch(OP_IFEQ,lab1); PutOp(OP_ICONST_0); // turn true into false EmitBranch(OP_GOTO,lab2); DefineLabel(lab1); PutOp(OP_ICONST_1); // here to turn false into true DefineLabel(lab2); CompleteLabel(lab1); CompleteLabel(lab2); } else chaos("unary ! on non-boolean not supported"); break; default: chaos("unknown preunary tag"); } } return GetTypeWords(type); // AstExpression *expression; } void ByteCode::EmitPreUnaryIncrementExpression(AstPreUnaryExpression *expression, int need_value) { // PRE_UNARY with side effects (++X or --X) int kind; switch(kind=GetLHSKind(expression, expression -> write_method)) { case LHS_LOCAL: case LHS_STATIC: case LHS_STATIC_METHOD: EmitPreUnaryIncrementExpressionSimple(kind,expression,need_value); break; case LHS_ARRAY: EmitPreUnaryIncrementExpressionArray(expression,need_value); break; case LHS_FIELD: case LHS_CLASS_METHOD: EmitPreUnaryIncrementExpressionField(kind, expression,need_value); break; default: chaos("unknown lhs kind for assignment"); } } void ByteCode::EmitPreUnaryIncrementExpressionSimple(int kind,AstPreUnaryExpression *expression, int need_value) { // AstExpression *expression; // POST_UNARY on name // load value of variable, do increment or decrement, duplicate, then store back, leaving original value // on top of stack. bool plus = (expression -> pre_unary_tag == AstPreUnaryExpression::PLUSPLUS) ? true : false; TypeSymbol * type = expression-> Type(); if (type == this_control.int_type) { if (kind == LHS_LOCAL) { PutOp(OP_IINC); PutU1(expression -> symbol -> VariableCast() -> LocalVariableIndex()); PutI1(plus ? 1 : -1); if (need_value) (void) LoadSimple(kind, expression); return; } } (void) LoadSimple(kind,expression -> expression); // will also load value if resolution needed if (this_control.IsSimpleIntegerValueType(type)) { // TBSL: use iinc eventually PutOp(OP_ICONST_1); PutOp(plus ? OP_IADD : OP_ISUB); EmitCast(type, this_control.int_type); if (need_value) PutOp(OP_DUP); } else if (type == this_control.long_type) { PutOp(OP_LCONST_1); PutOp(plus ? OP_LADD : OP_LSUB); if (need_value) PutOp(OP_DUP2); } else if (type == this_control.float_type) { PutOp(OP_FCONST_1); PutOp(plus ? OP_FADD : OP_FSUB); if (need_value) PutOp(OP_DUP); } else if (type == this_control.double_type) { PutOp(OP_DCONST_1); // load 1.0 PutOp(plus ? OP_DADD : OP_DSUB); if (need_value) PutOp(OP_DUP2); } if (kind==LHS_STATIC_METHOD) { int stack_words = this_control.IsDoubleWordType(type) ? 2: 1; PutOp(OP_INVOKESTATIC); CompleteCall(expression -> write_method, stack_words, 0); } else { StoreSimple(kind,expression); } } void ByteCode::EmitPreUnaryIncrementExpressionArrayCode(int load_op, int const_op, int plus, int add_op, int sub_op, int need_value, int dup_op, int store_op, int conv_op) { PutOp(load_op); PutOp(const_op); PutOp(plus ? add_op : sub_op); if (need_value) PutOp(dup_op); // save value below saved array base and index if (conv_op) PutOp(conv_op); // if need to check result in range PutOp(store_op); } void ByteCode::EmitPreUnaryIncrementExpressionArray(AstPreUnaryExpression *expression, int need_value) { // Post Unary for which operand is array element // assignment for which lhs is array element // AstExpression *expression; bool plus = (expression -> pre_unary_tag == AstPreUnaryExpression::PLUSPLUS) ? true : false; TypeSymbol * type = expression-> Type(); EmitArrayAccessLHS((AstArrayAccess *)expression -> expression); // lhs must be array access PutOp(OP_DUP2); // save array base and index for later store if (type == this_control.int_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_IALOAD, OP_ICONST_1, plus, OP_IADD, OP_ISUB, need_value, OP_DUP_X2, OP_IASTORE,0); } else if (type == this_control.byte_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_BALOAD, OP_ICONST_1, plus, OP_IADD, OP_ISUB, need_value, OP_DUP_X2, OP_BASTORE, OP_I2B); } else if (type == this_control.char_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_CALOAD, OP_ICONST_1, plus, OP_IADD, OP_ISUB, need_value, OP_DUP_X2, OP_CASTORE, OP_I2C); } else if (type == this_control.short_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_SALOAD, OP_ICONST_1, plus, OP_IADD, OP_ISUB, need_value, OP_DUP_X2, OP_SASTORE, OP_I2S); } else if (type == this_control.long_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_LALOAD, OP_LCONST_1, plus, OP_LADD, OP_LSUB, need_value, OP_DUP2_X2, OP_LASTORE, 0); } else if (type == this_control.float_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_FALOAD, OP_FCONST_1, plus, OP_FADD, OP_FSUB, need_value, OP_DUP_X2, OP_FASTORE, 0); } else if (type == this_control.double_type) { EmitPreUnaryIncrementExpressionArrayCode(OP_DALOAD, OP_DCONST_1, plus, OP_DADD, OP_DSUB, need_value, OP_DUP2_X2, OP_DASTORE, 0); } else chaos("unsupported PreUnary type"); } void ByteCode::EmitPreUnaryIncrementExpressionField(int kind, AstPreUnaryExpression *expression, int need_value) { // Pre Unary for which operand is field (instance variable) // AstExpression *expression; bool plus = (expression -> pre_unary_tag == AstPreUnaryExpression::PLUSPLUS) ? true : false; VariableSymbol * sym = (VariableSymbol *) expression -> symbol; TypeSymbol * type = (TypeSymbol *) sym -> owner; TypeSymbol * expression_type = expression-> Type(); if (kind==LHS_CLASS_METHOD) { // need to load address of object, obtained from resolution, saving a copy on the stack ResolveAccess(expression -> expression, 1); // get address and value } else { EmitFieldAccessLHS(expression -> expression); } if (this_control.IsSimpleIntegerValueType(expression_type)) { PutOp(OP_ICONST_1); PutOp(plus ? OP_IADD : OP_ISUB); EmitCast(expression_type, this_control.int_type); if (need_value)PutOp(OP_DUP_X1); } else if (expression_type == this_control.long_type) { PutOp(OP_LCONST_1); PutOp(plus ? OP_LADD : OP_LSUB); if (need_value)PutOp(OP_DUP2_X1); } else if (expression_type == this_control.float_type) { PutOp(OP_FCONST_1); PutOp(plus ? OP_FADD : OP_FSUB); if (need_value)PutOp(OP_DUP_X1); } else if (expression_type == this_control.double_type) { PutOp(OP_DCONST_1); PutOp(plus ? OP_DADD : OP_DSUB); if (need_value)PutOp(OP_DUP2_X1); } else chaos("unsupported PreUnary type"); if (kind==LHS_CLASS_METHOD) { int stack_words = this_control.IsDoubleWordType(expression_type) ? 2: 1; PutOp(OP_INVOKEVIRTUAL); CompleteCall(expression -> write_method, stack_words, 0); } else { PutOp(OP_PUTFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -3: -2); PutU2(GenerateFieldReference(sym)); } } void ByteCode::EmitThisInvocation(AstThisCall *this_call) { MethodSymbol * msym = this_call -> symbol; AstExpression *base_opt = this_call -> base_opt; // THIS_CALL // AstExpression *method; // AstList *arguments; // A call to another constructor (THIS_CALL) or super constructor (SUPER_CALL) // result in the same sort of generated code, as the semantic analysis // has resolved the proper constructor to be invoked. int stack_words = 0; // words on stack needed for arguments PutOp(OP_ALOAD_0); // load 'this' if (base_opt) { stack_words += EmitExpression(base_opt); } for (int i=0; i < this_call -> NumLocalArguments();i++) { stack_words += EmitExpression((AstExpression *) this_call -> LocalArgument(i)); } for (int k=0; k < this_call -> NumArguments();k++) { stack_words += EmitExpression((AstExpression *) this_call -> Argument(k)); } PutOp(OP_INVOKENONVIRTUAL); ChangeStack(-stack_words); // need to get method index, the constant_pool index for a // reference to this method (a Methodref); // caller will supply methodref if (msym -> constant_pool_index == 0 || msym -> constant_pool_class != class_id) { // build method ref for method msym -> constant_pool_index = BuildMethodref( this_class, BuildNameAndType( RegisterUtf8(msym -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(msym -> signature))); msym -> constant_pool_class = class_id; } PutU2(msym -> constant_pool_index); } void ByteCode::EmitSuperInvocation(AstSuperCall *super_call) { MethodSymbol *msym = super_call -> symbol; AstExpression *base_opt = super_call -> base_opt; int stack_words = 0; // words on stack needed for arguments PutOp(OP_ALOAD_0); // load 'this' if (base_opt) { stack_words += EmitExpression(base_opt); } for (int i=0; i < super_call -> NumLocalArguments();i++) { stack_words += EmitExpression((AstExpression *) super_call -> LocalArgument(i)); } for (int k=0; k < super_call -> NumArguments();k++) { stack_words += EmitExpression((AstExpression *) super_call -> Argument(k)); } PutOp(OP_INVOKENONVIRTUAL); ChangeStack(-stack_words); // need to get method index, the constant_pool index for a // reference to this method (a methodref); // caller will supply methodref if (msym -> constant_pool_index == 0 || msym -> constant_pool_class != class_id) { // build method ref for method msym -> constant_pool_index = BuildMethodref( super_class, BuildNameAndType( RegisterUtf8(msym -> ExternalIdentity() -> Utf8_literal), RegisterUtf8(msym -> signature))); msym -> constant_pool_class = class_id; } PutU2(msym -> constant_pool_index); } AstExpression * ByteCode::UnParenthesize(AstExpression * p) { // called when expression has been parenthesized to removed // parantheses and expose true structure. AstParenthesizedExpression * pe; while (p -> ParenthesizedExpressionCast()) { p = p -> ParenthesizedExpressionCast() -> expression; } return p; } // Methods for string concatenation void ByteCode::ConcatenateString(AstBinaryExpression * expression) { // generate code to concatenate strings, by generating a string buffer and appending the arguments // before calling toString, i.e., // s1+s2 compiles to // new StringBuffer().append(s1).append(s2).toString(); // look for sequences of concatenation to use a single buffer where possible EmitStringBuffer(); AppendString(expression -> left_expression); AppendString(expression -> right_expression); EmitCallStringToString(); // convert string buffer to string } void ByteCode::EmitCallStringToString() { // generate call to toString on stringbuffer PutOp(OP_INVOKEVIRTUAL); PutU2(RegisterMethod(METHOD_STRINGBUFFER_TOSTRING)); ChangeStack(1); // account for return value } void ByteCode::EmitStringBuffer() { // generate code to allocate new string buffer and initialize it PutOp(OP_NEW); PutU2(RegisterClass(U8S_java_SL_lang_SL_StringBuffer, strlen(U8S_java_SL_lang_SL_StringBuffer))); PutOp(OP_DUP); PutOp(OP_INVOKENONVIRTUAL); PutU2(RegisterMethod(METHOD_STRINGBUFFER_INIT)); } void ByteCode::AppendString(AstExpression * p) { AstBinaryExpression *binexpr; TypeSymbol * type = p-> Type(); if (p -> BinaryExpressionCast()) { binexpr = p -> BinaryExpressionCast(); if ( binexpr -> binary_tag == AstBinaryExpression::PLUS && (IsReferenceType(binexpr -> left_expression-> Type()) || IsReferenceType(binexpr -> right_expression-> Type()))) { AppendString(binexpr -> left_expression); AppendString(binexpr -> right_expression); return; } } if (p -> ParenthesizedExpressionCast()) { AppendString(p -> ParenthesizedExpressionCast() -> expression); return; } if (p -> CastExpressionCast()) { // here if cast expression, verify that converting to string AstCastExpression *cast = (AstCastExpression *) p; if (cast->kind == Ast::CAST && cast-> Type() == this_control.String()) { AppendString(cast->expression); return; } } if (type == this_control.null_type) { // replace explicit reference to "null" by // corresponding string. name_StringNull = BuildString(RegisterUtf8(U8S_null, strlen(U8S_null))); if (name_StringNull <=255) { PutOp(OP_LDC); PutU1((unsigned char) name_StringNull); } else { PutOp(OP_LDC_W); PutU2(name_StringNull); } type = this_control.String(); } else { EmitExpression(p); } EmitStringAppendMethod(type); } void ByteCode::EmitStringAppendMethod(TypeSymbol * type) { int method_sig = 0; int stack_words = 1; // assume one word put on stack // call appropriate append routine to add to string buffer if (type -> num_dimensions == 1 && type -> base_type == this_control.char_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDCHARARRAY); } else if (type == this_control.char_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDCHAR); } else if (type == this_control.boolean_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDBOOLEAN); } else if (type == this_control.int_type|| type == this_control.short_type || type == this_control.byte_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDINT); } else if (type == this_control.long_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDLONG); stack_words++; } else if (type == this_control.float_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDFLOAT); } else if (type == this_control.double_type) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDDOUBLE); stack_words++; } else if (type == this_control.String()) { method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDSTRING); } else if (IsReferenceType(type)) { // may need to call toString method on object before appending to stringbuffer // TODO: do above method_sig = RegisterMethod(METHOD_STRINGBUFFER_APPENDOBJECT); } else { chaos("unexpected string buffer append operand"); } PutOp(OP_INVOKEVIRTUAL); ChangeStack(-stack_words); PutU2(method_sig); ChangeStack(1); // account for return value if (method_sig == 0) chaos("unable to find type for string buffer concatenation"); } void ByteCode::chaos(char *msg) { cout << "chaos: " << msg << "\n"; cerr << "chaos: " << msg << "\n"; exit(1); } #ifdef TEST static void op_trap() { int i=0; // used for debugger trap } #endif ByteCode::ByteCode(TypeSymbol *unit_type) : ClassFile(unit_type), this_semantic(*unit_type -> semantic_environment -> sem), this_control(unit_type -> semantic_environment -> sem -> control) { int i; #ifdef TEST if (this_control.option.nowrite == 0) { this_control.class_files_written++; } #endif this_control.class_file_id++; class_id = this_control.class_file_id; initialize_statics_in_clinit = 1; stack_depth = 0; synchronized_blocks = 0; finally_blocks = 0; for (i=0;i<METHOD_NUMBER;i++) registered_methods[i] = 0; name_StringNull=0; access_flags = unit_type -> access_flags; // The flags for 'static' and 'protected' are set only for the inner // classes attribute, not for the class, as described in page 25 // of the inner classes document. if (unit_type -> ACC_PROTECTED()) { access_flags |= 0x0001; // set PUBLIC if PROTECTED } access_flags &= (~ 0x0008); // ResetACC_STATIC access_flags &= (~ 0x0004); // ResetACC_PROTECTED access_flags &= (~ 0x0002); // ResetACC_PRIVATE access_flags |= 0x0020; // must be set always set ACC_SUPER for class (cf page 86 of JVM Spec) magic = 0xcafebabe; major_version = 45; // use Sun JDK 1.0 version numbers minor_version = 3; constant_pool.Next()=NULL; this_class = RegisterClass(unit_type -> fully_qualified_name); if (unit_type -> super) { super_class = RegisterClass(unit_type -> super -> fully_qualified_name); } else { super_class=0; // primordial beast Object } for (i=0; i<unit_type -> NumInterfaces();i++) { interfaces.Next() = RegisterClass(unit_type -> Interface(i) -> fully_qualified_name); } return; } // Methods for manipulating labels void ByteCode::DefineLabel(Label& lab) { if (lab.defined){ chaos( "duplicate label definition"); } lab.defined = 1; lab.definition = code_attribute -> code.Length(); if (lab.definition > last_label_pc) { last_label_pc = lab.definition; } } void ByteCode::CompleteLabel(Label& lab) { // patch all uses to have proper value. This requires that // all labels be freed at some time. if (lab.uses.Length()) { if (lab.defined == 0) { chaos("label used but with no definition"); } for (int i=0; i<lab.uses.Length();i++) { // patch byte code reference to label to reflect it's definition // as 16-bit signed offset. unsigned int luse = lab.uses[i].use_offset;; int start = luse - lab.uses[i].op_offset; int offset = lab.definition - start; if (lab.uses[i].use_length == 2) { // here if short offset code_attribute -> code[luse] = (offset >> 8) & 0xFF; code_attribute -> code[luse+1] = offset & 0xFF; } else if (lab.uses[i].use_length == 4) { //here if 4 byte use code_attribute -> code[luse] = (offset >> 24) & 0xFF; code_attribute -> code[luse+1] = (offset >> 16) & 0xFF; code_attribute -> code[luse+2] = (offset >> 8) & 0xFF; code_attribute -> code[luse+3] = offset & 0xFF; } else { chaos( "label use length not 2 or 4"); exit(1); } } lab.uses.Reset(); } // reset in case label is used again. lab.definition = 0; lab.defined=0; } int ByteCode::IsLabelUsed(Label& lab) { return (lab.uses.Length()>0); } // int ByteCode::IsLabelDefined(Label& lab) // { // return (lab.defined != 0); // } void ByteCode::UseLabel(Label & lab,int _length, int _op_offset) { int lab_index = lab.uses.NextIndex(); lab.uses[lab_index].use_length = _length; lab.uses[lab_index].op_offset = _op_offset; lab.uses[lab_index].use_offset = code_attribute -> code.Length(); // fill next length bytes with zero; will be filled in with proper value when label completed for (int i=0;i<lab.uses[lab_index].use_length;i++) code_attribute -> code.Next() = 0; } // Methods to query attributes int ByteCode::IsLocal(AstExpression *p) { // return 1 if p refers to local variable, 0 otherwise VariableSymbol *sym = p -> symbol -> VariableCast(); return (sym && sym -> owner -> MethodCast()) ? 1 : 0; } int ByteCode::IsNull(AstExpression *p) { // see if operand is null. The front-end will have inserted a cast // of null to the present type if (p -> CastExpressionCast()) { return p -> CastExpressionCast() -> expression-> Type() == this_control.null_type; } else return 0; } int ByteCode::IsReferenceType(TypeSymbol *p) { return (! (this_control.IsNumeric(p) || p == this_control.boolean_type || p == this_control.null_type)); } int ByteCode::IsDefaultValue(AstExpression *p) { // see if operand is default value of its type TypeSymbol *type = p-> Type(); if (!p -> IsConstant()) return 0; LiteralValue * litp = p -> value; if (this_control.IsSimpleIntegerValueType(type) || type == this_control.boolean_type) { IntLiteralValue * vp = (IntLiteralValue *) litp; int val = vp -> value; return (val == 0); } else if (type == this_control.long_type) { LongLiteralValue * vp = (LongLiteralValue *) litp; LongInt val = vp -> value; return (val == 0); } else if (type == this_control.float_type) { FloatLiteralValue * vp = (FloatLiteralValue *) litp; IEEEfloat val = vp -> value; return (val.Word() == 0); } else if (type == this_control.double_type) { DoubleLiteralValue * vp = (DoubleLiteralValue *) litp; IEEEdouble val = vp -> value; return (val.HighWord() == 0 && val.LowWord() == 0); } else { // the default value for everything else is 'null' return (type == this_control.null_type); } return 0; } int ByteCode::IsZero(AstExpression *p) { // see if operand is integer type and is zero TypeSymbol *type = p-> Type(); if (!p -> IsConstant()) return 0; if (p-> Type() == this_control.int_type||p-> Type() == this_control.boolean_type) { LiteralValue * litp = p -> value; IntLiteralValue * vp = (IntLiteralValue *) litp; int val = vp -> value; return (val == 0); } return 0; } int ByteCode::GetTypeWords(TypeSymbol * type) { return this_control.IsDoubleWordType(type) ? 2: 1; } int ByteCode::GetLHSKind(AstExpression * expression, MethodSymbol * msym) { if (msym) { // if has write_method if (msym -> ACC_STATIC()) return LHS_STATIC_METHOD; else return LHS_CLASS_METHOD; } if (expression -> CastExpressionCast()) { expression = expression -> CastExpressionCast() -> expression; } else if (expression -> PreUnaryExpressionCast()) { expression = expression -> PreUnaryExpressionCast() -> expression; } else if (expression -> PostUnaryExpressionCast()) { expression = expression -> PostUnaryExpressionCast() -> expression; } // // 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. // In the case of an array access, it is resolved into a type. // VariableSymbol * sym = expression -> symbol -> VariableCast(); if (! sym) return LHS_ARRAY; else if (sym -> owner -> MethodCast()) return LHS_LOCAL; else if (sym -> ACC_STATIC()) return LHS_STATIC; else return LHS_FIELD; } // Methods to load values int ByteCode::GetConstant(LiteralValue *litp, TypeSymbol *type) { int lit_index; if (type == this_control.String()) { Utf8LiteralValue *vp = (Utf8LiteralValue *) litp; if (vp -> constant_pool_index_String != 0 && vp -> constant_pool_class == class_id) lit_index = vp -> constant_pool_index_String; else { // must be string lit_index = RegisterString(vp); } } else { if (litp -> constant_pool_index != 0 && litp -> constant_pool_class == class_id) lit_index = litp -> constant_pool_index; else { // load literal using literal value if (this_control.IsSimpleIntegerValueType(type) || type == this_control.boolean_type) { IntLiteralValue * vp = (IntLiteralValue *) litp; lit_index = RegisterInteger(vp); } else if (type == this_control.float_type) { FloatLiteralValue * vp = (FloatLiteralValue *) litp; IEEEfloat val = vp -> value; lit_index = RegisterFloat(vp); } else if (type == this_control.long_type) { LongLiteralValue * vp = (LongLiteralValue *) litp; lit_index = RegisterLong(vp); } else if (type == this_control.double_type) { DoubleLiteralValue * vp = (DoubleLiteralValue *) litp; lit_index = RegisterDouble(vp); } else chaos("unexpected GetConstant kind"); } } return lit_index; } int ByteCode::LoadConstant(AstExpression *p) { // here to load a constant when the LiteralValue is set. LiteralValue * litp = p -> value; if (!p -> IsConstant()) { chaos("constant expected by LoadConstant"); } return LoadLiteral(p -> value,p-> Type()); } int ByteCode::LoadLiteral(LiteralValue* litp, TypeSymbol *type) { // int lit_index = litp -> constant_pool_index; int lit_index; int is_long_or_double=0; // set if need lcd2_w if (litp -> constant_pool_index >0 && litp -> constant_pool_class == class_id) lit_index= litp -> constant_pool_index; else lit_index = 0; // see if can load without using LDC even if have literal index; otherwise generate constant pool entry // if one has not yet been generated. if (litp == this_control.NullValue()) { PutOp(OP_ACONST_NULL); return 1; } if (type == this_control.String()) { // register index as string if this has not yet been done Utf8LiteralValue * lv = (Utf8LiteralValue *) litp; lit_index = RegisterString(lv); } // load literal using literal value // note that boolean literal values stored as int literals else if (this_control.IsSimpleIntegerValueType(type) || type == this_control.boolean_type) { IntLiteralValue * vp = (IntLiteralValue *) litp; int val = vp -> value; if (val >= -32768 && val <32768) { LoadShort(val); return 1; } lit_index = RegisterInteger(vp); } else if (type == this_control.float_type) { FloatLiteralValue * vp = (FloatLiteralValue *) litp; IEEEfloat val = vp -> value; if (val.Word() == 0) { // if float 0.0 PutOp(OP_FCONST_0); return 1; } else if (val.Word() == 0x3f800000) { // if float 1.0 PutOp(OP_FCONST_1); return 1; } else if (val.Word() == 0x40000000) { // if float 2.0 PutOp(OP_FCONST_2); return 1; } lit_index = RegisterFloat(vp); } else if (type == this_control.long_type) { LongLiteralValue * vp = (LongLiteralValue *) litp; LongInt val = vp -> value; if (val == 0) { PutOp(OP_LCONST_0); // long 0 return 2; } else if (val == 1) { PutOp(OP_LCONST_1); // long 1 return 2; } lit_index = RegisterLong(vp); is_long_or_double=1; } else if (type == this_control.double_type) { // DoubleLiteralValue * vp = (DoubleLiteralValue *) litp; IEEEdouble val = vp -> value; if(val.HighWord() == 0 && val.LowWord() == 0) { PutOp(OP_DCONST_0); return 2; } else if (val.HighWord() == 0x3ff00000 && val.LowWord() == 0x00000000) { // if double 1.0 PutOp(OP_DCONST_1); return 2; } else { // if need ldc2_w lit_index = RegisterDouble(vp); is_long_or_double=1; } } else { chaos("unsupported constant kind"); } if (lit_index == 0) chaos("lit_index zero"); if(!is_long_or_double && lit_index <=255) { PutOp(OP_LDC); PutU1(lit_index); } else { PutOp(is_long_or_double ? OP_LDC2_W : OP_LDC_W); PutU2(lit_index); } return is_long_or_double + 1; } void ByteCode::LoadLocalVariable(VariableSymbol * var) { LoadLocal(var -> LocalVariableIndex(), var-> Type()); } void ByteCode::LoadLocal(int varno, TypeSymbol * type) { int opc0, opc; if (this_control.IsSimpleIntegerValueType(type)|| type == this_control.boolean_type) { opc0 = OP_ILOAD_0; opc = OP_ILOAD; } else if (type == this_control.long_type) { opc0 = OP_LLOAD_0; opc = OP_LLOAD; } else if (type == this_control.float_type) { opc0 = OP_FLOAD_0; opc = OP_FLOAD; } else if (type == this_control.double_type) { opc0 = OP_DLOAD_0; opc = OP_DLOAD; } else { // assume reference opc0 = OP_ALOAD_0; opc = OP_ALOAD; } if (varno<=3) PutOp(opc0+varno); else if (varno<256) { PutOp(opc); PutU1(varno); } else { PutOp(OP_WIDE); PutOp(opc); PutU2(varno); } } void ByteCode::LoadInteger(int val) { if (val >= -32768 && val <32768) { // if short LoadShort(val); } else { u2 index = BuildInteger(val); if (index <=255) { PutOp(OP_LDC); PutU1((unsigned char) index); } else { PutOp(OP_LDC_W); PutU2(index); } } } void ByteCode::LoadShort(int val) { // load short (signed) value onto stack if (val >= -128 && val <128) { switch (val) { case -1: case 0: case 1: case 2: case 3: case 4: case 5: PutOp(OP_ICONST_0 + val); // exploit opcode encoding break; default: // else put byte value PutOp(OP_BIPUSH); PutU1(val); } } else if (val >= -32768 && val <32768) { // if short PutOp(OP_SIPUSH); PutU1((val >> 8)); PutU1(val); } else { chaos("bcShort operand not short!"); } } void ByteCode::ResolveAccess(AstExpression *p, int need_value) { // if need_value zero, then just get address for access of private member // else get value with an extra copy of the needed address below the value AstExpression * resolve; if (p -> FieldAccessCast()) { resolve = p -> FieldAccessCast() -> resolution_opt; } else if (p -> SimpleNameCast()) { resolve = p -> SimpleNameCast() -> resolution_opt; } if (resolve -> MethodInvocationCast()) { if (need_value) { EmitMethodInvocation(resolve -> MethodInvocationCast(), 1); } else { // next does too much, getting base and field value; just want base //Expression(resolve -> MethodInvocationCast() -> method); if (resolve -> MethodInvocationCast() -> method -> FieldAccessCast()) { AstFieldAccess * field_expression = resolve -> MethodInvocationCast() -> method -> FieldAccessCast(); // VariableSymbol * sym = (VariableSymbol *) field_expression -> owner; EmitExpression (field_expression -> base); } else { chaos("field access expected in method resolution"); } } } else { chaos("method invocation expected here"); } } int ByteCode::LoadSimple (int kind,AstExpression *p) { VariableSymbol * sym = (VariableSymbol *) p -> symbol; TypeSymbol * type = (TypeSymbol *) sym -> owner; TypeSymbol * expression_type = p-> Type(); switch (kind) { case LHS_LOCAL: LoadLocal(sym -> LocalVariableIndex(), expression_type); break; case LHS_STATIC_METHOD: EmitExpression(p); // will do resolution break; case LHS_FIELD: case LHS_STATIC: { if (sym -> ACC_STATIC()) { PutOp(OP_GETSTATIC); ChangeStack(GetTypeWords(expression_type)); } else { PutOp(OP_ALOAD_0); // get address of "this" PutOp(OP_GETFIELD); ChangeStack(GetTypeWords(expression_type)-1); } PutU2(GenerateFieldReference(sym)); break; } default: chaos("LoadSimple bad kind"); } return GetTypeWords(expression_type); } void ByteCode::LoadReference(AstExpression *expression) { //load reference from local variable. // otherwise will use getstatic or getfield. TypeSymbol * type; int is_local=0,varno; if (expression -> ParenthesizedExpressionCast()) { expression = UnParenthesize(expression); } VariableSymbol * sym = expression -> symbol -> VariableCast(); if (sym && sym -> owner -> MethodCast()) { is_local=1; varno = sym -> LocalVariableIndex(); LoadLocal(varno,expression-> Type()); return; } if (expression -> ArrayAccessCast()) { // nested array reference EmitArrayAccessLHS(expression -> ArrayAccessCast()); PutOp(OP_AALOAD); } else if (expression -> FieldAccessCast() && expression -> FieldAccessCast() -> resolution_opt) { EmitExpression(expression -> FieldAccessCast() -> resolution_opt); return; } else if (expression -> FieldAccessCast() && (type=sym -> owner -> TypeCast())) { // TypeSymbol * expression_type = expression-> Type(); // here if field if (sym -> ACC_STATIC()) { PutOp(OP_GETSTATIC); ChangeStack(this_control.IsDoubleWordType(type) ? 2: 1); } else { AstFieldAccess *field = expression -> FieldAccessCast(); if (field){ EmitExpression(field -> base); } else if (expression -> SimpleNameCast()) { PutOp(OP_ALOAD_0); // get address of "this" } else { chaos("LoadReference unexpected base type"); } PutOp(OP_GETFIELD); ChangeStack(this_control.IsDoubleWordType(type) ? 1: 0); } PutU2(GenerateFieldReference(sym)); } else { // must have expression, the value of which is reference EmitExpression(expression); } } int ByteCode::LoadArrayElement(TypeSymbol * type) { int opc; if (type == this_control.byte_type || type == this_control.boolean_type) opc=OP_BALOAD; else if (type == this_control.short_type) opc = OP_SALOAD; else if (type == this_control.int_type) opc = OP_IALOAD; else if (type == this_control.long_type) opc = OP_LALOAD; else if (type == this_control.char_type) opc = OP_CALOAD; else if (type == this_control.float_type) opc = OP_FALOAD; else if (type == this_control.double_type) opc = OP_DALOAD; else opc = OP_AALOAD; // assume reference PutOp(opc); return GetTypeWords(type); } void ByteCode::StoreArrayElement(TypeSymbol * type) { int opc; if (type == this_control.byte_type || type == this_control.boolean_type) opc=OP_BASTORE; else if (type == this_control.short_type) opc = OP_SASTORE; else if (type == this_control.int_type) opc = OP_IASTORE; else if (type == this_control.long_type) opc = OP_LASTORE; else if (type == this_control.char_type) opc = OP_CASTORE; else if (type == this_control.float_type) opc = OP_FASTORE; else if (type == this_control.double_type) opc = OP_DASTORE; else opc = OP_AASTORE; // assume reference PutOp(opc); } // Method to generate field reference void ByteCode::StoreField(AstExpression *expression) { // DOT VariableSymbol * sym = (VariableSymbol *) expression -> symbol; TypeSymbol * type = (TypeSymbol *) sym -> owner; TypeSymbol * expression_type=expression-> Type(); if (sym -> ACC_STATIC()) { PutOp(OP_PUTSTATIC); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -2: -1); } else { PutOp(OP_PUTFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -3: -2); } PutU2(GenerateFieldReference(sym)); } void ByteCode::StoreLocalVariable(VariableSymbol * var) { StoreLocal(var -> LocalVariableIndex(), var-> Type()); if (this_control.option.g && var -> LocalVariableIndex() > last_parameter_index) { if (var -> local_program_counter == 0) { // here to update point of first assignment, marking point at which value is // available to be displayed by debugger. var -> local_program_counter = code_attribute -> code.Length(); } } } void ByteCode::StoreLocal(int varno, TypeSymbol * type) { int opc0, opc; if (this_control.IsSimpleIntegerValueType(type)|| type == this_control.boolean_type) { opc0 = OP_ISTORE_0; opc = OP_ISTORE; } else if (type == this_control.long_type) { opc0 = OP_LSTORE_0; opc = OP_LSTORE; } else if (type == this_control.float_type) { opc0 = OP_FSTORE_0; opc = OP_FSTORE; } else if (type == this_control.double_type) { opc0 = OP_DSTORE_0; opc = OP_DSTORE; } else { // assume reference opc0 = OP_ASTORE_0; opc = OP_ASTORE; } if (varno<=3) PutOp(opc0+varno); else if (varno<256) { PutOp(opc); PutU1(varno); } else { PutOp(OP_WIDE); PutOp(opc); PutU2(varno); } } int ByteCode::GenerateFieldReference(VariableSymbol * sym) { // generate a field reg from symbol and class literal // build field ref for field // the field ref requires Utf8 entries for the containing // class, the field name and the field signature, the latter // two expressed as a NameAndTypeEntry if (sym -> constant_pool_index == 0 || sym -> constant_pool_class != class_id) { TypeSymbol * owner = (TypeSymbol *) sym -> owner; sym -> constant_pool_index = BuildFieldref( RegisterClass(owner -> fully_qualified_name), BuildNameAndType( RegisterUtf8(sym -> ExternalIdentity()-> Utf8_literal), RegisterUtf8(sym-> Type() -> signature))); sym -> constant_pool_class = class_id; } return sym -> constant_pool_index; } void ByteCode::StoreSimple (int kind,AstExpression *p) { VariableSymbol * sym = (VariableSymbol *) p -> symbol; TypeSymbol * type = (TypeSymbol *) sym -> owner; TypeSymbol * expression_type = p-> Type(); switch (kind) { case LHS_LOCAL: StoreLocalVariable(sym); break; case LHS_FIELD: case LHS_STATIC: { if (sym -> ACC_STATIC()) { PutOp(OP_PUTSTATIC); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -2: -1); } else { PutOp(OP_ALOAD_0); // get address of "this" PutOp(OP_PUTFIELD); ChangeStack(this_control.IsDoubleWordType(expression_type) ? -3: -2); } PutU2(GenerateFieldReference(sym)); break; default: chaos("StoreSimple bad kind"); } } } // Methods to locate and build entries in constant pool. u2 ByteCode::BuildDouble(IEEEdouble d) { CONSTANT_Double_info *p = new CONSTANT_Double_info(CONSTANT_Double); p -> high_bytes = d.HighWord(); p -> low_bytes = d.LowWord(); constant_pool.Next() = p; constant_pool.Next() = 0; // extra slop for double-word entry return constant_pool.Length()-2; } u2 ByteCode::BuildFieldref(u2 cl_index, u2 nt_index) { CONSTANT_Fieldref_info *p = new CONSTANT_Fieldref_info(CONSTANT_Fieldref); p -> class_index = cl_index; p -> name_and_type_index = nt_index; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildFloat(IEEEfloat val) { CONSTANT_Float_info *p = new CONSTANT_Float_info(CONSTANT_Float); p -> bytes = val.Word(); constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildInteger(int val) { CONSTANT_Integer_info *p = new CONSTANT_Integer_info(CONSTANT_Integer); p -> bytes = ((val>>24 & 0xff) << 24) | ((val>>16 & 0xff) << 16) | ((val>>8 & 0xff) )<< 8 | (val&0xff); constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildInterfaceMethodref(u2 cl_index, u2 nt_index) { CONSTANT_InterfaceMethodref_info *p = new CONSTANT_InterfaceMethodref_info(CONSTANT_InterfaceMethodref); p -> class_index = cl_index; p -> name_and_type_index = nt_index; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildLong(LongInt val) { CONSTANT_Long_info *p = new CONSTANT_Long_info(CONSTANT_Long); p -> high_bytes = val.HighWord(); p -> low_bytes = val.LowWord(); constant_pool.Next() = p; constant_pool.Next() = 0; // extra slop for double-word entry return constant_pool.Length()-2; } static char registered_methods_data[] = { // // This comment describes the strings below. // // "java/lang/Object","clone","()Ljava/lang/Object;", // Clone // "java/lang/Throwable","getMessage","()Ljava/lang/String;", // Clone_getMessage // "java/lang/InternalError","<init>","(Ljava/lang/String;)V", // Clone_init // "java/lang/StringBuffer","toString","()Ljava/lang/String;", // StringBuffer_toString // "java/lang/StringBuffer","<init>","()V", // StringBuffer_init // "java/lang/StringBuffer","append","([C)Ljava/lang/StringBuffer;", // StringBuffer_appendCharArray // "java/lang/StringBuffer","append","(C)Ljava/lang/StringBuffer;", // StringBuffer_appendChar // "java/lang/StringBuffer","append","(Z)Ljava/lang/StringBuffer;", // StringBuffer_appendBoolean // "java/lang/StringBuffer","append","(I)Ljava/lang/StringBuffer;", // StringBuffer_appendInt // "java/lang/StringBuffer","append","(J)Ljava/lang/StringBuffer;", // StringBuffer_appendLong // "java/lang/StringBuffer","append","(F)Ljava/lang/StringBuffer;", // StringBuffer_appendFloat // "java/lang/StringBuffer","append","(D)Ljava/lang/StringBuffer;", // StringBuffer_appendDouble // "java/lang/StringBuffer","append","(Ljava/lang/String;)Ljava/lang/StringBuffer;", // StringBuffer_appendString // "java/lang/StringBuffer","append","(Ljava/lang/Object;)Ljava/lang/StringBuffer;" // StringBuffer_appendObject // U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_O,U_b,U_j,U_e,U_c,U_t,U_NU, U_c,U_l,U_o,U_n,U_e,U_NU, U_LP,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_O,U_b,U_j,U_e,U_c,U_t,U_SC,U_NU, // Clone U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_T,U_h,U_r,U_o,U_w,U_a,U_b,U_l,U_e,U_NU, U_g,U_e,U_t,U_M,U_e,U_s,U_s,U_a,U_g,U_e,U_NU, U_LP,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_SC,U_NU, // Clone_getMessage U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_I,U_n,U_t,U_e,U_r,U_n,U_a,U_l,U_E,U_r,U_r,U_o,U_r,U_NU, U_LT,U_i,U_n,U_i,U_t,U_GT,U_NU, U_LP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_SC,U_RP,U_V,U_NU, // Clone_init U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, U_t,U_o,U_S,U_t,U_r,U_i,U_n,U_g,U_NU, U_LP,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_SC,U_NU, // StringBuffer_toString U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, U_LT,U_i,U_n,U_i,U_t,U_GT,U_NU, U_LP,U_RP,U_V,U_NU, // StringBuffer_init //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"([C)Ljava/lang/StringBuffer;", U_LP,U_LB,U_C,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendCharArray //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(C)Ljava/lang/StringBuffer;", U_LP,U_C,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendChar //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(Z)Ljava/lang/StringBuffer;", U_LP,U_Z,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendBoolean //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(I)Ljava/lang/StringBuffer;", U_LP,U_I,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendInt //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(J)Ljava/lang/StringBuffer;", U_LP,U_J,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendLong //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(F)Ljava/lang/StringBuffer;", U_LP,U_F,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendFloat //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(D)Ljava/lang/StringBuffer;", U_LP,U_D,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendDouble //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(Ljava/lang/String;)Ljava/lang/StringBuffer;", U_LP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_SC,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU, // StringBuffer_appendString //"java/lang/StringBuffer", U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_NU, //"append", U_a,U_p,U_p,U_e,U_n,U_d,U_NU, //"(Ljava/lang/Object;)Ljava/lang/StringBuffer;" U_LP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_O,U_b,U_j,U_e,U_c,U_t,U_SC,U_RP,U_L,U_j,U_a,U_v,U_a,U_SL,U_l,U_a,U_n,U_g,U_SL,U_S,U_t,U_r,U_i,U_n,U_g,U_B,U_u,U_f,U_f,U_e,U_r,U_SC,U_NU // StringBuffer_appendObject #ifdef DD #endif ,U_a // to mark end of last string }; u2 ByteCode::RegisterMethod(int num) { // return index for use in method reference, building an entry if necessary. int pos = num * 3; // starting index of method descriptor // skip precdeing strings int i=0; char *p1, *p2, *p3, *p4; p1 = ®istered_methods_data[0]; for (i=0;i<num;i++) { while (*p1++); // skip first string while (*p1++); // skip second string while (*p1++); // skip third string } p2=p1; while (*p2++); // move p2 to stard of second string p3=p2; while (*p3++); // move p3 to stard of third string p4=p3; while(*p4++); // move past end of third string if (registered_methods[num] == 0) { registered_methods[num] = BuildMethodref( RegisterClass(p1, p2-p1-1), BuildNameAndType( RegisterUtf8(p2, p3-p2-1), RegisterUtf8(p3, p4-p3-1))); } return registered_methods[num]; } u2 ByteCode::BuildMethodref(u2 cl_index, u2 nt_index) { CONSTANT_Methodref_info *p = new CONSTANT_Methodref_info(CONSTANT_Methodref); p -> class_index = cl_index; p -> name_and_type_index = nt_index; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildNameAndType(u2 name, u2 type) { CONSTANT_NameAndType_info *p = new CONSTANT_NameAndType_info(CONSTANT_NameAndType); p -> name_index = name; p -> descriptor_index = type; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildString(u2 si) { CONSTANT_String_info *p = new CONSTANT_String_info(CONSTANT_String); p -> string_index = si; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::BuildUtf8(char * s,int len) { CONSTANT_Utf8_info *p = new CONSTANT_Utf8_info(CONSTANT_Utf8); // build Utf8 from ASCII string (assume no embedded nulls), so just do straight copy p -> bytes = new char[len]; // compute number of bytes in Utf8 form for (int i=0;i<len;i++) { p -> bytes[i] = s[i]; } p -> length_ = len; constant_pool.Next() = p; return constant_pool.Length()-1; } u2 ByteCode::RegisterClass(Utf8LiteralValue * lit) { if (lit == (Utf8LiteralValue *) 0) chaos("null argument to RegisterClass"); if (lit -> constant_pool_class != class_id) { // kill values assigned in prior class lit -> constant_pool_index_Class = 0; lit -> constant_pool_index_String = 0; lit -> constant_pool_index = 0; } if (lit -> constant_pool_index_Class == 0){ CONSTANT_Class_info *ci = new CONSTANT_Class_info(CONSTANT_Class); ci -> name_index = (RegisterUtf8(lit)); constant_pool.Next() = ci; lit -> constant_pool_index_Class = constant_pool.Length()-1; lit -> constant_pool_class = class_id; } return lit -> constant_pool_index_Class; } u2 ByteCode::RegisterClass(char * str, int len) { return RegisterClass(this_control.Utf8_pool.FindOrInsert(str,len)); } u2 ByteCode::RegisterDouble(DoubleLiteralValue * lit) { if (lit == (DoubleLiteralValue *) 0) chaos("null argument to RegisterDouble"); if (lit -> constant_pool_index == 0 || lit -> constant_pool_class != class_id){ lit -> constant_pool_index = BuildDouble(lit -> value); lit -> constant_pool_class = class_id; } return lit -> constant_pool_index; } u2 ByteCode::RegisterInteger(IntLiteralValue * lit) { if (lit == (IntLiteralValue *) 0) chaos("null argument to RegisterInteger"); if (lit -> constant_pool_index == 0 || lit -> constant_pool_class != class_id){ lit -> constant_pool_index = BuildInteger(lit -> value); lit -> constant_pool_class = class_id; } return lit -> constant_pool_index; } u2 ByteCode::RegisterLong(LongLiteralValue * lit) { if (lit == (LongLiteralValue *) 0) chaos("null argument to RegisterLong"); if (lit -> constant_pool_index == 0|| lit -> constant_pool_class != class_id){ lit -> constant_pool_index = BuildLong(lit -> value); lit -> constant_pool_class = class_id; } return lit -> constant_pool_index; } u2 ByteCode::RegisterFloat(FloatLiteralValue * lit) { if (lit == (FloatLiteralValue *) 0) chaos("null argument to RegisterFloat"); if (lit -> constant_pool_index == 0 || lit -> constant_pool_class != class_id){ lit -> constant_pool_index = BuildFloat(lit -> value); lit -> constant_pool_class = class_id; } return lit -> constant_pool_index; } u2 ByteCode::RegisterString(Utf8LiteralValue * lit) { if (lit == (Utf8LiteralValue *) 0) chaos("null argument to RegisterString"); if (lit -> constant_pool_class != class_id) { // kill values assigned in prior class lit -> constant_pool_index_Class = 0; lit -> constant_pool_index_String = 0; lit -> constant_pool_index = 0; } if (lit -> constant_pool_index_String == 0){ lit -> constant_pool_index_String = BuildString(RegisterUtf8(lit)); } return lit -> constant_pool_index_String; } u2 ByteCode::RegisterUtf8(Utf8LiteralValue * lit) { if (lit == (Utf8LiteralValue *) 0) chaos("null argument to RegisterUtf8"); if (lit -> constant_pool_class != class_id) { // kill values assigned in prior class lit -> constant_pool_index_Class = 0; lit -> constant_pool_index_String = 0; lit -> constant_pool_index = 0; } if (lit -> constant_pool_index == 0){ lit -> constant_pool_index = BuildUtf8(lit -> value,lit -> length); lit -> constant_pool_class = class_id; } return lit -> constant_pool_index; } u2 ByteCode::RegisterUtf8(char * str, int len) { return RegisterUtf8(this_control.Utf8_pool.FindOrInsert(str,len)); } // Methods to write out the byte code Deprecated_attribute * ByteCode::CreateDeprecatedAttribute() { Deprecated_attribute * deprecated_attribute; u2 deprecated_attribute_name; u4 deprecated_attribute_length = 0; deprecated_attribute_name = RegisterUtf8(U8S_Deprecated, strlen(U8S_Deprecated)); deprecated_attribute = new Deprecated_attribute(deprecated_attribute_name, deprecated_attribute_length); return deprecated_attribute; } Synthetic_attribute * ByteCode::CreateSyntheticAttribute() { Synthetic_attribute * synthetic_attribute; u2 synthetic_attribute_name; u4 synthetic_attribute_length = 0; synthetic_attribute_name = RegisterUtf8(U8S_Synthetic, strlen(U8S_Synthetic)); synthetic_attribute = new Synthetic_attribute(synthetic_attribute_name, synthetic_attribute_length); return synthetic_attribute; } void ByteCode::FinishCode(TypeSymbol * type) { // finish off code by writing SourceFile attribute // and InnerClasses attribute (if appropriate) u4 sourcefile_attribute_length = 2; int file_name_start=0; int delim=-1; // location of last delimiter in file name TypeSymbol * class_type; int i; u2 name; char *file_name = this_semantic.lex_stream -> FileName(); int file_name_length = this_semantic.lex_stream -> FileNameLength(); for (i = file_name_length; i >= 0; i--) { if (file_name[i] == U_SLASH) { delim = i; break; } } // define Source Attribute if (delim != -1) { file_name_start = delim+1; file_name_length -= (delim + 1); } name = RegisterUtf8(U8S_Sourcefile, strlen(U8S_Sourcefile)); SourceFile_attribute * sourcefile_attribute = new SourceFile_attribute(name, sourcefile_attribute_length); sourcefile_attribute -> sourcefile_index = BuildUtf8(file_name+file_name_start, file_name_length); attributes.Next() = sourcefile_attribute; if (type==(TypeSymbol *) 0) return; // return if interface type if (type -> IsLocal() || type -> IsNested() || type -> NumNestedTypes() > 0) { // here to generate InnerClasses attribute u4 inner_classes_attribute_length = 0; name = RegisterUtf8(U8S_InnerClasses, strlen(U8S_InnerClasses)); inner_classes_attribute = new InnerClasses_attribute(name, inner_classes_attribute_length); inner_classes_attribute -> attribute_name_index = name; Tuple<TypeSymbol *> owners; // need to build chain from this type to its owner all the way to the containing type // and then write that out in reverse order (so containing type comes first), // and then write out an entry for each immediately contained type TypeSymbol * this_type = type; if (this_type != type -> outermost_type) { for (this_type = type;this_type != ((TypeSymbol *) 0) && this_type != type -> outermost_type;this_type = this_type -> ContainingType()) { owners.Next() = this_type; } } for (i = owners.Length();i > 0; i--) { SetInnerAttribute(owners[i - 1]); } for (i = 0; i < type -> NumNestedTypes(); i++) { SetInnerAttribute(type -> NestedType(i)); } inner_classes_attribute -> attribute_length = inner_classes_attribute -> inner_classes.Length() * 8 + 2; attributes.Next() = inner_classes_attribute; } } void ByteCode::AddLocalVariableTableEntry(u2 start,u2 length,u2 name,u2 descriptor,u2 index) { // make entry in local variable table int li = local_variable_table_attribute -> local_variable_table.NextIndex(); local_variable_table_attribute -> local_variable_table[li].start_pc = start; local_variable_table_attribute -> local_variable_table[li].length = length; local_variable_table_attribute -> local_variable_table[li].name_index = name; local_variable_table_attribute -> local_variable_table[li].descriptor_index = descriptor; local_variable_table_attribute -> local_variable_table[li].index = index; } void ByteCode::SetInnerAttribute(TypeSymbol * itype) { int i = inner_classes_attribute -> inner_classes.NextIndex(); inner_classes_attribute -> inner_classes[i].inner_class_info_index = RegisterClass(itype -> fully_qualified_name); if (itype -> IsLocal()) { inner_classes_attribute -> inner_classes[i].outer_class_info_index = 0; } else { TypeSymbol * otype = itype -> ContainingType(); inner_classes_attribute -> inner_classes[i].outer_class_info_index = RegisterClass(otype -> fully_qualified_name); } if (itype -> Anonymous()) { inner_classes_attribute -> inner_classes[i].inner_name_index = 0; } else { inner_classes_attribute -> inner_classes[i].inner_name_index = RegisterUtf8(itype -> name_symbol -> Utf8_literal); } AccessFlags flags; flags.access_flags = itype -> access_flags; inner_classes_attribute -> inner_classes[i].inner_class_access_flags = flags.access_flags; } // Methods to insert values into byte code void ByteCode::PutI1(i1 i) { code_attribute -> code.Next() = i&0xff; } void ByteCode::PutI2(i2 i) { code_attribute -> code.Next() = (i>>8) & 0xff; code_attribute -> code.Next() = i & 0xff; } void ByteCode::PutU1(u1 u) { code_attribute -> code.Next() = u & 0xff; } void ByteCode::PutU2(u2 u) { code_attribute -> code.Next() = (u>>8) & 0xff; code_attribute -> code.Next() = u & 0xff; } void ByteCode::PutU4(u4 u) { code_attribute -> code.Next() = (u>>24) & 0xff; code_attribute -> code.Next() = (u>>16) & 0xff; code_attribute -> code.Next() = (u>>8) & 0xff; code_attribute -> code.Next() = u & 0xff; } // stack_effect gives effect on stack of executing an opcode static int stack_effect[] = { 0, // OP_NOP 1, // OP_ACONST_NULL 1, // OP_ICONST_M1 1, // OP_ICONST_0 1, // OP_ICONST_1 1, // OP_ICONST_2 1, // OP_ICONST_3 1, // OP_ICONST_4 1, // OP_ICONST_5 2, // OP_LCONST_0 2, // OP_LCONST_1 1, // OP_FCONST_0 1, // OP_FCONST_1 1, // OP_FCONST_2 2, // OP_DCONST_0 2, // OP_DCONST_1 1, // OP_BIPUSH 1, // OP_SIPUSH 1, // OP_LDC 1, // OP_LDC_W 2, // OP_LDC2_W 1, // OP_ILOAD 2, // OP_LLOAD 1, // OP_FLOAD 2, // OP_DLOAD 1, // OP_ALOAD 1, // OP_ILOAD_0 1, // OP_ILOAD_1 1, // OP_ILOAD_2 1, // OP_ILOAD_3 2, // OP_LLOAD_0 2, // OP_LLOAD_1 2, // OP_LLOAD_2 2, // OP_LLOAD_3 1, // OP_FLOAD_0 1, // OP_FLOAD_1 1, // OP_FLOAD_2 1, // OP_FLOAD_3 2, // OP_DLOAD_0 2, // OP_DLOAD_1 2, // OP_DLOAD_2 2, // OP_DLOAD_3 1, // OP_ALOAD_0 1, // OP_ALOAD_1 1, // OP_ALOAD_2 1, // OP_ALOAD_3 -1, // OP_IALOAD 0, // OP_LALOAD -1, // OP_FALOAD 0, // OP_DALOAD -1, // OP_AALOAD -1, // OP_BALOAD -1, // OP_CALOAD -1, // OP_SALOAD -1, // OP_ISTORE -2, // OP_LSTORE -1, // OP_FSTORE -2, // OP_DSTORE -1, // OP_ASTORE -1, // OP_ISTORE_0 -1, // OP_ISTORE_1 -1, // OP_ISTORE_2 -1, // OP_ISTORE_3 -2, // OP_LSTORE_0 -2, // OP_LSTORE_1 -2, // OP_LSTORE_2 -2, // OP_LSTORE_3 -1, // OP_FSTORE_0 -1, // OP_FSTORE_1 -1, // OP_FSTORE_2 -1, // OP_FSTORE_3 -2, // OP_DSTORE_0 -2, // OP_DSTORE_1 -2, // OP_DSTORE_2 -2, // OP_DSTORE_3 -1, // OP_ASTORE_0 -1, // OP_ASTORE_1 -1, // OP_ASTORE_2 -1, // OP_ASTORE_3 -3, // OP_IASTORE -4, // OP_LASTORE -3, // OP_FASTORE -4, // OP_DASTORE -3, // OP_AASTORE -3, // OP_BASTORE -3, // OP_CASTORE -3, // OP_SASTORE -1, // OP_POP -2, // OP_POP2 1, // OP_DUP 1, // OP_DUP_X1 1, // OP_DUP_X2 2, // OP_DUP2 2, // OP_DUP2_X1 2, // OP_DUP2_X2 0, // OP_SWAP -1, // OP_IADD -2, // OP_LADD -1, // OP_FADD -2, // OP_DADD -1, // OP_ISUB -2, // OP_LSUB -1, // OP_FSUB -2, // OP_DSUB -1, // OP_IMUL -2, // OP_LMUL -1, // OP_FMUL -2, // OP_DMUL -1, // OP_IDIV -2, // OP_LDIV -1, // OP_FDIV -2, // OP_DDIV -1, // OP_IREM -2, // OP_LREM -1, // OP_FREM -2, // OP_DREM 0, // OP_INEG 0, // OP_LNEG 0, // OP_FNEG 0, // OP_DNEG -1, // OP_ISHL -1, // OP_LSHL -1, // OP_ISHR -1, // OP_LSHR -1, // OP_IUSHR -1, // OP_LUSHR -1, // OP_IAND -2, // OP_LAND -1, // OP_IOR -2, // OP_LOR -1, // OP_IXOR -2, // OP_LXOR 0, // OP_IINC 1, // OP_I2L 0, // OP_I2F 1, // OP_I2D -1, // OP_L2I -1, // OP_L2F 0, // OP_L2D 0, // OP_F2I 1, // OP_F2L 1, // OP_F2D -1, // OP_D2I 0, // OP_D2L -1, // OP_D2F 0, // OP_I2B 0, // OP_I2C 0, // OP_I2S -3, // OP_LCMP -1, // OP_FCMPL -1, // OP_FCMPG -3, // OP_DCMPL -3, // OP_DCMPG -1, // OP_IFEQ -1, // OP_IFNE -1, // OP_IFLT -1, // OP_IFGE -1, // OP_IFGT -1, // OP_IFLE -2, // OP_IF_ICMPEQ -2, // OP_IF_ICMPNE -2, // OP_IF_ICMPLT -2, // OP_IF_ICMPGE -2, // OP_IF_ICMPGT -2, // OP_IF_ICMPLE -2, // OP_IF_ACMPEQ -2, // OP_IF_ACMPNE 0, // OP_GOTO 1, // OP_JSR 0, // OP_RET -1, // OP_TABLESWITCH -1, // OP_LOOKUPSWITCH -1, // OP_IRETURN -2, // OP_LRETURN -1, // OP_FRETURN -2, // OP_DRETURN -1, // OP_ARETURN 0, // OP_RETURN 0, // OP_GETSTATIC, caller must adjust if long or double 0, // OP_PUTSTATIC, caller must adjust if long or double 0, // OP_GETFIELD, caller must adjust if long or double 0, // OP_PUTFIELD, caller must adjust if long or double -1, // OP_INVOKEVIRTUAL, actually -1-args_length -1, // OP_INVOKENONVIRTUAL, actually -1-args_length 0, // OP_INVOKESTATIC, actually -args_length -1, // OP_INVOKEINTERFACE, actually -1 -args_length 0, // OP_XXXUNUSEDXXX 1, // OP_NEW 0, // OP_NEWARRAY 0, // OP_ANEWARRAY 0, // OP_ARRAYLENGTH 0, // OP_ATHROW 0, // OP_CHECKCAST 0, // OP_INSTANCEOF -1, // OP_MONITORENTER -1, // OP_MONITOREXIT 0, // OP_WIDE 0, // OP_MULTIANEWARRAY, actually dims-1 -1, // OP_IFNULL -1, // OP_IFNONNULL 0, // OP_GOTO_W 1, // OP_JSR_W 0, // OP_SOFTWARE 0 // OP_HARDWARE }; void ByteCode::PutNop(int optional) { // emit NOP. The NOP can be replaced by the next instruction if // optional is set; otherwise it must be kept. PutOp(OP_NOP); // this optimization is causing more trouble than it's worth. // latest problem (27 jan 97) was reported by Derek, in that // nop just before label definition, resulted in operation generated // after label def. being moved before the def! Since it's such a sin // to generate junk code, disable the "nop" optimization. // if (optional) last_op_nop = 1; } void ByteCode::PutOp(unsigned char opc) { #ifdef TEST int len = code_attribute -> code.Length(); // show current position if (this_control.option.debug_trap_op >0 && code_attribute -> code.Length() == this_control.option.debug_trap_op) { op_trap(); } // debug trick - force branch on opcode to see what opcode we are compiling switch (opc) { case OP_NOP: break; case OP_ACONST_NULL: break; case OP_ICONST_M1: break; case OP_ICONST_0: break; case OP_ICONST_1: break; case OP_ICONST_2: break; case OP_ICONST_3: break; case OP_ICONST_4: break; case OP_ICONST_5: break; case OP_LCONST_0: break; case OP_LCONST_1: break; case OP_FCONST_0: break; case OP_FCONST_1: break; case OP_FCONST_2: break; case OP_DCONST_0: break; case OP_DCONST_1: break; case OP_BIPUSH: break; case OP_SIPUSH: break; case OP_LDC: break; case OP_LDC_W: break; case OP_LDC2_W: break; case OP_ILOAD: break; case OP_LLOAD: break; case OP_FLOAD: break; case OP_DLOAD: break; case OP_ALOAD: break; case OP_ILOAD_0: break; case OP_ILOAD_1: break; case OP_ILOAD_2: break; case OP_ILOAD_3: break; case OP_LLOAD_0: break; case OP_LLOAD_1: break; case OP_LLOAD_2: break; case OP_LLOAD_3: break; case OP_FLOAD_0: break; case OP_FLOAD_1: break; case OP_FLOAD_2: break; case OP_FLOAD_3: break; case OP_DLOAD_0: break; case OP_DLOAD_1: break; case OP_DLOAD_2: break; case OP_DLOAD_3: break; case OP_ALOAD_0: break; case OP_ALOAD_1: break; case OP_ALOAD_2: break; case OP_ALOAD_3: break; case OP_IALOAD: break; case OP_LALOAD: break; case OP_FALOAD: break; case OP_DALOAD: break; case OP_AALOAD: break; case OP_BALOAD: break; case OP_CALOAD: break; case OP_SALOAD: break; case OP_ISTORE: break; case OP_LSTORE: break; case OP_FSTORE: break; case OP_DSTORE: break; case OP_ASTORE: break; case OP_ISTORE_0: break; case OP_ISTORE_1: break; case OP_ISTORE_2: break; case OP_ISTORE_3: break; case OP_LSTORE_0: break; case OP_LSTORE_1: break; case OP_LSTORE_2: break; case OP_LSTORE_3: break; case OP_FSTORE_0: break; case OP_FSTORE_1: break; case OP_FSTORE_2: break; case OP_FSTORE_3: break; case OP_DSTORE_0: break; case OP_DSTORE_1: break; case OP_DSTORE_2: break; case OP_DSTORE_3: break; case OP_ASTORE_0: break; case OP_ASTORE_1: break; case OP_ASTORE_2: break; case OP_ASTORE_3: break; case OP_IASTORE: break; case OP_LASTORE: break; case OP_FASTORE: break; case OP_DASTORE: break; case OP_AASTORE: break; case OP_BASTORE: break; case OP_CASTORE: break; case OP_SASTORE: break; case OP_POP: break; case OP_POP2: break; case OP_DUP: break; case OP_DUP_X1: break; case OP_DUP_X2: break; case OP_DUP2: break; case OP_DUP2_X1: break; case OP_DUP2_X2: break; case OP_SWAP: break; case OP_IADD: break; case OP_LADD: break; case OP_FADD: break; case OP_DADD: break; case OP_ISUB: break; case OP_LSUB: break; case OP_FSUB: break; case OP_DSUB: break; case OP_IMUL: break; case OP_LMUL: break; case OP_FMUL: break; case OP_DMUL: break; case OP_IDIV: break; case OP_LDIV: break; case OP_FDIV: break; case OP_DDIV: break; case OP_IREM: break; case OP_LREM: break; case OP_FREM: break; case OP_DREM: break; case OP_INEG: break; case OP_LNEG: break; case OP_FNEG: break; case OP_DNEG: break; case OP_ISHL: break; case OP_LSHL: break; case OP_ISHR: break; case OP_LSHR: break; case OP_IUSHR: break; case OP_LUSHR: break; case OP_IAND: break; case OP_LAND: break; case OP_IOR: break; case OP_LOR: break; case OP_IXOR: break; case OP_LXOR: break; case OP_IINC: break; case OP_I2L: break; case OP_I2F: break; case OP_I2D: break; case OP_L2I: break; case OP_L2F: break; case OP_L2D: break; case OP_F2I: break; case OP_F2L: break; case OP_F2D: break; case OP_D2I: break; case OP_D2L: break; case OP_D2F: break; case OP_I2B: break; case OP_I2C: break; case OP_I2S: break; case OP_LCMP: break; case OP_FCMPL: break; case OP_FCMPG: break; case OP_DCMPL: break; case OP_DCMPG: break; case OP_IFEQ: break; case OP_IFNE: break; case OP_IFLT: break; case OP_IFGE: break; case OP_IFGT: break; case OP_IFLE: break; case OP_IF_ICMPEQ: break; case OP_IF_ICMPNE: break; case OP_IF_ICMPLT: break; case OP_IF_ICMPGE: break; case OP_IF_ICMPGT: break; case OP_IF_ICMPLE: break; case OP_IF_ACMPEQ: break; case OP_IF_ACMPNE: break; case OP_GOTO: break; case OP_JSR: break; case OP_RET: break; case OP_TABLESWITCH: break; case OP_LOOKUPSWITCH: break; case OP_IRETURN: break; case OP_LRETURN: break; case OP_FRETURN: break; case OP_DRETURN: break; case OP_ARETURN: break; case OP_RETURN: break; case OP_GETSTATIC: break; case OP_PUTSTATIC: break; case OP_GETFIELD: break; case OP_PUTFIELD: break; case OP_INVOKEVIRTUAL: break; case OP_INVOKENONVIRTUAL: break; case OP_INVOKESTATIC: break; case OP_INVOKEINTERFACE: break; case OP_XXXUNUSEDXXX: break; case OP_NEW: break; case OP_NEWARRAY: break; case OP_ANEWARRAY: break; case OP_ARRAYLENGTH: break; case OP_ATHROW: break; case OP_CHECKCAST: break; case OP_INSTANCEOF: break; case OP_MONITORENTER: break; case OP_MONITOREXIT: break; case OP_WIDE: break; case OP_MULTIANEWARRAY: break; case OP_IFNULL: break; case OP_IFNONNULL: break; case OP_GOTO_W: break; case OP_JSR_W: break; case OP_SOFTWARE: break; case OP_HARDWARE: break; } #endif last_op_pc = code_attribute -> code.Length(); // save pc at start of operation #ifdef NOP_OPT // this optimization doesn't work - disable for now // if (last_op_nop) { // last_op_nop = 0; // code_attribute -> code[last_op_pc - 1] = opc; // } // else { // code_attribute -> code.Next() = opc; // } #else code_attribute -> code.Next() = opc; #endif ChangeStack(stack_effect[opc]); } void ByteCode::ChangeStack(int i) { stack_depth += i; if (stack_depth < 0) stack_depth = 0; if (i>0 && stack_depth > code_attribute -> max_stack) { code_attribute -> max_stack = stack_depth; } #ifdef TRACE_STACK_CHANGE cout << "stack change: pc " << last_op_pc << " change " << i << " stack_depth " << stack_depth << " max_stack: "<< code_attribute -> max_stack << "\n"; #endif } #ifdef TEST void ByteCode::PrintCode() { int i; cout << "magic " << hex << magic << dec << " major_version " << major_version << " minor_version " << minor_version << "\n"; AccessFlags::Print(); cout << "\n"; cout << " this_class " << this_class << " super_class " << super_class <<"\n"; cout << " constant_pool: " << constant_pool.Length() << "\n"; for (i=1;i<constant_pool.Length();i++) { cout << " " << i << " "; constant_pool[i] -> print(constant_pool); if (constant_pool[i] -> tag == CONSTANT_Long || constant_pool[i] -> tag == CONSTANT_Double) { i++;; // skip the next entry for eight-byte constants } } cout << " interfaces " << interfaces.Length() <<": "; for (i=0;i<interfaces.Length();i++) cout << " " << (int) interfaces[i]; cout <<"\n"; for (i=0;i<fields.Length();i++) { cout << "field " << i << "\n"; fields[i].print(constant_pool); } cout << " methods length " << methods.Length() << "\n"; for (i=0;i<methods.Length();i++) { cout << "method " << i << "\n"; methods[i].print(constant_pool); } for (i=0;i<attributes.Length();i++) { cout << "attribute " << i << "\n"; attributes[i] -> print(constant_pool); } cout << "\n"; } #endif