diff --git a/src/compiler/BytecodeGenerator.cpp b/src/compiler/BytecodeGenerator.cpp index 187852a6..ce9147be 100644 --- a/src/compiler/BytecodeGenerator.cpp +++ b/src/compiler/BytecodeGenerator.cpp @@ -38,6 +38,7 @@ #include "../vmobjects/Signature.h" #include "../vmobjects/VMMethod.h" #include "../vmobjects/VMSymbol.h" +#include "MethodGenerationContext.h" void Emit1(MethodGenerationContext& mgenc, uint8_t bytecode, int64_t stackEffect) { @@ -298,21 +299,31 @@ void EmitDupSecond(MethodGenerationContext& mgenc) { Emit1(mgenc, BC_DUP_SECOND, 1); } -size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc, - bool isIfTrue, bool needsPop) { +size_t EmitJumpOnWithDummyOffset(MethodGenerationContext& mgenc, + JumpCondition condition, bool needsPop) { // Remember: true and false seem flipped here. // This is because if the test passes, the block is inlined directly. // But if the test fails, we need to jump. // Thus, an `#ifTrue:` needs to generated a jump_on_false. uint8_t bc = 0; - int64_t stackEffect = 0; + int64_t const stackEffect = needsPop ? -1 : 0; - if (needsPop) { - bc = isIfTrue ? BC_JUMP_ON_FALSE_POP : BC_JUMP_ON_TRUE_POP; - stackEffect = -1; - } else { - bc = isIfTrue ? BC_JUMP_ON_FALSE_TOP_NIL : BC_JUMP_ON_TRUE_TOP_NIL; - stackEffect = 0; + switch (condition) { + case JumpCondition::ON_TRUE: + bc = needsPop ? BC_JUMP_ON_TRUE_POP : BC_JUMP_ON_TRUE_TOP_NIL; + break; + + case JumpCondition::ON_FALSE: + bc = needsPop ? BC_JUMP_ON_FALSE_POP : BC_JUMP_ON_FALSE_TOP_NIL; + break; + + case JumpCondition::ON_NIL: + bc = needsPop ? BC_JUMP_ON_NIL_POP : BC_JUMP_ON_NIL_TOP_TOP; + break; + + case JumpCondition::ON_NOT_NIL: + bc = needsPop ? BC_JUMP_ON_NOT_NIL_POP : BC_JUMP_ON_NOT_NIL_TOP_TOP; + break; } Emit1(mgenc, bc, stackEffect); diff --git a/src/compiler/BytecodeGenerator.h b/src/compiler/BytecodeGenerator.h index f250474e..8f077427 100644 --- a/src/compiler/BytecodeGenerator.h +++ b/src/compiler/BytecodeGenerator.h @@ -66,8 +66,8 @@ void EmitIncFieldPush(MethodGenerationContext& mgenc, uint8_t fieldIdx); void EmitDupSecond(MethodGenerationContext& mgenc); -size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc, - bool isIfTrue, bool needsPop); +size_t EmitJumpOnWithDummyOffset(MethodGenerationContext& mgenc, + JumpCondition condition, bool needsPop); size_t EmitJumpWithDumyOffset(MethodGenerationContext& mgenc); size_t EmitJumpIfGreaterWithDummyOffset(MethodGenerationContext& mgenc); void EmitJumpBackwardWithOffset(MethodGenerationContext& mgenc, diff --git a/src/compiler/Disassembler.cpp b/src/compiler/Disassembler.cpp index b29b8e75..077960be 100644 --- a/src/compiler/Disassembler.cpp +++ b/src/compiler/Disassembler.cpp @@ -96,12 +96,8 @@ void Disassembler::Dump(VMClass* cl) { VMSymbol* cname = cl->GetName(); DebugDump("%s>>%s = ", cname->GetStdString().c_str(), sig->GetStdString().c_str()); - if (inv->IsPrimitive()) { - DebugPrint("\n"); - continue; - } - // output actual method - DumpMethod(static_cast(inv), "\t"); + + inv->Dump("\t", true); } } @@ -154,6 +150,12 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, } switch (bytecode) { + case BC_PUSH_0: + case BC_PUSH_1: + case BC_PUSH_NIL: { + // no more details to be printed + break; + } case BC_PUSH_LOCAL_0: { DebugPrint("local: 0, context: 0\n"); break; @@ -199,11 +201,16 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, if (method != nullptr && printObjects) { vm_oop_t constant = method->GetConstant(bc_idx); VMClass* cl = CLASS_OF(constant); - VMSymbol* cname = cl->GetName(); - - DebugPrint("(index: %d) value: (%s) ", - bytecodes[bc_idx + 1], - cname->GetStdString().c_str()); + if (cl == nullptr) { + DebugPrint("(index: %d) value: (%s) ", + bytecodes[bc_idx + 1], + "class==nullptr"); + } else { + VMSymbol* cname = cl->GetName(); + DebugPrint("(index: %d) value: (%s) ", + bytecodes[bc_idx + 1], + cname->GetStdString().c_str()); + } dispatch(constant); } else { DebugPrint("(index: %d)", bytecodes[bc_idx + 1]); @@ -235,6 +242,15 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, DebugPrint("local: %d, context: %d\n", bytecodes[bc_idx + 1], bytecodes[bc_idx + 2]); break; + case BC_POP_LOCAL_0: + DebugPrint("local: 0, context: 0\n"); + break; + case BC_POP_LOCAL_1: + DebugPrint("local: 1, context: 0\n"); + break; + case BC_POP_LOCAL_2: + DebugPrint("local: 2, context: 0\n"); + break; case BC_POP_ARGUMENT: DebugPrint("argument: %d, context: %d\n", bytecodes[bc_idx + 1], bytecodes[bc_idx + 2]); @@ -266,7 +282,8 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, } break; } - case BC_SEND: { + case BC_SEND: + case BC_SEND_1: { if (method != nullptr && printObjects) { auto* name = static_cast(method->GetConstant(bc_idx)); @@ -295,12 +312,22 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, case BC_JUMP_ON_TRUE_POP: case BC_JUMP_ON_FALSE_TOP_NIL: case BC_JUMP_ON_TRUE_TOP_NIL: + case BC_JUMP_ON_NOT_NIL_POP: + case BC_JUMP_ON_NIL_POP: + case BC_JUMP_ON_NOT_NIL_TOP_TOP: + case BC_JUMP_ON_NIL_TOP_TOP: + case BC_JUMP_IF_GREATER: case BC_JUMP_BACKWARD: case BC_JUMP2: case BC_JUMP2_ON_FALSE_POP: case BC_JUMP2_ON_TRUE_POP: case BC_JUMP2_ON_FALSE_TOP_NIL: case BC_JUMP2_ON_TRUE_TOP_NIL: + case BC_JUMP2_ON_NOT_NIL_POP: + case BC_JUMP2_ON_NIL_POP: + case BC_JUMP2_ON_NOT_NIL_TOP_TOP: + case BC_JUMP2_ON_NIL_TOP_TOP: + case BC_JUMP2_IF_GREATER: case BC_JUMP2_BACKWARD: { uint16_t const offset = ComputeOffset(bytecodes[bc_idx + 1], bytecodes[bc_idx + 2]); @@ -331,6 +358,47 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, #define BC_1 method->GetBytecode(bc_idx + 1) #define BC_2 method->GetBytecode(bc_idx + 2) +void Disassembler::printArgument(uint8_t idx, uint8_t ctx, VMClass* cl, + VMFrame* frame) { + vm_oop_t o = frame->GetArgument(idx, ctx); + DebugPrint("argument: %d, context: %d", idx, ctx); + + if (cl != nullptr) { + VMClass* c = CLASS_OF(o); + VMSymbol* cname = c->GetName(); + + DebugPrint("<(%s) ", cname->GetStdString().c_str()); + dispatch(o); + DebugPrint(">"); + } + DebugPrint("\n"); +} + +void Disassembler::printPopLocal(uint8_t idx, uint8_t ctx, VMFrame* frame) { + vm_oop_t o = frame->GetStackElement(0); + VMClass* c = CLASS_OF(o); + VMSymbol* cname = c->GetName(); + + DebugPrint("popped local: %d, context: %d <(%s) ", idx, ctx, + cname->GetStdString().c_str()); + dispatch(o); + DebugPrint(">\n"); +} + +void Disassembler::printNth(uint8_t idx, VMFrame* frame, const char* op) { + vm_oop_t o = frame->GetStackElement(idx); + if (o != nullptr) { + VMClass* c = CLASS_OF(o); + VMSymbol* cname = c->GetName(); + + DebugPrint("GetStdString().c_str()); + dispatch(o); + } else { + DebugPrint("\n"); +} + /** * Dump bytecode from the frame running */ @@ -361,22 +429,30 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, } switch (bc) { + case BC_PUSH_0: + case BC_PUSH_1: + case BC_PUSH_NIL: { + // no more details to be printed + break; + } case BC_HALT: { DebugPrint("\n\n\n"); break; } case BC_DUP: { - vm_oop_t o = frame->GetStackElement(0); - if (o != nullptr) { - VMClass* c = CLASS_OF(o); - VMSymbol* cname = c->GetName(); - - DebugPrint("GetStdString().c_str()); - dispatch(o); - } else { - DebugPrint("\n"); + printNth(0, frame, "dup"); + break; + } + case BC_DUP_SECOND: { + printNth(1, frame, "dup-second"); + break; + } + case BC_INC: { + printNth(0, frame, "inc"); + break; + } + case BC_DEC: { + printNth(0, frame, "dec"); break; } case BC_PUSH_LOCAL: { @@ -425,21 +501,22 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, DebugPrint(">\n"); break; } + case BC_PUSH_SELF: { + printArgument(0, 0, cl, frame); + break; + } + case BC_PUSH_ARG_1: { + printArgument(1, 0, cl, frame); + break; + } + case BC_PUSH_ARG_2: { + printArgument(2, 0, cl, frame); + break; + } case BC_PUSH_ARGUMENT: { uint8_t const bc1 = BC_1; uint8_t const bc2 = BC_2; - vm_oop_t o = frame->GetArgument(bc1, bc2); - DebugPrint("argument: %d, context: %d", bc1, bc2); - - if (cl != nullptr) { - VMClass* c = CLASS_OF(o); - VMSymbol* cname = c->GetName(); - - DebugPrint("<(%s) ", cname->GetStdString().c_str()); - dispatch(o); - DebugPrint(">"); - } - DebugPrint("\n"); + printArgument(bc1, bc2, cl, frame); break; } case BC_PUSH_BLOCK: { @@ -493,14 +570,19 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, break; } case BC_POP_LOCAL: { - vm_oop_t o = frame->GetStackElement(0); - VMClass* c = CLASS_OF(o); - VMSymbol* cname = c->GetName(); - - DebugPrint("popped local: %d, context: %d <(%s) ", BC_1, BC_2, - cname->GetStdString().c_str()); - dispatch(o); - DebugPrint(">\n"); + printPopLocal(BC_1, BC_2, frame); + break; + } + case BC_POP_LOCAL_0: { + printPopLocal(0, 0, frame); + break; + } + case BC_POP_LOCAL_1: { + printPopLocal(1, 0, frame); + break; + } + case BC_POP_LOCAL_2: { + printPopLocal(2, 0, frame); break; } case BC_POP_ARGUMENT: { @@ -535,7 +617,8 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, break; } case BC_SUPER_SEND: - case BC_SEND: { + case BC_SEND: + case BC_SEND_1: { auto* sel = static_cast(method->GetConstant(bc_idx)); DebugPrint("(index: %d) signature: %s (", BC_1, @@ -567,12 +650,22 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, case BC_JUMP_ON_TRUE_POP: case BC_JUMP_ON_FALSE_TOP_NIL: case BC_JUMP_ON_TRUE_TOP_NIL: + case BC_JUMP_ON_NOT_NIL_POP: + case BC_JUMP_ON_NIL_POP: + case BC_JUMP_ON_NOT_NIL_TOP_TOP: + case BC_JUMP_ON_NIL_TOP_TOP: + case BC_JUMP_IF_GREATER: case BC_JUMP_BACKWARD: case BC_JUMP2: case BC_JUMP2_ON_FALSE_POP: case BC_JUMP2_ON_TRUE_POP: case BC_JUMP2_ON_FALSE_TOP_NIL: case BC_JUMP2_ON_TRUE_TOP_NIL: + case BC_JUMP2_ON_NOT_NIL_POP: + case BC_JUMP2_ON_NIL_POP: + case BC_JUMP2_ON_NOT_NIL_TOP_TOP: + case BC_JUMP2_ON_NIL_TOP_TOP: + case BC_JUMP2_IF_GREATER: case BC_JUMP2_BACKWARD: { uint16_t const offset = ComputeOffset(method->GetBytecode(bc_idx + 1), diff --git a/src/compiler/Disassembler.h b/src/compiler/Disassembler.h index f60e36ba..3bf0dc07 100644 --- a/src/compiler/Disassembler.h +++ b/src/compiler/Disassembler.h @@ -37,6 +37,9 @@ class Disassembler { static void DumpMethod(VMMethod* method, const char* indent, bool printObjects = true); static void DumpMethod(MethodGenerationContext* mgenc, const char* indent); + static void extracted(uint8_t bc1, uint8_t bc2, VMClass* cl, + VMFrame* frame); + static void DumpBytecode(VMFrame* frame, VMMethod* method, size_t bc_idx); private: @@ -45,4 +48,9 @@ class Disassembler { static void dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, const char* indent, VMMethod* method, bool printObjects); + + static void printArgument(uint8_t idx, uint8_t ctx, VMClass* cl, + VMFrame* frame); + static void printPopLocal(uint8_t idx, uint8_t ctx, VMFrame* frame); + static void printNth(uint8_t idx, VMFrame* frame, const char* op); }; diff --git a/src/compiler/MethodGenerationContext.cpp b/src/compiler/MethodGenerationContext.cpp index db40188d..88323fff 100644 --- a/src/compiler/MethodGenerationContext.cpp +++ b/src/compiler/MethodGenerationContext.cpp @@ -522,7 +522,7 @@ MethodGenerationContext::extractBlockMethodsAndRemoveBytecodes() { return {toBeInlined1, toBeInlined2}; } -bool MethodGenerationContext::InlineIfTrueOrIfFalse(bool isIfTrue) { +bool MethodGenerationContext::InlineThenBranch(JumpCondition condition) { // HACK: We do assume that the receiver on the stack is a boolean, // HACK: similar to the IfTrueIfFalseNode. // HACK: We don't support anything but booleans at the moment. @@ -534,7 +534,7 @@ bool MethodGenerationContext::InlineIfTrueOrIfFalse(bool isIfTrue) { VMInvokable* toBeInlined = extractBlockMethodAndRemoveBytecode(); size_t const jumpOffsetIdxToSkipBody = - EmitJumpOnBoolWithDummyOffset(*this, isIfTrue, false); + EmitJumpOnWithDummyOffset(*this, condition, false); isCurrentlyInliningABlock = true; @@ -548,7 +548,7 @@ bool MethodGenerationContext::InlineIfTrueOrIfFalse(bool isIfTrue) { return true; } -bool MethodGenerationContext::InlineIfTrueFalse(bool isIfTrue) { +bool MethodGenerationContext::InlineThenElseBranches(JumpCondition condition) { // HACK: We do assume that the receiver on the stack is a boolean, // HACK: similar to the IfTrueIfFalseNode. // HACK: We don't support anything but booleans at the moment. @@ -565,7 +565,7 @@ bool MethodGenerationContext::InlineIfTrueFalse(bool isIfTrue) { VMInvokable* bodyMethod = std::get<1>(methods); size_t const jumpOffsetIdxToSkipTrueBranch = - EmitJumpOnBoolWithDummyOffset(*this, isIfTrue, true); + EmitJumpOnWithDummyOffset(*this, condition, true); isCurrentlyInliningABlock = true; condMethod->InlineInto(*this); @@ -606,8 +606,8 @@ bool MethodGenerationContext::InlineWhile(Parser& parser, bool isWhileTrue) { isCurrentlyInliningABlock = true; condMethod->InlineInto(*this); - size_t const jumpOffsetIdxToSkipLoopBody = - EmitJumpOnBoolWithDummyOffset(*this, isWhileTrue, true); + size_t const jumpOffsetIdxToSkipLoopBody = EmitJumpOnWithDummyOffset( + *this, isWhileTrue ? ON_FALSE : ON_TRUE, true); bodyMethod->InlineInto(*this); @@ -632,7 +632,7 @@ bool MethodGenerationContext::InlineAndOr(bool isOr) { VMInvokable* toBeInlined = extractBlockMethodAndRemoveBytecode(); size_t const jumpOffsetIdxToSkipBranch = - EmitJumpOnBoolWithDummyOffset(*this, !isOr, true); + EmitJumpOnWithDummyOffset(*this, isOr ? ON_TRUE : ON_FALSE, true); isCurrentlyInliningABlock = true; toBeInlined->InlineInto(*this); diff --git a/src/compiler/MethodGenerationContext.h b/src/compiler/MethodGenerationContext.h index 3de8f4ab..451da83f 100644 --- a/src/compiler/MethodGenerationContext.h +++ b/src/compiler/MethodGenerationContext.h @@ -40,6 +40,8 @@ class Parser; #define NUM_LAST_BYTECODES 4 +enum JumpCondition : std::uint8_t { ON_TRUE, ON_FALSE, ON_NIL, ON_NOT_NIL }; + class MethodGenerationContext { public: explicit MethodGenerationContext(ClassGenerationContext& holder, @@ -102,8 +104,8 @@ class MethodGenerationContext { std::vector GetBytecodes() { return bytecode; } bool InlineWhile(Parser& parser, bool isWhileTrue); - bool InlineIfTrueOrIfFalse(bool isIfTrue); - bool InlineIfTrueFalse(bool isIfTrue); + bool InlineThenElseBranches(JumpCondition condition); + bool InlineThenBranch(JumpCondition condition); bool InlineAndOr(bool isOr); bool InlineToDo(); diff --git a/src/compiler/Parser.cpp b/src/compiler/Parser.cpp index 3d65d05f..c4d53808 100644 --- a/src/compiler/Parser.cpp +++ b/src/compiler/Parser.cpp @@ -52,6 +52,7 @@ #include "../vmobjects/VMSymbol.h" #include "BytecodeGenerator.h" #include "Lexer.h" +#include "MethodGenerationContext.h" void Parser::GetSym() { sym = lexer.GetSym(); @@ -678,8 +679,14 @@ void Parser::keywordMessage(MethodGenerationContext& mgenc, bool super) { if (!super) { if (numParts == 1 && - ((kw == "ifTrue:" && mgenc.InlineIfTrueOrIfFalse(true)) || - (kw == "ifFalse:" && mgenc.InlineIfTrueOrIfFalse(false)) || + ((kw == "ifTrue:" && + mgenc.InlineThenBranch(JumpCondition::ON_FALSE)) || + (kw == "ifFalse:" && + mgenc.InlineThenBranch(JumpCondition::ON_TRUE)) || + (kw == "ifNil:" && + mgenc.InlineThenBranch(JumpCondition::ON_NOT_NIL)) || + (kw == "ifNotNil:" && + mgenc.InlineThenBranch(JumpCondition::ON_NIL)) || (kw == "whileTrue:" && mgenc.InlineWhile(*this, true)) || (kw == "whileFalse:" && mgenc.InlineWhile(*this, false)) || (kw == "or:" && mgenc.InlineAndOr(true)) || @@ -688,8 +695,14 @@ void Parser::keywordMessage(MethodGenerationContext& mgenc, bool super) { } if (numParts == 2 && - ((kw == "ifTrue:ifFalse:" && mgenc.InlineIfTrueFalse(true)) || - (kw == "ifFalse:ifTrue:" && mgenc.InlineIfTrueFalse(false)) || + ((kw == "ifTrue:ifFalse:" && + mgenc.InlineThenElseBranches(JumpCondition::ON_FALSE)) || + (kw == "ifFalse:ifTrue:" && + mgenc.InlineThenElseBranches(JumpCondition::ON_TRUE)) || + (kw == "ifNil:ifNotNil:" && + mgenc.InlineThenElseBranches(JumpCondition::ON_NOT_NIL)) || + (kw == "ifNotNil:ifNil:" && + mgenc.InlineThenElseBranches(JumpCondition::ON_NIL)) || (kw == "to:do:" && mgenc.InlineToDo()))) { return; } diff --git a/src/interpreter/InterpreterLoop.h b/src/interpreter/InterpreterLoop.h index f9297ed2..954de244 100644 --- a/src/interpreter/InterpreterLoop.h +++ b/src/interpreter/InterpreterLoop.h @@ -55,6 +55,10 @@ vm_oop_t Start() { &&LABEL_BC_JUMP_ON_TRUE_POP, &&LABEL_BC_JUMP_ON_FALSE_TOP_NIL, &&LABEL_BC_JUMP_ON_TRUE_TOP_NIL, + &&LABEL_BC_JUMP_ON_NOT_NIL_POP, + &&LABEL_BC_JUMP_ON_NIL_POP, + &&LABEL_BC_JUMP_ON_NOT_NIL_TOP_TOP, + &&LABEL_BC_JUMP_ON_NIL_TOP_TOP, &&LABEL_BC_JUMP_IF_GREATER, &&LABEL_BC_JUMP_BACKWARD, &&LABEL_BC_JUMP2, @@ -62,6 +66,10 @@ vm_oop_t Start() { &&LABEL_BC_JUMP2_ON_TRUE_POP, &&LABEL_BC_JUMP2_ON_FALSE_TOP_NIL, &&LABEL_BC_JUMP2_ON_TRUE_TOP_NIL, + &&LABEL_BC_JUMP2_ON_NOT_NIL_POP, + &&LABEL_BC_JUMP2_ON_NIL_POP, + &&LABEL_BC_JUMP2_ON_NOT_NIL_TOP_TOP, + &&LABEL_BC_JUMP2_ON_NIL_TOP_TOP, &&LABEL_BC_JUMP2_IF_GREATER, &&LABEL_BC_JUMP2_BACKWARD}; @@ -300,7 +308,13 @@ LABEL_BC_RETURN_SELF: { LABEL_BC_INC: PROLOGUE(1); doInc(); +#if USE_TAGGING DISPATCH_NOGC(); +#else +// without integer tagging doInc() allocates memory and the IfNil benchmark +// will allocate, but not reach a GC point, and run out of memory +DISPATCH_GC(); +#endif LABEL_BC_DEC: PROLOGUE(1); @@ -373,6 +387,56 @@ LABEL_BC_JUMP_ON_TRUE_TOP_NIL: { } DISPATCH_NOGC(); +LABEL_BC_JUMP_ON_NOT_NIL_POP: { + vm_oop_t val = GetFrame()->Top(); + if (val != load_ptr(nilObject)) { + uint8_t const offset = currentBytecodes[bytecodeIndexGlobal + 1]; + bytecodeIndexGlobal += offset; + } else { + bytecodeIndexGlobal += 3; + } + GetFrame()->PopVoid(); +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP_ON_NIL_POP: { + vm_oop_t val = GetFrame()->Top(); + if (val == load_ptr(nilObject)) { + uint8_t const offset = currentBytecodes[bytecodeIndexGlobal + 1]; + bytecodeIndexGlobal += offset; + } else { + bytecodeIndexGlobal += 3; + } + GetFrame()->PopVoid(); +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP_ON_NOT_NIL_TOP_TOP: { + vm_oop_t val = GetFrame()->Top(); + if (val != load_ptr(nilObject)) { + uint8_t const offset = currentBytecodes[bytecodeIndexGlobal + 1]; + bytecodeIndexGlobal += offset; + // GetFrame()->SetTop(val); + } else { + GetFrame()->PopVoid(); + bytecodeIndexGlobal += 3; + } +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP_ON_NIL_TOP_TOP: { + vm_oop_t val = GetFrame()->Top(); + if (val == load_ptr(nilObject)) { + uint8_t const offset = currentBytecodes[bytecodeIndexGlobal + 1]; + bytecodeIndexGlobal += offset; + // GetFrame()->SetTop(val); + } else { + GetFrame()->PopVoid(); + bytecodeIndexGlobal += 3; + } +} + DISPATCH_NOGC(); + LABEL_BC_JUMP_IF_GREATER: { if (checkIsGreater()) { bytecodeIndexGlobal += currentBytecodes[bytecodeIndexGlobal + 1]; @@ -456,6 +520,64 @@ LABEL_BC_JUMP2_ON_TRUE_TOP_NIL: { } DISPATCH_NOGC(); +LABEL_BC_JUMP2_ON_NOT_NIL_POP: { + vm_oop_t val = GetFrame()->Top(); + if (val != load_ptr(nilObject)) { + uint16_t const offset = + ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1], + currentBytecodes[bytecodeIndexGlobal + 2]); + bytecodeIndexGlobal += offset; + } else { + bytecodeIndexGlobal += 3; + } + GetFrame()->PopVoid(); +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP2_ON_NIL_POP: { + vm_oop_t val = GetFrame()->Top(); + if (val == load_ptr(nilObject)) { + uint16_t const offset = + ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1], + currentBytecodes[bytecodeIndexGlobal + 2]); + bytecodeIndexGlobal += offset; + } else { + bytecodeIndexGlobal += 3; + } + GetFrame()->PopVoid(); +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP2_ON_NOT_NIL_TOP_TOP: { + vm_oop_t val = GetFrame()->Top(); + if (val != load_ptr(nilObject)) { + uint16_t const offset = + ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1], + currentBytecodes[bytecodeIndexGlobal + 2]); + bytecodeIndexGlobal += offset; + // GetFrame()->SetTop(val); + } else { + GetFrame()->PopVoid(); + bytecodeIndexGlobal += 3; + } +} + DISPATCH_NOGC(); + +LABEL_BC_JUMP2_ON_NIL_TOP_TOP: { + vm_oop_t val = GetFrame()->Top(); + if (val == load_ptr(nilObject)) { + uint16_t const offset = + ComputeOffset(currentBytecodes[bytecodeIndexGlobal + 1], + currentBytecodes[bytecodeIndexGlobal + 2]); + bytecodeIndexGlobal += offset; + // GetFrame()->SetTop(val); + } else { + GetFrame()->PopVoid(); + bytecodeIndexGlobal += 3; + } +} + DISPATCH_NOGC(); + LABEL_BC_JUMP2_IF_GREATER: { if (checkIsGreater()) { bytecodeIndexGlobal += diff --git a/src/interpreter/bytecodes.cpp b/src/interpreter/bytecodes.cpp index 975e84ce..1c1b4e27 100644 --- a/src/interpreter/bytecodes.cpp +++ b/src/interpreter/bytecodes.cpp @@ -81,6 +81,10 @@ const uint8_t Bytecode::bytecodeLengths[] = { 3, // BC_JUMP_ON_TRUE_POP 3, // BC_JUMP_ON_FALSE_TOP_NIL 3, // BC_JUMP_ON_TRUE_TOP_NIL + 3, // BC_JUMP_ON_NOT_NIL_POP + 3, // BC_JUMP_ON_NIL_POP + 3, // BC_JUMP_ON_NOT_NIL_TOP_TOP + 3, // BC_JUMP_ON_NIL_TOP_TOP 3, // BC_JUMP_IF_GREATER 3, // BC_JUMP_BACKWARD @@ -89,75 +93,87 @@ const uint8_t Bytecode::bytecodeLengths[] = { 3, // BC_JUMP2_ON_TRUE_POP 3, // BC_JUMP2_ON_FALSE_TOP_NIL 3, // BC_JUMP2_ON_TRUE_TOP_NIL + 3, // BC_JUMP2_ON_NOT_NIL_POP + 3, // BC_JUMP2_ON_NIL_POP + 3, // BC_JUMP2_ON_NOT_NIL_TOP_TOP + 3, // BC_JUMP2_ON_NIL_TOP_TOP 3, // BC_JUMP2_IF_GREATER 3, // BC_JUMP2_BACKWARD }; const char* Bytecode::bytecodeNames[] = { - "HALT ", // 0 - "DUP ", // 1 - "DUP_SECOND ", // 2 - "PUSH_LOCAL ", // 3 - "PUSH_LOCAL_0 ", // 4 - "PUSH_LOCAL_1 ", // 5 - "PUSH_LOCAL_2 ", // 6 - "PUSH_ARGUMENT ", // 7 - "PUSH_SELF ", // 8 - "PUSH_ARG_1 ", // 9 - "PUSH_ARG_2 ", // 10 - "PUSH_FIELD ", // 11 - "PUSH_FIELD_0 ", // 12 - "PUSH_FIELD_1 ", // 13 - "PUSH_BLOCK ", // 14 - "PUSH_CONSTANT ", // 15 - "PUSH_CONSTANT_0 ", // 16 - "PUSH_CONSTANT_1 ", // 17 - "PUSH_CONSTANT_2 ", // 18 - "PUSH_0 ", // 19 - "PUSH_1 ", // 20 - "PUSH_NIL ", // 21 - "PUSH_GLOBAL ", // 22 - "POP ", // 23 - "POP_LOCAL ", // 24 - "POP_LOCAL_0 ", // 25 - "POP_LOCAL_1 ", // 26 - "POP_LOCAL_2 ", // 27 - "POP_ARGUMENT ", // 28 - "POP_FIELD ", // 29 - "POP_FIELD_0 ", // 30 - "POP_FIELD_1 ", // 31 - "SEND ", // 32 - "SEND_1 ", // 33 - "SUPER_SEND ", // 34 - "RETURN_LOCAL ", // 35 - "RETURN_NON_LOCAL", // 36 - "RETURN_SELF ", // 37 - "RETURN_FIELD_0 ", // 38 - "RETURN_FIELD_1 ", // 39 - "RETURN_FIELD_2 ", // 40 - "INC ", // 41 - "DEC ", // 42 - "INC_FIELD ", // 43 - "INC_FIELD_PUSH ", // 44 - "JUMP ", // 45 - "JUMP_ON_FALSE_POP", // 46 - "JUMP_ON_TRUE_POP", // 47 - "JUMP_ON_FALSE_TOP_NIL", // 48 - "JUMP_ON_TRUE_TOP_NIL", // 49 - "JUMP_IF_GREATER ", // 50 - "JUMP_BACKWARD ", // 51 - "JUMP2 ", // 52 - "JUMP2_ON_FALSE_POP", // 53 - "JUMP2_ON_TRUE_POP", // 54 - "JUMP2_ON_FALSE_TOP_NIL", // 55 - "JUMP2_ON_TRUE_TOP_NIL", // 56 - "JUMP2_IF_GREATER", // 57 - "JUMP2_BACKWARD ", // 58 + "HALT ", // 0 + "DUP ", // 1 + "DUP_SECOND ", // 2 + "PUSH_LOCAL ", // 3 + "PUSH_LOCAL_0 ", // 4 + "PUSH_LOCAL_1 ", // 5 + "PUSH_LOCAL_2 ", // 6 + "PUSH_ARGUMENT ", // 7 + "PUSH_SELF ", // 8 + "PUSH_ARG_1 ", // 9 + "PUSH_ARG_2 ", // 10 + "PUSH_FIELD ", // 11 + "PUSH_FIELD_0 ", // 12 + "PUSH_FIELD_1 ", // 13 + "PUSH_BLOCK ", // 14 + "PUSH_CONSTANT ", // 15 + "PUSH_CONSTANT_0 ", // 16 + "PUSH_CONSTANT_1 ", // 17 + "PUSH_CONSTANT_2 ", // 18 + "PUSH_0 ", // 19 + "PUSH_1 ", // 20 + "PUSH_NIL ", // 21 + "PUSH_GLOBAL ", // 22 + "POP ", // 23 + "POP_LOCAL ", // 24 + "POP_LOCAL_0 ", // 25 + "POP_LOCAL_1 ", // 26 + "POP_LOCAL_2 ", // 27 + "POP_ARGUMENT ", // 28 + "POP_FIELD ", // 29 + "POP_FIELD_0 ", // 30 + "POP_FIELD_1 ", // 31 + "SEND ", // 32 + "SEND_1 ", // 33 + "SUPER_SEND ", // 34 + "RETURN_LOCAL ", // 35 + "RETURN_NON_LOCAL", // 36 + "RETURN_SELF ", // 37 + "RETURN_FIELD_0 ", // 38 + "RETURN_FIELD_1 ", // 39 + "RETURN_FIELD_2 ", // 40 + "INC ", // 41 + "DEC ", // 42 + "INC_FIELD ", // 43 + "INC_FIELD_PUSH ", // 44 + "JUMP ", // 45 + "JUMP_ON_FALSE_POP", // 46 + "JUMP_ON_TRUE_POP", // 47 + "JUMP_ON_FALSE_TOP_NIL", // 48 + "JUMP_ON_TRUE_TOP_NIL", // 49 + "JUMP_ON_NOT_NIL_POP", // 50 + "JUMP_ON_NIL_POP ", // 51 + "JUMP_ON_NOT_NIL_TOP_TOP", // 52 + "JUMP_ON_NIL_TOP_TOP", // 53 + "JUMP_IF_GREATER ", // 54 + "JUMP_BACKWARD ", // 55 + "JUMP2 ", // 56 + "JUMP2_ON_FALSE_POP", // 57 + "JUMP2_ON_TRUE_POP", // 58 + "JUMP2_ON_FALSE_TOP_NIL", // 59 + "JUMP2_ON_TRUE_TOP_NIL", // 60 + "JUMP2_ON_NOT_NIL_POP", // 61 + "JUMP2_ON_NIL_POP ", // 62 + "JUMP2_ON_NOT_NIL_TOP_TOP", // 63 + "JUMP2_ON_NIL_TOP_TOP", // 64 + "JUMP2_IF_GREATER", // 65 + "JUMP2_BACKWARD ", // 66 }; bool IsJumpBytecode(uint8_t bc) { static_assert(BC_JUMP < BC_JUMP2_BACKWARD); - static_assert((BC_JUMP2_BACKWARD - BC_JUMP) == 13); + static_assert((BC_JUMP2_BACKWARD - BC_JUMP) == 21); return BC_JUMP <= bc && bc <= BC_JUMP2_BACKWARD; } diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index 242ead38..47c73264 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -83,15 +83,23 @@ #define BC_JUMP_ON_TRUE_POP 47 #define BC_JUMP_ON_FALSE_TOP_NIL 48 #define BC_JUMP_ON_TRUE_TOP_NIL 49 -#define BC_JUMP_IF_GREATER 50 -#define BC_JUMP_BACKWARD 51 -#define BC_JUMP2 52 -#define BC_JUMP2_ON_FALSE_POP 53 -#define BC_JUMP2_ON_TRUE_POP 54 -#define BC_JUMP2_ON_FALSE_TOP_NIL 55 -#define BC_JUMP2_ON_TRUE_TOP_NIL 56 -#define BC_JUMP2_IF_GREATER 57 -#define BC_JUMP2_BACKWARD 58 +#define BC_JUMP_ON_NOT_NIL_POP 50 +#define BC_JUMP_ON_NIL_POP 51 +#define BC_JUMP_ON_NOT_NIL_TOP_TOP 52 +#define BC_JUMP_ON_NIL_TOP_TOP 53 +#define BC_JUMP_IF_GREATER 54 +#define BC_JUMP_BACKWARD 55 +#define BC_JUMP2 56 +#define BC_JUMP2_ON_FALSE_POP 57 +#define BC_JUMP2_ON_TRUE_POP 58 +#define BC_JUMP2_ON_FALSE_TOP_NIL 59 +#define BC_JUMP2_ON_TRUE_TOP_NIL 60 +#define BC_JUMP2_ON_NOT_NIL_POP 61 +#define BC_JUMP2_ON_NIL_POP 62 +#define BC_JUMP2_ON_NOT_NIL_TOP_TOP 63 +#define BC_JUMP2_ON_NIL_TOP_TOP 64 +#define BC_JUMP2_IF_GREATER 65 +#define BC_JUMP2_BACKWARD 66 #define _LAST_BYTECODE BC_JUMP2_BACKWARD diff --git a/src/unitTests/BytecodeGenerationTest.cpp b/src/unitTests/BytecodeGenerationTest.cpp index ab3c690e..b6e8f4f0 100644 --- a/src/unitTests/BytecodeGenerationTest.cpp +++ b/src/unitTests/BytecodeGenerationTest.cpp @@ -539,6 +539,8 @@ void BytecodeGenerationTest::testInliningOfToDo() { void BytecodeGenerationTest::testIfArg() { ifArg("ifTrue:", BC_JUMP_ON_FALSE_TOP_NIL); ifArg("ifFalse:", BC_JUMP_ON_TRUE_TOP_NIL); + ifArg("ifNil:", BC_JUMP_ON_NOT_NIL_TOP_TOP); + ifArg("ifNotNil:", BC_JUMP_ON_NIL_TOP_TOP); } void BytecodeGenerationTest::ifArg(std::string selector, int8_t jumpBytecode) { @@ -838,6 +840,10 @@ void BytecodeGenerationTest::testBlockIfTrueMethodArg() { void BytecodeGenerationTest::testIfTrueIfFalseReturn() { ifTrueIfFalseReturn("ifTrue:", "ifFalse:", BC(BC_JUMP_ON_FALSE_POP, 8, 0)); ifTrueIfFalseReturn("ifFalse:", "ifTrue:", BC(BC_JUMP_ON_TRUE_POP, 8, 0)); + + ifTrueIfFalseReturn( + "ifNil:", "ifNotNil:", BC(BC_JUMP_ON_NOT_NIL_POP, 8, 0)); + ifTrueIfFalseReturn("ifNotNil:", "ifNil:", BC(BC_JUMP_ON_NIL_POP, 8, 0)); } void BytecodeGenerationTest::ifTrueIfFalseReturn(const std::string& sel1, const std::string& sel2, diff --git a/src/vmobjects/VMEvaluationPrimitive.cpp b/src/vmobjects/VMEvaluationPrimitive.cpp index 30813148..1d94fe33 100644 --- a/src/vmobjects/VMEvaluationPrimitive.cpp +++ b/src/vmobjects/VMEvaluationPrimitive.cpp @@ -32,6 +32,7 @@ #include #include "../memory/Heap.h" +#include "../misc/debug.h" #include "../misc/defs.h" #include "../vm/Print.h" #include "../vm/Symbols.h" @@ -139,3 +140,8 @@ void VMEvaluationPrimitive::InlineInto(MethodGenerationContext& /*mgenc*/, "VMEvaluationPrimitive::InlineInto is not supported, and should not be " "reached"); } + +void VMEvaluationPrimitive::Dump(const char* /*indent*/, + bool /*printObjects*/) { + DebugPrint("\n"); +} diff --git a/src/vmobjects/VMEvaluationPrimitive.h b/src/vmobjects/VMEvaluationPrimitive.h index 105fac74..e454532e 100644 --- a/src/vmobjects/VMEvaluationPrimitive.h +++ b/src/vmobjects/VMEvaluationPrimitive.h @@ -58,6 +58,8 @@ class VMEvaluationPrimitive : public VMInvokable { return numberOfArguments; } + void Dump(const char* indent, bool printObjects) override; + private: static VMSymbol* computeSignatureString(size_t argc); void evaluationRoutine(VMFrame*); diff --git a/src/vmobjects/VMFrame.h b/src/vmobjects/VMFrame.h index 1262d018..c807dcb2 100644 --- a/src/vmobjects/VMFrame.h +++ b/src/vmobjects/VMFrame.h @@ -120,7 +120,7 @@ class VMFrame : public AbstractVMObject { } [[nodiscard]] inline vm_oop_t GetStackElement(size_t index) const { - return load_ptr(stack_ptr[-index]); + return load_ptr(stack_ptr[-std::make_signed_t(index)]); } inline vm_oop_t GetLocal(uint8_t index, uint8_t contextLevel) { diff --git a/src/vmobjects/VMInvokable.h b/src/vmobjects/VMInvokable.h index cd77c77e..a76f4552 100644 --- a/src/vmobjects/VMInvokable.h +++ b/src/vmobjects/VMInvokable.h @@ -76,6 +76,8 @@ class VMInvokable : public AbstractVMObject { holder = (GCClass*)INVALID_GC_POINTER; } + virtual void Dump(const char* indent, bool printObjects) = 0; + protected: make_testable(public); diff --git a/src/vmobjects/VMMethod.cpp b/src/vmobjects/VMMethod.cpp index 0f335018..c617555c 100644 --- a/src/vmobjects/VMMethod.cpp +++ b/src/vmobjects/VMMethod.cpp @@ -34,6 +34,7 @@ #include #include "../compiler/BytecodeGenerator.h" +#include "../compiler/Disassembler.h" #include "../compiler/LexicalScope.h" #include "../compiler/MethodGenerationContext.h" #include "../compiler/Variable.h" @@ -164,6 +165,10 @@ void VMMethod::SetHolderAll(VMClass* hld) { } } +void VMMethod::Dump(const char* indent, bool printObjects) { + Disassembler::DumpMethod(this, indent, printObjects); +} + std::string VMMethod::AsDebugString() const { VMClass* holder = GetHolder(); std::string holder_str; @@ -414,9 +419,13 @@ void VMMethod::inlineInto(MethodGenerationContext& mgenc) { case BC_JUMP: case BC_JUMP_ON_TRUE_TOP_NIL: case BC_JUMP_ON_FALSE_TOP_NIL: + case BC_JUMP_ON_NOT_NIL_TOP_TOP: + case BC_JUMP_ON_NIL_TOP_TOP: case BC_JUMP2: case BC_JUMP2_ON_TRUE_TOP_NIL: case BC_JUMP2_ON_FALSE_TOP_NIL: + case BC_JUMP2_ON_NOT_NIL_TOP_TOP: + case BC_JUMP2_ON_NIL_TOP_TOP: case BC_JUMP_IF_GREATER: case BC_JUMP2_IF_GREATER: { // emit the jump, but instead of the offset, emit a dummy @@ -430,7 +439,11 @@ void VMMethod::inlineInto(MethodGenerationContext& mgenc) { case BC_JUMP_ON_TRUE_POP: case BC_JUMP_ON_FALSE_POP: case BC_JUMP2_ON_TRUE_POP: - case BC_JUMP2_ON_FALSE_POP: { + case BC_JUMP2_ON_FALSE_POP: + case BC_JUMP_ON_NOT_NIL_POP: + case BC_JUMP_ON_NIL_POP: + case BC_JUMP2_ON_NOT_NIL_POP: + case BC_JUMP2_ON_NIL_POP: { // emit the jump, but instead of the offset, emit a dummy const size_t idx = Emit3WithDummy(mgenc, bytecode, -1); const size_t offset = @@ -548,12 +561,20 @@ void VMMethod::AdaptAfterOuterInlined( case BC_JUMP_ON_TRUE_POP: case BC_JUMP_ON_FALSE_TOP_NIL: case BC_JUMP_ON_FALSE_POP: + case BC_JUMP_ON_NOT_NIL_TOP_TOP: + case BC_JUMP_ON_NIL_TOP_TOP: + case BC_JUMP_ON_NOT_NIL_POP: + case BC_JUMP_ON_NIL_POP: case BC_JUMP_BACKWARD: case BC_JUMP2: case BC_JUMP2_ON_TRUE_TOP_NIL: case BC_JUMP2_ON_TRUE_POP: case BC_JUMP2_ON_FALSE_TOP_NIL: case BC_JUMP2_ON_FALSE_POP: + case BC_JUMP2_ON_NOT_NIL_TOP_TOP: + case BC_JUMP2_ON_NIL_TOP_TOP: + case BC_JUMP2_ON_NOT_NIL_POP: + case BC_JUMP2_ON_NIL_POP: case BC_JUMP2_BACKWARD: { // these bytecodes do not use context and don't need to be // adapted diff --git a/src/vmobjects/VMMethod.h b/src/vmobjects/VMMethod.h index 78a6f5f1..0edd70e9 100644 --- a/src/vmobjects/VMMethod.h +++ b/src/vmobjects/VMMethod.h @@ -181,6 +181,8 @@ class VMMethod : public VMInvokable { return lexicalScope->GetArgument(index, contextLevel); } + void Dump(const char* indent, bool printObjects) override; + private: void inlineInto(MethodGenerationContext& mgenc); std::priority_queue createBackJumpHeap(); diff --git a/src/vmobjects/VMPrimitive.cpp b/src/vmobjects/VMPrimitive.cpp index 2b7b3539..75b08026 100644 --- a/src/vmobjects/VMPrimitive.cpp +++ b/src/vmobjects/VMPrimitive.cpp @@ -29,6 +29,7 @@ #include #include "../memory/Heap.h" +#include "../misc/debug.h" #include "../misc/defs.h" #include "../primitivesCore/Primitives.h" #include "../vm/Globals.h" // NOLINT (misc-include-cleaner) @@ -73,3 +74,7 @@ std::string VMPrimitive::AsDebugString() const { return "Primitive(" + GetClass()->GetName()->GetStdString() + ">>#" + GetSignature()->GetStdString() + ")"; } + +void VMPrimitive::Dump(const char* /*indent*/, bool /*printObjects*/) { + DebugPrint("\n"); +} diff --git a/src/vmobjects/VMPrimitive.h b/src/vmobjects/VMPrimitive.h index f888ee3f..ed232ad6 100644 --- a/src/vmobjects/VMPrimitive.h +++ b/src/vmobjects/VMPrimitive.h @@ -86,6 +86,8 @@ class VMPrimitive : public VMInvokable { return Signature::GetNumberOfArguments(load_ptr(signature)); } + void Dump(const char* indent, bool printObjects) override; + private: make_testable(public); diff --git a/src/vmobjects/VMSafePrimitive.cpp b/src/vmobjects/VMSafePrimitive.cpp index 64737d16..57d26289 100644 --- a/src/vmobjects/VMSafePrimitive.cpp +++ b/src/vmobjects/VMSafePrimitive.cpp @@ -3,6 +3,7 @@ #include #include "../memory/Heap.h" +#include "../misc/debug.h" #include "../misc/defs.h" #include "../primitivesCore/Primitives.h" #include "../vm/Print.h" @@ -97,3 +98,7 @@ void VMSafePrimitive::InlineInto(MethodGenerationContext& /*mgenc*/, ErrorExit( "VMPrimitive::InlineInto is not supported, and should not be reached"); } + +void VMSafePrimitive::Dump(const char* /*indent*/, bool /*printObjects*/) { + DebugPrint("\n"); +} diff --git a/src/vmobjects/VMSafePrimitive.h b/src/vmobjects/VMSafePrimitive.h index 6b08f5ca..68740fa8 100644 --- a/src/vmobjects/VMSafePrimitive.h +++ b/src/vmobjects/VMSafePrimitive.h @@ -28,6 +28,8 @@ class VMSafePrimitive : public VMInvokable { [[nodiscard]] inline uint8_t GetNumberOfArguments() const final { return Signature::GetNumberOfArguments(load_ptr(signature)); } + + void Dump(const char* indent, bool printObjects) override; }; class VMSafeUnaryPrimitive : public VMSafePrimitive { diff --git a/src/vmobjects/VMTrivialMethod.cpp b/src/vmobjects/VMTrivialMethod.cpp index 8b75802a..9e7f0ca3 100644 --- a/src/vmobjects/VMTrivialMethod.cpp +++ b/src/vmobjects/VMTrivialMethod.cpp @@ -10,6 +10,7 @@ #include "../compiler/Variable.h" #include "../interpreter/Interpreter.h" #include "../memory/Heap.h" +#include "../misc/debug.h" #include "../misc/defs.h" #include "../vm/LogAllocation.h" #include "../vm/Print.h" @@ -240,3 +241,7 @@ std::string VMSetter::AsDebugString() const { return "VMSetter(fieldIndex: " + to_string(fieldIndex) + ", argIndex: " + to_string(argIndex) + ")"; } + +void VMTrivialMethod::Dump(const char* /*indent*/, bool /*printObjects*/) { + DebugPrint("\n"); +} diff --git a/src/vmobjects/VMTrivialMethod.h b/src/vmobjects/VMTrivialMethod.h index aa2c96e2..8997c8b5 100644 --- a/src/vmobjects/VMTrivialMethod.h +++ b/src/vmobjects/VMTrivialMethod.h @@ -38,6 +38,8 @@ class VMTrivialMethod : public VMInvokable { return Signature::GetNumberOfArguments(load_ptr(signature)); } + void Dump(const char* indent, bool printObjects) override; + private: vector arguments; };