LibJS: Replace PropertyKey(char[]) with PropertyKey(FlyString)

...and deal with the fallout.
This commit is contained in:
Andreas Kling 2025-03-16 21:25:29 -05:00 committed by Andreas Kling
commit 53da8893ac
Notes: github-actions[bot] 2025-03-24 22:28:43 +00:00
55 changed files with 254 additions and 251 deletions

View file

@ -193,16 +193,16 @@ ALWAYS_INLINE void Interpreter::set(Operand op, Value value)
ALWAYS_INLINE Value Interpreter::do_yield(Value value, Optional<Label> continuation)
{
auto object = Object::create(realm(), nullptr);
object->define_direct_property("result", value, JS::default_attributes);
object->define_direct_property(m_vm.names.result, value, JS::default_attributes);
if (continuation.has_value())
// FIXME: If we get a pointer, which is not accurately representable as a double
// will cause this to explode
object->define_direct_property("continuation", Value(continuation->address()), JS::default_attributes);
object->define_direct_property(m_vm.names.continuation, Value(continuation->address()), JS::default_attributes);
else
object->define_direct_property("continuation", js_null(), JS::default_attributes);
object->define_direct_property(m_vm.names.continuation, js_null(), JS::default_attributes);
object->define_direct_property("isAwait", Value(false), JS::default_attributes);
object->define_direct_property(m_vm.names.isAwait, Value(false), JS::default_attributes);
return object;
}
@ -2842,13 +2842,14 @@ void PrepareYield::execute_impl(Bytecode::Interpreter& interpreter) const
void Await::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
auto yielded_value = interpreter.get(m_argument).value_or(js_undefined());
auto object = Object::create(interpreter.realm(), nullptr);
object->define_direct_property("result", yielded_value, JS::default_attributes);
object->define_direct_property(vm.names.result, yielded_value, JS::default_attributes);
// FIXME: If we get a pointer, which is not accurately representable as a double
// will cause this to explode
object->define_direct_property("continuation", Value(m_continuation_label.address()), JS::default_attributes);
object->define_direct_property("isAwait", Value(true), JS::default_attributes);
object->define_direct_property(vm.names.continuation, Value(m_continuation_label.address()), JS::default_attributes);
object->define_direct_property(vm.names.isAwait, Value(true), JS::default_attributes);
interpreter.do_return(object);
}

View file

@ -36,15 +36,15 @@ void $262Object::initialize(Realm& realm)
m_is_htmldda = realm.create<IsHTMLDDA>(realm);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, "clearKeptObjects", clear_kept_objects, 0, attr);
define_native_function(realm, "createRealm", create_realm, 0, attr);
define_native_function(realm, "detachArrayBuffer", detach_array_buffer, 1, attr);
define_native_function(realm, "evalScript", eval_script, 1, attr);
define_native_function(realm, "clearKeptObjects"_fly_string, clear_kept_objects, 0, attr);
define_native_function(realm, "createRealm"_fly_string, create_realm, 0, attr);
define_native_function(realm, "detachArrayBuffer"_fly_string, detach_array_buffer, 1, attr);
define_native_function(realm, "evalScript"_fly_string, eval_script, 1, attr);
define_direct_property("agent", m_agent, attr);
define_direct_property("gc", realm.global_object().get_without_side_effects("gc"), attr);
define_direct_property("global", &realm.global_object(), attr);
define_direct_property("IsHTMLDDA", m_is_htmldda, attr);
define_direct_property("agent"_fly_string, m_agent, attr);
define_direct_property("gc"_fly_string, realm.global_object().get_without_side_effects("gc"_fly_string), attr);
define_direct_property("global"_fly_string, &realm.global_object(), attr);
define_direct_property("IsHTMLDDA"_fly_string, m_is_htmldda, attr);
}
void $262Object::visit_edges(Cell::Visitor& visitor)

View file

@ -24,8 +24,8 @@ void AgentObject::initialize(JS::Realm& realm)
Base::initialize(realm);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, "monotonicNow", monotonic_now, 0, attr);
define_native_function(realm, "sleep", sleep, 1, attr);
define_native_function(realm, "monotonicNow"_fly_string, monotonic_now, 0, attr);
define_native_function(realm, "sleep"_fly_string, sleep, 1, attr);
// TODO: broadcast
// TODO: getReport
// TODO: start

View file

@ -24,8 +24,8 @@ void GlobalObject::initialize(Realm& realm)
// https://github.com/tc39/test262/blob/master/INTERPRETING.md#host-defined-functions
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, "print", print, 1, attr);
define_direct_property("$262", m_$262, attr);
define_native_function(realm, "print"_fly_string, print, 1, attr);
define_direct_property("$262"_fly_string, m_$262, attr);
}
void GlobalObject::visit_edges(Cell::Visitor& visitor)

View file

@ -611,7 +611,7 @@ void CyclicModule::execute_async_module(VM& vm)
};
// 5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 0, "");
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 0);
// 6. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures module and performs the following steps when called:
auto rejected_closure = [&](VM& vm) -> ThrowCompletionOr<Value> {
@ -625,7 +625,7 @@ void CyclicModule::execute_async_module(VM& vm)
};
// 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 0, "");
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 0);
// 8. Perform PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected).
as<Promise>(capability->promise().ptr())->perform_then(on_fulfilled, on_rejected, {});
@ -863,7 +863,7 @@ void continue_dynamic_import(GC::Ref<PromiseCapability> promise_capability, Thro
};
// 5. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(*vm.current_realm(), move(reject_closure), 1, "");
auto on_rejected = NativeFunction::create(*vm.current_realm(), move(reject_closure), 1);
// 6. Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability,
// and onRejected and performs the following steps when called:
@ -897,7 +897,7 @@ void continue_dynamic_import(GC::Ref<PromiseCapability> promise_capability, Thro
};
// e. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
auto on_fulfilled = NativeFunction::create(*vm.current_realm(), move(fulfilled_closure), 0, "");
auto on_fulfilled = NativeFunction::create(*vm.current_realm(), move(fulfilled_closure), 0);
// f. Perform PerformPromiseThen(evaluatePromise, onFulfilled, onRejected).
evaluate_promise.value()->perform_then(on_fulfilled, on_rejected, {});
@ -907,7 +907,7 @@ void continue_dynamic_import(GC::Ref<PromiseCapability> promise_capability, Thro
};
// 7. Let linkAndEvaluate be CreateBuiltinFunction(linkAndEvaluateClosure, 0, "", « »).
auto link_and_evaluate = NativeFunction::create(*vm.current_realm(), move(link_and_evaluate_closure), 0, "");
auto link_and_evaluate = NativeFunction::create(*vm.current_realm(), move(link_and_evaluate_closure), 0);
// 8. Perform PerformPromiseThen(loadPromise, linkAndEvaluate, onRejected).
// FIXME: This is likely a spec bug, see load_requested_modules.

View file

@ -233,7 +233,7 @@ ThrowCompletionOr<void> initialize_bound_name(VM& vm, DeprecatedFlyString const&
bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const& descriptor, Optional<PropertyDescriptor> const& current)
{
// 1. Return ValidateAndApplyPropertyDescriptor(undefined, "", Extensible, Desc, Current).
return validate_and_apply_property_descriptor(nullptr, "", extensible, descriptor, current);
return validate_and_apply_property_descriptor(nullptr, FlyString {}, extensible, descriptor, current);
}
// 10.1.6.3 ValidateAndApplyPropertyDescriptor ( O, P, extensible, Desc, current ), https://tc39.es/ecma262/#sec-validateandapplypropertydescriptor
@ -1544,7 +1544,7 @@ ThrowCompletionOr<GC::Ptr<FunctionObject>> get_dispose_method(VM& vm, Value valu
// thrown synchronously.
// 3. Return CreateBuiltinFunction(closure, 0, "", « »).
return NativeFunction::create(realm, move(closure), 0, "");
return NativeFunction::create(realm, move(closure), 0);
}
}
}

View file

@ -68,7 +68,7 @@ JS_DEFINE_NATIVE_FUNCTION(AsyncDisposableStackPrototype::adopt)
};
// 6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
auto function = NativeFunction::create(realm, move(closure), 0, "");
auto function = NativeFunction::create(realm, move(closure), 0);
// 7. Perform ? AddDisposableResource(asyncDisposableStack.[[DisposeCapability]], undefined, async-dispose, F).
TRY(add_disposable_resource(vm, async_disposable_stack->dispose_capability(), js_undefined(), Environment::InitializeBindingHint::AsyncDispose, function));

View file

@ -58,7 +58,7 @@ static Object* async_from_sync_iterator_continuation(VM& vm, Object& result, Pro
// 9. Let onFulfilled be CreateBuiltinFunction(unwrap, 1, "", « »).
// 10. NOTE: onFulfilled is used when processing the "value" property of an IteratorResult object in order to wait for its value if it is a promise and re-package the result in a new "unwrapped" IteratorResult object.
auto on_fulfilled = NativeFunction::create(realm, move(unwrap), 1, "");
auto on_fulfilled = NativeFunction::create(realm, move(unwrap), 1);
// 11. Perform PerformPromiseThen(valueWrapper, onFulfilled, undefined, promiseCapability).
as<Promise>(value_wrapper)->perform_then(move(on_fulfilled), js_undefined(), &promise_capability);

View file

@ -75,7 +75,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
};
// 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1, "");
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
// 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the
// following steps when called:
@ -103,7 +103,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
};
// 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1, "");
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
// 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
m_current_promise = as<Promise>(promise_object);

View file

@ -104,7 +104,7 @@ ThrowCompletionOr<void> AsyncGenerator::await(Value value)
};
// 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1, "");
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
// 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the
// following steps when called:
@ -131,7 +131,7 @@ ThrowCompletionOr<void> AsyncGenerator::await(Value value)
};
// 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1, "");
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
// 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
m_current_promise = as<Promise>(promise_object);
@ -155,15 +155,15 @@ void AsyncGenerator::execute(VM& vm, Completion completion)
// Loosely based on step 4 of https://tc39.es/ecma262/#sec-asyncgeneratorstart
VERIFY(completion.value().has_value());
auto generated_value = [](Value value) -> Value {
auto generated_value = [&vm](Value value) -> Value {
if (value.is_object())
return value.as_object().get_without_side_effects("result");
return value.as_object().get_without_side_effects(vm.names.result);
return value.is_empty() ? js_undefined() : value;
};
auto generated_continuation = [&](Value value) -> Optional<size_t> {
if (value.is_object()) {
auto number_value = value.as_object().get_without_side_effects("continuation");
auto number_value = value.as_object().get_without_side_effects(vm.names.continuation);
if (number_value.is_null())
return {};
return static_cast<size_t>(number_value.as_double());
@ -171,9 +171,9 @@ void AsyncGenerator::execute(VM& vm, Completion completion)
return {};
};
auto generated_is_await = [](Value value) -> bool {
auto generated_is_await = [&vm](Value value) -> bool {
if (value.is_object())
return value.as_object().get_without_side_effects("isAwait").as_bool();
return value.as_object().get_without_side_effects(vm.names.isAwait).as_bool();
return false;
};
@ -393,7 +393,7 @@ void AsyncGenerator::await_return()
};
// 11. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1, "");
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
// 12. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures generator and performs
// the following steps when called:
@ -415,7 +415,7 @@ void AsyncGenerator::await_return()
};
// 13. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1, "");
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
// 14. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
// NOTE: await_return should only be called when the generator is in SuspendedStart or Completed state,

View file

@ -92,6 +92,7 @@ namespace JS {
P(construct) \
P(constructor) \
P(containing) \
P(continuation) \
P(copyWithin) \
P(cos) \
P(cosh) \
@ -277,6 +278,7 @@ namespace JS {
P(Intl) \
P(is) \
P(isArray) \
P(isAwait) \
P(isDisjointFrom) \
P(isError) \
P(isExtensible) \
@ -408,6 +410,7 @@ namespace JS {
P(reason) \
P(reduce) \
P(reduceRight) \
P(result) \
P(Reflect) \
P(RegExp) \
P(region) \

View file

@ -66,7 +66,7 @@ ThrowCompletionOr<Value> await(VM& vm, Value value)
};
// 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1, "");
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
// 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the following steps when called:
auto rejected_closure = [&success, &result](VM& vm) -> ThrowCompletionOr<Value> {
@ -90,7 +90,7 @@ ThrowCompletionOr<Value> await(VM& vm, Value value)
};
// 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1, "");
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
// 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
auto promise = as<Promise>(promise_object);

View file

@ -67,7 +67,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisposableStackPrototype::adopt)
};
// 6. Let F be CreateBuiltinFunction(closure, 0, "", « »).
auto function = NativeFunction::create(realm, move(closure), 0, "");
auto function = NativeFunction::create(realm, move(closure), 0);
// 7. Perform ? AddDisposableResource(disposableStack.[[DisposeCapability]], undefined, sync-dispose, F).
TRY(add_disposable_resource(vm, disposable_stack->dispose_capability(), js_undefined(), Environment::InitializeBindingHint::SyncDispose, function));

View file

@ -82,15 +82,15 @@ ThrowCompletionOr<Value> GeneratorObject::execute(VM& vm, Completion const& comp
VERIFY(completion.value().has_value());
auto generated_value = [](Value value) -> Value {
auto generated_value = [&vm](Value value) -> Value {
if (value.is_object())
return value.as_object().get_without_side_effects("result");
return value.as_object().get_without_side_effects(vm.names.result);
return value.is_empty() ? js_undefined() : value;
};
auto generated_continuation = [&](Value value) -> Optional<size_t> {
if (value.is_object()) {
auto number_value = value.as_object().get_without_side_effects("continuation");
auto number_value = value.as_object().get_without_side_effects(vm.names.continuation);
if (number_value.is_null())
return {};
return static_cast<u64>(number_value.as_double());

View file

@ -246,7 +246,7 @@ void Intrinsics::initialize_intrinsics(Realm& realm)
realm, [](VM& vm) {
return vm.throw_completion<TypeError>(ErrorType::RestrictedFunctionPropertiesAccess);
},
0, "", &realm);
0, FlyString {}, &realm);
m_throw_type_error_function->define_direct_property(vm.names.length, Value(0), 0);
m_throw_type_error_function->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), 0);
MUST(m_throw_type_error_function->internal_prevent_extensions());

View file

@ -21,7 +21,7 @@ class NativeFunction : public FunctionObject {
GC_DECLARE_ALLOCATOR(NativeFunction);
public:
static GC::Ref<NativeFunction> create(Realm&, ESCAPING Function<ThrowCompletionOr<Value>(VM&)> behaviour, i32 length, PropertyKey const& name, Optional<Realm*> = {}, Optional<Object*> prototype = {}, Optional<StringView> const& prefix = {});
static GC::Ref<NativeFunction> create(Realm&, ESCAPING Function<ThrowCompletionOr<Value>(VM&)> behaviour, i32 length, PropertyKey const& name = FlyString {}, Optional<Realm*> = {}, Optional<Object*> prototype = {}, Optional<StringView> const& prefix = {});
static GC::Ref<NativeFunction> create(Realm&, DeprecatedFlyString const& name, ESCAPING Function<ThrowCompletionOr<Value>(VM&)>);
virtual ~NativeFunction() override = default;

View file

@ -90,7 +90,7 @@ ThrowCompletionOr<GC::Ref<PromiseCapability>> new_promise_capability(VM& vm, Val
};
// 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »).
auto executor = NativeFunction::create(realm, move(executor_closure), 2, "");
auto executor = NativeFunction::create(realm, move(executor_closure), 2);
// 6. Let promise be ? Construct(C, « executor »).
auto promise = TRY(construct(vm, constructor.as_function(), executor));

View file

@ -121,14 +121,14 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally)
};
// iv. Let valueThunk be CreateBuiltinFunction(returnValue, 0, "", « »).
auto value_thunk = NativeFunction::create(realm, move(return_value), 0, "");
auto value_thunk = NativeFunction::create(realm, move(return_value), 0);
// v. Return ? Invoke(promise, "then", « valueThunk »).
return TRY(Value(promise).invoke(vm, vm.names.then, value_thunk));
};
// b. Let thenFinally be CreateBuiltinFunction(thenFinallyClosure, 1, "", « »).
then_finally = NativeFunction::create(realm, move(then_finally_closure), 1, "");
then_finally = NativeFunction::create(realm, move(then_finally_closure), 1);
// c. Let catchFinallyClosure be a new Abstract Closure with parameters (reason) that captures onFinally and C and performs the following steps when called:
auto catch_finally_closure = [constructor, on_finally](auto& vm) -> ThrowCompletionOr<Value> {
@ -148,14 +148,14 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally)
};
// iv. Let thrower be CreateBuiltinFunction(throwReason, 0, "", « »).
auto thrower = NativeFunction::create(realm, move(throw_reason), 0, "");
auto thrower = NativeFunction::create(realm, move(throw_reason), 0);
// v. Return ? Invoke(promise, "then", « thrower »).
return TRY(Value(promise).invoke(vm, vm.names.then, thrower));
};
// d. Let catchFinally be CreateBuiltinFunction(catchFinallyClosure, 1, "", « »).
catch_finally = NativeFunction::create(realm, move(catch_finally_closure), 1, "");
catch_finally = NativeFunction::create(realm, move(catch_finally_closure), 1);
}
// 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).

