/* Sun-$Revision: 23.20 $ */
/* Copyright 1992-9 Sun Microsystems, Inc. and Stanford University.
See the LICENSE file for license information. */
# pragma interface
class abstract_interpreter;
typedef void (*aiCheckFn)(abstract_interpreter*, oop);
// I am an abstract super class for interpreting bytecodes
class abstract_interpreter_method_info: public PartObj {
friend class frame; // for the ITERATORs (_map_oop) (ugh)
friend class InterpreterIterator; // for the interators
friend class FrameIterator;
protected:
mapOop _map_oop; // =badOop when checking codes and literals
public:
u_char* codes;
fint length_codes;
oop* literals;
fint length_literals;
// next two are for real interpreter scavenging & gc
objVectorOop literals_object;
byteVectorOop codes_object;
abstract_interpreter_method_info(methodMap *mm);
abstract_interpreter_method_info(byteVectorOop codes,
objVectorOop literals);
// hide whether oop or map is stored
mapOop map_oop() { return as_mapOop(_map_oop); }
methodMap* map() { return (methodMap*) _map_oop->addr(); }
void print_short();
bool verify();
protected:
void init(byteVectorOop codes, objVectorOop literals);
};
# define ABSTRACT_INTERPRETER_METHOD_INFO_ITERATOR(mi, template, doReinit ) \
{ \
oop* p; \
p = (oop*)&(mi)->_map_oop; template; \
p = (oop*)&(mi)->literals_object; template; \
p = (oop*)&(mi)->codes_object; template; \
\
if (doReinit) { \
assert_objVector((mi)->literals_object, \
"literals must be object vector"); \
(mi)->literals= (mi)->literals_object->objs(); \
assert_byteVector((mi)->codes_object, "codes must be byte vector"); \
(mi)->codes= (unsigned char*) (mi)->codes_object->bytes(); \
} \
}
class abstract_interpreter_bytecode_info: public PartObj {
public:
fint code; // the whole bytecode
fint op; // opcode field
fint x; // index field
inline void decode(fint c);
void print_short();
};
class abstract_interpreter_interbytecode_state: public PartObj {
public:
fint lexical_level; // set by lexical level code, used by local accessors
fint index; // set by index code for extended indices
oop last_literal; // set by literal code, used for setting delegatee
stringOop delegatee; // delegatee for next send, or NULL
bool is_undirected_resend;
inline abstract_interpreter_interbytecode_state();
void reset_index() { index= 0; }
void reset_lexical_level() { lexical_level= 0; }
void reset_send_modifiers() {
delegatee= NULL; is_undirected_resend= false; }
char* check_no_index() {
return index == 0 ? NULL : "this code does not use or preserve index";
}
char* check_no_lexical_level() {
return lexical_level == 0
? NULL
: "this code does not use or preserve lexical_level";
}
char* check_no_operand() {
char* c= check_no_index();
return c ? c : check_no_lexical_level();
}
char* check_no_send_modifiers() {
return !is_undirected_resend && delegatee == NULL
? NULL
: "send modifiers should be set right before the send" ;
}
char* check_no_two_send_modifiers() {
return !is_undirected_resend || delegatee == NULL
? NULL
: "send cannot be both undirected and directed" ;
}
void print_short();
};
# define ABSTRACT_INTERPRETER_INTERBYTECODE_STATE_ITERATOR(is, \
template, \
reinit ) \
{ \
oop* p; \
p = &(is)->last_literal; template; \
p = (oop*)&(is)->delegatee; template; \
}
// I factor out bytecode decoding for all the places in the VM
// that do it.
// I only know about "syntax".
class abstract_interpreter: public AnywhereObj {
friend class frame; // for the ITERATORs (ugh)
friend class FrameIterator; // for the ITERATORs (ugh)
friend class InterpreterIterator;
friend Location location_of_interpreter(void*); // needs prot fns
public:
fint pc;
protected:
char* error_msg;
class abstract_interpreter_method_info mi;
class abstract_interpreter_bytecode_info bc;
class abstract_interpreter_interbytecode_state is;
public:
inline abstract_interpreter(oop meth);
inline abstract_interpreter(methodMap *m);
inline abstract_interpreter(byteVectorOop codes, objVectorOop literals);
protected: // Checkers
friend void check_index_range( abstract_interpreter*, oop);
friend void check_selector_string( abstract_interpreter*, oop);
friend void check_branch_target( abstract_interpreter*, oop);
friend void check_no_send_modifiers( abstract_interpreter*, oop);
friend void check_no_lexical_level( abstract_interpreter*, oop);
friend void check_no_two_send_modifiers( abstract_interpreter*, oop);
friend void check_no_operand( abstract_interpreter*, oop);
friend void check_delegatee( abstract_interpreter*, oop);
friend void check_branch_vector( abstract_interpreter*, oop);
friend void check_for_pop( abstract_interpreter*, oop);
void set_error_msg(char* s) {
if (!error_msg) error_msg= s; } // want first one
public:
char* get_error_msg() { return error_msg; }
protected:
// inflection points for bytecode checker
virtual void check_branch_target(oop p) {
if (!p->is_smi())
set_error_msg( "branch target must be smallInt");
else if (
// == length_codes means return
0 <= smiOop(p)->value()
&& smiOop(p)->value() <= mi.length_codes ) {
}
else
set_error_msg( "bad branch target");
}
virtual bool check(aiCheckFn fn, oop p = NULL) {
assert(
( (*fn)(this, p), !error_msg),
error_msg);
UsedOnlyInAssert((void*)fn);
UsedOnlyInAssert(p);
return true;
}
virtual bool check_for_pop(oop) {
SubclassResponsibility();
return false;
}
protected:
oop get_literal() {
return check(check_index_range) ? mi.literals[is.index] : NULL;
}
inline stringOop get_selector();
int32 get_branch_pc() {
oop p = get_literal();
return check(::check_branch_target, p) ? smiOop(p)->value() : 0;
}
objVectorOop get_branch_vector() {
oop p = get_literal();
return check(check_branch_vector, p)
? objVectorOop(p) : Memory->objVectorObj;
}
public:
virtual void interpret_method();
virtual void interpret_bytecode() {
fetch_and_decode_bytecode();
dispatch_bytecode();
}
virtual void fetch_and_decode_bytecode();
void dispatch_bytecode();
protected:
// NOTE: The pre_*_CODE, do_*_CODE, and post_*_CODE
// routines are called via macro from dispatch_bytecode()
// The following pre_ routines check "syntax" here,
// i.e. checks that do not use method.
void pre_INDEX_CODE() { }
void pre_SEND_CODE() { check(check_no_send_modifiers);
check(check_no_lexical_level); }
void pre_IMPLICIT_SEND_CODE() { check(check_no_lexical_level);
check(check_no_two_send_modifiers); }
void pre_LEXICAL_LEVEL_CODE() { check(check_no_send_modifiers); }
void pre_READ_LOCAL_CODE() { check(check_no_send_modifiers); }
void pre_WRITE_LOCAL_CODE() { check(check_no_send_modifiers); }
void pre_LITERAL_CODE() { check(check_no_send_modifiers); }
void pre_DELEGATEE_CODE() { check(check_no_send_modifiers);
check(check_delegatee); }
void pre_SELF_CODE() { check(check_no_operand);
check(check_no_send_modifiers); }
void pre_POP_CODE() { check(check_no_operand);
check(check_no_send_modifiers); }
void pre_NONLOCAL_RETURN_CODE() { check(check_no_operand);
check(check_no_send_modifiers); }
void pre_UNDIRECTED_RESEND_CODE() { check(check_no_operand);
check(check_no_send_modifiers); }
void pre_DIRECTED_RESEND_CODE() { check(check_no_operand);
check(check_no_send_modifiers); }
void pre_branch_code() { check(check_no_send_modifiers);
check(check_no_lexical_level); }
void pre_BRANCH_CODE() { pre_branch_code(); }
void pre_BRANCH_TRUE_CODE() { pre_branch_code(); }
void pre_BRANCH_FALSE_CODE() { pre_branch_code(); }
void pre_BRANCH_INDEXED_CODE() { pre_branch_code(); }
void pre_illegal_no_operand_code() { }
void pre_illegal_code() { }
protected:
// NOTE: these routines are called via macro from dispatch_bytecode()
// see comment above the pre_'s
// override the following virtuals to do something real
virtual void do_SELF_CODE() { }
virtual void do_POP_CODE() { }
virtual void do_NONLOCAL_RETURN_CODE() { }
virtual void do_INDEX_CODE() { }
virtual void do_literal_code(oop lit) { Unused(lit); }
virtual void do_LITERAL_CODE();
// override either first one or 2 and 3
virtual void do_read_write_local_code(bool isWrite) { Unused(isWrite); }
virtual void do_READ_LOCAL_CODE() { do_read_write_local_code(false); }
virtual void do_WRITE_LOCAL_CODE() { do_read_write_local_code(true); }
// override either first one or 2 and 3
virtual void do_send_code(bool isSelfImplicit, stringOop selector) {
Unused(isSelfImplicit);
Unused(selector);
}
virtual void do_SEND_CODE() {
do_send_code(false, get_selector()); }
virtual void do_IMPLICIT_SEND_CODE() {
do_send_code(true, get_selector()); }
virtual void do_UNDIRECTED_RESEND_CODE() { }
virtual void do_DELEGATEE_CODE() { }
virtual void do_LEXICAL_LEVEL_CODE() { }
virtual void do_branch_code( int32 target_PC, oop target_oop = badOop ) {
Unused(target_PC); Unused(target_oop);
}
virtual void do_BRANCH_CODE() { do_branch_code( get_branch_pc() ); }
virtual void do_BRANCH_TRUE_CODE() {
do_branch_code( get_branch_pc(), (oop) Memory->trueObj ); }
virtual void do_BRANCH_FALSE_CODE() {
do_branch_code( get_branch_pc(), (oop) Memory->falseObj ); }
virtual void do_BRANCH_INDEXED_CODE() { get_branch_vector(); }
virtual void do_illegal_no_operand_code() { do_illegal_code(); }
virtual void do_illegal_code() {
fatal3("bad op code: %ld (opcode: $ld, index: %ld)",
bc.code, bc.op, bc.x);
}
protected:
// NOTE: these routines are called via macro from dispatch_bytecode()
// see comment above the pre_'s
// fixup after bytcode
void post_SELF_CODE() { }
void post_POP_CODE() { }
void post_NONLOCAL_RETURN_CODE() { }
void post_INDEX_CODE() { }
void post_LITERAL_CODE() { is.reset_index(); }
void post_READ_LOCAL_CODE() {
is.reset_index(); is.reset_lexical_level(); }
void post_WRITE_LOCAL_CODE() {
is.reset_index(); is.reset_lexical_level(); }
void post_SEND_CODE() {
is.reset_index(); is.reset_send_modifiers(); }
void post_IMPLICIT_SEND_CODE() {
is.reset_index(); is.reset_send_modifiers(); }
void post_UNDIRECTED_RESEND_CODE() { is.is_undirected_resend= true; }
void post_DELEGATEE_CODE() {
is.delegatee= stringOop(get_literal());
is.reset_index();
}
void post_LEXICAL_LEVEL_CODE() {
is.lexical_level= is.index; is.reset_index(); }
void post_BRANCH_CODE() { is.reset_index(); }
void post_BRANCH_TRUE_CODE() { is.reset_index(); }
void post_BRANCH_FALSE_CODE() { is.reset_index(); }
void post_BRANCH_INDEXED_CODE() { is.reset_index(); }
void post_illegal_no_operand_code() { }
void post_illegal_code() { }
public:
void print_short();
virtual bool verify();
};
// for scavenging, etc, see interpreter.h
# define ABSTRACT_INTERPRETER_ITERATOR(intrp, template, zap, reinit) \
{ \
ABSTRACT_INTERPRETER_METHOD_INFO_ITERATOR( &(intrp)->mi, template, reinit) \
ABSTRACT_INTERPRETER_INTERBYTECODE_STATE_ITERATOR(&(intrp)->is, template, reinit) \
}