mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
A class definition is always strict mode
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
2dee22f5c7
commit
a2381044da
6 changed files with 93 additions and 1 deletions
|
|
@ -139,6 +139,7 @@ struct GlobalVariableAccessCacheItem;
|
|||
F(StoreByNameWithAddress) \
|
||||
F(InitializeDisposable) \
|
||||
F(FinalizeDisposable) \
|
||||
F(SetExecutionStateInStrictMode) \
|
||||
F(FillOpcodeTable) \
|
||||
F(End)
|
||||
|
||||
|
|
@ -3139,6 +3140,32 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
// A class definition is always strict mode code, including its heritage
|
||||
// expression and computed property names, even when it appears inside
|
||||
// non-strict code. This opcode temporarily forces the running execution state
|
||||
// into strict mode while those parts are evaluated.
|
||||
// When m_enter is true, the current strict flag is saved into m_savedStrictRegisterIndex
|
||||
// and strict mode is turned on. When m_enter is false, the strict flag is restored
|
||||
// from m_savedStrictRegisterIndex (so that nested classes restore correctly).
|
||||
class SetExecutionStateInStrictMode : public ByteCode {
|
||||
public:
|
||||
SetExecutionStateInStrictMode(const ByteCodeLOC& loc, bool enter, const size_t savedStrictRegisterIndex)
|
||||
: ByteCode(Opcode::SetExecutionStateInStrictModeOpcode, loc)
|
||||
, m_enter(enter)
|
||||
, m_savedStrictRegisterIndex(savedStrictRegisterIndex)
|
||||
{
|
||||
}
|
||||
|
||||
bool m_enter;
|
||||
ByteCodeRegisterIndex m_savedStrictRegisterIndex;
|
||||
#ifndef NDEBUG
|
||||
void dump()
|
||||
{
|
||||
printf("set execution state in strict mode (%s) <-> r%u", m_enter ? "enter" : "exit", m_savedStrictRegisterIndex);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class BindingCalleeIntoRegister : public ByteCode {
|
||||
public:
|
||||
BindingCalleeIntoRegister(const ByteCodeLOC& loc)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ public:
|
|||
static void initializeDisposable(ExecutionState& state, Value* registerFile, size_t& programCounter);
|
||||
static bool finalizeDisposable(ExecutionState& state, Value* registerFile, size_t& programCounter, ByteCodeBlock* byteCodeBlock);
|
||||
|
||||
static void setExecutionStateInStrictModeOperation(ExecutionState& state, Value* registerFile, size_t& programCounter);
|
||||
|
||||
#if defined(ENABLE_TCO)
|
||||
static Value tailRecursionSlowCase(ExecutionState& state, TailRecursion* code, ByteCodeBlock* byteCodeBlock, const Value& callee, Value* registerFile);
|
||||
static Value prepareTailCallOptimization(ExecutionState*& state, TailCall* code, ScriptFunctionObject* callee, ByteCodeBlock*& callerBlock, size_t& programCounter, const Value* registerFile);
|
||||
|
|
@ -1574,6 +1576,14 @@ Value Interpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock
|
|||
NEXT_INSTRUCTION();
|
||||
}
|
||||
|
||||
// Rarely-used; see InterpreterSlowPath::setExecutionStateInStrictModeOperation.
|
||||
DEFINE_OPCODE(SetExecutionStateInStrictMode)
|
||||
:
|
||||
{
|
||||
InterpreterSlowPath::setExecutionStateInStrictModeOperation(*state, registerFile, programCounter);
|
||||
NEXT_INSTRUCTION();
|
||||
}
|
||||
|
||||
#if defined(ENABLE_TCO)
|
||||
// Tail recursion
|
||||
DEFINE_OPCODE(TailRecursion)
|
||||
|
|
@ -4883,6 +4893,23 @@ NEVER_INLINE void InterpreterSlowPath::initializeDisposable(ExecutionState& stat
|
|||
ADD_PROGRAM_COUNTER(InitializeDisposable);
|
||||
}
|
||||
|
||||
// A class definition is always strict mode code. This rarely-used opcode forces
|
||||
// the running execution state into strict mode while a class's heritage expression
|
||||
// and computed property names are evaluated, then restores the previous strict flag.
|
||||
// Kept out-of-line (and away from the hot opcodes) on purpose to keep it out of the
|
||||
// interpreter's hot path.
|
||||
NEVER_INLINE void InterpreterSlowPath::setExecutionStateInStrictModeOperation(ExecutionState& state, Value* registerFile, size_t& programCounter)
|
||||
{
|
||||
SetExecutionStateInStrictMode* code = (SetExecutionStateInStrictMode*)programCounter;
|
||||
if (code->m_enter) {
|
||||
registerFile[code->m_savedStrictRegisterIndex] = Value(state.inStrictMode());
|
||||
state.setInStrictMode(true);
|
||||
} else {
|
||||
state.setInStrictMode(registerFile[code->m_savedStrictRegisterIndex].asBoolean());
|
||||
}
|
||||
ADD_PROGRAM_COUNTER(SetExecutionStateInStrictMode);
|
||||
}
|
||||
|
||||
static void finalizeDisposableAwaitOperation(ExecutionState& state, ByteCodeBlock* byteCodeBlock, DisposableResourceRecord* data,
|
||||
const Value& awaitValue, size_t programCounter, FinalizeDisposable* code, size_t nextStage)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,6 +55,17 @@ public:
|
|||
context->m_classInfo.m_prototypeIndex = context->getRegister();
|
||||
context->m_classInfo.m_superIndex = hasSuper ? context->getRegister() : SIZE_MAX;
|
||||
|
||||
// A class definition is always strict mode code. When the surrounding code
|
||||
// is not strict, force strict mode while the heritage expression and the
|
||||
// computed property names are evaluated. The save register is allocated last
|
||||
// (on top of the register stack) so the completion-value register is untouched.
|
||||
bool needStrictModeSwitch = !codeBlock->m_codeBlock->isStrict();
|
||||
ByteCodeRegisterIndex savedStrictRegister = REGISTER_LIMIT;
|
||||
if (needStrictModeSwitch) {
|
||||
savedStrictRegister = context->getRegister();
|
||||
codeBlock->pushCode(SetExecutionStateInStrictMode(ByteCodeLOC(m_loc.index), true, savedStrictRegister), context, this->m_loc.index);
|
||||
}
|
||||
|
||||
// add class name property if there is no 'name' static member
|
||||
if (m_class.classBody()->hasStaticMemberName(codeBlock->m_codeBlock->context()->staticStrings().name)) {
|
||||
context->m_classInfo.m_name = Optional<AtomicString>();
|
||||
|
|
@ -104,6 +115,11 @@ public:
|
|||
classIdent->generateStoreByteCode(codeBlock, context, classIndex, true);
|
||||
ASSERT(!context->m_isLexicallyDeclaredBindingInitialization);
|
||||
|
||||
if (needStrictModeSwitch) {
|
||||
codeBlock->pushCode(SetExecutionStateInStrictMode(ByteCodeLOC(m_loc.index), false, savedStrictRegister), context, this->m_loc.index);
|
||||
context->giveUpRegister(); // for drop savedStrictRegister (allocated last)
|
||||
}
|
||||
|
||||
if (context->m_classInfo.m_superIndex != SIZE_MAX) {
|
||||
context->giveUpRegister(); // for drop m_superIndex
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,16 @@ public:
|
|||
Node* classIdent = m_class.id();
|
||||
bool hasSuper = m_class.superClass();
|
||||
|
||||
// A class definition is always strict mode code. When the surrounding code
|
||||
// is not strict, force strict mode while the heritage expression and the
|
||||
// computed property names are evaluated.
|
||||
bool needStrictModeSwitch = !codeBlock->m_codeBlock->isStrict();
|
||||
ByteCodeRegisterIndex savedStrictRegister = REGISTER_LIMIT;
|
||||
if (needStrictModeSwitch) {
|
||||
savedStrictRegister = context->getRegister();
|
||||
codeBlock->pushCode(SetExecutionStateInStrictMode(ByteCodeLOC(m_loc.index), true, savedStrictRegister), context, this->m_loc.index);
|
||||
}
|
||||
|
||||
const ClassContextInformation classInfoBefore = context->m_classInfo;
|
||||
context->m_classInfo.m_constructorIndex = dstIndex;
|
||||
context->m_classInfo.m_prototypeIndex = context->getRegister();
|
||||
|
|
@ -107,6 +117,11 @@ public:
|
|||
context->giveUpRegister(); // for drop m_bodyIndex
|
||||
|
||||
context->m_classInfo = classInfoBefore;
|
||||
|
||||
if (needStrictModeSwitch) {
|
||||
codeBlock->pushCode(SetExecutionStateInStrictMode(ByteCodeLOC(m_loc.index), false, savedStrictRegister), context, this->m_loc.index);
|
||||
context->giveUpRegister(); // for drop savedStrictRegister
|
||||
}
|
||||
}
|
||||
|
||||
virtual void iterateChildren(const std::function<void(Node* node)>& fn) override
|
||||
|
|
|
|||
|
|
@ -226,6 +226,13 @@ public:
|
|||
return m_inStrictMode;
|
||||
}
|
||||
|
||||
// Used to evaluate class heritage and computed property names as strict mode
|
||||
// code regardless of the surrounding code (a class definition is always strict).
|
||||
void setInStrictMode(bool inStrictMode)
|
||||
{
|
||||
m_inStrictMode = inStrictMode;
|
||||
}
|
||||
|
||||
bool inExecutionStopState() const
|
||||
{
|
||||
return m_inExecutionStopState;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 9169aa40a38a25c61d043511931c31209d980f4e
|
||||
Subproject commit 8cce9e0598052a8b6b3766f1100b3c1ef01fa093
|
||||
Loading…
Add table
Add a link
Reference in a new issue