Bug 1408740 - Correctly throw a TypeError when closing iterators when <generator>.return is an object emulating undefined. r=anba

--HG--
extra : rebase_source : f7bf3c2c955a8711eab3dd2c9edcbfaf9df6e45e
This commit is contained in:
Jeff Walden 2017-10-17 18:55:41 -07:00
parent 012a6c1870
commit 542c511e67
2 changed files with 43 additions and 14 deletions

View File

@ -5313,6 +5313,37 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = Iter
return true;
}
bool
BytecodeEmitter::emitPushNotUndefinedOrNull()
{
MOZ_ASSERT(this->stackDepth > 0); // V
if (!emit1(JSOP_DUP)) // V V
return false;
if (!emit1(JSOP_UNDEFINED)) // V V UNDEFINED
return false;
if (!emit1(JSOP_STRICTNE)) // V ?NEQL
return false;
JumpList undefinedOrNullJump;
if (!emitJump(JSOP_AND, &undefinedOrNullJump)) // V ?NEQL
return false;
if (!emit1(JSOP_POP)) // V
return false;
if (!emit1(JSOP_DUP)) // V V
return false;
if (!emit1(JSOP_NULL)) // V V NULL
return false;
if (!emit1(JSOP_STRICTNE)) // V ?NEQL
return false;
if (!emitJumpTargetAndPatch(undefinedOrNullJump)) // V NOT-UNDEF-OR-NULL
return false;
return true;
}
bool
BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
CompletionKind completionKind /* = CompletionKind::Normal */,
@ -5338,15 +5369,12 @@ BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync
// Step 4.
//
// Do nothing if "return" is null or undefined.
// Do nothing if "return" is undefined or null.
IfThenElseEmitter ifReturnMethodIsDefined(this);
if (!emit1(JSOP_DUP)) // ... ITER RET RET
if (!emitPushNotUndefinedOrNull()) // ... ITER RET NOT-UNDEF-OR-NULL
return false;
if (!emit1(JSOP_UNDEFINED)) // ... ITER RET RET UNDEFINED
return false;
if (!emit1(JSOP_NE)) // ... ITER RET ?NEQL
return false;
if (!ifReturnMethodIsDefined.emitIfElse())
if (!ifReturnMethodIsDefined.emitIfElse()) // ... ITER RET
return false;
if (completionKind == CompletionKind::Throw) {
@ -5447,10 +5475,12 @@ BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync
}
}
if (!ifReturnMethodIsDefined.emitElse())
if (!ifReturnMethodIsDefined.emitElse()) // ... ITER RET
return false;
if (!emit1(JSOP_POP)) // ... ITER
return false;
if (!ifReturnMethodIsDefined.emitEnd())
return false;
@ -8920,13 +8950,9 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
// Step iii.
//
// Do nothing if "return" is undefined.
// Do nothing if "return" is undefined or null.
IfThenElseEmitter ifReturnMethodIsDefined(this);
if (!emit1(JSOP_DUP)) // ITER RESULT FTYPE FVALUE ITER RET RET
return false;
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT FTYPE FVALUE ITER RET RET UNDEFINED
return false;
if (!emit1(JSOP_NE)) // ITER RESULT FTYPE FVALUE ITER RET ?NEQL
if (!emitPushNotUndefinedOrNull()) // ITER RESULT FTYPE FVALUE ITER RET NOT-UNDEF-OR-NULL
return false;
// Step iv.

View File

@ -508,6 +508,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// Helper to emit JSOP_CHECKISCALLABLE.
MOZ_MUST_USE bool emitCheckIsCallable(CheckIsCallableKind kind);
// Push whether the value atop of the stack is non-undefined and non-null.
MOZ_MUST_USE bool emitPushNotUndefinedOrNull();
// Emit a bytecode followed by an uint16 immediate operand stored in
// big-endian order.
MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand);