diff --git a/compiler/generator.cc b/compiler/generator.cc index 1dc981b..fa4b6f7 100644 --- a/compiler/generator.cc +++ b/compiler/generator.cc @@ -6,6 +6,9 @@ #include namespace ceos { + static unsigned lookupID = 1; + static bool capturesScope = true; + std::stringstream &Generator::generate() { generateProgram(m_ast); emitOpcode(Opcode::exit); @@ -103,6 +106,11 @@ namespace ceos { } else { emitOpcode(Opcode::lookup); write(id->uid); + if (capturesScope) { + write(0); + } else { + write(lookupID++); + } } } @@ -155,6 +163,7 @@ namespace ceos { } }; + capturesScope = fn->body->capturesScope; generateNode(fn->body); emitOpcode(Opcode::ret); @@ -205,6 +214,7 @@ namespace ceos { write(Section::Header); write(Section::Text); + write(lookupID); m_output << text; } @@ -326,6 +336,7 @@ section_functions: { } section_code: + bytecode.seekg(4, bytecode.cur); while (true) { char opcode = bytecode.get(); if (bytecode.eof() || bytecode.fail()) { @@ -358,7 +369,8 @@ section_functions: { } case Opcode::lookup: { READ_INT(bytecode, id); - WRITE(5, "lookup $" << id << "(" << strings[id] << ")"); + READ_INT(bytecode, cacheSlot); + WRITE(9, "lookup $" << id << "(" << strings[id] << ") [cacheSlot=" << cacheSlot << "]"); break; } case Opcode::create_closure: { diff --git a/compiler/interpreter.S b/compiler/interpreter.S index 2954c66..5bfede2 100644 --- a/compiler/interpreter.S +++ b/compiler/interpreter.S @@ -4,10 +4,13 @@ #define STRINGS r13 #define VM r14 #define BCBASE r15 +#define LOOKUP rbx .macro read .if $0 == 1 mov 0x1(%BYTECODE), $1 +.elseif $0 == 2 + mov 0x5(%BYTECODE), $1 .else mov $$$0, %rax mov -0x3(%BYTECODE, %rax, 4), $1 @@ -57,11 +60,13 @@ _execute: push %STRINGS push %VM push %BCBASE + push %LOOKUP mov %rsp, %rbp mov %rdi, %BYTECODE mov %rsi, %STRINGS mov %rdx, %VM mov %rcx, %BCBASE + mov %r8, %LOOKUP _loop: xor %rax, %rax @@ -88,6 +93,7 @@ _loop_op_addresses: _op_exit: mov %rbp, %rsp + pop %LOOKUP pop %BCBASE pop %VM pop %STRINGS @@ -101,20 +107,29 @@ _op_push: skip 1 _op_lookup: +_op_lookup_fast_path: + read 2, %edi + mov (%LOOKUP, %rdi, 8), %rsi // Cached address + test %rsi, %rsi + jz _op_lookup_slow_path + push %rsi + skip 2 + +_op_lookup_slow_path: read 1, %esi // string ID - mov (%STRINGS, %rsi, 8), %rsi // actual char * mov (%VM), %r9 // VM::m_scope * + mov (%STRINGS, %rsi, 8), %rsi // actual char * -load: +_op_lookup_load: mov (%r9), %rax // Scope::table * test %rax, %rax - jz check_parent + jz _op_lookup_check_parent mov 0x18(%r9), %edx // Scope::tableHash mov %esi, %ecx // index and %edx, %ecx // index &= hash mov %ecx, %r8d // begin -begin: +_op_lookup_begin: mov %ecx, %edi shl $1, %edi mov (%rax, %rdi, 0x8), %r11 // Entry::key @@ -125,22 +140,35 @@ begin: skip 1 slow_path: + cmp %rsi, %r11 + jz _op_lookup_found test %r11,%r11 - jz check_parent + jz _op_lookup_check_parent inc %ecx and %edx, %ecx cmp %ecx, %r8d - jnz begin + jnz _op_lookup_begin -check_parent: +_op_lookup_check_parent: mov 0x8(%r9), %r9 // Scope::parent test %r9, %r9 - jnz load + jnz _op_lookup_load -not_found: +_op_lookup_not_found: mov %rsi, %rdi ccall _symbolNotFound +_op_lookup_found: + mov 0x8(%rax, %rdi, 0x8), %rax // Entry::value + read 2, %edx + test %edx, %edx + jz _op_lookup_done + mov %rax, (%LOOKUP, %rdx, 8) // cache value + +_op_lookup_done: + push %rax + skip 2 + _op_call: // pop the callee from the stack pop %rcx diff --git a/compiler/vm.cc b/compiler/vm.cc index 4a84cef..ae8dd7f 100644 --- a/compiler/vm.cc +++ b/compiler/vm.cc @@ -11,7 +11,8 @@ extern "C" void execute( const uint8_t *bytecode, String *stringTable, VM *vm, - const uint8_t *bcbase); + const uint8_t *bcbase, + void *lookupTable); extern "C" void setScope(VM *vm, const char *name, Value value); void setScope(VM *vm, const char *name, Value value) { @@ -41,7 +42,7 @@ uint64_t createClosure(VM *vm, unsigned fnID, bool capturesScope) { extern "C" unsigned prepareClosure(unsigned argc, Value *argv, VM *vm, Closure *closure); unsigned prepareClosure(__unused unsigned argc, __unused Value *argv, VM *vm, Closure *closure) { - if (closure->scope) { + if (closure->scope != NULL) { vm->m_scope = vm->m_scope->create(closure->scope); } return closure->fn->offset; @@ -55,7 +56,7 @@ void finishClosure(VM *vm, Closure *closure) { } extern "C" void symbolNotFound(char *); -extern "C" void symbolNotFound(char *symbolName) { +void symbolNotFound(char *symbolName) { fprintf(stderr, "Symbol not found: %s\n", symbolName); throw; } @@ -80,9 +81,12 @@ extern "C" void symbolNotFound(char *symbolName) { case Section::Functions: loadFunctions(); break; - case Section::Text: - ::ceos::execute(m_bytecode + pc, m_stringTable.data(), this, m_bytecode); + case Section::Text: { + auto lookupTableSize = read(); + void *lookupTable = calloc(lookupTableSize * 8, 1); + ::ceos::execute(m_bytecode + pc, m_stringTable.data(), this, m_bytecode, lookupTable); return; + } default: std::cerr << "Unknown section: `0x0" << std::hex << section << "`\n"; throw; @@ -90,7 +94,7 @@ extern "C" void symbolNotFound(char *symbolName) { } } - void VM::loadStrings() { + inline void VM::loadStrings() { while (true) { auto header = read(); @@ -104,7 +108,7 @@ extern "C" void symbolNotFound(char *symbolName) { } } - void VM::loadFunctions() { + inline void VM::loadFunctions() { auto initialHeader = read(); assert(initialHeader == Section::FunctionHeader);