⚡ 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/ast_visitor.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_builtin.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/fg_props.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/math_lib.cpp
|
${CMAKE_SOURCE_DIR}/src/math_lib.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
||||||
|
|
10
makefile
10
makefile
|
@ -18,7 +18,8 @@ NASAL_HEADER=\
|
||||||
src/optimizer.h\
|
src/optimizer.h\
|
||||||
src/symbol_finder.h\
|
src/symbol_finder.h\
|
||||||
src/fg_props.h\
|
src/fg_props.h\
|
||||||
src/math_lib.h
|
src/math_lib.h\
|
||||||
|
src/coroutine.h
|
||||||
|
|
||||||
NASAL_OBJECT=\
|
NASAL_OBJECT=\
|
||||||
build/nasal_err.o\
|
build/nasal_err.o\
|
||||||
|
@ -37,6 +38,7 @@ NASAL_OBJECT=\
|
||||||
build/nasal_builtin.o\
|
build/nasal_builtin.o\
|
||||||
build/fg_props.o\
|
build/fg_props.o\
|
||||||
build/math_lib.o\
|
build/math_lib.o\
|
||||||
|
build/coroutine.o\
|
||||||
build/nasal_vm.o\
|
build/nasal_vm.o\
|
||||||
build/nasal_dbg.o\
|
build/nasal_dbg.o\
|
||||||
build/main.o
|
build/main.o
|
||||||
|
@ -89,6 +91,12 @@ build/nasal_builtin.o: \
|
||||||
src/nasal_builtin.h src/nasal_builtin.cpp | build
|
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 .
|
$(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: \
|
build/math_lib.o: \
|
||||||
src/nasal.h\
|
src/nasal.h\
|
||||||
src/nasal_gc.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()));
|
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) {
|
var builtin_millisec(var* local, gc& ngc) {
|
||||||
f64 res = std::chrono::duration_cast<std::chrono::milliseconds>
|
f64 res = std::chrono::duration_cast<std::chrono::milliseconds>
|
||||||
(std::chrono::high_resolution_clock::now().time_since_epoch())
|
(std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||||
|
@ -1295,11 +1189,6 @@ nasal_builtin_table builtin[] = {
|
||||||
{"__platform", builtin_platform},
|
{"__platform", builtin_platform},
|
||||||
{"__arch", builtin_arch},
|
{"__arch", builtin_arch},
|
||||||
{"__md5", builtin_md5},
|
{"__md5", builtin_md5},
|
||||||
{"__cocreate", builtin_cocreate},
|
|
||||||
{"__coresume", builtin_coresume},
|
|
||||||
{"__coyield", builtin_coyield},
|
|
||||||
{"__costatus", builtin_costatus},
|
|
||||||
{"__corun", builtin_corun},
|
|
||||||
{"__millisec", builtin_millisec},
|
{"__millisec", builtin_millisec},
|
||||||
{"__gcextd", builtin_gcextend},
|
{"__gcextd", builtin_gcextend},
|
||||||
{"__gcinfo", builtin_gcinfo},
|
{"__gcinfo", builtin_gcinfo},
|
||||||
|
|
|
@ -109,11 +109,6 @@ var builtin_arch(var*, gc&);
|
||||||
std::string tohex(u32);
|
std::string tohex(u32);
|
||||||
std::string md5(const std::string&);
|
std::string md5(const std::string&);
|
||||||
var builtin_md5(var*, gc&);
|
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_millisec(var*, gc&);
|
||||||
var builtin_gcextend(var*, gc&);
|
var builtin_gcextend(var*, gc&);
|
||||||
var builtin_gcinfo(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() {
|
void codegen::init_native_function() {
|
||||||
load_native_function_table(builtin);
|
load_native_function_table(builtin);
|
||||||
load_native_function_table(math_lib_native);
|
load_native_function_table(math_lib_native);
|
||||||
|
load_native_function_table(coroutine_native);
|
||||||
load_native_function_table(flight_gear_native);
|
load_native_function_table(flight_gear_native);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "nasal_import.h"
|
#include "nasal_import.h"
|
||||||
|
|
||||||
#include "nasal_builtin.h"
|
#include "nasal_builtin.h"
|
||||||
|
#include "coroutine.h"
|
||||||
#include "math_lib.h"
|
#include "math_lib.h"
|
||||||
#include "fg_props.h"
|
#include "fg_props.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue