✨ append code size from u32 to u64
This commit is contained in:
parent
8e38764df0
commit
96731d180f
2
makefile
2
makefile
|
@ -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 = \
|
||||
|
|
|
@ -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()=="|--") {
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 << ")";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue