static void print_ins(struct ins *i) { char *s; if (i->label > 0) printf("L%d:\t", i->label); else printf("\t"); printf("%s\t", get_opcode_name(i->op)); switch (i->type) { case R_TYPE: printf("%s, %s, %s", get_reg_name(i->un.r.rd), get_reg_name(i->un.r.rs), get_reg_name(i->un.r.rt)); break; case I_TYPE: if (i->op == OP_LW || i->op == OP_SW) printf("%s, %d (%s)", get_reg_name(i->un.i.rt), i->un.i.imm, get_reg_name(i->un.i.rs)); else printf("%s, %s, %d", get_reg_name(i->un.i.rt), get_reg_name(i->un.i.rs), i->un.i.imm); break; case J_TYPE: printf("%d", i->un.j.imm); break; } }
void dissemble(PFBlock fb) { Opcodes opcode; int rmode,rdata, k = 0; string name; Instruction *pi = fb->pstart; while (pi != end_of_code) { opcode = (Opcodes)pi->opcode; // *add 1.2.4 HALT+data is not always a breakpoint! // (it is used as a NOP + <any useful tag data>) if (opcode == HALT) { if (pi->data < MAX_BREAKPOINTS) { Breakpoint *pb = Breakpoint::from_id(pi->data); Instruction ai = pb->saved_instruction(); std::cout << "*"; opcode = (Opcodes)ai.opcode; rmode = ai.rmode; rdata = ai.data; } else { opcode = NOP; rdata = pi->data; } } else { rmode = pi->rmode; rdata = pi->data; } name = get_opcode_name(opcode); std::cout << k++ << ' ' << name << '\t'; if (opcode == CCALL || opcode == CALL || opcode == CALLD || opcode == CALLN) { FBlock* pfb; void *data = data_ptr(rdata); if (opcode == CALLN) pfb = Builtin::imported_fblock_from_function((void*)((NFBlock *)data)->pfn); else pfb = PFBlock(data_ptr(rdata)); if (pfb) Function::from_fun_block(pfb)->dump(std::cout); } else if (opcode == JSWITCH) { int *swb = (int *)data_ptr(rdata); int sz = *swb++; int def = *swb++; std::cout << '(' << sz << ',' << def << ") "; for (int i = 0; i < sz; i++) std::cout << *swb++ << ' ' << *swb++ << ' '; } else if (opcode == TOSD || opcode == TPODS) { PClass pc = *(PClass *)data_ptr(rdata); std::cout << pc->name(); } else { if (rmode) switch(rmode) { case DIRECT: std::cout << "D "; break; case SREL: std::cout << "R "; break; case OREL: std::cout << "S "; break; } if (rdata != 0) std::cout << rdata; } std::cout << std::endl; if (opcode == RET || opcode == RETI || opcode == RETD) break; pi++; } }
/** * Dump an instruction. */ static void tc_dump_inst(struct toy_compiler *tc, const struct toy_inst *inst) { const char *name; int i; name = get_opcode_name(inst->opcode); ilo_printf(" %s", name); if (inst->opcode == GEN6_OPCODE_NOP) { ilo_printf("\n"); return; } if (inst->saturate) ilo_printf(".sat"); name = get_cond_modifier_name(inst->opcode, inst->cond_modifier); if (name) ilo_printf(".%s", name); ilo_printf(" "); tc_dump_dst(tc, inst->dst); for (i = 0; i < Elements(inst->src); i++) { if (tsrc_is_null(inst->src[i])) break; ilo_printf(", "); tc_dump_src(tc, inst->src[i]); } ilo_printf("\n"); }
// Runs the given stack within the given ambience until a condition is // encountered or evaluation completes. This function also bails on and leaves // it to the surrounding code to report error messages. static value_t run_stack_pushing_signals(value_t ambience, value_t stack) { CHECK_FAMILY(ofAmbience, ambience); CHECK_FAMILY(ofStack, stack); runtime_t *runtime = get_ambience_runtime(ambience); frame_t frame = open_stack(stack); code_cache_t cache; code_cache_refresh(&cache, &frame); E_BEGIN_TRY_FINALLY(); while (true) { opcode_t opcode = (opcode_t) read_short(&cache, &frame, 0); TOPIC_INFO(Interpreter, "Opcode: %s (%i)", get_opcode_name(opcode), opcode_counter++); IF_EXPENSIVE_CHECKS_ENABLED(MAYBE_INTERRUPT()); switch (opcode) { case ocPush: { value_t value = read_value(&cache, &frame, 1); frame_push_value(&frame, value); frame.pc += kPushOperationSize; break; } case ocPop: { size_t count = read_short(&cache, &frame, 1); for (size_t i = 0; i < count; i++) frame_pop_value(&frame); frame.pc += kPopOperationSize; break; } case ocCheckStackHeight: { size_t expected = read_short(&cache, &frame, 1); size_t height = frame.stack_pointer - frame.frame_pointer; CHECK_EQ("stack height", expected, height); frame.pc += kCheckStackHeightOperationSize; break; } case ocNewArray: { size_t length = read_short(&cache, &frame, 1); E_TRY_DEF(array, new_heap_array(runtime, length)); for (size_t i = 0; i < length; i++) { value_t element = frame_pop_value(&frame); set_array_at(array, length - i - 1, element); } frame_push_value(&frame, array); frame.pc += kNewArrayOperationSize; break; } case ocInvoke: { // Look up the method in the method space. value_t tags = read_value(&cache, &frame, 1); CHECK_FAMILY(ofCallTags, tags); value_t fragment = read_value(&cache, &frame, 2); CHECK_FAMILY(ofModuleFragment, fragment); value_t helper = read_value(&cache, &frame, 3); CHECK_FAMILY(ofSignatureMap, helper); value_t arg_map; value_t method = lookup_method_full(ambience, fragment, tags, &frame, helper, &arg_map); if (in_condition_cause(ccLookupError, method)) { log_lookup_error(method, tags, &frame); E_RETURN(method); } // The lookup may have failed with a different condition. Check for that. E_TRY(method); E_TRY_DEF(code_block, ensure_method_code(runtime, method)); // We should now have done everything that can fail so we advance the // pc over this instruction. In reality we haven't, the frame push op // below can fail so we should really push the next frame before // storing the pc for this one. Laters. frame.pc += kInvokeOperationSize; // Push a new activation. E_TRY(push_stack_frame(runtime, stack, &frame, get_code_block_high_water_mark(code_block), arg_map)); frame_set_code_block(&frame, code_block); code_cache_refresh(&cache, &frame); break; } case ocSignalContinue: case ocSignalEscape: { // Look up the method in the method space. value_t tags = read_value(&cache, &frame, 1); CHECK_FAMILY(ofCallTags, tags); frame.pc += kSignalEscapeOperationSize; value_t arg_map = whatever(); value_t handler = whatever(); value_t method = lookup_signal_handler_method(ambience, tags, &frame, &handler, &arg_map); bool is_escape = (opcode == ocSignalEscape); if (in_condition_cause(ccLookupError, method)) { if (is_escape) { // There was no handler for this so we have to escape out of the // interpreter altogether. Push the signal frame onto the stack to // record the state of it for the enclosing code. E_TRY(push_stack_frame(runtime, stack, &frame, 1, nothing())); // The stack tracing code expects all frames to have a valid code block // object. The rest makes less of a difference. frame_set_code_block(&frame, ROOT(runtime, empty_code_block)); E_RETURN(new_signal_condition(is_escape)); } else { // There was no handler but this is not an escape so we skip over // the post-handler goto to the default block. CHECK_EQ("signal not followed by goto", ocGoto, read_short(&cache, &frame, 0)); frame.pc += kGotoOperationSize; } } else { // We found a method. Invoke it. E_TRY(method); E_TRY_DEF(code_block, ensure_method_code(runtime, method)); E_TRY(push_stack_frame(runtime, stack, &frame, get_code_block_high_water_mark(code_block), arg_map)); frame_set_code_block(&frame, code_block); CHECK_TRUE("subject not null", is_null(frame_get_argument(&frame, 0))); frame_set_argument(&frame, 0, handler); code_cache_refresh(&cache, &frame); } break; } case ocGoto: { size_t delta = read_short(&cache, &frame, 1); frame.pc += delta; break; } case ocDelegateToLambda: case ocDelegateToBlock: { // This op only appears in the lambda and block delegator methods. // They should never be executed because the delegation happens during // method lookup. If we hit here something's likely wrong with the // lookup process. UNREACHABLE("delegate to lambda"); return new_condition(ccWat); } case ocBuiltin: { value_t wrapper = read_value(&cache, &frame, 1); builtin_method_t impl = (builtin_method_t) get_void_p_value(wrapper); builtin_arguments_t args; builtin_arguments_init(&args, runtime, &frame); E_TRY_DEF(result, impl(&args)); frame_push_value(&frame, result); frame.pc += kBuiltinOperationSize; break; } case ocBuiltinMaybeEscape: { value_t wrapper = read_value(&cache, &frame, 1); builtin_method_t impl = (builtin_method_t) get_void_p_value(wrapper); builtin_arguments_t args; builtin_arguments_init(&args, runtime, &frame); value_t result = impl(&args); if (in_condition_cause(ccSignal, result)) { // The builtin failed. Find the appropriate signal handler and call // it. The invocation record is at the top of the stack. value_t tags = frame_pop_value(&frame); CHECK_FAMILY(ofCallTags, tags); value_t arg_map = whatever(); value_t handler = whatever(); value_t method = lookup_signal_handler_method(ambience, tags, &frame, &handler, &arg_map); if (in_condition_cause(ccLookupError, method)) { // Push the record back onto the stack to it's available to back // tracing. frame_push_value(&frame, tags); frame.pc += kBuiltinMaybeEscapeOperationSize; // There was no handler for this so we have to escape out of the // interpreter altogether. Push the signal frame onto the stack to // record the state of it for the enclosing code. E_TRY(push_stack_frame(runtime, stack, &frame, 1, nothing())); // The stack tracing code expects all frames to have a valid code block // object. The rest makes less of a difference. frame_set_code_block(&frame, ROOT(runtime, empty_code_block)); E_RETURN(new_signal_condition(true)); } // Either found a signal or encountered a different condition. E_TRY(method); // Skip forward to the point we want the signal to return to, the // leave-or-fire-barrier op that will do the leaving. size_t dest_offset = read_short(&cache, &frame, 2); frame.pc += dest_offset; // Run the handler. E_TRY_DEF(code_block, ensure_method_code(runtime, method)); E_TRY(push_stack_frame(runtime, stack, &frame, get_code_block_high_water_mark(code_block), arg_map)); frame_set_code_block(&frame, code_block); CHECK_TRUE("subject not null", is_null(frame_get_argument(&frame, 0))); frame_set_argument(&frame, 0, handler); code_cache_refresh(&cache, &frame); } else { // The builtin didn't cause a condition so we can just keep going. E_TRY(result); frame_push_value(&frame, result); frame.pc += kBuiltinMaybeEscapeOperationSize; } break; } case ocReturn: { value_t result = frame_pop_value(&frame); frame_pop_within_stack_piece(&frame); code_cache_refresh(&cache, &frame); frame_push_value(&frame, result); break; } case ocStackBottom: { value_t result = frame_pop_value(&frame); validate_stack_on_normal_exit(&frame); E_RETURN(result); } case ocStackPieceBottom: { value_t top_piece = frame.stack_piece; value_t result = frame_pop_value(&frame); value_t next_piece = get_stack_piece_previous(top_piece); set_stack_top_piece(stack, next_piece); frame = open_stack(stack); code_cache_refresh(&cache, &frame); frame_push_value(&frame, result); break; } case ocSlap: { value_t value = frame_pop_value(&frame); size_t argc = read_short(&cache, &frame, 1); for (size_t i = 0; i < argc; i++) frame_pop_value(&frame); frame_push_value(&frame, value); frame.pc += kSlapOperationSize; break; } case ocNewReference: { // Create the reference first so that if it fails we haven't clobbered // the stack yet. E_TRY_DEF(ref, new_heap_reference(runtime, nothing())); value_t value = frame_pop_value(&frame); set_reference_value(ref, value); frame_push_value(&frame, ref); frame.pc += kNewReferenceOperationSize; break; } case ocSetReference: { value_t ref = frame_pop_value(&frame); CHECK_FAMILY(ofReference, ref); value_t value = frame_peek_value(&frame, 0); set_reference_value(ref, value); frame.pc += kSetReferenceOperationSize; break; } case ocGetReference: { value_t ref = frame_pop_value(&frame); CHECK_FAMILY(ofReference, ref); value_t value = get_reference_value(ref); frame_push_value(&frame, value); frame.pc += kGetReferenceOperationSize; break; } case ocLoadLocal: { size_t index = read_short(&cache, &frame, 1); value_t value = frame_get_local(&frame, index); frame_push_value(&frame, value); frame.pc += kLoadLocalOperationSize; break; } case ocLoadGlobal: { value_t ident = read_value(&cache, &frame, 1); CHECK_FAMILY(ofIdentifier, ident); value_t fragment = read_value(&cache, &frame, 2); CHECK_FAMILY(ofModuleFragment, fragment); value_t module = get_module_fragment_module(fragment); E_TRY_DEF(value, module_lookup_identifier(runtime, module, get_identifier_stage(ident), get_identifier_path(ident))); frame_push_value(&frame, value); frame.pc += kLoadGlobalOperationSize; break; } case ocLoadArgument: { size_t param_index = read_short(&cache, &frame, 1); value_t value = frame_get_argument(&frame, param_index); frame_push_value(&frame, value); frame.pc += kLoadArgumentOperationSize; break; } case ocLoadRefractedArgument: { size_t param_index = read_short(&cache, &frame, 1); size_t block_depth = read_short(&cache, &frame, 2); value_t subject = frame_get_argument(&frame, 0); frame_t home = frame_empty(); get_refractor_refracted_frame(subject, block_depth, &home); value_t value = frame_get_argument(&home, param_index); frame_push_value(&frame, value); frame.pc += kLoadRefractedArgumentOperationSize; break; } case ocLoadRefractedLocal: { size_t index = read_short(&cache, &frame, 1); size_t block_depth = read_short(&cache, &frame, 2); value_t subject = frame_get_argument(&frame, 0); frame_t home = frame_empty(); get_refractor_refracted_frame(subject, block_depth, &home); value_t value = frame_get_local(&home, index); frame_push_value(&frame, value); frame.pc += kLoadRefractedLocalOperationSize; break; } case ocLoadLambdaCapture: { size_t index = read_short(&cache, &frame, 1); value_t subject = frame_get_argument(&frame, 0); CHECK_FAMILY(ofLambda, subject); value_t value = get_lambda_capture(subject, index); frame_push_value(&frame, value); frame.pc += kLoadLambdaCaptureOperationSize; break; } case ocLoadRefractedCapture: { size_t index = read_short(&cache, &frame, 1); size_t block_depth = read_short(&cache, &frame, 2); value_t subject = frame_get_argument(&frame, 0); frame_t home = frame_empty(); get_refractor_refracted_frame(subject, block_depth, &home); value_t lambda = frame_get_argument(&home, 0); CHECK_FAMILY(ofLambda, lambda); value_t value = get_lambda_capture(lambda, index); frame_push_value(&frame, value); frame.pc += kLoadRefractedLocalOperationSize; break; } case ocLambda: { value_t space = read_value(&cache, &frame, 1); CHECK_FAMILY(ofMethodspace, space); size_t capture_count = read_short(&cache, &frame, 2); value_t captures; E_TRY_DEF(lambda, new_heap_lambda(runtime, space, nothing())); if (capture_count == 0) { captures = ROOT(runtime, empty_array); frame.pc += kLambdaOperationSize; } else { E_TRY_SET(captures, new_heap_array(runtime, capture_count)); // The pc gets incremented here because it is after we've done all // the allocation but before anything has been popped off the stack. // This way all the above is idempotent, and the below is guaranteed // to succeed. frame.pc += kLambdaOperationSize; for (size_t i = 0; i < capture_count; i++) set_array_at(captures, i, frame_pop_value(&frame)); } set_lambda_captures(lambda, captures); frame_push_value(&frame, lambda); break; } case ocCreateBlock: { value_t space = read_value(&cache, &frame, 1); CHECK_FAMILY(ofMethodspace, space); // Create the block object. E_TRY_DEF(block, new_heap_block(runtime, nothing())); // Create the stack section that describes the block. value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgBlockSection)); set_barrier_state_payload(section, block); refraction_point_init(section, &frame); set_block_section_methodspace(section, space); set_block_section(block, section); value_validate(block); value_validate(section); // Push the block object. frame_push_value(&frame, block); frame.pc += kCreateBlockOperationSize; break; } case ocCreateEnsurer: { value_t code_block = read_value(&cache, &frame, 1); value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgEnsureSection)); set_barrier_state_payload(section, code_block); refraction_point_init(section, &frame); value_validate(section); frame_push_value(&frame, section); frame.pc += kCreateEnsurerOperationSize; break; } case ocCallEnsurer: { value_t value = frame_pop_value(&frame); value_t shard = frame_pop_value(&frame); frame_push_value(&frame, value); frame_push_value(&frame, shard); CHECK_GENUS(dgEnsureSection, shard); value_t code_block = get_barrier_state_payload(shard); CHECK_FAMILY(ofCodeBlock, code_block); // Unregister the barrier before calling it, otherwise if we leave // by escaping we'll end up calling it over again. barrier_state_unregister(shard, stack); frame.pc += kCallEnsurerOperationSize; value_t argmap = ROOT(runtime, array_of_zero); push_stack_frame(runtime, stack, &frame, get_code_block_high_water_mark(code_block), argmap); frame_set_code_block(&frame, code_block); code_cache_refresh(&cache, &frame); break; } case ocDisposeEnsurer: { // Discard the result of the ensure block. If an ensure blocks needs // to return a useful value it can do it via an escape. frame_pop_value(&frame); value_t shard = frame_pop_value(&frame); CHECK_GENUS(dgEnsureSection, shard); value_t value = frame_pop_value(&frame); frame_destroy_derived_object(&frame, get_genus_descriptor(dgEnsureSection)); frame_push_value(&frame, value); frame.pc += kDisposeEnsurerOperationSize; break; } case ocInstallSignalHandler: { value_t space = read_value(&cache, &frame, 1); CHECK_FAMILY(ofMethodspace, space); size_t dest_offset = read_short(&cache, &frame, 2); // Allocate the derived object that's going to hold the signal handler // state. value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgSignalHandlerSection)); // Initialize the handler. set_barrier_state_payload(section, space); refraction_point_init(section, &frame); // Bring the frame state to the point we'll want to escape to (modulo // the destination offset). frame_push_value(&frame, section); frame.pc += kInstallSignalHandlerOperationSize; // Finally capture the escape state. capture_escape_state(section, &frame, dest_offset); value_validate(section); break; } case ocUninstallSignalHandler: { // The result has been left at the top of the stack. value_t value = frame_pop_value(&frame); value_t section = frame_pop_value(&frame); CHECK_GENUS(dgSignalHandlerSection, section); barrier_state_unregister(section, stack); frame_destroy_derived_object(&frame, get_genus_descriptor(dgSignalHandlerSection)); frame_push_value(&frame, value); frame.pc += kUninstallSignalHandlerOperationSize; break; } case ocCreateEscape: { size_t dest_offset = read_short(&cache, &frame, 1); // Create an initially empty escape object. E_TRY_DEF(escape, new_heap_escape(runtime, nothing())); // Allocate the escape section on the stack, hooking the barrier into // the barrier chain. value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgEscapeSection)); // Point the state and object to each other. set_barrier_state_payload(section, escape); set_escape_section(escape, section); // Get execution ready for the next operation. frame_push_value(&frame, escape); frame.pc += kCreateEscapeOperationSize; // This is the execution state the escape will escape to (modulo the // destination offset) so this is what we want to capture. capture_escape_state(section, &frame, dest_offset); break; } case ocLeaveOrFireBarrier: { size_t argc = read_short(&cache, &frame, 1); // At this point the handler has been set as the subject of the call // to the handler method. Above the arguments are also two scratch // stack entries. value_t handler = frame_peek_value(&frame, argc + 2); CHECK_GENUS(dgSignalHandlerSection, handler); if (maybe_fire_next_barrier(&cache, &frame, runtime, stack, handler)) { // Pop the scratch entries off. frame_pop_value(&frame); frame_pop_value(&frame); // Pop the value off. value_t value = frame_pop_value(&frame); // Escape to the handler's home. restore_escape_state(&frame, stack, handler); code_cache_refresh(&cache, &frame); // Push the value back on, now in the handler's home frame. frame_push_value(&frame, value); } else { // If a barrier was fired we'll want to let the interpreter loop // around again so just break without touching .pc. } break; } case ocFireEscapeOrBarrier: { value_t escape = frame_get_argument(&frame, 0); CHECK_FAMILY(ofEscape, escape); value_t section = get_escape_section(escape); // Fire the next barrier or, if there are no more barriers, apply the // escape. if (maybe_fire_next_barrier(&cache, &frame, runtime, stack, section)) { value_t value = frame_get_argument(&frame, 2); restore_escape_state(&frame, stack, section); code_cache_refresh(&cache, &frame); frame_push_value(&frame, value); } else { // If a barrier was fired we'll want to let the interpreter loop // around again so just break without touching .pc. } break; } case ocDisposeEscape: { value_t value = frame_pop_value(&frame); value_t escape = frame_pop_value(&frame); CHECK_FAMILY(ofEscape, escape); value_t section = get_escape_section(escape); value_validate(section); barrier_state_unregister(section, stack); on_escape_section_exit(section); frame_destroy_derived_object(&frame, get_genus_descriptor(dgEscapeSection)); frame_push_value(&frame, value); frame.pc += kDisposeEscapeOperationSize; break; } case ocDisposeBlock: { value_t value = frame_pop_value(&frame); value_t block = frame_pop_value(&frame); CHECK_FAMILY(ofBlock, block); value_t section = get_block_section(block); barrier_state_unregister(section, stack); on_block_section_exit(section); frame_destroy_derived_object(&frame, get_genus_descriptor(dgBlockSection)); frame_push_value(&frame, value); frame.pc += kDisposeBlockOperationSize; break; } default: ERROR("Unexpected opcode %i", opcode); UNREACHABLE("unexpected opcode"); break; } } E_FINALLY(); close_frame(&frame); E_END_TRY_FINALLY(); }
floatf sm_run(StackMachine *sm, SMOpCode *codes, int codelen) { #if 0 float registers[9]={0}; //hrm, wonder if compiler will put these in actual registers for me. . . SMOpCode *curcode = codes; sm->registers = registers; #ifdef DEBUG_SM printf("\n\nStarting run: %i %p %p\n", codelen, curcode, sm); #endif while (curcode < codes + codelen) { #ifdef DEBUG_SM printf("%s %i %i %i %p %p : %d\n", get_opcode_name(curcode->code), curcode->arg1, curcode->arg2, curcode->arg3, sm->func_table, func_table, sm->stackcur); #endif if (sm->exception) { fprintf(stderr, "Detected exception;\n"); fprintf(stderr, "Exception: %s\n", sm->except_msg); break; } switch(curcode->code) { case PUSH: //args: register to push onto stack #register 7 is /dev/null? sm->stack[sm->stackcur++] = sm->registers[curcode->arg1]; break; case POP: //args: register to pop stack value onto sm->registers[curcode->arg1] = sm->stack[--sm->stackcur]; break; case PUSH_GLOBAL: { int loc = curcode->arg1 | curcode->arg2<<16; sm->stack[sm->stackcur++] = sm->stack[loc]; break; } case LOAD_GLOBAL: { int loc = curcode->arg1 | curcode->arg2<<16; sm->stack[sm->stackcur-1] = sm->stack[loc]; break; } case REG_TO_STK: //args: location in stack, register to load into stack { int loc = curcode->arg1 | curcode->arg2<<16; sm->stack[sm->stackcur-1-loc] = sm->registers[curcode->arg3]; break; } case CONST_TO_REG: //[register, index in constant table] sm->registers[curcode->arg1] = sm->constants[curcode->arg2]; break; case CONST_TO_STK: //[stack (two args), index in constant table] { int loc = curcode->arg1 | curcode->arg2<<16; sm->stack[sm->stackcur-1-loc] = sm->constants[curcode->arg3]; break; } case ABS_STK_TO_REG: { int loc = curcode->arg1 | curcode->arg2<<16; sm->registers[curcode->arg3] = sm->stack[loc]; break; } case STK_TO_REG: //args: location in stack, register to load stack entry into { int loc = curcode->arg1 | curcode->arg2<<16; sm->registers[curcode->arg3] = sm->stack[sm->stackcur-1-loc]; break; } case MUL: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] * sm->registers[curcode->arg2]; break; case DIV: //args: [register a:register b:register out] if (sm->registers[curcode->arg2] == 0.0) sm->registers[curcode->arg3] = 0.0; else sm->registers[curcode->arg3] = sm->registers[curcode->arg1] / sm->registers[curcode->arg2]; break; case ADD: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] + sm->registers[curcode->arg2]; break; case SUB: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] - sm->registers[curcode->arg2]; break; case GT: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] > sm->registers[curcode->arg2]; break; case LT: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] < sm->registers[curcode->arg2]; break; case GTE: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] >= sm->registers[curcode->arg2]; break; case LTE: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] <= sm->registers[curcode->arg2]; break; case EQ: //args: [register a:register b:register out] sm->registers[curcode->arg3] = sm->registers[curcode->arg1] == sm->registers[curcode->arg2]; break; case LOGICAL_NEGATE: //args: [register a:register out] sm->registers[curcode->arg2] = sm->registers[curcode->arg1] == 0.0; break; case NEGATE: //args: [register a:register out] sm->registers[curcode->arg2] = -sm->registers[curcode->arg1]; break; case POW: //args: [register a:register b:register out] sm->registers[curcode->arg3] = pow(sm->registers[curcode->arg1], sm->registers[curcode->arg2]); break; case FUNC_CALL: //args: [func name id] sm->func_table = func_table; #ifdef DEBUG_SM printf(" %p %d\n", sm->func_table, sm->totfunc); printf(" %p\n", sm->func_table + curcode->arg1); printf(" %s %p\n", sm->func_table[curcode->arg1].name, sm->func_table[curcode->arg1].function); #endif sm->func_table[curcode->arg1].function(sm); //return value from called function should now be on stack //the called function also popped the arguments, itself break; default: printf("Unimplemented opcode %d!\n", curcode->code); break; } curcode++; } sm->registers = NULL; return sm->stack[sm->stackcur-1]; #endif return; //0.0; }