Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit 8c78a22

Browse files
IteratorClose should suppress GetMethod errors
https://bugs.webkit.org/show_bug.cgi?id=212378 Reviewed by Keith Miller. JSTests: * stress/custom-iterators.js: * stress/iterator-return-abrupt-lookup-builtins.js: Added. * test262/expectations.yaml: Mark 4 test cases as passing. Source/JavaScriptCore: This patch implements recent spec change [1] that prevents "return" method lookup error from overriding outer exception, aligning JSC with V8 and SpiderMonkey. It is accomplished by moving pushTry() before emitGetById() in BytecodeGenerator.cpp (covered by test262 suite) and removal of RETURN_IF_EXCEPTION in IteratorOperations.cpp (added a stress test). Before this patch, JSC partly implemented the spec change [1] by suppressing TypeError if "return" method of iterator was not callable. BytecodeGenerator::emitDelegateYield() is intentionally left unchanged. Also, this patch utilizes emitIteratorGenericClose() to avoid code duplication. for/of microbenchmarks are neutral. [1]: tc39/ecma262#1408 * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitGenericEnumeration): (JSC::BytecodeGenerator::emitEnumeration): * runtime/IteratorOperations.cpp: (JSC::iteratorClose): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@262165 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 2ca210f commit 8c78a22

File tree

7 files changed

+75
-39
lines changed

7 files changed

+75
-39
lines changed

JSTests/ChangeLog

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2020-05-26 Alexey Shvayka <[email protected]>
2+
3+
IteratorClose should suppress GetMethod errors
4+
https://bugs.webkit.org/show_bug.cgi?id=212378
5+
6+
Reviewed by Keith Miller.
7+
8+
* stress/custom-iterators.js:
9+
* stress/iterator-return-abrupt-lookup-builtins.js: Added.
10+
* test262/expectations.yaml: Mark 4 test cases as passing.
11+
112
2020-05-23 Caio Lima <[email protected]>
213

314
[bmalloc] Fix OOM errors on MIPS after r261667

JSTests/stress/custom-iterators.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ try {
135135
throw "Error: Terminate iteration.";
136136
}
137137
} catch (e) {
138-
if (String(e) !== "Error: looking up return.")
138+
if (String(e) !== "Error: Terminate iteration.")
139139
throw e;
140140
}
141141

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function shouldThrow(func, expectedError) {
2+
let actualError;
3+
try {
4+
func();
5+
} catch (error) {
6+
actualError = error;
7+
}
8+
if (actualError !== expectedError)
9+
throw new Error(`bad error: ${actualError}`);
10+
}
11+
12+
const iter = {
13+
[Symbol.iterator]() { return this; },
14+
next() { return { value: [], done: false }; },
15+
get return() { throw 'return'; },
16+
};
17+
18+
Map.prototype.set = () => { throw 'set'; };
19+
Set.prototype.add = () => { throw 'add'; };
20+
WeakMap.prototype.set = () => { throw 'set'; };
21+
WeakSet.prototype.add = () => { throw 'add'; };
22+
23+
for (let i = 0; i < 1e4; ++i) {
24+
shouldThrow(() => new Map(iter), 'set');
25+
shouldThrow(() => new Set(iter), 'add');
26+
shouldThrow(() => new WeakMap(iter), 'set');
27+
shouldThrow(() => new WeakSet(iter), 'add');
28+
}

