Skip to content

Commit

Permalink
Fix a bug that interpreter reuses an argument buffer of caller in tai…
Browse files Browse the repository at this point in the history
…l call

Signed-off-by: HyukWoo Park <[email protected]>
  • Loading branch information
clover2123 authored and ksh8281 committed May 30, 2023
1 parent 0c1a125 commit 7e68583
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 19 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/es-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
tc: ['octane', 'v8 chakracore spidermonkey']
build_opt: ['', '-DESCARGOT_THREADING=ON', '-DESCARGOT_SMALL_CONFIG=ON -DESCARGOT_USE_CUSTOM_LOGGING=ON']
tc: ['new-es octane', 'v8 chakracore spidermonkey']
build_opt: ['', '-DESCARGOT_THREADING=ON -DESCARGOT_TCO=ON', '-DESCARGOT_SMALL_CONFIG=ON -DESCARGOT_USE_CUSTOM_LOGGING=ON']
exclude:
# exclude spidermonkey on threading-enabled build (TODO)
- tc: 'v8 chakracore spidermonkey'
build_opt: '-DESCARGOT_THREADING=ON'
# exclue octane due to low performance incurred by SMALL_CONFIG
- tc: 'octane'
- tc: 'new-es octane'
build_opt: '-DESCARGOT_SMALL_CONFIG=ON -DESCARGOT_USE_CUSTOM_LOGGING=ON'
steps:
- uses: actions/checkout@v3
Expand Down
37 changes: 30 additions & 7 deletions src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -1966,7 +1966,11 @@ class Call : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("call r%u <- r%u(r%u-r%u)", m_resultIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
if (m_argumentCount) {
printf("call r%u <- r%u(r%u-r%u)", m_resultIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("call r%u <- r%u()", m_resultIndex, m_calleeIndex);
}
}
#endif
};
Expand All @@ -1992,13 +1996,16 @@ class CallWithReceiver : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("call r%u <- r%u,r%u(r%u-r%u)", m_resultIndex, m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
if (m_argumentCount) {
printf("call r%u <- r%u.r%u(r%u-r%u)", m_resultIndex, m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("call r%u <- r%u.r%u()", m_resultIndex, m_receiverIndex, m_calleeIndex);
}
}
#endif
};

#if defined(ENABLE_TCO)
// TCO
class CallReturn : public ByteCode {
public:
CallReturn(const ByteCodeLOC& loc, const size_t calleeIndex, const size_t argumentsStartIndex, const size_t argumentCount)
Expand All @@ -2015,7 +2022,11 @@ class CallReturn : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("tail call r%u(r%u-r%u)", m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
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
};
Expand All @@ -2036,7 +2047,11 @@ class TailRecursion : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("tail recursion call r%u(r%u-r%u)", m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
if (m_argumentCount) {
printf("tail recursion call r%u(r%u-r%u)", m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("tail recursion call r%u()", m_calleeIndex);
}
}
#endif
};
Expand All @@ -2060,7 +2075,11 @@ class CallReturnWithReceiver : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("tail call with receiver <- r%u,r%u(r%u-r%u)", m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
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);
}
}
#endif
};
Expand All @@ -2084,7 +2103,11 @@ class TailRecursionWithReceiver : public ByteCode {
#ifndef NDEBUG
void dump()
{
printf("tail recursion call with receiver r%u,r%u(r%u-r%u)", m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
if (m_argumentCount) {
printf("tail recursion call r%u.r%u(r%u-r%u)", m_receiverIndex, m_calleeIndex, m_argumentsStartIndex, m_argumentsStartIndex + m_argumentCount);
} else {
printf("tail recursion call r%u.r%u()", m_receiverIndex, m_calleeIndex);
}
}
#endif
};
Expand Down
34 changes: 26 additions & 8 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1546,11 +1546,20 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
// fast tail recursion
ASSERT(callee.isPointerValue() && callee.asPointerValue()->isScriptFunctionObject());
ASSERT(callee.asPointerValue()->asScriptFunctionObject()->codeBlock() == byteCodeBlock->codeBlock());

// its safe to overwrite arguments because old arguments are no longer necessary
ASSERT(state->m_argc == code->m_argumentCount);
for (size_t i = 0; i < state->m_argc; i++) {
state->m_argv[i] = registerFile[code->m_argumentsStartIndex + i];

if (code->m_argumentCount) {
// At the start of tail call, we need to allocate a buffer for arguments
// because recursive tail call reuses this buffer
if (UNLIKELY(!state->initTCO())) {
Value* newArgs = ALLOCA(sizeof(Value) * code->m_argumentCount, Value, state);
state->setTCOArguments(newArgs);
}

// its safe to overwrite arguments because old arguments are no longer necessary
for (size_t i = 0; i < state->m_argc; i++) {
state->m_argv[i] = registerFile[code->m_argumentsStartIndex + i];
}
}

// set this value
Expand Down Expand Up @@ -1579,11 +1588,20 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
// fast tail recursion with receiver
ASSERT(callee.isPointerValue() && callee.asPointerValue()->isScriptFunctionObject());
ASSERT(callee.asPointerValue()->asScriptFunctionObject()->codeBlock() == byteCodeBlock->codeBlock());

// its safe to overwrite arguments because old arguments are no longer necessary
ASSERT(state->m_argc == code->m_argumentCount);
for (size_t i = 0; i < state->m_argc; i++) {
state->m_argv[i] = registerFile[code->m_argumentsStartIndex + i];

if (code->m_argumentCount) {
// At the start of tail call, we need to allocate a buffer for arguments
// because recursive tail call reuses this buffer
if (UNLIKELY(!state->initTCO())) {
Value* newArgs = ALLOCA(sizeof(Value) * code->m_argumentCount, Value, state);
state->setTCOArguments(newArgs);
}

// its safe to overwrite arguments because old arguments are no longer necessary
for (size_t i = 0; i < state->m_argc; i++) {
state->m_argv[i] = registerFile[code->m_argumentsStartIndex + i];
}
}

// set this value (receiver) // FIXME
Expand Down
35 changes: 35 additions & 0 deletions src/runtime/ExecutionState.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class ExecutionState : public gc {
, m_onTry(false)
, m_onCatch(false)
, m_onFinally(false)
#if defined(ENABLE_TCO)
, m_initTCO(false)
#endif
, m_argc(parent->argc())
, m_argv(parent->argv())
{
Expand All @@ -99,6 +102,9 @@ class ExecutionState : public gc {
, m_onTry(false)
, m_onCatch(false)
, m_onFinally(false)
#if defined(ENABLE_TCO)
, m_initTCO(false)
#endif
, m_argc(0)
, m_argv(nullptr)
{
Expand All @@ -117,6 +123,9 @@ class ExecutionState : public gc {
, m_onTry(false)
, m_onCatch(false)
, m_onFinally(false)
#if defined(ENABLE_TCO)
, m_initTCO(false)
#endif
, m_argc(argc)
, m_argv(argv)
{
Expand All @@ -135,6 +144,9 @@ class ExecutionState : public gc {
, m_onTry(false)
, m_onCatch(false)
, m_onFinally(false)
#if defined(ENABLE_TCO)
, m_initTCO(false)
#endif
, m_argc(argc)
, m_argv(argv)
{
Expand All @@ -156,6 +168,9 @@ class ExecutionState : public gc {
, m_onTry(false)
, m_onCatch(false)
, m_onFinally(false)
#if defined(ENABLE_TCO)
, m_initTCO(false)
#endif
, m_argc(argc)
, m_argv(argv)
{
Expand Down Expand Up @@ -253,6 +268,22 @@ class ExecutionState : public gc {
return m_onFinally;
}

#if defined(ENABLE_TCO)
bool initTCO() const
{
return m_initTCO;
}

void setTCOArguments(Value* argv)
{
// allocate a new argument buffer
// because tail call reuses this buffer which can modify caller's register file
ASSERT(!m_initTCO && !!argv);
m_initTCO = true;
m_argv = argv;
}
#endif

bool isNativeFunctionObjectExecutionContext() const
{
return m_isNativeFunctionObjectExecutionContext;
Expand Down Expand Up @@ -330,6 +361,10 @@ class ExecutionState : public gc {
bool m_onTry : 1;
bool m_onCatch : 1;
bool m_onFinally : 1;
#if defined(ENABLE_TCO)
bool m_initTCO : 1;
#endif

#ifdef ESCARGOT_32
size_t m_argc : 24;
#else
Expand Down
2 changes: 1 addition & 1 deletion test/vendortest

0 comments on commit 7e68583

Please sign in to comment.