Skip to content

Commit

Permalink
Fixes compiler and runtime related to dynamic block dispatch
Browse files Browse the repository at this point in the history
Issue: #17
Issue: #92
  • Loading branch information
0x7CFE committed Jul 17, 2016
1 parent 15a7e2a commit 3daecdb
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 29 deletions.
4 changes: 2 additions & 2 deletions include/inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ typedef std::map<TNodeIndex, Type> TTypeMap;

inline std::string getQualifiedMethodName(TMethod* method, const Type& arguments) {
return
arguments.toString(true) + "::" +
method->getClass()->name->toString() + ">>" +
arguments.toString() + "::" +
method->klass->name->toString() + ">>" +
method->name->toString();
}

Expand Down
4 changes: 2 additions & 2 deletions include/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ class MethodCompiler {

void doPushBlock(TJITContext& jit);
llvm::Function* compileBlock(const std::string& blockFunctionName, st::ParsedBlock* parsedBlock, type::InferContext& blockContext);
llvm::Function* compileInvokedBlock(TJITContext& jit);
llvm::Function* compileInferredBlock(TJITContext& jit);

void doAssignTemporary(TJITContext& jit);
void doAssignInstance(TJITContext& jit);
Expand Down Expand Up @@ -385,7 +385,7 @@ class MethodCompiler {
llvm::Value** contextHolder = 0
);

llvm::Function* compileBlock(TBlock* block);
llvm::Function* compileDynamicBlock(TBlock* block);

// TStackObject is a pair of entities allocated on a thread stack space
// objectSlot is a container for actual object's data
Expand Down
5 changes: 1 addition & 4 deletions src/JITRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,8 @@ void JITRuntime::invokeBlock(TBlock* block, TContext* callingContext, TReturnVal
Function* blockFunction = 0;

if (! compiledBlockFunction) {
// Block functions are created when wrapping method gets compiled.
// If function was not found then the whole method needs compilation.

// Compiling function and storing it to the table for further use
blockFunction = m_methodCompiler->compileBlock(block);
blockFunction = m_methodCompiler->compileDynamicBlock(block);

if (!blockFunction) {
// Something is really wrong!
Expand Down
70 changes: 49 additions & 21 deletions src/MethodCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,7 @@ void createBlockTypes(
st::ControlGraph& blockGraph,
type::Type& blockType,
type::Type& blockArguments,
type::Type& blockTemps,
type::InferContext::TVariableMap& closureTypes)
{
blockType.set(globals.blockClass, type::Type::tkMonotype);
Expand All @@ -931,6 +932,11 @@ void createBlockTypes(
const uint32_t argumentLocation = block->argumentLocation;

const st::ControlGraph::TMetaInfo::TIndexList& readsTemporaries = blockGraph.getMeta().readsTemporaries;
const st::ControlGraph::TMetaInfo::TIndexList& writesTemporaries = blockGraph.getMeta().writesTemporaries;

type::Type readIndices(globals.arrayClass, type::Type::tkArray);
type::Type writeIndices(globals.arrayClass, type::Type::tkArray);

for (std::size_t index = 0; index < readsTemporaries.size(); index++) {
const uint32_t tempIndex = readsTemporaries[index];
TObject* const argument = temporaries[tempIndex];
Expand All @@ -940,17 +946,37 @@ void createBlockTypes(
if (readsTemporaries[index] < argumentLocation)
closureTypes[tempIndex] = newType;
else
blockArguments.pushSubType(newType);
blockTemps.pushSubType(newType);

// We're interested only in temporaries from lexical context, not block arguments
if (readsTemporaries[index] < argumentLocation)
readIndices.pushSubType(type::Type(TInteger(readsTemporaries[index])));
}

for (std::size_t index = 0; index < writesTemporaries.size(); index++) {
// We're interested only in temporaries from lexical context, not block arguments
if (writesTemporaries[index] >= argumentLocation)
continue;

writeIndices.pushSubType(type::Type(TInteger(writesTemporaries[index])));
}

blockType.pushSubType(readIndices); // [Type::bstReadsTemps]
blockType.pushSubType(writeIndices); // [Type::bstWritesTemps]
blockType.pushSubType(type::Type(TInteger(0))); // [Type::bstCaptureIndex]
}

std::string getBlockFunctionName(const type::Type& blockType, const type::Type& blockArguments)
std::string getDynamicBlockFunctionName(const type::Type& blockType, const type::Type& blockArguments, const type::Type& blockTemps)
{
return blockArguments.toString() + blockTemps.toString() + "::" + blockType.toString();
}

std::string getStaticBlockFunctionName(const type::Type& blockType, const type::Type& blockArguments)
{
return blockArguments.toString() + "::" + blockType.toString();
}

llvm::Function* MethodCompiler::compileBlock(TBlock* block)
llvm::Function* MethodCompiler::compileDynamicBlock(TBlock* block)
{
const uint16_t blockOffset = block->blockBytePointer;
st::ControlGraph* const methodGraph = m_typeSystem.getMethodGraph(block->method);
Expand All @@ -964,10 +990,11 @@ llvm::Function* MethodCompiler::compileBlock(TBlock* block)

type::Type blockType;
type::Type blockArguments(globals.arrayClass, type::Type::tkArray);
createBlockTypes(block, *blockGraph, blockType, blockArguments, closureTypes);
type::Type blockTemps(globals.arrayClass, type::Type::tkArray);
createBlockTypes(block, *blockGraph, blockType, blockArguments, blockTemps, closureTypes);

// Check if function was already compiled
const std::string& blockFunctionName = getBlockFunctionName(blockType, blockArguments);
const std::string& blockFunctionName = getDynamicBlockFunctionName(blockType, blockArguments, blockTemps);
if (Function* const blockFunction = m_JITModule->getFunction(blockFunctionName))
return blockFunction;

Expand All @@ -978,10 +1005,10 @@ llvm::Function* MethodCompiler::compileBlock(TBlock* block)
return compileBlock(blockFunctionName, parsedBlock, *blockInferContext);
}

llvm::Function* MethodCompiler::compileInvokedBlock(TJITContext& jit)
llvm::Function* MethodCompiler::compileInferredBlock(TJITContext& jit)
{
type::Type& blockType = jit.inferContext[*jit.currentNode->getArgument()];
if (blockType.isBlock())
if (! blockType.isBlock())
return 0;

type::Type blockArguments(type::Type::tkArray);
Expand All @@ -992,13 +1019,12 @@ llvm::Function* MethodCompiler::compileInvokedBlock(TJITContext& jit)
if (jit.currentNode->getArgumentsCount() > 2)
blockArguments.pushSubType(jit.inferContext[*jit.currentNode->getArgument(2)]);

type::TContextStack stack(jit.inferContext); // Probably not needed, the context must already be cached
type::InferContext* const blockContext = m_typeSystem.inferBlock(blockType, blockArguments, &stack);
type::InferContext* const blockContext = m_typeSystem.inferBlock(blockType, blockArguments, 0);

if (! blockContext)
return 0;

const std::string& blockFunctionName = getBlockFunctionName(blockType, blockArguments);
const std::string& blockFunctionName = getStaticBlockFunctionName(blockType, blockArguments);
if (Function* const blockFunction = m_JITModule->getFunction(blockFunctionName))
return blockFunction;

Expand Down Expand Up @@ -1514,8 +1540,7 @@ void MethodCompiler::doSendMessage(TJITContext& jit)
const uint32_t literalIndex = jit.currentNode->getInstruction().getArgument();
TSymbol* const selector = literals[literalIndex];

type::InferContext* const messageContext = m_typeSystem.inferMessage(selector, arguments, 0, false);
if (messageContext) {
if (type::InferContext* const messageContext = m_typeSystem.inferMessage(selector, arguments, 0, false)) {
doSendInferredMessage(jit, *messageContext);
return;
}
Expand Down Expand Up @@ -1905,29 +1930,31 @@ void MethodCompiler::compilePrimitive(TJITContext& jit,
break;

case primitive::blockInvoke: { // 8

Value* const object = getArgument(jit); // jit.popValue();
Value* const block = jit.builder->CreateBitCast(object, m_baseTypes.block->getPointerTo());

const uint32_t argCount = jit.currentNode->getInstruction().getArgument() - 1;

Value* const blockAsContext = jit.builder->CreateBitCast(block, m_baseTypes.context->getPointerTo());
Value* const blockTemps = jit.builder->CreateCall(m_baseFunctions.getTemps, blockAsContext);
Value* const tempsSize = jit.builder->CreateCall(m_baseFunctions.getObjectSize, blockTemps, "tempsSize.");

// Value* const tempsSize = jit.builder->CreateCall(m_baseFunctions.getObjectSize, blockTemps, "tempsSize.");
Value* const argumentLocationPtr = jit.builder->CreateStructGEP(block, 1);
Value* const argumentLocationField = jit.builder->CreateLoad(argumentLocationPtr);
Value* const argumentLocationObject = jit.builder->CreateIntToPtr(argumentLocationField, m_baseTypes.object->getPointerTo());
Value* const argumentLocation = jit.builder->CreateCall(m_baseFunctions.getIntegerValue, argumentLocationObject, "argLocation.");

BasicBlock* const tempsChecked = BasicBlock::Create(m_JITModule->getContext(), "tempsChecked.", jit.function);
tempsChecked->moveAfter(jit.builder->GetInsertBlock());
// BasicBlock* const tempsChecked = BasicBlock::Create(m_JITModule->getContext(), "tempsChecked.", jit.function);
// tempsChecked->moveAfter(jit.builder->GetInsertBlock());

// FIXME Check will lead to a crash if containing method have no temporaries at all
// TODO Remove the check if block is inferred
//Checking the passed temps size TODO unroll stack
Value* const blockAcceptsArgCount = jit.builder->CreateSub(tempsSize, argumentLocation, "blockAcceptsArgCount.");
Value* const tempSizeOk = jit.builder->CreateICmpSLE(jit.builder->getInt32(argCount), blockAcceptsArgCount, "tempSizeOk.");
jit.builder->CreateCondBr(tempSizeOk, tempsChecked, primitiveFailedBB);
jit.builder->SetInsertPoint(tempsChecked);
// Value* const blockAcceptsArgCount = jit.builder->CreateSub(tempsSize, argumentLocation, "blockAcceptsArgCount.");
// Value* const tempSizeOk = jit.builder->CreateICmpSLE(jit.builder->getInt32(argCount), blockAcceptsArgCount, "tempSizeOk.");
// jit.builder->CreateCondBr(tempSizeOk, tempsChecked, primitiveFailedBB);
// jit.builder->SetInsertPoint(tempsChecked);

// Storing values in the block's wrapping context
for (uint32_t index = argCount - 1, count = argCount; count > 0; index--, count--)
Expand All @@ -1939,12 +1966,13 @@ void MethodCompiler::compilePrimitive(TJITContext& jit,
jit.builder->CreateCall3(m_baseFunctions.setObjectField, blockTemps, fieldIndex, argument);
}

if (Function* const blockFunction = compileInvokedBlock(jit))
if (Function* const blockFunction = compileInferredBlock(jit)) {
// Direct call to the inferred block function
primitiveResult = jit.builder->CreateCall(blockFunction, block);
else
} else {
// Generic dispatch using runtime
primitiveResult = jit.builder->CreateCall2(m_runtimeAPI.invokeBlock, block, jit.getCurrentContext());
}
} break;

case primitive::throwError: { //19
Expand Down

0 comments on commit 3daecdb

Please sign in to comment.