mirror of
https://github.com/RGBCube/serenity
synced 2025-06-29 03:42:07 +00:00
LibJS: Only update anonymous function names when necessary
Previously we would generate function names for anonymous functions on every AssignmentExpression, even if we weren't assigning a function. We were also setting names of anonymous functions in arrays, which is apparently a SpiderMonkey specific behavior not supported by V8, JSC or required by ECMA262. This patch removes that behavior. This is a huge performance improvement on the CanvasCycle demo! :^)
This commit is contained in:
parent
f89c479358
commit
dc8817638e
2 changed files with 13 additions and 33 deletions
|
@ -80,30 +80,13 @@ String ASTNode::class_name() const
|
||||||
return demangle(typeid(*this).name()).substring(4);
|
return demangle(typeid(*this).name()).substring(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_function_name(Value value, const FlyString& name, HashTable<JS::Cell*>& visited)
|
|
||||||
{
|
|
||||||
if (!value.is_object())
|
|
||||||
return;
|
|
||||||
if (visited.contains(value.as_cell()))
|
|
||||||
return;
|
|
||||||
visited.set(value.as_cell());
|
|
||||||
auto& object = value.as_object();
|
|
||||||
if (object.is_function()) {
|
|
||||||
auto& function = static_cast<Function&>(object);
|
|
||||||
if (is<ScriptFunction>(function) && function.name().is_empty())
|
|
||||||
static_cast<ScriptFunction&>(function).set_name(name);
|
|
||||||
} else if (object.is_array()) {
|
|
||||||
auto& array = static_cast<Array&>(object);
|
|
||||||
array.indexed_properties().for_each_value([&](auto& array_element_value) {
|
|
||||||
update_function_name(array_element_value, name, visited);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_function_name(Value value, const FlyString& name)
|
static void update_function_name(Value value, const FlyString& name)
|
||||||
{
|
{
|
||||||
HashTable<JS::Cell*> visited;
|
if (!value.is_function())
|
||||||
update_function_name(value, name, visited);
|
return;
|
||||||
|
auto& function = value.as_function();
|
||||||
|
if (is<ScriptFunction>(function) && function.name().is_empty())
|
||||||
|
static_cast<ScriptFunction&>(function).set_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String get_function_name(GlobalObject& global_object, Value value)
|
static String get_function_name(GlobalObject& global_object, Value value)
|
||||||
|
@ -1443,7 +1426,11 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
|
||||||
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::InvalidLeftHandAssignment);
|
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::InvalidLeftHandAssignment);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
update_function_name(rhs_result, get_function_name(global_object, reference.name().to_value(interpreter.vm())));
|
|
||||||
|
// FIXME: We should also check if the LHS is an identifier reference.
|
||||||
|
if (rhs_result.is_function())
|
||||||
|
update_function_name(rhs_result, get_function_name(global_object, reference.name().to_value(interpreter.vm())));
|
||||||
|
|
||||||
reference.put(global_object, rhs_result);
|
reference.put(global_object, rhs_result);
|
||||||
|
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
|
|
|
@ -21,9 +21,9 @@ test("function assigned to variable", () => {
|
||||||
|
|
||||||
test("functions in array assigned to variable", () => {
|
test("functions in array assigned to variable", () => {
|
||||||
const arr = [function () {}, function () {}, function () {}];
|
const arr = [function () {}, function () {}, function () {}];
|
||||||
expect(arr[0].name).toBe("arr");
|
expect(arr[0].name).toBe("");
|
||||||
expect(arr[1].name).toBe("arr");
|
expect(arr[1].name).toBe("");
|
||||||
expect(arr[2].name).toBe("arr");
|
expect(arr[2].name).toBe("");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("functions in objects", () => {
|
test("functions in objects", () => {
|
||||||
|
@ -48,10 +48,3 @@ test("names of native functions", () => {
|
||||||
expect((console.debug.name = "warn")).toBe("warn");
|
expect((console.debug.name = "warn")).toBe("warn");
|
||||||
expect(console.debug.name).toBe("debug");
|
expect(console.debug.name).toBe("debug");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("cyclic members should not cause infinite recursion (#3471)", () => {
|
|
||||||
let a = [() => 4];
|
|
||||||
a[1] = a;
|
|
||||||
a = a;
|
|
||||||
expect(a[0].name).toBe("a");
|
|
||||||
});
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue