Attachment #8767828: (Plan A) Part 1: Throw if the value returned by iterator.next() is not an object. for bug #1016936

View | Details | Raw Unified | Return to bug 1016936
Collapse All | Expand All

(-)a/js/src/frontend/BytecodeEmitter.cpp (+10 lines)
Line     Link Here 
 Lines 452-467   BytecodeEmitter::emitDupAt(unsigned slot Link Here 
452
    if (!emitN(JSOP_DUPAT, 3, &off))
452
    if (!emitN(JSOP_DUPAT, 3, &off))
453
        return false;
453
        return false;
454
454
455
    jsbytecode* pc = code(off);
455
    jsbytecode* pc = code(off);
456
    SET_UINT24(pc, slotFromTop);
456
    SET_UINT24(pc, slotFromTop);
457
    return true;
457
    return true;
458
}
458
}
459
459
460
bool
461
BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
462
{
463
    return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
464
}
465
460
static const char*
466
static const char*
461
StatementName(StmtInfoBCE* stmt)
467
StatementName(StmtInfoBCE* stmt)
462
{
468
{
463
    if (!stmt)
469
    if (!stmt)
464
        return js_script_str;
470
        return js_script_str;
465
471
466
    /* XXX too many "... statement" L10N gaffes -- fix via js.msg! */
472
    /* XXX too many "... statement" L10N gaffes -- fix via js.msg! */
467
    static const char* const statementName[] = {
473
    static const char* const statementName[] = {
 Lines 4142-4157   BytecodeEmitter::emitIteratorNext(ParseN Link Here 
4142
    if (!emit1(JSOP_DUP))                                 // ... ITER ITER
4148
    if (!emit1(JSOP_DUP))                                 // ... ITER ITER
4143
        return false;
4149
        return false;
4144
    if (!emitAtomOp(cx->names().next, JSOP_CALLPROP))     // ... ITER NEXT
4150
    if (!emitAtomOp(cx->names().next, JSOP_CALLPROP))     // ... ITER NEXT
4145
        return false;
4151
        return false;
4146
    if (!emit1(JSOP_SWAP))                                // ... NEXT ITER
4152
    if (!emit1(JSOP_SWAP))                                // ... NEXT ITER
4147
        return false;
4153
        return false;
4148
    if (!emitCall(JSOP_CALL, 0, pn))                      // ... RESULT
4154
    if (!emitCall(JSOP_CALL, 0, pn))                      // ... RESULT
4149
        return false;
4155
        return false;
4156
    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
4157
        return false;
4150
    checkTypeSet(JSOP_CALL);
4158
    checkTypeSet(JSOP_CALL);
4151
    return true;
4159
    return true;
4152
}
4160
}
4153
4161
4154
bool
4162
bool
4155
BytecodeEmitter::emitDefault(ParseNode* defaultExpr)
4163
BytecodeEmitter::emitDefault(ParseNode* defaultExpr)
4156
{
4164
{
4157
    if (!emit1(JSOP_DUP))                                 // VALUE VALUE
4165
    if (!emit1(JSOP_DUP))                                 // VALUE VALUE
 Lines 7228-7243   BytecodeEmitter::emitYieldStar(ParseNode Link Here 
7228
    if (!emitAtomOp(cx->names().next, JSOP_CALLPROP))            // RECEIVED ITER ITER NEXT
7236
    if (!emitAtomOp(cx->names().next, JSOP_CALLPROP))            // RECEIVED ITER ITER NEXT
7229
        return false;
7237
        return false;
7230
    if (!emit1(JSOP_SWAP))                                       // RECEIVED ITER NEXT ITER
7238
    if (!emit1(JSOP_SWAP))                                       // RECEIVED ITER NEXT ITER
7231
        return false;
7239
        return false;
7232
    if (!emit2(JSOP_PICK, 3))                                    // ITER NEXT ITER RECEIVED
7240
    if (!emit2(JSOP_PICK, 3))                                    // ITER NEXT ITER RECEIVED
7233
        return false;
7241
        return false;
7234
    if (!emitCall(JSOP_CALL, 1, iter))                           // ITER RESULT
7242
    if (!emitCall(JSOP_CALL, 1, iter))                           // ITER RESULT
7235
        return false;
7243
        return false;
7244
    if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext))        // ITER RESULT
7245
        return false;
7236
    checkTypeSet(JSOP_CALL);
7246
    checkTypeSet(JSOP_CALL);
7237
    MOZ_ASSERT(this->stackDepth == depth);
7247
    MOZ_ASSERT(this->stackDepth == depth);
7238
7248
7239
    if (!emitJumpTargetAndPatch(checkResult))                    // checkResult:
7249
    if (!emitJumpTargetAndPatch(checkResult))                    // checkResult:
7240
        return false;
7250
        return false;
7241
7251
7242
    // if (!result.done) goto tryStart;                          // ITER RESULT
7252
    // if (!result.done) goto tryStart;                          // ITER RESULT
7243
    if (!emit1(JSOP_DUP))                                        // ITER RESULT RESULT
7253
    if (!emit1(JSOP_DUP))                                        // ITER RESULT RESULT
(-)a/js/src/frontend/BytecodeEmitter.h (+4 lines)
Line     Link Here 
 Lines 14-29    Link Here 
14
#include "jscntxt.h"
14
#include "jscntxt.h"
15
#include "jsopcode.h"
15
#include "jsopcode.h"
16
#include "jsscript.h"
16
#include "jsscript.h"
17
17
18
#include "frontend/ParseMaps.h"
18
#include "frontend/ParseMaps.h"
19
#include "frontend/Parser.h"
19
#include "frontend/Parser.h"
20
#include "frontend/SharedContext.h"
20
#include "frontend/SharedContext.h"
21
#include "frontend/SourceNotes.h"
21
#include "frontend/SourceNotes.h"
22
#include "vm/Interpreter.h"
22
23
23
namespace js {
24
namespace js {
24
25
25
class ScopeObject;
26
class ScopeObject;
26
27
27
namespace frontend {
28
namespace frontend {
28
29
29
class FullParseHandler;
30
class FullParseHandler;
 Lines 499-514   struct BytecodeEmitter Link Here 
499
500
500
    // Emit three bytecodes, an opcode with two bytes of immediate operands.
501
    // Emit three bytecodes, an opcode with two bytes of immediate operands.
501
    MOZ_MUST_USE bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
502
    MOZ_MUST_USE bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
502
503
503
    // Helper to emit JSOP_DUPAT. The argument is the value's depth on the
504
    // Helper to emit JSOP_DUPAT. The argument is the value's depth on the
504
    // JS stack, as measured from the top.
505
    // JS stack, as measured from the top.
505
    MOZ_MUST_USE bool emitDupAt(unsigned slotFromTop);
506
    MOZ_MUST_USE bool emitDupAt(unsigned slotFromTop);
506
507
508
    // Helper to emit JSOP_CHECKISOBJ.
509
    MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind);
510
507
    // Emit a bytecode followed by an uint16 immediate operand stored in
511
    // Emit a bytecode followed by an uint16 immediate operand stored in
508
    // big-endian order.
512
    // big-endian order.
509
    MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand);
513
    MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand);
510
514
511
    // Emit a bytecode followed by an uint32 immediate operand.
515
    // Emit a bytecode followed by an uint32 immediate operand.
512
    MOZ_MUST_USE bool emitUint32Operand(JSOp op, uint32_t operand);
516
    MOZ_MUST_USE bool emitUint32Operand(JSOp op, uint32_t operand);
513
517
514
    // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
518
    // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
(-)a/js/src/jsopcode.cpp (+2 lines)
Line     Link Here 
 Lines 1222-1237   ExpressionDecompiler::decompilePC(jsbyte Link Here 
1222
      case JSOP_NEWARRAY_COPYONWRITE: {
1222
      case JSOP_NEWARRAY_COPYONWRITE: {
1223
        JSObject* obj = script->getObject(GET_UINT32_INDEX(pc));
1223
        JSObject* obj = script->getObject(GET_UINT32_INDEX(pc));
1224
        RootedValue objv(cx, ObjectValue(*obj));
1224
        RootedValue objv(cx, ObjectValue(*obj));
1225
        JSString* str = ValueToSource(cx, objv);
1225
        JSString* str = ValueToSource(cx, objv);
1226
        if (!str)
1226
        if (!str)
1227
            return false;
1227
            return false;
1228
        return write(str);
1228
        return write(str);
1229
      }
1229
      }
1230
      case JSOP_CHECKISOBJ:
1231
        return decompilePCForStackOperand(pc, -1);
1230
      case JSOP_VOID:
1232
      case JSOP_VOID:
1231
        return write("void ") && decompilePCForStackOperand(pc, -1);
1233
        return write("void ") && decompilePCForStackOperand(pc, -1);
1232
      default:
1234
      default:
1233
        break;
1235
        break;
1234
    }
1236
    }
1235
    return write("(intermediate value)");
1237
    return write("(intermediate value)");
1236
}
1238
}
1237
1239
(-)a/js/src/vm/ForOfIterator.cpp (-3 / +3 lines)
Line     Link Here 
 Lines 130-149   ForOfIterator::next(MutableHandleValue v Link Here 
130
130
131
    RootedValue v(cx_);
131
    RootedValue v(cx_);
132
    if (!GetProperty(cx_, iterator, iterator, cx_->names().next, &v))
132
    if (!GetProperty(cx_, iterator, iterator, cx_->names().next, &v))
133
        return false;
133
        return false;
134
134
135
    if (!js::Call(cx_, v, iterator, &v))
135
    if (!js::Call(cx_, v, iterator, &v))
136
        return false;
136
        return false;
137
137
138
    RootedObject resultObj(cx_, ToObject(cx_, v));
138
    if (!v.isObject())
139
    if (!resultObj)
139
        return ThrowCheckIsObject(cx_, CheckIsObjectKind::IteratorNext);
140
        return false;
141
140
141
    RootedObject resultObj(cx_, &v.toObject());
142
    if (!GetProperty(cx_, resultObj, resultObj, cx_->names().done, &v))
142
    if (!GetProperty(cx_, resultObj, resultObj, cx_->names().done, &v))
143
        return false;
143
        return false;
144
144
145
    *done = ToBoolean(v);
145
    *done = ToBoolean(v);
146
    if (*done) {
146
    if (*done) {
147
        vp.setUndefined();
147
        vp.setUndefined();
148
        return true;
148
        return true;
149
    }
149
    }
(-)a/js/src/vm/Interpreter.cpp (-1 / +22 lines)
Line     Link Here 
 Lines 1820-1836   CASE(EnableInterruptsPseudoOpcode) Link Here 
1820
    /* Commence executing the actual opcode. */
1820
    /* Commence executing the actual opcode. */
1821
    SANITY_CHECKS();
1821
    SANITY_CHECKS();
1822
    DISPATCH_TO(op);
1822
    DISPATCH_TO(op);
1823
}
1823
}
1824
1824
1825
/* Various 1-byte no-ops. */
1825
/* Various 1-byte no-ops. */
1826
CASE(JSOP_NOP)
1826
CASE(JSOP_NOP)
1827
CASE(JSOP_NOP_DESTRUCTURING)
1827
CASE(JSOP_NOP_DESTRUCTURING)
1828
CASE(JSOP_UNUSED14)
1829
CASE(JSOP_UNUSED149)
1828
CASE(JSOP_UNUSED149)
1830
CASE(JSOP_UNUSED179)
1829
CASE(JSOP_UNUSED179)
1831
CASE(JSOP_UNUSED180)
1830
CASE(JSOP_UNUSED180)
1832
CASE(JSOP_UNUSED181)
1831
CASE(JSOP_UNUSED181)
1833
CASE(JSOP_UNUSED182)
1832
CASE(JSOP_UNUSED182)
1834
CASE(JSOP_UNUSED183)
1833
CASE(JSOP_UNUSED183)
1835
CASE(JSOP_UNUSED187)
1834
CASE(JSOP_UNUSED187)
1836
CASE(JSOP_UNUSED192)
1835
CASE(JSOP_UNUSED192)
 Lines 2551-2566   CASE(JSOP_GLOBALTHIS) Link Here 
2551
            goto error;
2550
            goto error;
2552
    } else {
2551
    } else {
2553
        ClonedBlockObject* lexicalScope = &cx->global()->lexicalScope();
2552
        ClonedBlockObject* lexicalScope = &cx->global()->lexicalScope();
2554
        PUSH_COPY(lexicalScope->thisValue());
2553
        PUSH_COPY(lexicalScope->thisValue());
2555
    }
