Skip to content

Commit

Permalink
Implement general tail call optimization
Browse files Browse the repository at this point in the history
Signed-off-by: HyukWoo Park <[email protected]>
  • Loading branch information
clover2123 authored and ksh8281 committed Feb 20, 2024
1 parent 6555853 commit 023b7ea
Show file tree
Hide file tree
Showing 27 changed files with 368 additions and 89 deletions.
5 changes: 5 additions & 0 deletions src/Escargot.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,11 @@ typedef uint16_t LexicalBlockIndex;
#define REGEXP_CACHE_SIZE_MAX 64
#endif

// maximum number of tail call arguments allowed
#ifndef TCO_ARGUMENT_COUNT_LIMIT
#define TCO_ARGUMENT_COUNT_LIMIT 8
#endif

#include <tsl/robin_set.h>
template <class Key, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
Expand Down
4 changes: 2 additions & 2 deletions src/codecache/CodeCacheReaderWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ void CodeCacheWriter::storeByteCodeBlock(ByteCodeBlock* block)
m_buffer.ensureSize(2 * sizeof(bool) + 2 * sizeof(uint16_t));
m_buffer.put(block->m_shouldClearStack);
m_buffer.put(block->m_isOwnerMayFreed);
m_buffer.put(block->m_needsExtendedExectuionState);
m_buffer.put(block->m_needsExtendedExecutionState);
m_buffer.put((uint16_t)block->m_requiredOperandRegisterNumber);
m_buffer.put((uint16_t)block->m_requiredTotalRegisterNumber);

