From 40c461f1f4dadb4da9b2531f174bf3bd43c632fc Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Wed, 17 Jun 2015 13:46:16 +0000 Subject: [PATCH] added more code to handle block context --- stix/lib/comp.c | 48 +++++++++++++---- stix/lib/exec.c | 123 ++++++++++++++++++++++++++++++++++++++++---- stix/lib/stix-prv.h | 14 +++-- stix/lib/stix.h | 19 +------ 4 files changed, 162 insertions(+), 42 deletions(-) diff --git a/stix/lib/comp.c b/stix/lib/comp.c index 2a2be2f..26efaed 100644 --- a/stix/lib/comp.c +++ b/stix/lib/comp.c @@ -1868,9 +1868,9 @@ static int compile_method_primitive (stix_t* stix) while (ptr < end && is_digitchar(*ptr)) { prim_no = prim_no * 10 + (*ptr - '0'); - if (prim_no > 0xFFFF) /* TODO: replace 0xFFFF by a macro name */ + if (prim_no > MAX_CODE_PRIMNO) { - set_syntax_error (stix, STIX_SYNERR_PRIMITIVENO, &stix->c->tok.loc, &stix->c->tok.name); + set_syntax_error (stix, STIX_SYNERR_PRIMNO, &stix->c->tok.loc, &stix->c->tok.name); return -1; } @@ -2030,8 +2030,8 @@ static int compile_block_temporaries (stix_t* stix) static int compile_block_expression (stix_t* stix) { - stix_size_t jump_inst_pos; - stix_size_t saved_tmpr_count; + stix_size_t i, jump_inst_pos; + stix_size_t saved_tmpr_count, saved_tmprs_len; stix_size_t block_arg_count; stix_size_t block_code_size; stix_ioloc_t block_loc, colon_loc; @@ -2047,6 +2047,7 @@ static int compile_block_expression (stix_t* stix) block_loc = stix->c->tok.loc; GET_TOKEN (stix); + saved_tmprs_len = stix->c->mth.tmprs.len; saved_tmpr_count = stix->c->mth.tmpr_count; if (stix->c->tok.type == STIX_IOTOK_COLON) @@ -2073,6 +2074,7 @@ static int compile_block_expression (stix_t* stix) } if (add_temporary_variable(stix, &stix->c->tok.name) <= -1) return -1; + stix->c->mth.tmpr_count++; GET_TOKEN (stix); } @@ -2090,20 +2092,36 @@ static int compile_block_expression (stix_t* stix) block_arg_count = stix->c->mth.tmpr_count - saved_tmpr_count; if (block_arg_count > MAX_CODE_NBLKARGS) { + /* while an integer object is pused to indicate the number of + * block arguments, evaluation which is done by message passing + * limits the number of arguments that can be passed. so the + * check is implemented */ set_syntax_error (stix, STIX_SYNERR_BLKARGFLOOD, &colon_loc, STIX_NULL); return -1; } +printf ("push_context %d\n", (int)block_arg_count); +printf ("send_block_copy\n"); if (emit_byte_instruction(stix, CODE_PUSH_CONTEXT) <= -1 || emit_push_smint_literal(stix, block_arg_count) <= -1 || emit_byte_instruction(stix, CODE_SEND_BLOCK_COPY) <= -1) return -1; +printf ("jump\n"); /* insert dummy instructions before replacing them with a jump instruction */ jump_inst_pos = stix->c->mth.code.len; - if (emit_byte_instruction(stix, 0) <= -1 || + if (emit_byte_instruction(stix, MAKE_CODE(CMD_EXTEND_DOUBLE, CMD_JUMP)) <= -1 || emit_byte_instruction(stix, 0) <= -1 || emit_byte_instruction(stix, 0) <= -1) return -1; +/* TODO: fix this part below */ + for (i = 0; i < block_arg_count; i++) + { + /* arrange to store the top of the stack to a block argument + * when evaluation of a block begins */ + if (emit_positional_instruction(stix, CMD_STORE_INTO_TEMPVAR, i) <= -1) return -1; + } +/* TODO: fix this part above */ + if (compile_block_temporaries(stix) <= -1 || compile_block_statements(stix) <= -1) return -1; @@ -2113,17 +2131,22 @@ static int compile_block_expression (stix_t* stix) return -1; } - block_code_size = stix->c->mth.code.len - jump_inst_pos + 3; + block_code_size = stix->c->mth.code.len - jump_inst_pos - 3; /* -3 to exclude JUMP code */ if (block_code_size > MAX_CODE_BLKCODE) { - set_syntax_error (stix, STIX_SYNERR_BLKFLOOD, &colon_loc, STIX_NULL); + set_syntax_error (stix, STIX_SYNERR_BLKFLOOD, &block_loc, STIX_NULL); return -1; } -/* TODO: use CMD_EXTEND if block_code_size is <= 255 */ - stix->c->mth.code.ptr[jump_inst_pos] = MAKE_CODE(CMD_EXTEND_DOUBLE, CMD_JUMP); - stix->c->mth.code.ptr[jump_inst_pos + 1] = (block_code_size & 0xFF00u) >> 8; - stix->c->mth.code.ptr[jump_inst_pos + 2] = (block_code_size & 0x00FFu); +/* TODO: use CMD_EXTEND if block_code_size is > 127 or < -128 and shift code by 1 after having eliminated 1 byte. + stix->c->mth.code.ptr[jump_inst_pos + 1] = (stix_int8_t)block_code_size & 0xFF;*/ + /* note that the jump offset is a signed number */ + stix->c->mth.code.ptr[jump_inst_pos + 1] = ((stix_int16_t)block_code_size) >> 8; + stix->c->mth.code.ptr[jump_inst_pos + 2] = ((stix_int16_t)block_code_size & 0xFF); + + /* restore the temporary count */ + stix->c->mth.tmpr_count = saved_tmpr_count; + stix->c->mth.tmprs.len = saved_tmprs_len; GET_TOKEN (stix); @@ -2578,6 +2601,7 @@ static int compile_method_statement (stix_t* stix) /* handle the return statement */ GET_TOKEN (stix); if (compile_method_expression(stix, 0) <= -1) return -1; +printf ("return_stacktop\n"); return emit_byte_instruction (stix, CODE_RETURN_STACKTOP); } else @@ -2593,6 +2617,7 @@ static int compile_method_statement (stix_t* stix) n = compile_method_expression(stix, 1); if (n <= -1) return -1; +if (n == 0) printf ("return_stacktop\n"); return (n == 0)? emit_byte_instruction (stix, CODE_POP_STACKTOP): 0; } } @@ -2634,6 +2659,7 @@ static int compile_method_statements (stix_t* stix) /* arrange to return the receiver if execution reached * the end of the method without explicit return */ +printf ("return_receiver\n"); return emit_byte_instruction (stix, CODE_RETURN_RECEIVER); } diff --git a/stix/lib/exec.c b/stix/lib/exec.c index adbb180..20b7e06 100644 --- a/stix/lib/exec.c +++ b/stix/lib/exec.c @@ -372,6 +372,33 @@ int primitive_new_with_size (stix_t* stix, stix_ooi_t nargs) return 1; /* success */ } +int primitive_block_context_value (stix_t* stix, stix_ooi_t nargs) +{ + stix_ooi_t sp; + stix_oop_block_context_t blkctx; + + LOAD_ACTIVE_SP (stix, sp); + blkctx = (stix_oop_block_context_t)STACK_GET(stix, sp - nargs); + STIX_ASSERT (STIX_CLASSOF(stix, blkctx) == stix->_block_context); + + if (STIX_OOP_TO_SMINT(blkctx->nargs) != nargs) + { + /* the number of argument doesn't match */ +printf ("PRIM BlockContext value FAIL - NARGS MISMATCH\n"); + return 0; + } + + sp -= nargs + 1; /* pop arguments and receiver */ + STORE_ACTIVE_SP (stix, sp); + + blkctx->ip = blkctx->iip; + blkctx->sp = STIX_OOP_FROM_SMINT(nargs); + blkctx->caller = (stix_oop_t)stix->active_context; + + stix->active_context = (stix_oop_context_t)blkctx; + return 1; +} + typedef int (*primitive_handler_t) (stix_t* stix, stix_ooi_t nargs); struct primitive_t @@ -383,9 +410,10 @@ typedef struct primitive_t primitive_t; static primitive_t primitives[] = { - { -1, primitive_dump }, - { 0, primitive_new }, - { 1, primitive_new_with_size } + { -1, primitive_dump }, + { 0, primitive_new }, + { 1, primitive_new_with_size }, + { -1, primitive_block_context_value } }; int stix_execute (stix_t* stix) @@ -395,7 +423,7 @@ int stix_execute (stix_t* stix) stix_ooi_t ip, sp; stix_byte_t bc, cmd; - stix_oow_t b1; + stix_ooi_t b1; STIX_ASSERT (stix->active_context != STIX_NULL); ip = STIX_OOP_TO_SMINT(stix->active_context->ip); @@ -411,7 +439,11 @@ int stix_execute (stix_t* stix) */ while (1) { - mth = stix->active_context->method; +/* TODO: improve how to access method??? */ + if (stix->active_context->unused == stix->_nil) + mth = stix->active_context->method; + else + mth = ((stix_oop_block_context_t)stix->active_context)->home->method; code = mth->code; printf ("IP => %d ", (int)ip); @@ -422,9 +454,22 @@ printf ("IP => %d ", (int)ip); if (cmd == CMD_EXTEND) { cmd = bc & 0xF; - b1 = code->slot[ip++]; + if (cmd == CMD_JUMP || cmd == CMD_JUMP_IF_FALSE) + b1 = (stix_int8_t)code->slot[ip++]; + else + b1 = code->slot[ip++]; + ip++; + } + else if (cmd == CMD_EXTEND_DOUBLE) + { + cmd = bc & 0xF; + b1 = code->slot[ip++]; + + if (cmd == CMD_JUMP || cmd == CMD_JUMP_IF_FALSE) + b1 = (stix_int16_t)((b1 << 8) | code->slot[ip++]); /* JUMP encodes a signed offset */ + else + b1 = (b1 << 8) | code->slot[ip++]; } -/* TODO: handle CMD_EXTEND_DOUBLE */ else { b1 = bc & 0xF; @@ -463,8 +508,10 @@ printf ("STORE_TEMPVAR %d\n", (int)b1); /* -------------------------------------------------------- */ +/* TODO: CMD_JUMP_IF_FALSE */ case CMD_JUMP: - /* TODO: */ +printf ("JUMP %d\n", (int)b1); + ip += b1; break; /* -------------------------------------------------------- */ @@ -475,7 +522,10 @@ printf ("STORE_TEMPVAR %d\n", (int)b1); /* b1 -> variable index */ stix_ooi_t obj_index; stix_oop_oop_t obj; + obj_index = code->slot[ip++]; + if (cmd == CMD_EXTEND_DOUBLE) + obj_index = (obj_index << 8) | code->slot[ip++]; obj = (stix_oop_oop_t)mth->slot[obj_index]; printf ("PUSH OBJVAR %d %d\n", (int)b1, (int)obj_index); @@ -490,6 +540,8 @@ printf ("PUSH OBJVAR %d %d\n", (int)b1, (int)obj_index); stix_ooi_t obj_index; stix_oop_oop_t obj; obj_index = code->slot[ip++]; + if (cmd == CMD_EXTEND_DOUBLE) + obj_index = (obj_index << 8) | code->slot[ip++]; printf ("STORE OBJVAR %d %d\n", (int)b1, (int)obj_index); obj = (stix_oop_oop_t)mth->slot[obj_index]; @@ -503,8 +555,8 @@ printf ("STORE OBJVAR %d %d\n", (int)b1, (int)obj_index); case CMD_SEND_MESSAGE: case CMD_SEND_MESSAGE_TO_SUPER: { +/* TODO: tail call optimization */ /* b1 -> number of arguments -TODO: handle double extension */ stix_ucs_t mthname; stix_oop_t newrcv; @@ -516,6 +568,8 @@ TODO: handle double extension /* the next byte is the message selector index to the * literal frame. */ selector_index = code->slot[ip++]; + if (cmd == CMD_EXTEND_DOUBLE) + selector_index = (selector_index << 8) | code->slot[ip++]; /* get the selector from the literal frame */ selector = (stix_oop_char_t)mth->slot[selector_index]; @@ -574,8 +628,10 @@ printf ("RETURN INSTVAR AT PREAMBLE\n"); (primitives[prim_no].nargs < 0 || primitives[prim_no].nargs == b1)) { stix_pushtmp (stix, (stix_oop_t*)&newmth); + STORE_ACTIVE_IP (stix, ip); STORE_ACTIVE_SP (stix, sp); n = primitives[prim_no].handler (stix, b1); + LOAD_ACTIVE_IP (stix, ip); LOAD_ACTIVE_SP (stix, sp); stix_poptmp (stix); if (n <= -1) goto oops; @@ -624,14 +680,17 @@ printf ("PUSH_CONTEXT\n"); break; case SUBCMD_PUSH_NEGONE: +printf ("PUSH_NEGONE\n"); STACK_PUSH (stix, STIX_OOP_FROM_SMINT(-1)); break; case SUBCMD_PUSH_ZERO: +printf ("PUSH_ZERO\n"); STACK_PUSH (stix, STIX_OOP_FROM_SMINT(0)); break; case SUBCMD_PUSH_ONE: +printf ("PUSH_SMINT\n"); STACK_PUSH (stix, STIX_OOP_FROM_SMINT(1)); break; } @@ -664,6 +723,52 @@ printf ("RETURN_RECEIVER\n"); /*case CMD_RETURN_BLOCK_STACKTOP:*/ /* TODO: */ + + case SUBCMD_SEND_BLOCK_COPY: + { +printf ("SEND_BLOCK_COPY\n"); + stix_ooi_t nargs; + stix_oop_t rctx; + stix_oop_block_context_t blkctx; + + /* it emulates thisContext blockCopy: nargs */ + STIX_ASSERT (sp >= 1); + STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context->slot[sp]) == stix->_small_integer); + nargs = STIX_OOP_TO_SMINT(stix->active_context->slot[sp]); + STIX_ASSERT (nargs >= 0); + + STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context->slot[sp - 1]) == stix->_context); + + blkctx = (stix_oop_block_context_t)stix_instantiate (stix, stix->_block_context, STIX_NULL, 255); /* TODO: proper stack size */ + if (!blkctx) return -1; + + --sp; + rctx = stix->active_context->slot[sp]; + + /* blkctx->caller is left to nil */ + blkctx->ip = STIX_OOP_FROM_SMINT(ip + 3); /* skip the following JUMP */ + blkctx->sp = 0; + blkctx->nargs = STIX_OOP_FROM_SMINT(nargs); + blkctx->iip = STIX_OOP_FROM_SMINT(ip + 3); + + if (((stix_oop_block_context_t)rctx)->iip == stix->_nil) + { + /* the receiver context is a method context */ + STIX_ASSERT (STIX_CLASSOF(stix, rctx) == stix->_context); + blkctx->home = stix->active_context; + } + else + { + /* block context is active */ + STIX_ASSERT (STIX_CLASSOF(stix, rctx) == stix->_block_context); + blkctx->home = ((stix_oop_block_context_t)rctx)->home; + + } + + stix->active_context->slot[sp] = (stix_oop_t)blkctx; + break; + } + default: stix->errnum = STIX_EINTERN; break; diff --git a/stix/lib/stix-prv.h b/stix/lib/stix-prv.h index 3d8ff7c..4f9af65 100644 --- a/stix/lib/stix-prv.h +++ b/stix/lib/stix-prv.h @@ -305,7 +305,7 @@ enum stix_synerrnum_t STIX_SYNERR_ARGFLOOD, /* too many arguments */ STIX_SYNERR_BLKARGFLOOD, /* too many block arguments */ STIX_SYNERR_BLKFLOOD, /* too large block */ - STIX_SYNERR_PRIMITIVENO /* wrong primitive number */ + STIX_SYNERR_PRIMNO /* wrong primitive number */ }; typedef enum stix_synerrnum_t stix_synerrnum_t; @@ -442,10 +442,14 @@ struct stix_compiler_t #define MAKE_CODE(x,y) (((x) << 4) | y) -#define MAX_CODE_INDEX 0xFFFFu -#define MAX_CODE_NARGS 0xFFFFu -#define MAX_CODE_NBLKARGS 0xFFFFu -#define MAX_CODE_BLKCODE 0xFFFFu +#define MAX_CODE_INDEX (0xFFFFu) +#define MAX_CODE_NARGS (0xFFFFu) +#define MAX_CODE_NBLKARGS (0xFFFFu) +#define MAX_CODE_PRIMNO (0xFFFFu) + +#define MIN_CODE_JUMP (-0x8000) +#define MAX_CODE_JUMP (0x7FFF) +#define MAX_CODE_BLKCODE MAX_CODE_JUMP enum stix_cmdcode_t { diff --git a/stix/lib/stix.h b/stix/lib/stix.h index b76a0ec..ab32cfc 100644 --- a/stix/lib/stix.h +++ b/stix/lib/stix.h @@ -603,12 +603,12 @@ struct stix_context_t { STIX_OBJ_HEADER; - stix_oop_t sender; + stix_oop_t sender; /* message sending context - active context before new context activation*/ stix_oop_t ip; /* instruction pointer */ stix_oop_t sp; /* stack pointer */ stix_oop_method_t method; /* CompiledMethod */ stix_oop_t unused; - stix_oop_t receiver; + stix_oop_t receiver; /* receiver of the message. For a statement '#xxx do: #yyyy', #xxx is the receiver.*/ /* variable indexed part */ stix_oop_t slot[1]; /* stack contents */ @@ -632,21 +632,6 @@ struct stix_block_context_t stix_oop_t slot[1]; /* stack */ }; -#if 0 -#define STIX_PROCESS_NAMED_INSTVARS 4 -typedef struct stix_process_t stix_process_t; -typedef struct stix_process_t* stix_oop_process_t; -struct stix_process_t -{ - STIX_OBJ_HEADER; - stix_oop_context_t context; - stix_oop_t state; /* SmallInteger */ - - stix_oop_process_t prev; - stix_oop_process_t next; -}; -#endif - /** * The STIX_CLASSOF() macro return the class of an object including a numeric * object encoded into a pointer.