started representing a block([...]) in a CompiledBlock object. BlockContext represents an activated CompiledBlock context from now on
This commit is contained in:
parent
821b68a971
commit
7eb10b162a
@ -111,6 +111,80 @@ class(#pointer,#final,#limited) BlockContext(Context)
|
||||
^self.home vargAt: index
|
||||
}
|
||||
|
||||
method pc
|
||||
{
|
||||
^self.ip
|
||||
}
|
||||
|
||||
method pc: anInteger
|
||||
{
|
||||
self.ip := anInteger.
|
||||
}
|
||||
|
||||
method sp
|
||||
{
|
||||
^self.sp
|
||||
}
|
||||
|
||||
method sp: anInteger
|
||||
{
|
||||
self.sp := anInteger.
|
||||
}
|
||||
|
||||
method restart
|
||||
{
|
||||
ip := self.source pc.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class(#pointer) CompiledMethod(Object)
|
||||
{
|
||||
var owner,
|
||||
name,
|
||||
preamble,
|
||||
preamble_data_1,
|
||||
preamble_data_2,
|
||||
ntmprs,
|
||||
nargs,
|
||||
dbi_file_offset,
|
||||
dbi_method_offset.
|
||||
|
||||
method preamble
|
||||
{
|
||||
^self.preamble
|
||||
}
|
||||
|
||||
method preambleCode
|
||||
{
|
||||
/* TODO: make this a primtive for performance */
|
||||
^(self.preamble bitShift: -4) bitAnd: 16r1F.
|
||||
}
|
||||
|
||||
method owner
|
||||
{
|
||||
^self.owner
|
||||
}
|
||||
|
||||
method name
|
||||
{
|
||||
^self.name
|
||||
}
|
||||
|
||||
method(#primitive) sourceText.
|
||||
method(#primitive) sourceFile.
|
||||
method(#primitive) sourceLine.
|
||||
method(#primitive) ipSourceLine: ip.
|
||||
}
|
||||
|
||||
class CompiledBlock(Object)
|
||||
{
|
||||
var ip, ntmprs, nargs, home.
|
||||
|
||||
// create a new process in the suspended state
|
||||
method(#variadic,#primitive) newProcess().
|
||||
method(#variadic,#primitive) newSystemProcess(). // this method is for internal use only. never call this.
|
||||
|
||||
// TODO: how can i pass variadic arguments to newProcess
|
||||
// method(#variadic) fork() -> how to pass them to newProcess???
|
||||
method fork
|
||||
@ -119,40 +193,35 @@ class(#pointer,#final,#limited) BlockContext(Context)
|
||||
^self newProcess resume.
|
||||
}
|
||||
|
||||
// create a new process in the suspended state
|
||||
method(#variadic,#primitive) newProcess().
|
||||
method(#variadic,#primitive) newSystemProcess(). // this method is for internal use only. never call this.
|
||||
|
||||
// evaluate the block
|
||||
method(#variadic,#primitive) value().
|
||||
|
||||
method value: a
|
||||
{
|
||||
<primitive: #BlockContext_value>
|
||||
<primitive: #CompiledBlock_value>
|
||||
self primitiveFailed.
|
||||
}
|
||||
method value: a value: b
|
||||
{
|
||||
<primitive: #BlockContext_value>
|
||||
<primitive: #CompiledBlock_value>
|
||||
self primitiveFailed.
|
||||
}
|
||||
method value: a value: b value: c
|
||||
{
|
||||
<primitive: #BlockContext_value>
|
||||
<primitive: #CompiledBlock_value>
|
||||
self primitiveFailed.
|
||||
}
|
||||
method value: a value: b value: c value: d
|
||||
{
|
||||
<primitive: #BlockContext_value>
|
||||
<primitive: #CompiledBlock_value>
|
||||
self primitiveFailed.
|
||||
}
|
||||
method value: a value: b value: c value: d value: e
|
||||
{
|
||||
<primitive: #BlockContext_value>
|
||||
<primitive: #CompiledBlock_value>
|
||||
self primitiveFailed.
|
||||
}
|
||||
|
||||
|
||||
method ifTrue: aBlock
|
||||
{
|
||||
//^(self value) ifTrue: aBlock.
|
||||
@ -285,69 +354,4 @@ class(#pointer,#final,#limited) BlockContext(Context)
|
||||
* -------------------------------------------------- */
|
||||
while ((self value) == false) { }.
|
||||
}
|
||||
|
||||
method pc
|
||||
{
|
||||
^self.ip
|
||||
}
|
||||
|
||||
method pc: anInteger
|
||||
{
|
||||
self.ip := anInteger.
|
||||
}
|
||||
|
||||
method sp
|
||||
{
|
||||
^self.sp
|
||||
}
|
||||
|
||||
method sp: anInteger
|
||||
{
|
||||
self.sp := anInteger.
|
||||
}
|
||||
|
||||
method restart
|
||||
{
|
||||
ip := self.source pc.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class(#pointer) CompiledMethod(Object)
|
||||
{
|
||||
var owner,
|
||||
name,
|
||||
preamble,
|
||||
preamble_data_1,
|
||||
preamble_data_2,
|
||||
ntmprs,
|
||||
nargs,
|
||||
dbi_file_offset,
|
||||
dbi_method_offset.
|
||||
|
||||
method preamble
|
||||
{
|
||||
^self.preamble
|
||||
}
|
||||
|
||||
method preambleCode
|
||||
{
|
||||
/* TODO: make this a primtive for performance */
|
||||
^(self.preamble bitShift: -4) bitAnd: 16r1F.
|
||||
}
|
||||
|
||||
method owner
|
||||
{
|
||||
^self.owner
|
||||
}
|
||||
|
||||
method name
|
||||
{
|
||||
^self.name
|
||||
}
|
||||
|
||||
method(#primitive) sourceText.
|
||||
method(#primitive) sourceFile.
|
||||
method(#primitive) sourceLine.
|
||||
method(#primitive) ipSourceLine: ip.
|
||||
}
|
||||
|
@ -337,13 +337,12 @@ extend MethodContext
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
extend BlockContext
|
||||
extend CompiledBlock
|
||||
{
|
||||
method on: anException do: anExceptionBlock
|
||||
{
|
||||
| exception_active |
|
||||
<exception>
|
||||
|
||||
/* -------------------------------
|
||||
thisContext isExceptionContext dump.
|
||||
(thisContext basicSize) dump.
|
||||
|
@ -11,6 +11,6 @@
|
||||
#include 'Stream.moo'.
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
#include 'FFI.moo'.
|
||||
// #include 'FFI.moo'.
|
||||
#include 'Stdio.moo'.
|
||||
#include 'Console.moo'.
|
||||
// #include 'Console.moo'.
|
||||
|
@ -427,5 +427,9 @@ extend MyObject
|
||||
tb := tc at: idx.
|
||||
System log(System.Log.INFO, idx asString, (if (tb value) { " PASS" } else { " FAIL" }), "\n").
|
||||
].
|
||||
|
||||
|
||||
[ 10 dump. [20 dump] value; value; ] value; value.
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -172,26 +172,30 @@ start:
|
||||
// 10-14
|
||||
[(10 isKindOf: Integer) == true],
|
||||
[(10 isKindOf: 20) == false],
|
||||
[([] isKindOf: BlockContext) == true],
|
||||
[([] isKindOf: MethodContext) == false],
|
||||
[([] isKindOf: Context) == true],
|
||||
[([] isKindOf: CompiledBlock) == true],
|
||||
[([] isKindOf: CompiledMethod) == false],
|
||||
[([] isKindOf: BlockContext) == false],
|
||||
|
||||
|
||||
|
||||
// 15-19
|
||||
[([] isKindOf: MethodContext) == false],
|
||||
[([] isKindOf: Context) == false],
|
||||
[("string" isKindOf: String) == true],
|
||||
[(#symbol isKindOf: String) == true],
|
||||
[("string" isKindOf: Symbol) == false],
|
||||
[(#symbol isKindOf: Symbol) == true],
|
||||
[ [] value == nil ],
|
||||
|
||||
// 20-24
|
||||
[(#symbol isKindOf: Symbol) == true],
|
||||
[ [] value == nil ],
|
||||
[ self test_local_return_001 ],
|
||||
[ self test_if_001 ],
|
||||
[ self test_while_001 ],
|
||||
[ (if (1 > 2) { } else { }) == nil. ],
|
||||
[ (if (1 < 2) { } else { }) == nil. ],
|
||||
[ (if (1 > 2) { } else { goto A01. A01: nil }) == nil ],
|
||||
|
||||
// 25-29
|
||||
[ (if (1 < 2) { } else { }) == nil. ],
|
||||
[ (if (1 > 2) { } else { goto A01. A01: nil }) == nil ],
|
||||
[ (if (1 > 2) { } else { 9876. goto A02. A02: 9876. }) == 9876 ],
|
||||
[ [ | a3 | a3:= 20. if (a3 == 21) { a3 := 4321. goto L03 } else { a3 := 1234. goto L03 }. a3 := 8888. L03: a3 ] value == 1234 ],
|
||||
[ [ | a4 | a4:= 21. if (a4 == 21) { a4 := 4321. goto L04 } else { a4 := 1234. goto L04 }. a4 := 8888. L04: a4 ] value == 4321 ]
|
||||
|
@ -254,5 +254,5 @@
|
||||
/* 251 */ &&case_BCODE_RETURN_FROM_BLOCK,
|
||||
/* 252 */ &&case_BCODE_LOCAL_RETURN,
|
||||
/* 253 */ &&case_BCODE_MAKE_BLOCK,
|
||||
/* 254 */ &&case_BCODE_SEND_BLOCK_COPY,
|
||||
/* 254 */ &&case_DEFAULT,
|
||||
/* 255 */ &&case_BCODE_NOOP
|
||||
|
@ -5110,14 +5110,7 @@ static int compile_block_expression (moo_t* moo)
|
||||
* updating the temporaries count for the current block. */
|
||||
if (store_tmpr_count_for_block(moo, md->tmpr_count) <= -1) return -1;
|
||||
|
||||
#if defined(MOO_USE_MAKE_BLOCK)
|
||||
if (emit_double_param_instruction(moo, BCODE_MAKE_BLOCK, block_arg_count, md->tmpr_count/*block_tmpr_count*/, &block_loc) <= -1) return -1;
|
||||
#else
|
||||
if (emit_byte_instruction(moo, BCODE_PUSH_CONTEXT, &block_loc) <= -1 ||
|
||||
emit_push_smooi_literal(moo, block_arg_count, &block_loc) <= -1 ||
|
||||
emit_push_smooi_literal(moo, md->tmpr_count/*block_tmpr_count*/, &block_loc) <= -1 ||
|
||||
emit_byte_instruction(moo, BCODE_SEND_BLOCK_COPY, &block_loc) <= -1) return -1;
|
||||
#endif
|
||||
|
||||
/* insert dummy instructions before replacing them with a jump instruction */
|
||||
jump_inst_pos = md->code.len;
|
||||
|
@ -585,10 +585,6 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn)
|
||||
MOO_ASSERT (moo, b2 >= b1);
|
||||
break;
|
||||
|
||||
case BCODE_SEND_BLOCK_COPY:
|
||||
LOG_INST_0 (moo, "send_block_copy");
|
||||
break;
|
||||
|
||||
case BCODE_NOOP:
|
||||
/* do nothing */
|
||||
LOG_INST_0 (moo, "noop");
|
||||
|
210
moo/lib/exec.c
210
moo/lib/exec.c
@ -2531,7 +2531,7 @@ static moo_pfrc_t pf_method_get_source_text (moo_t* moo, moo_mod_t* mod, moo_ooi
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static moo_pfrc_t __block_value (moo_t* moo, moo_oop_context_t rcv_blkctx, moo_ooi_t nargs, moo_ooi_t num_first_arg_elems, moo_oop_context_t* pblkctx)
|
||||
static moo_pfrc_t __block_value (moo_t* moo, moo_oop_block_t rcv_block, moo_ooi_t nargs, moo_ooi_t num_first_arg_elems, moo_oop_context_t* pblkctx)
|
||||
{
|
||||
/* prepare a new block context for activation.
|
||||
* the receiver must be a block context which becomes the base
|
||||
@ -2555,54 +2555,48 @@ static moo_pfrc_t __block_value (moo_t* moo, moo_oop_context_t rcv_blkctx, moo_o
|
||||
*/
|
||||
|
||||
/* the receiver must be a block context */
|
||||
MOO_ASSERT (moo, MOO_CLASSOF(moo, rcv_blkctx) == moo->_block_context);
|
||||
if (rcv_blkctx->receiver_or_base != moo->_nil)
|
||||
MOO_ASSERT (moo, MOO_CLASSOF(moo, rcv_block) == moo->_block);
|
||||
#if 0
|
||||
if (rcv_block->receiver_or_base != moo->_nil)
|
||||
{
|
||||
/* the 'source' field is not nil.
|
||||
* this block context has already been activated once.
|
||||
* you can't send 'value' again to reactivate it.
|
||||
* For example, [thisContext value] value. */
|
||||
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(rcv_blkctx) > MOO_CONTEXT_NAMED_INSTVARS);
|
||||
moo_seterrbfmt (moo, MOO_EPERM, "re-valuing of a block context - %O", rcv_blkctx);
|
||||
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(rcv_block) > MOO_CONTEXT_NAMED_INSTVARS);
|
||||
moo_seterrbfmt (moo, MOO_EPERM, "re-valuing of a block context - %O", rcv_block);
|
||||
return MOO_PF_FAILURE;
|
||||
}
|
||||
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(rcv_blkctx) == MOO_CONTEXT_NAMED_INSTVARS);
|
||||
#endif
|
||||
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(rcv_block) == MOO_BLOCK_NAMED_INSTVARS);
|
||||
|
||||
if (MOO_OOP_TO_SMOOI(rcv_blkctx->method_or_nargs) != actual_arg_count /* nargs */)
|
||||
if (MOO_OOP_TO_SMOOI(rcv_block->nargs) != actual_arg_count /* nargs */)
|
||||
{
|
||||
moo_seterrbfmt (moo, MOO_ENUMARGS,
|
||||
"wrong number of arguments to a block context %O - %zd expected, %zd given",
|
||||
rcv_blkctx, MOO_OOP_TO_SMOOI(rcv_blkctx->method_or_nargs), actual_arg_count);
|
||||
rcv_block, MOO_OOP_TO_SMOOI(rcv_block->nargs), actual_arg_count);
|
||||
return MOO_PF_FAILURE;
|
||||
}
|
||||
|
||||
/* the number of temporaries stored in the block context
|
||||
* accumulates the number of temporaries starting from the origin.
|
||||
* simple calculation is needed to find the number of local temporaries */
|
||||
local_ntmprs = MOO_OOP_TO_SMOOI(rcv_blkctx->ntmprs) -
|
||||
MOO_OOP_TO_SMOOI(((moo_oop_context_t)rcv_blkctx->home)->ntmprs);
|
||||
local_ntmprs = MOO_OOP_TO_SMOOI(rcv_block->ntmprs) -
|
||||
MOO_OOP_TO_SMOOI(((moo_oop_context_t)rcv_block->home)->ntmprs);
|
||||
MOO_ASSERT (moo, local_ntmprs >= actual_arg_count);
|
||||
|
||||
/* create a new block context to clone rcv_blkctx */
|
||||
moo_pushvolat (moo, (moo_oop_t*)&rcv_blkctx);
|
||||
/* create a new block context based on the receiver block(rcv_block) */
|
||||
moo_pushvolat (moo, (moo_oop_t*)&rcv_block);
|
||||
blkctx = (moo_oop_context_t)moo_instantiate(moo, moo->_block_context, MOO_NULL, local_ntmprs);
|
||||
moo_popvolat (moo);
|
||||
if (!blkctx) return MOO_PF_FAILURE;
|
||||
if (MOO_UNLIKELY(!blkctx)) return MOO_PF_FAILURE;
|
||||
|
||||
#if 0
|
||||
/* shallow-copy the named part including home, origin, etc. */
|
||||
for (i = 0; i < MOO_CONTEXT_NAMED_INSTVARS; i++)
|
||||
{
|
||||
MOO_STORE_OOP (moo, MOO_OBJ_GET_OOP_PTR(blkctx, i), MOO_OBJ_GET_OOP_VAL(rcv_blkctx, i));
|
||||
}
|
||||
#else
|
||||
blkctx->ip = rcv_blkctx->ip; /* no MOO_STORE_OOP() as it's a small integer */
|
||||
blkctx->ntmprs = rcv_blkctx->ntmprs; /* no MOO_STORE_OOP() as it's a small integer */
|
||||
MOO_STORE_OOP (moo, &blkctx->method_or_nargs, rcv_blkctx->method_or_nargs);
|
||||
MOO_STORE_OOP (moo, &blkctx->receiver_or_base, (moo_oop_t)rcv_blkctx);
|
||||
MOO_STORE_OOP (moo, &blkctx->home, rcv_blkctx->home);
|
||||
MOO_STORE_OOP (moo, (moo_oop_t*)&blkctx->origin, (moo_oop_t)rcv_blkctx->origin);
|
||||
#endif
|
||||
blkctx->ip = rcv_block->ip; /* no MOO_STORE_OOP() as it's a small integer */
|
||||
blkctx->ntmprs = rcv_block->ntmprs; /* no MOO_STORE_OOP() as it's a small integer */
|
||||
MOO_STORE_OOP (moo, &blkctx->method_or_nargs, rcv_block->nargs);
|
||||
MOO_STORE_OOP (moo, &blkctx->receiver_or_base, (moo_oop_t)rcv_block);
|
||||
MOO_STORE_OOP (moo, &blkctx->home, (moo_oop_t)rcv_block->home);
|
||||
MOO_STORE_OOP (moo, (moo_oop_t*)&blkctx->origin, (moo_oop_t)rcv_block->home->origin);
|
||||
|
||||
/* TODO: check the stack size of a block context to see if it's large enough to hold arguments */
|
||||
if (num_first_arg_elems > 0)
|
||||
@ -2641,15 +2635,16 @@ static moo_pfrc_t __block_value (moo_t* moo, moo_oop_context_t rcv_blkctx, moo_o
|
||||
static moo_pfrc_t pf_block_value (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
|
||||
{
|
||||
moo_pfrc_t x;
|
||||
moo_oop_context_t rcv_blkctx, blkctx;
|
||||
moo_oop_block_t rcv_block;
|
||||
moo_oop_context_t blkctx;
|
||||
|
||||
rcv_blkctx = (moo_oop_context_t)MOO_STACK_GETRCV(moo, nargs);
|
||||
MOO_PF_CHECK_RCV (moo, MOO_CLASSOF(moo,rcv_blkctx) == moo->_block_context);
|
||||
rcv_block = (moo_oop_block_t)MOO_STACK_GETRCV(moo, nargs);
|
||||
MOO_PF_CHECK_RCV (moo, MOO_CLASSOF(moo,rcv_block) == moo->_block);
|
||||
|
||||
x = __block_value(moo, rcv_blkctx, nargs, 0, &blkctx);
|
||||
x = __block_value(moo, rcv_block, nargs, 0, &blkctx);
|
||||
if (x <= MOO_PF_FAILURE) return x; /* hard failure and soft failure */
|
||||
|
||||
SWITCH_ACTIVE_CONTEXT (moo, (moo_oop_context_t)blkctx);
|
||||
SWITCH_ACTIVE_CONTEXT (moo, blkctx);
|
||||
return MOO_PF_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2662,7 +2657,8 @@ static MOO_INLINE moo_pfrc_t __block_new_process (moo_t* moo, moo_mod_t* mod, mo
|
||||
*/
|
||||
|
||||
int x;
|
||||
moo_oop_context_t rcv_blkctx, blkctx;
|
||||
moo_oop_block_t rcv_block;
|
||||
moo_oop_context_t blkctx;
|
||||
moo_oop_process_t proc;
|
||||
#if 0
|
||||
moo_ooi_t num_first_arg_elems = 0;
|
||||
@ -2686,15 +2682,15 @@ static MOO_INLINE moo_pfrc_t __block_new_process (moo_t* moo, moo_mod_t* mod, mo
|
||||
}
|
||||
#endif
|
||||
|
||||
rcv_blkctx = (moo_oop_context_t)MOO_STACK_GETRCV(moo, nargs);
|
||||
MOO_PF_CHECK_RCV (moo, MOO_CLASSOF(moo,rcv_blkctx) == moo->_block_context);
|
||||
rcv_block = (moo_oop_block_t)MOO_STACK_GETRCV(moo, nargs);
|
||||
MOO_PF_CHECK_RCV (moo, MOO_CLASSOF(moo,rcv_block) == moo->_block);
|
||||
|
||||
/* this primitive creates a new process with a block as if the block
|
||||
* is sent the value message */
|
||||
#if 0
|
||||
x = __block_value(moo, rcv_blkctx, nargs, num_first_arg_elems, &blkctx);
|
||||
x = __block_value(moo, rcv_block, nargs, num_first_arg_elems, &blkctx);
|
||||
#else
|
||||
x = __block_value(moo, rcv_blkctx, nargs, 0, &blkctx);
|
||||
x = __block_value(moo, rcv_block, nargs, 0, &blkctx);
|
||||
#endif
|
||||
if (x <= 0) return x; /* both hard failure and soft failure */
|
||||
|
||||
@ -2705,7 +2701,7 @@ static MOO_INLINE moo_pfrc_t __block_new_process (moo_t* moo, moo_mod_t* mod, mo
|
||||
blkctx->sender = (moo_oop_context_t)moo->_nil;
|
||||
|
||||
proc = make_process(moo, blkctx, proc_flags);
|
||||
if (!proc) return MOO_PF_FAILURE; /* hard failure */ /* TOOD: can't this be treated as a soft failure? throw an exception instead?? */
|
||||
if (MOO_UNLIKELY(!proc)) return MOO_PF_FAILURE; /* hard failure */ /* TOOD: can't this be treated as a soft failure? throw an exception instead?? */
|
||||
|
||||
/* __block_value() has popped all arguments and the receiver.
|
||||
* PUSH the return value instead of changing the stack top */
|
||||
@ -4320,10 +4316,6 @@ static pf_t pftab[] =
|
||||
{ "Apex_~=", { moo_pf_not_equal, 1, 1 } },
|
||||
{ "Apex_~~", { moo_pf_not_identical, 1, 1 } },
|
||||
|
||||
{ "BlockContext_newProcess", { pf_block_new_process, 0, MA } },
|
||||
{ "BlockContext_newSystemProcess", { pf_block_new_system_process, 0, MA } },
|
||||
{ "BlockContext_value", { pf_block_value, 0, MA } },
|
||||
|
||||
{ "Character_<", { pf_character_lt, 1, 1 } },
|
||||
{ "Character_<=", { pf_character_le, 1, 1 } },
|
||||
{ "Character_>", { pf_character_gt, 1, 1 } },
|
||||
@ -4331,6 +4323,9 @@ static pf_t pftab[] =
|
||||
{ "Character_asError", { pf_character_as_error, 0, 0 } },
|
||||
{ "Character_asInteger", { pf_character_as_smooi, 0, 0 } },
|
||||
|
||||
{ "CompiledBlock_newProcess", { pf_block_new_process, 0, MA } },
|
||||
{ "CompiledBlock_newSystemProcess", { pf_block_new_system_process, 0, MA } },
|
||||
{ "CompiledBlock_value", { pf_block_value, 0, MA } },
|
||||
{ "CompiledMethod_ipSourceLine:", { pf_method_get_ip_source_line, 1, 1 } },
|
||||
{ "CompiledMethod_sourceFile", { pf_method_get_source_file, 0, 0 } },
|
||||
{ "CompiledMethod_sourceLine", { pf_method_get_source_line, 0, 0 } },
|
||||
@ -5416,6 +5411,7 @@ static MOO_INLINE void do_return_from_block (moo_t* moo)
|
||||
|
||||
static MOO_INLINE int make_block (moo_t* moo)
|
||||
{
|
||||
#if 0
|
||||
moo_oop_context_t blkctx;
|
||||
moo_oob_t b1, b2;
|
||||
|
||||
@ -5461,6 +5457,46 @@ static MOO_INLINE int make_block (moo_t* moo)
|
||||
/* push the new block context to the stack of the active context */
|
||||
MOO_STACK_PUSH (moo, (moo_oop_t)blkctx);
|
||||
return 0;
|
||||
#else
|
||||
moo_oop_block_t block;
|
||||
moo_oob_t b1, b2;
|
||||
|
||||
/* b1 - number of block arguments
|
||||
* b2 - number of block temporaries */
|
||||
FETCH_PARAM_CODE_TO (moo, b1);
|
||||
FETCH_PARAM_CODE_TO (moo, b2);
|
||||
|
||||
LOG_INST2 (moo, "make_block %zu %zu", b1, b2);
|
||||
|
||||
MOO_ASSERT (moo, b1 >= 0);
|
||||
MOO_ASSERT (moo, b2 >= b1);
|
||||
|
||||
/* the block context object created here is used as a base
|
||||
* object for block context activation. pf_block_value()
|
||||
* clones a block context and activates the cloned context.
|
||||
* this base block context is created with no stack for
|
||||
* this reason */
|
||||
block = (moo_oop_block_t)moo_instantiate(moo, moo->_block, MOO_NULL, 0);
|
||||
if (MOO_UNLIKELY(!block)) return -1;
|
||||
|
||||
/* the long forward jump instruction has the format of
|
||||
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
|
||||
* depending on MOO_BCODE_LONG_PARAM_SIZE. change 'ip' to point to
|
||||
* the instruction after the jump. */
|
||||
block->ip = MOO_SMOOI_TO_OOP(moo->ip + MOO_BCODE_LONG_PARAM_SIZE + 1);
|
||||
/* the number of arguments for a block context is local to the block */
|
||||
block->nargs = MOO_SMOOI_TO_OOP(b1);
|
||||
/* the number of temporaries here is an accumulated count including
|
||||
* the number of temporaries of a home context */
|
||||
block->ntmprs = MOO_SMOOI_TO_OOP(b2);
|
||||
|
||||
/* set the home context where it's defined */
|
||||
MOO_STORE_OOP (moo, (moo_oop_t*)&block->home, (moo_oop_t)moo->active_context);
|
||||
|
||||
/* push the new block context to the stack of the active context */
|
||||
MOO_STACK_PUSH (moo, (moo_oop_t)block);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __execute (moo_t* moo)
|
||||
@ -6059,7 +6095,7 @@ static int __execute (moo_t* moo)
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
ON_INST(BCODE_PUSH_RECEIVER)
|
||||
ON_INST(BCODE_PUSH_RECEIVER) /* push self or super */
|
||||
LOG_INST0 (moo, "push_receiver");
|
||||
MOO_STACK_PUSH (moo, moo->active_context->origin->receiver_or_base);
|
||||
NEXT_INST();
|
||||
@ -6333,94 +6369,6 @@ static int __execute (moo_t* moo)
|
||||
if (make_block(moo) <= -1) return -1;
|
||||
NEXT_INST();
|
||||
|
||||
ON_INST(BCODE_SEND_BLOCK_COPY)
|
||||
{
|
||||
moo_ooi_t nargs, ntmprs;
|
||||
moo_oop_context_t rctx;
|
||||
moo_oop_context_t blkctx;
|
||||
|
||||
LOG_INST0 (moo, "send_block_copy");
|
||||
|
||||
/* it emulates thisContext blockCopy: nargs ofTmprCount: ntmprs */
|
||||
MOO_ASSERT (moo, moo->sp >= 2);
|
||||
|
||||
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(MOO_STACK_GETTOP(moo)));
|
||||
ntmprs = MOO_OOP_TO_SMOOI(MOO_STACK_GETTOP(moo));
|
||||
MOO_STACK_POP (moo);
|
||||
|
||||
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(MOO_STACK_GETTOP(moo)));
|
||||
nargs = MOO_OOP_TO_SMOOI(MOO_STACK_GETTOP(moo));
|
||||
MOO_STACK_POP (moo);
|
||||
|
||||
MOO_ASSERT (moo, nargs >= 0);
|
||||
MOO_ASSERT (moo, ntmprs >= nargs);
|
||||
|
||||
/* the block context object created here is used
|
||||
* as a base object for block context activation.
|
||||
* pf_block_value() clones a block
|
||||
* context and activates the cloned context.
|
||||
* this base block context is created with no
|
||||
* stack for this reason. */
|
||||
blkctx = (moo_oop_context_t)moo_instantiate(moo, moo->_block_context, MOO_NULL, 0);
|
||||
if (!blkctx) return -1;
|
||||
|
||||
/* get the receiver to the block copy message after block context instantiation
|
||||
* not to get affected by potential GC */
|
||||
rctx = (moo_oop_context_t)MOO_STACK_GETTOP(moo);
|
||||
MOO_ASSERT (moo, rctx == moo->active_context);
|
||||
|
||||
/* [NOTE]
|
||||
* blkctx->sender is left to nil. it is set to the
|
||||
* active context before it gets activated. see
|
||||
* pf_block_value().
|
||||
*
|
||||
* blkctx->home is set here to the active context.
|
||||
* it's redundant to have them pushed to the stack
|
||||
* though it is to emulate the message sending of
|
||||
* blockCopy:withNtmprs:. BCODE_MAKE_BLOCK has been
|
||||
* added to replace BCODE_SEND_BLOCK_COPY and pusing
|
||||
* arguments to the stack.
|
||||
*
|
||||
* blkctx->origin is set here by copying the origin
|
||||
* of the active context.
|
||||
*/
|
||||
|
||||
/* the extended jump instruction has the format of
|
||||
* 0000XXXX KKKKKKKK or 0000XXXX KKKKKKKK KKKKKKKK
|
||||
* depending on MOO_BCODE_LONG_PARAM_SIZE. change 'ip' to point to
|
||||
* the instruction after the jump. */
|
||||
blkctx->ip = MOO_SMOOI_TO_OOP(moo->ip + MOO_BCODE_LONG_PARAM_SIZE + 1);
|
||||
blkctx->sp = MOO_SMOOI_TO_OOP(-1);
|
||||
/* the number of arguments for a block context is local to the block */
|
||||
blkctx->method_or_nargs = MOO_SMOOI_TO_OOP(nargs);
|
||||
/* the number of temporaries here is an accumulated count including
|
||||
* the number of temporaries of a home context */
|
||||
blkctx->ntmprs = MOO_SMOOI_TO_OOP(ntmprs);
|
||||
|
||||
MOO_STORE_OOP (moo, &blkctx->home, (moo_oop_t)rctx);
|
||||
blkctx->receiver_or_base = moo->_nil;
|
||||
|
||||
/* [NOTE]
|
||||
* the origin of a method context is set to itself
|
||||
* when it's created. so it's safe to simply copy
|
||||
* the origin field this way.
|
||||
*
|
||||
* if the context that receives the blockCopy message
|
||||
* is a method context, the following conditions are all true.
|
||||
* rctx->home == moo->_nil
|
||||
* MOO_CLASSOF(moo, rctx) == moo->_method_context
|
||||
* rctx == (moo_oop_t)moo->active_context
|
||||
* rctx == rctx->origin
|
||||
*
|
||||
* if it is a block context, the following condition is true.
|
||||
* MOO_CLASSOF(moo, rctx) == moo->_block_context
|
||||
*/
|
||||
MOO_STORE_OOP (moo, (moo_oop_t*)&blkctx->origin, (moo_oop_t)rctx->origin);
|
||||
|
||||
MOO_STACK_SETTOP (moo, (moo_oop_t)blkctx);
|
||||
NEXT_INST();
|
||||
}
|
||||
|
||||
ON_INST(BCODE_NOOP)
|
||||
/* do nothing */
|
||||
LOG_INST0 (moo, "noop");
|
||||
|
@ -254,6 +254,14 @@ static kernel_class_info_t kernel_classes[] =
|
||||
MOO_OBJ_TYPE_OOP,
|
||||
MOO_OFFSETOF(moo_t, _methsig) },
|
||||
|
||||
{ 13,
|
||||
{ 'C','o','m','p','i','l','e','d','B','l','o','c','k' },
|
||||
0,
|
||||
0,
|
||||
MOO_BLOCK_NAMED_INSTVARS,
|
||||
0,
|
||||
MOO_OBJ_TYPE_OOP,
|
||||
MOO_OFFSETOF(moo_t, _block) },
|
||||
|
||||
{ 13,
|
||||
{ 'M','e','t','h','o','d','C','o','n','t','e','x','t' },
|
||||
|
@ -42,10 +42,6 @@
|
||||
/* define this to generate XXXX_CTXTEMVAR instructions */
|
||||
#define MOO_USE_CTXTEMPVAR
|
||||
|
||||
/* define this to use the MAKE_BLOCK instruction instead of
|
||||
* PUSH_CONTEXT, PUSH_INTLIT, PUSH_INTLIT, SEND_BLOCK_COPY */
|
||||
#define MOO_USE_MAKE_BLOCK
|
||||
|
||||
/* define this to enable karatsuba multiplication in bigint */
|
||||
#define MOO_ENABLE_KARATSUBA
|
||||
#define MOO_KARATSUBA_CUTOFF 32
|
||||
@ -1021,7 +1017,7 @@ enum moo_bcode_t
|
||||
BCODE_RETURN_FROM_BLOCK = 0xFB, /* return the stack top from a block */
|
||||
BCODE_LOCAL_RETURN = 0xFC,
|
||||
BCODE_MAKE_BLOCK = 0xFD,
|
||||
BCODE_SEND_BLOCK_COPY = 0xFE,
|
||||
/* UNUSED 0xFE */
|
||||
BCODE_NOOP = 0xFF
|
||||
};
|
||||
|
||||
|
@ -868,7 +868,7 @@ int moo_genpfmethod (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class, moo_met
|
||||
}
|
||||
|
||||
mnsym = (moo_oop_char_t)moo_makesymbol(moo, mthname, i);
|
||||
if (!mnsym) goto oops;
|
||||
if (MOO_UNLIKELY(!mnsym)) goto oops;
|
||||
moo_pushvolat (moo, (moo_oop_t*)&mnsym); tmp_count++;
|
||||
|
||||
/* compose a full primitive function identifier to VM's string buffer.
|
||||
@ -882,7 +882,7 @@ int moo_genpfmethod (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class, moo_met
|
||||
}
|
||||
|
||||
pfidsym = (moo_oop_char_t)moo_makesymbol(moo, moo->sbuf[MOO_SBUF_ID_TMP].ptr, moo->sbuf[MOO_SBUF_ID_TMP].len);
|
||||
if (!pfidsym)
|
||||
if (MOO_UNLIKELY(!pfidsym))
|
||||
{
|
||||
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - symbol instantiation failure\n", mthname, _class->name);
|
||||
goto oops;
|
||||
@ -890,7 +890,7 @@ int moo_genpfmethod (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class, moo_met
|
||||
moo_pushvolat (moo, (moo_oop_t*)&pfidsym); tmp_count++;
|
||||
|
||||
mth = (moo_oop_method_t)moo_instantiatewithtrailer(moo, moo->_method, 1, MOO_NULL, 0);
|
||||
if (!mth)
|
||||
if (MOO_UNLIKELY(!mth))
|
||||
{
|
||||
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - method instantiation failure\n", mthname, _class->name);
|
||||
goto oops;
|
||||
|
@ -695,6 +695,8 @@ struct moo_method_t
|
||||
#define MOO_METHOD_PREAMBLE_FLAG_DUAL (1 << 2)
|
||||
#define MOO_METHOD_PREAMBLE_FLAG_LENIENT (1 << 3) /* lenient primitive method - no exception upon failure. return an error instead */
|
||||
|
||||
|
||||
|
||||
/* [NOTE] if you change the number of instance variables for moo_context_t,
|
||||
* you need to change the defintion of BlockContext and MethodContext.
|
||||
* plus, you need to update various exception handling code in MethodContext */
|
||||
@ -741,7 +743,7 @@ struct moo_context_t
|
||||
* for a block context, it points to the active context at the
|
||||
* moment the block context was created. that is, it points to
|
||||
* a method context where the base block has been defined.
|
||||
* an activated block context copies this field from the source. */
|
||||
* an activated block context copies this field from the base block context. */
|
||||
moo_oop_t home;
|
||||
|
||||
/* it points to the method context created of the method defining the code
|
||||
@ -753,7 +755,7 @@ struct moo_context_t
|
||||
*
|
||||
* when a method context is created, it is set to itself. no change is
|
||||
* made when the method context is activated. when a base block context is
|
||||
* created (when MAKE_BLOCK or BLOCK_COPY is executed), it is set to the
|
||||
* created (when MAKE_BLOCK is executed), it is set to the
|
||||
* origin of the active context. when the base block context is shallow-copied
|
||||
* for activation (when it is sent 'value'), it is set to the origin of
|
||||
* the base block context. */
|
||||
@ -763,6 +765,17 @@ struct moo_context_t
|
||||
moo_oop_t stack[1]; /* context stack that stores arguments and temporaries */
|
||||
};
|
||||
|
||||
#define MOO_BLOCK_NAMED_INSTVARS 4
|
||||
typedef struct moo_block_t moo_block_t;
|
||||
typedef struct moo_block_t* moo_oop_block_t;
|
||||
struct moo_block_t
|
||||
{
|
||||
MOO_OBJ_HEADER;
|
||||
moo_oop_t ip; /* smooi. instruction pointer where the byte code begins in home->origin */
|
||||
moo_oop_t ntmprs;
|
||||
moo_oop_t nargs;
|
||||
moo_oop_context_t home; /* home context */
|
||||
};
|
||||
|
||||
#define MOO_PROCESS_NAMED_INSTVARS 13
|
||||
typedef struct moo_process_t moo_process_t;
|
||||
@ -1609,6 +1622,7 @@ struct moo_t
|
||||
moo_oop_class_t _method_dictionary; /* MethodDictionary */
|
||||
moo_oop_class_t _method; /* CompiledMethod */
|
||||
moo_oop_class_t _methsig; /* MethodSignature */
|
||||
moo_oop_class_t _block; /* CompiledBlock */
|
||||
|
||||
moo_oop_class_t _method_context; /* MethodContext */
|
||||
moo_oop_class_t _block_context; /* BlockContext */
|
||||
|
Loading…
Reference in New Issue
Block a user