From 02ce432ff56ba2949da9afd01e92d2e1a842e9a5 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 9 May 2017 14:45:26 -0700 Subject: [PATCH] Bug 1357075 - Pad a nop to unwind to the scope just before a destructuring iterator close trynote. (r=arai) --- js/src/frontend/BytecodeEmitter.cpp | 8 ++++++++ js/src/jit-test/tests/parser/bug-1357075.js | 10 ++++++++++ js/src/vm/Interpreter.cpp | 5 ++++- js/src/vm/Opcodes.h | 11 ++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/parser/bug-1357075.js diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 6bb1014fbcbd..b866492a07fd 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5470,6 +5470,14 @@ BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth, In { MOZ_ASSERT(this->stackDepth >= iterDepth); + // Pad a nop at the beginning of the bytecode covered by the trynote so + // that when unwinding environments, we may unwind to the scope + // corresponding to the pc *before* the start, in case the first bytecode + // emitted by |emitter| is the start of an inner scope. See comment above + // UnwindEnvironmentToTryPc. + if (!emit1(JSOP_TRY_DESTRUCTURING_ITERCLOSE)) + return false; + ptrdiff_t start = offset(); if (!emitter(this)) return false; diff --git a/js/src/jit-test/tests/parser/bug-1357075.js b/js/src/jit-test/tests/parser/bug-1357075.js new file mode 100644 index 000000000000..47482e372b34 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1357075.js @@ -0,0 +1,10 @@ +// |jit-test| error: TypeError + +var iterable = {}; +var iterator = { + return: 1 +}; +iterable[Symbol.iterator] = function() { + return iterator; +}; +for ([ class get {} ().iterator ] of [iterable]) {} diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index ee196f8e0552..44741881140b 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1098,6 +1098,9 @@ js::UnwindEnvironmentToTryPc(JSScript* script, JSTryNote* tn) if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY) { pc -= JSOP_TRY_LENGTH; MOZ_ASSERT(*pc == JSOP_TRY); + } else if (tn->kind == JSTRY_DESTRUCTURING_ITERCLOSE) { + pc -= JSOP_TRY_DESTRUCTURING_ITERCLOSE_LENGTH; + MOZ_ASSERT(*pc == JSOP_TRY_DESTRUCTURING_ITERCLOSE); } return pc; } @@ -1938,7 +1941,7 @@ CASE(EnableInterruptsPseudoOpcode) /* Various 1-byte no-ops. */ CASE(JSOP_NOP) CASE(JSOP_NOP_DESTRUCTURING) -CASE(JSOP_UNUSED220) +CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE) CASE(JSOP_UNUSED221) CASE(JSOP_UNUSED222) CASE(JSOP_UNUSED223) diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 723bc35170bf..754f970a5636 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -2251,7 +2251,16 @@ * Stack: obj => obj */ \ macro(JSOP_CHECKISCALLABLE, 219, "checkiscallable", NULL, 2, 1, 1, JOF_UINT8) \ - macro(JSOP_UNUSED220, 220,"unused220", NULL, 1, 0, 0, JOF_BYTE) \ + \ + /* + * No-op used by the exception unwinder to determine the correct + * environment to unwind to when performing IteratorClose due to + * destructuring. + * Category: Other + * Operands: + * Stack: => + */ \ + macro(JSOP_TRY_DESTRUCTURING_ITERCLOSE, 220, "try-destructuring-iterclose", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED221, 221,"unused221", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED222, 222,"unused222", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED223, 223,"unused223", NULL, 1, 0, 0, JOF_BYTE) \