diff --git a/src/compiler/BytecodeGenerator.cpp b/src/compiler/BytecodeGenerator.cpp index 92c74fcd..28772441 100644 --- a/src/compiler/BytecodeGenerator.cpp +++ b/src/compiler/BytecodeGenerator.cpp @@ -234,7 +234,7 @@ void EmitSEND(MethodGenerationContext& mgenc, VMSymbol* msg) { const int numArgs = Signature::GetNumberOfArguments(msg); const size_t stackEffect = -numArgs + 1; // +1 for the result - Emit2(mgenc, BC_SEND, idx, stackEffect); + Emit2(mgenc, numArgs == 1 ? BC_SEND_1 : BC_SEND, idx, stackEffect); } void EmitSUPERSEND(MethodGenerationContext& mgenc, VMSymbol* msg) { diff --git a/src/interpreter/Interpreter.cpp b/src/interpreter/Interpreter.cpp index e40b3c06..8ec5b9c0 100644 --- a/src/interpreter/Interpreter.cpp +++ b/src/interpreter/Interpreter.cpp @@ -147,11 +147,8 @@ void Interpreter::send(VMSymbol* signature, VMClass* receiverClass) { Universe::callStats[name].noPrimitiveCalls++; } #endif - // since an invokable is able to change/use the frame, we have to write - // cached values before, and read cached values after calling - GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); + invokable->Invoke(GetFrame()); - bytecodeIndexGlobal = GetFrame()->GetBytecodeIndex(); } else { triggerDoesNotUnderstand(signature); } @@ -366,6 +363,45 @@ void Interpreter::doSend(long bytecodeIndex) { send(signature, receiverClass); } +void Interpreter::doUnarySend(long bytecodeIndex) { + VMSymbol* signature = + static_cast(method->GetConstant(bytecodeIndex)); + + const int numOfArgs = 1; + + vm_oop_t receiver = frame->GetStackElement(numOfArgs - 1); + + assert(IsValidObject(receiver)); + // make sure it is really a class + assert(dynamic_cast(CLASS_OF(receiver)) != nullptr); + + VMClass* receiverClass = CLASS_OF(receiver); + + assert(IsValidObject(receiverClass)); + +#ifdef LOG_RECEIVER_TYPES + Universe::receiverTypes[receiverClass->GetName()->GetStdString()]++; +#endif + + VMInvokable* invokable = receiverClass->LookupInvokable(signature); + + if (invokable != nullptr) { +#ifdef LOG_RECEIVER_TYPES + std::string name = receiverClass->GetName()->GetStdString(); + if (Universe::callStats.find(name) == Universe::callStats.end()) { + Universe::callStats[name] = {0, 0}; + } + Universe::callStats[name].noCalls++; + if (invokable->IsPrimitive()) { + Universe::callStats[name].noPrimitiveCalls++; + } +#endif + invokable->Invoke1(GetFrame()); + } else { + triggerDoesNotUnderstand(signature); + } +} + void Interpreter::doSuperSend(long bytecodeIndex) { VMSymbol* signature = static_cast(method->GetConstant(bytecodeIndex)); diff --git a/src/interpreter/Interpreter.h b/src/interpreter/Interpreter.h index f60f7ee7..60052dd8 100644 --- a/src/interpreter/Interpreter.h +++ b/src/interpreter/Interpreter.h @@ -58,6 +58,8 @@ class Interpreter { static void SendUnknownGlobal(VMSymbol* globalName); + static inline long GetBytecodeIndex() { return bytecodeIndexGlobal; } + private: static vm_oop_t GetSelf(); @@ -105,6 +107,7 @@ class Interpreter { static void doPopField(long bytecodeIndex); static void doPopFieldWithIndex(uint8_t fieldIndex); static void doSend(long bytecodeIndex); + static void doUnarySend(long bytecodeIndex); static void doSuperSend(long bytecodeIndex); static void doReturnLocal(); static void doReturnNonLocal(); diff --git a/src/interpreter/InterpreterLoop.h b/src/interpreter/InterpreterLoop.h index 2835cf4e..2fe3f03f 100644 --- a/src/interpreter/InterpreterLoop.h +++ b/src/interpreter/InterpreterLoop.h @@ -38,6 +38,7 @@ vm_oop_t Start() { &&LABEL_BC_POP_FIELD_0, &&LABEL_BC_POP_FIELD_1, &&LABEL_BC_SEND, + &&LABEL_BC_SEND_1, &&LABEL_BC_SUPER_SEND, &&LABEL_BC_RETURN_LOCAL, &&LABEL_BC_RETURN_NON_LOCAL, @@ -253,6 +254,11 @@ vm_oop_t Start() { doSend(bytecodeIndexGlobal - 2); DISPATCH_GC(); +LABEL_BC_SEND_1: + PROLOGUE(2); + doUnarySend(bytecodeIndexGlobal - 2); + DISPATCH_GC(); + LABEL_BC_SUPER_SEND: PROLOGUE(2); doSuperSend(bytecodeIndexGlobal - 2); diff --git a/src/interpreter/bytecodes.cpp b/src/interpreter/bytecodes.cpp index dc3f42e0..f05dfd41 100644 --- a/src/interpreter/bytecodes.cpp +++ b/src/interpreter/bytecodes.cpp @@ -63,6 +63,7 @@ const uint8_t Bytecode::bytecodeLengths[] = { 1, // BC_POP_FIELD_0 1, // BC_POP_FIELD_1 2, // BC_SEND + 2, // BC_SEND_1 2, // BC_SUPER_SEND 1, // BC_RETURN_LOCAL 1, // BC_RETURN_NON_LOCAL @@ -126,31 +127,32 @@ const char* Bytecode::bytecodeNames[] = { "POP_FIELD_0 ", // 30 "POP_FIELD_1 ", // 31 "SEND ", // 32 - "SUPER_SEND ", // 33 - "RETURN_LOCAL ", // 34 - "RETURN_NON_LOCAL", // 35 - "RETURN_SELF ", // 36 - "RETURN_FIELD_0 ", // 37 - "RETURN_FIELD_1 ", // 38 - "RETURN_FIELD_2 ", // 39 - "INC ", // 40 - "DEC ", // 41 - "INC_FIELD ", // 42 - "INC_FIELD_PUSH ", // 43 - "JUMP ", // 44 - "JUMP_ON_FALSE_POP", // 45 - "JUMP_ON_TRUE_POP", // 46 - "JUMP_ON_FALSE_TOP_NIL", // 47 - "JUMP_ON_TRUE_TOP_NIL", // 48 - "JUMP_IF_GREATER ", // 49 - "JUMP_BACKWARD ", // 50 - "JUMP2 ", // 51 - "JUMP2_ON_FALSE_POP", // 52 - "JUMP2_ON_TRUE_POP", // 53 - "JUMP2_ON_FALSE_TOP_NIL", // 54 - "JUMP2_ON_TRUE_TOP_NIL", // 55 - "JUMP2_IF_GREATER", // 56 - "JUMP2_BACKWARD ", // 57 + "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 }; bool IsJumpBytecode(uint8_t bc) { diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index cce9fc34..ea3916ba 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -66,31 +66,32 @@ #define BC_POP_FIELD_0 30 #define BC_POP_FIELD_1 31 #define BC_SEND 32 -#define BC_SUPER_SEND 33 -#define BC_RETURN_LOCAL 34 -#define BC_RETURN_NON_LOCAL 35 -#define BC_RETURN_SELF 36 -#define BC_RETURN_FIELD_0 37 -#define BC_RETURN_FIELD_1 38 -#define BC_RETURN_FIELD_2 39 -#define BC_INC 40 -#define BC_DEC 41 -#define BC_INC_FIELD 42 -#define BC_INC_FIELD_PUSH 43 -#define BC_JUMP 44 -#define BC_JUMP_ON_FALSE_POP 45 -#define BC_JUMP_ON_TRUE_POP 46 -#define BC_JUMP_ON_FALSE_TOP_NIL 47 -#define BC_JUMP_ON_TRUE_TOP_NIL 48 -#define BC_JUMP_IF_GREATER 49 -#define BC_JUMP_BACKWARD 50 -#define BC_JUMP2 51 -#define BC_JUMP2_ON_FALSE_POP 52 -#define BC_JUMP2_ON_TRUE_POP 53 -#define BC_JUMP2_ON_FALSE_TOP_NIL 54 -#define BC_JUMP2_ON_TRUE_TOP_NIL 55 -#define BC_JUMP2_IF_GREATER 56 -#define BC_JUMP2_BACKWARD 57 +#define BC_SEND_1 33 +#define BC_SUPER_SEND 34 +#define BC_RETURN_LOCAL 35 +#define BC_RETURN_NON_LOCAL 36 +#define BC_RETURN_SELF 37 +#define BC_RETURN_FIELD_0 38 +#define BC_RETURN_FIELD_1 39 +#define BC_RETURN_FIELD_2 40 +#define BC_INC 41 +#define BC_DEC 42 +#define BC_INC_FIELD 43 +#define BC_INC_FIELD_PUSH 44 +#define BC_JUMP 45 +#define BC_JUMP_ON_FALSE_POP 46 +#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 _LAST_BYTECODE BC_JUMP2_BACKWARD @@ -104,7 +105,6 @@ #define BC_SEND_N 250 #define BC_SEND_3 249 #define BC_SEND_2 248 -#define BC_SEND_1 247 // clang-format on // properties of the bytecodes diff --git a/src/unitTests/BytecodeGenerationTest.cpp b/src/unitTests/BytecodeGenerationTest.cpp index 18eec87f..3320afec 100644 --- a/src/unitTests/BytecodeGenerationTest.cpp +++ b/src/unitTests/BytecodeGenerationTest.cpp @@ -127,7 +127,7 @@ void BytecodeGenerationTest::testSendDupPopFieldReturnLocal() { auto bytecodes = methodToBytecode("test = ( ^ field := self method )"); check(bytecodes, - {BC_PUSH_SELF, BC(BC_SEND, 0), BC_DUP, BC_POP_FIELD_0, + {BC_PUSH_SELF, BC(BC_SEND_1, 0), BC_DUP, BC_POP_FIELD_0, BC_RETURN_LOCAL}); } @@ -136,7 +136,7 @@ void BytecodeGenerationTest::testSendDupPopFieldReturnLocalPeriod() { auto bytecodes = methodToBytecode("test = ( ^ field := self method. )"); check(bytecodes, - {BC_PUSH_SELF, BC(BC_SEND, 0), BC_DUP, BC_POP_FIELD_0, + {BC_PUSH_SELF, BC(BC_SEND_1, 0), BC_DUP, BC_POP_FIELD_0, BC_RETURN_LOCAL}); } @@ -377,7 +377,7 @@ void BytecodeGenerationTest::ifTrueWithLiteralReturn(std::string literal, bytecode.bytecode == BC_PUSH_BLOCK; check(bytecodes, - {BC_PUSH_SELF, BC(BC_SEND, 0), + {BC_PUSH_SELF, BC(BC_SEND_1, 0), BC(BC_JUMP_ON_FALSE_TOP_NIL, twoByte2 ? 5 : 4, 0), bytecode, BC_POP, BC_RETURN_SELF}); @@ -418,7 +418,7 @@ void BytecodeGenerationTest::ifTrueWithSomethingAndLiteralReturn( bytecode.bytecode == BC_PUSH_BLOCK; check(bytecodes, - {BC_PUSH_SELF, BC(BC_SEND, 0), + {BC_PUSH_SELF, BC(BC_SEND_1, 0), BC(BC_JUMP_ON_FALSE_TOP_NIL, twoByte2 ? 7 : 6, 0), BC_PUSH_CONSTANT_1, BC_POP, bytecode, BC_POP, BC_RETURN_SELF}); @@ -433,7 +433,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseArg() { ) )"""); check(bytecodes, - {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), + {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_POP, 7, 0), BC_PUSH_ARG_1, BC(BC_JUMP, 4, 0), BC_PUSH_ARG_2, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF}); } @@ -446,7 +446,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseNlrArg1() { ) )"""); check(bytecodes, - {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), + {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_POP, 8, 0), BC_PUSH_ARG_1, BC_RETURN_LOCAL, BC(BC_JUMP, 4, 0), BC_PUSH_ARG_2, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF}); @@ -460,7 +460,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseNlrArg2() { ) )"""); check(bytecodes, - {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), + {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_POP, 7, 0), BC_PUSH_ARG_1, BC(BC_JUMP, 5, 0), BC_PUSH_ARG_2, BC_RETURN_LOCAL, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF}); @@ -552,7 +552,7 @@ void BytecodeGenerationTest::ifArg(std::string selector, int8_t jumpBytecode) { auto bytecodes = methodToBytecode(source.data()); check(bytecodes, - {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), + {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1), BC(jumpBytecode, 4, 0), BC_PUSH_ARG_1, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF}); @@ -588,7 +588,7 @@ void BytecodeGenerationTest::ifReturnNonLocal(std::string selector, auto bytecodes = methodToBytecode(source.data()); check(bytecodes, - {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), + {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1), BC(jumpBytecode, 5, 0), BC_PUSH_ARG_1, BC_RETURN_LOCAL, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF}); @@ -813,7 +813,7 @@ void BytecodeGenerationTest::testBlockIfTrueArg() { check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1), - BC(BC_SEND, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 4, 0), BC_PUSH_ARG_1, + BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 4, 0), BC_PUSH_ARG_1, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_LOCAL}); } @@ -829,7 +829,7 @@ void BytecodeGenerationTest::testBlockIfTrueMethodArg() { ] )"""); check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1), - BC(BC_SEND, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 6, 0), + BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 6, 0), BC(BC_PUSH_ARGUMENT, 1, 1), BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_LOCAL}); } @@ -844,9 +844,9 @@ void BytecodeGenerationTest::ifTrueIfFalseReturn(std::string sel1, sel1 + " [ ^ arg1 ] " + sel2 + " [ arg2 ] )"; auto bytecodes = methodToBytecode(source.data()); - check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1), - bc, BC_PUSH_ARG_1, BC_RETURN_LOCAL, BC(BC_JUMP, 4, 0), - BC_PUSH_ARG_2, BC_RETURN_LOCAL}); + check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, + BC(BC_SEND_1, 1), bc, BC_PUSH_ARG_1, BC_RETURN_LOCAL, + BC(BC_JUMP, 4, 0), BC_PUSH_ARG_2, BC_RETURN_LOCAL}); tearDown(); } @@ -867,7 +867,7 @@ void BytecodeGenerationTest::blockIfReturnNonLocal(std::string sel, BC bc) { auto bytecodes = blockToBytecode(source.data()); check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1), - BC(BC_SEND, 1), bc, BC_PUSH_ARG_1, BC_RETURN_NON_LOCAL, BC_POP, + BC(BC_SEND_1, 1), bc, BC_PUSH_ARG_1, BC_RETURN_NON_LOCAL, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_LOCAL}); tearDown(); diff --git a/src/vm/IsValidObject.cpp b/src/vm/IsValidObject.cpp index 47e98d61..592160bc 100644 --- a/src/vm/IsValidObject.cpp +++ b/src/vm/IsValidObject.cpp @@ -159,6 +159,11 @@ bool IsSetter(vm_oop_t obj) { return get_vtable(AS_OBJ(obj)) == vt_setter; } +bool IsSafeUnaryPrim(vm_oop_t obj) { + assert(vt_safe_un_primitive != nullptr); + return get_vtable(AS_OBJ(obj)) == vt_safe_un_primitive; +} + void obtain_vtables_of_known_classes(VMSymbol* someValidSymbol) { // These objects are allocated on the heap. So, they will get GC'ed soon // enough. diff --git a/src/vm/IsValidObject.h b/src/vm/IsValidObject.h index 31da1cc7..6c42b0cf 100644 --- a/src/vm/IsValidObject.h +++ b/src/vm/IsValidObject.h @@ -12,6 +12,7 @@ bool IsLiteralReturn(vm_oop_t obj); bool IsGlobalReturn(vm_oop_t obj); bool IsGetter(vm_oop_t obj); bool IsSetter(vm_oop_t obj); +bool IsSafeUnaryPrim(vm_oop_t obj); void set_vt_to_null(); diff --git a/src/vmobjects/VMEvaluationPrimitive.cpp b/src/vmobjects/VMEvaluationPrimitive.cpp index a7d700a3..3d80069d 100644 --- a/src/vmobjects/VMEvaluationPrimitive.cpp +++ b/src/vmobjects/VMEvaluationPrimitive.cpp @@ -102,6 +102,23 @@ VMFrame* VMEvaluationPrimitive::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMEvaluationPrimitive::Invoke1(VMFrame* frame) { + assert(numberOfArguments == 1); + // Get the block (the receiver) from the stack + VMBlock* block = static_cast(frame->GetStackElement(0)); + + // Get the context of the block... + VMFrame* context = block->GetContext(); + VMInvokable* method = block->GetMethod(); + VMFrame* newFrame = method->Invoke1(frame); + + // Push set its context to be the one specified in the block + if (newFrame != nullptr) { + newFrame->SetContext(context); + } + return nullptr; +} + std::string VMEvaluationPrimitive::AsDebugString() const { return "VMEvaluationPrimitive(" + to_string(numberOfArguments) + ")"; } diff --git a/src/vmobjects/VMEvaluationPrimitive.h b/src/vmobjects/VMEvaluationPrimitive.h index f7d60f0f..d3778839 100644 --- a/src/vmobjects/VMEvaluationPrimitive.h +++ b/src/vmobjects/VMEvaluationPrimitive.h @@ -48,6 +48,7 @@ class VMEvaluationPrimitive : public VMInvokable { bool IsMarkedInvalid() const override; VMFrame* Invoke(VMFrame* frm) override; + VMFrame* Invoke1(VMFrame* frm) override; void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final; diff --git a/src/vmobjects/VMFrame.h b/src/vmobjects/VMFrame.h index 312d8e1c..eaa3dc4f 100644 --- a/src/vmobjects/VMFrame.h +++ b/src/vmobjects/VMFrame.h @@ -33,6 +33,9 @@ class Universe; class VMFrame : public VMObject { friend class Universe; + friend class Interpreter; + friend class Shell; + friend class VMMethod; public: typedef GCFrame Stored; @@ -89,7 +92,6 @@ class VMFrame : public VMObject { } inline long GetBytecodeIndex() const; - inline void SetBytecodeIndex(long); inline vm_oop_t GetStackElement(long index) const { return load_ptr(stack_ptr[-index]); @@ -124,6 +126,11 @@ class VMFrame : public VMObject { void PrintStackTrace() const; long ArgumentStackIndex(long index) const; void CopyArgumentsFrom(VMFrame* frame); + + inline void SetArgument(size_t argIdx, vm_oop_t value) { + store_ptr(arguments[argIdx], value); + } + void WalkObjects(walk_heap_fn) override; VMFrame* CloneForMovingGC() const override; @@ -152,9 +159,9 @@ class VMFrame : public VMObject { gc_oop_t* locals; gc_oop_t* stack_ptr; - inline void SetArgument(long index, vm_oop_t value); - static const long VMFrameNumberOfFields; + + inline void SetBytecodeIndex(long index) { bytecodeIndex = index; } }; bool VMFrame::HasContext() const { @@ -169,10 +176,6 @@ long VMFrame::GetBytecodeIndex() const { return bytecodeIndex; } -void VMFrame::SetBytecodeIndex(long index) { - bytecodeIndex = index; -} - bool VMFrame::IsBootstrapFrame() const { return !HasPreviousFrame(); } @@ -200,7 +203,3 @@ void VMFrame::ClearPreviousFrame() { VMMethod* VMFrame::GetMethod() const { return load_ptr(method); } - -void VMFrame::SetArgument(long index, vm_oop_t value) { - store_ptr(arguments[index], value); -} diff --git a/src/vmobjects/VMInvokable.h b/src/vmobjects/VMInvokable.h index 3a112a7f..2c5880be 100644 --- a/src/vmobjects/VMInvokable.h +++ b/src/vmobjects/VMInvokable.h @@ -44,6 +44,7 @@ class VMInvokable : public AbstractVMObject { int64_t GetHash() const override { return hash; } virtual VMFrame* Invoke(VMFrame*) = 0; + virtual VMFrame* Invoke1(VMFrame*) = 0; virtual void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) = 0; virtual void MergeScopeInto( diff --git a/src/vmobjects/VMMethod.cpp b/src/vmobjects/VMMethod.cpp index 2fe74fc7..0998034d 100644 --- a/src/vmobjects/VMMethod.cpp +++ b/src/vmobjects/VMMethod.cpp @@ -127,11 +127,25 @@ void VMMethod::SetCachedFrame(VMFrame* frame) { #endif VMFrame* VMMethod::Invoke(VMFrame* frame) { + // since an invokable is able to change/use the frame, we have to write + // cached values before, and read cached values after calling + frame->SetBytecodeIndex(Interpreter::GetBytecodeIndex()); + VMFrame* frm = Interpreter::PushNewFrame(this); frm->CopyArgumentsFrom(frame); return frm; } +VMFrame* VMMethod::Invoke1(VMFrame* frame) { + // since an invokable is able to change/use the frame, we have to write + // cached values before, and read cached values after calling + frame->SetBytecodeIndex(Interpreter::GetBytecodeIndex()); + + VMFrame* frm = Interpreter::PushNewFrame(this); + frm->SetArgument(0, frame->Top()); + return frm; +} + void VMMethod::SetHolder(VMClass* hld) { VMInvokable::SetHolder(hld); SetHolderAll(hld); diff --git a/src/vmobjects/VMMethod.h b/src/vmobjects/VMMethod.h index c4e96f4b..d43a502e 100644 --- a/src/vmobjects/VMMethod.h +++ b/src/vmobjects/VMMethod.h @@ -150,6 +150,7 @@ class VMMethod : public VMInvokable { } VMFrame* Invoke(VMFrame* frame) override; + VMFrame* Invoke1(VMFrame* frame) override; void MarkObjectAsInvalid() override { VMInvokable::MarkObjectAsInvalid(); diff --git a/src/vmobjects/VMPrimitive.h b/src/vmobjects/VMPrimitive.h index 4abd9dfe..5d35b565 100644 --- a/src/vmobjects/VMPrimitive.h +++ b/src/vmobjects/VMPrimitive.h @@ -58,6 +58,11 @@ class VMPrimitive : public VMInvokable { return nullptr; }; + VMFrame* Invoke1(VMFrame* frm) override { + prim.pointer(frm); + return nullptr; + }; + void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final; diff --git a/src/vmobjects/VMSafePrimitive.cpp b/src/vmobjects/VMSafePrimitive.cpp index 192bbb09..8457e2de 100644 --- a/src/vmobjects/VMSafePrimitive.cpp +++ b/src/vmobjects/VMSafePrimitive.cpp @@ -26,6 +26,13 @@ VMFrame* VMSafeUnaryPrimitive::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMSafeUnaryPrimitive::Invoke1(VMFrame* frame) { + vm_oop_t receiverObj = frame->Pop(); + + frame->Push(prim.pointer(receiverObj)); + return nullptr; +} + VMSafePrimitive* VMSafePrimitive::GetSafeBinary(VMSymbol* sig, BinaryPrim prim) { VMSafeBinaryPrimitive* p = @@ -41,6 +48,10 @@ VMFrame* VMSafeBinaryPrimitive::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMSafeBinaryPrimitive::Invoke1(VMFrame* frame) { + ErrorExit("Unary invoke on binary primitive"); +} + VMSafePrimitive* VMSafePrimitive::GetSafeTernary(VMSymbol* sig, TernaryPrim prim) { VMSafeTernaryPrimitive* p = @@ -57,6 +68,10 @@ VMFrame* VMSafeTernaryPrimitive::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMSafeTernaryPrimitive::Invoke1(VMFrame* frame) { + ErrorExit("Unary invoke on binary primitive"); +} + std::string VMSafePrimitive::AsDebugString() const { return "SafePrim(" + GetClass()->GetName()->GetStdString() + ">>#" + GetSignature()->GetStdString() + ")"; diff --git a/src/vmobjects/VMSafePrimitive.h b/src/vmobjects/VMSafePrimitive.h index e5f7a1da..f4493330 100644 --- a/src/vmobjects/VMSafePrimitive.h +++ b/src/vmobjects/VMSafePrimitive.h @@ -41,6 +41,7 @@ class VMSafeUnaryPrimitive : public VMSafePrimitive { } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; AbstractVMObject* CloneForMovingGC() const final; @@ -69,6 +70,7 @@ class VMSafeBinaryPrimitive : public VMSafePrimitive { } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; AbstractVMObject* CloneForMovingGC() const final; @@ -97,6 +99,7 @@ class VMSafeTernaryPrimitive : public VMSafePrimitive { } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; AbstractVMObject* CloneForMovingGC() const final; diff --git a/src/vmobjects/VMTrivialMethod.cpp b/src/vmobjects/VMTrivialMethod.cpp index 7013e7e6..d92f6e11 100644 --- a/src/vmobjects/VMTrivialMethod.cpp +++ b/src/vmobjects/VMTrivialMethod.cpp @@ -58,6 +58,13 @@ VMFrame* VMLiteralReturn::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMLiteralReturn::Invoke1(VMFrame* frame) { + assert(numberOfArguments == 1); + frame->Pop(); + frame->Push(load_ptr(literal)); + return nullptr; +} + AbstractVMObject* VMLiteralReturn::CloneForMovingGC() const { VMLiteralReturn* prim = new (GetHeap(), 0 ALLOC_MATURE) VMLiteralReturn(*this); @@ -93,6 +100,20 @@ VMFrame* VMGlobalReturn::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMGlobalReturn::Invoke1(VMFrame* frame) { + assert(numberOfArguments == 1); + frame->Pop(); + + vm_oop_t value = Universe::GetGlobal(load_ptr(globalName)); + if (value != nullptr) { + frame->Push(value); + } else { + Interpreter::SendUnknownGlobal(load_ptr(globalName)); + } + + return nullptr; +} + void VMGlobalReturn::InlineInto(MethodGenerationContext& mgenc, bool) { EmitPUSHGLOBAL(mgenc, load_ptr(globalName)); } @@ -134,6 +155,25 @@ VMFrame* VMGetter::Invoke(VMFrame* frame) { return nullptr; } +VMFrame* VMGetter::Invoke1(VMFrame* frame) { + assert(numberOfArguments == 1); + vm_oop_t self = frame->Pop(); + + assert(self != nullptr); + + vm_oop_t result; + if (unlikely(IS_TAGGED(self))) { + result = nullptr; + ErrorExit("Integers do not have fields!"); + } else { + result = ((VMObject*)self)->GetField(fieldIndex); + } + + frame->Push(result); + + return nullptr; +} + void VMGetter::InlineInto(MethodGenerationContext& mgenc, bool) { EmitPushFieldWithIndex(mgenc, fieldIndex); } @@ -176,7 +216,11 @@ VMFrame* VMSetter::Invoke(VMFrame* frame) { return nullptr; } -void VMSetter::InlineInto(MethodGenerationContext& mgenc, bool) { +VMFrame* VMSetter::Invoke1(VMFrame*) { + ErrorExit("VMSetter::Invoke1 should not be reachable"); +} + +void VMSetter::InlineInto(MethodGenerationContext&, bool) { ErrorExit("We don't currently support blocks for trivial setters"); } diff --git a/src/vmobjects/VMTrivialMethod.h b/src/vmobjects/VMTrivialMethod.h index ad2c9df1..49251eba 100644 --- a/src/vmobjects/VMTrivialMethod.h +++ b/src/vmobjects/VMTrivialMethod.h @@ -67,6 +67,8 @@ class VMLiteralReturn : public VMTrivialMethod { } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; + void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final; @@ -106,6 +108,8 @@ class VMGlobalReturn : public VMTrivialMethod { } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; + void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final; @@ -142,6 +146,8 @@ class VMGetter : public VMTrivialMethod { inline size_t GetObjectSize() const override { return sizeof(VMGetter); } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; + void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final; @@ -177,6 +183,8 @@ class VMSetter : public VMTrivialMethod { inline size_t GetObjectSize() const override { return sizeof(VMSetter); } VMFrame* Invoke(VMFrame*) override; + VMFrame* Invoke1(VMFrame*) override; + void InlineInto(MethodGenerationContext& mgenc, bool mergeScope = true) final;