escargot/src/runtime/ShadowRealmObject.cpp
Seonghyun Kim 982f15c83d Revise ShadowRealm
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
2025-12-31 10:22:29 +09:00

119 lines
5 KiB
C++

/*
* Copyright (c) 2025-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "Escargot.h"
#include "runtime/ShadowRealmObject.h"
#include "runtime/WrappedFunctionObject.h"
#include "parser/Script.h"
#include "parser/ScriptParser.h"
namespace Escargot {
#if defined(ENABLE_SHADOWREALM)
ShadowRealmObject::ShadowRealmObject(ExecutionState& state)
: DerivedObject(state)
, m_realmContext(nullptr)
{
}
ShadowRealmObject::ShadowRealmObject(ExecutionState& state, Object* proto)
: DerivedObject(state, proto)
, m_realmContext(nullptr)
{
}
// https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate
static Value wrappedFunctionCreate(ExecutionState& state, Context* callerRealm, Object* target)
{
// Let internalSlotsList be the internal slots listed in Table 2, plus [[Prototype]] and [[Extensible]].
// Let wrapped be MakeBasicObject(internalSlotsList).
// Set wrapped.[[Prototype]] to callerRealm.[[Intrinsics]].[[%Function.prototype%]].
// Set wrapped.[[Call]] as described in 2.1.
// Set wrapped.[[WrappedTargetFunction]] to Target.
// Set wrapped.[[Realm]] to callerRealm.
// Let result be Completion(CopyNameAndLength(wrapped, Target)).
// If result is an abrupt completion, throw a TypeError exception.
WrappedFunctionObject* wrapped = nullptr;
try {
// https://tc39.es/proposal-shadowrealm/#sec-copynameandlength
double L = 0;
Value targetName;
bool targetHasLength = target->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().length));
if (targetHasLength) {
Value targetLen = target->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, target);
if (targetLen.isNumber()) {
if (targetLen.toNumber(state) == std::numeric_limits<double>::infinity()) {
L = std::numeric_limits<double>::infinity();
} else if (targetLen.toNumber(state) == -std::numeric_limits<double>::infinity()) {
L = 0;
} else {
double targetLenAsInt = targetLen.toInteger(state);
L = std::max(0.0, targetLenAsInt);
}
}
}
targetName = target->get(state, ObjectPropertyName(state.context()->staticStrings().name)).value(state, target);
if (!targetName.isString()) {
targetName = String::emptyString();
}
wrapped = new WrappedFunctionObject(state, target, callerRealm, Value(Value::DoubleToIntConvertibleTestNeeds, L), targetName);
} catch (const Value& e) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Copy name and length from target function failed");
}
// Return wrapped.
return wrapped;
}
Value ShadowRealmObject::wrappedValue(ExecutionState& state, Context* callerRealm, const Value& value)
{
// If value is an Object, then
if (value.isObject()) {
// If IsCallable(value) is false, throw a TypeError exception.
if (!value.asObject()->isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "The result of ShadowRealm.evaluate must be a callable function");
}
// Return ? WrappedFunctionCreate(callerRealm, value).
return wrappedFunctionCreate(state, callerRealm, value.asObject());
}
// Return value.
return value;
}
Value ShadowRealmObject::eval(ExecutionState& state, String* sourceText, Context* callerRealm)
{
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 {
scriptResult = script->execute(state, true, false);
} catch (const Value& e) {
StringBuilder builder;
builder.appendString("ShadowRealm.evaluate failed : ");
builder.appendString(e.toStringWithoutException(state));
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, builder.finalize());
}
return wrappedValue(state, callerRealm, scriptResult);
}
#endif
} // namespace Escargot