Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
Re-introduce literal functions (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
lnihlen committed Oct 2, 2022
1 parent b63af69 commit 22d0e29
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 30 deletions.
30 changes: 28 additions & 2 deletions src/hadron/Generator.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
#include "hadron/Generator.hpp"

#include "hadron/library/HadronHIR.hpp"
#include "hadron/library/Function.hpp"
#include "hadron/ThreadContext.hpp"

namespace hadron {

SCMethod Generator::serialize(ThreadContext* context, const library::CFGFrame frame) {
SCMethod Generator::serialize(ThreadContext* context, library::CFGFrame frame) {
// Compile any inner blocks first.
for (int32_t i = 0; i < frame.innerBlocks().size(); ++i) {
auto innerBlock = frame.innerBlocks().typedAt(i);
SCMethod code = serialize(context, innerBlock.frame());
auto functionDef = library::FunctionDef::alloc(context);
functionDef.initToNil();
functionDef.setCode(Slot::makeRawPointer(reinterpret_cast<int8_t*>(code)));
functionDef.setSelectors(innerBlock.frame().selectors());
functionDef.setPrototypeFrame(innerBlock.frame().prototypeFrame());
innerBlock.setFunctionDef(functionDef);
frame.setSelectors(frame.selectors().typedAdd(context, functionDef));
}

// Map of block number (index) to Block struct, useful when traversing control flow graph.
std::vector<library::CFGBlock> blocks;
blocks.resize(frame.numberOfBlocks(), library::CFGBlock());
Expand All @@ -27,7 +42,7 @@ SCMethod Generator::serialize(ThreadContext* context, const library::CFGFrame fr
// Third argument is the stack pointer.
signature.addArg(asmjit::TypeId::kIntPtr);

return buildFunction(context, frame, signature, blocks, blockOrder);
return buildFunction(context, signature, blocks, blockOrder);
}

// static
Expand All @@ -45,6 +60,17 @@ void Generator::markThreadForJITExecution() {
#endif
}

// static
uint64_t Generator::newFunction(ThreadContext* context, uint64_t functionDef,
schema::FramePrivateSchema* framePointer) {
auto def = library::FunctionDef(Slot::makeFromBits(functionDef));
auto frame = library::Frame(framePointer);
auto f = library::Function::alloc(context);
f.setDef(def);
f.setContext(frame);
return f.slot().asBits();
}

void Generator::orderBlocks(ThreadContext* context, library::CFGBlock block, std::vector<library::CFGBlock>& blocks,
library::TypedArray<library::BlockId> blockOrder) {
// Mark block as visited by updating number to pointer map.
Expand Down
9 changes: 4 additions & 5 deletions src/hadron/Generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@
// c) Selector-specific dispatch function that handles routing

namespace hadron {
namespace schema {
struct FramePrivateSchema;
} // namespace schema

typedef uint64_t (*SCMethod)(ThreadContext*, schema::FramePrivateSchema* framePointer, Slot* stackPointer);

Expand All @@ -41,16 +38,18 @@ class Generator {
Generator() = default;
~Generator() = default;

SCMethod serialize(ThreadContext* context, const library::CFGFrame frame);
SCMethod serialize(ThreadContext* context, library::CFGFrame frame);

static bool markThreadForJITCompilation();
static void markThreadForJITExecution();

private:
static uint64_t newFunction(ThreadContext* context, uint64_t functionDef, schema::FramePrivateSchema* framePointer);

// Performs a recursive postorder traversal of the blocks and saves the output in |blockOrder|.
void orderBlocks(ThreadContext* context, library::CFGBlock block, std::vector<library::CFGBlock>& blocks,
library::TypedArray<library::BlockId> blockOrder);
SCMethod buildFunction(ThreadContext* context, const library::CFGFrame frame, asmjit::FuncSignature signature,
SCMethod buildFunction(ThreadContext* context, asmjit::FuncSignature signature,
std::vector<library::CFGBlock>& blocks, library::TypedArray<library::BlockId> blockOrder);

asmjit::JitRuntime m_jitRuntime; // needs to last for the lifetime of the program
Expand Down
28 changes: 20 additions & 8 deletions src/hadron/GeneratorA64.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "hadron/Generator.hpp"

#include "hadron/ClassLibrary.hpp"
#include "hadron/library/Function.hpp"
#include "hadron/library/HadronHIR.hpp"

#include "spdlog/spdlog.h"
Expand All @@ -9,8 +10,8 @@

namespace hadron {

SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFrame /* frame */,
asmjit::FuncSignature signature, std::vector<library::CFGBlock>& blocks,
SCMethod Generator::buildFunction(ThreadContext* context, asmjit::FuncSignature signature,
std::vector<library::CFGBlock>& blocks,
library::TypedArray<library::BlockId> blockOrder) {
asmjit::CodeHolder codeHolder;
codeHolder.init(m_jitRuntime.environment());
Expand Down Expand Up @@ -46,9 +47,20 @@ SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFram
for (int32_t j = 0; j < block.statements().size(); ++j) {
auto hir = block.statements().typedAt(j);
switch (hir.className()) {
case library::BlockLiteralHIR::nameHash():
assert(false);
case library::BlockLiteralHIR::nameHash(): {
auto blockLiteralHIR = library::BlockLiteralHIR(hir.slot());
auto invokePointer = compiler.newGp(asmjit::TypeId::kUIntPtr);
compiler.mov(invokePointer, (uint64_t)Generator::newFunction);
asmjit::InvokeNode* invokeNode = nullptr;
compiler.invoke(&invokeNode, invokePointer,
asmjit::FuncSignatureT<uint64_t, ThreadContext*, uint64_t, schema::FramePrivateSchema*>(
asmjit::CallConvId::kHost));
invokeNode->setRet(0, vRegs[blockLiteralHIR.id().int32()]);
invokeNode->setArg(0, contextReg);
invokeNode->setArg(1, asmjit::Imm(blockLiteralHIR.functionDef().slot().asBits()));
invokeNode->setArg(2, framePointerReg);
break;
}

case library::BranchHIR::nameHash(): {
auto branchHIR = library::BranchHIR(hir.slot());
Expand Down Expand Up @@ -94,13 +106,13 @@ SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFram
compiler.invoke(&invokeNode, functionPointer,
asmjit::FuncSignatureT<uint64_t, ThreadContext*, Hash, int32_t, int32_t,
schema::FramePrivateSchema*, Slot*>(asmjit::CallConvId::kHost));
invokeNode->setRet(0, vRegs[messageHIR.id().int32()]);
invokeNode->setArg(0, contextReg);
invokeNode->setArg(1, asmjit::Imm(messageHIR.selector(context).hash()));
invokeNode->setArg(2, asmjit::Imm(messageHIR.arguments().size()));
invokeNode->setArg(3, asmjit::Imm(messageHIR.keywordArguments().size() / 2));
invokeNode->setArg(4, framePointerReg);
invokeNode->setArg(5, stackPointerReg);
invokeNode->setRet(0, vRegs[messageHIR.id().int32()]);
} break;

case library::MethodReturnHIR::nameHash(): {
Expand All @@ -125,9 +137,9 @@ SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFram

case library::ReadFromFrameHIR::nameHash(): {
auto readFromFrameHIR = library::ReadFromFrameHIR(hir.slot());
auto src = asmjit::a64::ptr(framePointerReg,
sizeof(schema::FramePrivateSchema)
+ ((readFromFrameHIR.frameIndex() - 1) * kSlotSize));
auto fp = readFromFrameHIR.frameId() ? vRegs[readFromFrameHIR.frameId().int32()] : framePointerReg;
auto src = asmjit::a64::ptr(
fp, sizeof(schema::FramePrivateSchema) + ((readFromFrameHIR.frameIndex() - 1) * kSlotSize));
compiler.ldr(vRegs[readFromFrameHIR.id().int32()], src);
} break;

Expand Down
25 changes: 17 additions & 8 deletions src/hadron/GeneratorX64.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#include "hadron/Generator.hpp"

#include "hadron/ClassLibrary.hpp"
#include "hadron/library/Function.hpp"
#include "hadron/library/HadronHIR.hpp"

#include <algorithm>

namespace hadron {

SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFrame /* frame */,
asmjit::FuncSignature signature, std::vector<library::CFGBlock>& blocks,
SCMethod Generator::buildFunction(ThreadContext* context, asmjit::FuncSignature signature,
std::vector<library::CFGBlock>& blocks,
library::TypedArray<library::BlockId> blockOrder) {
asmjit::CodeHolder codeHolder;
codeHolder.init(m_jitRuntime.environment());
Expand Down Expand Up @@ -45,9 +46,17 @@ SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFram
for (int32_t j = 0; j < block.statements().size(); ++j) {
auto hir = block.statements().typedAt(j);
switch (hir.className()) {
case library::BlockLiteralHIR::nameHash():
assert(false);
break;
case library::BlockLiteralHIR::nameHash(): {
auto blockLiteralHIR = library::BlockLiteralHIR(hir.slot());
asmjit::InvokeNode* invokeNode = nullptr;
compiler.invoke(&invokeNode, Generator::newFunction,
asmjit::FuncSignatureT<uint64_t, ThreadContext*, uint64_t, schema::FramePrivateSchema*>(
asmjit::CallConvId::kHost));
invokeNode->setRet(0, vRegs[blockLiteralHIR.id().int32()]);
invokeNode->setArg(0, contextReg);
invokeNode->setArg(1, asmjit::Imm(blockLiteralHIR.functionDef().slot().asBits()));
invokeNode->setArg(2, framePointerReg);
} break;

case library::BranchHIR::nameHash(): {
auto branchHIR = library::BranchHIR(hir.slot());
Expand Down Expand Up @@ -120,9 +129,9 @@ SCMethod Generator::buildFunction(ThreadContext* context, const library::CFGFram

case library::ReadFromFrameHIR::nameHash(): {
auto readFromFrameHIR = library::ReadFromFrameHIR(hir.slot());
auto src = asmjit::x86::ptr(framePointerReg,
sizeof(schema::FramePrivateSchema)
+ ((readFromFrameHIR.frameIndex() - 1) * kSlotSize));
auto fp = readFromFrameHIR.frameId() ? vRegs[readFromFrameHIR.frameId().int32()] : framePointerReg;
auto src = asmjit::x86::ptr(
fp, sizeof(schema::FramePrivateSchema) + ((readFromFrameHIR.frameIndex() - 1) * kSlotSize));
compiler.mov(vRegs[readFromFrameHIR.id().int32()], src);
} break;

Expand Down
6 changes: 6 additions & 0 deletions src/hadron/library/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ Slot ObjectBase::_BasicNew(ThreadContext* context, int32_t maxSize) {
object->sizeInBytes = sizeInBytes;
object->className = targetName.hash();
object->allocationSize = allocatedSize;
Slot* contents = reinterpret_cast<Slot*>(object + 1);
for (int32_t i = 0; i < sizeInSlots; ++i) {
*contents = Slot::makeNil();
++contents;
}

return Slot::makePointer(object);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set(SCTESTS
expressions/primitives

lexical_analysis/floats
# lexical_analysis/functions
lexical_analysis/functions
lexical_analysis/integers
)

Expand Down
8 changes: 2 additions & 6 deletions tests/lexical_analysis/functions.sctest
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
//+//: Function Declarations Tests

//+ RUN: Empty function declaration
(
{}
)
//+ EXPECTING:
a Function
//+ CHECK: {}
//+ GIVES: a Function
//+//:

0 comments on commit 22d0e29

Please sign in to comment.