-- Copyright 1993-1998, by the Cecil Project -- Department of Computer Science and Engineering, University of Washington -- See the LICENSE file for license information. --DOC This file includes primitives allowing the Cecil program access to the --DOC run-time system's compiled code and method lookup tables, thus --DOC supporting reflection. method send(msg_name@:string, num_params@:int, args@:ordered_collection[dynamic]):dynamic { send(msg_name, num_params, args, { error("message lookup error") }) } method send(msg_name@:string, num_params@:int, args@:ordered_collection[dynamic], if_error:&():dynamic):dynamic { send(msg_name.as_vstring, num_params, args.as_vector, if_error) } method send(msg_name@:vstring, num_params@:int, args@:vector[dynamic], if_error:&():dynamic):dynamic { send_internal(msg_name, num_params, args, false, if_error) } method field_send(msg_name@:string, num_params@:int, args@:ordered_collection[dynamic], if_error:&():dynamic):dynamic { field_send(msg_name.as_vstring, num_params, args.as_vector, if_error) } method field_send(msg_name@:vstring, num_params@:int, args@:vector[dynamic], if_error:&():dynamic):dynamic { send_internal(msg_name, num_params, args, true, if_error) } prim c_++ { #include "selectors.h" }; private method send_internal(msg_name_oop@:vstring, num_params_oop@:int, args_oop@:vector[dynamic], is_field_init:bool, if_error:&():dynamic ):dynamic (** sends_anything, has_nlr, has_side_effects, does_io, formals_escape(f,f,f,f,f) **) { prim c_++ { char* msg_name = AS_C_STRING(msg_name_oop); int num_params = num_params_oop->asInt(); OOP* args = VEC_ELEMS(args_oop,OOP); int num_args = NUM_ELEMS(args_oop); // convert string name/# args into selector int selector = findSelector(msg_name, num_params, num_args); if (selector >= 0) goto found; // did not find right selector => msg not understood printf("\n\n** Error: message \"%s\" with ", msg_name); if (num_params > 0) { printf("%d param%s and ", num_params, num_params == 1 ? "" : "s"); } printf("%d arg%s not understood.\n", num_args, num_args == 1 ? "" : "s"); goto error; found:; { OOP pr_t1; OOP buffer[30]; OOPList* args_list = (OOPList*) &buffer; for (int i = 0; i < num_args; i++) { (*args_list)[i] = args[i]; } RegisteredOOPList args_list_(args_list, num_args); errorsAreFatal = false; c_proc cCode = sendLookup(IF_DEBUG(currentEnv COMMA) selector, *args_list, NULL, is_field_init == BASE(true) ? 0 : 1); errorsAreFatal = true; if (cCode != NULL) { // found a method; invoke it now FrameMarker marker(CallingCecilFrame); #ifdef DEBUG_SUPPORT // get current env on end of argument list (*args_list)[num_args] = (OOP)currentEnv; #endif return (*cCode)((*args_list)[0],(*args_list)[1],(*args_list)[2], (*args_list)[3],(*args_list)[4],(*args_list)[5], (*args_list)[6],(*args_list)[7],(*args_list)[8], (*args_list)[9],(*args_list)[10],(*args_list)[11], (*args_list)[12],(*args_list)[13],(*args_list)[14], (*args_list)[15],(*args_list)[16],(*args_list)[17], (*args_list)[18],(*args_list)[19],(*args_list)[20], (*args_list)[21]); } // error message already printed by run-time system } error:; TAIL_SEND(eval, 0, 1, (if_error), "2#send_internal(@vstring,@int,@vector[A],d,e)"); } } method prim_resend(msg_name@:string, num_params@:int, args@:ordered_collection[dynamic], dirs@:ordered_collection[dynamic], is_undirected:bool, if_error:&():dynamic):dynamic { prim_resend(msg_name.as_vstring, num_params, args.as_vector, dirs.as_vector, is_undirected, if_error) } method prim_resend(msg_name@:vstring, num_params@:int, args@:vector[dynamic], dirs@:vector[dynamic], is_undirected:bool, if_error:&():dynamic):dynamic { prim_resend_internal(msg_name, num_params, args, dirs, is_undirected, false, if_error) } method directed_field_send(msg_name@:string, num_params@:int, args@:ordered_collection[dynamic], dirs@:ordered_collection[dynamic], if_error:&():dynamic):dynamic { directed_field_send(msg_name.as_vstring, num_params, args.as_vector, dirs.as_vector, if_error) } method directed_field_send(msg_name@:vstring, num_params@:int, args@:vector[dynamic], dirs@:vector[dynamic], if_error:&():dynamic):dynamic { prim_resend_internal(msg_name, num_params, args, dirs, false, true, if_error) } private method prim_resend_internal(msg_name_oop@:vstring, num_params_oop@:int, args_oop@:vector[dynamic], dirs_oop@:vector[dynamic], is_undirected:bool, is_directed_field_init:bool, if_error:&():dynamic ):dynamic (** sends_anything, has_nlr, formals_escapes(f,f,f,f,f,f,f), does_io, has_side_effects **) { prim c_++ { char* msg_name = AS_C_STRING(msg_name_oop); int num_params = num_params_oop->asInt(); OOP* args = VEC_ELEMS(args_oop,OOP); int num_args = NUM_ELEMS(args_oop); OOP* dirs = VEC_ELEMS(dirs_oop,OOP); int num_dirs = NUM_ELEMS(dirs_oop); if (num_args != num_dirs) { printf("error: mismatched number of directions and args in resend\n"); goto error; } // convert string name/# args into selector int selector; // not same line, to avoid g++ error selector = findSelector(msg_name, num_params, num_args); if (selector >= 0) goto found; // did not find right selector => msg not understood printf("error: message \"%s\" with %d params and %d args not understood.\n", msg_name, num_params, num_args); goto error; found:; { OOP pr_t1; OOP buffer[30]; OOPList* args_list = (OOPList*) &buffer; int i; for (i = 0; i < num_args; i++) { (*args_list)[i] = args[i]; } RegisteredOOPList args_list_(args_list, num_args); OOP buffer2[30]; OOPList* dirs_list = (OOPList*) &buffer2; for (i = 0; i < num_dirs; i++) { (*dirs_list)[i] = dirs[i]; } RegisteredOOPList dirs_list_(dirs_list, num_dirs); int offset; errorsAreFatal = false; c_proc cCode; errorsAreFatal = false; cCode = resendLookup(IF_DEBUG(currentEnv COMMA) selector, *args_list, *dirs_list, is_undirected == BASE(true) ? (c_proc)0x1 : NULL, NULL, is_directed_field_init == BASE(true) ? 0 : 1); errorsAreFatal = true; if (cCode != NULL) { // found a method; invoke it now FrameMarker marker(CallingCecilFrame); #ifdef DEBUG_SUPPORT // get current env on end of argument list (*args_list)[num_args] = (OOP)currentEnv; #endif return (*cCode)((*args_list)[0],(*args_list)[1],(*args_list)[2], (*args_list)[3],(*args_list)[4],(*args_list)[5], (*args_list)[6],(*args_list)[7],(*args_list)[8], (*args_list)[9],(*args_list)[10],(*args_list)[11], (*args_list)[12],(*args_list)[13],(*args_list)[14], (*args_list)[15],(*args_list)[16],(*args_list)[17], (*args_list)[18],(*args_list)[19],(*args_list)[20], (*args_list)[21]); } // error message already printed by run-time system } error:; TAIL_SEND(eval, 0, 1, (if_error), "2#prim_resend_internal(@vstring,@int,@vector[A],@vector[A],e,f,g)"); } } method type_id(t:any):int (** return_type(int), sends(), formals_escape(f) **) { prim c_++ { #ifdef DISPATCHERS RETURN(asTaggedInt((wordInt)t->map())); #else BP(asTaggedInt((wordInt)t->map())); #endif } } method inherits_from(obj1:any, obj2:any):bool (** return_type(true, false), sends(), formals_escape(f,f) **) { prim c_++ { CecilMap* m1 = obj1->map(); CecilMap* m2 = obj2->map(); #ifdef DISPATCHERS RETURN(m1->descendsFrom(m2) ? BASE(true) : BASE(false)); #else BP(m1->descendsFrom(m2) ? BASE(true) : BASE(false)); #endif } } prim c_++ { #ifdef INDEXED_FIELDS #include "breakpoints.h" #else extern "C++" { #include "breakpoints.h" } #endif }; method set_breakpoint(msg_name@:string):void { set_breakpoint(msg_name.as_vstring); } method set_breakpoint(msg_name_oop@:vstring):void (** return_type(void), sends(), does_io, formals_escape(f) **) { prim c_++ { #ifdef INTERRUPT_CHECKING char* msg_name = AS_C_STRING(msg_name_oop); setBreakpoint(msg_name); #else printf("Breakpoints not supported;\n" "\tprogram compiled with interrupt_checking disabled\n"); #endif } } method show_breakpoints():void (** return_type(void), sends(), does_io **) { prim c_++ { #ifdef INTERRUPT_CHECKING showBreakpoints(); #endif } }