Quellcode durchsuchen

LibJS: Use ThrowCompletionOr in get_prototype_from_constructor()

Also add spec step comments to it while we're here.
Linus Groh vor 3 Jahren
Ursprung
Commit
2d4650714f

+ 15 - 4
Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp

@@ -331,16 +331,27 @@ bool validate_and_apply_property_descriptor(Object* object, PropertyName const&
 }
 }
 
 
 // 10.1.14 GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ), https://tc39.es/ecma262/#sec-getprototypefromconstructor
 // 10.1.14 GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ), https://tc39.es/ecma262/#sec-getprototypefromconstructor
-Object* get_prototype_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)())
+ThrowCompletionOr<Object*> get_prototype_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)())
 {
 {
     auto& vm = global_object.vm();
     auto& vm = global_object.vm();
+
+    // 1. Assert: intrinsicDefaultProto is this specification's name of an intrinsic object. The corresponding object must be an intrinsic that is intended to be used as the [[Prototype]] value of an object.
+
+    // 2. Let proto be ? Get(constructor, "prototype").
     auto prototype = constructor.get(vm.names.prototype);
     auto prototype = constructor.get(vm.names.prototype);
-    if (vm.exception())
-        return nullptr;
+    if (auto* exception = vm.exception())
+        return throw_completion(exception->value());
+
+    // 3. If Type(proto) is not Object, then
     if (!prototype.is_object()) {
     if (!prototype.is_object()) {
-        auto* realm = TRY_OR_DISCARD(get_function_realm(global_object, constructor));
+        // a. Let realm be ? GetFunctionRealm(constructor).
+        auto* realm = TRY(get_function_realm(global_object, constructor));
+
+        // b. Set proto to realm's intrinsic object named intrinsicDefaultProto.
         prototype = (realm->global_object().*intrinsic_default_prototype)();
         prototype = (realm->global_object().*intrinsic_default_prototype)();
     }
     }
+
+    // 4. Return proto.
     return &prototype.as_object();
     return &prototype.as_object();
 }
 }
 
 

+ 2 - 5
Userland/Libraries/LibJS/Runtime/AbstractOperations.h

@@ -26,7 +26,7 @@ ThrowCompletionOr<FunctionObject*> species_constructor(GlobalObject&, Object con
 ThrowCompletionOr<Realm*> get_function_realm(GlobalObject&, FunctionObject const&);
 ThrowCompletionOr<Realm*> get_function_realm(GlobalObject&, FunctionObject const&);
 bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
 bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
 bool validate_and_apply_property_descriptor(Object*, PropertyName const&, bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
 bool validate_and_apply_property_descriptor(Object*, PropertyName const&, bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
-Object* get_prototype_from_constructor(GlobalObject&, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)());
+ThrowCompletionOr<Object*> get_prototype_from_constructor(GlobalObject&, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)());
 Object* create_unmapped_arguments_object(GlobalObject&, Span<Value> arguments);
 Object* create_unmapped_arguments_object(GlobalObject&, Span<Value> arguments);
 Object* create_mapped_arguments_object(GlobalObject&, FunctionObject&, Vector<FunctionNode::Parameter> const&, Span<Value> arguments, Environment&);
 Object* create_mapped_arguments_object(GlobalObject&, FunctionObject&, Vector<FunctionNode::Parameter> const&, Span<Value> arguments, Environment&);
 Value canonical_numeric_index_string(GlobalObject&, PropertyName const&);
 Value canonical_numeric_index_string(GlobalObject&, PropertyName const&);
@@ -46,10 +46,7 @@ Value perform_eval(Value, GlobalObject&, CallerMode, EvalMode);
 template<typename T, typename... Args>
 template<typename T, typename... Args>
 T* ordinary_create_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)(), Args&&... args)
 T* ordinary_create_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)(), Args&&... args)
 {
 {
-    auto& vm = global_object.vm();
-    auto* prototype = get_prototype_from_constructor(global_object, constructor, intrinsic_default_prototype);
-    if (vm.exception())
-        return nullptr;
+    auto* prototype = TRY_OR_DISCARD(get_prototype_from_constructor(global_object, constructor, intrinsic_default_prototype));
     return global_object.heap().allocate<T>(global_object, forward<Args>(args)..., *prototype);
     return global_object.heap().allocate<T>(global_object, forward<Args>(args)..., *prototype);
 }
 }
 
 

+ 1 - 3
Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp

@@ -55,9 +55,7 @@ Value ArrayConstructor::construct(FunctionObject& new_target)
 {
 {
     auto& vm = this->vm();
     auto& vm = this->vm();
 
 
-    auto* proto = get_prototype_from_constructor(global_object(), new_target, &GlobalObject::array_prototype);
-    if (vm.exception())
-        return {};
+    auto* proto = TRY_OR_DISCARD(get_prototype_from_constructor(global_object(), new_target, &GlobalObject::array_prototype));
 
 
     if (vm.argument_count() == 0)
     if (vm.argument_count() == 0)
         return Array::create(global_object(), 0, proto);
         return Array::create(global_object(), 0, proto);

+ 1 - 3
Userland/Libraries/LibJS/Runtime/StringConstructor.cpp

@@ -67,9 +67,7 @@ Value StringConstructor::construct(FunctionObject& new_target)
         primitive_string = vm.argument(0).to_primitive_string(global_object());
         primitive_string = vm.argument(0).to_primitive_string(global_object());
     if (!primitive_string)
     if (!primitive_string)
         return {};
         return {};
-    auto* prototype = get_prototype_from_constructor(global_object(), new_target, &GlobalObject::string_prototype);
-    if (vm.exception())
-        return {};
+    auto* prototype = TRY_OR_DISCARD(get_prototype_from_constructor(global_object(), new_target, &GlobalObject::string_prototype));
     return StringObject::create(global_object(), *primitive_string, *prototype);
     return StringObject::create(global_object(), *primitive_string, *prototype);
 }
 }
 
 

+ 2 - 4
Userland/Libraries/LibJS/Runtime/TypedArray.cpp

@@ -270,10 +270,8 @@ void TypedArrayBase::visit_edges(Visitor& visitor)
 #define JS_DEFINE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type)                                             \
 #define JS_DEFINE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type)                                             \
     ClassName* ClassName::create(GlobalObject& global_object, u32 length, FunctionObject& new_target)                                  \
     ClassName* ClassName::create(GlobalObject& global_object, u32 length, FunctionObject& new_target)                                  \
     {                                                                                                                                  \
     {                                                                                                                                  \
-        auto& vm = global_object.vm();                                                                                                 \
-        auto* prototype = get_prototype_from_constructor(global_object, new_target, &GlobalObject::snake_name##_prototype);            \
-        if (vm.exception())                                                                                                            \
-            return {};                                                                                                                 \
+        auto* prototype = TRY_OR_DISCARD(get_prototype_from_constructor(                                                               \
+            global_object, new_target, &GlobalObject::snake_name##_prototype));                                                        \
         return global_object.heap().allocate<ClassName>(global_object, length, *prototype);                                            \
         return global_object.heap().allocate<ClassName>(global_object, length, *prototype);                                            \
     }                                                                                                                                  \
     }                                                                                                                                  \
                                                                                                                                        \
                                                                                                                                        \