diff --git a/b9/include/b9/compiler/MethodBuilder.hpp b/b9/include/b9/compiler/MethodBuilder.hpp index 96ba760..7ee9c2f 100644 --- a/b9/include/b9/compiler/MethodBuilder.hpp +++ b/b9/include/b9/compiler/MethodBuilder.hpp @@ -4,7 +4,7 @@ #include "b9/VirtualMachine.hpp" #include "b9/compiler/Compiler.hpp" #include "b9/compiler/GlobalTypes.hpp" -#include "b9/compiler/VirtualMachineState.hpp" +#include "b9/compiler/State.hpp" #include "b9/instructions.hpp" #include @@ -25,7 +25,9 @@ class MethodBuilder : public TR::MethodBuilder { private: void defineFunctions(); + void defineLocals(); + void defineParameters(); /// For a single bytecode, generate the @@ -50,7 +52,7 @@ class MethodBuilder : public TR::MethodBuilder { TR::IlValue *popInt48(TR::BytecodeBuilder *builder); - void drop(TR::BytecodeBuilder *builder); + void drop(TR::BytecodeBuilder *builder, std::size_t n = 1); TR::IlValue *loadVal(TR::IlBuilder *builder, int valIndex); diff --git a/b9/include/b9/compiler/State.hpp b/b9/include/b9/compiler/State.hpp new file mode 100644 index 0000000..112a3ff --- /dev/null +++ b/b9/include/b9/compiler/State.hpp @@ -0,0 +1,178 @@ +#if !defined(B9_STATE_HPP_) +#define B9_STATE_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +namespace b9 { + +/// An interface to working with the state of the B9 execution context. +class State : public TR::VirtualMachineState { + public: + /// Push an Om::Value onto the stack + virtual void pushValue(TR::IlBuilder *, TR::IlValue *value) = 0; + + /// Pop an Om::Value from the stack + virtual TR::IlValue *popValue(TR::IlBuilder *) = 0; + + /// The size of the stack has been changed as part of an external operation. + /// Adjust the model to note the new size. + virtual void adjust(TR::IlBuilder *b, int n) = 0; +}; + +template +State *state(BuilderT *b) { + return dynamic_cast(b->vmState()); +} + +/// State object that keeps VM structures up to date. Commit and reload are +/// no-ops, since state is always written out immediately. Copy and Merge are +/// also no-ops, there is no model to merge or copy. +class ActiveState : public State { + public: + ActiveState(TR::MethodBuilder *b, const GlobalTypes &types) : types_(types) {} + + ActiveState(const ActiveState &) = default; + + /// Push a Value onto the OperandStack. Will actually update the stack. + virtual void pushValue(TR::IlBuilder *b, TR::IlValue *value) override final { + TR::IlValue *stack = this->stack(b); + + TR::IlValue *stackTop = b->LoadIndirect("b9::OperandStack", "top_", stack); + + b->StoreAt(stackTop, b->ConvertTo(types_.stackElement, value)); + + TR::IlValue *newStackTop = + b->IndexAt(types_.stackElementPtr, stackTop, b->ConstInt32(1)); + + b->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); + } + + /// Pop a Value from the OperandStack. Will actually update the stack. + virtual TR::IlValue *popValue(TR::IlBuilder *b) override final { + auto stack = this->stack(b); + + TR::IlValue *stackTop = b->LoadIndirect("b9::OperandStack", "top_", stack); + + TR::IlValue *newStackTop = + b->IndexAt(types_.stackElementPtr, stackTop, b->ConstInt32(-1)); + + b->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); + + TR::IlValue *value = b->LoadAt(types_.stackElementPtr, newStackTop); + + return value; + } + + virtual void adjust(TR::IlBuilder *b, int n) override final { + assert(n < 1); + // TODO: No way to increase stack size in model. + } + + /// @group VirtualMachineState overrides + /// @{ + + virtual void Commit(TR::IlBuilder *b) override final { + // nothing to commit + } + + virtual void Reload(TR::IlBuilder *b) override final { + // nothing to reload + } + + virtual VirtualMachineState *MakeCopy() override final { + return new ActiveState(*this); + } + + virtual void MergeInto(TR::VirtualMachineState *other, + TR::IlBuilder *b) override final { + // nothing to merge + } + + /// @} + + private: + TR::IlValue *stack(TR::IlBuilder *b) { + return b->StructFieldInstanceAddress("b9::ExecutionContext", "stack_", + b->Load("executionContext")); + } + + const GlobalTypes &types_; +}; + +/// Lazy VM state that only commits state on demand. +/// Simulates all state of the virtual machine state while compiled code is +/// running. It simulates the stack and the pointer to the top of the stack. +class ModelState : public State { + public: + ModelState(TR::MethodBuilder *b, const GlobalTypes &types) + : stack_(nullptr), stackTop_(nullptr) { + stackTop_ = new TR::VirtualMachineRegisterInStruct( + b, "b9::OperandStack", "stack", "top_", "stackTop"); + + stack_ = new TR::VirtualMachineOperandStack(b, 64, types.stackElement, + stackTop_, true, 0); + } + + ModelState(const ModelState &other) + : stack_(other.stack_), stackTop_(other.stackTop_) {} + + /// Model a push onto the OperandStack. The Value will be saved in an + /// intermediate IlValue. + virtual void pushValue(TR::IlBuilder *b, TR::IlValue *value) override final { + return stack_->Push(b, value); + } + + /// Model a pop from the OperandStack. The result is an Il Value. + virtual TR::IlValue *popValue(TR::IlBuilder *b) override final { + return stack_->Pop(b); + } + + virtual void adjust(TR::IlBuilder *b, int n) override final { + assert(n < 1); + // TODO: No way to increase stack size yet. + stack_->Drop(b, -int32_t(n)); + } + + /// @group TR::VirtualMachineState overrides + /// @{ + + virtual void Commit(TR::IlBuilder *b) override final { + stack_->Commit(b); + stackTop_->Commit(b); + } + + virtual void Reload(TR::IlBuilder *b) override final { + stackTop_->Reload(b); + stack_->Reload(b); + } + + virtual TR::VirtualMachineState *MakeCopy() override final { + return new ModelState(*this); + } + + virtual void MergeInto(TR::VirtualMachineState *other, + TR::IlBuilder *b) override final { + MergeInto(dynamic_cast(other), b); + } + + void MergeInto(ModelState *other, TR::IlBuilder *b) { + stack_->MergeInto(other->stack_, b); + stackTop_->MergeInto(other->stackTop_, b); + } + + /// @} + + private: + TR::VirtualMachineOperandStack *stack_; + TR::VirtualMachineRegister *stackTop_; +}; + +} // namespace b9 + +#endif // B9_STATE_HPP_ diff --git a/b9/include/b9/compiler/VirtualMachineState.hpp b/b9/include/b9/compiler/VirtualMachineState.hpp deleted file mode 100644 index 581fac1..0000000 --- a/b9/include/b9/compiler/VirtualMachineState.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#if !defined(B9_VIRTUALMACHINESTATE_HPP_) -#define B9_VIRTUALMACHINESTATE_HPP_ - -#include -#include -#include -#include - -namespace b9 { - -/// Simulates all state of the virtual machine state while compiled code is -/// running. It simulates the stack and the pointer to the top of the stack. -class VirtualMachineState : public OMR::VirtualMachineState { - public: - VirtualMachineState() = default; - - VirtualMachineState(OMR::VirtualMachineOperandStack *stack, - OMR::VirtualMachineRegister *stackTop) - : _stack(stack), _stackTop(stackTop) {} - - void Commit(TR::IlBuilder *b) override { - _stack->Commit(b); - _stackTop->Commit(b); - } - - void Reload(TR::IlBuilder *b) override { - _stackTop->Reload(b); - _stack->Reload(b); - } - - VirtualMachineState *MakeCopy() override { - auto newState = new VirtualMachineState(); - newState->_stack = - dynamic_cast(_stack->MakeCopy()); - newState->_stackTop = - dynamic_cast(_stackTop->MakeCopy()); - return newState; - } - - void MergeInto(OMR::VirtualMachineState *other, TR::IlBuilder *b) override { - auto otherState = dynamic_cast(other); - _stack->MergeInto(otherState->_stack, b); - _stackTop->MergeInto(otherState->_stackTop, b); - } - - OMR::VirtualMachineOperandStack *_stack = nullptr; - OMR::VirtualMachineRegister *_stackTop = nullptr; -}; - -} // namespace b9 - -#endif // B9_VIRTUALMACHINESTATE_HPP_ \ No newline at end of file diff --git a/b9/src/MethodBuilder.cpp b/b9/src/MethodBuilder.cpp index 348727d..1fdadbc 100644 --- a/b9/src/MethodBuilder.cpp +++ b/b9/src/MethodBuilder.cpp @@ -4,6 +4,8 @@ #include "b9/compiler/Compiler.hpp" #include "b9/instructions.hpp" +#include + #include #include #include @@ -23,18 +25,6 @@ void print_stack(b9::ExecutionContext *context) { namespace b9 { -namespace ValueBuilder { - -TR::IlValue *getInt48(TR::BytecodeBuilder *builder, TR::IlValue *value) { - return builder->And(value, builder->ConstInt64(Om::Value::PAYLOAD_MASK)); -} - -TR::IlValue *fromInt48(TR::BytecodeBuilder *builder, TR::IlValue *value) { - return builder->Or(value, builder->ConstInt64(Om::Value::Tag::INT48)); -} - -} // namespace ValueBuilder - MethodBuilder::MethodBuilder(VirtualMachine &virtualMachine, const std::size_t functionIndex) : TR::MethodBuilder(&virtualMachine.compiler()->typeDictionary()), @@ -160,12 +150,6 @@ void MethodBuilder::defineFunctions() { globalTypes().executionContextPtr); } -#define QSTACK(b) (((VirtualMachineState *)(b)->vmState())->_stack) -#define QRELOAD(b) \ - if (cfg_.lazyVmState) ((b)->vmState()->Reload(b)); -#define QRELOAD_DROP(b, toDrop) \ - if (cfg_.lazyVmState) QSTACK(b)->Drop(b, toDrop); - bool MethodBuilder::inlineProgramIntoBuilder( const std::size_t functionIndex, bool isTopLevel, TR::BytecodeBuilder *currentBuilder, @@ -231,19 +215,9 @@ bool MethodBuilder::buildIL() { Store("stackTop", stackTop); if (cfg_.lazyVmState) { - auto simulatedStackTop = new OMR::VirtualMachineRegisterInStruct( - this, "b9::OperandStack", "stack", "top_", "stackTop"); - - auto simulateOperandStack = new OMR::VirtualMachineOperandStack( - this, 64 /* starting size */, globalTypes().stackElement, - simulatedStackTop, true /* grows up */, 0 /* commit address offset */); - - auto vms = new VirtualMachineState(simulateOperandStack, simulatedStackTop); - - setVMState(vms); - + setVMState(new ModelState(this, globalTypes())); } else { - setVMState(new OMR::VirtualMachineState()); + setVMState(new ActiveState(this, globalTypes())); } /// When this function exits, we reset the stack top to the beginning of @@ -380,7 +354,7 @@ bool MethodBuilder::generateILForBytecode( "trace", 2, builder->ConstAddress(function), builder->ConstAddress(&function->instructions[instructionIndex])); - builder->vmState()->Commit(builder); + state(builder)->Commit(builder); } switch (instruction.opCode()) { @@ -487,11 +461,11 @@ bool MethodBuilder::generateILForBytecode( builder->AddFallThroughBuilder(nextBytecodeBuilder); } break; case OpCode::PRIMITIVE_CALL: { - builder->vmState()->Commit(builder); + state(builder)->Commit(builder); TR::IlValue *result = builder->Call("primitive_call", 2, builder->Load("executionContext"), builder->ConstInt32(instruction.immediate())); - QRELOAD(builder); + state(builder)->Reload(builder); if (nextBytecodeBuilder) builder->AddFallThroughBuilder(nextBytecodeBuilder); } break; @@ -584,7 +558,7 @@ bool MethodBuilder::generateILForBytecode( << std::endl; } TR::IlValue *result; - builder->vmState()->Commit(builder); + state(builder)->Commit(builder); if (interp) { if (cfg_.debug) std::cout << "calling interpreter: interpreter_0" << std::endl; @@ -597,7 +571,8 @@ bool MethodBuilder::generateILForBytecode( result = builder->Call(nameToCall, 1, builder->Load("executionContext")); } - QRELOAD_DROP(builder, paramsCount); + state(builder)->adjust(builder, -paramsCount); + state(builder)->Reload(builder); pushValue(builder, result); } } else { @@ -606,11 +581,12 @@ bool MethodBuilder::generateILForBytecode( std::cout << "Calling interpret_0 to dispatch call for " << callee->name << " with " << paramsCount << " args" << std::endl; - builder->vmState()->Commit(builder); + state(builder)->Commit(builder); TR::IlValue *result = builder->Call("interpret_0", 2, builder->Load("executionContext"), builder->ConstInt32(callindex)); - QRELOAD_DROP(builder, paramsCount); + state(builder)->adjust(builder, -paramsCount); + state(builder)->Reload(builder); pushValue(builder, result); } @@ -792,71 +768,30 @@ void MethodBuilder::handle_bc_not(TR::BytecodeBuilder *builder, builder->AddFallThroughBuilder(nextBuilder); } -void MethodBuilder::drop(TR::BytecodeBuilder *builder) { popValue(builder); } +void MethodBuilder::drop(TR::BytecodeBuilder *builder, std::size_t n) { + for (std::size_t i = 0; i < n; i++) popValue(builder); +} /// Input is a Value. -void MethodBuilder::pushValue(TR::BytecodeBuilder *builder, - TR::IlValue *value) { - if (cfg_.lazyVmState) { - VirtualMachineState *vmState = - dynamic_cast(builder->vmState()); - - vmState->_stack->Push(builder, value); - - } else { - TR::IlValue *stack = builder->StructFieldInstanceAddress( - "b9::ExecutionContext", "stack_", builder->Load("executionContext")); - - TR::IlValue *stackTop = - builder->LoadIndirect("b9::OperandStack", "top_", stack); - - builder->StoreAt(stackTop, - builder->ConvertTo(globalTypes().stackElement, value)); - - TR::IlValue *newStackTop = builder->IndexAt( - globalTypes().stackElementPtr, stackTop, builder->ConstInt32(1)); - - builder->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); - } +/// state may model the push, or keep the vm updated. +void MethodBuilder::pushValue(TR::BytecodeBuilder *b, TR::IlValue *value) { + return state(b)->pushValue(b, value); } /// output is an unboxed value. -TR::IlValue *MethodBuilder::popValue(TR::BytecodeBuilder *builder) { - if (cfg_.lazyVmState) { - VirtualMachineState *vmState = - dynamic_cast(builder->vmState()); - - TR::IlValue *result = vmState->_stack->Pop(builder); - - return result; - - } else { - TR::IlValue *stack = builder->StructFieldInstanceAddress( - "b9::ExecutionContext", "stack_", builder->Load("executionContext")); - - TR::IlValue *stackTop = - builder->LoadIndirect("b9::OperandStack", "top_", stack); - - TR::IlValue *newStackTop = builder->IndexAt( - globalTypes().stackElementPtr, stackTop, builder->ConstInt32(-1)); - - builder->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); - - TR::IlValue *value = - builder->LoadAt(globalTypes().stackElementPtr, newStackTop); - - return value; - } +/// State may model the pop, or keep the vm updated. +TR::IlValue *MethodBuilder::popValue(TR::BytecodeBuilder *b) { + return state(b)->popValue(b); } /// input is an unboxed int48. void MethodBuilder::pushInt48(TR::BytecodeBuilder *builder, TR::IlValue *value) { - pushValue(builder, ValueBuilder::fromInt48(builder, value)); + pushValue(builder, OMR::Om::ValueBuilder::fromInt48(builder, value)); } TR::IlValue *MethodBuilder::popInt48(TR::BytecodeBuilder *builder) { - return ValueBuilder::getInt48(builder, popValue(builder)); + return OMR::Om::ValueBuilder::getInt48(builder, popValue(builder)); } } // namespace b9 diff --git a/third_party/omr b/third_party/omr index 72616c7..d187a6f 160000 --- a/third_party/omr +++ b/third_party/omr @@ -1 +1 @@ -Subproject commit 72616c7acbd8030c4ed74d2ca8c546efff07047e +Subproject commit d187a6fb066a858581e1e2b835e2b6f30d4c72a4