Expand Down Expand Up @@ -859,7 +859,7 @@ ByteCodeBlock* CodeCacheReader::loadByteCodeBlock(Context* context, InterpretedC

block->m_shouldClearStack = m_buffer.get<bool>();
block->m_isOwnerMayFreed = m_buffer.get<bool>();
block->m_needsExtendedExectuionState = m_buffer.get<bool>();
block->m_needsExtendedExecutionState = m_buffer.get<bool>();
block->m_requiredOperandRegisterNumber = m_buffer.get<uint16_t>();
block->m_requiredTotalRegisterNumber = m_buffer.get<uint16_t>();

Expand Down
4 changes: 2 additions & 2 deletions src/interpreter/ByteCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void SetGlobalVariable::dump()
ByteCodeBlock::ByteCodeBlock()
: m_shouldClearStack(false)
, m_isOwnerMayFreed(false)
, m_needsExtendedExectuionState(false)
, m_needsExtendedExecutionState(false)
, m_requiredOperandRegisterNumber(2)
, m_requiredTotalRegisterNumber(0)
, m_inlineCacheDataSize(0)
Expand Down Expand Up @@ -129,7 +129,7 @@ static void clearByteCodeBlock(ByteCodeBlock* self)
ByteCodeBlock::ByteCodeBlock(InterpretedCodeBlock* codeBlock)
: m_shouldClearStack(false)
, m_isOwnerMayFreed(false)
, m_needsExtendedExectuionState(false)
, m_needsExtendedExecutionState(false)
, m_requiredOperandRegisterNumber(2)
, m_requiredTotalRegisterNumber(0)
, m_inlineCacheDataSize(0)
Expand Down
57 changes: 53 additions & 4 deletions src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ struct GlobalVariableAccessCacheItem;
#if defined(ENABLE_TCO)
#define FOR_EACH_BYTECODE_TCO_OP(F) \
F(CallReturn) \
F(TailCall) \
F(TailRecursion) \
F(TailRecursionInTry)
#else
Expand Down Expand Up @@ -2158,6 +2159,53 @@ class CallReturn : public ByteCode {
#endif
};

class TailCall : public ByteCode {
public:
TailCall(const ByteCodeLOC& loc, const size_t calleeIndex, const size_t argumentsStartIndex, const size_t argumentCount)
: ByteCode(Opcode::TailCallOpcode, loc)
, m_receiverIndex(REGISTER_LIMIT)
, m_calleeIndex(calleeIndex)
, m_argumentsStartIndex(argumentsStartIndex)
, m_argumentCount(argumentCount)
{
// tail call without receiver
}

TailCall(const ByteCodeLOC& loc, const size_t receiverIndex, const size_t calleeIndex, const size_t argumentsStartIndex, const size_t argumentCount)
: ByteCode(Opcode::TailCallOpcode, loc)
, m_receiverIndex(receiverIndex)
, m_calleeIndex(calleeIndex)
, m_argumentsStartIndex(argumentsStartIndex)
, m_argumentCount(argumentCount)
{
// tail call with receiver
}

ByteCodeRegisterIndex m_receiverIndex;
ByteCodeRegisterIndex m_calleeIndex;
ByteCodeRegisterIndex m_argumentsStartIndex;
uint16_t m_argumentCount;

#ifndef NDEBUG
void dump()
{
if (m_receiverIndex != REGISTER_LIMIT) {
if (m_argumentCount) {
printf("tail call r%u.r%u(r%u-r%u)", m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("tail call r%u.r%u()", m_receiverIndex, m_calleeIndex);
}
} else {
if (m_argumentCount) {
printf("tail call r%u(r%u-r%u)", m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("tail call r%u()", m_calleeIndex);
}
}
}
#endif
};

class TailRecursion : public ByteCode {
public:
TailRecursion(const ByteCodeLOC& loc, const size_t calleeIndex, const size_t argumentsStartIndex, const size_t argumentCount)
Expand All @@ -2167,7 +2215,7 @@ class TailRecursion : public ByteCode {
, m_argumentsStartIndex(argumentsStartIndex)
, m_argumentCount(argumentCount)
{
// tail recursion call without receiver
// tail recursion without receiver
}

TailRecursion(const ByteCodeLOC& loc, const size_t receiverIndex, const size_t calleeIndex, const size_t argumentsStartIndex, const size_t argumentCount)
Expand All @@ -2177,7 +2225,7 @@ class TailRecursion : public ByteCode {
, m_argumentsStartIndex(argumentsStartIndex)
, m_argumentCount(argumentCount)
{
// tail recursion call with receiver
// tail recursion with receiver
}

ByteCodeRegisterIndex m_receiverIndex;
Expand Down Expand Up @@ -2232,6 +2280,7 @@ class TailRecursionInTry : public ByteCode {
#endif
};

COMPILE_ASSERT(sizeof(CallReturn) == sizeof(TailCall), "");
COMPILE_ASSERT(sizeof(CallReturn) == sizeof(TailRecursion), "");
COMPILE_ASSERT(sizeof(Call) == sizeof(TailRecursionInTry), "");
#endif
Expand Down Expand Up @@ -3242,7 +3291,7 @@ class ByteCodeBlock : public gc {

bool needsExtendedExecutionState() const
{
return m_needsExtendedExectuionState;
return m_needsExtendedExecutionState;
}

ExtendedNodeLOC computeNodeLOCFromByteCode(Context* c, size_t codePosition, InterpretedCodeBlock* cb, ByteCodeLOCData* locData);
Expand All @@ -3251,7 +3300,7 @@ class ByteCodeBlock : public gc {

bool m_shouldClearStack : 1;
bool m_isOwnerMayFreed : 1;
bool m_needsExtendedExectuionState : 1;
bool m_needsExtendedExecutionState : 1;
// number of bytecode registers used for bytecode operation like adding...moving...
ByteCodeRegisterIndex m_requiredOperandRegisterNumber : REGISTER_INDEX_IN_BIT;
// precomputed value of total register number which is "m_requiredTotalRegisterNumber + stack allocated variables size"
Expand Down
9 changes: 8 additions & 1 deletion src/interpreter/ByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ ByteCodeBlock* ByteCodeGenerator::generateByteCode(Context* context, Interpreted

block->m_code.shrinkToFit();
block->m_requiredTotalRegisterNumber = block->m_requiredOperandRegisterNumber + codeBlock->totalStackAllocatedVariableSize() + block->m_numeralLiteralData.size();
block->m_needsExtendedExectuionState = ctx.m_needsExtendedExecutionState;
block->m_needsExtendedExecutionState = ctx.m_needsExtendedExecutionState;

#if defined(ENABLE_CODE_CACHE)
// cache bytecode right before relocation
Expand Down Expand Up @@ -612,6 +612,13 @@ void ByteCodeGenerator::relocateByteCode(ByteCodeBlock* block)
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TailCallOpcode: {
TailCall* cd = (TailCall*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_calleeIndex, stackBase, stackBaseWillBe, stackVariableSize);
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_argumentsStartIndex, stackBase, stackBaseWillBe, stackVariableSize);
break;
}
case TailRecursionOpcode: {
TailRecursion* cd = (TailRecursion*)currentCode;
ASSIGN_STACKINDEX_IF_NEEDED(cd->m_receiverIndex, stackBase, stackBaseWillBe, stackVariableSize);
Expand Down
Loading

0 comments on commit 023b7ea

Please sign in to comment.