mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-28 10:37:17 +02:00
NativeFunction previously stored an AK::Function for every builtin, even when the callable was just a plain C++ entry point. That mixed together two different representations, made simple builtins carry capture storage they did not need, and forced the GC to treat every native function as if it might contain captured JS values. Introduce RawNativeFunction for plain NativeFunctionPointer callees and keep AK::Function-backed callables on a CapturingNativeFunction subclass. Update the straightforward native registrations in LibJS and LibWeb to use the raw representation, while leaving exported Wasm functions on the capturing path because they still capture state. Wrap UniversalGlobalScope's byte-length strategy lambda in Function<...> explicitly so it keeps selecting the capturing NativeFunction::create overload.
96 lines
4.1 KiB
C++
96 lines
4.1 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
|
|
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Badge.h>
|
|
#include <AK/Optional.h>
|
|
#include <LibJS/Export.h>
|
|
#include <LibJS/Runtime/Completion.h>
|
|
#include <LibJS/Runtime/FunctionObject.h>
|
|
#include <LibJS/Runtime/PropertyKey.h>
|
|
|
|
namespace JS {
|
|
|
|
class JS_API NativeFunction : public FunctionObject {
|
|
JS_OBJECT(NativeFunction, FunctionObject);
|
|
GC_DECLARE_ALLOCATOR(NativeFunction);
|
|
|
|
public:
|
|
static GC::Ref<NativeFunction> create(Realm&, ESCAPING Function<ThrowCompletionOr<Value>(VM&)> behaviour, i32 length, PropertyKey const& name = Utf16FlyString {}, Optional<Realm*> = {}, Optional<StringView> const& prefix = {}, Optional<Bytecode::Builtin> builtin = {});
|
|
static GC::Ref<NativeFunction> create(Realm&, NativeFunctionPointer behaviour, i32 length, PropertyKey const& name = Utf16FlyString {}, Optional<Realm*> = {}, Optional<StringView> const& prefix = {}, Optional<Bytecode::Builtin> builtin = {});
|
|
static GC::Ref<NativeFunction> create(Realm&, Utf16FlyString const& name, ESCAPING Function<ThrowCompletionOr<Value>(VM&)>);
|
|
static GC::Ref<NativeFunction> create(Realm&, Utf16FlyString const& name, NativeFunctionPointer);
|
|
|
|
virtual ~NativeFunction() override = default;
|
|
|
|
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
|
virtual ThrowCompletionOr<GC::Ref<Object>> internal_construct(ExecutionContext&, FunctionObject& new_target) override;
|
|
|
|
// Used for [[Call]] / [[Construct]]'s "...result of evaluating F in a manner that conforms to the specification of F".
|
|
virtual ThrowCompletionOr<Value> call();
|
|
virtual ThrowCompletionOr<GC::Ref<Object>> construct(FunctionObject& new_target);
|
|
|
|
virtual Utf16String name_for_call_stack() const override;
|
|
|
|
Utf16FlyString const& name() const { return m_name; }
|
|
virtual bool is_strict_mode() const override;
|
|
virtual bool has_constructor() const override { return false; }
|
|
virtual Realm* realm() const override { return m_realm; }
|
|
|
|
Optional<Utf16FlyString> const& initial_name() const { return m_initial_name; }
|
|
void set_initial_name(Badge<FunctionObject>, Utf16FlyString initial_name) { m_initial_name = move(initial_name); }
|
|
|
|
virtual bool function_environment_needed() const { return false; }
|
|
virtual size_t function_environment_bindings_count() const { return 0; }
|
|
|
|
protected:
|
|
NativeFunction(Object* prototype, Realm& realm, Optional<Bytecode::Builtin> builtin);
|
|
NativeFunction(Utf16FlyString name, Object& prototype);
|
|
explicit NativeFunction(Object& prototype);
|
|
|
|
virtual void visit_edges(Cell::Visitor& visitor) override;
|
|
|
|
private:
|
|
virtual bool is_native_function() const final { return true; }
|
|
|
|
Utf16FlyString m_name;
|
|
Optional<Utf16FlyString> m_initial_name; // [[InitialName]]
|
|
GC::Ref<Realm> m_realm;
|
|
};
|
|
|
|
template<>
|
|
inline bool Object::fast_is<NativeFunction>() const { return is_native_function(); }
|
|
|
|
class JS_API RawNativeFunction final : public NativeFunction {
|
|
JS_OBJECT(RawNativeFunction, NativeFunction);
|
|
GC_DECLARE_ALLOCATOR(RawNativeFunction);
|
|
|
|
public:
|
|
static GC::Ref<RawNativeFunction> create(Realm&, NativeFunctionPointer behaviour, i32 length, PropertyKey const& name = Utf16FlyString {}, Optional<Realm*> = {}, Optional<StringView> const& prefix = {}, Optional<Bytecode::Builtin> builtin = {});
|
|
static GC::Ref<RawNativeFunction> create(Realm&, Utf16FlyString const& name, NativeFunctionPointer);
|
|
|
|
virtual ~RawNativeFunction() override = default;
|
|
|
|
virtual ThrowCompletionOr<Value> call() override;
|
|
|
|
NativeFunctionPointer native_function() const { return m_native_function; }
|
|
|
|
private:
|
|
RawNativeFunction(NativeFunctionPointer, Object* prototype, Realm& realm, Optional<Bytecode::Builtin> builtin);
|
|
RawNativeFunction(Utf16FlyString name, NativeFunctionPointer, Object& prototype);
|
|
|
|
virtual bool is_raw_native_function() const final { return true; }
|
|
|
|
NativeFunctionPointer m_native_function { nullptr };
|
|
};
|
|
|
|
template<>
|
|
inline bool Object::fast_is<RawNativeFunction>() const { return is_raw_native_function(); }
|
|
|
|
}
|