2554
    }
2556
}
2555
}
2557
END_CASE(JSOP_GLOBALTHIS)
2556
END_CASE(JSOP_GLOBALTHIS)
2558
2557
2558
CASE(JSOP_CHECKISOBJ)
2559
{
2560
    if (!REGS.sp[-1].isObject()) {
2561
        MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
2562
        goto error;
2563
    }
2564
}
2565
END_CASE(JSOP_CHECKISOBJ)
2566
2559
CASE(JSOP_CHECKTHIS)
2567
CASE(JSOP_CHECKTHIS)
2560
{
2568
{
2561
    if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2569
    if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2562
        MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx, REGS.fp()));
2570
        MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx, REGS.fp()));
2563
        goto error;
2571
        goto error;
2564
    }
2572
    }
2565
}
2573
}
2566
END_CASE(JSOP_CHECKTHIS)
2574
END_CASE(JSOP_CHECKTHIS)
 Lines 4964-4979   js::ReportRuntimeRedeclaration(JSContext Link Here 
4964
        else
4972
        else
4965
            kindStr = frontend::Definition::kindString(declKind);
4973
            kindStr = frontend::Definition::kindString(declKind);
4966
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_REDECLARED_VAR,
4974
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_REDECLARED_VAR,
4967
                             kindStr, printable.ptr());
4975
                             kindStr, printable.ptr());
4968
    }
4976
    }
4969
}
4977
}
4970
4978
4971
bool
4979
bool
4980
js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
4981
{
4982
    switch (kind) {
4983
      case CheckIsObjectKind::IteratorNext:
4984
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEXT_RETURNED_PRIMITIVE);
4985
        break;
4986
      default:
4987
        MOZ_CRASH("Unknown kind");
4988
    }
4989
    return false;
4990
}
4991
4992
bool
4972
js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
4993
js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
4973
{
4994
{
4974
    RootedFunction fun(cx);
4995
    RootedFunction fun(cx);
4975
    if (frame.isFunctionFrame()) {
4996
    if (frame.isFunctionFrame()) {
4976
        fun = frame.callee();
4997
        fun = frame.callee();
4977
    } else {
4998
    } else {
4978
        MOZ_ASSERT(frame.isEvalFrame());
4999
        MOZ_ASSERT(frame.isEvalFrame());
4979
        MOZ_ASSERT(frame.script()->isDirectEvalInFunction());
5000
        MOZ_ASSERT(frame.script()->isDirectEvalInFunction());
(-)a/js/src/vm/Interpreter.h (+7 lines)
Line     Link Here 
 Lines 554-569   ReportRuntimeLexicalError(JSContext* cx, Link Here 
554
554
555
// The parser only reports redeclarations that occurs within a single
555
// The parser only reports redeclarations that occurs within a single
556
// script. Due to the extensibility of the global lexical scope, we also check
556
// script. Due to the extensibility of the global lexical scope, we also check
557
// for redeclarations during runtime in JSOP_DEF{VAR,LET,CONST}.
557
// for redeclarations during runtime in JSOP_DEF{VAR,LET,CONST}.
558
void
558
void
559
ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
559
ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
560
                           frontend::Definition::Kind declKind);
560
                           frontend::Definition::Kind declKind);
561
561
562
enum class CheckIsObjectKind : uint8_t {
563
    IteratorNext
564
};
565
566
bool
567
ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind);
568
562
bool
569
bool
563
ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
570
ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
564
571
565
bool
572
bool
566
DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
573
DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
567
574
568
bool
575
bool
569
Debug_CheckSelfHosted(JSContext* cx, HandleValue v);
576
Debug_CheckSelfHosted(JSContext* cx, HandleValue v);
(-)a/js/src/vm/Opcodes.h (-1 / +8 lines)
Line     Link Here 
 Lines 215-231   1234567890123456789012345678901234567890 Link Here 
215
     * Duplicates the top two values on the stack.
215
     * Duplicates the top two values on the stack.
216
     *   Category: Operators
216
     *   Category: Operators
217
     *   Type: Stack Operations
217
     *   Type: Stack Operations
218
     *   Operands:
218
     *   Operands:
219
     *   Stack: v1, v2 => v1, v2, v1, v2
219
     *   Stack: v1, v2 => v1, v2, v1, v2
220
     */ \
220
     */ \
221
    macro(JSOP_DUP2,      13, "dup2",       NULL,         1,  2,  4, JOF_BYTE) \
221
    macro(JSOP_DUP2,      13, "dup2",       NULL,         1,  2,  4, JOF_BYTE) \
222
    \
222
    \
223
    macro(JSOP_UNUSED14,  14, "unused14",   NULL,         1,  0,  0, JOF_BYTE) \
223
    /*
224
     * Check if the top value of the stack is an object, and throws if not.
225
     *   Category: Statements
226
     *   Type: Generator
227
     *   Operands: int8_t kind
228
     *   Stack: result => result
229
     */ \
230
    macro(JSOP_CHECKISOBJ,14, "checkisobj", NULL,         2,  1,  1, JOF_UINT8) \
224
    \
231
    \
225
    /*
232
    /*
226
     * Pops the top two values 'lval' and 'rval' from the stack, then pushes
233
     * Pops the top two values 'lval' and 'rval' from the stack, then pushes
227
     * the result of the operation applied to the two operands, converting
234
     * the result of the operation applied to the two operands, converting
228
     * both to 32-bit signed integers if necessary.
235
     * both to 32-bit signed integers if necessary.
229
     *   Category: Operators
236
     *   Category: Operators
230
     *   Type: Bitwise Logical Operators
237
     *   Type: Bitwise Logical Operators
231
     *   Operands:
238
     *   Operands:

Return to bug 1016936