Skip to content

Commit

Permalink
Adds special handling of dynamically inferred blocks
Browse files Browse the repository at this point in the history
Unlike statically inferred block, dynamic ones
need to create and carry their closure environment.

Two blocks with the same set of argument types may have
different closure types even if their closure context
is the same.

We add closure types to a dynamic block's cache key and
to block function name to disambiguate calls.

Issue: #17
Issue: #92
  • Loading branch information
0x7CFE committed Jul 21, 2016
1 parent f17ef79 commit ee7d469
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 13 deletions.
8 changes: 8 additions & 0 deletions include/inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,20 @@ class TypeSystem {
bool sendToSuper = false);

InferContext* inferBlock(Type& block, const Type& arguments, TContextStack* parent);
InferContext* inferDynamicBlock(Type& block, const Type& arguments, const Type& temporaries, TContextStack* parent);

// TODO Solve concurrent modifications by returning:
// - R/O holder to the shared graph
// - R/W holder to the exclusive copy
st::ControlGraph* getMethodGraph(TMethod* method);
st::ControlGraph* getBlockGraph(st::ParsedBlock* parsedBlock);

void dumpAllContexts() const;
void drawCallGraph() const;

private:
void doInferBlock(InferContext* inferContext, Type& block, const Type& arguments, TContextStack* parent);

private:
typedef std::pair<st::ParsedBytecode*, st::ControlGraph*> TGraphEntry;
typedef std::map<TMethod*, TGraphEntry> TGraphCache;
Expand Down
2 changes: 2 additions & 0 deletions src/JITRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,8 @@ void JITRuntime::sendMessage(TContext* callingContext, TSymbol* message, TObject
Function* methodFunction = m_JITModule->getFunction(functionName);

if (! methodFunction) {
outs() << "Compiling dynamic method " << functionName << "\n";

// Compiling function and storing it to the table for further use
methodFunction = m_methodCompiler->compileMethod(method, argumentsType);

Expand Down
7 changes: 4 additions & 3 deletions src/MethodCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,8 +997,10 @@ llvm::Function* MethodCompiler::compileDynamicBlock(TBlock* block)
if (Function* const blockFunction = m_JITModule->getFunction(blockFunctionName))
return blockFunction;

printf("compiling dynamic block %s\n", blockFunctionName.c_str());

type::TContextStack stack(methodContext);
type::InferContext* const blockInferContext = m_typeSystem.inferBlock(blockType, blockArguments, &stack);
type::InferContext* const blockInferContext = m_typeSystem.inferDynamicBlock(blockType, blockArguments, blockTemps, &stack);
assert(blockInferContext);

return compileBlock(blockFunctionName, parsedBlock, *blockInferContext);
Expand Down Expand Up @@ -1033,6 +1035,7 @@ llvm::Function* MethodCompiler::compileInferredBlock(TJITContext& jit)
st::ControlGraph* const methodGraph = m_typeSystem.getMethodGraph(method);
st::ParsedBlock* const parsedBlock = methodGraph->getParsedMethod()->getParsedBlockByOffset(blockOffset);

printf("compiling inferred block %s\n", blockFunctionName.c_str());
return compileBlock(blockFunctionName, parsedBlock, *blockContext);
}

Expand All @@ -1042,8 +1045,6 @@ llvm::Function* MethodCompiler::compileBlock(const std::string& blockFunctionNam
if (Function* const blockFunction = m_JITModule->getFunction(blockFunctionName))
return blockFunction;

printf("compiling block %s\n", blockFunctionName.c_str());

st::ControlGraph* const blockGraph = m_typeSystem.getBlockGraph(parsedBlock);

TJITBlockContext blockContext(this, parsedBlock->getContainer(), parsedBlock, blockGraph, blockcontext);
Expand Down
52 changes: 42 additions & 10 deletions src/TypeAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ InferContext* TypeSystem::inferMessage(
const TContextMap::iterator iContext = contextMap.find(key);
if (iContext != contextMap.end()) {
InferContext* const cachedContext = iContext->second;
std::printf("*** Found cached context for key: %s, cache: %p\n", key.toString().c_str(), &contextMap);
std::printf("*** Found cached context for key: %s, selector: %s\n", key.toString().c_str(), selector->toString().c_str());

if (cachedContext->getRecursionKind() == InferContext::rkUnknown) {
for (TContextStack* stack = parent; stack; stack = stack->parent) {
Expand All @@ -1255,7 +1255,7 @@ InferContext* TypeSystem::inferMessage(
return cachedContext;
}

std::printf("*** Not found cached context for key: %s, cache: %p\n", key.toString().c_str(), &contextMap);
std::printf("*** Not found cached context for key: %s, selector: %s\n", key.toString().c_str(), selector->toString().c_str());
}

TClass* receiver = 0;
Expand Down Expand Up @@ -1313,29 +1313,63 @@ InferContext* TypeSystem::inferMessage(
return inferContext;
}

InferContext* TypeSystem::inferBlock(Type& block, const Type& arguments, TContextStack* parent) {
if (block.getKind() != Type::tkMonotype)
InferContext* TypeSystem::inferDynamicBlock(
Type& block,
const Type& arguments,
const Type& temporaries,
TContextStack* parent)
{
if (! block.isBlock())
return 0;

// FIXME Prove that this is enough.
// What about captured types/args?
Type key(Type::tkArray);
key.pushSubType(block);
key.pushSubType(arguments);
key.pushSubType(temporaries);

TBlockCache::iterator iBlock = m_blockCache.find(key);
if (iBlock != m_blockCache.end())
return iBlock->second;

TMethod* const method = block[Type::bstOrigin].getValue()->cast<TMethod>();
const uint16_t offset = TInteger(block[Type::bstOffset].getValue());
InferContext* const inferContext = new InferContext(method, m_lastContextIndex++, arguments);
m_blockCache[key] = inferContext;
std::printf("Cached dynamic block context %s -> %p (index %u), cache size %u\n",
key.toString().c_str(), inferContext, inferContext->getIndex(), m_blockCache.size());

InferContext* inferContext = new InferContext(method, m_lastContextIndex++, arguments);
doInferBlock(inferContext, block, arguments, parent);

return inferContext;
}

InferContext* TypeSystem::inferBlock(Type& block, const Type& arguments, TContextStack* parent) {
if (! block.isBlock())
return 0;

Type key(Type::tkArray);
key.pushSubType(block);
key.pushSubType(arguments);

TBlockCache::iterator iBlock = m_blockCache.find(key);
if (iBlock != m_blockCache.end())
return iBlock->second;

TMethod* const method = block[Type::bstOrigin].getValue()->cast<TMethod>();
InferContext* const inferContext = new InferContext(method, m_lastContextIndex++, arguments);

m_blockCache[key] = inferContext;
std::printf("Cached block context %s -> %p (index %u), cache size %u\n",
key.toString().c_str(), inferContext, inferContext->getIndex(), m_blockCache.size());

doInferBlock(inferContext, block, arguments, parent);
return inferContext;

}

void TypeSystem::doInferBlock(InferContext* inferContext, Type& block, const Type& arguments, TContextStack* parent) {
TMethod* const method = block[Type::bstOrigin].getValue()->cast<TMethod>();
const uint16_t offset = TInteger(block[Type::bstOffset].getValue());

ControlGraph* const methodGraph = getMethodGraph(method);
assert(methodGraph);

Expand Down Expand Up @@ -1366,8 +1400,6 @@ InferContext* TypeSystem::inferBlock(Type& block, const Type& arguments, TContex

std::printf("%s::%s -> %s\n", arguments.toString().c_str(), block.toString().c_str(),
inferContext->getRawReturnType().toString().c_str());

return inferContext;
}

void type::TypeSystem::dumpAllContexts() const {
Expand Down

0 comments on commit ee7d469

Please sign in to comment.