
This patch adds two macros to declare per-type allocators: - JS_DECLARE_ALLOCATOR(TypeName) - JS_DEFINE_ALLOCATOR(TypeName) When used, they add a type-specific CellAllocator that the Heap will delegate allocation requests to. The result of this is that GC objects of the same type always end up within the same HeapBlock, drastically reducing the ability to perform type confusion attacks. It also improves HeapBlock utilization, since each block now has cells sized exactly to the type used within that block. (Previously we only had a handful of block sizes available, and most GC allocations ended up with a large amount of slack in their tails.) There is a small performance hit from this, but I'm sure we can make up for it elsewhere. Note that the old size-based allocators still exist, and we fall back to them for any type that doesn't have its own CellAllocator.
165 lines
8.9 KiB
C++
165 lines
8.9 KiB
C++
/*
|
|
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
|
|
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibJS/Bytecode/Generator.h>
|
|
#include <LibJS/Runtime/ClassFieldDefinition.h>
|
|
#include <LibJS/Runtime/ExecutionContext.h>
|
|
#include <LibJS/Runtime/FunctionObject.h>
|
|
|
|
namespace JS {
|
|
|
|
template<typename T>
|
|
void async_block_start(VM&, T const& async_body, PromiseCapability const&, ExecutionContext&);
|
|
|
|
template<typename T>
|
|
void async_function_start(VM&, PromiseCapability const&, T const& async_function_body);
|
|
|
|
// 10.2 ECMAScript Function Objects, https://tc39.es/ecma262/#sec-ecmascript-function-objects
|
|
class ECMAScriptFunctionObject final : public FunctionObject {
|
|
JS_OBJECT(ECMAScriptFunctionObject, FunctionObject);
|
|
JS_DECLARE_ALLOCATOR(ECMAScriptFunctionObject);
|
|
|
|
public:
|
|
enum class ConstructorKind : u8 {
|
|
Base,
|
|
Derived,
|
|
};
|
|
|
|
enum class ThisMode : u8 {
|
|
Lexical,
|
|
Strict,
|
|
Global,
|
|
};
|
|
|
|
static NonnullGCPtr<ECMAScriptFunctionObject> create(Realm&, DeprecatedFlyString name, DeprecatedString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> parameters, i32 m_function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, bool might_need_arguments_object = true, bool contains_direct_call_to_eval = true, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
|
|
static NonnullGCPtr<ECMAScriptFunctionObject> create(Realm&, DeprecatedFlyString name, Object& prototype, DeprecatedString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> parameters, i32 m_function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind, bool is_strict, bool might_need_arguments_object = true, bool contains_direct_call_to_eval = true, bool is_arrow_function = false, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name = {});
|
|
|
|
virtual void initialize(Realm&) override;
|
|
virtual ~ECMAScriptFunctionObject() override = default;
|
|
|
|
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
|
|
virtual ThrowCompletionOr<NonnullGCPtr<Object>> internal_construct(MarkedVector<Value> arguments_list, FunctionObject& new_target) override;
|
|
|
|
void make_method(Object& home_object);
|
|
|
|
Statement const& ecmascript_code() const { return m_ecmascript_code; }
|
|
Vector<FunctionParameter> const& formal_parameters() const { return m_formal_parameters; }
|
|
|
|
virtual DeprecatedFlyString const& name() const override { return m_name; }
|
|
void set_name(DeprecatedFlyString const& name);
|
|
|
|
void set_is_class_constructor() { m_is_class_constructor = true; }
|
|
|
|
auto& bytecode_executable() const { return m_bytecode_executable; }
|
|
|
|
Environment* environment() { return m_environment; }
|
|
virtual Realm* realm() const override { return m_realm; }
|
|
|
|
ConstructorKind constructor_kind() const { return m_constructor_kind; }
|
|
void set_constructor_kind(ConstructorKind constructor_kind) { m_constructor_kind = constructor_kind; }
|
|
|
|
ThisMode this_mode() const { return m_this_mode; }
|
|
|
|
Object* home_object() const { return m_home_object; }
|
|
void set_home_object(Object* home_object) { m_home_object = home_object; }
|
|
|
|
DeprecatedString const& source_text() const { return m_source_text; }
|
|
void set_source_text(DeprecatedString source_text) { m_source_text = move(source_text); }
|
|
|
|
Vector<ClassFieldDefinition> const& fields() const { return m_fields; }
|
|
void add_field(ClassFieldDefinition field) { m_fields.append(move(field)); }
|
|
|
|
Vector<PrivateElement> const& private_methods() const { return m_private_methods; }
|
|
void add_private_method(PrivateElement method) { m_private_methods.append(move(method)); }
|
|
|
|
// This is for IsSimpleParameterList (static semantics)
|
|
bool has_simple_parameter_list() const { return m_has_simple_parameter_list; }
|
|
|
|
// Equivalent to absence of [[Construct]]
|
|
virtual bool has_constructor() const override { return m_kind == FunctionKind::Normal && !m_is_arrow_function; }
|
|
|
|
virtual Vector<DeprecatedFlyString> const& local_variables_names() const override { return m_local_variables_names; }
|
|
|
|
FunctionKind kind() const { return m_kind; }
|
|
|
|
// This is used by LibWeb to disassociate event handler attribute callback functions from the nearest script on the call stack.
|
|
// https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler Step 3.11
|
|
void set_script_or_module(ScriptOrModule script_or_module) { m_script_or_module = move(script_or_module); }
|
|
|
|
Variant<PropertyKey, PrivateName, Empty> const& class_field_initializer_name() const { return m_class_field_initializer_name; }
|
|
|
|
protected:
|
|
virtual bool is_strict_mode() const final { return m_strict; }
|
|
|
|
virtual Completion ordinary_call_evaluate_body();
|
|
|
|
private:
|
|
ECMAScriptFunctionObject(DeprecatedFlyString name, DeprecatedString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> parameters, i32 m_function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name);
|
|
|
|
virtual bool is_ecmascript_function_object() const override { return true; }
|
|
virtual void visit_edges(Visitor&) override;
|
|
|
|
ThrowCompletionOr<void> prepare_for_ordinary_call(ExecutionContext& callee_context, Object* new_target);
|
|
void ordinary_call_bind_this(ExecutionContext&, Value this_argument);
|
|
|
|
ThrowCompletionOr<void> function_declaration_instantiation();
|
|
|
|
DeprecatedFlyString m_name;
|
|
RefPtr<Bytecode::Executable> m_bytecode_executable;
|
|
Vector<NonnullRefPtr<Bytecode::Executable>> m_default_parameter_bytecode_executables;
|
|
i32 m_function_length { 0 };
|
|
Vector<DeprecatedFlyString> m_local_variables_names;
|
|
|
|
// Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects
|
|
GCPtr<Environment> m_environment; // [[Environment]]
|
|
GCPtr<PrivateEnvironment> m_private_environment; // [[PrivateEnvironment]]
|
|
Vector<FunctionParameter> const m_formal_parameters; // [[FormalParameters]]
|
|
NonnullRefPtr<Statement const> m_ecmascript_code; // [[ECMAScriptCode]]
|
|
GCPtr<Realm> m_realm; // [[Realm]]
|
|
ScriptOrModule m_script_or_module; // [[ScriptOrModule]]
|
|
GCPtr<Object> m_home_object; // [[HomeObject]]
|
|
DeprecatedString m_source_text; // [[SourceText]]
|
|
Vector<ClassFieldDefinition> m_fields; // [[Fields]]
|
|
Vector<PrivateElement> m_private_methods; // [[PrivateMethods]]
|
|
Variant<PropertyKey, PrivateName, Empty> m_class_field_initializer_name; // [[ClassFieldInitializerName]]
|
|
ConstructorKind m_constructor_kind : 1 { ConstructorKind::Base }; // [[ConstructorKind]]
|
|
bool m_strict : 1 { false }; // [[Strict]]
|
|
bool m_is_class_constructor : 1 { false }; // [[IsClassConstructor]]
|
|
ThisMode m_this_mode : 2 { ThisMode::Global }; // [[ThisMode]]
|
|
|
|
bool m_might_need_arguments_object : 1 { true };
|
|
bool m_contains_direct_call_to_eval : 1 { true };
|
|
bool m_is_arrow_function : 1 { false };
|
|
bool m_has_simple_parameter_list : 1 { false };
|
|
FunctionKind m_kind : 3 { FunctionKind::Normal };
|
|
|
|
struct VariableNameToInitialize {
|
|
Identifier const& identifier;
|
|
bool parameter_binding { false };
|
|
bool function_name { false };
|
|
};
|
|
|
|
bool m_has_parameter_expressions { false };
|
|
bool m_has_duplicates { false };
|
|
HashTable<DeprecatedFlyString> m_parameter_names;
|
|
Vector<FunctionDeclaration const&> m_functions_to_initialize;
|
|
bool m_arguments_object_needed { false };
|
|
Vector<VariableNameToInitialize> m_var_names_to_initialize_binding;
|
|
Vector<DeprecatedFlyString> m_function_names_to_initialize_binding;
|
|
|
|
size_t m_function_environment_bindings_count { 0 };
|
|
size_t m_var_environment_bindings_count { 0 };
|
|
size_t m_lex_environment_bindings_count { 0 };
|
|
};
|
|
|
|
template<>
|
|
inline bool Object::fast_is<ECMAScriptFunctionObject>() const { return is_ecmascript_function_object(); }
|
|
|
|
}
|