mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Revise ShadowRealm
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
23b88e0d3d
commit
982f15c83d
5 changed files with 29 additions and 126 deletions
|
|
@ -38,7 +38,7 @@ namespace Escargot {
|
|||
|
||||
#if defined(ENABLE_SHADOWREALM)
|
||||
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm
|
||||
static Value builtinShadowRealmConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
|
|
@ -72,13 +72,9 @@ static Value builtinShadowRealmEvaluate(ExecutionState& state, Value thisValue,
|
|||
// Let O be the this value.
|
||||
const Value& O = thisValue;
|
||||
// Perform ? ValidateShadowRealmObject(O).
|
||||
if (!O.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "this value must be an Object");
|
||||
}
|
||||
if (!O.asObject()->isShadowRealmObject()) {
|
||||
if (!O.isObject() || !O.asObject()->isShadowRealmObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "this value must be a ShadowRealm object");
|
||||
}
|
||||
|
||||
// If sourceText is not a String, throw a TypeError exception.
|
||||
if (!argv[0].isString()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "sourceText must be a String");
|
||||
|
|
@ -88,7 +84,7 @@ static Value builtinShadowRealmEvaluate(ExecutionState& state, Value thisValue,
|
|||
// Let evalRealm be O.[[ShadowRealm]].
|
||||
Context* evalRealm = O.asObject()->asShadowRealmObject()->realmContext();
|
||||
// Return ? PerformShadowRealmEval(sourceText, callerRealm, evalRealm).
|
||||
return ShadowRealmObject::performShadowRealmEval(state, argv[0], callerRealm, evalRealm);
|
||||
return O.asObject()->asShadowRealmObject()->eval(state, argv[0].asString(), callerRealm);
|
||||
}
|
||||
|
||||
void GlobalObject::initializeShadowRealm(ExecutionState& state)
|
||||
|
|
@ -113,7 +109,7 @@ void GlobalObject::installShadowRealm(ExecutionState& state)
|
|||
m_shadowRealm->setFunctionPrototype(state, m_shadowRealmPrototype);
|
||||
|
||||
m_shadowRealmPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
|
||||
ObjectPropertyDescriptor(String::fromASCII("ShadowRealm"), ObjectPropertyDescriptor::ConfigurablePresent));
|
||||
ObjectPropertyDescriptor(state.context()->staticStrings().ShadowRealm.string(), ObjectPropertyDescriptor::ConfigurablePresent));
|
||||
|
||||
m_shadowRealmPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->evaluate),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->evaluate, builtinShadowRealmEvaluate, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
|
|
|||
|
|
@ -18,17 +18,6 @@
|
|||
*/
|
||||
|
||||
#include "Escargot.h"
|
||||
#include "interpreter/ByteCode.h"
|
||||
#include "interpreter/ByteCodeGenerator.h"
|
||||
#include "interpreter/ByteCodeInterpreter.h"
|
||||
#include "runtime/Global.h"
|
||||
#include "runtime/GlobalObject.h"
|
||||
#include "runtime/Context.h"
|
||||
#include "runtime/Environment.h"
|
||||
#include "runtime/EnvironmentRecord.h"
|
||||
#include "runtime/ExtendedNativeFunctionObject.h"
|
||||
#include "runtime/VMInstance.h"
|
||||
#include "runtime/ExecutionState.h"
|
||||
#include "runtime/ShadowRealmObject.h"
|
||||
#include "runtime/WrappedFunctionObject.h"
|
||||
#include "parser/Script.h"
|
||||
|
|
@ -40,11 +29,13 @@ namespace Escargot {
|
|||
|
||||
ShadowRealmObject::ShadowRealmObject(ExecutionState& state)
|
||||
: DerivedObject(state)
|
||||
, m_realmContext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ShadowRealmObject::ShadowRealmObject(ExecutionState& state, Object* proto)
|
||||
: DerivedObject(state, proto)
|
||||
, m_realmContext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +82,7 @@ static Value wrappedFunctionCreate(ExecutionState& state, Context* callerRealm,
|
|||
return wrapped;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue
|
||||
Value ShadowRealmObject::getWrappedValue(ExecutionState& state, Context* callerRealm, const Value& value)
|
||||
Value ShadowRealmObject::wrappedValue(ExecutionState& state, Context* callerRealm, const Value& value)
|
||||
{
|
||||
// If value is an Object, then
|
||||
if (value.isObject()) {
|
||||
|
|
@ -107,103 +97,21 @@ Value ShadowRealmObject::getWrappedValue(ExecutionState& state, Context* callerR
|
|||
return value;
|
||||
}
|
||||
|
||||
static Value execute(ExecutionState& state, Script* script, bool isExecuteOnEvalFunction, bool inStrictMode, Context* callerContext, Context* evalContext)
|
||||
Value ShadowRealmObject::eval(ExecutionState& state, String* sourceText, Context* callerRealm)
|
||||
{
|
||||
InterpretedCodeBlock* topCodeBlock = script->topCodeBlock();
|
||||
ByteCodeBlock* byteCodeBlock = topCodeBlock->byteCodeBlock();
|
||||
|
||||
ExecutionState* newState;
|
||||
if (byteCodeBlock->needsExtendedExecutionState()) {
|
||||
newState = new (alloca(sizeof(ExtendedExecutionState))) ExtendedExecutionState(evalContext);
|
||||
} else {
|
||||
newState = new (alloca(sizeof(ExecutionState))) ExecutionState(evalContext);
|
||||
}
|
||||
|
||||
ExecutionState* codeExecutionState = newState;
|
||||
|
||||
EnvironmentRecord* globalRecord = new GlobalEnvironmentRecord(*newState, topCodeBlock, evalContext->globalObject(), evalContext->globalDeclarativeRecord(), evalContext->globalDeclarativeStorage());
|
||||
LexicalEnvironment* globalLexicalEnvironment = new LexicalEnvironment(globalRecord, nullptr);
|
||||
newState->setLexicalEnvironment(globalLexicalEnvironment, topCodeBlock->isStrict());
|
||||
|
||||
EnvironmentRecord* globalVariableRecord = globalRecord;
|
||||
|
||||
EnvironmentRecord* newVariableRecord = new DeclarativeEnvironmentRecordNotIndexed(*newState, true);
|
||||
ExecutionState* newVariableState = new ExtendedExecutionState(evalContext);
|
||||
newVariableState->setLexicalEnvironment(new LexicalEnvironment(newVariableRecord, globalLexicalEnvironment), topCodeBlock->isStrict());
|
||||
newVariableState->setParent(newState);
|
||||
codeExecutionState = newVariableState;
|
||||
|
||||
const InterpretedCodeBlock::IdentifierInfoVector& identifierVector = topCodeBlock->identifierInfos();
|
||||
size_t identifierVectorLen = identifierVector.size();
|
||||
|
||||
const auto& globalLexicalVector = topCodeBlock->blockInfo(0)->identifiers();
|
||||
size_t globalLexicalVectorLen = globalLexicalVector.size();
|
||||
|
||||
{
|
||||
VirtualIdDisabler d(evalContext); // we should create binding even there is virtual ID
|
||||
|
||||
for (size_t i = 0; i < globalLexicalVectorLen; i++) {
|
||||
codeExecutionState->lexicalEnvironment()->record()->createBinding(*codeExecutionState, globalLexicalVector[i].m_name, false, globalLexicalVector[i].m_isMutable, false);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < identifierVectorLen; i++) {
|
||||
// https://www.ecma-international.org/ecma-262/5.1/#sec-10.5
|
||||
// Step 2. If code is eval code, then let configurableBindings be true.
|
||||
if (identifierVector[i].m_isVarDeclaration) {
|
||||
globalVariableRecord->createBinding(*codeExecutionState, identifierVector[i].m_name, isExecuteOnEvalFunction, identifierVector[i].m_isMutable, true, topCodeBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value thisValue(evalContext->globalObjectProxy());
|
||||
|
||||
const size_t literalStorageSize = byteCodeBlock->m_numeralLiteralData.size();
|
||||
const size_t registerFileSize = byteCodeBlock->m_requiredTotalRegisterNumber;
|
||||
ASSERT(registerFileSize == byteCodeBlock->m_requiredOperandRegisterNumber + topCodeBlock->totalStackAllocatedVariableSize() + literalStorageSize);
|
||||
|
||||
Value* registerFile;
|
||||
registerFile = CustomAllocator<Value>().allocate(registerFileSize);
|
||||
// we need to reset allocated memory because customAllocator read it
|
||||
memset(static_cast<void*>(registerFile), 0, sizeof(Value) * registerFileSize);
|
||||
registerFile[0] = Value();
|
||||
|
||||
Value* stackStorage = registerFile + byteCodeBlock->m_requiredOperandRegisterNumber;
|
||||
stackStorage[0] = thisValue;
|
||||
|
||||
Value* literalStorage = stackStorage + topCodeBlock->totalStackAllocatedVariableSize();
|
||||
Value* src = byteCodeBlock->m_numeralLiteralData.data();
|
||||
for (size_t i = 0; i < literalStorageSize; i++) {
|
||||
literalStorage[i] = src[i];
|
||||
}
|
||||
|
||||
Value resultValue;
|
||||
#ifdef ESCARGOT_DEBUGGER
|
||||
// set the next(first) breakpoint to be stopped in a newer script execution
|
||||
evalContext->setAsAlwaysStopState();
|
||||
#endif
|
||||
resultValue = Interpreter::interpret(codeExecutionState, byteCodeBlock, reinterpret_cast<size_t>(byteCodeBlock->m_code.data()), registerFile);
|
||||
clearStack<512>();
|
||||
|
||||
// we give up program bytecodeblock after first excution for reducing memory usage
|
||||
topCodeBlock->setByteCodeBlock(nullptr);
|
||||
|
||||
return resultValue;
|
||||
}
|
||||
|
||||
Value ShadowRealmObject::performShadowRealmEval(ExecutionState& state, Value& sourceText, Context* callerRealm, Context* evalRealm)
|
||||
{
|
||||
ScriptParser parser(evalRealm);
|
||||
bool strictFromOutside = false;
|
||||
Script* script = parser.initializeScript(nullptr, 0, sourceText.asString(), evalRealm->staticStrings().lazyEvalCode().string(), nullptr, false, true, false, false, strictFromOutside, false, false, false, true).scriptThrowsExceptionIfParseError(state);
|
||||
|
||||
ExtendedExecutionState stateForNewGlobal(evalRealm);
|
||||
Value result;
|
||||
ScriptParser parser(m_realmContext);
|
||||
Script* script = parser.initializeScript(nullptr, 0, sourceText, m_realmContext->staticStrings().lazyEvalCode().string(), nullptr, false, true, false, false, false, false, false, false, true).scriptThrowsExceptionIfParseError(state);
|
||||
Value scriptResult;
|
||||
ExecutionState stateForNewGlobal(m_realmContext);
|
||||
try {
|
||||
result = execute(stateForNewGlobal, script, true, script->topCodeBlock()->isStrict(), callerRealm, evalRealm);
|
||||
scriptResult = script->execute(state, true, false);
|
||||
} catch (const Value& e) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "ShadowRealm.evaluate failed");
|
||||
StringBuilder builder;
|
||||
builder.appendString("ShadowRealm.evaluate failed : ");
|
||||
builder.appendString(e.toStringWithoutException(state));
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, builder.finalize());
|
||||
}
|
||||
return getWrappedValue(state, callerRealm, result);
|
||||
return wrappedValue(state, callerRealm, scriptResult);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
static Value getWrappedValue(ExecutionState& state, Context* callerRealm, const Value& value);
|
||||
static Value performShadowRealmEval(ExecutionState& state, Value& sourceText, Context* callerRealm, Context* evalRealm);
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue
|
||||
static Value wrappedValue(ExecutionState& state, Context* callerRealm, const Value& value);
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-performshadowrealmeval
|
||||
Value eval(ExecutionState& state, String* sourceText, Context* callerRealm);
|
||||
|
||||
private:
|
||||
Context* m_realmContext;
|
||||
|
|
|
|||
|
|
@ -29,16 +29,13 @@ namespace Escargot {
|
|||
#if defined(ENABLE_SHADOWREALM)
|
||||
|
||||
WrappedFunctionObject::WrappedFunctionObject(ExecutionState& state, Object* wrappedTargetFunction, Context* realm, const Value& length, const Value& name)
|
||||
: DerivedObject(state, state.context()->globalObject()->objectPrototype(), ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)
|
||||
: DerivedObject(state, realm->globalObject()->functionPrototype(), ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)
|
||||
, m_wrappedTargetFunction(wrappedTargetFunction)
|
||||
, m_realm(realm)
|
||||
{
|
||||
m_structure = state.context()->defaultStructureForWrappedFunctionObject();
|
||||
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 0] = length;
|
||||
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1] = name;
|
||||
|
||||
Value proto = m_wrappedTargetFunction->getPrototype(state);
|
||||
Object::setPrototype(state, proto);
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-ordinary-wrapped-function-call
|
||||
|
|
@ -50,21 +47,23 @@ Value WrappedFunctionObject::ordinaryWrappedFunctionCall(ExecutionState& state,
|
|||
Context* callerRealm = m_realm;
|
||||
Context* targetRealm = target->getFunctionRealm(state);
|
||||
|
||||
ExecutionState newState(callerRealm);
|
||||
|
||||
Value* wrappedArgv = ALLOCA(calledArgc * sizeof(Value), Value);
|
||||
for (size_t i = 0; i < calledArgc; i++) {
|
||||
Value wrappedValue = ShadowRealmObject::getWrappedValue(state, targetRealm, calledArgv[i]);
|
||||
Value wrappedValue = ShadowRealmObject::wrappedValue(newState, targetRealm, calledArgv[i]);
|
||||
wrappedArgv[i] = wrappedValue;
|
||||
}
|
||||
|
||||
Value wrappedThisValue = ShadowRealmObject::getWrappedValue(state, targetRealm, thisValue);
|
||||
Value wrappedThisValue = ShadowRealmObject::wrappedValue(newState, targetRealm, thisValue);
|
||||
Value result;
|
||||
try {
|
||||
result = Object::call(state, target, wrappedThisValue, calledArgc, wrappedArgv);
|
||||
result = Object::call(newState, target, wrappedThisValue, calledArgc, wrappedArgv);
|
||||
} catch (const Value& e) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Call target function failed");
|
||||
}
|
||||
|
||||
return ShadowRealmObject::getWrappedValue(state, callerRealm, result);
|
||||
return ShadowRealmObject::wrappedValue(newState, callerRealm, result);
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist
|
||||
|
|
|
|||
|
|
@ -135,8 +135,6 @@
|
|||
<test id="built-ins/Object/freeze/typedarray-backed-by-resizable-buffer"><reason>TODO</reason></test>
|
||||
<test id="built-ins/Object/seal/proxy-with-defineProperty-handler"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/evaluate/globalthis-ordinary-object"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/evaluate/wrapped-function-proto-from-caller-realm"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/evaluate/wrapped-function-throws-typeerror-from-caller-realm"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/importValue/descriptor"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/importValue/import-value"><reason>TODO</reason></test>
|
||||
<test id="built-ins/ShadowRealm/prototype/importValue/length"><reason>TODO</reason></test>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue