⚡ split coroutine lib from builtin
This commit is contained in:
parent
654a37ab88
commit
29b15b89f7
|
@ -20,6 +20,7 @@ set(NASAL_OBJECT_SOURCE_FILE
|
|||
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_builtin.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/coroutine.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/fg_props.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/math_lib.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
||||
|
|
10
makefile
10
makefile
|
@ -18,7 +18,8 @@ NASAL_HEADER=\
|
|||
src/optimizer.h\
|
||||
src/symbol_finder.h\
|
||||
src/fg_props.h\
|
||||
src/math_lib.h
|
||||
src/math_lib.h\
|
||||
src/coroutine.h
|
||||
|
||||
NASAL_OBJECT=\
|
||||
build/nasal_err.o\
|
||||
|
@ -37,6 +38,7 @@ NASAL_OBJECT=\
|
|||
build/nasal_builtin.o\
|
||||
build/fg_props.o\
|
||||
build/math_lib.o\
|
||||
build/coroutine.o\
|
||||
build/nasal_vm.o\
|
||||
build/nasal_dbg.o\
|
||||
build/main.o
|
||||
|
@ -89,6 +91,12 @@ build/nasal_builtin.o: \
|
|||
src/nasal_builtin.h src/nasal_builtin.cpp | build
|
||||
$(CXX) -std=$(STD) -c -O3 src/nasal_builtin.cpp -fno-exceptions -fPIC -o build/nasal_builtin.o -I .
|
||||
|
||||
build/coroutine.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_gc.h\
|
||||
src/coroutine.h src/coroutine.cpp | build
|
||||
$(CXX) -std=$(STD) -c -O3 src/coroutine.cpp -fno-exceptions -fPIC -o build/coroutine.o -I .
|
||||
|
||||
build/math_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_gc.h\
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#include "coroutine.h"
|
||||
|
||||
var builtin_cocreate(var* local, gc& ngc) {
|
||||
// +-------------+
|
||||
// | old pc | <- top[0]
|
||||
// +-------------+
|
||||
// | old localr | <- top[-1]
|
||||
// +-------------+
|
||||
// | old upvalr | <- top[-2]
|
||||
// +-------------+
|
||||
// | local scope |
|
||||
// | ... |
|
||||
// +-------------+ <- local pointer stored in localr
|
||||
// | old funcr | <- old function stored in funcr
|
||||
// +-------------+
|
||||
var func = local[1];
|
||||
if (func.type!=vm_func) {
|
||||
return nas_err("coroutine::create", "must use a function to create coroutine");
|
||||
}
|
||||
if (ngc.cort) {
|
||||
return nas_err("coroutine::create", "cannot create another coroutine in a coroutine");
|
||||
}
|
||||
var co = ngc.alloc(vm_co);
|
||||
nas_co& cort = co.co();
|
||||
cort.ctx.pc = func.func().entry-1;
|
||||
|
||||
cort.ctx.top[0] = nil;
|
||||
cort.ctx.localr = cort.ctx.top+1;
|
||||
cort.ctx.top = cort.ctx.localr+func.func().lsize;
|
||||
cort.ctx.localr[0] = func.func().local[0];
|
||||
cort.ctx.top[0] = nil; // old upvalr
|
||||
cort.ctx.top++;
|
||||
cort.ctx.top[0] = var::addr((var*)nullptr); // old localr
|
||||
cort.ctx.top++;
|
||||
cort.ctx.top[0] = var::ret(0); // old pc, set to zero to make op_ret recognizing this as coroutine function
|
||||
|
||||
cort.ctx.funcr = func; // make sure the coroutine function can use correct upvalues
|
||||
cort.status = nas_co::status::suspended;
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
var builtin_coresume(var* local, gc& ngc) {
|
||||
if (ngc.cort) {
|
||||
return nas_err("coroutine::resume", "cannot start another coroutine when one is running");
|
||||
}
|
||||
var co = local[1];
|
||||
// return nil if is not a coroutine object
|
||||
if (co.type!=vm_co) {
|
||||
return nil;
|
||||
}
|
||||
// cannot resume a dead coroutine
|
||||
if (co.co().status==nas_co::status::dead) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// change to coroutine context
|
||||
ngc.ctxchg(co.co());
|
||||
|
||||
// fetch coroutine's stack top and return
|
||||
// so the coroutine's stack top in fact is not changed
|
||||
if (ngc.rctx->top[0].type==vm_ret) {
|
||||
// when first calling this coroutine, the stack top must be vm_ret
|
||||
return ngc.rctx->top[0];
|
||||
}
|
||||
|
||||
// after first calling the coroutine, each time coroutine.yield triggered
|
||||
// a new space will be reserved on stack with value nil
|
||||
// so we could fill this place with args
|
||||
|
||||
// the coroutine seems like coroutine.yield returns the value
|
||||
// but in fact coroutine.yield stop the coroutine
|
||||
// until main context calls the coroutine.resume
|
||||
return local[2];
|
||||
}
|
||||
|
||||
var builtin_coyield(var* local, gc& ngc) {
|
||||
if (!ngc.cort) {
|
||||
return nas_err("coroutine::yield", "no coroutine is running");
|
||||
}
|
||||
|
||||
// this will set to main stack top
|
||||
ngc.ctxreserve();
|
||||
|
||||
// then this will return value to main's stack top[0]
|
||||
// the procedure seems like coroutine.resume returns the value
|
||||
// but in fact coroutine.resume stop the main context
|
||||
// until coroutine calls the coroutine.yield
|
||||
return local[1];
|
||||
}
|
||||
|
||||
var builtin_costatus(var* local, gc& ngc) {
|
||||
var co = local[1];
|
||||
if (co.type!=vm_co) {
|
||||
return ngc.newstr("error");
|
||||
}
|
||||
switch(co.co().status) {
|
||||
case nas_co::status::suspended: return ngc.newstr("suspended");
|
||||
case nas_co::status::running: return ngc.newstr("running");
|
||||
case nas_co::status::dead: return ngc.newstr("dead");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
var builtin_corun(var* local, gc& ngc) {
|
||||
return ngc.cort? one:zero;
|
||||
}
|
||||
|
||||
nasal_builtin_table coroutine_native[] = {
|
||||
{"__cocreate", builtin_cocreate},
|
||||
{"__coresume", builtin_coresume},
|
||||
{"__coyield", builtin_coyield},
|
||||
{"__costatus", builtin_costatus},
|
||||
{"__corun", builtin_corun},
|
||||
{nullptr, nullptr}
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
|
||||
var builtin_cocreate(var*, gc&);
|
||||
var builtin_coresume(var*, gc&);
|
||||
var builtin_coyield(var*, gc&);
|
||||
var builtin_costatus(var*, gc&);
|
||||
var builtin_corun(var*, gc&);
|
||||
|
||||
extern nasal_builtin_table coroutine_native[];
|
|
@ -1040,112 +1040,6 @@ var builtin_md5(var* local, gc& ngc) {
|
|||
return ngc.newstr(md5(str.str()));
|
||||
}
|
||||
|
||||
var builtin_cocreate(var* local, gc& ngc) {
|
||||
// +-------------+
|
||||
// | old pc | <- top[0]
|
||||
// +-------------+
|
||||
// | old localr | <- top[-1]
|
||||
// +-------------+
|
||||
// | old upvalr | <- top[-2]
|
||||
// +-------------+
|
||||
// | local scope |
|
||||
// | ... |
|
||||
// +-------------+ <- local pointer stored in localr
|
||||
// | old funcr | <- old function stored in funcr
|
||||
// +-------------+
|
||||
var func = local[1];
|
||||
if (func.type!=vm_func) {
|
||||
return nas_err("coroutine::create", "must use a function to create coroutine");
|
||||
}
|
||||
if (ngc.cort) {
|
||||
return nas_err("coroutine::create", "cannot create another coroutine in a coroutine");
|
||||
}
|
||||
var co = ngc.alloc(vm_co);
|
||||
nas_co& cort = co.co();
|
||||
cort.ctx.pc = func.func().entry-1;
|
||||
|
||||
cort.ctx.top[0] = nil;
|
||||
cort.ctx.localr = cort.ctx.top+1;
|
||||
cort.ctx.top = cort.ctx.localr+func.func().lsize;
|
||||
cort.ctx.localr[0] = func.func().local[0];
|
||||
cort.ctx.top[0] = nil; // old upvalr
|
||||
cort.ctx.top++;
|
||||
cort.ctx.top[0] = var::addr((var*)nullptr); // old localr
|
||||
cort.ctx.top++;
|
||||
cort.ctx.top[0] = var::ret(0); // old pc, set to zero to make op_ret recognizing this as coroutine function
|
||||
|
||||
cort.ctx.funcr = func; // make sure the coroutine function can use correct upvalues
|
||||
cort.status = nas_co::status::suspended;
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
var builtin_coresume(var* local, gc& ngc) {
|
||||
if (ngc.cort) {
|
||||
return nas_err("coroutine::resume", "cannot start another coroutine when one is running");
|
||||
}
|
||||
var co = local[1];
|
||||
// return nil if is not a coroutine object
|
||||
if (co.type!=vm_co) {
|
||||
return nil;
|
||||
}
|
||||
// cannot resume a dead coroutine
|
||||
if (co.co().status==nas_co::status::dead) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// change to coroutine context
|
||||
ngc.ctxchg(co.co());
|
||||
|
||||
// fetch coroutine's stack top and return
|
||||
// so the coroutine's stack top in fact is not changed
|
||||
if (ngc.rctx->top[0].type==vm_ret) {
|
||||
// when first calling this coroutine, the stack top must be vm_ret
|
||||
return ngc.rctx->top[0];
|
||||
}
|
||||
|
||||
// after first calling the coroutine, each time coroutine.yield triggered
|
||||
// a new space will be reserved on stack with value nil
|
||||
// so we could fill this place with args
|
||||
|
||||
// the coroutine seems like coroutine.yield returns the value
|
||||
// but in fact coroutine.yield stop the coroutine
|
||||
// until main context calls the coroutine.resume
|
||||
return local[2];
|
||||
}
|
||||
|
||||
var builtin_coyield(var* local, gc& ngc) {
|
||||
if (!ngc.cort) {
|
||||
return nas_err("coroutine::yield", "no coroutine is running");
|
||||
}
|
||||
|
||||
// this will set to main stack top
|
||||
ngc.ctxreserve();
|
||||
|
||||
// then this will return value to main's stack top[0]
|
||||
// the procedure seems like coroutine.resume returns the value
|
||||
// but in fact coroutine.resume stop the main context
|
||||
// until coroutine calls the coroutine.yield
|
||||
return local[1];
|
||||
}
|
||||
|
||||
var builtin_costatus(var* local, gc& ngc) {
|
||||
var co = local[1];
|
||||
if (co.type!=vm_co) {
|
||||
return ngc.newstr("error");
|
||||
}
|
||||
switch(co.co().status) {
|
||||
case nas_co::status::suspended: return ngc.newstr("suspended");
|
||||
case nas_co::status::running: return ngc.newstr("running");
|
||||
case nas_co::status::dead: return ngc.newstr("dead");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
var builtin_corun(var* local, gc& ngc) {
|
||||
return ngc.cort? one:zero;
|
||||
}
|
||||
|
||||
var builtin_millisec(var* local, gc& ngc) {
|
||||
f64 res = std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
(std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||
|
@ -1295,11 +1189,6 @@ nasal_builtin_table builtin[] = {
|
|||
{"__platform", builtin_platform},
|
||||
{"__arch", builtin_arch},
|
||||
{"__md5", builtin_md5},
|
||||
{"__cocreate", builtin_cocreate},
|
||||
{"__coresume", builtin_coresume},
|
||||
{"__coyield", builtin_coyield},
|
||||
{"__costatus", builtin_costatus},
|
||||
{"__corun", builtin_corun},
|
||||
{"__millisec", builtin_millisec},
|
||||
{"__gcextd", builtin_gcextend},
|
||||
{"__gcinfo", builtin_gcinfo},
|
||||
|
|
|
@ -109,11 +109,6 @@ var builtin_arch(var*, gc&);
|
|||
std::string tohex(u32);
|
||||
std::string md5(const std::string&);
|
||||
var builtin_md5(var*, gc&);
|
||||
var builtin_cocreate(var*, gc&);
|
||||
var builtin_coresume(var*, gc&);
|
||||
var builtin_coyield(var*, gc&);
|
||||
var builtin_costatus(var*, gc&);
|
||||
var builtin_corun(var*, gc&);
|
||||
var builtin_millisec(var*, gc&);
|
||||
var builtin_gcextend(var*, gc&);
|
||||
var builtin_gcinfo(var*, gc&);
|
||||
|
|
|
@ -15,6 +15,7 @@ void codegen::load_native_function_table(nasal_builtin_table* table) {
|
|||
void codegen::init_native_function() {
|
||||
load_native_function_table(builtin);
|
||||
load_native_function_table(math_lib_native);
|
||||
load_native_function_table(coroutine_native);
|
||||
load_native_function_table(flight_gear_native);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nasal_import.h"
|
||||
|
||||
#include "nasal_builtin.h"
|
||||
#include "coroutine.h"
|
||||
#include "math_lib.h"
|
||||
#include "fg_props.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue