mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 06:08:41 +01:00
Pull out opcode definitions into an X-macro file.
This commit is contained in:
@ -50,6 +50,7 @@
|
||||
29205CA61AB4E65E0073018D /* wren_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_utils.h; path = ../../src/vm/wren_utils.h; sourceTree = "<group>"; };
|
||||
29205CA71AB4E65E0073018D /* wren_value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_value.h; path = ../../src/vm/wren_value.h; sourceTree = "<group>"; };
|
||||
29205CA81AB4E65E0073018D /* wren_vm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_vm.h; path = ../../src/vm/wren_vm.h; sourceTree = "<group>"; };
|
||||
296371B31AC713D000079FDA /* wren_opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_opcodes.h; path = ../../src/vm/wren_opcodes.h; sourceTree = "<group>"; };
|
||||
29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
29C8A92E1AB71C1C00DEC81D /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = io.c; path = ../../src/cli/io.c; sourceTree = "<group>"; };
|
||||
29C8A9301AB71C3300DEC81D /* io.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/cli/io.h; sourceTree = "<group>"; };
|
||||
@ -84,6 +85,7 @@
|
||||
29205C951AB4E6430073018D /* wren_io.c */,
|
||||
29DE39521AC3A50A00987D41 /* wren_meta.h */,
|
||||
29DE39511AC3A50A00987D41 /* wren_meta.c */,
|
||||
296371B31AC713D000079FDA /* wren_opcodes.h */,
|
||||
29205CA61AB4E65E0073018D /* wren_utils.h */,
|
||||
29205C961AB4E6430073018D /* wren_utils.c */,
|
||||
29205CA71AB4E65E0073018D /* wren_value.h */,
|
||||
|
||||
192
src/vm/wren_opcodes.h
Normal file
192
src/vm/wren_opcodes.h
Normal file
@ -0,0 +1,192 @@
|
||||
// This defines the bytecode instructions used by the VM. It does so by invoking
|
||||
// an OPCODE() macro which is expected to be defined at the point that this is
|
||||
// included. See: http://en.wikipedia.org/wiki/X_Macro.
|
||||
//
|
||||
// Note that the order of instructions here affects the order of the dispatch
|
||||
// table in the VM's interpreter loop. That in turn affects caching which
|
||||
// affects overall performance. Take care to run benchmarks if you change the
|
||||
// order here.
|
||||
|
||||
// Load the constant at index [arg].
|
||||
OPCODE(CONSTANT)
|
||||
|
||||
// Push null onto the stack.
|
||||
OPCODE(NULL)
|
||||
|
||||
// Push false onto the stack.
|
||||
OPCODE(FALSE)
|
||||
|
||||
// Push true onto the stack.
|
||||
OPCODE(TRUE)
|
||||
|
||||
// Pushes the value in the given local slot.
|
||||
OPCODE(LOAD_LOCAL_0)
|
||||
OPCODE(LOAD_LOCAL_1)
|
||||
OPCODE(LOAD_LOCAL_2)
|
||||
OPCODE(LOAD_LOCAL_3)
|
||||
OPCODE(LOAD_LOCAL_4)
|
||||
OPCODE(LOAD_LOCAL_5)
|
||||
OPCODE(LOAD_LOCAL_6)
|
||||
OPCODE(LOAD_LOCAL_7)
|
||||
OPCODE(LOAD_LOCAL_8)
|
||||
|
||||
// Note: The compiler assumes the following _STORE instructions always
|
||||
// immediately follow their corresponding _LOAD ones.
|
||||
|
||||
// Pushes the value in local slot [arg].
|
||||
OPCODE(LOAD_LOCAL)
|
||||
|
||||
// Stores the top of stack in local slot [arg]. Does not pop it.
|
||||
OPCODE(STORE_LOCAL)
|
||||
|
||||
// Pushes the value in upvalue [arg].
|
||||
OPCODE(LOAD_UPVALUE)
|
||||
|
||||
// Stores the top of stack in upvalue [arg]. Does not pop it.
|
||||
OPCODE(STORE_UPVALUE)
|
||||
|
||||
// Pushes the value of the top-level variable in slot [arg].
|
||||
OPCODE(LOAD_MODULE_VAR)
|
||||
|
||||
// Stores the top of stack in top-level variable slot [arg]. Does not pop it.
|
||||
OPCODE(STORE_MODULE_VAR)
|
||||
|
||||
// Pushes the value of the field in slot [arg] of the receiver of the current
|
||||
// function. This is used for regular field accesses on "this" directly in
|
||||
// methods. This instruction is faster than the more general CODE_LOAD_FIELD
|
||||
// instruction.
|
||||
OPCODE(LOAD_FIELD_THIS)
|
||||
|
||||
// Stores the top of the stack in field slot [arg] in the receiver of the
|
||||
// current value. Does not pop the value. This instruction is faster than the
|
||||
// more general CODE_LOAD_FIELD instruction.
|
||||
OPCODE(STORE_FIELD_THIS)
|
||||
|
||||
// Pops an instance and pushes the value of the field in slot [arg] of it.
|
||||
OPCODE(LOAD_FIELD)
|
||||
|
||||
// Pops an instance and stores the subsequent top of stack in field slot
|
||||
// [arg] in it. Does not pop the value.
|
||||
OPCODE(STORE_FIELD)
|
||||
|
||||
// Pop and discard the top of stack.
|
||||
OPCODE(POP)
|
||||
|
||||
// Push a copy of the value currently on the top of the stack.
|
||||
OPCODE(DUP)
|
||||
|
||||
// Invoke the method with symbol [arg]. The number indicates the number of
|
||||
// arguments (not including the receiver).
|
||||
OPCODE(CALL_0)
|
||||
OPCODE(CALL_1)
|
||||
OPCODE(CALL_2)
|
||||
OPCODE(CALL_3)
|
||||
OPCODE(CALL_4)
|
||||
OPCODE(CALL_5)
|
||||
OPCODE(CALL_6)
|
||||
OPCODE(CALL_7)
|
||||
OPCODE(CALL_8)
|
||||
OPCODE(CALL_9)
|
||||
OPCODE(CALL_10)
|
||||
OPCODE(CALL_11)
|
||||
OPCODE(CALL_12)
|
||||
OPCODE(CALL_13)
|
||||
OPCODE(CALL_14)
|
||||
OPCODE(CALL_15)
|
||||
OPCODE(CALL_16)
|
||||
|
||||
// Invoke a superclass method with symbol [arg]. The number indicates the
|
||||
// number of arguments (not including the receiver).
|
||||
OPCODE(SUPER_0)
|
||||
OPCODE(SUPER_1)
|
||||
OPCODE(SUPER_2)
|
||||
OPCODE(SUPER_3)
|
||||
OPCODE(SUPER_4)
|
||||
OPCODE(SUPER_5)
|
||||
OPCODE(SUPER_6)
|
||||
OPCODE(SUPER_7)
|
||||
OPCODE(SUPER_8)
|
||||
OPCODE(SUPER_9)
|
||||
OPCODE(SUPER_10)
|
||||
OPCODE(SUPER_11)
|
||||
OPCODE(SUPER_12)
|
||||
OPCODE(SUPER_13)
|
||||
OPCODE(SUPER_14)
|
||||
OPCODE(SUPER_15)
|
||||
OPCODE(SUPER_16)
|
||||
|
||||
// Jump the instruction pointer [arg] forward.
|
||||
OPCODE(JUMP)
|
||||
|
||||
// Jump the instruction pointer [arg] backward. Pop and discard the top of
|
||||
// the stack.
|
||||
OPCODE(LOOP)
|
||||
|
||||
// Pop and if not truthy then jump the instruction pointer [arg] forward.
|
||||
OPCODE(JUMP_IF)
|
||||
|
||||
// If the top of the stack is false, jump [arg] forward. Otherwise, pop and
|
||||
// continue.
|
||||
OPCODE(AND)
|
||||
|
||||
// If the top of the stack is non-false, jump [arg] forward. Otherwise, pop
|
||||
// and continue.
|
||||
OPCODE(OR)
|
||||
|
||||
// Pop [a] then [b] and push true if [b] is an instance of [a].
|
||||
OPCODE(IS)
|
||||
|
||||
// Close the upvalue for the local on the top of the stack, then pop it.
|
||||
OPCODE(CLOSE_UPVALUE)
|
||||
|
||||
// Exit from the current function and return the value on the top of the
|
||||
// stack.
|
||||
OPCODE(RETURN)
|
||||
|
||||
// Creates a closure for the function stored at [arg] in the constant table.
|
||||
//
|
||||
// Following the function argument is a number of arguments, two for each
|
||||
// upvalue. The first is true if the variable being captured is a local (as
|
||||
// opposed to an upvalue), and the second is the index of the local or
|
||||
// upvalue being captured.
|
||||
//
|
||||
// Pushes the created closure.
|
||||
OPCODE(CLOSURE)
|
||||
|
||||
// Creates a class. Top of stack is the superclass, or `null` if the class
|
||||
// inherits Object. Below that is a string for the name of the class. Byte
|
||||
// [arg] is the number of fields in the class.
|
||||
OPCODE(CLASS)
|
||||
|
||||
// Define a method for symbol [arg]. The class receiving the method is popped
|
||||
// off the stack, then the function defining the body is popped.
|
||||
//
|
||||
// If a foreign method is being defined, the "function" will be a string
|
||||
// identifying the foreign method. Otherwise, it will be a function or
|
||||
// closure.
|
||||
OPCODE(METHOD_INSTANCE)
|
||||
|
||||
// Define a method for symbol [arg]. The class whose metaclass will receive
|
||||
// the method is popped off the stack, then the function defining the body is
|
||||
// popped.
|
||||
//
|
||||
// If a foreign method is being defined, the "function" will be a string
|
||||
// identifying the foreign method. Otherwise, it will be a function or
|
||||
// closure.
|
||||
OPCODE(METHOD_STATIC)
|
||||
|
||||
// Load the module whose name is stored in string constant [arg]. Pushes
|
||||
// NULL onto the stack. If the module has already been loaded, does nothing
|
||||
// else. Otherwise, it creates a fiber to run the desired module and switches
|
||||
// to that. When that fiber is done, the current one is resumed.
|
||||
OPCODE(LOAD_MODULE)
|
||||
|
||||
// Reads a top-level variable from another module. [arg1] is a string
|
||||
// constant for the name of the module, and [arg2] is a string constant for
|
||||
// the variable name. Pushes the variable if found, or generates a runtime
|
||||
// error otherwise.
|
||||
OPCODE(IMPORT_VARIABLE)
|
||||
|
||||
// This pseudo-instruction indicates the end of the bytecode. It should
|
||||
// always be preceded by a `CODE_RETURN`, so is never actually executed.
|
||||
OPCODE(END)
|
||||
@ -658,80 +658,9 @@ static bool runInterpreter(WrenVM* vm)
|
||||
// Note that the order of instructions here must exacly match the Code enum
|
||||
// in wren_vm.h or horrendously bad things happen.
|
||||
static void* dispatchTable[] = {
|
||||
&&code_CONSTANT,
|
||||
&&code_NULL,
|
||||
&&code_FALSE,
|
||||
&&code_TRUE,
|
||||
&&code_LOAD_LOCAL_0,
|
||||
&&code_LOAD_LOCAL_1,
|
||||
&&code_LOAD_LOCAL_2,
|
||||
&&code_LOAD_LOCAL_3,
|
||||
&&code_LOAD_LOCAL_4,
|
||||
&&code_LOAD_LOCAL_5,
|
||||
&&code_LOAD_LOCAL_6,
|
||||
&&code_LOAD_LOCAL_7,
|
||||
&&code_LOAD_LOCAL_8,
|
||||
&&code_LOAD_LOCAL,
|
||||
&&code_STORE_LOCAL,
|
||||
&&code_LOAD_UPVALUE,
|
||||
&&code_STORE_UPVALUE,
|
||||
&&code_LOAD_MODULE_VAR,
|
||||
&&code_STORE_MODULE_VAR,
|
||||
&&code_LOAD_FIELD_THIS,
|
||||
&&code_STORE_FIELD_THIS,
|
||||
&&code_LOAD_FIELD,
|
||||
&&code_STORE_FIELD,
|
||||
&&code_POP,
|
||||
&&code_DUP,
|
||||
&&code_CALL_0,
|
||||
&&code_CALL_1,
|
||||
&&code_CALL_2,
|
||||
&&code_CALL_3,
|
||||
&&code_CALL_4,
|
||||
&&code_CALL_5,
|
||||
&&code_CALL_6,
|
||||
&&code_CALL_7,
|
||||
&&code_CALL_8,
|
||||
&&code_CALL_9,
|
||||
&&code_CALL_10,
|
||||
&&code_CALL_11,
|
||||
&&code_CALL_12,
|
||||
&&code_CALL_13,
|
||||
&&code_CALL_14,
|
||||
&&code_CALL_15,
|
||||
&&code_CALL_16,
|
||||
&&code_SUPER_0,
|
||||
&&code_SUPER_1,
|
||||
&&code_SUPER_2,
|
||||
&&code_SUPER_3,
|
||||
&&code_SUPER_4,
|
||||
&&code_SUPER_5,
|
||||
&&code_SUPER_6,
|
||||
&&code_SUPER_7,
|
||||
&&code_SUPER_8,
|
||||
&&code_SUPER_9,
|
||||
&&code_SUPER_10,
|
||||
&&code_SUPER_11,
|
||||
&&code_SUPER_12,
|
||||
&&code_SUPER_13,
|
||||
&&code_SUPER_14,
|
||||
&&code_SUPER_15,
|
||||
&&code_SUPER_16,
|
||||
&&code_JUMP,
|
||||
&&code_LOOP,
|
||||
&&code_JUMP_IF,
|
||||
&&code_AND,
|
||||
&&code_OR,
|
||||
&&code_IS,
|
||||
&&code_CLOSE_UPVALUE,
|
||||
&&code_RETURN,
|
||||
&&code_CLOSURE,
|
||||
&&code_CLASS,
|
||||
&&code_METHOD_INSTANCE,
|
||||
&&code_METHOD_STATIC,
|
||||
&&code_LOAD_MODULE,
|
||||
&&code_IMPORT_VARIABLE,
|
||||
&&code_END
|
||||
#define OPCODE(name) &&code_##name,
|
||||
#include "wren_opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
#define INTERPRET_LOOP DISPATCH();
|
||||
|
||||
186
src/vm/wren_vm.h
186
src/vm/wren_vm.h
@ -12,189 +12,9 @@
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// Load the constant at index [arg].
|
||||
CODE_CONSTANT,
|
||||
|
||||
// Push null onto the stack.
|
||||
CODE_NULL,
|
||||
|
||||
// Push false onto the stack.
|
||||
CODE_FALSE,
|
||||
|
||||
// Push true onto the stack.
|
||||
CODE_TRUE,
|
||||
|
||||
// Pushes the value in the given local slot.
|
||||
CODE_LOAD_LOCAL_0,
|
||||
CODE_LOAD_LOCAL_1,
|
||||
CODE_LOAD_LOCAL_2,
|
||||
CODE_LOAD_LOCAL_3,
|
||||
CODE_LOAD_LOCAL_4,
|
||||
CODE_LOAD_LOCAL_5,
|
||||
CODE_LOAD_LOCAL_6,
|
||||
CODE_LOAD_LOCAL_7,
|
||||
CODE_LOAD_LOCAL_8,
|
||||
|
||||
// Note: The compiler assumes the following _STORE instructions always
|
||||
// immediately follow their corresponding _LOAD ones.
|
||||
|
||||
// Pushes the value in local slot [arg].
|
||||
CODE_LOAD_LOCAL,
|
||||
|
||||
// Stores the top of stack in local slot [arg]. Does not pop it.
|
||||
CODE_STORE_LOCAL,
|
||||
|
||||
// Pushes the value in upvalue [arg].
|
||||
CODE_LOAD_UPVALUE,
|
||||
|
||||
// Stores the top of stack in upvalue [arg]. Does not pop it.
|
||||
CODE_STORE_UPVALUE,
|
||||
|
||||
// Pushes the value of the top-level variable in slot [arg].
|
||||
CODE_LOAD_MODULE_VAR,
|
||||
|
||||
// Stores the top of stack in top-level variable slot [arg]. Does not pop it.
|
||||
CODE_STORE_MODULE_VAR,
|
||||
|
||||
// Pushes the value of the field in slot [arg] of the receiver of the current
|
||||
// function. This is used for regular field accesses on "this" directly in
|
||||
// methods. This instruction is faster than the more general CODE_LOAD_FIELD
|
||||
// instruction.
|
||||
CODE_LOAD_FIELD_THIS,
|
||||
|
||||
// Stores the top of the stack in field slot [arg] in the receiver of the
|
||||
// current value. Does not pop the value. This instruction is faster than the
|
||||
// more general CODE_LOAD_FIELD instruction.
|
||||
CODE_STORE_FIELD_THIS,
|
||||
|
||||
// Pops an instance and pushes the value of the field in slot [arg] of it.
|
||||
CODE_LOAD_FIELD,
|
||||
|
||||
// Pops an instance and stores the subsequent top of stack in field slot
|
||||
// [arg] in it. Does not pop the value.
|
||||
CODE_STORE_FIELD,
|
||||
|
||||
// Pop and discard the top of stack.
|
||||
CODE_POP,
|
||||
|
||||
// Push a copy of the value currently on the top of the stack.
|
||||
CODE_DUP,
|
||||
|
||||
// Invoke the method with symbol [arg]. The number indicates the number of
|
||||
// arguments (not including the receiver).
|
||||
CODE_CALL_0,
|
||||
CODE_CALL_1,
|
||||
CODE_CALL_2,
|
||||
CODE_CALL_3,
|
||||
CODE_CALL_4,
|
||||
CODE_CALL_5,
|
||||
CODE_CALL_6,
|
||||
CODE_CALL_7,
|
||||
CODE_CALL_8,
|
||||
CODE_CALL_9,
|
||||
CODE_CALL_10,
|
||||
CODE_CALL_11,
|
||||
CODE_CALL_12,
|
||||
CODE_CALL_13,
|
||||
CODE_CALL_14,
|
||||
CODE_CALL_15,
|
||||
CODE_CALL_16,
|
||||
|
||||
// Invoke a superclass method with symbol [arg]. The number indicates the
|
||||
// number of arguments (not including the receiver).
|
||||
CODE_SUPER_0,
|
||||
CODE_SUPER_1,
|
||||
CODE_SUPER_2,
|
||||
CODE_SUPER_3,
|
||||
CODE_SUPER_4,
|
||||
CODE_SUPER_5,
|
||||
CODE_SUPER_6,
|
||||
CODE_SUPER_7,
|
||||
CODE_SUPER_8,
|
||||
CODE_SUPER_9,
|
||||
CODE_SUPER_10,
|
||||
CODE_SUPER_11,
|
||||
CODE_SUPER_12,
|
||||
CODE_SUPER_13,
|
||||
CODE_SUPER_14,
|
||||
CODE_SUPER_15,
|
||||
CODE_SUPER_16,
|
||||
|
||||
// Jump the instruction pointer [arg] forward.
|
||||
CODE_JUMP,
|
||||
|
||||
// Jump the instruction pointer [arg] backward. Pop and discard the top of
|
||||
// the stack.
|
||||
CODE_LOOP,
|
||||
|
||||
// Pop and if not truthy then jump the instruction pointer [arg] forward.
|
||||
CODE_JUMP_IF,
|
||||
|
||||
// If the top of the stack is false, jump [arg] forward. Otherwise, pop and
|
||||
// continue.
|
||||
CODE_AND,
|
||||
|
||||
// If the top of the stack is non-false, jump [arg] forward. Otherwise, pop
|
||||
// and continue.
|
||||
CODE_OR,
|
||||
|
||||
// Pop [a] then [b] and push true if [b] is an instance of [a].
|
||||
CODE_IS,
|
||||
|
||||
// Close the upvalue for the local on the top of the stack, then pop it.
|
||||
CODE_CLOSE_UPVALUE,
|
||||
|
||||
// Exit from the current function and return the value on the top of the
|
||||
// stack.
|
||||
CODE_RETURN,
|
||||
|
||||
// Creates a closure for the function stored at [arg] in the constant table.
|
||||
//
|
||||
// Following the function argument is a number of arguments, two for each
|
||||
// upvalue. The first is true if the variable being captured is a local (as
|
||||
// opposed to an upvalue), and the second is the index of the local or
|
||||
// upvalue being captured.
|
||||
//
|
||||
// Pushes the created closure.
|
||||
CODE_CLOSURE,
|
||||
|
||||
// Creates a class. Top of stack is the superclass, or `null` if the class
|
||||
// inherits Object. Below that is a string for the name of the class. Byte
|
||||
// [arg] is the number of fields in the class.
|
||||
CODE_CLASS,
|
||||
|
||||
// Define a method for symbol [arg]. The class receiving the method is popped
|
||||
// off the stack, then the function defining the body is popped.
|
||||
//
|
||||
// If a foreign method is being defined, the "function" will be a string
|
||||
// identifying the foreign method. Otherwise, it will be a function or
|
||||
// closure.
|
||||
CODE_METHOD_INSTANCE,
|
||||
|
||||
// Define a method for symbol [arg]. The class whose metaclass will receive
|
||||
// the method is popped off the stack, then the function defining the body is
|
||||
// popped.
|
||||
//
|
||||
// If a foreign method is being defined, the "function" will be a string
|
||||
// identifying the foreign method. Otherwise, it will be a function or
|
||||
// closure.
|
||||
CODE_METHOD_STATIC,
|
||||
|
||||
// Load the module whose name is stored in string constant [arg]. Pushes
|
||||
// NULL onto the stack. If the module has already been loaded, does nothing
|
||||
// else. Otherwise, it creates a fiber to run the desired module and switches
|
||||
// to that. When that fiber is done, the current one is resumed.
|
||||
CODE_LOAD_MODULE,
|
||||
|
||||
// Reads a top-level variable from another module. [arg1] is a string
|
||||
// constant for the name of the module, and [arg2] is a string constant for
|
||||
// the variable name. Pushes the variable if found, or generates a runtime
|
||||
// error otherwise.
|
||||
CODE_IMPORT_VARIABLE,
|
||||
|
||||
// This pseudo-instruction indicates the end of the bytecode. It should
|
||||
// always be preceded by a `CODE_RETURN`, so is never actually executed.
|
||||
CODE_END
|
||||
#define OPCODE(name) CODE_##name,
|
||||
#include "wren_opcodes.h"
|
||||
#undef OPCODE
|
||||
} Code;
|
||||
|
||||
struct WrenMethod
|
||||
|
||||
Reference in New Issue
Block a user