View file

@ -61,9 +61,8 @@ public:
{
}
template<size_t N>
PropertyKey(char const (&chars)[N])
: PropertyKey(DeprecatedFlyString(chars))
PropertyKey(FlyString const& string)
: PropertyKey(string.to_deprecated_fly_string())
{
}

View file

@ -108,7 +108,7 @@ JS_DEFINE_NATIVE_FUNCTION(ProxyConstructor::revocable)
// 3. Let revoker be CreateBuiltinFunction(revokerClosure, 0, "", « [[RevocableProxy]] »).
// 4. Set revoker.[[RevocableProxy]] to p.
auto revoker = NativeFunction::create(realm, move(revoker_closure), 0, "");
auto revoker = NativeFunction::create(realm, move(revoker_closure), 0);
// 5. Let result be OrdinaryObjectCreate(%Object.prototype%).
auto result = Object::create(realm, realm.intrinsics().object_prototype());

View file

@ -253,7 +253,7 @@ ThrowCompletionOr<Value> shadow_realm_import_value(VM& vm, String specifier_stri
// 10. Let onFulfilled be CreateBuiltinFunction(steps, 1, "", « [[ExportNameString]] », callerRealm).
// 11. Set onFulfilled.[[ExportNameString]] to exportNameString.
auto on_fulfilled = NativeFunction::create(realm, move(steps), 1, "", &caller_realm);
auto on_fulfilled = NativeFunction::create(realm, move(steps), 1, FlyString {}, &caller_realm);
// 12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promise_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));

View file

@ -603,7 +603,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all)
// b. If isRegExp is true, then
if (is_regexp) {
// i. Let flags be ? Get(regexp, "flags").
auto flags = TRY(regexp.as_object().get("flags"));
auto flags = TRY(regexp.as_object().get(vm.names.flags));
// ii. Perform ? RequireObjectCoercible(flags).
auto flags_object = TRY(require_object_coercible(vm, flags));