JSTests/test262/expectations.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,9 +3258,6 @@ test/language/statements/for-await-of/async-func-decl-dstr-array-elem-nested-obj
32583258
strict mode: 'Test262: This statement should not be evaluated.'
32593259
test/language/statements/for-await-of/async-func-decl-dstr-array-elem-target-simple-strict.js:
32603260
strict mode: 'Test262: This statement should not be evaluated.'
3261-
test/language/statements/for-await-of/iterator-close-throw-get-method-abrupt.js:
3262-
default: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected SameValue(«function Object() {'
3263-
strict mode: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected SameValue(«function Object() {'
32643261
test/language/statements/for-await-of/let-array-with-newline.js:
32653262
default: 'Test262: This statement should not be evaluated.'
32663263
test/language/statements/for-await-of/ticks-with-async-iter-resolved-promise-and-constructor-lookup-two.js:
@@ -3475,9 +3472,6 @@ test/language/statements/for-of/head-lhs-non-asnmt-trgt.js:
34753472
test/language/statements/for-of/head-var-no-expr.js:
34763473
default: 'Test262: This statement should not be evaluated.'
34773474
strict mode: 'Test262: This statement should not be evaluated.'
3478-
test/language/statements/for-of/iterator-close-throw-get-method-abrupt.js:
3479-
default: 'Test262Error: Expected a Test262Error but got a Object'
3480-
strict mode: 'Test262Error: Expected a Test262Error but got a Object'
34813475
test/language/statements/for-of/let-array-with-newline.js:
34823476
default: 'Test262: This statement should not be evaluated.'
34833477
test/language/statements/for/head-lhs-let.js:

Source/JavaScriptCore/ChangeLog

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
2020-05-26 Alexey Shvayka <[email protected]>
2+
3+
IteratorClose should suppress GetMethod errors
4+
https://bugs.webkit.org/show_bug.cgi?id=212378
5+
6+
Reviewed by Keith Miller.
7+
8+
This patch implements recent spec change [1] that prevents "return" method lookup error
9+
from overriding outer exception, aligning JSC with V8 and SpiderMonkey.
10+
11+
It is accomplished by moving pushTry() before emitGetById() in BytecodeGenerator.cpp
12+
(covered by test262 suite) and removal of RETURN_IF_EXCEPTION in IteratorOperations.cpp
13+
(added a stress test).
14+
15+
Before this patch, JSC partly implemented the spec change [1] by suppressing TypeError
16+
if "return" method of iterator was not callable.
17+
18+
BytecodeGenerator::emitDelegateYield() is intentionally left unchanged.
19+
Also, this patch utilizes emitIteratorGenericClose() to avoid code duplication.
20+
for/of microbenchmarks are neutral.
21+
22+
[1]: https://github.com/tc39/ecma262/pull/1408
23+
24+
* bytecompiler/BytecodeGenerator.cpp:
25+
(JSC::BytecodeGenerator::emitGenericEnumeration):
26+
(JSC::BytecodeGenerator::emitEnumeration):
27+
* runtime/IteratorOperations.cpp:
28+
(JSC::iteratorClose):
29+
130
2020-05-26 Mark Lam <[email protected]>
231

332
SamplingProfiler::takeSample() should not assume that ENABLE(WEBASSEMBLY) means Wasm is enabled.

Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4082,26 +4082,12 @@ void BytecodeGenerator::emitGenericEnumeration(ThrowableExpressionData* node, Ex
40824082
emitLabel(finallyBodyLabel.get());
40834083
restoreScopeRegister();
40844084

4085-
Ref<Label> finallyDone = newLabel();
4086-
4087-
RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
4088-
emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), finallyDone.get());
4089-
40904085
Ref<Label> returnCallTryStart = newLabel();
40914086
emitLabel(returnCallTryStart.get());
40924087
TryData* returnCallTryData = pushTry(returnCallTryStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
40934088

4094-
CallArguments returnArguments(*this, nullptr);
4095-
move(returnArguments.thisRegister(), iterator.get());
4096-
emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
4097-
4098-
if (isForAwait)
4099-
emitAwait(value.get());
4100-
4101-
emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), finallyDone.get());
4102-
emitThrowTypeError("Iterator result interface is not an object."_s);
4103-
4104-
emitLabel(finallyDone.get());
4089+
emitIteratorGenericClose(iterator.get(), node, shouldEmitAwait);
4090+
Ref<Label> finallyDone = newEmittedLabel();
41054091
emitFinallyCompletion(finallyContext, endCatchLabel.get());
41064092

41074093
popTry(returnCallTryData, finallyDone.get());
@@ -4238,23 +4224,12 @@ void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, Expressio
42384224
emitLabel(finallyBodyLabel.get());
42394225
restoreScopeRegister();
42404226

4241-
Ref<Label> finallyDone = newLabel();
4242-
4243-
RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
4244-
emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), finallyDone.get());
4245-
42464227
Ref<Label> returnCallTryStart = newLabel();
42474228
emitLabel(returnCallTryStart.get());
42484229
TryData* returnCallTryData = pushTry(returnCallTryStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
42494230

4250-
CallArguments returnArguments(*this, nullptr);
4251-
move(returnArguments.thisRegister(), iterator.get());
4252-
emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
4253-
4254-
emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), finallyDone.get());
4255-
emitThrowTypeError("Iterator result interface is not an object."_s);
4256-
4257-
emitLabel(finallyDone.get());
4231+
emitIteratorGenericClose(iterator.get(), node, EmitAwait::No);
4232+
Ref<Label> finallyDone = newEmittedLabel();
42584233
emitFinallyCompletion(finallyContext, endCatchLabel.get());
42594234

42604235
popTry(returnCallTryData, finallyDone.get());

Source/JavaScriptCore/runtime/IteratorOperations.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,9 @@ void iteratorClose(JSGlobalObject* globalObject, IterationRecord iterationRecord
9393
exception = catchScope.exception();
9494
catchScope.clearException();
9595
}
96-
JSValue returnFunction = iterationRecord.iterator.get(globalObject, vm.propertyNames->returnKeyword);
97-
RETURN_IF_EXCEPTION(throwScope, void());
9896

99-
if (returnFunction.isUndefined()) {
97+
JSValue returnFunction = iterationRecord.iterator.get(globalObject, vm.propertyNames->returnKeyword);
98+
if (UNLIKELY(throwScope.exception()) || returnFunction.isUndefined()) {
10099
if (exception)
101100
throwException(globalObject, throwScope, exception);
102101
return;

0 commit comments

Comments
 (0)