diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 70a181d7fe..77250683a0 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -114,8 +114,7 @@ Value CallExpression::execute(Interpreter& interpreter) const ASSERT(!callee.is_empty()); - if (!callee.is_object() - || !callee.as_object().is_function() + if (!callee.is_function() || (is_new_expression() && (callee.as_object().is_native_function() && !static_cast(callee.as_object()).has_constructor()))) { String error_message; auto call_type = is_new_expression() ? "constructor" : "function"; @@ -132,7 +131,7 @@ Value CallExpression::execute(Interpreter& interpreter) const return interpreter.throw_exception(error_message); } - auto& function = static_cast(callee.as_object()); + auto& function = callee.as_function(); MarkedValueList arguments(interpreter.heap()); arguments.values().append(function.bound_arguments()); @@ -469,7 +468,7 @@ Value UnaryExpression::execute(Interpreter& interpreter) const case Value::Type::String: return js_string(interpreter, "string"); case Value::Type::Object: - if (lhs_result.as_object().is_function()) + if (lhs_result.is_function()) return js_string(interpreter, "function"); return js_string(interpreter, "object"); case Value::Type::Boolean: diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index 003013b1a0..9df20acea3 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -76,11 +76,11 @@ static Function* callback_from_args(Interpreter& interpreter, const String& name return nullptr; } auto callback = interpreter.argument(0); - if (!callback.is_object() || !callback.as_object().is_function()) { + if (!callback.is_function()) { interpreter.throw_exception(String::format("%s is not a function", callback.to_string().characters())); return nullptr; } - return static_cast(&callback.as_object()); + return &callback.as_function(); } Value ArrayPrototype::filter(Interpreter& interpreter) diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index d5a30a3086..c7088155c9 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -477,10 +477,8 @@ Value Object::to_primitive(PreferredType preferred_type) const Value Object::to_string() const { auto to_string_property = get("toString"); - if (!to_string_property.is_empty() - && to_string_property.is_object() - && to_string_property.as_object().is_function()) { - auto& to_string_function = static_cast(to_string_property.as_object()); + if (!to_string_property.is_empty() && to_string_property.is_function()) { + auto& to_string_function = to_string_property.as_function(); auto& interpreter = const_cast(this)->interpreter(); auto to_string_result = interpreter.call(to_string_function, const_cast(this)); if (to_string_result.is_object()) diff --git a/Libraries/LibJS/Runtime/ReflectObject.cpp b/Libraries/LibJS/Runtime/ReflectObject.cpp index 98af31c97c..1c07dc53c0 100644 --- a/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -47,11 +47,11 @@ static Object* get_target_object_from(Interpreter& interpreter, const String& na static Function* get_target_function_from(Interpreter& interpreter, const String& name) { auto target = interpreter.argument(0); - if (!target.is_object() || !target.as_object().is_function()) { + if (!target.is_function()) { interpreter.throw_exception(String::format("First argument of Reflect.%s() must be a function", name.characters())); return nullptr; } - return static_cast(&target.as_object()); + return &target.as_function(); } static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments) @@ -121,13 +121,12 @@ Value ReflectObject::construct(Interpreter& interpreter) auto* new_target = target; if (interpreter.argument_count() > 2) { auto new_target_value = interpreter.argument(2); - if (!new_target_value.is_object() - || !new_target_value.as_object().is_function() + if (!new_target_value.is_function() || (new_target_value.as_object().is_native_function() && !static_cast(new_target_value.as_object()).has_constructor())) { interpreter.throw_exception("Optional third argument of Reflect.construct() must be a constructor"); return {}; } - new_target = static_cast(&new_target_value.as_object()); + new_target = &new_target_value.as_function(); } return interpreter.construct(*target, *new_target, move(arguments)); } diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 81ff30cda4..a2f1cceec5 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,17 @@ bool Value::is_array() const return is_object() && as_object().is_array(); } +bool Value::is_function() const +{ + return is_object() && as_object().is_function(); +} + +Function& Value::as_function() +{ + ASSERT(is_function()); + return static_cast(as_object()); +} + String Value::to_string() const { if (is_boolean()) diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index 48d8cc4c10..82c4e4478a 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -54,6 +54,7 @@ public: bool is_boolean() const { return m_type == Type::Boolean; } bool is_cell() const { return is_string() || is_object(); } bool is_array() const; + bool is_function() const; bool is_nan() const { return is_number() && __builtin_isnan(as_double()); } bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); } @@ -157,6 +158,8 @@ public: return m_value.as_cell; } + Function& as_function(); + String to_string() const; bool to_boolean() const; Value to_number() const;