// $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 = &registered_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