Statically set computed property method's function name if computed property name is string or number
Categories
(Core :: JavaScript Engine, defect, P3)
Tracking
()
People
(Reporter: arai, Assigned: mohamedatef1698, Mentored)
References
Details
(Whiteboard: [lang=c++])
Attachments
(1 file)
Updated•7 years ago
|
Reporter | ||
Comment 1•3 years ago
|
||
Context:
Anonymous function's name is calculated from the surrounding context.
In this bug's case, it's an object's property with anonymous function, that corresponds to the following spec step.
https://tc39.es/ecma262/#sec-runtime-semantics-propertydefinitionevaluation
PropertyDefinition : PropertyName : AssignmentExpression
...
6. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and isProtoSetter is false, then
a. Let propValue be ? NamedEvaluation of AssignmentExpression with argument propKey.
Inside SpiderMonkey, this is done in 2 places.
- If the property name is simple and known at compile time, set it inside js::frontend::NameFunctions
- If the property name is complex or not known at compile time, set it at runtime by JSOp::SetFunName instruction
You can see the difference by running the following 2 codes, inside the debug build of SpiderMonkey shell:
dis(() => ({ foo: function() {} }));
dis(() => ({ ["foo"]: function() {} }));
Things to do here:
- Inside NameFunctions.cpp, detect if the computed property name is known at compile time (primitive, like string), and set it there
- Inside BytecodeEmitter.cpp, stop emitting
JSOp::SetFunName
for the handled case
If you have any question, feel free to ask here, or in https://chat.mozilla.org/#/room/#spidermonkey:mozilla.org
Assignee | ||
Comment 2•3 years ago
|
||
the resolveFun
is the function that resolves the name of the anonymous functions.
what if we add these lines
if (funbox->displayAtom()) {
if (!NameFunctions(this->cx_, this->ec_, this->stackLimit_,
this->parserAtoms_, funNode)) {
return false;
}
}
after this line: https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#325
Assignee | ||
Comment 3•3 years ago
|
||
also here, I think this line corresponds to the specs.
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#325
should I call the function the same way mentioned in Comment 2
?
or should I iterate over the nodes inside NameFunctions
this way:
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#325
and Check if the name exists and use JSOp::SetFunName
to emit it.
another thought,
maybe I can edit the visit function of the AST to emit the name if the function has a simple name
Assignee | ||
Comment 4•3 years ago
|
||
(In reply to Mohamed Atef from comment #3)
also here, I think this line corresponds to the specs.
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#325
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#257
should I call the function the same way mentioned inComment 2
?
or should I iterate over the nodes insideNameFunctions
this way:
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#325
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#158
and Check if the name exists and useJSOp::SetFunName
to emit it.
another thought,
maybe I can edit the visit function of the AST to emit the name if the function has a simple name
Assignee | ||
Comment 5•3 years ago
|
||
(In reply to Mohamed Atef from comment #4)
(In reply to Mohamed Atef from comment #3)
also here, I think this line corresponds to the specs.
should I call the function the same way mentioned in
Comment 2
?
or should I iterate over the nodes insideNameFunctions
this way:
and Check if the name exists and use
JSOp::SetFunName
to emit it.
another thought,
maybe I can edit the visit function of the AST to emit the name if the function has a simple name
Reporter | ||
Comment 6•3 years ago
|
||
Yes, the second URL for resolveFun
corresponds to the spec, and that's where the fix is needed.
I think you don't have to touch gatherNameable
function, given it already handles object property.
In the following range in resolveFun
, 4 cases are handled:
https://searchfox.org/mozilla-central/rev/4a15041348e08fb0d6f5726015c32861e663fbfe/js/src/frontend/NameFunctions.cpp#252-302
(1) foo = function() {}
if (assignment->is<AssignmentNode>()) {
assignment = assignment->as<AssignmentNode>().left();
...
if (!nameExpression(assignment, &foundName)) {
(2) ({ foo: function() {} })
if (node->isKind(ParseNodeKind::PropertyDefinition) ||
node->isKind(ParseNodeKind::Shorthand)) {
ParseNode* left = node->as<BinaryNode>().left();
if (left->isKind(ParseNodeKind::ObjectPropertyName) ||
...
if (!appendPropertyReference(left->as<NameNode>().atom())) {
(3) ({ "foo": function() {} })
if (node->isKind(ParseNodeKind::PropertyDefinition) ||
node->isKind(ParseNodeKind::Shorthand)) {
ParseNode* left = node->as<BinaryNode>().left();
...
left->isKind(ParseNodeKind::StringExpr)) {
if (!appendPropertyReference(left->as<NameNode>().atom())) {
(4) ({ 10: function() {} })
if (node->isKind(ParseNodeKind::PropertyDefinition) ||
node->isKind(ParseNodeKind::Shorthand)) {
ParseNode* left = node->as<BinaryNode>().left();
...
} else if (left->isKind(ParseNodeKind::NumberExpr)) {
if (!appendNumericPropertyReference(
left->as<NumericLiteral>().value())) {
ParseNode.h has the document for some node kind.
then, as you can see in the above range, left->isKind(ParseNodeKind::ComputedName)
and left->isKind(ParseNodeKind::BigIntExpr)
are not handled for object property.
if (node->isKind(ParseNodeKind::PropertyDefinition) ||
node->isKind(ParseNodeKind::Shorthand)) {
ParseNode* left = node->as<BinaryNode>().left();
...
} else {
MOZ_ASSERT(left->isKind(ParseNodeKind::ComputedName) ||
left->isKind(ParseNodeKind::BigIntExpr));
ParseNodeKind::ComputedName
corresponds to ({ ["foo"]: function() {} })
case, and
ParseNodeKind::BigIntExpr
corresponds to ({ 10n: function() {} })
case.
And those cases use JSOp::SetFunName
to set name at runtime.
So, to handle computed property, you need to add another branch inside the loop, to check if the object property key is ComputedName
, and see if its expression is literal.
Assignee | ||
Comment 7•3 years ago
|
||
Thanks, It's very clear now.
But, What do you mean by its expression literal?
do you mean this: https://searchfox.org/mozilla-central/source/js/src/frontend/ParseNode.h#803 ?
The function name is computed from the surrounding context as you mentioned,
so may be it's a string or a number,
if (!appendPropertyReference(left->as<NameNode>().atom()) ||
!appendNumericPropertyReference(left->as<NumericLiteral>().value())) {
return false;
}
Reporter | ||
Comment 8•3 years ago
|
||
Yes, they're literal.
in the context of computed property name, by literal, I mean numeric literal 123
, string literal "foo"
, etc,
and by "expression" there, I mean the computed property name's content.
If the code is ({ ["foo"]: function() {} })
, the content of the computed property name is "foo"
, and it's known at compile time,
and the anonymous function's name is known to be "foo"
.
In the same way, if the code is ({ [10]: function() {} })
, the content of the computed property name is 10
, and it's known at compile time,
and the anonymous function's name is known to be "10"
.
So, we can set the function's name at compile-time, and don't have to emit JSOp::SetFunName
.
On the other hand, if the code is ({ [someVariable]: function() {} })
, the content of the computed property name if someVariable
, and its value
is generally not known at compile time. and this case still needs JSOp::SetFunName
, to set the function name at runtime.
Then, in the loop, left
is the property name, and what we want to handle is left->isKind(ParseNodeKind::ComputedName)
case.
ComputedName
node is unary node, and kid()
method on it returns the content.
* ComputedName (UnaryNode)
* ES6 ComputedPropertyName.
* kid: the AssignmentExpression inside the square brackets
class UnaryNode : public ParseNode {
...
ParseNode* kid() const { return kid_; }
You can cast left
(ParseNode*
type) to UnaryNode
with left->as<UnaryNode>()
method.
So, computed property with string literal corresponds to left->as<UnaryNode>().kid()->isKind(ParseNodeKind::StringExpr)
,
and if that's true, you can pass the kid
to appendPropertyReference
.
Same for numeric literal (NumericLiteral
) case.
Assignee | ||
Comment 9•3 years ago
|
||
I added the following lines, when I open the debug build terminal and try dis(() => ({ ["foo"]: function() {} }));
the debug build crashes, I think there's a problem with the stack after my modification.
Did I over-code it?
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3796,6 +3796,13 @@ static bool IsDestructuringRestExclusion
continue;
}
+ if (key->isKind(ParseNodeKind::ComputedName)) {
+ ParseNode* keyKid = key->as<UnaryNode>().kid();
+ if (keyKid->isKind(ParseNodeKind::StringExpr)) {
+ continue;
+ }
+ }
+
// Number and BigInt keys aren't yet supported. Computed property names need
// to be added dynamically.
MOZ_ASSERT(key->isKind(ParseNodeKind::NumberExpr) ||
@@ -3855,6 +3862,18 @@ bool BytecodeEmitter::emitDestructuringO
} else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
key->isKind(ParseNodeKind::StringExpr)) {
pnatom = key->as<NameNode>().atom();
+ } else if (key->isKind(ParseNodeKind::ComputedName) &&
+ (key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::StringExpr) ||
+ key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::NumberExpr))) {
+ ParseNode* keyKid = key->as<UnaryNode>().kid();
+ if (keyKid->as<NumericLiteral>().value()) {
+ return false;
+ isIndex = true;
+ } else if (keyKid->isKind(ParseNodeKind::StringExpr)) {
+ pnatom = keyKid->as<NameNode>().atom();
+ }
} else {
// Otherwise this is a computed property name which needs to
// be added dynamically.
@@ -8657,8 +8676,10 @@ void BytecodeEmitter::isPropertyListObjL
// Computed keys not OK (ObjLiteral data stores constant keys).
if (key->isKind(ParseNodeKind::ComputedName)) {
- keysOK = false;
- break;
+ if (!key->as<UnaryNode>().kid()->isKind(ParseNodeKind::NumberExpr)) {
+ keysOK = false;
+ break;
+ }
}
// BigIntExprs should have been lowered to computed names at parse
@@ -8666,8 +8687,15 @@ void BytecodeEmitter::isPropertyListObjL
MOZ_ASSERT(!key->isKind(ParseNodeKind::BigIntExpr));
// Numeric keys OK as long as they are integers and in range.
- if (key->isKind(ParseNodeKind::NumberExpr)) {
+ if (key->isKind(ParseNodeKind::NumberExpr) ||
+ (key->isKind(ParseNodeKind::ComputedName) &&
+ key->as<UnaryNode>().kid()->isKind(ParseNodeKind::NumberExpr))) {
double numValue = key->as<NumericLiteral>().value();
+
+ if (key->isKind(ParseNodeKind::ComputedName) &&
+ key->as<UnaryNode>().kid()->isKind(ParseNodeKind::NumberExpr))
+ numValue = key->as<UnaryNode>().kid()->as<NumericLiteral>().value();
+
int32_t i = 0;
if (!NumberIsInt32(numValue, &i)) {
keysOK = false;
@@ -8869,6 +8897,33 @@ bool BytecodeEmitter::emitPropertyList(L
// [stack] CTOR? OBJ CTOR? VAL
return false;
}
+ } else if (key->isKind(ParseNodeKind::ComputedName) &&
+ (key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::StringExpr) ||
+ key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::NumberExpr))) {
+ ParseNode* keyKid = key->as<UnaryNode>().kid();
+ if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
+ MOZ_ASSERT(accessorType == AccessorType::None);
+
+ auto keyAtom
+ = keyKid->as<NumericLiteral>().toAtom(cx, parserAtoms());
+ if (!keyAtom) {
+ return false;
+ }
+ if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
+ // [stack] CTOR? OBJ CTOR? KEY VAL
+ return false;
+ }
+ } else if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
+ MOZ_ASSERT(accessorType == AccessorType::None);
+
+ auto keyAtom = key->as<NameNode>().atom();
+ if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
+ // [stack] CTOR? OBJ CTOR? VAL
+ return false;
+ }
+ }
} else {
MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName) ||
key->isKind(ParseNodeKind::BigIntExpr));
diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -289,6 +289,22 @@ class NameResolver : public ParseNodeVis
left->as<NumericLiteral>().value())) {
return false;
}
+ } else if (left->isKind(ParseNodeKind::ComputedName) &&
+ (left->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::StringExpr) ||
+ left->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::NumberExpr))) {
+ ParseNode* kid = left->as<UnaryNode>().kid();
+ if (kid->isKind(ParseNodeKind::StringExpr)) {
+ if (!appendPropertyReference(kid->as<NameNode>().atom())) {
+ return false;
+ }
+ } else if (kid->isKind(ParseNodeKind::NumberExpr)) {
+ if (!appendNumericPropertyReference(
+ kid->as<NumericLiteral>().value())) {
+ return false;
+ }
+ }
} else {
MOZ_ASSERT(left->isKind(ParseNodeKind::ComputedName) ||
left->isKind(ParseNodeKind::BigIntExpr));
Reporter | ||
Comment 10•3 years ago
|
||
Good question :)
It crashes with the following assertion failure.
Assertion failure: stackDepth_ >= 0, at .../mozilla-unified/js/src/frontend/BytecodeSection.cpp:179
in the following backtrace:
#01: js::frontend::BytecodeSection::updateDepth(js::frontend::BytecodeOffset)[.../mozilla-unified/obj/sm-pds/dist/bin/js +0xc04fb0]
#02: js::frontend::BytecodeEmitter::emit1(JSOp)[.../mozilla-unified/obj/sm-pds/dist/bin/js +0xbfa924]
#03: js::frontend::PropertyEmitter::emitInitIndexOrComputed(JSOp)[.../mozilla-unified/obj/sm-pds/dist/bin/js +0xcac060]
#04: js::frontend::PropertyEmitter::emitInitIndexOrComputed(js::frontend::AccessorType)[.../mozilla-unified/obj/sm-pds/dist/bin/js +0xcabd54]
#05: js::frontend::BytecodeEmitter::emitPropertyList(js::frontend::ListNode*, js::frontend::PropertyEmitter&, js::frontend::PropListType)[.../mozilla-unified/obj/sm-pds/dist/bin/js +0xc310dc]
SpiderMonkey's VM is stack machine, and the stackDepth_
variable tracks the depth of the value stack during emitting bytecode, to verify if it balances.
And the assertion stackDepth_ >= 0
failed means stackDepth_ < 0
, that means the last opcode emitted before the assertion failure wanted to pop N
values but the stack had N-1
or less values.
Running the JS shell with debugger will tell what happens.
The opcode op
in BytecodeEmitter::emit1
is JSOp::InitElem
.
/*
* Define a data property on `obj` with property key `id` and value `val`.
...
* Stack: obj, id, val => obj
*/ \
MACRO(InitElem, init_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
JSOp::InitElem
pops 3 valus, val
, id
, and obj
, and performs obj[id] = val
initialization, and pushes obj
.
And stackDepth_
in BytecodeSection::updateDepth
is -1
, that means there were only 2 values on the stack,
and given the patch modifies bytecode around the property value with anonymous function, it's likely that the val
is missing.
Now, let's look into the patch.
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -8869,6 +8897,33 @@ bool BytecodeEmitter::emitPropertyList(L
...
+ } else if (key->isKind(ParseNodeKind::ComputedName) &&
+ (key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::StringExpr) ||
+ key->as<UnaryNode>().kid()->isKind(
+ ParseNodeKind::NumberExpr))) {
This branch is taken if the computed property's content is either string or number.
+ ParseNode* keyKid = key->as<UnaryNode>().kid();
+ if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
Here, this branch checks if the expression is number.
...
+ } else if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
and here, this branch also checks if the expression is number.
and the string case is not handled and value is not pushed,
that results in the assertion failure.
So, this branch should check keyKid->isKind(ParseNodeKind::StringExpr)
.
+ } else if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
+ MOZ_ASSERT(accessorType == AccessorType::None);
+
+ auto keyAtom = key->as<NameNode>().atom();
keyKid->as<NameNode>().atom()
Reporter | ||
Comment 11•3 years ago
|
||
(In reply to Tooru Fujisawa [:arai] from comment #10)
+ } else if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
and here, this branch also checks if the expression is number.
and the string case is not handled and value is not pushed,
that results in the assertion failure.So, this branch should check
keyKid->isKind(ParseNodeKind::StringExpr)
.
Actually, this branch doesn't have to check the kind again.
Given the enclosing branch already checks the keyKid
is either ParseNodeKind::StringExpr
or ParseNodeKind::NumberExpr
,
the else
after if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
is always ParseNodeKind::StringExpr
.
So, it can be written like the following:
} else if (key->isKind(ParseNodeKind::ComputedName) &&
(key->as<UnaryNode>().kid()->isKind(
ParseNodeKind::StringExpr) ||
key->as<UnaryNode>().kid()->isKind(
ParseNodeKind::NumberExpr))) {
ParseNode* keyKid = key->as<UnaryNode>().kid();
if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
...
}
} else {
MOZ_ASSERT(keyKid->isKind(ParseNodeKind::StringExpr));
...
}
}
} else {
This way a bug due to missing case can be avoided.
Assignee | ||
Comment 12•3 years ago
|
||
Updated•3 years ago
|
Comment 13•3 years ago
|
||
Comment 14•3 years ago
|
||
Backed out for causing reftest failures on function-name-computed-03.js
Failure line: REFTEST TEST-UNEXPECTED-FAIL | js/src/tests/non262/Function/function-name-computed-03.js | Unknown file:///opt/worker/tasks/task_165996400230035/build/tests/jsreftest/tests/js/src/tests/non262/Function/function-name-computed-03.js:12: ReferenceError: displayName is not defined item 1
[task 2022-08-08T13:44:26.888Z] 13:44:26 INFO - REFTEST TEST-START | js/src/tests/non262/Function/function-name-computed-03.js
[task 2022-08-08T13:44:26.889Z] 13:44:26 INFO - REFTEST TEST-LOAD | file:///opt/worker/tasks/task_165996400230035/build/tests/jsreftest/tests/js/src/tests/jsreftest.html?test=non262/Function/function-name-computed-03.js | 441 / 15577 (2%)
[task 2022-08-08T13:44:26.898Z] 13:44:26 INFO - TEST-INFO | FAILED! ReferenceError: displayName is not defined
[task 2022-08-08T13:44:26.899Z] 13:44:26 INFO - JavaScript error: file:///opt/worker/tasks/task_165996400230035/build/tests/jsreftest/tests/js/src/tests/non262/Function/function-name-computed-03.js, line 12: ReferenceError: displayName is not defined
[task 2022-08-08T13:44:26.907Z] 13:44:26 INFO - REFTEST TEST-UNEXPECTED-FAIL | js/src/tests/non262/Function/function-name-computed-03.js | Unknown file:///opt/worker/tasks/task_165996400230035/build/tests/jsreftest/tests/js/src/tests/non262/Function/function-name-computed-03.js:12: ReferenceError: displayName is not defined item 1
[task 2022-08-08T13:44:26.908Z] 13:44:26 INFO - REFTEST INFO | Saved log: START file:///opt/worker/tasks/task_165996400230035/build/tests/jsreftest/tests/js/src/tests/jsreftest.html?test=non262/Function/function-name-computed-03.js
[task 2022-08-08T13:44:26.908Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] OnDocumentLoad triggering AfterOnLoadScripts
[task 2022-08-08T13:44:26.909Z] 13:44:26 INFO - REFTEST INFO | Saved log: Initializing canvas snapshot
[task 2022-08-08T13:44:26.909Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] AfterOnLoadScripts belatedly entering WaitForTestEnd
[task 2022-08-08T13:44:26.909Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] WaitForTestEnd: Adding listeners
[task 2022-08-08T13:44:26.910Z] 13:44:26 INFO - REFTEST INFO | Saved log: Initializing canvas snapshot
[task 2022-08-08T13:44:26.910Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress
[task 2022-08-08T13:44:26.910Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: STATE_WAITING_TO_FIRE_INVALIDATE_EVENT
[task 2022-08-08T13:44:26.911Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: dispatching MozReftestInvalidate
[task 2022-08-08T13:44:26.911Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress
[task 2022-08-08T13:44:26.912Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL
[task 2022-08-08T13:44:26.912Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress
[task 2022-08-08T13:44:26.912Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: STATE_WAITING_FOR_SPELL_CHECKS
[task 2022-08-08T13:44:26.913Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: STATE_WAITING_FOR_APZ_FLUSH
[task 2022-08-08T13:44:26.913Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: APZ flush not required
[task 2022-08-08T13:44:26.914Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress
[task 2022-08-08T13:44:26.914Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: STATE_WAITING_TO_FINISH
[task 2022-08-08T13:44:26.914Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: Doing sync flush to compositor
[task 2022-08-08T13:44:26.915Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] MakeProgress: Completed
[task 2022-08-08T13:44:26.915Z] 13:44:26 INFO - REFTEST INFO | Saved log: [CONTENT] RecordResult fired
[task 2022-08-08T13:44:26.915Z] 13:44:26 INFO - REFTEST INFO | Saved log: RecordResult fired
[task 2022-08-08T13:44:26.916Z] 13:44:26 INFO - REFTEST TEST-END | js/src/tests/non262/Function/function-name-computed-03.js
[task 2022-08-08T13:44:26.916Z] 13:44:26 INFO - REFTEST TEST-START | js/src/tests/non262/Function/function-name-for.js
Comment 15•3 years ago
|
||
Comment 16•3 years ago
|
||
bugherder |
Updated•2 years ago
|
Description
•