append code size from u32 to u64

This commit is contained in:
ValKmjolnir 2024-05-12 22:33:51 +08:00
parent 8e38764df0
commit 96731d180f
15 changed files with 252 additions and 225 deletions

View File

@ -6,7 +6,7 @@ endif
ifeq ($(OS), Darwin)
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I src
else
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src -Wconversion -Wno-float-conversion
endif
NASAL_HEADER = \

View File

@ -9,9 +9,11 @@
namespace nasal {
class ast_dumper:public ast_visitor {
class ast_dumper: public ast_visitor {
private:
std::vector<std::string> indent;
private:
void push_indent() {
if (indent.size()) {
if (indent.back()=="|--") {

View File

@ -95,7 +95,8 @@ std::ostream& logo(std::ostream& out) {
}
std::ostream& version(std::ostream& out) {
std::srand(std::time(nullptr));
std::srand(static_cast<u16>(std::time(nullptr)));
f64 num = 0;
for(u32 i = 0; i<5; ++i) {
num = (num+rand())*(1.0/(RAND_MAX+1.0));
@ -103,6 +104,7 @@ std::ostream& version(std::ostream& out) {
if (num<0.01) {
nasal::parse::easter_egg();
}
out << "nasal interpreter version " << __nasver__;
out << " " << nasal::get_platform() << " " << nasal::get_arch();
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
@ -181,7 +183,7 @@ void execute(const std::string& file,
const auto end = clk::now();
if (cmd&VM_TIME) {
std::clog << "process exited after ";
std::clog << (end-start).count()*1.0/den << "s.\n\n";
std::clog << static_cast<f64>((end-start).count())/den << "s.\n\n";
}
}

View File

@ -70,7 +70,8 @@ void codegen::regist_number(const f64 num) {
if (const_number_map.count(num)) {
return;
}
u32 size = const_number_map.size();
auto size = const_number_map.size();
const_number_map[num] = size;
const_number_table.push_back(num);
}
@ -79,7 +80,8 @@ void codegen::regist_string(const std::string& str) {
if (const_string_map.count(str)) {
return;
}
u32 size = const_string_map.size();
auto size = const_string_map.size();
const_string_map[str] = size;
const_string_table.push_back(str);
}
@ -107,18 +109,20 @@ void codegen::find_symbol(code_block* node) {
}
void codegen::regist_symbol(const std::string& name) {
// regist global if local scope list is empty
if (local.empty()) {
if (global.count(name)) {
return;
}
i32 index = global.size();
auto index = global.size();
global[name] = index;
return;
}
if (local.back().count(name)) {
return;
}
i32 index = local.back().size();
auto index = local.back().size();
local.back()[name] = index;
}
@ -149,7 +153,7 @@ i32 codegen::upvalue_symbol_find(const std::string& name) {
return index;
}
void codegen::emit(u8 operation_code, u32 immediate_num, const span& location) {
void codegen::emit(u8 operation_code, u64 immediate_num, const span& location) {
code.push_back({
operation_code,
static_cast<u16>(file_map.at(location.file)),
@ -505,7 +509,7 @@ void codegen::single_def(definition_expr* node) {
const auto& str = node->get_variable_name()->get_name();
calc_gen(node->get_value());
// only generate in repl mode and in global scope
if (need_repl_output && local.empty()) {
if (flag_need_repl_output && local.empty()) {
emit(op_repl, 0, node->get_location());
}
if (local.empty()) {
@ -752,16 +756,16 @@ void codegen::multi_assign_gen(multi_assign* node) {
}
}
i32 size = tuple_node->get_elements().size();
i64 size = static_cast<i64>(tuple_node->get_elements().size());
// generate multiple assignment: (a, b, c) = (1, 2, 3);
if (value_node->get_type()==expr_type::ast_tuple) {
const auto& value_tuple = reinterpret_cast<tuple_expr*>(value_node)
->get_elements();
for(i32 i = size-1; i>=0; --i) {
for(i64 i = size-1; i>=0; --i) {
calc_gen(value_tuple[i]);
}
auto& tuple = tuple_node->get_elements();
for(i32 i = 0; i<size; ++i) {
for(i64 i = 0; i<size; ++i) {
mcall(tuple[i]);
// use load operands to avoid meq's pop operand
// and this operation changes local and global value directly
@ -773,13 +777,14 @@ void codegen::multi_assign_gen(multi_assign* node) {
// generate multiple assignment: (a, b, c) = [1, 2, 3];
calc_gen(value_node);
auto& tuple = tuple_node->get_elements();
for(i32 i = 0; i<size; ++i) {
for(i64 i = 0; i<size; ++i) {
emit(op_callvi, i, value_node->get_location());
mcall(tuple[i]);
// use load operands to avoid meq's pop operand
// and this operation changes local and global value directly
replace_left_assignment_with_load(tuple[i]->get_location());
}
// pop source vector
emit(op_pop, 0, node->get_location());
}
@ -834,7 +839,7 @@ void codegen::loop_gen(expr* node) {
}
}
void codegen::load_continue_break(i32 continue_place, i32 break_place) {
void codegen::load_continue_break(u64 continue_place, u64 break_place) {
for(auto i : continue_ptr.front()) {
code[i].num = continue_place;
}
@ -943,7 +948,7 @@ void codegen::statement_generation(expr* node) {
case expr_type::ast_ternary:
calc_gen(node);
// only generate in repl mode and in global scope
if (need_repl_output && local.empty()) {
if (flag_need_repl_output && local.empty()) {
emit(op_repl, 0, node->get_location());
}
emit(op_pop, 0, node->get_location());
@ -1254,7 +1259,7 @@ void codegen::block_gen(code_block* node) {
break;
case expr_type::ast_null: break;
case expr_type::ast_id:
if (need_repl_output && local.empty()) {
if (flag_need_repl_output && local.empty()) {
repl_mode_info_output_gen(tmp);
} else {
check_id_exist(reinterpret_cast<identifier*>(tmp));
@ -1264,7 +1269,7 @@ void codegen::block_gen(code_block* node) {
case expr_type::ast_num:
case expr_type::ast_str:
case expr_type::ast_bool:
if (need_repl_output && local.empty()) {
if (flag_need_repl_output && local.empty()) {
repl_mode_info_output_gen(tmp);
}
break;
@ -1313,7 +1318,7 @@ const error& codegen::compile(parse& parse,
linker& import,
bool repl_flag,
bool limit_mode) {
need_repl_output = repl_flag;
flag_need_repl_output = repl_flag;
flag_limited_mode = limit_mode;
init_native_function();
init_file_map(import.get_file_list());
@ -1334,13 +1339,13 @@ const error& codegen::compile(parse& parse,
emit(op_exit, 0, parse.tree()->get_location());
// size out of bound check
if (const_number_table.size()>0xffffff) {
if (const_number_table.size()>INT64_MAX) {
err.err("code",
"too many constant numbers: " +
std::to_string(const_number_table.size())
);
}
if (const_string_table.size()>0xffffff) {
if (const_string_table.size()>INT64_MAX) {
err.err("code",
"too many constant strings: " +
std::to_string(const_string_table.size())
@ -1356,7 +1361,7 @@ const error& codegen::compile(parse& parse,
}
// check generated code size
if (code.size()>0xffffff) {
if (code.size()>INT64_MAX) {
err.err("code",
"bytecode size overflow: " +
std::to_string(code.size())
@ -1367,8 +1372,8 @@ const error& codegen::compile(parse& parse,
void codegen::print(std::ostream& out) {
// func end stack, reserved for code print
std::stack<u32> func_begin_stack;
std::stack<u32> func_end_stack;
std::stack<u64> func_begin_stack;
std::stack<u64> func_end_stack;
// print const numbers
for(auto num : const_number_table) {
@ -1391,7 +1396,8 @@ void codegen::print(std::ostream& out) {
const_string_table.data(),
native_function.data()
);
for(u32 i = 0; i<code.size(); ++i) {
for(u64 i = 0; i<code.size(); ++i) {
// print opcode index, opcode name, opcode immediate number
const auto& c = code[i];
if (!func_end_stack.empty() && i==func_end_stack.top()) {
@ -1407,7 +1413,7 @@ void codegen::print(std::ostream& out) {
// get function begin index and end index
if (c.op==op_newf) {
out << std::hex << "\nfunc <0x" << i << std::dec << ">:\n";
for(u32 j = i; j<code.size(); ++j) {
for(u64 j = i; j<code.size(); ++j) {
if (code[j].op==op_jmp) {
func_begin_stack.push(i);
func_end_stack.push(code[j].num);

View File

@ -37,10 +37,11 @@ private:
error err;
// repl output flag, will generate op_repl to output stack top value if true
bool need_repl_output = false;
bool flag_need_repl_output = false;
// limit mode flag
bool flag_limited_mode = false;
// under limited mode, unsafe system api will be banned
const std::unordered_set<std::string> unsafe_system_api = {
// builtin
@ -67,8 +68,8 @@ private:
std::vector<u32> in_foreach_loop_level;
// constant numbers and strings
std::unordered_map<f64, u32> const_number_map;
std::unordered_map<std::string, u32> const_string_map;
std::unordered_map<f64, u64> const_number_map;
std::unordered_map<std::string, u64> const_string_map;
std::vector<f64> const_number_table;
std::vector<std::string> const_string_table;
@ -82,17 +83,17 @@ private:
std::vector<opcode> code;
// used to store jmp operands index, to fill the jump address back
std::list<std::vector<i32>> continue_ptr;
std::list<std::vector<i32>> break_ptr;
std::list<std::vector<u64>> continue_ptr;
std::list<std::vector<u64>> break_ptr;
// symbol table
// global : max STACK_DEPTH-1 values
std::unordered_map<std::string, i32> global;
std::unordered_map<std::string, u64> global;
std::unordered_map<std::string, std::unordered_set<std::string>> experimental_namespace;
// local : max 32768 upvalues 65536 values
// but in fact local scope also has less than STACK_DEPTH value
std::list<std::unordered_map<std::string, i32>> local;
std::list<std::unordered_map<std::string, u64>> local;
void check_id_exist(identifier*);
@ -108,7 +109,7 @@ private:
i32 global_symbol_find(const std::string&);
i32 upvalue_symbol_find(const std::string&);
void emit(u8, u32, const span&);
void emit(u8, u64, const span&);
void number_gen(number_literal*);
void string_gen(string_literal*);
@ -135,7 +136,7 @@ private:
void multi_assign_gen(multi_assign*);
void cond_gen(condition_expr*);
void loop_gen(expr*);
void load_continue_break(i32, i32);
void load_continue_break(u64, u64);
void while_gen(while_expr*);
void for_gen(for_expr*);
void forei_gen(forei_expr*);

View File

@ -147,12 +147,14 @@ void dbg::list_file() const {
}
void dbg::step_info() {
u32 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1;
u32 begin = (line>>3)==0? 0:((line>>3)<<3);
u32 end = (1+(line>>3))<<3;
u64 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1;
u64 begin = (line>>3)==0? 0:((line>>3)<<3);
u64 end = (1+(line>>3))<<3;
src.load(files[bytecode[ctx.pc].fidx]);
std::clog << "\nsource code:\n";
for(u32 i = begin; i<end && i<src.size(); ++i) {
for(u64 i = begin; i<end && i<src.size(); ++i) {
std::clog << (i==line? back_white:reset);
std::clog << (i==line? "--> ":" ") << src[i] << reset << "\n";
}
@ -160,8 +162,9 @@ void dbg::step_info() {
begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3);
end = (1+(ctx.pc>>3))<<3;
codestream::set(const_number, const_string, native_function.data(), files);
std::clog << "\nnext bytecode:\n";
for(u32 i = begin; i<end && bytecode[i].op!=op_exit; ++i) {
for(u64 i = begin; i<end && bytecode[i].op!=op_exit; ++i) {
std::clog
<< (i==ctx.pc? back_white:reset)
<< (i==ctx.pc? "--> ":" ")
@ -234,19 +237,18 @@ void dbg::interact() {
}
}
void dbg::run(
const codegen& gen,
const linker& linker,
const std::vector<std::string>& argv,
bool profile,
bool show_all_prof_result) {
void dbg::run(const codegen& gen,
const linker& linker,
const std::vector<std::string>& argv,
bool profile,
bool show_all_prof_result) {
set_detail_report_info(true);
do_operand_count = profile || show_all_prof_result;
const auto& file_list = linker.get_file_list();
fsize = file_list.size();
init(
vm_init_enrty(
gen.strs(),
gen.nums(),
gen.natives(),
@ -257,9 +259,9 @@ void dbg::run(
);
counter.init(file_list);
std::vector<u32> code;
std::vector<u8> code;
std::vector<u16> code_file_index;
std::vector<u32> code_line;
std::vector<u64> code_line;
for(const auto& i : gen.codes()) {
code.push_back(i.op);
code_file_index.push_back(i.fidx);

View File

@ -189,7 +189,7 @@ void gc::extend(const vm_type type) {
const u8 index = static_cast<u8>(type)-static_cast<u8>(vm_type::vm_str);
size[index] += incr[index];
for(u32 i = 0; i<incr[index]; ++i) {
for(u64 i = 0; i<incr[index]; ++i) {
// no need to check, will be killed if memory is not enough
nas_val* tmp = new nas_val(type);
@ -197,14 +197,13 @@ void gc::extend(const vm_type type) {
memory.push_back(tmp);
unused[index].push_back(tmp);
}
// if incr[index] = 1, this will always be 1
incr[index] = incr[index]+incr[index]/2;
}
void gc::init(
const std::vector<std::string>& constant_strings,
const std::vector<std::string>& argv
) {
void gc::init(const std::vector<std::string>& constant_strings,
const std::vector<std::string>& argv) {
// initialize counters
worktime = 0;
for(u8 i = 0; i<gc_type_size; ++i) {
@ -216,7 +215,7 @@ void gc::init(
// init constant strings
strs.resize(constant_strings.size());
for(u32 i = 0; i<strs.size(); ++i) {
for(u64 i = 0; i<strs.size(); ++i) {
// incremental initialization, avoid memory leak in repl mode
if (strs[i].is_str() && strs[i].str()==constant_strings[i]) {
continue;
@ -228,7 +227,7 @@ void gc::init(
// record arguments
env_argv.resize(argv.size());
for(usize i = 0; i<argv.size(); ++i) {
for(u64 i = 0; i<argv.size(); ++i) {
// incremental initialization, avoid memory leak in repl mode
if (env_argv[i].is_str() && env_argv[i].str()==argv[i]) {
continue;
@ -315,7 +314,7 @@ void gc::info() const {
if (!gcnt[i] && !acnt[i] && !size[i]) {
continue;
}
total += gcnt[i];
total += static_cast<f64>(gcnt[i]);
std::clog << " " << left << setw(indent) << setfill(' ') << name[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << acnt[i];

View File

@ -41,7 +41,7 @@ struct gc {
std::vector<nas_val*> unused[gc_type_size]; // gc free list
/* heap increase size */
u32 incr[gc_type_size] = {
u64 incr[gc_type_size] = {
128, // vm_str
128, // vm_vec
64, // vm_hash

View File

@ -27,11 +27,10 @@ const char* opname[] = {
"mcallv", "mcallh", "ret "
};
void codestream::set(
const f64* number_list,
const std::string* string_list,
const nasal_builtin_table* native_table,
const std::string* file_list) {
void codestream::set(const f64* number_list,
const std::string* string_list,
const nasal_builtin_table* native_table,
const std::string* file_list) {
const_number = number_list;
const_string = string_list;
natives = native_table;
@ -110,6 +109,8 @@ void codestream::dump(std::ostream& out) const {
}
break;
}
// if file list is loaded, dump file location info
if (files) {
out << " (" << files[code.fidx] << ":" << code.line << ")";
}

View File

@ -8,99 +8,99 @@
namespace nasal {
enum op_code_type: u8 {
op_exit, // stop the virtual machine
op_repl, // in repl mode: print value on stack top
op_intl, // local scope size
op_loadg, // load global value
op_loadl, // load local value
op_loadu, // load upvalue
op_pnum, // push constant number to the stack
op_pnil, // push constant nil to the stack
op_pstr, // push constant std::string to the stack
op_newv, // push new vector with initial values from stack
op_newh, // push new hash to the stack
op_newf, // push new function to the stack
op_happ, // hash append
op_para, // normal parameter
op_deft, // default parameter
op_dyn, // dynamic parameter
op_lnot, // ! logical negation
op_usub, // - negation
op_bnot, // ~ bitwise not static_cast<i32>
op_btor, // | bitwise or
op_btxor, // ^ bitwise xor
op_btand, // & bitwise and
op_add, // +
op_sub, // -
op_mul, // *
op_div, // /
op_lnk, // ~
op_addc, // + const
op_subc, // - const
op_mulc, // * const
op_divc, // / const
op_lnkc, // ~ const
op_addeq, // += maybe pop stack top
op_subeq, // -= maybe pop stack top
op_muleq, // *= maybe pop stack top
op_diveq, // /= maybe pop stack top
op_lnkeq, // ~= maybe pop stack top
op_btandeq,// &= maybe pop stack top
op_btoreq, // |= maybe pop stack top
op_btxoreq,// ^= maybe pop stack top
op_addeqc, // += const don't pop stack top
op_subeqc, // -= const don't pop stack top
op_muleqc, // *= const don't pop stack top
op_diveqc, // /= const don't pop stack top
op_lnkeqc, // ~= const don't pop stack top
op_addecp, // += const and pop stack top
op_subecp, // -= const and pop stack top
op_mulecp, // *= const and pop stack top
op_divecp, // /= const and pop stack top
op_lnkecp, // ~= concat const std::string and pop stack top
op_meq, // = maybe pop stack top
op_eq, // == compare operator
op_neq, // != compare operator
op_less, // < compare operator
op_leq, // <= compare operator
op_grt, // > compare operator
op_geq, // >= compare operator
op_lessc, // < const compare operator
op_leqc, // <= const compare operator
op_grtc, // > const compare operator
op_geqc, // >= const compare operator
op_pop, // pop a value out of stack top
op_jmp, // jump absolute address with no condition
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP
op_jf, // used in conditional/loop,jmp when condition is false and POP STACK
op_cnt, // add counter for forindex/foreach
op_findex, // index counter on the top of forindex_stack plus 1
op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector
op_callg, // get value in global scope
op_calll, // get value in local scope
op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local
op_callv, // call vec[index]
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
op_callh, // call hash.label
op_callfv, // call function(vector as parameters)
op_callfh, // call function(hash as parameters)
op_callb, // call native functions
op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1]
op_slcend, // end of slice
op_slc, // slice like vec[1]
op_slc2, // slice like vec[nil:10]
op_mcallg, // get memory space of value in global scope
op_mcalll, // get memory space of value in local scope
op_mupval, // get memory space of value in closure
op_mcallv, // get memory space of vec[index]
op_mcallh, // get memory space of hash.label
op_ret // return
op_exit, // stop the virtual machine
op_repl, // in repl mode: print value on stack top
op_intl, // local scope size
op_loadg, // load global value
op_loadl, // load local value
op_loadu, // load upvalue
op_pnum, // push constant number to the stack
op_pnil, // push constant nil to the stack
op_pstr, // push constant std::string to the stack
op_newv, // push new vector with initial values from stack
op_newh, // push new hash to the stack
op_newf, // push new function to the stack
op_happ, // hash append
op_para, // normal parameter
op_deft, // default parameter
op_dyn, // dynamic parameter
op_lnot, // ! logical negation
op_usub, // - negation
op_bnot, // ~ bitwise not static_cast<i32>
op_btor, // | bitwise or
op_btxor, // ^ bitwise xor
op_btand, // & bitwise and
op_add, // +
op_sub, // -
op_mul, // *
op_div, // /
op_lnk, // ~
op_addc, // + const
op_subc, // - const
op_mulc, // * const
op_divc, // / const
op_lnkc, // ~ const
op_addeq, // += maybe pop stack top
op_subeq, // -= maybe pop stack top
op_muleq, // *= maybe pop stack top
op_diveq, // /= maybe pop stack top
op_lnkeq, // ~= maybe pop stack top
op_btandeq, // &= maybe pop stack top
op_btoreq, // |= maybe pop stack top
op_btxoreq, // ^= maybe pop stack top
op_addeqc, // += const don't pop stack top
op_subeqc, // -= const don't pop stack top
op_muleqc, // *= const don't pop stack top
op_diveqc, // /= const don't pop stack top
op_lnkeqc, // ~= const don't pop stack top
op_addecp, // += const and pop stack top
op_subecp, // -= const and pop stack top
op_mulecp, // *= const and pop stack top
op_divecp, // /= const and pop stack top
op_lnkecp, // ~= concat const std::string and pop stack top
op_meq, // = maybe pop stack top
op_eq, // == compare operator
op_neq, // != compare operator
op_less, // < compare operator
op_leq, // <= compare operator
op_grt, // > compare operator
op_geq, // >= compare operator
op_lessc, // < const compare operator
op_leqc, // <= const compare operator
op_grtc, // > const compare operator
op_geqc, // >= const compare operator
op_pop, // pop a value out of stack top
op_jmp, // jump absolute address with no condition
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP
op_jf, // used in conditional/loop,jmp when condition is false and POP STACK
op_cnt, // add counter for forindex/foreach
op_findex, // index counter on the top of forindex_stack plus 1
op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector
op_callg, // get value in global scope
op_calll, // get value in local scope
op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local
op_callv, // call vec[index]
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
op_callh, // call hash.label
op_callfv, // call function(vector as parameters)
op_callfh, // call function(hash as parameters)
op_callb, // call native functions
op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1]
op_slcend, // end of slice
op_slc, // slice like vec[1]
op_slc2, // slice like vec[nil:10]
op_mcallg, // get memory space of value in global scope
op_mcalll, // get memory space of value in local scope
op_mupval, // get memory space of value in closure
op_mcallv, // get memory space of vec[index]
op_mcallh, // get memory space of hash.label
op_ret // return
};
struct opcode {
u8 op; // opcode
u16 fidx; // source code file index
u32 num; // immediate num
u64 num; // immediate num
u64 line; // location line of source code
opcode() = default;
opcode(const opcode&) = default;
@ -110,19 +110,18 @@ struct opcode {
class codestream {
private:
opcode code;
const u32 index;
const u64 index;
inline static const f64* const_number = nullptr;
inline static const std::string* const_string = nullptr;
inline static const nasal_builtin_table* natives = nullptr;
inline static const std::string* files = nullptr;
public:
codestream(const opcode& c, const u32 i): code(c), index(i) {}
static void set(
const f64*, const std::string*,
const nasal_builtin_table*,
const std::string* file_list = nullptr
);
codestream(const opcode& c, const u64 i): code(c), index(i) {}
static void set(const f64*,
const std::string*,
const nasal_builtin_table*,
const std::string* file_list = nullptr);
void dump(std::ostream&) const;
};

View File

@ -279,14 +279,14 @@ bool var::object_check(const std::string& name) {
}
var var::none() {
return {vm_type::vm_none, static_cast<u32>(0)};
return {vm_type::vm_none, static_cast<u64>(0)};
}
var var::nil() {
return {vm_type::vm_nil, static_cast<u32>(0)};
return {vm_type::vm_nil, static_cast<u64>(0)};
}
var var::ret(u32 pc) {
var var::ret(u64 pc) {
return {vm_type::vm_ret, pc};
}
@ -310,7 +310,7 @@ var* var::addr() {
return val.addr;
}
u32 var::ret() const {
u64 var::ret() const {
return val.ret;
}

View File

@ -49,7 +49,7 @@ struct var {
public:
vm_type type = vm_type::vm_none;
union {
u32 ret;
u64 ret;
i64 cnt;
f64 num;
var* addr;
@ -57,7 +57,7 @@ public:
} val;
private:
var(vm_type t, u32 pc) {type = t; val.ret = pc;}
var(vm_type t, u64 pc) {type = t; val.ret = pc;}
var(vm_type t, i64 ct) {type = t; val.cnt = ct;}
var(vm_type t, f64 n) {type = t; val.num = n;}
var(vm_type t, var* p) {type = t; val.addr = p;}
@ -82,7 +82,7 @@ public:
// create new var object
static var none();
static var nil();
static var ret(u32);
static var ret(u64);
static var cnt(i64);
static var num(f64);
static var gcobj(nas_val*);
@ -91,7 +91,7 @@ public:
public:
// get value
var* addr();
u32 ret() const;
u64 ret() const;
i64& cnt();
f64 num() const;
std::string& str();
@ -143,10 +143,10 @@ struct nas_hash {
};
struct nas_func {
i32 dynamic_parameter_index; // dynamic parameter name index in hash.
u32 entry; // pc will set to entry-1 to call this function
i64 dynamic_parameter_index; // dynamic parameter name index in hash.
u64 entry; // pc will set to entry-1 to call this function
u32 parameter_size; // used to load default parameters to a new function
u32 local_size; // used to expand memory space for local values on stack
u64 local_size; // used to expand memory space for local values on stack
std::vector<var> local; // local scope with default value(var)
std::vector<var> upval; // closure
@ -163,7 +163,7 @@ struct nas_upval {
public:
/* on stack, use these variables */
bool on_stack;
u32 size;
u64 size;
var* stack_frame_offset;
/* not on stack, use this */
@ -207,7 +207,7 @@ public:
};
struct context {
u32 pc = 0;
u64 pc = 0;
var* localr = nullptr;
var* memr = nullptr;
var funcr = var::nil();

View File

@ -2,15 +2,13 @@
namespace nasal {
void vm::init(
const std::vector<std::string>& strs,
const std::vector<f64>& nums,
const std::vector<nasal_builtin_table>& natives,
const std::vector<opcode>& code,
const std::unordered_map<std::string, i32>& global_symbol,
const std::vector<std::string>& filenames,
const std::vector<std::string>& argv
) {
void vm::vm_init_enrty(const std::vector<std::string>& strs,
const std::vector<f64>& nums,
const std::vector<nasal_builtin_table>& natives,
const std::vector<opcode>& code,
const std::unordered_map<std::string, u64>& global_symbol,
const std::vector<std::string>& filenames,
const std::vector<std::string>& argv) {
const_number = nums.data();
const_string = strs.data();
bytecode = code.data();
@ -411,11 +409,10 @@ void vm::die(const std::string& str) {
}
}
void vm::run(
const codegen& gen,
const linker& linker,
const std::vector<std::string>& argv) {
init(
void vm::run(const codegen& gen,
const linker& linker,
const std::vector<std::string>& argv) {
vm_init_enrty(
gen.strs(),
gen.nums(),
gen.natives(),
@ -424,6 +421,7 @@ void vm::run(
linker.get_file_list(),
argv
);
#ifndef _MSC_VER
// using labels as values/computed goto
const void* oprs[] = {

View File

@ -26,7 +26,7 @@ protected:
/* constants */
const f64* const_number = nullptr; // constant numbers
const std::string* const_string = nullptr; // constant symbols and strings
std::vector<u32> imm; // immediate number table
std::vector<u64> imm; // immediate number table
std::vector<nasal_builtin_table> native_function;
/* garbage collector */
@ -49,15 +49,13 @@ protected:
bool flag_limited_mode = false;
/* vm initializing function */
void init(
const std::vector<std::string>&,
const std::vector<f64>&,
const std::vector<nasal_builtin_table>&,
const std::vector<opcode>&,
const std::unordered_map<std::string, i32>&,
const std::vector<std::string>&,
const std::vector<std::string>&
);
void vm_init_enrty(const std::vector<std::string>&,
const std::vector<f64>&,
const std::vector<nasal_builtin_table>&,
const std::vector<opcode>&,
const std::unordered_map<std::string, u64>&,
const std::vector<std::string>&,
const std::vector<std::string>&);
void context_and_global_init();
/* debug functions */
@ -183,11 +181,9 @@ public:
}
/* execution entry */
void run(
const codegen&, // get generated code
const linker&, // get list of used files
const std::vector<std::string>& // get arguments input by command line
);
void run(const codegen&, // get generated code
const linker&, // get list of used files
const std::vector<std::string>&); // get command line arguments
/* set detail report info flag */
void set_detail_report_info(bool flag) {verbose = flag;}
@ -700,7 +696,7 @@ inline void vm::o_callh() {
}
inline void vm::o_callfv() {
const u32 argc = imm[ctx.pc]; // arguments counter
const auto argc = imm[ctx.pc]; // arguments counter
var* local = ctx.top-argc+1; // arguments begin address
if (!local[-1].is_func()) {
die("must call a function but get "+type_name_string(local[-1]));
@ -719,7 +715,7 @@ inline void vm::o_callfv() {
return;
}
// parameter size is func->psize-1, 1 is reserved for "me"
const u32 parameter_size = func.parameter_size-1;
const u64 parameter_size = func.parameter_size-1;
if (argc<parameter_size && func.local[argc+1].is_none()) {
die(report_lack_arguments(argc, func));
return;
@ -730,16 +726,17 @@ inline void vm::o_callfv() {
if (func.dynamic_parameter_index>=0) {
// load dynamic argument
dynamic = ngc.alloc(vm_type::vm_vec);
for(u32 i = parameter_size; i<argc; ++i) {
for(u64 i = parameter_size; i<argc; ++i) {
dynamic.vec().elems.push_back(local[i]);
}
} else if (parameter_size<argc) {
// load arguments to default dynamic argument "arg", located at stack+1
dynamic = ngc.alloc(vm_type::vm_vec);
for(u32 i = parameter_size; i<argc; ++i) {
for(u64 i = parameter_size; i<argc; ++i) {
dynamic.vec().elems.push_back(local[i]);
}
}
// should reset stack top after allocating vector
// because this may cause gc
// then all the available values the vector needs
@ -747,14 +744,18 @@ inline void vm::o_callfv() {
// collected incorrectly
ctx.top = local+func.local_size;
const u32 min_size = (std::min)(parameter_size, argc); // avoid error in MSVC
for(u32 i = min_size; i>=1; --i) { // load arguments
// use (std::min) to avoid compilation error in MSVC
// MSVC windows.h uses macro std::min
const u64 min_size = (std::min)(parameter_size, argc);
// load arguments
for(u64 i = min_size; i>=1; --i) {
local[i] = local[i-1];
}
local[0] = func.local[0];// load "me"
local[0] = func.local[0]; // load "me"
// load local scope & default arguments
for(u32 i = min_size+1; i<func.local_size; ++i) {
for(u64 i = min_size+1; i<func.local_size; ++i) {
local[i] = func.local[i];
}
// load dynamic argument

View File

@ -204,16 +204,17 @@ var builtin_str(context* ctx, gc* ngc) {
var builtin_size(context* ctx, gc* ngc) {
auto val = ctx->localr[1];
f64 num = 0;
usize num = 0;
switch(val.type) {
case vm_type::vm_num: num = val.num(); break;
case vm_type::vm_num: return val;
case vm_type::vm_str: num = val.str().length(); break;
case vm_type::vm_vec: num = val.vec().size(); break;
case vm_type::vm_hash: num = val.hash().size(); break;
case vm_type::vm_map: num = val.map().mapper.size(); break;
default: break;
}
return var::num(num);
return var::num(static_cast<f64>(num));
}
var builtin_time(context* ctx, gc* ngc) {
@ -569,12 +570,12 @@ public:
stamp = std::chrono::high_resolution_clock::now();
}
f64 elapsed_milliseconds() {
auto elapsed_milliseconds() const {
const auto duration = std::chrono::high_resolution_clock::now() - stamp;
return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
}
f64 elapsed_microseconds() {
auto elapsed_microseconds() const {
const auto duration = std::chrono::high_resolution_clock::now() - stamp;
return std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
}
@ -611,7 +612,7 @@ var builtin_elapsed_millisecond(context* ctx, gc* ngc) {
return var::num(-1);
}
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
return var::num(stamp->elapsed_milliseconds());
return var::num(static_cast<f64>(stamp->elapsed_milliseconds()));
}
var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
@ -620,7 +621,7 @@ var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
return var::num(-1);
}
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
return var::num(stamp->elapsed_microseconds());
return var::num(static_cast<f64>(stamp->elapsed_microseconds()));
}
var builtin_gcextend(context* ctx, gc* ngc) {
@ -648,20 +649,27 @@ var builtin_gcextend(context* ctx, gc* ngc) {
}
var builtin_gcinfo(context* ctx, gc* ngc) {
auto den = std::chrono::high_resolution_clock::duration::period::den;
const auto den = std::chrono::high_resolution_clock::duration::period::den;
var res = ngc->alloc(vm_type::vm_hash);
double total = 0;
f64 total = 0;
for(u32 i = 0; i<gc_type_size; ++i) {
total += ngc->gcnt[i];
total += static_cast<f64>(ngc->gcnt[i]);
}
// using ms
auto& map = res.hash().elems;
map["total"] = var::num(ngc->worktime*1.0/den*1000);
map["average"] = var::num(ngc->worktime*1.0/den*1000/total);
map["max_gc"] = var::num(ngc->max_time*1.0/den*1000);
map["max_mark"] = var::num(ngc->max_mark_time*1.0/den*1000);
map["max_sweep"] = var::num(ngc->max_sweep_time*1.0/den*1000);
const auto worktime = static_cast<f64>(ngc->worktime);
const auto max_time = static_cast<f64>(ngc->max_time);
const auto max_mark_time = static_cast<f64>(ngc->max_mark_time);
const auto max_sweep_time = static_cast<f64>(ngc->max_sweep_time);
// using ms
map["total"] = var::num(worktime/den*1000);
map["average"] = var::num(worktime/den*1000/total);
map["max_gc"] = var::num(max_time/den*1000);
map["max_mark"] = var::num(max_mark_time/den*1000);
map["max_sweep"] = var::num(max_sweep_time/den*1000);
return res;
}
@ -686,9 +694,17 @@ var builtin_ghosttype(context* ctx, gc* ngc) {
if (!arg.is_ghost()) {
return nas_err("ghosttype", "this is not a ghost object.");
}
const auto& name = arg.ghost().get_ghost_name();
// https://wiki.flightgear.org/Nasal_library#ghosttype()
// tolds us if no name has been set,
// return a unique id (the pointer to the instance)
if (!name.length()) {
return var::num(reinterpret_cast<u64>(arg.ghost().pointer));
std::stringstream ss;
ss << "0x" << std::hex;
ss << reinterpret_cast<u64>(arg.ghost().pointer) << std::dec;
return ngc->newstr(ss.str());
}
return ngc->newstr(name);
}