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) ifeq ($(OS), Darwin)
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I src CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I src
else else
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src -Wconversion -Wno-float-conversion
endif endif
NASAL_HEADER = \ NASAL_HEADER = \

View File

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

View File

@ -95,7 +95,8 @@ std::ostream& logo(std::ostream& out) {
} }
std::ostream& version(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; f64 num = 0;
for(u32 i = 0; i<5; ++i) { for(u32 i = 0; i<5; ++i) {
num = (num+rand())*(1.0/(RAND_MAX+1.0)); num = (num+rand())*(1.0/(RAND_MAX+1.0));
@ -103,6 +104,7 @@ std::ostream& version(std::ostream& out) {
if (num<0.01) { if (num<0.01) {
nasal::parse::easter_egg(); nasal::parse::easter_egg();
} }
out << "nasal interpreter version " << __nasver__; out << "nasal interpreter version " << __nasver__;
out << " " << nasal::get_platform() << " " << nasal::get_arch(); out << " " << nasal::get_platform() << " " << nasal::get_arch();
out << " (" << __DATE__ << " " << __TIME__ << ")\n"; out << " (" << __DATE__ << " " << __TIME__ << ")\n";
@ -181,7 +183,7 @@ void execute(const std::string& file,
const auto end = clk::now(); const auto end = clk::now();
if (cmd&VM_TIME) { if (cmd&VM_TIME) {
std::clog << "process exited after "; 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)) { if (const_number_map.count(num)) {
return; return;
} }
u32 size = const_number_map.size();
auto size = const_number_map.size();
const_number_map[num] = size; const_number_map[num] = size;
const_number_table.push_back(num); const_number_table.push_back(num);
} }
@ -79,7 +80,8 @@ void codegen::regist_string(const std::string& str) {
if (const_string_map.count(str)) { if (const_string_map.count(str)) {
return; return;
} }
u32 size = const_string_map.size();
auto size = const_string_map.size();
const_string_map[str] = size; const_string_map[str] = size;
const_string_table.push_back(str); 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) { void codegen::regist_symbol(const std::string& name) {
// regist global if local scope list is empty
if (local.empty()) { if (local.empty()) {
if (global.count(name)) { if (global.count(name)) {
return; return;
} }
i32 index = global.size(); auto index = global.size();
global[name] = index; global[name] = index;
return; return;
} }
if (local.back().count(name)) { if (local.back().count(name)) {
return; return;
} }
i32 index = local.back().size(); auto index = local.back().size();
local.back()[name] = index; local.back()[name] = index;
} }
@ -149,7 +153,7 @@ i32 codegen::upvalue_symbol_find(const std::string& name) {
return index; 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({ code.push_back({
operation_code, operation_code,
static_cast<u16>(file_map.at(location.file)), 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(); const auto& str = node->get_variable_name()->get_name();
calc_gen(node->get_value()); calc_gen(node->get_value());
// only generate in repl mode and in global scope // 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_repl, 0, node->get_location());
} }
if (local.empty()) { 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); // generate multiple assignment: (a, b, c) = (1, 2, 3);
if (value_node->get_type()==expr_type::ast_tuple) { if (value_node->get_type()==expr_type::ast_tuple) {
const auto& value_tuple = reinterpret_cast<tuple_expr*>(value_node) const auto& value_tuple = reinterpret_cast<tuple_expr*>(value_node)
->get_elements(); ->get_elements();
for(i32 i = size-1; i>=0; --i) { for(i64 i = size-1; i>=0; --i) {
calc_gen(value_tuple[i]); calc_gen(value_tuple[i]);
} }
auto& tuple = tuple_node->get_elements(); auto& tuple = tuple_node->get_elements();
for(i32 i = 0; i<size; ++i) { for(i64 i = 0; i<size; ++i) {
mcall(tuple[i]); mcall(tuple[i]);
// use load operands to avoid meq's pop operand // use load operands to avoid meq's pop operand
// and this operation changes local and global value directly // 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]; // generate multiple assignment: (a, b, c) = [1, 2, 3];
calc_gen(value_node); calc_gen(value_node);
auto& tuple = tuple_node->get_elements(); 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()); emit(op_callvi, i, value_node->get_location());
mcall(tuple[i]); mcall(tuple[i]);
// use load operands to avoid meq's pop operand // use load operands to avoid meq's pop operand
// and this operation changes local and global value directly // and this operation changes local and global value directly
replace_left_assignment_with_load(tuple[i]->get_location()); replace_left_assignment_with_load(tuple[i]->get_location());
} }
// pop source vector // pop source vector
emit(op_pop, 0, node->get_location()); 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()) { for(auto i : continue_ptr.front()) {
code[i].num = continue_place; code[i].num = continue_place;
} }
@ -943,7 +948,7 @@ void codegen::statement_generation(expr* node) {
case expr_type::ast_ternary: case expr_type::ast_ternary:
calc_gen(node); calc_gen(node);
// only generate in repl mode and in global scope // 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_repl, 0, node->get_location());
} }
emit(op_pop, 0, node->get_location()); emit(op_pop, 0, node->get_location());
@ -1254,7 +1259,7 @@ void codegen::block_gen(code_block* node) {
break; break;
case expr_type::ast_null: break; case expr_type::ast_null: break;
case expr_type::ast_id: case expr_type::ast_id:
if (need_repl_output && local.empty()) { if (flag_need_repl_output && local.empty()) {
repl_mode_info_output_gen(tmp); repl_mode_info_output_gen(tmp);
} else { } else {
check_id_exist(reinterpret_cast<identifier*>(tmp)); 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_num:
case expr_type::ast_str: case expr_type::ast_str:
case expr_type::ast_bool: case expr_type::ast_bool:
if (need_repl_output && local.empty()) { if (flag_need_repl_output && local.empty()) {
repl_mode_info_output_gen(tmp); repl_mode_info_output_gen(tmp);
} }
break; break;
@ -1313,7 +1318,7 @@ const error& codegen::compile(parse& parse,
linker& import, linker& import,
bool repl_flag, bool repl_flag,
bool limit_mode) { bool limit_mode) {
need_repl_output = repl_flag; flag_need_repl_output = repl_flag;
flag_limited_mode = limit_mode; flag_limited_mode = limit_mode;
init_native_function(); init_native_function();
init_file_map(import.get_file_list()); 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()); emit(op_exit, 0, parse.tree()->get_location());
// size out of bound check // size out of bound check
if (const_number_table.size()>0xffffff) { if (const_number_table.size()>INT64_MAX) {
err.err("code", err.err("code",
"too many constant numbers: " + "too many constant numbers: " +
std::to_string(const_number_table.size()) std::to_string(const_number_table.size())
); );
} }
if (const_string_table.size()>0xffffff) { if (const_string_table.size()>INT64_MAX) {
err.err("code", err.err("code",
"too many constant strings: " + "too many constant strings: " +
std::to_string(const_string_table.size()) std::to_string(const_string_table.size())
@ -1356,7 +1361,7 @@ const error& codegen::compile(parse& parse,
} }
// check generated code size // check generated code size
if (code.size()>0xffffff) { if (code.size()>INT64_MAX) {
err.err("code", err.err("code",
"bytecode size overflow: " + "bytecode size overflow: " +
std::to_string(code.size()) std::to_string(code.size())
@ -1367,8 +1372,8 @@ const error& codegen::compile(parse& parse,
void codegen::print(std::ostream& out) { void codegen::print(std::ostream& out) {
// func end stack, reserved for code print // func end stack, reserved for code print
std::stack<u32> func_begin_stack; std::stack<u64> func_begin_stack;
std::stack<u32> func_end_stack; std::stack<u64> func_end_stack;
// print const numbers // print const numbers
for(auto num : const_number_table) { for(auto num : const_number_table) {
@ -1391,7 +1396,8 @@ void codegen::print(std::ostream& out) {
const_string_table.data(), const_string_table.data(),
native_function.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 // print opcode index, opcode name, opcode immediate number
const auto& c = code[i]; const auto& c = code[i];
if (!func_end_stack.empty() && i==func_end_stack.top()) { 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 // get function begin index and end index
if (c.op==op_newf) { if (c.op==op_newf) {
out << std::hex << "\nfunc <0x" << i << std::dec << ">:\n"; 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) { if (code[j].op==op_jmp) {
func_begin_stack.push(i); func_begin_stack.push(i);
func_end_stack.push(code[j].num); func_end_stack.push(code[j].num);

View File

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

View File

@ -147,12 +147,14 @@ void dbg::list_file() const {
} }
void dbg::step_info() { void dbg::step_info() {
u32 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1; u64 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1;
u32 begin = (line>>3)==0? 0:((line>>3)<<3); u64 begin = (line>>3)==0? 0:((line>>3)<<3);
u32 end = (1+(line>>3))<<3; u64 end = (1+(line>>3))<<3;
src.load(files[bytecode[ctx.pc].fidx]); src.load(files[bytecode[ctx.pc].fidx]);
std::clog << "\nsource code:\n"; 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? back_white:reset);
std::clog << (i==line? "--> ":" ") << src[i] << reset << "\n"; 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); begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3);
end = (1+(ctx.pc>>3))<<3; end = (1+(ctx.pc>>3))<<3;
codestream::set(const_number, const_string, native_function.data(), files); codestream::set(const_number, const_string, native_function.data(), files);
std::clog << "\nnext bytecode:\n"; 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 std::clog
<< (i==ctx.pc? back_white:reset) << (i==ctx.pc? back_white:reset)
<< (i==ctx.pc? "--> ":" ") << (i==ctx.pc? "--> ":" ")
@ -234,19 +237,18 @@ void dbg::interact() {
} }
} }
void dbg::run( void dbg::run(const codegen& gen,
const codegen& gen, const linker& linker,
const linker& linker, const std::vector<std::string>& argv,
const std::vector<std::string>& argv, bool profile,
bool profile, bool show_all_prof_result) {
bool show_all_prof_result) {
set_detail_report_info(true); set_detail_report_info(true);
do_operand_count = profile || show_all_prof_result; do_operand_count = profile || show_all_prof_result;
const auto& file_list = linker.get_file_list(); const auto& file_list = linker.get_file_list();
fsize = file_list.size(); fsize = file_list.size();
init( vm_init_enrty(
gen.strs(), gen.strs(),
gen.nums(), gen.nums(),
gen.natives(), gen.natives(),
@ -257,9 +259,9 @@ void dbg::run(
); );
counter.init(file_list); counter.init(file_list);
std::vector<u32> code; std::vector<u8> code;
std::vector<u16> code_file_index; std::vector<u16> code_file_index;
std::vector<u32> code_line; std::vector<u64> code_line;
for(const auto& i : gen.codes()) { for(const auto& i : gen.codes()) {
code.push_back(i.op); code.push_back(i.op);
code_file_index.push_back(i.fidx); 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); const u8 index = static_cast<u8>(type)-static_cast<u8>(vm_type::vm_str);
size[index] += incr[index]; 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 // no need to check, will be killed if memory is not enough
nas_val* tmp = new nas_val(type); nas_val* tmp = new nas_val(type);
@ -197,14 +197,13 @@ void gc::extend(const vm_type type) {
memory.push_back(tmp); memory.push_back(tmp);
unused[index].push_back(tmp); unused[index].push_back(tmp);
} }
// if incr[index] = 1, this will always be 1 // if incr[index] = 1, this will always be 1
incr[index] = incr[index]+incr[index]/2; incr[index] = incr[index]+incr[index]/2;
} }
void gc::init( void gc::init(const std::vector<std::string>& constant_strings,
const std::vector<std::string>& constant_strings, const std::vector<std::string>& argv) {
const std::vector<std::string>& argv
) {
// initialize counters // initialize counters
worktime = 0; worktime = 0;
for(u8 i = 0; i<gc_type_size; ++i) { for(u8 i = 0; i<gc_type_size; ++i) {
@ -216,7 +215,7 @@ void gc::init(
// init constant strings // init constant strings
strs.resize(constant_strings.size()); 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 // incremental initialization, avoid memory leak in repl mode
if (strs[i].is_str() && strs[i].str()==constant_strings[i]) { if (strs[i].is_str() && strs[i].str()==constant_strings[i]) {
continue; continue;
@ -228,7 +227,7 @@ void gc::init(
// record arguments // record arguments
env_argv.resize(argv.size()); 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 // incremental initialization, avoid memory leak in repl mode
if (env_argv[i].is_str() && env_argv[i].str()==argv[i]) { if (env_argv[i].is_str() && env_argv[i].str()==argv[i]) {
continue; continue;
@ -315,7 +314,7 @@ void gc::info() const {
if (!gcnt[i] && !acnt[i] && !size[i]) { if (!gcnt[i] && !acnt[i] && !size[i]) {
continue; continue;
} }
total += gcnt[i]; total += static_cast<f64>(gcnt[i]);
std::clog << " " << left << setw(indent) << setfill(' ') << name[i]; std::clog << " " << left << setw(indent) << setfill(' ') << name[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i]; std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << acnt[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 std::vector<nas_val*> unused[gc_type_size]; // gc free list
/* heap increase size */ /* heap increase size */
u32 incr[gc_type_size] = { u64 incr[gc_type_size] = {
128, // vm_str 128, // vm_str
128, // vm_vec 128, // vm_vec
64, // vm_hash 64, // vm_hash

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -204,16 +204,17 @@ var builtin_str(context* ctx, gc* ngc) {
var builtin_size(context* ctx, gc* ngc) { var builtin_size(context* ctx, gc* ngc) {
auto val = ctx->localr[1]; auto val = ctx->localr[1];
f64 num = 0;
usize num = 0;
switch(val.type) { 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_str: num = val.str().length(); break;
case vm_type::vm_vec: num = val.vec().size(); 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_hash: num = val.hash().size(); break;
case vm_type::vm_map: num = val.map().mapper.size(); break; case vm_type::vm_map: num = val.map().mapper.size(); break;
default: break; default: break;
} }
return var::num(num); return var::num(static_cast<f64>(num));
} }
var builtin_time(context* ctx, gc* ngc) { var builtin_time(context* ctx, gc* ngc) {
@ -569,12 +570,12 @@ public:
stamp = std::chrono::high_resolution_clock::now(); stamp = std::chrono::high_resolution_clock::now();
} }
f64 elapsed_milliseconds() { auto elapsed_milliseconds() const {
const auto duration = std::chrono::high_resolution_clock::now() - stamp; const auto duration = std::chrono::high_resolution_clock::now() - stamp;
return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); 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; const auto duration = std::chrono::high_resolution_clock::now() - stamp;
return std::chrono::duration_cast<std::chrono::microseconds>(duration).count(); 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); return var::num(-1);
} }
auto stamp = static_cast<time_stamp*>(object.ghost().pointer); 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) { var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
@ -620,7 +621,7 @@ var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
return var::num(-1); return var::num(-1);
} }
auto stamp = static_cast<time_stamp*>(object.ghost().pointer); 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) { 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) { 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); var res = ngc->alloc(vm_type::vm_hash);
double total = 0; f64 total = 0;
for(u32 i = 0; i<gc_type_size; ++i) { 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; auto& map = res.hash().elems;
map["total"] = var::num(ngc->worktime*1.0/den*1000); const auto worktime = static_cast<f64>(ngc->worktime);
map["average"] = var::num(ngc->worktime*1.0/den*1000/total); const auto max_time = static_cast<f64>(ngc->max_time);
map["max_gc"] = var::num(ngc->max_time*1.0/den*1000); const auto max_mark_time = static_cast<f64>(ngc->max_mark_time);
map["max_mark"] = var::num(ngc->max_mark_time*1.0/den*1000); const auto max_sweep_time = static_cast<f64>(ngc->max_sweep_time);
map["max_sweep"] = var::num(ngc->max_sweep_time*1.0/den*1000);
// 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; return res;
} }
@ -686,9 +694,17 @@ var builtin_ghosttype(context* ctx, gc* ngc) {
if (!arg.is_ghost()) { if (!arg.is_ghost()) {
return nas_err("ghosttype", "this is not a ghost object."); return nas_err("ghosttype", "this is not a ghost object.");
} }
const auto& name = arg.ghost().get_ghost_name(); 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()) { 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); return ngc->newstr(name);
} }