diff --git a/src/vm/wren_compiler.c b/src/vm/wren_compiler.c index 04d983c1..f4bf3fa6 100644 --- a/src/vm/wren_compiler.c +++ b/src/vm/wren_compiler.c @@ -322,6 +322,13 @@ struct sCompiler // here means top-level code is being compiled and there is no block scope // in effect at all. Any variables declared will be module-level. int scopeDepth; + + // The current number of slots (locals and temporaries) in use. + int numSlots; + + // The maximum number of slots (locals and temporaries) in use at one time in + // the function. + int maxSlots; // The current innermost loop being compiled, or NULL if not in a loop. Loop* loop; @@ -336,6 +343,14 @@ struct sCompiler IntBuffer debugSourceLines; }; +// The stack effect of each opcode. The index in the array is the opcode, and +// the value is the stack effect of that instruction. +static const int stackEffects[] = { + #define OPCODE(_, effect) effect, + #include "wren_opcodes.h" + #undef OPCODE +}; + // Outputs a compile or syntax error. This also marks the compilation as having // an error, which ensures that the resulting code will be discarded and never // run. This means that after calling lexError(), it's fine to generate whatever @@ -469,6 +484,9 @@ static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent, // The initial scope for function or method is a local scope. compiler->scopeDepth = 0; } + + compiler->numSlots = compiler->numLocals; + compiler->maxSlots = compiler->numLocals; wrenByteBufferInit(&compiler->bytecode); wrenIntBufferInit(&compiler->debugSourceLines); @@ -1063,38 +1081,51 @@ static void consumeLine(Compiler* compiler, const char* errorMessage) // Variables and scopes -------------------------------------------------------- -// Emits one bytecode instruction or single-byte argument. Returns its index. -static int emit(Compiler* compiler, int byte) +// Emits one single-byte argument. Returns its index. +static int emitByte(Compiler* compiler, int byte) { wrenByteBufferWrite(compiler->parser->vm, &compiler->bytecode, (uint8_t)byte); - + // Assume the instruction is associated with the most recently consumed token. wrenIntBufferWrite(compiler->parser->vm, &compiler->debugSourceLines, - compiler->parser->previous.line); - + compiler->parser->previous.line); + return compiler->bytecode.count - 1; } +// Emits one bytecode instruction. +static void emitOp(Compiler* compiler, Code instruction) +{ + emitByte(compiler, instruction); + + // Keep track of the stack's high water mark. + compiler->numSlots += stackEffects[instruction]; + if (compiler->numSlots > compiler->maxSlots) + { + compiler->maxSlots = compiler->numSlots; + } +} + // Emits one 16-bit argument, which will be written big endian. static void emitShort(Compiler* compiler, int arg) { - emit(compiler, (arg >> 8) & 0xff); - emit(compiler, arg & 0xff); + emitByte(compiler, (arg >> 8) & 0xff); + emitByte(compiler, arg & 0xff); } // Emits one bytecode instruction followed by a 8-bit argument. Returns the // index of the argument in the bytecode. static int emitByteArg(Compiler* compiler, Code instruction, int arg) { - emit(compiler, instruction); - return emit(compiler, arg); + emitOp(compiler, instruction); + return emitByte(compiler, arg); } // Emits one bytecode instruction followed by a 16-bit argument, which will be // written big endian. static void emitShortArg(Compiler* compiler, Code instruction, int arg) { - emit(compiler, instruction); + emitOp(compiler, instruction); emitShort(compiler, arg); } @@ -1103,9 +1134,9 @@ static void emitShortArg(Compiler* compiler, Code instruction, int arg) // placeholder. static int emitJump(Compiler* compiler, Code instruction) { - emit(compiler, instruction); - emit(compiler, 0xff); - return emit(compiler, 0xff) - 1; + emitOp(compiler, instruction); + emitByte(compiler, 0xff); + return emitByte(compiler, 0xff) - 1; } // Creates a new constant for the current value and emits the bytecode to load @@ -1207,7 +1238,7 @@ static void defineVariable(Compiler* compiler, int symbol) // It's a module-level variable, so store the value in the module slot and // then discard the temporary for the initializer. emitShortArg(compiler, CODE_STORE_MODULE_VAR, symbol); - emit(compiler, CODE_POP); + emitOp(compiler, CODE_POP); } // Starts a new local block scope. @@ -1231,15 +1262,18 @@ static int discardLocals(Compiler* compiler, int depth) while (local >= 0 && compiler->locals[local].depth >= depth) { // If the local was closed over, make sure the upvalue gets closed when it - // goes out of scope on the stack. + // goes out of scope on the stack. We use emitByte() and not emitOp() here + // because we don't want to track that stack effect of these pops since the + // variables are still in scope after the break. if (compiler->locals[local].isUpvalue) { - emit(compiler, CODE_CLOSE_UPVALUE); + emitByte(compiler, CODE_CLOSE_UPVALUE); } else { - emit(compiler, CODE_POP); + emitByte(compiler, CODE_POP); } + local--; } @@ -1252,7 +1286,9 @@ static int discardLocals(Compiler* compiler, int depth) // temporaries are still on the stack. static void popScope(Compiler* compiler) { - compiler->numLocals -= discardLocals(compiler, compiler->scopeDepth); + int popped = discardLocals(compiler, compiler->scopeDepth); + compiler->numLocals -= popped; + compiler->numSlots -= popped; compiler->scopeDepth--; } @@ -1382,7 +1418,7 @@ static void loadLocal(Compiler* compiler, int slot) { if (slot <= 8) { - emit(compiler, CODE_LOAD_LOCAL_0 + slot); + emitOp(compiler, (Code)(CODE_LOAD_LOCAL_0 + slot)); return; } @@ -1416,7 +1452,7 @@ static ObjFn* endCompiler(Compiler* compiler, // Mark the end of the bytecode. Since it may contain multiple early returns, // we can't rely on CODE_RETURN to tell us we're at the end. - emit(compiler, CODE_END); + emitOp(compiler, CODE_END); // Create a function object for the code we just compiled. ObjFn* fn = wrenNewFunction(compiler->parser->vm, @@ -1424,6 +1460,7 @@ static ObjFn* endCompiler(Compiler* compiler, compiler->constants.data, compiler->constants.count, compiler->numUpvalues, + compiler->maxSlots, compiler->numParams, compiler->bytecode.data, compiler->bytecode.count, @@ -1454,8 +1491,8 @@ static ObjFn* endCompiler(Compiler* compiler, // an upvalue. for (int i = 0; i < compiler->numUpvalues; i++) { - emit(compiler->parent, compiler->upvalues[i].isLocal ? 1 : 0); - emit(compiler->parent, compiler->upvalues[i].index); + emitByte(compiler->parent, compiler->upvalues[i].isLocal ? 1 : 0); + emitByte(compiler->parent, compiler->upvalues[i].index); } } } @@ -1574,23 +1611,28 @@ static bool finishBlock(Compiler* compiler) // In that case, this adds the code to ensure it returns `this`. static void finishBody(Compiler* compiler, bool isInitializer) { + // Now that the parameter list has been compiled, we know how many slots they + // use. + compiler->numSlots = compiler->numLocals; + compiler->maxSlots = compiler->numLocals; + bool isExpressionBody = finishBlock(compiler); if (isInitializer) { // If the initializer body evaluates to a value, discard it. - if (isExpressionBody) emit(compiler, CODE_POP); + if (isExpressionBody) emitOp(compiler, CODE_POP); // The receiver is always stored in the first local slot. - emit(compiler, CODE_LOAD_LOCAL_0); + emitOp(compiler, CODE_LOAD_LOCAL_0); } else if (!isExpressionBody) { // Implicitly return null in statement bodies. - emit(compiler, CODE_NULL); + emitOp(compiler, CODE_NULL); } - emit(compiler, CODE_RETURN); + emitOp(compiler, CODE_RETURN); } // The VM can only handle a certain number of parameters, so check that we @@ -1971,8 +2013,8 @@ static void unaryOp(Compiler* compiler, bool allowAssignment) static void boolean(Compiler* compiler, bool allowAssignment) { - emit(compiler, - compiler->parser->previous.type == TOKEN_FALSE ? CODE_FALSE : CODE_TRUE); + emitOp(compiler, + compiler->parser->previous.type == TOKEN_FALSE ? CODE_FALSE : CODE_TRUE); } // Walks the compiler chain to find the compiler for the nearest class @@ -2119,7 +2161,7 @@ static void staticField(Compiler* compiler, bool allowAssignment) int symbol = declareVariable(classCompiler, NULL); // Implicitly initialize it to null. - emit(classCompiler, CODE_NULL); + emitOp(classCompiler, CODE_NULL); defineVariable(classCompiler, symbol); } @@ -2199,7 +2241,7 @@ static void name(Compiler* compiler, bool allowAssignment) static void null(Compiler* compiler, bool allowAssignment) { - emit(compiler, CODE_NULL); + emitOp(compiler, CODE_NULL); } // A number or string literal. @@ -2642,7 +2684,7 @@ void block(Compiler* compiler) if (finishBlock(compiler)) { // Block was an expression, so discard it. - emit(compiler, CODE_POP); + emitOp(compiler, CODE_POP); } popScope(compiler); return; @@ -2993,14 +3035,14 @@ void statement(Compiler* compiler) if (peek(compiler) == TOKEN_LINE) { // Implicitly return null if there is no value. - emit(compiler, CODE_NULL); + emitOp(compiler, CODE_NULL); } else { expression(compiler); } - emit(compiler, CODE_RETURN); + emitOp(compiler, CODE_RETURN); return; } @@ -3011,7 +3053,7 @@ void statement(Compiler* compiler) // Expression statement. expression(compiler); - emit(compiler, CODE_POP); + emitOp(compiler, CODE_POP); } // Creates a matching constructor method for an initializer with [signature] @@ -3033,9 +3075,11 @@ static void createConstructor(Compiler* compiler, Signature* signature, { Compiler methodCompiler; initCompiler(&methodCompiler, compiler->parser, compiler, false); + methodCompiler.numSlots = signature->arity + 1; + methodCompiler.maxSlots = methodCompiler.numSlots; // Allocate the instance. - emit(&methodCompiler, compiler->enclosingClass->isForeign + emitOp(&methodCompiler, compiler->enclosingClass->isForeign ? CODE_FOREIGN_CONSTRUCT : CODE_CONSTRUCT); // Run its initializer. @@ -3043,7 +3087,7 @@ static void createConstructor(Compiler* compiler, Signature* signature, initializerSymbol); // Return the instance. - emit(&methodCompiler, CODE_RETURN); + emitOp(&methodCompiler, CODE_RETURN); endCompiler(&methodCompiler, "", 0); } @@ -3178,7 +3222,7 @@ static void classDefinition(Compiler* compiler, bool isForeign) int numFieldsInstruction = -1; if (isForeign) { - emit(compiler, CODE_FOREIGN_CLASS); + emitOp(compiler, CODE_FOREIGN_CLASS); } else { @@ -3245,7 +3289,7 @@ static void import(Compiler* compiler) emitShortArg(compiler, CODE_LOAD_MODULE, moduleConstant); // Discard the unused result value from calling the module's fiber. - emit(compiler, CODE_POP); + emitOp(compiler, CODE_POP); // The for clause is optional. if (!match(compiler, TOKEN_FOR)) return; @@ -3368,8 +3412,8 @@ ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source, } } - emit(&compiler, CODE_NULL); - emit(&compiler, CODE_RETURN); + emitOp(&compiler, CODE_NULL); + emitOp(&compiler, CODE_RETURN); // See if there are any implicitly declared module-level variables that never // got an explicit definition. diff --git a/src/vm/wren_debug.c b/src/vm/wren_debug.c index 429eff6f..8914d81c 100644 --- a/src/vm/wren_debug.c +++ b/src/vm/wren_debug.c @@ -349,7 +349,9 @@ int wrenDumpInstruction(WrenVM* vm, ObjFn* fn, int i) void wrenDumpCode(WrenVM* vm, ObjFn* fn) { - printf("%s: %s\n", fn->module->name->value, fn->debug->name); + printf("%s: %s\n", + fn->module->name == NULL ? "" : fn->module->name->value, + fn->debug->name); int i = 0; int lastLine = -1; diff --git a/src/vm/wren_opcodes.h b/src/vm/wren_opcodes.h index 1626bf22..4a6e7592 100644 --- a/src/vm/wren_opcodes.h +++ b/src/vm/wren_opcodes.h @@ -1,6 +1,11 @@ // 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. +// included. (See: http://en.wikipedia.org/wiki/X_Macro for more.) +// +// The first argument is the name of the opcode. The second is its "stack +// effect" -- the amount that the op code changes the size of the stack. A +// stack effect of 1 means it pushes a value and the stack grows one larger. +// -2 means it pops two values, etc. // // 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 @@ -8,137 +13,136 @@ // order here. // Load the constant at index [arg]. -OPCODE(CONSTANT) +OPCODE(CONSTANT, 1) // Push null onto the stack. -OPCODE(NULL) +OPCODE(NULL, 1) // Push false onto the stack. -OPCODE(FALSE) +OPCODE(FALSE, 1) // Push true onto the stack. -OPCODE(TRUE) +OPCODE(TRUE, 1) // 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) +OPCODE(LOAD_LOCAL_0, 1) +OPCODE(LOAD_LOCAL_1, 1) +OPCODE(LOAD_LOCAL_2, 1) +OPCODE(LOAD_LOCAL_3, 1) +OPCODE(LOAD_LOCAL_4, 1) +OPCODE(LOAD_LOCAL_5, 1) +OPCODE(LOAD_LOCAL_6, 1) +OPCODE(LOAD_LOCAL_7, 1) +OPCODE(LOAD_LOCAL_8, 1) // 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) +OPCODE(LOAD_LOCAL, 1) // Stores the top of stack in local slot [arg]. Does not pop it. -OPCODE(STORE_LOCAL) +OPCODE(STORE_LOCAL, 0) // Pushes the value in upvalue [arg]. -OPCODE(LOAD_UPVALUE) +OPCODE(LOAD_UPVALUE, 1) // Stores the top of stack in upvalue [arg]. Does not pop it. -OPCODE(STORE_UPVALUE) +OPCODE(STORE_UPVALUE, 0) // Pushes the value of the top-level variable in slot [arg]. -OPCODE(LOAD_MODULE_VAR) +OPCODE(LOAD_MODULE_VAR, 1) // Stores the top of stack in top-level variable slot [arg]. Does not pop it. -OPCODE(STORE_MODULE_VAR) +OPCODE(STORE_MODULE_VAR, 0) // 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) +OPCODE(LOAD_FIELD_THIS, 1) // 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) +OPCODE(STORE_FIELD_THIS, 0) // Pops an instance and pushes the value of the field in slot [arg] of it. -OPCODE(LOAD_FIELD) +OPCODE(LOAD_FIELD, 0) // Pops an instance and stores the subsequent top of stack in field slot // [arg] in it. Does not pop the value. -OPCODE(STORE_FIELD) +OPCODE(STORE_FIELD, -1) // Pop and discard the top of stack. -OPCODE(POP) +OPCODE(POP, -1) // Push a copy of the value currently on the top of the stack. -OPCODE(DUP) +OPCODE(DUP, 1) // 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) +OPCODE(CALL_0, 0) +OPCODE(CALL_1, -1) +OPCODE(CALL_2, -2) +OPCODE(CALL_3, -3) +OPCODE(CALL_4, -4) +OPCODE(CALL_5, -5) +OPCODE(CALL_6, -6) +OPCODE(CALL_7, -7) +OPCODE(CALL_8, -8) +OPCODE(CALL_9, -9) +OPCODE(CALL_10, -10) +OPCODE(CALL_11, -11) +OPCODE(CALL_12, -12) +OPCODE(CALL_13, -13) +OPCODE(CALL_14, -14) +OPCODE(CALL_15, -15) +OPCODE(CALL_16, -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) +OPCODE(SUPER_0, 0) +OPCODE(SUPER_1, -1) +OPCODE(SUPER_2, -2) +OPCODE(SUPER_3, -3) +OPCODE(SUPER_4, -4) +OPCODE(SUPER_5, -5) +OPCODE(SUPER_6, -6) +OPCODE(SUPER_7, -7) +OPCODE(SUPER_8, -8) +OPCODE(SUPER_9, -9) +OPCODE(SUPER_10, -10) +OPCODE(SUPER_11, -11) +OPCODE(SUPER_12, -12) +OPCODE(SUPER_13, -13) +OPCODE(SUPER_14, -14) +OPCODE(SUPER_15, -15) +OPCODE(SUPER_16, -16) // Jump the instruction pointer [arg] forward. -OPCODE(JUMP) +OPCODE(JUMP, 0) -// Jump the instruction pointer [arg] backward. Pop and discard the top of -// the stack. -OPCODE(LOOP) +// Jump the instruction pointer [arg] backward. +OPCODE(LOOP, 0) // Pop and if not truthy then jump the instruction pointer [arg] forward. -OPCODE(JUMP_IF) +OPCODE(JUMP_IF, -1) // If the top of the stack is false, jump [arg] forward. Otherwise, pop and // continue. -OPCODE(AND) +OPCODE(AND, -1) // If the top of the stack is non-false, jump [arg] forward. Otherwise, pop // and continue. -OPCODE(OR) +OPCODE(OR, -1) // Close the upvalue for the local on the top of the stack, then pop it. -OPCODE(CLOSE_UPVALUE) +OPCODE(CLOSE_UPVALUE, -1) // Exit from the current function and return the value on the top of the // stack. -OPCODE(RETURN) +OPCODE(RETURN, 0) // Creates a closure for the function stored at [arg] in the constant table. // @@ -148,29 +152,29 @@ OPCODE(RETURN) // upvalue being captured. // // Pushes the created closure. -OPCODE(CLOSURE) +OPCODE(CLOSURE, 1) // Creates a new instance of a class. // // Assumes the class object is in slot zero, and replaces it with the new // uninitialized instance of that class. This opcode is only emitted by the // compiler-generated constructor metaclass methods. -OPCODE(CONSTRUCT) +OPCODE(CONSTRUCT, 0) // Creates a new instance of a foreign class. // // Assumes the class object is in slot zero, and replaces it with the new // uninitialized instance of that class. This opcode is only emitted by the // compiler-generated constructor metaclass methods. -OPCODE(FOREIGN_CONSTRUCT) +OPCODE(FOREIGN_CONSTRUCT, 0) // Creates a class. Top of stack is the superclass. Below that is a string for // the name of the class. Byte [arg] is the number of fields in the class. -OPCODE(CLASS) +OPCODE(CLASS, -1) // Creates a foreign class. Top of stack is the superclass. Below that is a // string for the name of the class. -OPCODE(FOREIGN_CLASS) +OPCODE(FOREIGN_CLASS, -1) // Define a method for symbol [arg]. The class receiving the method is popped // off the stack, then the function defining the body is popped. @@ -178,7 +182,7 @@ OPCODE(FOREIGN_CLASS) // 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) +OPCODE(METHOD_INSTANCE, -2) // 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 @@ -187,20 +191,20 @@ OPCODE(METHOD_INSTANCE) // 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) +OPCODE(METHOD_STATIC, -2) // 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) +OPCODE(LOAD_MODULE, 1) // 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) +OPCODE(IMPORT_VARIABLE, 1) // 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) \ No newline at end of file +OPCODE(END, 0) diff --git a/src/vm/wren_value.c b/src/vm/wren_value.c index 748b4679..3697e677 100644 --- a/src/vm/wren_value.c +++ b/src/vm/wren_value.c @@ -186,7 +186,7 @@ ObjForeign* wrenNewForeign(WrenVM* vm, ObjClass* classObj, size_t size) ObjFn* wrenNewFunction(WrenVM* vm, ObjModule* module, const Value* constants, int numConstants, - int numUpvalues, int arity, + int numUpvalues, int maxSlots, int arity, uint8_t* bytecode, int bytecodeLength, const char* debugName, int debugNameLength, int* sourceLines) @@ -222,6 +222,7 @@ ObjFn* wrenNewFunction(WrenVM* vm, ObjModule* module, fn->bytecode = bytecode; fn->constants = copiedConstants; fn->module = module; + fn->maxSlots = maxSlots; fn->numUpvalues = numUpvalues; fn->numConstants = numConstants; fn->arity = arity; diff --git a/src/vm/wren_value.h b/src/vm/wren_value.h index d2dcfa54..a891f1e7 100644 --- a/src/vm/wren_value.h +++ b/src/vm/wren_value.h @@ -303,6 +303,9 @@ typedef struct // The module where this function was defined. ObjModule* module; + // The maximum number of stack slots this function may use. + int maxSlots; + int numUpvalues; int numConstants; @@ -660,7 +663,7 @@ ObjForeign* wrenNewForeign(WrenVM* vm, ObjClass* classObj, size_t size); // copy [constants] into its own array. ObjFn* wrenNewFunction(WrenVM* vm, ObjModule* module, const Value* constants, int numConstants, - int numUpvalues, int arity, + int numUpvalues, int maxSlots, int arity, uint8_t* bytecode, int bytecodeLength, const char* debugName, int debugNameLength, int* sourceLines); diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index af6a235f..c0a00b8e 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -777,7 +777,7 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber) #if WREN_COMPUTED_GOTO static void* dispatchTable[] = { - #define OPCODE(name) &&code_##name, + #define OPCODE(name, _) &&code_##name, #include "wren_opcodes.h" #undef OPCODE }; @@ -1293,7 +1293,7 @@ static ObjFn* makeCallStub(WrenVM* vm, ObjModule* module, const char* signature) int* debugLines = ALLOCATE_ARRAY(vm, int, 5); memset(debugLines, 1, 5); - return wrenNewFunction(vm, module, NULL, 0, 0, 0, bytecode, 5, + return wrenNewFunction(vm, module, NULL, 0, 0, numParams + 1, 0, bytecode, 5, signature, signatureLength, debugLines); } diff --git a/src/vm/wren_vm.h b/src/vm/wren_vm.h index 9b613a80..ed6a810d 100644 --- a/src/vm/wren_vm.h +++ b/src/vm/wren_vm.h @@ -12,7 +12,7 @@ typedef enum { - #define OPCODE(name) CODE_##name, + #define OPCODE(name, _) CODE_##name, #include "wren_opcodes.h" #undef OPCODE } Code;