Attachment #8476211: Rollup of parts 1-3 for fuzzing for bug #1001090

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

(-)a/js/public/Value.h (+2 lines)
Line     Link Here 
 Lines 238-253   typedef enum JSWhyMagic Link Here 
238
    JS_OPTIMIZED_ARGUMENTS,      /* optimized-away 'arguments' value */
238
    JS_OPTIMIZED_ARGUMENTS,      /* optimized-away 'arguments' value */
239
    JS_IS_CONSTRUCTING,          /* magic value passed to natives to indicate construction */
239
    JS_IS_CONSTRUCTING,          /* magic value passed to natives to indicate construction */
240
    JS_OVERWRITTEN_CALLEE,       /* arguments.callee has been overwritten */
240
    JS_OVERWRITTEN_CALLEE,       /* arguments.callee has been overwritten */
241
    JS_BLOCK_NEEDS_CLONE,        /* value of static block object slot */
241
    JS_BLOCK_NEEDS_CLONE,        /* value of static block object slot */
242
    JS_HASH_KEY_EMPTY,           /* see class js::HashableValue */
242
    JS_HASH_KEY_EMPTY,           /* see class js::HashableValue */
243
    JS_ION_ERROR,                /* error while running Ion code */
243
    JS_ION_ERROR,                /* error while running Ion code */
244
    JS_ION_BAILOUT,              /* missing recover instruction result */
244
    JS_ION_BAILOUT,              /* missing recover instruction result */
245
    JS_OPTIMIZED_OUT,            /* optimized out slot */
245
    JS_OPTIMIZED_OUT,            /* optimized out slot */
246
    JS_UNINITIALIZED_LET,        /* uninitialized let bindings that produce ReferenceError on
247
                                  * touch. */
246
    JS_GENERIC_MAGIC             /* for local use */
248
    JS_GENERIC_MAGIC             /* for local use */
247
} JSWhyMagic;
249
} JSWhyMagic;
248
250
249
#if defined(IS_LITTLE_ENDIAN)
251
#if defined(IS_LITTLE_ENDIAN)
250
# if defined(JS_NUNBOX32)
252
# if defined(JS_NUNBOX32)
251
typedef union jsval_layout
253
typedef union jsval_layout
252
{
254
{
253
    uint64_t asBits;
255
    uint64_t asBits;
(-)a/js/src/frontend/BytecodeCompiler.cpp (-10 / +12 lines)
Line     Link Here 
 Lines 286-302   frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco Link Here 
286
    // We can specialize a bit for the given scope chain if that scope chain is the global object.
286
    // We can specialize a bit for the given scope chain if that scope chain is the global object.
287
    JSObject *globalScope =
287
    JSObject *globalScope =
288
        scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : nullptr;
288
        scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : nullptr;
289
    JS_ASSERT_IF(globalScope, globalScope->isNative());
289
    JS_ASSERT_IF(globalScope, globalScope->isNative());
290
    JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
290
    JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
291
291
292
    BytecodeEmitter::EmitterMode emitterMode =
292
    BytecodeEmitter::EmitterMode emitterMode =
293
        options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
293
        options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
294
    BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, options.forEval,
294
    BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script,
295
                        /* lazyScript = */ js::NullPtr(), options.forEval,
295
                        evalCaller, !!globalScope, options.lineno, emitterMode);
296
                        evalCaller, !!globalScope, options.lineno, emitterMode);
296
    if (!bce.init())
297
    if (!bce.init())
297
        return nullptr;
298
        return nullptr;
298
299
299
    // Syntax parsing may cause us to restart processing of top level
300
    // Syntax parsing may cause us to restart processing of top level
300
    // statements in the script. Use Maybe<> so that the parse context can be
301
    // statements in the script. Use Maybe<> so that the parse context can be
301
    // reset when this occurs.
302
    // reset when this occurs.
302
    Maybe<ParseContext<FullParseHandler> > pc;
303
    Maybe<ParseContext<FullParseHandler> > pc;
 Lines 431-449   frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco Link Here 
431
    if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
432
    if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
432
        return nullptr;
433
        return nullptr;
433
434
434
    // Global/eval script bindings are always empty (all names are added to the
435
    // Global/eval script bindings are always empty (all names are added to the
435
    // scope dynamically via JSOP_DEFFUN/VAR).  They may have block-scoped
436
    // scope dynamically via JSOP_DEFFUN/VAR).  They may have block-scoped
436
    // locals, however, which are allocated to the fixed part of the stack
437
    // locals, however, which are allocated to the fixed part of the stack
437
    // frame.
438
    // frame.
438
    InternalHandle<Bindings*> bindings(script, &script->bindings);
439
    InternalHandle<Bindings*> bindings(script, &script->bindings);
439
    if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, nullptr,
440
    if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, 0,
440
                                            pc->blockScopeDepth))
441
                                            pc->blockScopeDepth, nullptr))
442
    {
441
        return nullptr;
443
        return nullptr;
444
    }
442
445
443
    if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
446
    if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
444
        return nullptr;
447
        return nullptr;
445
448
446
    // Note that this marking must happen before we tell Debugger
449
    // Note that this marking must happen before we tell Debugger
447
    // about the new script, in case Debugger delazifies the script's
450
    // about the new script, in case Debugger delazifies the script's
448
    // inner functions.
451
    // inner functions.
449
    if (options.forEval)
452
    if (options.forEval)
 Lines 504-528   frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const jsc Link Here 
504
507
505
    if (lazy->directlyInsideEval())
508
    if (lazy->directlyInsideEval())
506
        script->setDirectlyInsideEval();
509
        script->setDirectlyInsideEval();
507
    if (lazy->usesArgumentsAndApply())
510
    if (lazy->usesArgumentsAndApply())
508
        script->setUsesArgumentsAndApply();
511
        script->setUsesArgumentsAndApply();
509
    if (lazy->hasBeenCloned())
512
    if (lazy->hasBeenCloned())
510
        script->setHasBeenCloned();
513
        script->setHasBeenCloned();
511
514
512
    BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
515
    BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
513
                        /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
516
                        options.forEval, /* evalCaller = */ js::NullPtr(),
514
                        options.lineno, BytecodeEmitter::LazyFunction);
517
                        /* hasGlobalScope = */ true, options.lineno,
518
                        BytecodeEmitter::LazyFunction);
515
    if (!bce.init())
519
    if (!bce.init())
516
        return false;
520
        return false;
517
521
518
    if (lazy->treatAsRunOnce())
519
        bce.lazyRunOnceLambda = true;
520
521
    return EmitFunctionScript(cx, &bce, pn->pn_body);
522
    return EmitFunctionScript(cx, &bce, pn->pn_body);
522
}
523
}
523
524
524
// Compile a JS function body, which might appear as the value of an event
525
// Compile a JS function body, which might appear as the value of an event
525
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
526
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
526
static bool
527
static bool
527
CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
528
CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
528
                    const AutoNameVector &formals, SourceBufferHolder &srcBuf,
529
                    const AutoNameVector &formals, SourceBufferHolder &srcBuf,
 Lines 627-643   CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp Link Here 
627
        /*
628
        /*
628
         * The reason for checking fun->environment() below is that certain
629
         * The reason for checking fun->environment() below is that certain
629
         * consumers of JS::CompileFunction, namely
630
         * consumers of JS::CompileFunction, namely
630
         * EventListenerManager::CompileEventHandlerInternal, passes in a
631
         * EventListenerManager::CompileEventHandlerInternal, passes in a
631
         * nullptr environment. This compiled function is never used, but
632
         * nullptr environment. This compiled function is never used, but
632
         * instead is cloned immediately onto the right scope chain.
633
         * instead is cloned immediately onto the right scope chain.
633
         */
634
         */
634
        BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script,
635
        BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script,
635
                               /* insideEval = */ false, /* evalCaller = */ js::NullPtr(),
636
                               /* lazyScript = */ js::NullPtr(), /* insideEval = */ false,
637
                               /* evalCaller = */ js::NullPtr(),
636
                               fun->environment() && fun->environment()->is<GlobalObject>(),
638
                               fun->environment() && fun->environment()->is<GlobalObject>(),
637
                               options.lineno);
639
                               options.lineno);
638
        if (!funbce.init())
640
        if (!funbce.init())
639
            return false;
641
            return false;
640
642
641
        if (!EmitFunctionScript(cx, &funbce, fn->pn_body))
643
        if (!EmitFunctionScript(cx, &funbce, fn->pn_body))
642
            return false;
644
            return false;
643
    } else {
645
    } else {
(-)a/js/src/frontend/BytecodeEmitter.cpp (-117 / +265 lines)
Line     Link Here 
 Lines 105-125   struct LoopStmtInfo : public StmtInfoBCE Link Here 
105
        return static_cast<LoopStmtInfo*>(stmt);
105
        return static_cast<LoopStmtInfo*>(stmt);
106
    }
106
    }
107
};
107
};
108
108
109
} // anonymous namespace
109
} // anonymous namespace
110
110
111
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
111
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
112
                                 Parser<FullParseHandler> *parser, SharedContext *sc,
112
                                 Parser<FullParseHandler> *parser, SharedContext *sc,
113
                                 HandleScript script, bool insideEval, HandleScript evalCaller,
113
                                 HandleScript script, Handle<LazyScript *> lazyScript,
114
                                 bool insideEval, HandleScript evalCaller,
114
                                 bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode)
115
                                 bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode)
115
  : sc(sc),
116
  : sc(sc),
116
    parent(parent),
117
    parent(parent),
117
    script(sc->context, script),
118
    script(sc->context, script),
119
    lazyScript(sc->context, lazyScript),
118
    prolog(sc->context, lineNum),
120
    prolog(sc->context, lineNum),
119
    main(sc->context, lineNum),
121
    main(sc->context, lineNum),
120
    current(&main),
122
    current(&main),
121
    parser(parser),
123
    parser(parser),
122
    evalCaller(evalCaller),
124
    evalCaller(evalCaller),
123
    topStmt(nullptr),
125
    topStmt(nullptr),
124
    topScopeStmt(nullptr),
126
    topScopeStmt(nullptr),
125
    staticScope(sc->context),
127
    staticScope(sc->context),
 Lines 130-151   BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Link Here 
130
    emitLevel(0),
132
    emitLevel(0),
131
    constList(sc->context),
133
    constList(sc->context),
132
    tryNoteList(sc->context),
134
    tryNoteList(sc->context),
133
    blockScopeList(sc->context),
135
    blockScopeList(sc->context),
134
    typesetCount(0),
136
    typesetCount(0),
135
    hasSingletons(false),
137
    hasSingletons(false),
136
    emittingForInit(false),
138
    emittingForInit(false),
137
    emittingRunOnceLambda(false),
139
    emittingRunOnceLambda(false),
138
    lazyRunOnceLambda(false),
139
    insideEval(insideEval),
140
    insideEval(insideEval),
140
    hasGlobalScope(hasGlobalScope),
141
    hasGlobalScope(hasGlobalScope),
141
    emitterMode(emitterMode)
142
    emitterMode(emitterMode)
142
{
143
{
143
    JS_ASSERT_IF(evalCaller, insideEval);
144
    JS_ASSERT_IF(evalCaller, insideEval);
145
    JS_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
144
}
146
}
145
147
146
bool
148
bool
147
BytecodeEmitter::init()
149
BytecodeEmitter::init()
148
{
150
{
149
    return atomIndices.ensureMap(sc->context);
151
    return atomIndices.ensureMap(sc->context);
150
}
152
}
151
153
 Lines 218-234   frontend::Emit2(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode Link Here 
218
    code[0] = jsbytecode(op);
220
    code[0] = jsbytecode(op);
219
    code[1] = op1;
221
    code[1] = op1;
220
    UpdateDepth(cx, bce, offset);
222
    UpdateDepth(cx, bce, offset);
221
    return offset;
223
    return offset;
222
}
224
}
223
225
224
ptrdiff_t
226
ptrdiff_t
225
frontend::Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
227
frontend::Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
226
                    jsbytecode op2)
228
                jsbytecode op2)
227
{
229
{
228
    /* These should filter through EmitVarOp. */
230
    /* These should filter through EmitVarOp. */
229
    JS_ASSERT(!IsArgOp(op));
231
    JS_ASSERT(!IsArgOp(op));
230
    JS_ASSERT(!IsLocalOp(op));
232
    JS_ASSERT(!IsLocalOp(op));
231
233
232
    ptrdiff_t offset = EmitCheck(cx, bce, 3);
234
    ptrdiff_t offset = EmitCheck(cx, bce, 3);
233
    if (offset < 0)
235
    if (offset < 0)
234
        return -1;
236
        return -1;
 Lines 794-825   EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit Link Here 
794
796
795
// In a function, block-scoped locals go after the vars, and form part of the
797
// In a function, block-scoped locals go after the vars, and form part of the
796
// fixed part of a stack frame.  Outside a function, there are no fixed vars,
798
// fixed part of a stack frame.  Outside a function, there are no fixed vars,
797
// but block-scoped locals still form part of the fixed part of a stack frame
799
// but block-scoped locals still form part of the fixed part of a stack frame
798
// and are thus addressable via GETLOCAL and friends.
800
// and are thus addressable via GETLOCAL and friends.
799
static void
801
static void
800
ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
802
ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
801
{
803
{
802
    unsigned nfixedvars = bce->sc->isFunctionBox() ? bce->script->bindings.numVars() : 0;
804
    unsigned nbodyfixed = bce->sc->isFunctionBox() ? bce->script->bindings.numBodyLevelLocals() : 0;
803
    unsigned localOffset = nfixedvars;
805
    unsigned localOffset = nbodyfixed;
804
806
805
    if (bce->staticScope) {
807
    if (bce->staticScope) {
806
        Rooted<NestedScopeObject *> outer(cx, bce->staticScope);
808
        Rooted<NestedScopeObject *> outer(cx, bce->staticScope);
807
        for (; outer; outer = outer->enclosingNestedScope()) {
809
        for (; outer; outer = outer->enclosingNestedScope()) {
808
            if (outer->is<StaticBlockObject>()) {
810
            if (outer->is<StaticBlockObject>()) {
809
                StaticBlockObject &outerBlock = outer->as<StaticBlockObject>();
811
                StaticBlockObject &outerBlock = outer->as<StaticBlockObject>();
810
                localOffset = outerBlock.localOffset() + outerBlock.numVariables();
812
                localOffset = outerBlock.localOffset() + outerBlock.numVariables();
811
                break;
813
                break;
812
            }
814
            }
813
        }
815
        }
814
    }
816
    }
815
817
816
    JS_ASSERT(localOffset + blockObj->numVariables()
818
    JS_ASSERT(localOffset + blockObj->numVariables()
817
              <= nfixedvars + bce->script->bindings.numBlockScoped());
819
              <= nbodyfixed + bce->script->bindings.numBlockScoped());
818
820
819
    blockObj->setLocalOffset(localOffset);
821
    blockObj->setLocalOffset(localOffset);
820
}
822
}
821
823
822
// ~ Nested Scopes ~
824
// ~ Nested Scopes ~
823
//
825
//
824
// A nested scope is a region of a compilation unit (function, script, or eval
826
// A nested scope is a region of a compilation unit (function, script, or eval
825
// code) with an additional node on the scope chain.  This node may either be a
827
// code) with an additional node on the scope chain.  This node may either be a
 Lines 1056-1095   EmitRegExp(ExclusiveContext *cx, uint32_t index, BytecodeEmitter *bce) Link Here 
1056
/*
1058
/*
1057
 * To catch accidental misuse, EMIT_UINT16_IMM_OP/Emit3 assert that they are
1059
 * To catch accidental misuse, EMIT_UINT16_IMM_OP/Emit3 assert that they are
1058
 * not used to unconditionally emit JSOP_GETLOCAL. Variable access should
1060
 * not used to unconditionally emit JSOP_GETLOCAL. Variable access should
1059
 * instead be emitted using EmitVarOp. In special cases, when the caller
1061
 * instead be emitted using EmitVarOp. In special cases, when the caller
1060
 * definitely knows that a given local slot is unaliased, this function may be
1062
 * definitely knows that a given local slot is unaliased, this function may be
1061
 * used as a non-asserting version of EMIT_UINT16_IMM_OP.
1063
 * used as a non-asserting version of EMIT_UINT16_IMM_OP.
1062
 */
1064
 */
1063
static bool
1065
static bool
1064
EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, BytecodeEmitter *bce)
1066
EmitLocalOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, uint32_t slot)
1067
{
1068
    JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
1069
    JS_ASSERT(IsLocalOp(op));
1070
1071
    ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN);
1072
    if (off < 0)
1073
        return false;
1074
1075
    SET_LOCALNO(bce->code(off), slot);
1076
    return true;
1077
}
1078
1079
static bool
1080
EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, bool checkUninitializedLet,
1081
                   BytecodeEmitter *bce)
1065
{
1082
{
1066
    JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
1083
    JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
1067
1084
1068
    if (IsLocalOp(op)) {
1085
    if (IsLocalOp(op)) {
1069
        ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN);
1086
        if (checkUninitializedLet) {
1070
        if (off < 0)
1087
            MOZ_ASSERT(op != JSOP_INITLET);
1071
            return false;
1088
            if (!EmitLocalOp(cx, bce, JSOP_CHECKLET, slot))
1089
                return false;
1090
        }
1072
1091
1073
        SET_LOCALNO(bce->code(off), slot);
1092
        return EmitLocalOp(cx, bce, op, slot);
1074
        return true;
1075
    }
1093
    }
1076
1094
1077
    JS_ASSERT(IsArgOp(op));
1095
    JS_ASSERT(IsArgOp(op));
1078
    ptrdiff_t off = EmitN(cx, bce, op, ARGNO_LEN);
1096
    ptrdiff_t off = EmitN(cx, bce, op, ARGNO_LEN);
1079
    if (off < 0)
1097
    if (off < 0)
1080
        return false;
1098
        return false;
1081
1099
1082
    SET_ARGNO(bce->code(off), slot);
1100
    SET_ARGNO(bce->code(off), slot);
1083
    return true;
1101
    return true;
1084
}
1102
}
1085
1103
1086
static bool
1104
static bool
1087
EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce)
1105
EmitScopeCoordOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, ScopeCoordinate sc)
1088
{
1106
{
1089
    JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
1107
    JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
1090
1108
1091
    unsigned n = SCOPECOORD_HOPS_LEN + SCOPECOORD_SLOT_LEN;
1109
    unsigned n = SCOPECOORD_HOPS_LEN + SCOPECOORD_SLOT_LEN;
1092
    JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length);
1110
    JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length);
1093
1111
1094
    ptrdiff_t off = EmitN(cx, bce, op, n);
1112
    ptrdiff_t off = EmitN(cx, bce, op, n);
1095
    if (off < 0)
1113
    if (off < 0)
 Lines 1099-1153   EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmit Link Here 
1099
    SET_SCOPECOORD_HOPS(pc, sc.hops());
1117
    SET_SCOPECOORD_HOPS(pc, sc.hops());
1100
    pc += SCOPECOORD_HOPS_LEN;
1118
    pc += SCOPECOORD_HOPS_LEN;
1101
    SET_SCOPECOORD_SLOT(pc, sc.slot());
1119
    SET_SCOPECOORD_SLOT(pc, sc.slot());
1102
    pc += SCOPECOORD_SLOT_LEN;
1120
    pc += SCOPECOORD_SLOT_LEN;
1103
    CheckTypeSet(cx, bce, op);
1121
    CheckTypeSet(cx, bce, op);
1104
    return true;
1122
    return true;
1105
}
1123
}
1106
1124
1125
static bool
1126
EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, bool checkUninitializedLet,
1127
                 BytecodeEmitter *bce)
1128
{
1129
    if (checkUninitializedLet) {
1130
        MOZ_ASSERT(op != JSOP_INITALIASEDLET);
1131
        if (!EmitScopeCoordOp(cx, bce, JSOP_CHECKALIASEDLET, sc))
1132
            return false;
1133
    }
1134
1135
    return EmitScopeCoordOp(cx, bce, op, sc);
1136
}
1137
1107
// Compute the number of nested scope objects that will actually be on the scope
1138
// Compute the number of nested scope objects that will actually be on the scope
1108
// chain at runtime, given the BCE's current staticScope.
1139
// chain at runtime, given the BCE's current staticScope.
1109
static unsigned
1140
static unsigned
1110
DynamicNestedScopeDepth(BytecodeEmitter *bce)
1141
DynamicNestedScopeDepth(BytecodeEmitter *bce)
1111
{
1142
{
1112
    unsigned depth = 0;
1143
    unsigned depth = 0;
1113
    for (NestedScopeObject *b = bce->staticScope; b; b = b->enclosingNestedScope()) {
1144
    for (NestedScopeObject *b = bce->staticScope; b; b = b->enclosingNestedScope()) {
1114
        if (!b->is<StaticBlockObject>() || b->as<StaticBlockObject>().needsClone())
1145
        if (!b->is<StaticBlockObject>() || b->as<StaticBlockObject>().needsClone())
1115
            ++depth;
1146
            ++depth;
1116
    }
1147
    }
1117
1148
1118
    return depth;
1149
    return depth;
1119
}
1150
}
1120
1151
1121
static bool
1152
static bool
1122
LookupAliasedName(HandleScript script, PropertyName *name, uint32_t *pslot)
1153
LookupAliasedName(BytecodeEmitter *bce, HandleScript script, PropertyName *name, uint32_t *pslot,
1154
                  ParseNode *pn = nullptr)
1123
{
1155
{
1124
    /*
1156
    /*
1125
     * Beware: BindingIter may contain more than one Binding for a given name
1157
     * Beware: BindingIter may contain more than one Binding for a given name
1126
     * (in the case of |function f(x,x) {}|) but only one will be aliased.
1158
     * (in the case of |function f(x,x) {}|) but only one will be aliased.
1127
     */
1159
     */
1160
    uint32_t bindingIndex = 0;
1128
    uint32_t slot = CallObject::RESERVED_SLOTS;
1161
    uint32_t slot = CallObject::RESERVED_SLOTS;
1129
    for (BindingIter bi(script); !bi.done(); bi++) {
1162
    for (BindingIter bi(script); !bi.done(); bi++) {
1130
        if (bi->aliased()) {
1163
        if (bi->aliased()) {
1131
            if (bi->name() == name) {
1164
            if (bi->name() == name) {
1165
                // Check if the free variable from a lazy script was marked as
1166
                // a possible hoisted use and is a let. If so, mark it as such
1167
                // so we emit a dead zone check.
1168
                if (bce->emitterMode == BytecodeEmitter::LazyFunction) {
1169
                    LazyScript::FreeVariable *freeVariables = bce->lazyScript->freeVariables();
1170
                    uint32_t letBegin = script->bindings.numArgs() + script->bindings.numVars();
1171
                    for (uint32_t i = 0; i < bce->lazyScript->numFreeVariables(); i++) {
1172
                        if (freeVariables[i].atom() == name) {
1173
                            if (freeVariables[i].isHoistedUse() && bindingIndex >= letBegin) {
1174
                                MOZ_ASSERT(pn);
1175
                                MOZ_ASSERT(pn->isUsed());
1176
                                pn->pn_dflags |= PND_LET;
1177
                            }
1178
1179
                            break;
1180
                        }
1181
                    }
1182
                }
1183
1132
                *pslot = slot;
1184
                *pslot = slot;
1133
                return true;
1185
                return true;
1134
            }
1186
            }
1135
            slot++;
1187
            slot++;
1136
        }
1188
        }
1189
        bindingIndex++;
1137
    }
1190
    }
1138
    return false;
1191
    return false;
1139
}
1192
}
1140
1193
1141
static bool
1194
static bool
1142
LookupAliasedNameSlot(HandleScript script, PropertyName *name, ScopeCoordinate *sc)
1195
LookupAliasedNameSlot(BytecodeEmitter *bce, HandleScript script, PropertyName *name,
1196
                      ScopeCoordinate *sc)
1143
{
1197
{
1144
    uint32_t slot;
1198
    uint32_t slot;
1145
    if (!LookupAliasedName(script, name, &slot))
1199
    if (!LookupAliasedName(bce, script, name, &slot))
1146
        return false;
1200
        return false;
1147
1201
1148
    sc->setSlot(slot);
1202
    sc->setSlot(slot);
1149
    return true;
1203
    return true;
1150
}
1204
}
1151
1205
1152
/*
1206
/*
1153
 * Use this function instead of assigning directly to 'hops' to guard for
1207
 * Use this function instead of assigning directly to 'hops' to guard for
 Lines 1206-1272   EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter * Link Here 
1206
     * and so includes the full DynamicNestedScopeDepth. A let/catch-binding
1260
     * and so includes the full DynamicNestedScopeDepth. A let/catch-binding
1207
     * requires a search of the block chain to see how many (dynamic) block
1261
     * requires a search of the block chain to see how many (dynamic) block
1208
     * objects to skip.
1262
     * objects to skip.
1209
     */
1263
     */
1210
    ScopeCoordinate sc;
1264
    ScopeCoordinate sc;
1211
    if (IsArgOp(pn->getOp())) {
1265
    if (IsArgOp(pn->getOp())) {
1212
        if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
1266
        if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
1213
            return false;
1267
            return false;
1214
        JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
1268
        JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc));
1215
    } else {
1269
    } else {
1216
        JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION));
1270
        JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION));
1217
        uint32_t local = pn->pn_cookie.slot();
1271
        uint32_t local = pn->pn_cookie.slot();
1218
        if (local < bceOfDef->script->bindings.numVars()) {
1272
        if (local < bceOfDef->script->bindings.numBodyLevelLocals()) {
1219
            if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
1273
            if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
1220
                return false;
1274
                return false;
1221
            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
1275
            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc));
1222
        } else {
1276
        } else {
1223
            JS_ASSERT_IF(bce->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals());
1277
            JS_ASSERT_IF(bce->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals());
1224
            JS_ASSERT(bceOfDef->staticScope->is<StaticBlockObject>());
1278
            JS_ASSERT(bceOfDef->staticScope->is<StaticBlockObject>());
1225
            Rooted<StaticBlockObject*> b(cx, &bceOfDef->staticScope->as<StaticBlockObject>());
1279
            Rooted<StaticBlockObject*> b(cx, &bceOfDef->staticScope->as<StaticBlockObject>());
1226
            while (local < b->localOffset()) {
1280
            while (local < b->localOffset()) {
1227
                if (b->needsClone())
1281
                if (b->needsClone())
1228
                    skippedScopes++;
1282
                    skippedScopes++;
1229
                b = &b->enclosingNestedScope()->as<StaticBlockObject>();
1283
                b = &b->enclosingNestedScope()->as<StaticBlockObject>();
1230
            }
1284
            }
1231
            if (!AssignHops(bce, pn, skippedScopes, &sc))
1285
            if (!AssignHops(bce, pn, skippedScopes, &sc))
1232
                return false;
1286
                return false;
1233
            sc.setSlot(b->localIndexToSlot(local));
1287
            sc.setSlot(b->localIndexToSlot(local));
1234
        }
1288
        }
1235
    }
1289
    }
1236
1290
1237
    return EmitAliasedVarOp(cx, op, sc, bce);
1291
    return EmitAliasedVarOp(cx, op, sc, pn->isHoistedLetUse(), bce);
1238
}
1292
}
1239
1293
1240
static bool
1294
static bool
1241
EmitVarOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
1295
EmitVarOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
1242
{
1296
{
1243
    JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
1297
    JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
1244
    JS_ASSERT(!pn->pn_cookie.isFree());
1298
    JS_ASSERT(!pn->pn_cookie.isFree());
1245
1299
1246
    if (IsAliasedVarOp(op)) {
1300
    if (IsAliasedVarOp(op)) {
1247
        ScopeCoordinate sc;
1301
        ScopeCoordinate sc;
1248
        sc.setHops(pn->pn_cookie.level());
1302
        sc.setHops(pn->pn_cookie.level());
1249
        sc.setSlot(pn->pn_cookie.slot());
1303
        sc.setSlot(pn->pn_cookie.slot());
1250
        return EmitAliasedVarOp(cx, op, sc, bce);
1304
        return EmitAliasedVarOp(cx, op, sc, pn->isHoistedLetUse(), bce);
1251
    }
1305
    }
1252
1306
1253
    JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op));
1307
    JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op));
1254
1308
1255
    if (!bce->isAliasedName(pn)) {
1309
    if (!bce->isAliasedName(pn)) {
1256
        JS_ASSERT(pn->isUsed() || pn->isDefn());
1310
        JS_ASSERT(pn->isUsed() || pn->isDefn());
1257
        JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0);
1311
        JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0);
1258
        JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel());
1312
        JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel());
1259
        return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce);
1313
        return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), pn->isHoistedLetUse(), bce);
1260
    }
1314
    }
1261
1315
1262
    switch (op) {
1316
    switch (op) {
1263
      case JSOP_GETARG: case JSOP_GETLOCAL: op = JSOP_GETALIASEDVAR; break;
1317
      case JSOP_GETARG: case JSOP_GETLOCAL: op = JSOP_GETALIASEDVAR; break;
1264
      case JSOP_SETARG: case JSOP_SETLOCAL: op = JSOP_SETALIASEDVAR; break;
1318
      case JSOP_SETARG: case JSOP_SETLOCAL: op = JSOP_SETALIASEDVAR; break;
1319
      case JSOP_INITLET: op = JSOP_INITALIASEDLET; break;
1265
      default: MOZ_CRASH("unexpected var op");
1320
      default: MOZ_CRASH("unexpected var op");
1266
    }
1321
    }
1267
1322
1268
    return EmitAliasedVarOp(cx, op, pn, bce);
1323
    return EmitAliasedVarOp(cx, op, pn, bce);
1269
}
1324
}
1270
1325
1271
static JSOp
1326
static JSOp
1272
GetIncDecInfo(ParseNodeKind kind, bool *post)
1327
GetIncDecInfo(ParseNodeKind kind, bool *post)
 Lines 1430-1452   TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) Link Here 
1430
                    hops++;
1485
                    hops++;
1431
                continue;
1486
                continue;
1432
            }
1487
            }
1433
            RootedScript script(bce->sc->context, ssi.funScript());
1488
            RootedScript script(bce->sc->context, ssi.funScript());
1434
            if (script->functionNonDelazifying()->atom() == pn->pn_atom)
1489
            if (script->functionNonDelazifying()->atom() == pn->pn_atom)
1435
                return false;
1490
                return false;
1436
            if (ssi.hasDynamicScopeObject()) {
1491
            if (ssi.hasDynamicScopeObject()) {
1437
                uint32_t slot;
1492
                uint32_t slot;
1438
                if (LookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot)) {
1493
                if (LookupAliasedName(bce, script, pn->pn_atom->asPropertyName(), &slot, pn)) {
1439
                    JSOp op;
1494
                    JSOp op;
1440
                    switch (pn->getOp()) {
1495
                    switch (pn->getOp()) {
1441
                      case JSOP_NAME:     op = JSOP_GETALIASEDVAR; break;
1496
                      case JSOP_NAME:    op = JSOP_GETALIASEDVAR; break;
1442
                      case JSOP_SETNAME:  op = JSOP_SETALIASEDVAR; break;
1497
                      case JSOP_SETNAME: op = JSOP_SETALIASEDVAR; break;
1443
                      default: return false;
1498
                      default: return false;
1444
                    }
1499
                    }
1500
1445
                    pn->setOp(op);
1501
                    pn->setOp(op);
1446
                    JS_ALWAYS_TRUE(pn->pn_cookie.set(bce->parser->tokenStream, hops, slot));
1502
                    JS_ALWAYS_TRUE(pn->pn_cookie.set(bce->parser->tokenStream, hops, slot));
1447
                    return true;
1503
                    return true;
1448
                }
1504
                }
1449
                hops++;
1505
                hops++;
1450
            }
1506
            }
1451
1507
1452
            if (script->funHasExtensibleScope() || script->directlyInsideEval())
1508
            if (script->funHasExtensibleScope() || script->directlyInsideEval())
 Lines 2470-2518   PushUndefinedValues(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned n) Link Here 
2470
        if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
2526
        if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
2471
            return false;
2527
            return false;
2472
    }
2528
    }
2473
    return true;
2529
    return true;
2474
}
2530
}
2475
2531
2476
static bool
2532
static bool
2477
InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce,
2533
InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce,
2478
                                     Handle<StaticBlockObject *> blockObj)
2534
                                     Handle<StaticBlockObject *> blockObj,
2535
                                     uint32_t valuesPushed)
2479
{
2536
{
2480
    for (unsigned i = blockObj->numVariables(); i > 0; --i) {
2537
    for (unsigned i = valuesPushed; i > 0; --i) {
2481
        if (blockObj->isAliased(i - 1)) {
2538
        if (blockObj->isAliased(i - 1)) {
2482
            ScopeCoordinate sc;
2539
            ScopeCoordinate sc;
2483
            sc.setHops(0);
2540
            sc.setHops(0);
2484
            sc.setSlot(BlockObject::RESERVED_SLOTS + i - 1);
2541
            sc.setSlot(BlockObject::RESERVED_SLOTS + i - 1);
2485
            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
2542
            if (!EmitAliasedVarOp(cx, JSOP_INITALIASEDLET, sc,
2543
                                  /* checkUninitializedLet = */ false, bce))
2544
            {
2486
                return false;
2545
                return false;
2546
            }
2487
        } else {
2547
        } else {
2488
            unsigned local = blockObj->blockIndexToLocalIndex(i - 1);
2548
            unsigned local = blockObj->blockIndexToLocalIndex(i - 1);
2489
            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, local, bce))
2549
            if (!EmitUnaliasedVarOp(cx, JSOP_INITLET, local,
2550
                                    /* checkUninitializedLet = */ false, bce))
2551
            {
2490
                return false;
2552
                return false;
2553
            }
2491
        }
2554
        }
2492
        if (Emit1(cx, bce, JSOP_POP) < 0)
2555
        if (Emit1(cx, bce, JSOP_POP) < 0)
2493
            return false;
2556
            return false;
2494
    }
2557
    }
2495
    return true;
2558
    return true;
2496
}
2559
}
2497
2560
2498
static bool
2561
static bool
2499
EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmtInfo,
2562
EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmtInfo,
2500
                ObjectBox *objbox, unsigned alreadyPushed = 0)
2563
                ObjectBox *objbox, unsigned valuesPushed = 0)
2501
{
2564
{
2502
    // Initial values for block-scoped locals.
2503
    Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
2565
    Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
2504
    if (!PushUndefinedValues(cx, bce, blockObj->numVariables() - alreadyPushed))
2505
        return false;
2506
2507
    if (!EnterNestedScope(cx, bce, stmtInfo, objbox, STMT_BLOCK))
2566
    if (!EnterNestedScope(cx, bce, stmtInfo, objbox, STMT_BLOCK))
2508
        return false;
2567
        return false;
2509
2568
2510
    if (!InitializeBlockScopedLocalsFromStack(cx, bce, blockObj))
2569
    if (!InitializeBlockScopedLocalsFromStack(cx, bce, blockObj, valuesPushed))
2570
        return false;
2571
2572
    return true;
2573
}
2574
2575
static bool
2576
EnterBlockScopeWithUndefined(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmtInfo,
2577
                             ObjectBox *objbox, unsigned alreadyPushed = 0)
2578
{
2579
    // Initial values for block-scoped locals.
2580
    Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
2581
    unsigned undefinedsPushed = blockObj->numVariables() - alreadyPushed;
2582
    if (!PushUndefinedValues(cx, bce, undefinedsPushed))
2583
        return false;
2584
2585
    if (!EnterBlockScope(cx, bce, stmtInfo, objbox, undefinedsPushed))
2511
        return false;
2586
        return false;
2512
2587
2513
    return true;
2588
    return true;
2514
}
2589
}
2515
2590
2516
/*
2591
/*
2517
 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
2592
 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
2518
 * LLVM is deciding to inline this function which uses a lot of stack space
2593
 * LLVM is deciding to inline this function which uses a lot of stack space
 Lines 2842-2859   EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) Link Here 
2842
2917
2843
bool
2918
bool
2844
BytecodeEmitter::isRunOnceLambda()
2919
BytecodeEmitter::isRunOnceLambda()
2845
{
2920
{
2846
    // The run once lambda flags set by the parser are approximate, and we look
2921
    // The run once lambda flags set by the parser are approximate, and we look
2847
    // at properties of the function itself before deciding to emit a function
2922
    // at properties of the function itself before deciding to emit a function
2848
    // as a run once lambda.
2923
    // as a run once lambda.
2849
2924
2850
    if (!(parent && parent->emittingRunOnceLambda) && !lazyRunOnceLambda)
2925
    if (!(parent && parent->emittingRunOnceLambda) &&
2926
        (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce()))
2927
    {
2851
        return false;
2928
        return false;
2929
    }
2852
2930
2853
    FunctionBox *funbox = sc->asFunctionBox();
2931
    FunctionBox *funbox = sc->asFunctionBox();
2854
    return !funbox->argumentsHasLocalBinding() &&
2932
    return !funbox->argumentsHasLocalBinding() &&
2855
           !funbox->isGenerator() &&
2933
           !funbox->isGenerator() &&
2856
           !funbox->function()->name();
2934
           !funbox->function()->name();
2857
}
2935
}
2858
2936
2859
bool
2937
bool
 Lines 2872-2892   frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo Link Here 
2872
        bce->switchToProlog();
2950
        bce->switchToProlog();
2873
        if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
2951
        if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
2874
            return false;
2952
            return false;
2875
        InternalBindingsHandle bindings(bce->script, &bce->script->bindings);
2953
        InternalBindingsHandle bindings(bce->script, &bce->script->bindings);
2876
        uint32_t varIndex = Bindings::argumentsVarIndex(cx, bindings);
2954
        uint32_t varIndex = Bindings::argumentsVarIndex(cx, bindings);
2877
        if (bce->script->varIsAliased(varIndex)) {
2955
        if (bce->script->varIsAliased(varIndex)) {
2878
            ScopeCoordinate sc;
2956
            ScopeCoordinate sc;
2879
            sc.setHops(0);
2957
            sc.setHops(0);
2880
            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce->script, cx->names().arguments, &sc));
2958
            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().arguments, &sc));
2881
            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
2959
            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc,
2960
                                  /* checkUninitializedLet = */ false, bce))
2961
            {
2882
                return false;
2962
                return false;
2963
            }
2883
        } else {
2964
        } else {
2884
            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, bce))
2965
            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex,
2966
                                    /* checkUninitializedLet = */ false, bce))
2885
                return false;
2967
                return false;
2886
        }
2968
        }
2887
        if (Emit1(cx, bce, JSOP_POP) < 0)
2969
        if (Emit1(cx, bce, JSOP_POP) < 0)
2888
            return false;
2970
            return false;
2889
        bce->switchToMain();
2971
        bce->switchToMain();
2890
    }
2972
    }
2891
2973
2892
    if (funbox->isGenerator()) {
2974
    if (funbox->isGenerator()) {
 Lines 3002-3055   enum VarEmitOption Link Here 
3002
    DefineVars        = 0,
3084
    DefineVars        = 0,
3003
    PushInitialValues = 1,
3085
    PushInitialValues = 1,
3004
    InitializeVars    = 2
3086
    InitializeVars    = 2
3005
};
3087
};
3006
3088
3007
typedef bool
3089
typedef bool
3008
(*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
3090
(*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
3009
3091
3092
template <DestructuringDeclEmitter EmitName>
3010
static bool
3093
static bool
3011
EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
3094
EmitDestructuringDeclsWithEmitter(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
3012
{
3095
                                  ParseNode *pattern)
3013
    JS_ASSERT(pn->isKind(PNK_NAME));
3014
    if (!BindNameToSlot(cx, bce, pn))
3015
        return false;
3016
3017
    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
3018
    return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr);
3019
}
3020
3021
static bool
3022
EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
3023
                       ParseNode *pattern)
3024
{
3096
{
3025
    if (pattern->isKind(PNK_ARRAY)) {
3097
    if (pattern->isKind(PNK_ARRAY)) {
3026
        for (ParseNode *element = pattern->pn_head; element; element = element->pn_next) {
3098
        for (ParseNode *element = pattern->pn_head; element; element = element->pn_next) {
3027
            if (element->isKind(PNK_ELISION))
3099
            if (element->isKind(PNK_ELISION))
3028
                continue;
3100
                continue;
3029
            DestructuringDeclEmitter emitter =
3101
3030
                element->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
3102
            if (element->isKind(PNK_NAME)) {
3031
            if (!emitter(cx, bce, prologOp, element))
3103
                if (!EmitName(cx, bce, prologOp, element))
3032
                return false;
3104
                    return false;
3105
            } else {
3106
                if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, element))
3107
                    return false;
3108
            }
3033
        }
3109
        }
3034
        return true;
3110
        return true;
3035
    }
3111
    }
3036
3112
3037
    MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
3113
    MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
3038
    for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) {
3114
    for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) {
3039
        ParseNode *target = member->pn_right;
3115
        ParseNode *target = member->pn_right;
3040
        DestructuringDeclEmitter emitter =
3116
3041
            target->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
3117
        if (target->isKind(PNK_NAME)) {
3042
        if (!emitter(cx, bce, prologOp, target))
3118
            if (!EmitName(cx, bce, prologOp, target))
3043
            return false;
3119
                return false;
3120
        } else {
3121
            if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, target))
3122
                return false;
3123
        }
3044
    }
3124
    }
3045
    return true;
3125
    return true;
3046
}
3126
}
3047
3127
3128
bool
3129
EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
3130
{
3131
    JS_ASSERT(pn->isKind(PNK_NAME));
3132
    if (!BindNameToSlot(cx, bce, pn))
3133
        return false;
3134
3135
    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
3136
    return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr);
3137
}
3138
3139
static inline bool
3140
EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
3141
                       ParseNode *pattern)
3142
{
3143
    return EmitDestructuringDeclsWithEmitter<EmitDestructuringDecl>(cx, bce, prologOp, pattern);
3144
}
3145
3146
bool
3147
EmitInitializeDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
3148
                                ParseNode *pn)
3149
{
3150
    MOZ_ASSERT(pn->isKind(PNK_NAME));
3151
    MOZ_ASSERT(pn->isBound());
3152
    return EmitVarOp(cx, pn, pn->getOp(), bce);
3153
}
3154
3155
// Emit code to initialize all destructured names to the value on the top of
3156
// the stack.
3157
static inline bool
3158
EmitInitializeDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
3159
                                 ParseNode *pattern)
3160
{
3161
    return EmitDestructuringDeclsWithEmitter<EmitInitializeDestructuringDecl>(cx, bce,
3162
                                                                              prologOp, pattern);
3163
}
3164
3048
static bool
3165
static bool
3049
EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn,
3166
EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn,
3050
                           VarEmitOption emitOption);
3167
                           VarEmitOption emitOption);
3051
3168
3052
/*
3169
/*
3053
 * EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
3170
 * EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
3054
 * the stack and emits code to destructure a single lhs expression (either a
3171
 * the stack and emits code to destructure a single lhs expression (either a
3055
 * name or a compound []/{} expression).
3172
 * name or a compound []/{} expression).
 Lines 3077-3093   EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, Link Here 
3077
            // Per its post-condition, EmitDestructuringOpsHelper has left the
3194
            // Per its post-condition, EmitDestructuringOpsHelper has left the
3078
            // to-be-destructured value on top of the stack.
3195
            // to-be-destructured value on top of the stack.
3079
            if (Emit1(cx, bce, JSOP_POP) < 0)
3196
            if (Emit1(cx, bce, JSOP_POP) < 0)
3080
                return false;
3197
                return false;
3081
        }
3198
        }
3082
    } else if (emitOption == PushInitialValues) {
3199
    } else if (emitOption == PushInitialValues) {
3083
        // The lhs is a simple name so the to-be-destructured value is
3200
        // The lhs is a simple name so the to-be-destructured value is
3084
        // its initial value and there is nothing to do.
3201
        // its initial value and there is nothing to do.
3085
        JS_ASSERT(pn->getOp() == JSOP_SETLOCAL);
3202
        JS_ASSERT(pn->getOp() == JSOP_SETLOCAL || pn->getOp() == JSOP_INITLET);
3086
        JS_ASSERT(pn->pn_dflags & PND_BOUND);
3203
        JS_ASSERT(pn->pn_dflags & PND_BOUND);
3087
    } else {
3204
    } else {
3088
        switch (pn->getKind()) {
3205
        switch (pn->getKind()) {
3089
          case PNK_NAME:
3206
          case PNK_NAME:
3090
            if (!BindNameToSlot(cx, bce, pn))
3207
            if (!BindNameToSlot(cx, bce, pn))
3091
                return false;
3208
                return false;
3092
3209
3093
            // Allow 'const [x,y] = o', make 'const x,y; [x,y] = o' a nop.
3210
            // Allow 'const [x,y] = o', make 'const x,y; [x,y] = o' a nop.
 Lines 3122-3137   EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, Link Here 
3122
3239
3123
                if (!EmitIndexOp(cx, pn->getOp(), atomIndex, bce))
3240
                if (!EmitIndexOp(cx, pn->getOp(), atomIndex, bce))
3124
                    return false;
3241
                    return false;
3125
                break;
3242
                break;
3126
              }
3243
              }
3127
3244
3128
              case JSOP_SETLOCAL:
3245
              case JSOP_SETLOCAL:
3129
              case JSOP_SETARG:
3246
              case JSOP_SETARG:
3247
              case JSOP_INITLET:
3130
                if (!EmitVarOp(cx, pn, pn->getOp(), bce))
3248
                if (!EmitVarOp(cx, pn, pn->getOp(), bce))
3131
                    return false;
3249
                    return false;
3132
                break;
3250
                break;
3133
3251
3134
              default:
3252
              default:
3135
                MOZ_CRASH("EmitDestructuringLHS: bad name op");
3253
                MOZ_CRASH("EmitDestructuringLHS: bad name op");
3136
            }
3254
            }
3137
            break;
3255
            break;
 Lines 3479-3520   EmitTemplateString(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) Link Here 
3479
        }
3597
        }
3480
3598
3481
    }
3599
    }
3482
    return true;
3600
    return true;
3483
}
3601
}
3484
3602
3485
static bool
3603
static bool
3486
EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
3604
EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
3487
              bool isLet = false)
3605
              bool isLetExpr = false)
3488
{
3606
{
3489
    JS_ASSERT(pn->isArity(PN_LIST));
3607
    JS_ASSERT(pn->isArity(PN_LIST));
3490
    JS_ASSERT(isLet == (emitOption == PushInitialValues));
3608
    JS_ASSERT(isLetExpr == (emitOption == PushInitialValues));
3491
3609
3492
    ParseNode *next;
3610
    ParseNode *next;
3493
    for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
3611
    for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
3494
        if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
3612
        if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
3495
            return false;
3613
            return false;
3496
        next = pn2->pn_next;
3614
        next = pn2->pn_next;
3497
3615
3498
        ParseNode *pn3;
3616
        ParseNode *pn3;
3499
        if (!pn2->isKind(PNK_NAME)) {
3617
        if (!pn2->isKind(PNK_NAME)) {
3500
            if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
3618
            if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
3501
                /*
3619
                // If the emit option is DefineVars, emit variable binding
3502
                 * Emit variable binding ops, but not destructuring ops.  The
3620
                // ops, but not destructuring ops.  The parser (see
3503
                 * parser (see Parser::variables) has ensured that our caller
3621
                // Parser::variables) has ensured that our caller will be the
3504
                 * will be the PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and
3622
                // PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and that case
3505
                 * that case will emit the destructuring code only after
3623
                // will emit the destructuring code only after emitting an
3506
                 * emitting an enumerating opcode and a branch that tests
3624
                // enumerating opcode and a branch that tests whether the
3507
                 * whether the enumeration ended.
3625
                // enumeration ended.
3508
                 */
3626
                //
3509
                JS_ASSERT(emitOption == DefineVars);
3627
                // Otherwise this is emitting destructuring let binding
3628
                // initialization for a legacy comprehension expression. See
3629
                // EmitForInOrOfVariables.
3510
                JS_ASSERT(pn->pn_count == 1);
3630
                JS_ASSERT(pn->pn_count == 1);
3511
                if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
3631
                if (emitOption == DefineVars) {
3512
                    return false;
3632
                    if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
3633
                        return false;
3634
                } else {
3635
                    // 'let' bindings cannot be used before they are
3636
                    // initialized. Similar to the JSOP_INITLET case below.
3637
                    MOZ_ASSERT(emitOption != DefineVars);
3638
                    MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR);
3639
                    if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
3640
                        return false;
3641
                    if (!EmitInitializeDestructuringDecls(cx, bce, pn->getOp(), pn2))
3642
                        return false;
3643
                }
3513
                break;
3644
                break;
3514
            }
3645
            }
3515
3646
3516
            /*
3647
            /*
3517
             * A destructuring initialiser assignment preceded by var will
3648
             * A destructuring initialiser assignment preceded by var will
3518
             * never occur to the left of 'in' in a for-in loop.  As with 'for
3649
             * never occur to the left of 'in' in a for-in loop.  As with 'for
3519
             * (var x = i in o)...', this will cause the entire 'var [a, b] =
3650
             * (var x = i in o)...', this will cause the entire 'var [a, b] =
3520
             * i' to be hoisted out of the loop.
3651
             * i' to be hoisted out of the loop.
 Lines 3538-3554   EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit Link Here 
3538
            if (pn->pn_count == 1) {
3669
            if (pn->pn_count == 1) {
3539
                /*
3670
                /*
3540
                 * If this is the only destructuring assignment in the list,
3671
                 * If this is the only destructuring assignment in the list,
3541
                 * try to optimize to a group assignment.  If we're in a let
3672
                 * try to optimize to a group assignment.  If we're in a let
3542
                 * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
3673
                 * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
3543
                 * in pn->pn_op, to suppress a second (and misplaced) 'let'.
3674
                 * in pn->pn_op, to suppress a second (and misplaced) 'let'.
3544
                 */
3675
                 */
3545
                JS_ASSERT(!pn2->pn_next);
3676
                JS_ASSERT(!pn2->pn_next);
3546
                if (isLet) {
3677
                if (isLetExpr) {
3547
                    if (!MaybeEmitLetGroupDecl(cx, bce, pn2, &op))
3678
                    if (!MaybeEmitLetGroupDecl(cx, bce, pn2, &op))
3548
                        return false;
3679
                        return false;
3549
                } else {
3680
                } else {
3550
                    if (!MaybeEmitGroupAssignment(cx, bce, pn->getOp(), pn2, GroupIsDecl, &op))
3681
                    if (!MaybeEmitGroupAssignment(cx, bce, pn->getOp(), pn2, GroupIsDecl, &op))
3551
                        return false;
3682
                        return false;
3552
                }
3683
                }
3553
            }
3684
            }
3554
            if (op == JSOP_NOP) {
3685
            if (op == JSOP_NOP) {
 Lines 3556-3572   EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit Link Here 
3556
            } else {
3687
            } else {
3557
                pn3 = pn2->pn_left;
3688
                pn3 = pn2->pn_left;
3558
                if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn3))
3689
                if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn3))
3559
                    return false;
3690
                    return false;
3560
3691
3561
                if (!EmitTree(cx, bce, pn2->pn_right))
3692
                if (!EmitTree(cx, bce, pn2->pn_right))
3562
                    return false;
3693
                    return false;
3563
3694
3564
                if (!EmitDestructuringOps(cx, bce, pn3, isLet))
3695
                if (!EmitDestructuringOps(cx, bce, pn3, isLetExpr))
3565
                    return false;
3696
                    return false;
3566
            }
3697
            }
3567
3698
3568
            /* If we are not initializing, nothing to pop. */
3699
            /* If we are not initializing, nothing to pop. */
3569
            if (emitOption != InitializeVars) {
3700
            if (emitOption != InitializeVars) {
3570
                if (next)
3701
                if (next)
3571
                    continue;
3702
                    continue;
3572
                break;
3703
                break;
 Lines 3611-3633   EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit Link Here 
3611
                    return false;
3742
                    return false;
3612
            }
3743
            }
3613
3744
3614
            bool oldEmittingForInit = bce->emittingForInit;
3745
            bool oldEmittingForInit = bce->emittingForInit;
3615
            bce->emittingForInit = false;
3746
            bce->emittingForInit = false;
3616
            if (!EmitTree(cx, bce, pn3))
3747
            if (!EmitTree(cx, bce, pn3))
3617
                return false;
3748
                return false;
3618
            bce->emittingForInit = oldEmittingForInit;
3749
            bce->emittingForInit = oldEmittingForInit;
3619
        } else if (isLet) {
3750
        } else if (op == JSOP_INITLET || isLetExpr) {
3620
            /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
3751
            // 'let' bindings cannot be used before they are
3752
            // initialized. JSOP_INITLET distinguishes the binding site.
3753
            MOZ_ASSERT(emitOption != DefineVars);
3754
            MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR);
3621
            if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
3755
            if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
3622
                return false;
3756
                return false;
3623
        }
3757
        }
3624
3758
3625
        /* If we are not initializing, nothing to pop. */
3759
        // If we are not initializing, nothing to pop. If we are initializing
3760
        // lets, we must emit the pops.
3626
        if (emitOption != InitializeVars) {
3761
        if (emitOption != InitializeVars) {
3627
            if (next)
3762
            if (next)
3628
                continue;
3763
                continue;
3629
            break;
3764
            break;
3630
        }
3765
        }
3631
3766
3632
        JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
3767
        JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
3633
        if (!pn2->pn_cookie.isFree()) {
3768
        if (!pn2->pn_cookie.isFree()) {
 Lines 4065-4081   EmitCatch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) Link Here 
4065
            return false;
4200
            return false;
4066
        if (Emit1(cx, bce, JSOP_POP) < 0)
4201
        if (Emit1(cx, bce, JSOP_POP) < 0)
4067
            return false;
4202
            return false;
4068
        break;
4203
        break;
4069
4204
4070
      case PNK_NAME:
4205
      case PNK_NAME:
4071
        /* Inline and specialize BindNameToSlot for pn2. */
4206
        /* Inline and specialize BindNameToSlot for pn2. */
4072
        JS_ASSERT(!pn2->pn_cookie.isFree());
4207
        JS_ASSERT(!pn2->pn_cookie.isFree());
4073
        if (!EmitVarOp(cx, pn2, JSOP_SETLOCAL, bce))
4208
        if (!EmitVarOp(cx, pn2, JSOP_INITLET, bce))
4074
            return false;
4209
            return false;
4075
        if (Emit1(cx, bce, JSOP_POP) < 0)
4210
        if (Emit1(cx, bce, JSOP_POP) < 0)
4076
            return false;
4211
            return false;
4077
        break;
4212
        break;
4078
4213
4079
      default:
4214
      default:
4080
        JS_ASSERT(0);
4215
        JS_ASSERT(0);
4081
    }
4216
    }
 Lines 4419-4437   EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) Link Here 
4419
    JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
4554
    JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
4420
4555
4421
    int letHeadDepth = bce->stackDepth;
4556
    int letHeadDepth = bce->stackDepth;
4422
4557
4423
    if (!EmitVariables(cx, bce, varList, PushInitialValues, true))
4558
    if (!EmitVariables(cx, bce, varList, PushInitialValues, true))
4424
        return false;
4559
        return false;
4425
4560
4426
    /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
4561
    /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
4427
    uint32_t alreadyPushed = bce->stackDepth - letHeadDepth;
4562
    uint32_t valuesPushed = bce->stackDepth - letHeadDepth;
4428
    StmtInfoBCE stmtInfo(cx);
4563
    StmtInfoBCE stmtInfo(cx);
4429
    if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, alreadyPushed))
4564
    if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, valuesPushed))
4430
        return false;
4565
        return false;
4431
4566
4432
    if (!EmitTree(cx, bce, letBody->pn_expr))
4567
    if (!EmitTree(cx, bce, letBody->pn_expr))
4433
        return false;
4568
        return false;
4434
4569
4435
    if (!LeaveNestedScope(cx, bce, &stmtInfo))
4570
    if (!LeaveNestedScope(cx, bce, &stmtInfo))
4436
        return false;
4571
        return false;
4437
4572
 Lines 4490-4505   EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce) Link Here 
4490
    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
4625
    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
4491
        return false;
4626
        return false;
4492
    if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
4627
    if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
4493
        return false;
4628
        return false;
4494
    CheckTypeSet(cx, bce, JSOP_CALL);
4629
    CheckTypeSet(cx, bce, JSOP_CALL);
4495
    return true;
4630
    return true;
4496
}
4631
}
4497
4632
4633
static bool
4634
EmitForInOrOfVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool *letDecl)
4635
{
4636
    *letDecl = pn->isKind(PNK_LEXICALSCOPE);
4637
    MOZ_ASSERT_IF(*letDecl, pn->isLet());
4638
4639
    // If the left part is 'var x', emit code to define x if necessary using a
4640
    // prolog opcode, but do not emit a pop. If it is 'let x', we don't need
4641
    // to do anything here. EnterBlockScopeWithUndefined will initialize let
4642
    // bindings in EmitForOf and EmitForIn.
4643
    //
4644
    // Due to the horror of legacy comprehensions, there is a third case where
4645
    // we have PNK_LET without a lexical scope, because those expressions are
4646
    // parsed with single lexical scope for the entire comprehension. In this
4647
    // case we must initialize the lets to not trigger dead zone checks via
4648
    // InitializeVars.
4649
    if (pn && !*letDecl) {
4650
        bce->emittingForInit = true;
4651
        if (pn->isKind(PNK_VAR)) {
4652
            if (!EmitVariables(cx, bce, pn, DefineVars))
4653
                return false;
4654
        } else {
4655
            MOZ_ASSERT(pn->isKind(PNK_LET));
4656
            if (!EmitVariables(cx, bce, pn, InitializeVars))
4657
                return false;
4658
        }
4659
        bce->emittingForInit = false;
4660
    }
4661
4662
    return true;
4663
}
4664
4665
4498
/**
4666
/**
4499
 * If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
4667
 * If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
4500
 * pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
4668
 * pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
4501
 *
4669
 *
4502
 * If type is STMT_SPREAD, it emits bytecode for spread operator.
4670
 * If type is STMT_SPREAD, it emits bytecode for spread operator.
4503
 * pn should be nullptr.
4671
 * pn should be nullptr.
4504
 * Please refer the comment above EmitSpread for additional information about
4672
 * Please refer the comment above EmitSpread for additional information about
4505
 * stack convention.
4673
 * stack convention.
 Lines 4510-4538   EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode * Link Here 
4510
    JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
4678
    JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
4511
    JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
4679
    JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
4512
    JS_ASSERT_IF(type == STMT_SPREAD, !pn);
4680
    JS_ASSERT_IF(type == STMT_SPREAD, !pn);
4513
4681
4514
    ParseNode *forHead = pn ? pn->pn_left : nullptr;
4682
    ParseNode *forHead = pn ? pn->pn_left : nullptr;
4515
    ParseNode *forBody = pn ? pn->pn_right : nullptr;
4683
    ParseNode *forBody = pn ? pn->pn_right : nullptr;
4516
4684
4517
    ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
4685
    ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
4518
    bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
4686
    bool letDecl = false;
4519
    JS_ASSERT_IF(letDecl, pn1->isLet());
4687
    if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl))
4520
4688
        return false;
4521
    // If the left part is 'var x', emit code to define x if necessary using a
4522
    // prolog opcode, but do not emit a pop.
4523
    if (pn1) {
4524
        ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
4525
        JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
4526
        bce->emittingForInit = true;
4527
        if (!EmitVariables(cx, bce, decl, DefineVars))
4528
            return false;
4529
        bce->emittingForInit = false;
4530
    }
4531
4689
4532
    if (type == STMT_FOR_OF_LOOP) {
4690
    if (type == STMT_FOR_OF_LOOP) {
4533
        // For-of loops run with two values on the stack: the iterator and the
4691
        // For-of loops run with two values on the stack: the iterator and the
4534
        // current result object.
4692
        // current result object.
4535
4693
4536
        // Compile the object expression to the right of 'of'.
4694
        // Compile the object expression to the right of 'of'.
4537
        if (!EmitTree(cx, bce, forHead->pn_kid3))
4695
        if (!EmitTree(cx, bce, forHead->pn_kid3))
4538
            return false;
4696
            return false;
 Lines 4547-4565   EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode * Link Here 
4547
        // the stack.
4705
        // the stack.
4548
        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // I ITER ARR
4706
        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // I ITER ARR
4549
            return false;
4707
            return false;
4550
        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // ITER ARR I
4708
        if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)      // ITER ARR I
4551
            return false;
4709
            return false;
4552
    }
4710
    }
4553
4711
4554
    // Enter the block before the loop body, after evaluating the obj.
4712
    // Enter the block before the loop body, after evaluating the obj.
4713
    // Initialize let bindings with undefined when entering, as the name
4714
    // assigned to is a plain assignment.
4555
    StmtInfoBCE letStmt(cx);
4715
    StmtInfoBCE letStmt(cx);
4556
    if (letDecl) {
4716
    if (letDecl) {
4557
        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0))
4717
        if (!EnterBlockScopeWithUndefined(cx, bce, &letStmt, pn1->pn_objbox, 0))
4558
            return false;
4718
            return false;
4559
    }
4719
    }
4560
4720
4561
    LoopStmtInfo stmtInfo(cx);
4721
    LoopStmtInfo stmtInfo(cx);
4562
    PushLoopStatement(bce, &stmtInfo, type, top);
4722
    PushLoopStatement(bce, &stmtInfo, type, top);
4563
4723
4564
    // Jump down to the loop condition to minimize overhead assuming at least
4724
    // Jump down to the loop condition to minimize overhead assuming at least
4565
    // one iteration, as the other loop forms do.  Annotate so IonMonkey can
4725
    // one iteration, as the other loop forms do.  Annotate so IonMonkey can
 Lines 4678-4728   EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode * Link Here 
4678
4838
4679
static bool
4839
static bool
4680
EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
4840
EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
4681
{
4841
{
4682
    ParseNode *forHead = pn->pn_left;
4842
    ParseNode *forHead = pn->pn_left;
4683
    ParseNode *forBody = pn->pn_right;
4843
    ParseNode *forBody = pn->pn_right;
4684
4844
4685
    ParseNode *pn1 = forHead->pn_kid1;
4845
    ParseNode *pn1 = forHead->pn_kid1;
4686
    bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
4846
    bool letDecl = false;
4687
    JS_ASSERT_IF(letDecl, pn1->isLet());
4847
    if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl))
4688
4848
        return false;
4689
    /*
4690
     * If the left part is 'var x', emit code to define x if necessary
4691
     * using a prolog opcode, but do not emit a pop. If the left part was
4692
     * originally 'var x = i', the parser will have rewritten it; see
4693
     * Parser::forStatement. 'for (let x = i in o)' is mercifully banned.
4694
     */
4695
    if (pn1) {
4696
        ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
4697
        JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
4698
        bce->emittingForInit = true;
4699
        if (!EmitVariables(cx, bce, decl, DefineVars))
4700
            return false;
4701
        bce->emittingForInit = false;
4702
    }
4703
4849
4704
    /* Compile the object expression to the right of 'in'. */
4850
    /* Compile the object expression to the right of 'in'. */
4705
    if (!EmitTree(cx, bce, forHead->pn_kid3))
4851
    if (!EmitTree(cx, bce, forHead->pn_kid3))
4706
        return false;
4852
        return false;
4707
4853
4708
    /*
4854
    /*
4709
     * Emit a bytecode to convert top of stack value to the iterator
4855
     * Emit a bytecode to convert top of stack value to the iterator
4710
     * object depending on the loop variant (for-in, for-each-in, or
4856
     * object depending on the loop variant (for-in, for-each-in, or
4711
     * destructuring for-in).
4857
     * destructuring for-in).
4712
     */
4858
     */
4713
    JS_ASSERT(pn->isOp(JSOP_ITER));
4859
    JS_ASSERT(pn->isOp(JSOP_ITER));
4714
    if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
4860
    if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
4715
        return false;
4861
        return false;
4716
4862
4717
    /* Enter the block before the loop body, after evaluating the obj. */
4863
    // Enter the block before the loop body, after evaluating the obj.
4864
    // Initialize let bindings with undefined when entering, as the name
4865
    // assigned to is a plain assignment.
4718
    StmtInfoBCE letStmt(cx);
4866
    StmtInfoBCE letStmt(cx);
4719
    if (letDecl) {
4867
    if (letDecl) {
4720
        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0))
4868
        if (!EnterBlockScopeWithUndefined(cx, bce, &letStmt, pn1->pn_objbox, 0))
4721
            return false;
4869
            return false;
4722
    }
4870
    }
4723
4871
4724
    LoopStmtInfo stmtInfo(cx);
4872
    LoopStmtInfo stmtInfo(cx);
4725
    PushLoopStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
4873
    PushLoopStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
4726
4874
4727
    /* Annotate so IonMonkey can find the loop-closing jump. */
4875
    /* Annotate so IonMonkey can find the loop-closing jump. */
4728
    int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
4876
    int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
 Lines 5035-5052   EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) Link Here 
5035
                                                          sourceObject,
5183
                                                          sourceObject,
5036
                                                          funbox->bufStart, funbox->bufEnd));
5184
                                                          funbox->bufStart, funbox->bufEnd));
5037
            if (!script)
5185
            if (!script)
5038
                return false;
5186
                return false;
5039
5187
5040
            script->bindings = funbox->bindings;
5188
            script->bindings = funbox->bindings;
5041
5189
5042
            uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
5190
            uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
5043
            BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->insideEval,
5191
            BytecodeEmitter bce2(bce, bce->parser, funbox, script, /* lazyScript = */ js::NullPtr(),
5044
                                 bce->evalCaller, bce->hasGlobalScope, lineNum,
5192
                                 bce->insideEval, bce->evalCaller, bce->hasGlobalScope, lineNum,
5045
                                 bce->emitterMode);
5193
                                 bce->emitterMode);
5046
            if (!bce2.init())
5194
            if (!bce2.init())
5047
                return false;
5195
                return false;
5048
5196
5049
            /* We measured the max scope depth when we parsed the function. */
5197
            /* We measured the max scope depth when we parsed the function. */
5050
            if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
5198
            if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
5051
                return false;
5199
                return false;
5052
5200
(-)a/js/src/frontend/BytecodeEmitter.h (-4 / +6 lines)
Line     Link Here 
 Lines 81-96   struct BytecodeEmitter Link Here 
81
    typedef StmtInfoBCE StmtInfo;
81
    typedef StmtInfoBCE StmtInfo;
82
82
83
    SharedContext   *const sc;      /* context shared between parsing and bytecode generation */
83
    SharedContext   *const sc;      /* context shared between parsing and bytecode generation */
84
84
85
    BytecodeEmitter *const parent;  /* enclosing function or global context */
85
    BytecodeEmitter *const parent;  /* enclosing function or global context */
86
86
87
    Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
87
    Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
88
88
89
    Rooted<LazyScript *> lazyScript; /* the lazy script if mode is LazyFunction,
90
                                        nullptr otherwise. */
91
89
    struct EmitSection {
92
    struct EmitSection {
90
        BytecodeVector code;        /* bytecode */
93
        BytecodeVector code;        /* bytecode */
91
        SrcNotesVector notes;       /* source notes, see below */
94
        SrcNotesVector notes;       /* source notes, see below */
92
        ptrdiff_t   lastNoteOffset; /* code offset for last source note */
95
        ptrdiff_t   lastNoteOffset; /* code offset for last source note */
93
        uint32_t    currentLine;    /* line number for tree-based srcnote gen */
96
        uint32_t    currentLine;    /* line number for tree-based srcnote gen */
94
        uint32_t    lastColumn;     /* zero-based column index on currentLine of
97
        uint32_t    lastColumn;     /* zero-based column index on currentLine of
95
                                       last SRC_COLSPAN-annotated opcode */
98
                                       last SRC_COLSPAN-annotated opcode */
96
99
 Lines 131-148   struct BytecodeEmitter Link Here 
131
    uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
134
    uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
132
135
133
    bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
136
    bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
134
137
135
    bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
138
    bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
136
139
137
    bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
140
    bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
138
                                                expected to run once. */
141
                                                expected to run once. */
139
    bool            lazyRunOnceLambda:1; /* true while lazily emitting a script for
140
                                          * a lambda which is only expected to run once. */
141
142
142
    bool isRunOnceLambda();
143
    bool isRunOnceLambda();
143
144
144
    bool            insideEval:1;       /* True if compiling an eval-expression or a function
145
    bool            insideEval:1;       /* True if compiling an eval-expression or a function
145
                                           nested inside an eval. */
146
                                           nested inside an eval. */
146
147
147
    const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
148
    const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
148
                                           global object */
149
                                           global object */
 Lines 168-185   struct BytecodeEmitter Link Here 
168
169
169
    /*
170
    /*
170
     * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
171
     * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
171
     * space above their tempMark points. This means that you cannot alloc from
172
     * space above their tempMark points. This means that you cannot alloc from
172
     * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
173
     * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
173
     * destruction.
174
     * destruction.
174
     */
175
     */
175
    BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
176
    BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
176
                    HandleScript script, bool insideEval, HandleScript evalCaller,
177
                    HandleScript script, Handle<LazyScript *> lazyScript,
177
                    bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode = Normal);
178
                    bool insideEval, HandleScript evalCaller, bool hasGlobalScope,
179
                    uint32_t lineNum, EmitterMode emitterMode = Normal);
178
    bool init();
180
    bool init();
179
181
180
    bool isAliasedName(ParseNode *pn);
182
    bool isAliasedName(ParseNode *pn);
181
183
182
    MOZ_ALWAYS_INLINE
184
    MOZ_ALWAYS_INLINE
183
    bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
185
    bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
184
        AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
186
        AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
185
        if (p) {
187
        if (p) {
(-)a/js/src/frontend/FullParseHandler.h (-5 / +18 lines)
Line     Link Here 
 Lines 580-595   class FullParseHandler Link Here 
580
    inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
580
    inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
581
581
582
    static Definition *getDefinitionNode(Definition *dn) {
582
    static Definition *getDefinitionNode(Definition *dn) {
583
        return dn;
583
        return dn;
584
    }
584
    }
585
    static Definition::Kind getDefinitionKind(Definition *dn) {
585
    static Definition::Kind getDefinitionKind(Definition *dn) {
586
        return dn->kind();
586
        return dn->kind();
587
    }
587
    }
588
    static bool isPlaceholderDefinition(Definition *dn) {
589
        return dn->isPlaceholder();
590
    }
588
    void linkUseToDef(ParseNode *pn, Definition *dn)
591
    void linkUseToDef(ParseNode *pn, Definition *dn)
589
    {
592
    {
590
        JS_ASSERT(!pn->isUsed());
593
        JS_ASSERT(!pn->isUsed());
591
        JS_ASSERT(!pn->isDefn());
594
        JS_ASSERT(!pn->isDefn());
592
        JS_ASSERT(pn != dn->dn_uses);
595
        JS_ASSERT(pn != dn->dn_uses);
593
        JS_ASSERT(dn->isDefn());
596
        JS_ASSERT(dn->isDefn());
594
        pn->pn_link = dn->dn_uses;
597
        pn->pn_link = dn->dn_uses;
595
        dn->dn_uses = pn;
598
        dn->dn_uses = pn;
 Lines 607-622   class FullParseHandler Link Here 
607
            JS_ASSERT(!pnu->isDefn());
610
            JS_ASSERT(!pnu->isDefn());
608
            if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
611
            if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
609
                pnu->pn_dflags |= PND_DEOPTIMIZED;
612
                pnu->pn_dflags |= PND_DEOPTIMIZED;
610
        }
613
        }
611
    }
614
    }
612
    bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
615
    bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
613
        return pn->pn_blockid >= blockid;
616
        return pn->pn_blockid >= blockid;
614
    }
617
    }
618
    void markMaybeUninitializedLetUseInSwitch(ParseNode *pn, Definition *dn,
619
                                              uint16_t firstDominatingLetSlot)
620
    {
621
        MOZ_ASSERT(pn->isUsed());
622
        if (dn->isLet() && dn->pn_cookie.slot() < firstDominatingLetSlot)
623
            pn->pn_dflags |= PND_LET;
624
    }
615
625
616
    static uintptr_t definitionToBits(Definition *dn) {
626
    static uintptr_t definitionToBits(Definition *dn) {
617
        return uintptr_t(dn);
627
        return uintptr_t(dn);
618
    }
628
    }
619
    static Definition *definitionFromBits(uintptr_t bits) {
629
    static Definition *definitionFromBits(uintptr_t bits) {
620
        return (Definition *) bits;
630
        return (Definition *) bits;
621
    }
631
    }
622
    static Definition *nullDefinition() {
632
    static Definition *nullDefinition() {
 Lines 694-714   FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JS Link Here 
694
    if (pn->isUsed()) {
704
    if (pn->isUsed()) {
695
        pn = makeAssignment(pn, init);
705
        pn = makeAssignment(pn, init);
696
        if (!pn)
706
        if (!pn)
697
            return false;
707
            return false;
698
    } else {
708
    } else {
699
        pn->pn_expr = init;
709
        pn->pn_expr = init;
700
    }
710
    }
701
711
702
    pn->setOp((pn->pn_dflags & PND_BOUND)
712
    if (op == JSOP_INITLET)
703
              ? JSOP_SETLOCAL
713
        pn->setOp(op);
704
              : (op == JSOP_DEFCONST)
714
    else if (pn->pn_dflags & PND_BOUND)
705
              ? JSOP_SETCONST
715
        pn->setOp(JSOP_SETLOCAL);
706
              : JSOP_SETNAME);
716
    else if (op == JSOP_DEFCONST)
717
        pn->setOp(JSOP_SETCONST);
718
    else
719
        pn->setOp(JSOP_SETNAME);
707
720
708
    pn->markAsAssigned();
721
    pn->markAsAssigned();
709
722
710
    /* The declarator's position must include the initializer. */
723
    /* The declarator's position must include the initializer. */
711
    pn->pn_pos.end = init->pn_pos.end;
724
    pn->pn_pos.end = init->pn_pos.end;
712
    return true;
725
    return true;
713
}
726
}
714
727
(-)a/js/src/frontend/ParseNode.cpp (-1 / +2 lines)
Line     Link Here 
 Lines 402-417   Parser<FullParseHandler>::cloneParseTree(ParseNode *opn) Link Here 
402
        if (opn->isUsed()) {
402
        if (opn->isUsed()) {
403
            /*
403
            /*
404
             * The old name is a use of its pn_lexdef. Make the clone also be a
404
             * The old name is a use of its pn_lexdef. Make the clone also be a
405
             * use of that definition.
405
             * use of that definition.
406
             */
406
             */
407
            Definition *dn = pn->pn_lexdef;
407
            Definition *dn = pn->pn_lexdef;
408
408
409
            pn->pn_link = dn->dn_uses;
409
            pn->pn_link = dn->dn_uses;
410
            pn->pn_dflags = opn->pn_dflags;
410
            dn->dn_uses = pn;
411
            dn->dn_uses = pn;
411
        } else if (opn->pn_expr) {
412
        } else if (opn->pn_expr) {
412
            NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr));
413
            NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr));
413
414
414
            /*
415
            /*
415
             * If the old name is a definition, the new one has pn_defn set.
416
             * If the old name is a definition, the new one has pn_defn set.
416
             * Make the old name a use of the new node.
417
             * Make the old name a use of the new node.
417
             */
418
             */
 Lines 496-512   Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn) Link Here 
496
497
497
        pn->pn_link = dn->dn_uses;
498
        pn->pn_link = dn->dn_uses;
498
        dn->dn_uses = pn;
499
        dn->dn_uses = pn;
499
    } else {
500
    } else {
500
        pn->pn_expr = nullptr;
501
        pn->pn_expr = nullptr;
501
        if (opn->isDefn()) {
502
        if (opn->isDefn()) {
502
            /* We copied some definition-specific state into pn. Clear it out. */
503
            /* We copied some definition-specific state into pn. Clear it out. */
503
            pn->pn_cookie.makeFree();
504
            pn->pn_cookie.makeFree();
504
            pn->pn_dflags &= ~PND_BOUND;
505
            pn->pn_dflags &= ~(PND_LET | PND_BOUND);
505
            pn->setDefn(false);
506
            pn->setDefn(false);
506
507
507
            handler.linkUseToDef(pn, (Definition *) opn);
508
            handler.linkUseToDef(pn, (Definition *) opn);
508
        }
509
        }
509
    }
510
    }
510
    return pn;
511
    return pn;
511
}
512
}
512
513
(-)a/js/src/frontend/ParseNode.h (-2 / +3 lines)
Line     Link Here 
 Lines 658-674   class ParseNode Link Here 
658
    }
658
    }
659
659
660
    ParseNode  *maybeExpr()   { return pn_used ? nullptr : expr(); }
660
    ParseNode  *maybeExpr()   { return pn_used ? nullptr : expr(); }
661
    Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; }
661
    Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; }
662
662
663
    Definition *resolve();
663
    Definition *resolve();
664
664
665
/* PN_CODE and PN_NAME pn_dflags bits. */
665
/* PN_CODE and PN_NAME pn_dflags bits. */
666
#define PND_LET                 0x01    /* let (block-scoped) binding */
666
#define PND_LET                 0x01    /* let (block-scoped) binding or use of a hoisted let */
667
#define PND_CONST               0x02    /* const binding (orthogonal to let) */
667
#define PND_CONST               0x02    /* const binding (orthogonal to let) */
668
#define PND_ASSIGNED            0x04    /* set if ever LHS of assignment */
668
#define PND_ASSIGNED            0x04    /* set if ever LHS of assignment */
669
#define PND_PLACEHOLDER         0x08    /* placeholder definition for lexdep */
669
#define PND_PLACEHOLDER         0x08    /* placeholder definition for lexdep */
670
#define PND_BOUND               0x10    /* bound to a stack or global slot */
670
#define PND_BOUND               0x10    /* bound to a stack or global slot */
671
#define PND_DEOPTIMIZED         0x20    /* former pn_used name node, pn_lexdef
671
#define PND_DEOPTIMIZED         0x20    /* former pn_used name node, pn_lexdef
672
                                           still valid, but this use no longer
672
                                           still valid, but this use no longer
673
                                           optimizable via an upvar opcode */
673
                                           optimizable via an upvar opcode */
674
#define PND_CLOSED              0x40    /* variable is closed over */
674
#define PND_CLOSED              0x40    /* variable is closed over */
 Lines 740-763   class ParseNode Link Here 
740
            if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
740
            if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
741
                return kid->pn_atom;
741
                return kid->pn_atom;
742
        }
742
        }
743
        return nullptr;
743
        return nullptr;
744
    }
744
    }
745
745
746
    inline bool test(unsigned flag) const;
746
    inline bool test(unsigned flag) const;
747
747
748
    bool isLet() const          { return test(PND_LET); }
748
    bool isLet() const          { return test(PND_LET) && !isUsed(); }
749
    bool isConst() const        { return test(PND_CONST); }
749
    bool isConst() const        { return test(PND_CONST); }
750
    bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
750
    bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
751
    bool isDeoptimized() const  { return test(PND_DEOPTIMIZED); }
751
    bool isDeoptimized() const  { return test(PND_DEOPTIMIZED); }
752
    bool isAssigned() const     { return test(PND_ASSIGNED); }
752
    bool isAssigned() const     { return test(PND_ASSIGNED); }
753
    bool isClosed() const       { return test(PND_CLOSED); }
753
    bool isClosed() const       { return test(PND_CLOSED); }
754
    bool isBound() const        { return test(PND_BOUND); }
754
    bool isBound() const        { return test(PND_BOUND); }
755
    bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
755
    bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
756
    bool isHoistedLetUse() const { return test(PND_LET) && isUsed(); }
756
757
757
    /* True if pn is a parsenode representing a literal constant. */
758
    /* True if pn is a parsenode representing a literal constant. */
758
    bool isLiteral() const {
759
    bool isLiteral() const {
759
        return isKind(PNK_NUMBER) ||
760
        return isKind(PNK_NUMBER) ||
760
               isKind(PNK_STRING) ||
761
               isKind(PNK_STRING) ||
761
               isKind(PNK_TRUE) ||
762
               isKind(PNK_TRUE) ||
762
               isKind(PNK_FALSE) ||
763
               isKind(PNK_FALSE) ||
763
               isKind(PNK_NULL);
764
               isKind(PNK_NULL);
(-)a/js/src/frontend/Parser.cpp (-85 / +284 lines)
Line     Link Here 
 Lines 91-106   GenerateBlockId(TokenStream &ts, ParseContext<FullParseHandler> *pc, uint32_t &b Link Here 
91
template <typename ParseHandler>
91
template <typename ParseHandler>
92
static void
92
static void
93
PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type)
93
PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type)
94
{
94
{
95
    stmt->blockid = pc->blockid();
95
    stmt->blockid = pc->blockid();
96
    PushStatement(pc, stmt, type);
96
    PushStatement(pc, stmt, type);
97
}
97
}
98
98
99
template <>
100
bool
101
ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream &ts)
102
{
103
    if (vars_.length() + bodyLevelLets_.length() >= LOCALNO_LIMIT) {
104
        ts.reportError(JSMSG_TOO_MANY_LOCALS);
105
        return false;
106
    }
107
    return true;
108
}
109
110
static void
111
MarkUsesAsHoistedLet(ParseNode *pn)
112
{
113
    MOZ_ASSERT(pn->isDefn());
114
115
    Definition *dn = (Definition *)pn;
116
    ParseNode **pnup = &dn->dn_uses;
117
    ParseNode *pnu;
118
    unsigned start = pn->pn_blockid;
119
120
    // In ES6, 'let' bindings cannot be accessed until initialized.
121
    // Distinguish hoisted uses as a different JSOp for easier compilation.
122
    while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) {
123
        MOZ_ASSERT(pnu->isUsed());
124
        pnu->pn_dflags |= PND_LET;
125
        pnup = &pnu->pn_link;
126
    }
127
}
128
99
// See comment on member function declaration.
129
// See comment on member function declaration.
100
template <>
130
template <>
101
bool
131
bool
102
ParseContext<FullParseHandler>::define(TokenStream &ts,
132
ParseContext<FullParseHandler>::define(TokenStream &ts,
103
                                       HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
133
                                       HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
104
{
134
{
105
    JS_ASSERT(!pn->isUsed());
135
    JS_ASSERT(!pn->isUsed());
106
    JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
136
    JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
 Lines 145-160   ParseContext<FullParseHandler>::define(TokenStream &ts, Link Here 
145
    if (kind == Definition::CONST)
175
    if (kind == Definition::CONST)
146
        pn->pn_dflags |= PND_CONST;
176
        pn->pn_dflags |= PND_CONST;
147
177
148
    Definition *dn = (Definition *)pn;
178
    Definition *dn = (Definition *)pn;
149
    switch (kind) {
179
    switch (kind) {
150
      case Definition::ARG:
180
      case Definition::ARG:
151
        JS_ASSERT(sc->isFunctionBox());
181
        JS_ASSERT(sc->isFunctionBox());
152
        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG);
182
        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG);
183
        dn->pn_blockid = bodyid;
153
        dn->pn_dflags |= PND_BOUND;
184
        dn->pn_dflags |= PND_BOUND;
154
        if (!dn->pn_cookie.set(ts, staticLevel, args_.length()))
185
        if (!dn->pn_cookie.set(ts, staticLevel, args_.length()))
155
            return false;
186
            return false;
156
        if (!args_.append(dn))
187
        if (!args_.append(dn))
157
            return false;
188
            return false;
158
        if (args_.length() >= ARGNO_LIMIT) {
189
        if (args_.length() >= ARGNO_LIMIT) {
159
            ts.reportError(JSMSG_TOO_MANY_FUN_ARGS);
190
            ts.reportError(JSMSG_TOO_MANY_FUN_ARGS);
160
            return false;
191
            return false;
 Lines 164-210   ParseContext<FullParseHandler>::define(TokenStream &ts, Link Here 
164
        if (!decls_.addUnique(name, dn))
195
        if (!decls_.addUnique(name, dn))
165
            return false;
196
            return false;
166
        break;
197
        break;
167
198
168
      case Definition::CONST:
199
      case Definition::CONST:
169
      case Definition::VAR:
200
      case Definition::VAR:
170
        if (sc->isFunctionBox()) {
201
        if (sc->isFunctionBox()) {
171
            dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
202
            dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
203
            dn->pn_blockid = bodyid;
172
            dn->pn_dflags |= PND_BOUND;
204
            dn->pn_dflags |= PND_BOUND;
173
            if (!dn->pn_cookie.set(ts, staticLevel, vars_.length()))
205
            if (!dn->pn_cookie.set(ts, staticLevel, vars_.length()))
174
                return false;
206
                return false;
175
            if (!vars_.append(dn))
207
            if (!vars_.append(dn))
176
                return false;
208
                return false;
177
            if (vars_.length() >= LOCALNO_LIMIT) {
209
            if (!checkLocalsOverflow(ts))
178
                ts.reportError(JSMSG_TOO_MANY_LOCALS);
179
                return false;
210
                return false;
180
            }
181
        }
211
        }
182
        if (!decls_.addUnique(name, dn))
212
        if (!decls_.addUnique(name, dn))
183
            return false;
213
            return false;
184
        break;
214
        break;
185
215
186
      case Definition::LET:
216
      case Definition::LET:
187
        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
217
        dn->setOp(JSOP_INITLET);
188
        dn->pn_dflags |= (PND_LET | PND_BOUND);
218
        dn->pn_dflags |= (PND_LET | PND_BOUND);
189
        JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */
219
        JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */
220
        if (atBodyLevel()) {
221
            if (!bodyLevelLets_.append(dn))
222
                return false;
223
            if (!checkLocalsOverflow(ts))
224
                return false;
225
        }
226
227
        // In ES6, lets cannot be accessed until initialized. If the
228
        // definition has existing uses, they need to be marked so that we
229
        // emit dead zone checks.
230
        MarkUsesAsHoistedLet(pn);
231
190
        if (!decls_.addShadow(name, dn))
232
        if (!decls_.addShadow(name, dn))
191
            return false;
233
            return false;
192
        break;
234
        break;
193
235
194
      default:
236
      default:
195
        MOZ_CRASH("unexpected kind");
237
        MOZ_CRASH("unexpected kind");
196
    }
238
    }
197
239
198
    return true;
240
    return true;
199
}
241
}
200
242
201
template <>
243
template <>
202
bool
244
bool
245
ParseContext<SyntaxParseHandler>::checkLocalsOverflow(TokenStream &ts)
246
{
247
    return true;
248
}
249
250
template <>
251
bool
203
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
252
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
204
                                         Definition::Kind kind)
253
                                         Definition::Kind kind)
205
{
254
{
206
    JS_ASSERT(!decls_.lookupFirst(name));
255
    JS_ASSERT(!decls_.lookupFirst(name));
207
256
208
    if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
257
    if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
209
        lexdeps->remove(name);
258
        lexdeps->remove(name);
210
259
 Lines 273-288   static void Link Here 
273
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
322
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
274
{
323
{
275
    for (size_t i = 0; i < vec.length(); ++i, ++dst) {
324
    for (size_t i = 0; i < vec.length(); ++i, ++dst) {
276
        Definition *dn = vec[i];
325
        Definition *dn = vec[i];
277
        PropertyName *name = dn->name();
326
        PropertyName *name = dn->name();
278
327
279
        Binding::Kind kind;
328
        Binding::Kind kind;
280
        switch (dn->kind()) {
329
        switch (dn->kind()) {
330
          case Definition::LET:
331
            // Treat body-level let declarations as var bindings by falling
332
            // through. The fact that the binding is in fact a let declaration
333
            // is reflected in the slot. All body-level lets go after the
334
            // vars.
281
          case Definition::VAR:
335
          case Definition::VAR:
282
            kind = Binding::VARIABLE;
336
            kind = Binding::VARIABLE;
283
            break;
337
            break;
284
          case Definition::CONST:
338
          case Definition::CONST:
285
            kind = Binding::CONSTANT;
339
            kind = Binding::CONSTANT;
286
            break;
340
            break;
287
          case Definition::ARG:
341
          case Definition::ARG:
288
            kind = Binding::ARGUMENT;
342
            kind = Binding::ARGUMENT;
 Lines 308-344   AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec Link Here 
308
template <typename ParseHandler>
362
template <typename ParseHandler>
309
bool
363
bool
310
ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
364
ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
311
                                                     LifoAlloc &alloc,
365
                                                     LifoAlloc &alloc,
312
                                                     InternalHandle<Bindings*> bindings) const
366
                                                     InternalHandle<Bindings*> bindings) const
313
{
367
{
314
    JS_ASSERT(sc->isFunctionBox());
368
    JS_ASSERT(sc->isFunctionBox());
315
    JS_ASSERT(args_.length() < ARGNO_LIMIT);
369
    JS_ASSERT(args_.length() < ARGNO_LIMIT);
316
    JS_ASSERT(vars_.length() < LOCALNO_LIMIT);
370
    JS_ASSERT(vars_.length() + bodyLevelLets_.length() < LOCALNO_LIMIT);
317
371
318
    /*
372
    /*
319
     * Avoid pathological edge cases by explicitly limiting the total number of
373
     * Avoid pathological edge cases by explicitly limiting the total number of
320
     * bindings to what will fit in a uint32_t.
374
     * bindings to what will fit in a uint32_t.
321
     */
375
     */
322
    if (UINT32_MAX - args_.length() <= vars_.length())
376
    if (UINT32_MAX - args_.length() <= vars_.length() + bodyLevelLets_.length())
323
        return ts.reportError(JSMSG_TOO_MANY_LOCALS);
377
        return ts.reportError(JSMSG_TOO_MANY_LOCALS);
324
378
325
    uint32_t count = args_.length() + vars_.length();
379
    // Fix up the slots of body-level lets to come after the vars now that we
380
    // know how many vars there are.
381
    for (size_t i = 0; i < bodyLevelLets_.length(); i++) {
382
        Definition *dn = bodyLevelLets_[i];
383
        if (!dn->pn_cookie.set(ts, dn->pn_cookie.level(), vars_.length() + i))
384
            return false;
385
    }
386
387
    uint32_t count = args_.length() + vars_.length() + bodyLevelLets_.length();
326
    Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count);
388
    Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count);
327
    if (!packedBindings) {
389
    if (!packedBindings) {
328
        js_ReportOutOfMemory(cx);
390
        js_ReportOutOfMemory(cx);
329
        return false;
391
        return false;
330
    }
392
    }
331
393
332
    AppendPackedBindings(this, args_, packedBindings);
394
    AppendPackedBindings(this, args_, packedBindings);
333
    AppendPackedBindings(this, vars_, packedBindings + args_.length());
395
    AppendPackedBindings(this, vars_, packedBindings + args_.length());
396
    AppendPackedBindings(this, bodyLevelLets_, packedBindings + args_.length() + vars_.length());
334
397
335
    return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
398
    return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
336
                                              packedBindings, blockScopeDepth);
399
                                              bodyLevelLets_.length(), blockScopeDepth,
400
                                              packedBindings);
337
}
401
}
338
402
339
template <typename ParseHandler>
403
template <typename ParseHandler>
340
bool
404
bool
341
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
405
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
342
                                   unsigned errorNumber, va_list args)
406
                                   unsigned errorNumber, va_list args)
343
{
407
{
344
    bool result = false;
408
    bool result = false;
 Lines 973-990   Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ Link Here 
973
        return null();
1037
        return null();
974
1038
975
    return pn;
1039
    return pn;
976
}
1040
}
977
1041
978
/* See comment for use in Parser::functionDef. */
1042
/* See comment for use in Parser::functionDef. */
979
template <>
1043
template <>
980
bool
1044
bool
981
Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom)
1045
Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom,
1046
                                         bool *pbodyLevelHoistedUse)
982
{
1047
{
1048
    // See comment in addFreeVariablesFromLazyFunction.
1049
    *pbodyLevelHoistedUse = !!dn->dn_uses;
1050
983
    /* Turn pn into a definition. */
1051
    /* Turn pn into a definition. */
984
    pc->updateDecl(atom, pn);
1052
    pc->updateDecl(atom, pn);
985
1053
986
    /* Change all uses of dn to be uses of pn. */
1054
    /* Change all uses of dn to be uses of pn. */
987
    for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
1055
    for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
988
        JS_ASSERT(pnu->isUsed());
1056
        JS_ASSERT(pnu->isUsed());
989
        JS_ASSERT(!pnu->isDefn());
1057
        JS_ASSERT(!pnu->isDefn());
990
        pnu->pn_lexdef = (Definition *) pn;
1058
        pnu->pn_lexdef = (Definition *) pn;
 Lines 1070-1091   struct BindData Link Here 
1070
1138
1071
    struct LetData {
1139
    struct LetData {
1072
        explicit LetData(ExclusiveContext *cx) : blockObj(cx) {}
1140
        explicit LetData(ExclusiveContext *cx) : blockObj(cx) {}
1073
        VarContext varContext;
1141
        VarContext varContext;
1074
        RootedStaticBlockObject blockObj;
1142
        RootedStaticBlockObject blockObj;
1075
        unsigned   overflow;
1143
        unsigned   overflow;
1076
    } let;
1144
    } let;
1077
1145
1078
    void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) {
1146
    void initLet(VarContext varContext, StaticBlockObject *blockObj, unsigned overflow) {
1079
        this->pn = ParseHandler::null();
1147
        this->pn = ParseHandler::null();
1080
        this->op = JSOP_NOP;
1148
        this->op = JSOP_INITLET;
1081
        this->binder = Parser<ParseHandler>::bindLet;
1149
        this->binder = Parser<ParseHandler>::bindLet;
1082
        this->let.varContext = varContext;
1150
        this->let.varContext = varContext;
1083
        this->let.blockObj = &blockObj;
1151
        this->let.blockObj = blockObj;
1084
        this->let.overflow = overflow;
1152
        this->let.overflow = overflow;
1085
    }
1153
    }
1086
1154
1087
    void initVarOrConst(JSOp op) {
1155
    void initVarOrConst(JSOp op) {
1088
        this->op = op;
1156
        this->op = op;
1089
        this->binder = Parser<ParseHandler>::bindVarOrConst;
1157
        this->binder = Parser<ParseHandler>::bindVarOrConst;
1090
    }
1158
    }
1091
};
1159
};
 Lines 1187-1203   ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext<FullParseHandler Link Here 
1187
 * Beware: this function is called for functions nested in other functions or
1255
 * Beware: this function is called for functions nested in other functions or
1188
 * global scripts but not for functions compiled through the Function
1256
 * global scripts but not for functions compiled through the Function
1189
 * constructor or JSAPI. To always execute code when a function has finished
1257
 * constructor or JSAPI. To always execute code when a function has finished
1190
 * parsing, use Parser::functionBody.
1258
 * parsing, use Parser::functionBody.
1191
 */
1259
 */
1192
template <>
1260
template <>
1193
bool
1261
bool
1194
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc,
1262
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc,
1195
                                        FunctionSyntaxKind kind)
1263
                                        bool bodyLevelHoistedUse, FunctionSyntaxKind kind)
1196
{
1264
{
1197
    outerpc->blockidGen = pc->blockidGen;
1265
    outerpc->blockidGen = pc->blockidGen;
1198
1266
1199
    FunctionBox *funbox = fn->pn_funbox;
1267
    FunctionBox *funbox = fn->pn_funbox;
1200
    JS_ASSERT(funbox == pc->sc->asFunctionBox());
1268
    JS_ASSERT(funbox == pc->sc->asFunctionBox());
1201
1269
1202
    /* Propagate unresolved lexical names up to outerpc->lexdeps. */
1270
    /* Propagate unresolved lexical names up to outerpc->lexdeps. */
1203
    if (pc->lexdeps->count()) {
1271
    if (pc->lexdeps->count()) {
 Lines 1259-1274   Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHan Link Here 
1259
             * when leaving the inner function.
1327
             * when leaving the inner function.
1260
             *
1328
             *
1261
             * The dn == outer_dn case arises with generator expressions
1329
             * The dn == outer_dn case arises with generator expressions
1262
             * (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME
1330
             * (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME
1263
             * case), and nowhere else, currently.
1331
             * case), and nowhere else, currently.
1264
             */
1332
             */
1265
            if (dn != outer_dn) {
1333
            if (dn != outer_dn) {
1266
                if (ParseNode *pnu = dn->dn_uses) {
1334
                if (ParseNode *pnu = dn->dn_uses) {
1335
                    // In ES6, 'let' bindings cannot be accessed until
1336
                    // initialized. If we are parsing a function with a
1337
                    // hoisted body-level use, all free variables that get
1338
                    // linked to an outer 'let' binding need to be marked as
1339
                    // needing dead zone checks. e.g.,
1340
                    //
1341
                    // function outer() {
1342
                    //   inner();
1343
                    //   function inner() { use(x); }
1344
                    //   let x;
1345
                    // }
1346
                    //
1347
                    // The use of 'x' inside 'inner' needs to be marked.
1348
                    if (bodyLevelHoistedUse && outer_dn->isLet()) {
1349
                        while (true) {
1350
                            pnu->pn_dflags |= PND_LET;
1351
                            if (!pnu->pn_link)
1352
                                break;
1353
                            pnu = pnu->pn_link;
1354
                        }
1355
                        pnu = dn->dn_uses;
1356
                    }
1357
1267
                    while (true) {
1358
                    while (true) {
1268
                        pnu->pn_lexdef = outer_dn;
1359
                        pnu->pn_lexdef = outer_dn;
1269
                        if (!pnu->pn_link)
1360
                        if (!pnu->pn_link)
1270
                            break;
1361
                            break;
1271
                        pnu = pnu->pn_link;
1362
                        pnu = pnu->pn_link;
1272
                    }
1363
                    }
1273
                    pnu->pn_link = outer_dn->dn_uses;
1364
                    pnu->pn_link = outer_dn->dn_uses;
1274
                    outer_dn->dn_uses = dn->dn_uses;
1365
                    outer_dn->dn_uses = dn->dn_uses;
 Lines 1286-1307   Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHan Link Here 
1286
    InternalHandle<Bindings*> bindings =
1377
    InternalHandle<Bindings*> bindings =
1287
        InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
1378
        InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
1288
    return pc->generateFunctionBindings(context, tokenStream, alloc, bindings);
1379
    return pc->generateFunctionBindings(context, tokenStream, alloc, bindings);
1289
}
1380
}
1290
1381
1291
template <>
1382
template <>
1292
bool
1383
bool
1293
Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc,
1384
Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc,
1294
                                          FunctionSyntaxKind kind)
1385
                                          bool bodyLevelHoistedUse, FunctionSyntaxKind kind)
1295
{
1386
{
1296
    outerpc->blockidGen = pc->blockidGen;
1387
    outerpc->blockidGen = pc->blockidGen;
1297
1388
1298
    FunctionBox *funbox = pc->sc->asFunctionBox();
1389
    FunctionBox *funbox = pc->sc->asFunctionBox();
1299
    return addFreeVariablesFromLazyFunction(funbox->function(), outerpc);
1390
    return addFreeVariablesFromLazyFunction(funbox->function(), outerpc, bodyLevelHoistedUse);
1300
}
1391
}
1301
1392
1302
/*
1393
/*
1303
 * defineArg is called for both the arguments of a regular function definition
1394
 * defineArg is called for both the arguments of a regular function definition
1304
 * and the arguments specified by the Function constructor.
1395
 * and the arguments specified by the Function constructor.
1305
 *
1396
 *
1306
 * The 'disallowDuplicateArgs' bool indicates whether the use of another
1397
 * The 'disallowDuplicateArgs' bool indicates whether the use of another
1307
 * feature (destructuring or default arguments) disables duplicate arguments.
1398
 * feature (destructuring or default arguments) disables duplicate arguments.
 Lines 1562-1581   Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No Link Here 
1562
1653
1563
    return true;
1654
    return true;
1564
}
1655
}
1565
1656
1566
template <>
1657
template <>
1567
bool
1658
bool
1568
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
1659
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
1569
                                                  ParseNode **pn_, FunctionSyntaxKind kind,
1660
                                                  ParseNode **pn_, FunctionSyntaxKind kind,
1570
                                                  bool *pbodyProcessed)
1661
                                                  bool *pbodyProcessed,
1662
                                                  bool *pbodyLevelHoistedUse)
1571
{
1663
{
1572
    ParseNode *&pn = *pn_;
1664
    ParseNode *&pn = *pn_;
1573
    *pbodyProcessed = false;
1665
    *pbodyProcessed = false;
1666
    *pbodyLevelHoistedUse = false;
1574
1667
1575
    /* Function statements add a binding to the enclosing scope. */
1668
    /* Function statements add a binding to the enclosing scope. */
1576
    bool bodyLevel = pc->atBodyLevel();
1669
    bool bodyLevel = pc->atBodyLevel();
1577
1670
1578
    if (kind == Statement) {
1671
    if (kind == Statement) {
1579
        /*
1672
        /*
1580
         * Handle redeclaration and optimize cases where we can statically bind the
1673
         * Handle redeclaration and optimize cases where we can statically bind the
1581
         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
1674
         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
 Lines 1612-1628   Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName, Link Here 
1612
                    // remains a definition. But change the function node pn so
1705
                    // remains a definition. But change the function node pn so
1613
                    // that it knows where the argument is located.
1706
                    // that it knows where the argument is located.
1614
                    pn->setOp(JSOP_GETARG);
1707
                    pn->setOp(JSOP_GETARG);
1615
                    pn->setDefn(true);
1708
                    pn->setDefn(true);
1616
                    pn->pn_cookie = dn->pn_cookie;
1709
                    pn->pn_cookie = dn->pn_cookie;
1617
                    pn->pn_dflags |= PND_BOUND;
1710
                    pn->pn_dflags |= PND_BOUND;
1618
                    dn->markAsAssigned();
1711
                    dn->markAsAssigned();
1619
                } else {
1712
                } else {
1620
                    if (!makeDefIntoUse(dn, pn, funName))
1713
                    if (!makeDefIntoUse(dn, pn, funName, pbodyLevelHoistedUse))
1621
                        return false;
1714
                        return false;
1622
                }
1715
                }
1623
            }
1716
            }
1624
        } else if (bodyLevel) {
1717
        } else if (bodyLevel) {
1625
            /*
1718
            /*
1626
             * If this function was used before it was defined, claim the
1719
             * If this function was used before it was defined, claim the
1627
             * pre-created definition node for this function that primaryExpr
1720
             * pre-created definition node for this function that primaryExpr
1628
             * put in pc->lexdeps on first forward reference, and recycle pn.
1721
             * put in pc->lexdeps on first forward reference, and recycle pn.
 Lines 1635-1650   Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName, Link Here 
1635
                fn->pn_pos.end = pn->pn_pos.end;
1728
                fn->pn_pos.end = pn->pn_pos.end;
1636
1729
1637
                fn->pn_body = nullptr;
1730
                fn->pn_body = nullptr;
1638
                fn->pn_cookie.makeFree();
1731
                fn->pn_cookie.makeFree();
1639
1732
1640
                pc->lexdeps->remove(funName);
1733
                pc->lexdeps->remove(funName);
1641
                handler.freeTree(pn);
1734
                handler.freeTree(pn);
1642
                pn = fn;
1735
                pn = fn;
1736
1737
                *pbodyLevelHoistedUse = true;
1643
            }
1738
            }
1644
1739
1645
            if (!pc->define(tokenStream, funName, pn, Definition::VAR))
1740
            if (!pc->define(tokenStream, funName, pn, Definition::VAR))
1646
                return false;
1741
                return false;
1647
        }
1742
        }
1648
1743
1649
        if (bodyLevel) {
1744
        if (bodyLevel) {
1650
            JS_ASSERT(pn->functionIsHoisted());
1745
            JS_ASSERT(pn->functionIsHoisted());
 Lines 1703-1719   Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName, Link Here 
1703
    if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
1798
    if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
1704
        JSFunction *fun = handler.nextLazyInnerFunction();
1799
        JSFunction *fun = handler.nextLazyInnerFunction();
1705
        JS_ASSERT(!fun->isLegacyGenerator());
1800
        JS_ASSERT(!fun->isLegacyGenerator());
1706
        FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
1801
        FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
1707
                                             fun->generatorKind());
1802
                                             fun->generatorKind());
1708
        if (!funbox)
1803
        if (!funbox)
1709
            return false;
1804
            return false;
1710
1805
1711
        if (!addFreeVariablesFromLazyFunction(fun, pc))
1806
        if (!addFreeVariablesFromLazyFunction(fun, pc, *pbodyLevelHoistedUse))
1712
            return false;
1807
            return false;
1713
1808
1714
        // The position passed to tokenStream.advance() is relative to
1809
        // The position passed to tokenStream.advance() is relative to
1715
        // userbuf.base() while LazyScript::{begin,end} offsets are relative to
1810
        // userbuf.base() while LazyScript::{begin,end} offsets are relative to
1716
        // the outermost script source. N.B: userbuf.base() is initialized
1811
        // the outermost script source. N.B: userbuf.base() is initialized
1717
        // (in TokenStream()) to begin() - column() so that column numbers in
1812
        // (in TokenStream()) to begin() - column() so that column numbers in
1718
        // the lazily parsed script are correct.
1813
        // the lazily parsed script are correct.
1719
        uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column();
1814
        uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column();
 Lines 1734-1786   PropagateTransitiveParseFlags(const T *inner, U *outer) Link Here 
1734
     outer->setBindingsAccessedDynamically();
1829
     outer->setBindingsAccessedDynamically();
1735
   if (inner->hasDebuggerStatement())
1830
   if (inner->hasDebuggerStatement())
1736
     outer->setHasDebuggerStatement();
1831
     outer->setHasDebuggerStatement();
1737
}
1832
}
1738
1833
1739
template <typename ParseHandler>
1834
template <typename ParseHandler>
1740
bool
1835
bool
1741
Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun,
1836
Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun,
1742
                                                       ParseContext<ParseHandler> *pc)
1837
                                                       ParseContext<ParseHandler> *pc,
1838
                                                       bool bodyLevelHoistedUse)
1743
{
1839
{
1840
    MOZ_ASSERT_IF(bodyLevelHoistedUse, fun->displayAtom() && pc->atBodyLevel());
1841
1744
    // Update any definition nodes in this context according to free variables
1842
    // Update any definition nodes in this context according to free variables
1745
    // in a lazily parsed inner function.
1843
    // in a lazily parsed inner function.
1746
1844
1747
    LazyScript *lazy = fun->lazyScript();
1845
    LazyScript *lazy = fun->lazyScript();
1748
    HeapPtrAtom *freeVariables = lazy->freeVariables();
1846
    LazyScript::FreeVariable *freeVariables = lazy->freeVariables();
1749
    for (size_t i = 0; i < lazy->numFreeVariables(); i++) {
1847
    for (size_t i = 0; i < lazy->numFreeVariables(); i++) {
1750
        JSAtom *atom = freeVariables[i];
1848
        JSAtom *atom = freeVariables[i].atom();
1751
1849
1752
        // 'arguments' will be implicitly bound within the inner function.
1850
        // 'arguments' will be implicitly bound within the inner function.
1753
        if (atom == context->names().arguments)
1851
        if (atom == context->names().arguments)
1754
            continue;
1852
            continue;
1755
1853
1756
        DefinitionNode dn = pc->decls().lookupFirst(atom);
1854
        DefinitionNode dn = pc->decls().lookupFirst(atom);
1757
1855
1758
        if (!dn) {
1856
        if (!dn) {
1759
            dn = getOrCreateLexicalDependency(pc, atom);
1857
            dn = getOrCreateLexicalDependency(pc, atom);
1760
            if (!dn)
1858
            if (!dn)
1761
                return false;
1859
                return false;
1762
        }
1860
        }
1763
1861
1862
        // In ES6, lets are unaccessible before initialization. If the inner
1863
        // function closes over a placeholder definition, we need to mark the
1864
        // variable as maybe needing a dead zone check when we emit bytecode.
1865
        //
1866
        // Note that body-level function declaration statements are always
1867
        // hoisted to the top, so all accesses to free let variables need the
1868
        // dead zone check.
1869
        if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse)
1870
            freeVariables[i].setIsHoistedUse();
1871
1764
        /* Mark the outer dn as escaping. */
1872
        /* Mark the outer dn as escaping. */
1765
        handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED);
1873
        handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED);
1766
    }
1874
    }
1767
1875
1768
    PropagateTransitiveParseFlags(lazy, pc->sc);
1876
    PropagateTransitiveParseFlags(lazy, pc->sc);
1769
    return true;
1877
    return true;
1770
}
1878
}
1771
1879
1772
template <>
1880
template <>
1773
bool
1881
bool
1774
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
1882
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
1775
                                                    Node *pn, FunctionSyntaxKind kind,
1883
                                                    Node *pn, FunctionSyntaxKind kind,
1776
                                                    bool *pbodyProcessed)
1884
                                                    bool *pbodyProcessed,
1885
                                                    bool *pbodyLevelHoistedUse)
1777
{
1886
{
1778
    *pbodyProcessed = false;
1887
    *pbodyProcessed = false;
1888
    *pbodyLevelHoistedUse = false;
1779
1889
1780
    /* Function statements add a binding to the enclosing scope. */
1890
    /* Function statements add a binding to the enclosing scope. */
1781
    bool bodyLevel = pc->atBodyLevel();
1891
    bool bodyLevel = pc->atBodyLevel();
1782
1892
1783
    if (kind == Statement) {
1893
    if (kind == Statement) {
1784
        /*
1894
        /*
1785
         * Handle redeclaration and optimize cases where we can statically bind the
1895
         * Handle redeclaration and optimize cases where we can statically bind the
1786
         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
1896
         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
 Lines 1791-1808   Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName, Link Here 
1791
                if (!AtomToPrintableString(context, funName, &name) ||
1901
                if (!AtomToPrintableString(context, funName, &name) ||
1792
                    !report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
1902
                    !report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
1793
                            Definition::kindString(dn), name.ptr()))
1903
                            Definition::kindString(dn), name.ptr()))
1794
                {
1904
                {
1795
                    return false;
1905
                    return false;
1796
                }
1906
                }
1797
            }
1907
            }
1798
        } else if (bodyLevel) {
1908
        } else if (bodyLevel) {
1799
            if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName))
1909
            if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName)) {
1910
                *pbodyLevelHoistedUse = true;
1800
                pc->lexdeps->remove(funName);
1911
                pc->lexdeps->remove(funName);
1912
            }
1801
1913
1802
            if (!pc->define(tokenStream, funName, *pn, Definition::VAR))
1914
            if (!pc->define(tokenStream, funName, *pn, Definition::VAR))
1803
                return false;
1915
                return false;
1804
        }
1916
        }
1805
1917
1806
        if (!bodyLevel && funName == context->names().arguments)
1918
        if (!bodyLevel && funName == context->names().arguments)
1807
            pc->sc->setBindingsAccessedDynamically();
1919
            pc->sc->setBindingsAccessedDynamically();
1808
    }
1920
    }
 Lines 1891-1907   Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream: Link Here 
1891
    JS_ASSERT_IF(kind == Statement, funName);
2003
    JS_ASSERT_IF(kind == Statement, funName);
1892
2004
1893
    /* Make a TOK_FUNCTION node. */
2005
    /* Make a TOK_FUNCTION node. */
1894
    Node pn = handler.newFunctionDefinition();
2006
    Node pn = handler.newFunctionDefinition();
1895
    if (!pn)
2007
    if (!pn)
1896
        return null();
2008
        return null();
1897
2009
1898
    bool bodyProcessed;
2010
    bool bodyProcessed;
1899
    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed))
2011
    bool bodyLevelHoistedUse;
2012
    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed, &bodyLevelHoistedUse))
1900
        return null();
2013
        return null();
1901
2014
1902
    if (bodyProcessed)
2015
    if (bodyProcessed)
1903
        return pn;
2016
        return pn;
1904
2017
1905
    RootedObject proto(context);
2018
    RootedObject proto(context);
1906
    if (generatorKind == StarGenerator) {
2019
    if (generatorKind == StarGenerator) {
1907
        // If we are off the main thread, the generator meta-objects have
2020
        // If we are off the main thread, the generator meta-objects have
 Lines 1919-1935   Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream: Link Here 
1919
    // Speculatively parse using the directives of the parent parsing context.
2032
    // Speculatively parse using the directives of the parent parsing context.
1920
    // If a directive is encountered (e.g., "use strict") that changes how the
2033
    // If a directive is encountered (e.g., "use strict") that changes how the
1921
    // function should have been parsed, we backup and reparse with the new set
2034
    // function should have been parsed, we backup and reparse with the new set
1922
    // of directives.
2035
    // of directives.
1923
    Directives directives(pc);
2036
    Directives directives(pc);
1924
    Directives newDirectives = directives;
2037
    Directives newDirectives = directives;
1925
2038
1926
    while (true) {
2039
    while (true) {
1927
        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives))
2040
        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives,
2041
                                bodyLevelHoistedUse))
1928
            break;
2042
            break;
1929
        if (tokenStream.hadError() || directives == newDirectives)
2043
        if (tokenStream.hadError() || directives == newDirectives)
1930
            return null();
2044
            return null();
1931
2045
1932
        // Assignment must be monotonic to prevent reparsing iloops
2046
        // Assignment must be monotonic to prevent reparsing iloops
1933
        JS_ASSERT_IF(directives.strict(), newDirectives.strict());
2047
        JS_ASSERT_IF(directives.strict(), newDirectives.strict());
1934
        JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
2048
        JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
1935
        directives = newDirectives;
2049
        directives = newDirectives;
 Lines 2010-2029   Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbo Link Here 
2010
2124
2011
    RootedFunction fun(context, funbox->function());
2125
    RootedFunction fun(context, funbox->function());
2012
    LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
2126
    LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
2013
                                             versionNumber(), funbox->bufStart, funbox->bufEnd,
2127
                                             versionNumber(), funbox->bufStart, funbox->bufEnd,
2014
                                             funbox->startLine, funbox->startColumn);
2128
                                             funbox->startLine, funbox->startColumn);
2015
    if (!lazy)
2129
    if (!lazy)
2016
        return false;
2130
        return false;
2017
2131
2018
    HeapPtrAtom *freeVariables = lazy->freeVariables();
2132
    LazyScript::FreeVariable *freeVariables = lazy->freeVariables();
2019
    size_t i = 0;
2133
    size_t i = 0;
2020
    for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
2134
    for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
2021
        freeVariables[i++].init(r.front().key());
2135
        freeVariables[i++] = LazyScript::FreeVariable(r.front().key());
2022
    JS_ASSERT(i == numFreeVariables);
2136
    JS_ASSERT(i == numFreeVariables);
2023
2137
2024
    HeapPtrFunction *innerFunctions = lazy->innerFunctions();
2138
    HeapPtrFunction *innerFunctions = lazy->innerFunctions();
2025
    for (size_t i = 0; i < numInnerFunctions; i++)
2139
    for (size_t i = 0; i < numInnerFunctions; i++)
2026
        innerFunctions[i].init(pc->innerFunctions[i]);
2140
        innerFunctions[i].init(pc->innerFunctions[i]);
2027
2141
2028
    if (pc->sc->strict)
2142
    if (pc->sc->strict)
2029
        lazy->setStrict();
2143
        lazy->setStrict();
 Lines 2037-2053   Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbo Link Here 
2037
}
2151
}
2038
2152
2039
template <>
2153
template <>
2040
bool
2154
bool
2041
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
2155
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
2042
                                              FunctionType type, FunctionSyntaxKind kind,
2156
                                              FunctionType type, FunctionSyntaxKind kind,
2043
                                              GeneratorKind generatorKind,
2157
                                              GeneratorKind generatorKind,
2044
                                              Directives inheritedDirectives,
2158
                                              Directives inheritedDirectives,
2045
                                              Directives *newDirectives)
2159
                                              Directives *newDirectives,
2160
                                              bool bodyLevelHoistedUse)
2046
{
2161
{
2047
    ParseContext<FullParseHandler> *outerpc = pc;
2162
    ParseContext<FullParseHandler> *outerpc = pc;
2048
2163
2049
    // Create box for fun->object early to protect against last-ditch GC.
2164
    // Create box for fun->object early to protect against last-ditch GC.
2050
    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
2165
    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
2051
    if (!funbox)
2166
    if (!funbox)
2052
        return false;
2167
        return false;
2053
2168
 Lines 2061-2078   Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, Link Here 
2061
            // Move the syntax parser to the current position in the stream.
2176
            // Move the syntax parser to the current position in the stream.
2062
            TokenStream::Position position(keepAtoms);
2177
            TokenStream::Position position(keepAtoms);
2063
            tokenStream.tell(&position);
2178
            tokenStream.tell(&position);
2064
            if (!parser->tokenStream.seek(position, tokenStream))
2179
            if (!parser->tokenStream.seek(position, tokenStream))
2065
                return false;
2180
                return false;
2066
2181
2067
            ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
2182
            ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
2068
                                                   newDirectives, outerpc->staticLevel + 1,
2183
                                                   newDirectives, outerpc->staticLevel + 1,
2069
                                                   outerpc->blockidGen,
2184
                                                   outerpc->blockidGen, /* blockScopeDepth = */ 0);
2070
                                                   /* blockScopeDepth = */ 0);
2071
            if (!funpc.init(tokenStream))
2185
            if (!funpc.init(tokenStream))
2072
                return false;
2186
                return false;
2073
2187
2074
            if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
2188
            if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
2075
                                                    fun, type, kind, newDirectives))
2189
                                                    fun, type, kind, newDirectives))
2076
            {
2190
            {
2077
                if (parser->hadAbortedSyntaxParse()) {
2191
                if (parser->hadAbortedSyntaxParse()) {
2078
                    // Try again with a full parse.
2192
                    // Try again with a full parse.
 Lines 2088-2104   Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, Link Here 
2088
            parser->tokenStream.tell(&position);
2202
            parser->tokenStream.tell(&position);
2089
            if (!tokenStream.seek(position, parser->tokenStream))
2203
            if (!tokenStream.seek(position, parser->tokenStream))
2090
                return false;
2204
                return false;
2091
2205
2092
            // Update the end position of the parse node.
2206
            // Update the end position of the parse node.
2093
            pn->pn_pos.end = tokenStream.currentToken().pos.end;
2207
            pn->pn_pos.end = tokenStream.currentToken().pos.end;
2094
        }
2208
        }
2095
2209
2096
        if (!addFreeVariablesFromLazyFunction(fun, pc))
2210
        if (!addFreeVariablesFromLazyFunction(fun, pc, bodyLevelHoistedUse))
2097
            return false;
2211
            return false;
2098
2212
2099
        pn->pn_blockid = outerpc->blockid();
2213
        pn->pn_blockid = outerpc->blockid();
2100
        PropagateTransitiveParseFlags(funbox, outerpc->sc);
2214
        PropagateTransitiveParseFlags(funbox, outerpc->sc);
2101
        return true;
2215
        return true;
2102
    } while (false);
2216
    } while (false);
2103
2217
2104
    // Continue doing a full parse for this inner function.
2218
    // Continue doing a full parse for this inner function.
 Lines 2106-2122   Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, Link Here 
2106
                                         outerpc->staticLevel + 1, outerpc->blockidGen,
2220
                                         outerpc->staticLevel + 1, outerpc->blockidGen,
2107
                                         /* blockScopeDepth = */ 0);
2221
                                         /* blockScopeDepth = */ 0);
2108
    if (!funpc.init(tokenStream))
2222
    if (!funpc.init(tokenStream))
2109
        return false;
2223
        return false;
2110
2224
2111
    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
2225
    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
2112
        return false;
2226
        return false;
2113
2227
2114
    if (!leaveFunction(pn, outerpc, kind))
2228
    if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind))
2115
        return false;
2229
        return false;
2116
2230
2117
    pn->pn_blockid = outerpc->blockid();
2231
    pn->pn_blockid = outerpc->blockid();
2118
2232
2119
    /*
2233
    /*
2120
     * Fruit of the poisonous tree: if a closure contains a dynamic name access
2234
     * Fruit of the poisonous tree: if a closure contains a dynamic name access
2121
     * (eval, with, etc), we consider the parent to do the same. The reason is
2235
     * (eval, with, etc), we consider the parent to do the same. The reason is
2122
     * that the deoptimizing effects of dynamic name access apply equally to
2236
     * that the deoptimizing effects of dynamic name access apply equally to
 Lines 2127-2143   Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, Link Here 
2127
}
2241
}
2128
2242
2129
template <>
2243
template <>
2130
bool
2244
bool
2131
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
2245
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
2132
                                                FunctionType type, FunctionSyntaxKind kind,
2246
                                                FunctionType type, FunctionSyntaxKind kind,
2133
                                                GeneratorKind generatorKind,
2247
                                                GeneratorKind generatorKind,
2134
                                                Directives inheritedDirectives,
2248
                                                Directives inheritedDirectives,
2135
                                                Directives *newDirectives)
2249
                                                Directives *newDirectives,
2250
                                                bool bodyLevelHoistedUse)
2136
{
2251
{
2137
    ParseContext<SyntaxParseHandler> *outerpc = pc;
2252
    ParseContext<SyntaxParseHandler> *outerpc = pc;
2138
2253
2139
    // Create box for fun->object early to protect against last-ditch GC.
2254
    // Create box for fun->object early to protect against last-ditch GC.
2140
    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
2255
    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
2141
    if (!funbox)
2256
    if (!funbox)
2142
        return false;
2257
        return false;
2143
2258
 Lines 2146-2162   Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun, Link Here 
2146
                                           outerpc->staticLevel + 1, outerpc->blockidGen,
2261
                                           outerpc->staticLevel + 1, outerpc->blockidGen,
2147
                                           /* blockScopeDepth = */ 0);
2262
                                           /* blockScopeDepth = */ 0);
2148
    if (!funpc.init(tokenStream))
2263
    if (!funpc.init(tokenStream))
2149
        return false;
2264
        return false;
2150
2265
2151
    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
2266
    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
2152
        return false;
2267
        return false;
2153
2268
2154
    if (!leaveFunction(pn, outerpc, kind))
2269
    if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind))
2155
        return false;
2270
        return false;
2156
2271
2157
    // This is a lazy function inner to another lazy function. Remember the
2272
    // This is a lazy function inner to another lazy function. Remember the
2158
    // inner function so that if the outer function is eventually parsed we do
2273
    // inner function so that if the outer function is eventually parsed we do
2159
    // not need any further parsing or processing of the inner function.
2274
    // not need any further parsing or processing of the inner function.
2160
    JS_ASSERT(fun->lazyScript());
2275
    JS_ASSERT(fun->lazyScript());
2161
    return outerpc->innerFunctions.append(fun);
2276
    return outerpc->innerFunctions.append(fun);
2162
}
2277
}
 Lines 2650-2707   Parser<FullParseHandler>::bindLet(BindData<FullParseHandler> *data, Link Here 
2650
                                  HandlePropertyName name, Parser<FullParseHandler> *parser)
2765
                                  HandlePropertyName name, Parser<FullParseHandler> *parser)
2651
{
2766
{
2652
    ParseContext<FullParseHandler> *pc = parser->pc;
2767
    ParseContext<FullParseHandler> *pc = parser->pc;
2653
    ParseNode *pn = data->pn;
2768
    ParseNode *pn = data->pn;
2654
    if (!parser->checkStrictBinding(name, pn))
2769
    if (!parser->checkStrictBinding(name, pn))
2655
        return false;
2770
        return false;
2656
2771
2657
    ExclusiveContext *cx = parser->context;
2772
    ExclusiveContext *cx = parser->context;
2658
2659
    Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
2773
    Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
2660
    unsigned index = blockObj->numVariables();
2774
2661
    if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) {
2775
    unsigned index;
2662
        parser->report(ParseError, false, pn, data->let.overflow);
2776
    if (blockObj) {
2663
        return false;
2777
        index = blockObj->numVariables();
2778
        if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) {
2779
            parser->report(ParseError, false, pn, data->let.overflow);
2780
            return false;
2781
        }
2782
    } else {
2783
        // If we don't have a block object, we are parsing a body-level let,
2784
        // in which case we use a bogus index. See comment block below in
2785
        // setting the pn_cookie for explanation on how it gets adjusted.
2786
        index = 0;
2664
    }
2787
    }
2665
2788
2666
    /*
2789
    // For block-level lets, assign block-local index to pn->pn_cookie right
2667
     * Assign block-local index to pn->pn_cookie right away, encoding it as an
2790
    // away, encoding it as an upvar cookie whose skip tells the current
2668
     * upvar cookie whose skip tells the current static level. The emitter will
2791
    // static level. The emitter will adjust the node's slot based on its
2669
     * adjust the node's slot based on its stack depth model -- and, for global
2792
    // stack depth model -- and, for global and eval code,
2670
     * and eval code, js::frontend::CompileScript will adjust the slot
2793
    // js::frontend::CompileScript will adjust the slot again to include
2671
     * again to include script->nfixed.
2794
    // script->nfixed and body-level lets.
2672
     */
2795
    //
2796
    // For body-level lets, the index is bogus at this point and is adjusted
2797
    // when creating Bindings. See ParseContext::generateFunctionBindings.
2673
    if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index))
2798
    if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index))
2674
        return false;
2799
        return false;
2675
2800
2676
    /*
2801
    /*
2677
     * For bindings that are hoisted to the beginning of the block/function,
2802
     * For bindings that are hoisted to the beginning of the block/function,
2678
     * define() right now. Otherwise, delay define until PushLetScope.
2803
     * define() right now. Otherwise, delay define until PushLetScope.
2679
     */
2804
     */
2680
    if (data->let.varContext == HoistVars) {
2805
    if (data->let.varContext == HoistVars) {
2681
        JS_ASSERT(!pc->atBodyLevel());
2682
        Definition *dn = pc->decls().lookupFirst(name);
2806
        Definition *dn = pc->decls().lookupFirst(name);
2683
        if (dn && dn->pn_blockid == pc->blockid())
2807
        if (dn && dn->pn_blockid == pc->blockid())
2684
            return parser->reportRedeclaration(pn, dn->isConst(), name);
2808
            return parser->reportRedeclaration(pn, dn->isConst(), name);
2685
        if (!pc->define(parser->tokenStream, name, pn, Definition::LET))
2809
        if (!pc->define(parser->tokenStream, name, pn, Definition::LET))
2686
            return false;
2810
            return false;
2687
    }
2811
    }
2688
2812
2689
    bool redeclared;
2813
    if (blockObj) {
2690
    RootedId id(cx, NameToId(name));
2814
        bool redeclared;
2691
    RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared));
2815
        RootedId id(cx, NameToId(name));
2692
    if (!shape) {
2816
        RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared));
2693
        if (redeclared)
2817
        if (!shape) {
2694
            parser->reportRedeclaration(pn, false, name);
2818
            if (redeclared)
2695
        return false;
2819
                parser->reportRedeclaration(pn, false, name);
2820
            return false;
2821
        }
2822
2823
        /* Store pn in the static block object. */
2824
        blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition *>(pn));
2825
    } else {
2826
        // Body-level lets are hoisted and need to have been defined via
2827
        // pc->define above.
2828
        MOZ_ASSERT(data->let.varContext == HoistVars);
2829
        MOZ_ASSERT(pc->decls().lookupFirst(name));
2696
    }
2830
    }
2697
2831
2698
    /* Store pn in the static block object. */
2699
    blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition *>(pn));
2700
    return true;
2832
    return true;
2701
}
2833
}
2702
2834
2703
template <>
2835
template <>
2704
/* static */ bool
2836
/* static */ bool
2705
Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data,
2837
Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data,
2706
                                    HandlePropertyName name, Parser<SyntaxParseHandler> *parser)
2838
                                    HandlePropertyName name, Parser<SyntaxParseHandler> *parser)
2707
{
2839
{
 Lines 2978-2995   Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn) Link Here 
2978
         */
3110
         */
2979
        dn = getOrCreateLexicalDependency(pc, name);
3111
        dn = getOrCreateLexicalDependency(pc, name);
2980
        if (!dn)
3112
        if (!dn)
2981
            return false;
3113
            return false;
2982
    }
3114
    }
2983
3115
2984
    handler.linkUseToDef(pn, dn);
3116
    handler.linkUseToDef(pn, dn);
2985
3117
2986
    if (stmt && stmt->type == STMT_WITH)
3118
    if (stmt) {
2987
        handler.setFlag(pn, PND_DEOPTIMIZED);
3119
        if (stmt->type == STMT_WITH) {
3120
            handler.setFlag(pn, PND_DEOPTIMIZED);
3121
        } else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) {
3122
            // See comments above StmtInfoPC and switchStatement for how
3123
            // firstDominatingLetInCase is computed.
3124
            MOZ_ASSERT(stmt->firstDominatingLetInCase <= stmt->staticBlock().numVariables());
3125
            handler.markMaybeUninitializedLetUseInSwitch(pn, dn, stmt->firstDominatingLetInCase);
3126
        }
3127
    }
2988
3128
2989
    return true;
3129
    return true;
2990
}
3130
}
2991
3131
2992
template <>
3132
template <>
2993
bool
3133
bool
2994
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn)
3134
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn)
2995
{
3135
{
 Lines 3000-3016   Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, Link Here 
3000
    data->pn = pn;
3140
    data->pn = pn;
3001
    if (!data->binder(data, name, this))
3141
    if (!data->binder(data, name, this))
3002
        return false;
3142
        return false;
3003
3143
3004
    /*
3144
    /*
3005
     * Select the appropriate name-setting opcode, respecting eager selection
3145
     * Select the appropriate name-setting opcode, respecting eager selection
3006
     * done by the data->binder function.
3146
     * done by the data->binder function.
3007
     */
3147
     */
3008
    if (pn->pn_dflags & PND_BOUND)
3148
    if (data->op == JSOP_INITLET)
3149
        pn->setOp(JSOP_INITLET);
3150
    else if (pn->pn_dflags & PND_BOUND)
3009
        pn->setOp(JSOP_SETLOCAL);
3151
        pn->setOp(JSOP_SETLOCAL);
3010
    else if (data->op == JSOP_DEFCONST)
3152
    else if (data->op == JSOP_DEFCONST)
3011
        pn->setOp(JSOP_SETCONST);
3153
        pn->setOp(JSOP_SETCONST);
3012
    else
3154
    else
3013
        pn->setOp(JSOP_SETNAME);
3155
        pn->setOp(JSOP_SETNAME);
3014
3156
3015
    if (data->op == JSOP_DEFCONST)
3157
    if (data->op == JSOP_DEFCONST)
3016
        pn->pn_dflags |= PND_CONST;
3158
        pn->pn_dflags |= PND_CONST;
 Lines 3394-3423   Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple, Link Here 
3394
    JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_CALL);
3536
    JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_CALL);
3395
3537
3396
    /*
3538
    /*
3397
     * The simple flag is set if the declaration has the form 'var x', with
3539
     * The simple flag is set if the declaration has the form 'var x', with
3398
     * only one variable declared and no initializer expression.
3540
     * only one variable declared and no initializer expression.
3399
     */
3541
     */
3400
    JS_ASSERT_IF(psimple, *psimple);
3542
    JS_ASSERT_IF(psimple, *psimple);
3401
3543
3402
    JSOp op = blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST;
3544
    JSOp op = kind == PNK_LET ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST;
3403
3545
3404
    Node pn = handler.newList(kind, null(), op);
3546
    Node pn = handler.newList(kind, null(), op);
3405
    if (!pn)
3547
    if (!pn)
3406
        return null();
3548
        return null();
3407
3549
3408
    /*
3550
    /*
3409
     * SpiderMonkey const is really "write once per initialization evaluation"
3551
     * SpiderMonkey const is really "write once per initialization evaluation"
3410
     * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
3552
     * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
3411
     * this code will change soon.
3553
     * this code will change soon.
3412
     */
3554
     */
3413
    BindData<ParseHandler> data(context);
3555
    BindData<ParseHandler> data(context);
3414
    if (blockObj)
3556
    if (kind == PNK_LET)
3415
        data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS);
3557
        data.initLet(varContext, blockObj, JSMSG_TOO_MANY_LOCALS);
3416
    else
3558
    else
3417
        data.initVarOrConst(op);
3559
        data.initVarOrConst(op);
3418
3560
3419
    bool first = true;
3561
    bool first = true;
3420
    Node pn2;
3562
    Node pn2;
3421
    do {
3563
    do {
3422
        if (psimple && !first)
3564
        if (psimple && !first)
3423
            *psimple = false;
3565
            *psimple = false;
 Lines 3429-3459   Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple, Link Here 
3429
                *psimple = false;
3571
                *psimple = false;
3430
3572
3431
            pc->inDeclDestructuring = true;
3573
            pc->inDeclDestructuring = true;
3432
            pn2 = primaryExpr(tt);
3574
            pn2 = primaryExpr(tt);
3433
            pc->inDeclDestructuring = false;
3575
            pc->inDeclDestructuring = false;
3434
            if (!pn2)
3576
            if (!pn2)
3435
                return null();
3577
                return null();
3436
3578
3437
            if (!checkDestructuring(&data, pn2))
3438
                return null();
3439
            bool ignored;
3579
            bool ignored;
3440
            if (pc->parsingForInit && matchInOrOf(&ignored)) {
3580
            bool parsingForInOrOfInit = pc->parsingForInit && matchInOrOf(&ignored);
3581
3582
            // See comment below for bindBeforeInitializer in the code that
3583
            // handles the non-destructuring case.
3584
            bool bindBeforeInitializer = kind != PNK_LET || parsingForInOrOfInit;
3585
            if (bindBeforeInitializer && !checkDestructuring(&data, pn2))
3586
                return null();
3587
3588
            if (parsingForInOrOfInit) {
3441
                tokenStream.ungetToken();
3589
                tokenStream.ungetToken();
3442
                handler.addList(pn, pn2);
3590
                handler.addList(pn, pn2);
3443
                continue;
3591
                continue;
3444
            }
3592
            }
3445
3593
3446
            MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
3594
            MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
3447
3595
3448
            Node init = assignExpr();
3596
            Node init = assignExpr();
3449
            if (!init)
3597
            if (!init)
3450
                return null();
3598
                return null();
3451
3599
3600
            if (!bindBeforeInitializer && !checkDestructuring(&data, pn2))
3601
                return null();
3602
3452
            pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
3603
            pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
3453
            if (!pn2)
3604
            if (!pn2)
3454
                return null();
3605
                return null();
3455
            handler.addList(pn, pn2);
3606
            handler.addList(pn, pn2);
3456
            continue;
3607
            continue;
3457
        }
3608
        }
3458
3609
3459
        if (tt != TOK_NAME) {
3610
        if (tt != TOK_NAME) {
 Lines 3469-3499   Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple, Link Here 
3469
3620
3470
        RootedPropertyName name(context, tokenStream.currentName());
3621
        RootedPropertyName name(context, tokenStream.currentName());
3471
        pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
3622
        pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
3472
        if (!pn2)
3623
        if (!pn2)
3473
            return null();
3624
            return null();
3474
        if (data.op == JSOP_DEFCONST)
3625
        if (data.op == JSOP_DEFCONST)
3475
            handler.setFlag(pn2, PND_CONST);
3626
            handler.setFlag(pn2, PND_CONST);
3476
        data.pn = pn2;
3627
        data.pn = pn2;
3477
        if (!data.binder(&data, name, this))
3628
3478
            return null();
3479
        handler.addList(pn, pn2);
3629
        handler.addList(pn, pn2);
3480
3630
3481
        if (tokenStream.matchToken(TOK_ASSIGN)) {
3631
        if (tokenStream.matchToken(TOK_ASSIGN)) {
3482
            if (psimple)
3632
            if (psimple)
3483
                *psimple = false;
3633
                *psimple = false;
3484
3634
3635
            // Per ES6, 'let' declarations may not be accessed until
3636
            // initialized. So a declaration of the form |let x = x| results in a
3637
            // ReferenceError, as the 'x' on the RHS is accessing the let binding
3638
            // before it is initialized.
3639
            //
3640
            // If we are not parsing a let declaration, bind the name
3641
            // now. Otherwise we must wait until after parsing the initializing
3642
            // assignment.
3643
            //
3644
            // Optimize the common case of recursive function calls, e.g.,
3645
            //
3646
            //   let f = function (...) { f(...); };
3647
            //
3648
            // by binding early, since any uses of the binding inside the body of
3649
            // the function will be after initialization.
3650
            TokenKind nextToken = tokenStream.peekToken(TokenStream::Operand);
3651
            bool bindBeforeInitializer = kind != PNK_LET || nextToken == TOK_FUNCTION;
3652
            if (bindBeforeInitializer && !data.binder(&data, name, this))
3653
                return null();
3654
3485
            Node init = assignExpr();
3655
            Node init = assignExpr();
3486
            if (!init)
3656
            if (!init)
3487
                return null();
3657
                return null();
3488
3658
3659
            if (!bindBeforeInitializer && !data.binder(&data, name, this))
3660
                return null();
3661
3489
            if (!handler.finishInitializerAssignment(pn2, init, data.op))
3662
            if (!handler.finishInitializerAssignment(pn2, init, data.op))
3490
                return null();
3663
                return null();
3664
        } else {
3665
            if (!data.binder(&data, name, this))
3666
                return null();
3491
        }
3667
        }
3668
3669
3492
    } while (tokenStream.matchToken(TOK_COMMA));
3670
    } while (tokenStream.matchToken(TOK_COMMA));
3493
3671
3494
    return pn;
3672
    return pn;
3495
}
3673
}
3496
3674
3497
template <>
3675
template <>
3498
ParseNode *
3676
ParseNode *
3499
Parser<FullParseHandler>::letDeclaration()
3677
Parser<FullParseHandler>::letDeclaration()
 Lines 3530-3558   Parser<FullParseHandler>::letDeclaration() Link Here 
3530
                 * before the global object in the overall chain.  This extra
3708
                 * before the global object in the overall chain.  This extra
3531
                 * object is present in the scope chain for all code in that
3709
                 * object is present in the scope chain for all code in that
3532
                 * global, including self-hosted code.  But self-hosted code
3710
                 * global, including self-hosted code.  But self-hosted code
3533
                 * must be usable against *any* global object, including ones
3711
                 * must be usable against *any* global object, including ones
3534
                 * with other let variables -- variables possibly placed in
3712
                 * with other let variables -- variables possibly placed in
3535
                 * conflicting slots.  Forbid top-level let declarations to
3713
                 * conflicting slots.  Forbid top-level let declarations to
3536
                 * prevent such conflicts from ever occurring.
3714
                 * prevent such conflicts from ever occurring.
3537
                 */
3715
                 */
3538
                if (options().selfHostingMode &&
3716
                bool globalLet = !pc->sc->isFunctionBox() && stmt == pc->topScopeStmt;
3539
                    !pc->sc->isFunctionBox() &&
3717
                if (options().selfHostingMode && globalLet) {
3540
                    stmt == pc->topScopeStmt)
3541
                {
3542
                    report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET);
3718
                    report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET);
3543
                    return null();
3719
                    return null();
3544
                }
3720
                }
3545
3721
3546
                /*
3722
                /*
3547
                 * ES4 specifies that let at top level and at body-block scope
3723
                 * Parse body-level lets without a new block object. ES6 specs
3548
                 * does not shadow var, so convert back to var.
3724
                 * that an execution environment's initial lexical environment
3725
                 * is the VariableEnvironment, i.e., body-level lets are in
3726
                 * the same environment record as vars.
3727
                 *
3728
                 * However, they cannot be parsed exactly as vars, as ES6
3729
                 * requires that uninitialized lets throw ReferenceError on use.
3730
                 *
3731
                 * See 8.1.1.1.6 and the note in 13.2.1.
3732
                 *
3733
                 * FIXME global-level lets are still considered vars until
3734
                 * other bugs are fixed.
3549
                 */
3735
                 */
3550
                pn = variables(PNK_VAR);
3736
                pn = variables(globalLet ? PNK_VAR : PNK_LET);
3551
                if (!pn)
3737
                if (!pn)
3552
                    return null();
3738
                    return null();
3553
                pn->pn_xflags |= PNX_POPVAR;
3739
                pn->pn_xflags |= PNX_POPVAR;
3554
                break;
3740
                break;
3555
            }
3741
            }
3556
3742
3557
            /*
3743
            /*
3558
             * Some obvious assertions here, but they may help clarify the
3744
             * Some obvious assertions here, but they may help clarify the
 Lines 4577-4592   Parser<ParseHandler>::switchStatement() Link Here 
4577
            if (tt == TOK_ERROR)
4763
            if (tt == TOK_ERROR)
4578
                return null();
4764
                return null();
4579
            Node stmt = statement();
4765
            Node stmt = statement();
4580
            if (!stmt)
4766
            if (!stmt)
4581
                return null();
4767
                return null();
4582
            handler.addList(body, stmt);
4768
            handler.addList(body, stmt);
4583
        }
4769
        }
4584
4770
4771
        // In ES6, 'let' bindings canot be accessed until initialized. If
4772
        // there was a 'let' declaration in the case we just parsed, remember
4773
        // the slot starting at which new 'let' bindings will be
4774
        // assigned. Since 'let' bindings from previous cases will not
4775
        // dominate uses in the current case, any such uses will require a
4776
        // dead zone check.
4777
        if (pc->blockNode != caseList)
4778
            stmtInfo.firstDominatingLetInCase = stmtInfo.staticBlock().numVariables();
4779
4585
        Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body);
4780
        Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body);
4586
        if (!casepn)
4781
        if (!casepn)
4587
            return null();
4782
            return null();
4588
        handler.addList(caseList, casepn);
4783
        handler.addList(caseList, casepn);
4589
    }
4784
    }
4590
4785
4591
    /*
4786
    /*
4592
     * Handle the case where there was a let declaration in any case in
4787
     * Handle the case where there was a let declaration in any case in
 Lines 5049-5065   Parser<ParseHandler>::tryStatement() Link Here 
5049
             */
5244
             */
5050
            MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
5245
            MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
5051
5246
5052
            /*
5247
            /*
5053
             * Contrary to ECMA Ed. 3, the catch variable is lexically
5248
             * Contrary to ECMA Ed. 3, the catch variable is lexically
5054
             * scoped, not a property of a new Object instance.  This is
5249
             * scoped, not a property of a new Object instance.  This is
5055
             * an intentional change that anticipates ECMA Ed. 4.
5250
             * an intentional change that anticipates ECMA Ed. 4.
5056
             */
5251
             */
5057
            data.initLet(HoistVars, pc->staticScope->template as<StaticBlockObject>(),
5252
            data.initLet(HoistVars, &pc->staticScope->template as<StaticBlockObject>(),
5058
                         JSMSG_TOO_MANY_CATCH_VARS);
5253
                         JSMSG_TOO_MANY_CATCH_VARS);
5059
            JS_ASSERT(data.let.blockObj);
5254
            JS_ASSERT(data.let.blockObj);
5060
5255
5061
            tt = tokenStream.getToken();
5256
            tt = tokenStream.getToken();
5062
            Node catchName;
5257
            Node catchName;
5063
            switch (tt) {
5258
            switch (tt) {
5064
              case TOK_LB:
5259
              case TOK_LB:
5065
              case TOK_LC:
5260
              case TOK_LC:
 Lines 6097-6113   Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned Link Here 
6097
    LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
6292
    LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
6098
    if (!transplanter.init())
6293
    if (!transplanter.init())
6099
        return null();
6294
        return null();
6100
6295
6101
    if (!transplanter.transplant(bodyStmt))
6296
    if (!transplanter.transplant(bodyStmt))
6102
        return null();
6297
        return null();
6103
6298
6104
    JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
6299
    JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
6105
    data.initLet(HoistVars, pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
6300
    data.initLet(HoistVars, &pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
6106
6301
6107
    do {
6302
    do {
6108
        /*
6303
        /*
6109
         * FOR node is binary, left is loop control and right is body.  Use
6304
         * FOR node is binary, left is loop control and right is body.  Use
6110
         * index to count each block-local let-variable on the left-hand side
6305
         * index to count each block-local let-variable on the left-hand side
6111
         * of the in/of.
6306
         * of the in/of.
6112
         */
6307
         */
6113
        pn2 = BinaryNode::create(PNK_FOR, &handler);
6308
        pn2 = BinaryNode::create(PNK_FOR, &handler);
 Lines 6213-6243   Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned Link Here 
6213
            break;
6408
            break;
6214
6409
6215
          default:;
6410
          default:;
6216
        }
6411
        }
6217
6412
6218
        /*
6413
        /*
6219
         * Synthesize a declaration. Every definition must appear in the parse
6414
         * Synthesize a declaration. Every definition must appear in the parse
6220
         * tree in order for ComprehensionTranslator to work.
6415
         * tree in order for ComprehensionTranslator to work.
6416
         *
6417
         * These are lets to tell the bytecode emitter to emit initialization
6418
         * code for the temporal dead zone.
6221
         */
6419
         */
6222
        ParseNode *vars = ListNode::create(PNK_VAR, &handler);
6420
        ParseNode *lets = ListNode::create(PNK_LET, &handler);
6223
        if (!vars)
6421
        if (!lets)
6224
            return null();
6422
            return null();
6225
        vars->setOp(JSOP_NOP);
6423
        lets->setOp(JSOP_NOP);
6226
        vars->pn_pos = pn3->pn_pos;
6424
        lets->pn_pos = pn3->pn_pos;
6227
        vars->makeEmpty();
6425
        lets->makeEmpty();
6228
        vars->append(pn3);
6426
        lets->append(pn3);
6427
        lets->pn_xflags |= PNX_POPVAR;
6229
6428
6230
        /* Definitions can't be passed directly to EmitAssignment as lhs. */
6429
        /* Definitions can't be passed directly to EmitAssignment as lhs. */
6231
        pn3 = cloneLeftHandSide(pn3);
6430
        pn3 = cloneLeftHandSide(pn3);
6232
        if (!pn3)
6431
        if (!pn3)
6233
            return null();
6432
            return null();
6234
6433
6235
        pn2->pn_left = handler.newTernary(headKind, vars, pn3, pn4);
6434
        pn2->pn_left = handler.newTernary(headKind, lets, pn3, pn4);
6236
        if (!pn2->pn_left)
6435
        if (!pn2->pn_left)
6237
            return null();
6436
            return null();
6238
        *pnp = pn2;
6437
        *pnp = pn2;
6239
        pnp = &pn2->pn_right;
6438
        pnp = &pn2->pn_right;
6240
    } while (tokenStream.matchToken(TOK_FOR));
6439
    } while (tokenStream.matchToken(TOK_FOR));
6241
6440
6242
    if (tokenStream.matchToken(TOK_IF)) {
6441
    if (tokenStream.matchToken(TOK_IF)) {
6243
        pn2 = TernaryNode::create(PNK_IF, &handler);
6442
        pn2 = TernaryNode::create(PNK_IF, &handler);
 Lines 6393-6409   Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi Link Here 
6393
6592
6394
    // Note that if we ever start syntax-parsing generators, we will also
6593
    // Note that if we ever start syntax-parsing generators, we will also
6395
    // need to propagate the closed-over variable set to the inner
6594
    // need to propagate the closed-over variable set to the inner
6396
    // lazyscript, as in finishFunctionDefinition.
6595
    // lazyscript, as in finishFunctionDefinition.
6397
    handler.setFunctionBody(genfn, body);
6596
    handler.setFunctionBody(genfn, body);
6398
6597
6399
    PropagateTransitiveParseFlags(genFunbox, outerpc->sc);
6598
    PropagateTransitiveParseFlags(genFunbox, outerpc->sc);
6400
6599
6401
    if (!leaveFunction(genfn, outerpc))
6600
    if (!leaveFunction(genfn, outerpc, /* bodyLevelHoistedUse = */ false))
6402
        return null();
6601
        return null();
6403
6602
6404
    return genfn;
6603
    return genfn;
6405
}
6604
}
6406
6605
6407
#if JS_HAS_GENERATOR_EXPRS
6606
#if JS_HAS_GENERATOR_EXPRS
6408
6607
6409
/*
6608
/*
 Lines 6499-6515   Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind) Link Here 
6499
6698
6500
    TokenPos headPos(begin, pos().end);
6699
    TokenPos headPos(begin, pos().end);
6501
6700
6502
    StmtInfoPC stmtInfo(context);
6701
    StmtInfoPC stmtInfo(context);
6503
    BindData<ParseHandler> data(context);
6702
    BindData<ParseHandler> data(context);
6504
    RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
6703
    RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
6505
    if (!blockObj)
6704
    if (!blockObj)
6506
        return null();
6705
        return null();
6507
    data.initLet(DontHoistVars, *blockObj, JSMSG_TOO_MANY_LOCALS);
6706
    data.initLet(DontHoistVars, blockObj, JSMSG_TOO_MANY_LOCALS);
6508
    Node lhs = newName(name);
6707
    Node lhs = newName(name);
6509
    if (!lhs)
6708
    if (!lhs)
6510
        return null();
6709
        return null();
6511
    Node decls = handler.newList(PNK_LET, lhs, JSOP_NOP);
6710
    Node decls = handler.newList(PNK_LET, lhs, JSOP_NOP);
6512
    if (!decls)
6711
    if (!decls)
6513
        return null();
6712
        return null();
6514
    data.pn = lhs;
6713
    data.pn = lhs;
6515
    if (!data.binder(&data, name, this))
6714
    if (!data.binder(&data, name, this))
(-)a/js/src/frontend/Parser.h (-6 / +25 lines)
Line     Link Here 
 Lines 25-41   namespace frontend { Link Here 
25
25
26
struct StmtInfoPC : public StmtInfoBase {
26
struct StmtInfoPC : public StmtInfoBase {
27
    StmtInfoPC      *down;          /* info for enclosing statement */
27
    StmtInfoPC      *down;          /* info for enclosing statement */
28
    StmtInfoPC      *downScope;     /* next enclosing lexical scope */
28
    StmtInfoPC      *downScope;     /* next enclosing lexical scope */
29
29
30
    uint32_t        blockid;        /* for simplified dominance computation */
30
    uint32_t        blockid;        /* for simplified dominance computation */
31
    uint32_t        innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */
31
    uint32_t        innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */
32
32
33
    explicit StmtInfoPC(ExclusiveContext *cx) : StmtInfoBase(cx), innerBlockScopeDepth(0) {}
33
    // 'let' declarations inside switches are tricky because the block id
34
    // doesn't convey dominance information. Record what index the current
35
    // case's 'let' declarations start at so we may generate dead zone checks
36
    // for other cases' declarations.
37
    //
38
    // Only valid if type is STMT_SWITCH.
39
    uint16_t        firstDominatingLetInCase;
40
41
    explicit StmtInfoPC(ExclusiveContext *cx)
42
      : StmtInfoBase(cx),
43
        innerBlockScopeDepth(0),
44
        firstDominatingLetInCase(0)
45
    {}
34
};
46
};
35
47
36
typedef HashSet<JSAtom *> FuncStmtSet;
48
typedef HashSet<JSAtom *> FuncStmtSet;
37
class SharedContext;
49
class SharedContext;
38
50
39
typedef Vector<Definition *, 16> DeclVector;
51
typedef Vector<Definition *, 16> DeclVector;
40
52
41
struct GenericParseContext
53
struct GenericParseContext
 Lines 121-140   struct ParseContext : public GenericParseContext Link Here 
121
133
122
    bool isArrowFunction() const {
134
    bool isArrowFunction() const {
123
        return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow();
135
        return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow();
124
    }
136
    }
125
137
126
    uint32_t        blockScopeDepth; /* maximum depth of nested block scopes, in slots */
138
    uint32_t        blockScopeDepth; /* maximum depth of nested block scopes, in slots */
127
    Node            blockNode;      /* parse node for a block with let declarations
139
    Node            blockNode;      /* parse node for a block with let declarations
128
                                       (block with its own lexical scope)  */
140
                                       (block with its own lexical scope)  */
141
129
  private:
142
  private:
130
    AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
143
    AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
131
    DeclVector      args_;          /* argument definitions */
144
    DeclVector      args_;          /* argument definitions */
132
    DeclVector      vars_;          /* var/const definitions */
145
    DeclVector      vars_;          /* var/const definitions */
146
    DeclVector      bodyLevelLets_; /* let definitions at body-level */
147
148
    bool checkLocalsOverflow(TokenStream &ts);
133
149
134
  public:
150
  public:
135
    const AtomDecls<ParseHandler> &decls() const {
151
    const AtomDecls<ParseHandler> &decls() const {
136
        return decls_;
152
        return decls_;
137
    }
153
    }
138
154
139
    uint32_t numArgs() const {
155
    uint32_t numArgs() const {
140
        JS_ASSERT(sc->isFunctionBox());
156
        JS_ASSERT(sc->isFunctionBox());
 Lines 254-269   struct ParseContext : public GenericParseContext Link Here 
254
        maybeFunction(maybeFunction),
270
        maybeFunction(maybeFunction),
255
        staticLevel(staticLevel),
271
        staticLevel(staticLevel),
256
        lastYieldOffset(NoYieldOffset),
272
        lastYieldOffset(NoYieldOffset),
257
        blockScopeDepth(blockScopeDepth),
273
        blockScopeDepth(blockScopeDepth),
258
        blockNode(ParseHandler::null()),
274
        blockNode(ParseHandler::null()),
259
        decls_(prs->context, prs->alloc),
275
        decls_(prs->context, prs->alloc),
260
        args_(prs->context),
276
        args_(prs->context),
261
        vars_(prs->context),
277
        vars_(prs->context),
278
        bodyLevelLets_(prs->context),
262
        parserPC(&prs->pc),
279
        parserPC(&prs->pc),
263
        oldpc(prs->pc),
280
        oldpc(prs->pc),
264
        lexdeps(prs->context),
281
        lexdeps(prs->context),
265
        funcStmts(nullptr),
282
        funcStmts(nullptr),
266
        innerFunctions(prs->context),
283
        innerFunctions(prs->context),
267
        newDirectives(newDirectives),
284
        newDirectives(newDirectives),
268
        inDeclDestructuring(false)
285
        inDeclDestructuring(false)
269
    {
286
    {
 Lines 546-562   class Parser : private JS::AutoGCRooter, public StrictModeGetter Link Here 
546
     */
563
     */
547
    bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool *hasRest);
564
    bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool *hasRest);
548
565
549
    Node functionDef(HandlePropertyName name, const TokenStream::Position &start,
566
    Node functionDef(HandlePropertyName name, const TokenStream::Position &start,
550
                     FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind);
567
                     FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind);
551
    bool functionArgsAndBody(Node pn, HandleFunction fun,
568
    bool functionArgsAndBody(Node pn, HandleFunction fun,
552
                             FunctionType type, FunctionSyntaxKind kind,
569
                             FunctionType type, FunctionSyntaxKind kind,
553
                             GeneratorKind generatorKind,
570
                             GeneratorKind generatorKind,
554
                             Directives inheritedDirectives, Directives *newDirectives);
571
                             Directives inheritedDirectives, Directives *newDirectives,
572
                             bool bodyLevelHoistedUse);
555
573
556
    Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
574
    Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
557
575
558
    Node condition();
576
    Node condition();
559
577
560
    Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
578
    Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
561
                                      Node innerStmt);
579
                                      Node innerStmt);
562
580
 Lines 595-615   class Parser : private JS::AutoGCRooter, public StrictModeGetter Link Here 
595
        KeyedDestructuringAssignment,
613
        KeyedDestructuringAssignment,
596
        IncDecAssignment
614
        IncDecAssignment
597
    };
615
    };
598
616
599
    bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
617
    bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
600
    bool matchInOrOf(bool *isForOfp);
618
    bool matchInOrOf(bool *isForOfp);
601
619
602
    bool checkFunctionArguments();
620
    bool checkFunctionArguments();
603
    bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom);
621
    bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom, bool *pbodyLevelHoistedUse);
604
    bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
622
    bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
605
                                 bool *pbodyProcessed);
623
                                 bool *pbodyProcessed, bool *pbodyLevelHoistedUse);
606
    bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
624
    bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
607
    bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext<ParseHandler> *pc);
625
    bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext<ParseHandler> *pc,
626
                                          bool bodyLevelHoistedUse);
608
627
609
    bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
628
    bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
610
                                ParseNodeKind headKind);
629
                                ParseNodeKind headKind);
611
    bool checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder);
630
    bool checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder);
612
    bool checkStrictAssignment(Node lhs, AssignmentFlavor flavor);
631
    bool checkStrictAssignment(Node lhs, AssignmentFlavor flavor);
613
    bool checkStrictBinding(PropertyName *name, Node pn);
632
    bool checkStrictBinding(PropertyName *name, Node pn);
614
    bool defineArg(Node funcpn, HandlePropertyName name,
633
    bool defineArg(Node funcpn, HandlePropertyName name,
615
                   bool disallowDuplicateArgs = false, Node *duplicatedArg = nullptr);
634
                   bool disallowDuplicateArgs = false, Node *duplicatedArg = nullptr);
 Lines 647-663   class Parser : private JS::AutoGCRooter, public StrictModeGetter Link Here 
647
666
648
    static Node null() { return ParseHandler::null(); }
667
    static Node null() { return ParseHandler::null(); }
649
668
650
    bool reportRedeclaration(Node pn, bool isConst, HandlePropertyName name);
669
    bool reportRedeclaration(Node pn, bool isConst, HandlePropertyName name);
651
    bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
670
    bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
652
    DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom);
671
    DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom);
653
672
654
    bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc,
673
    bool leaveFunction(Node fn, ParseContext<ParseHandler> *outerpc,
655
                       FunctionSyntaxKind kind = Expression);
674
                       bool bodyLevelHoistedUse, FunctionSyntaxKind kind = Expression);
656
675
657
    TokenPos pos() const { return tokenStream.currentToken().pos; }
676
    TokenPos pos() const { return tokenStream.currentToken().pos; }
658
677
659
    bool asmJS(Node list);
678
    bool asmJS(Node list);
660
679
661
    friend class LegacyCompExprTransplanter;
680
    friend class LegacyCompExprTransplanter;
662
    friend struct BindData<ParseHandler>;
681
    friend struct BindData<ParseHandler>;
663
};
682
};
(-)a/js/src/frontend/SyntaxParseHandler.h (+3 lines)
Line     Link Here 
 Lines 244-268   class SyntaxParseHandler Link Here 
244
        }
244
        }
245
        return nullptr;
245
        return nullptr;
246
    }
246
    }
247
247
248
    Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; }
248
    Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; }
249
249
250
    static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; }
250
    static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; }
251
    static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; }
251
    static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; }
252
    static bool isPlaceholderDefinition(DefinitionNode dn) { return dn == Definition::PLACEHOLDER; }
252
    void linkUseToDef(Node pn, DefinitionNode dn) {}
253
    void linkUseToDef(Node pn, DefinitionNode dn) {}
253
    DefinitionNode resolve(DefinitionNode dn) { return dn; }
254
    DefinitionNode resolve(DefinitionNode dn) { return dn; }
254
    void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {}
255
    void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {}
255
    bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) {
256
    bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) {
256
        // Only resolve lexical dependencies in cases where a definition covers
257
        // Only resolve lexical dependencies in cases where a definition covers
257
        // the entire function. Not enough information is kept to compare the
258
        // the entire function. Not enough information is kept to compare the
258
        // dependency location with blockid.
259
        // dependency location with blockid.
259
        return functionScope;
260
        return functionScope;
260
    }
261
    }
262
    void markMaybeUninitializedLetUseInSwitch(Node pn, DefinitionNode dn,
263
                                              uint16_t firstDominatingLetSlot) {}
261
264
262
    static uintptr_t definitionToBits(DefinitionNode dn) {
265
    static uintptr_t definitionToBits(DefinitionNode dn) {
263
        // Use a shift, as DefinitionList tags the lower bit of its associated union.
266
        // Use a shift, as DefinitionList tags the lower bit of its associated union.
264
        return uintptr_t(dn << 1);
267
        return uintptr_t(dn << 1);
265
    }
268
    }
266
    static DefinitionNode definitionFromBits(uintptr_t bits) {
269
    static DefinitionNode definitionFromBits(uintptr_t bits) {
267
        return (DefinitionNode) (bits >> 1);
270
        return (DefinitionNode) (bits >> 1);
268
    }
271
    }
(-)a/js/src/jit-test/tests/arguments/alias-function-closed.js (-1 / +1 lines)
Line     Link Here 
 Lines 117-133   function f5(a, b, c, d) { Link Here 
117
    // close here
117
    // close here
118
    assertEq(a(), 52);
118
    assertEq(a(), 52);
119
    assertEq(b(), 63);
119
    assertEq(b(), 63);
120
    assertEq(c(), 54);
120
    assertEq(c(), 54);
121
    assertEq(d(), 65);
121
    assertEq(d(), 65);
122
  }
122
  }
123
123
124
  var a, b = ()=>63;
124
  var a, b = ()=>63;
125
  let c, d = ()=>65;
125
  var c, d = ()=>65;
126
126
127
  // after var declarations, before function declarations
127
  // after var declarations, before function declarations
128
  assertEq(a(), 52);
128
  assertEq(a(), 52);
129
  assertEq(b(), 63);
129
  assertEq(b(), 63);
130
  assertEq(c(), 54);
130
  assertEq(c(), 54);
131
  assertEq(d(), 65);
131
  assertEq(d(), 65);
132
132
133
  function h() {
133
  function h() {
(-)a/js/src/jit-test/tests/arguments/alias-function-not-closed.js (-1 / +1 lines)
Line     Link Here 
 Lines 54-70   f2(()=>42); Link Here 
54
function f3(a, b, c, d) {
54
function f3(a, b, c, d) {
55
  // before var/function declarations
55
  // before var/function declarations
56
  assertEq(a(), 52);
56
  assertEq(a(), 52);
57
  assertEq(b(), 53);
57
  assertEq(b(), 53);
58
  assertEq(c(), 54);
58
  assertEq(c(), 54);
59
  assertEq(d(), 55);
59
  assertEq(d(), 55);
60
60
61
  var a, b = ()=>63;
61
  var a, b = ()=>63;
62
  let c, d = ()=>65;
62
  var c, d = ()=>65;
63
63
64
  // after var declarations, before function declarations
64
  // after var declarations, before function declarations
65
  assertEq(a(), 52);
65
  assertEq(a(), 52);
66
  assertEq(b(), 63);
66
  assertEq(b(), 63);
67
  assertEq(c(), 54);
67
  assertEq(c(), 54);
68
  assertEq(d(), 65);
68
  assertEq(d(), 65);
69
69
70
  function a() {
70
  function a() {
(-)a/js/src/jit-test/tests/basic/testLet.js (-30 / +48 lines)
Line     Link Here 
 Lines 27-54   function test(str, arg, result) Link Here 
27
    var expect = result;
27
    var expect = result;
28
    if (got !== expect) {
28
    if (got !== expect) {
29
        print("GOT:" + got);
29
        print("GOT:" + got);
30
        print("EXPECT: " + expect);
30
        print("EXPECT: " + expect);
31
        assertEq(got, expect);
31
        assertEq(got, expect);
32
    }
32
    }
33
}
33
}
34
34
35
function isError(str)
35
function isParseError(str)
36
{
36
{
37
    var caught = false;
37
    var caught = false;
38
    try {
38
    try {
39
        new Function(str);
39
        new Function(str);
40
    } catch(e) {
40
    } catch(e) {
41
        assertEq(String(e).indexOf('TypeError') == 0 || String(e).indexOf('SyntaxError') == 0, true);
41
        assertEq(String(e).indexOf('TypeError') == 0 || String(e).indexOf('SyntaxError') == 0, true);
42
        caught = true;
42
        caught = true;
43
    }
43
    }
44
    assertEq(caught, true);
44
    assertEq(caught, true);
45
}
45
}
46
46
47
function isReferenceError(str)
48
{
49
    var caught = false;
50
    try {
51
        (new Function(str))();
52
    } catch(e) {
53
        assertEq(String(e).indexOf('ReferenceError') == 0, true);
54
        caught = true;
55
    }
56
    assertEq(caught, true);
57
}
58
47
// let expr
59
// let expr
48
test('return let (y) x;');
60
test('return let (y) x;');
49
test('return let (x) "" + x;', 'unicorns', 'undefined');
61
test('return let (x) "" + x;', 'unicorns', 'undefined');
50
test('return let (y = x) (y++, "" + y);', 'unicorns', 'NaN');
62
test('return let (y = x) (y++, "" + y);', 'unicorns', 'NaN');
51
test('return let (y = 1) (y = x, y);');
63
test('return let (y = 1) (y = x, y);');
52
test('return let ([] = x) x;');
64
test('return let ([] = x) x;');
53
test('return let (x = {a: x}) x.a;');
65
test('return let (x = {a: x}) x.a;');
54
test('return let ({a: x} = {a: x}) x;');
66
test('return let ({a: x} = {a: x}) x;');
 Lines 89-110   test('return let ([x] = (3, [x])) x;'); Link Here 
89
test('return let ([] = [[]] = {}) x;');
101
test('return let ([] = [[]] = {}) x;');
90
test('return let (y = x) function () {return eval("y");}();');
102
test('return let (y = x) function () {return eval("y");}();');
91
test('return eval("let (y = x) y");');
103
test('return eval("let (y = x) y");');
92
test('return let (y = x) (eval("var y = 2"), y);', 'ponies', 2);
104
test('return let (y = x) (eval("var y = 2"), y);', 'ponies', 2);
93
test('"use strict";return let (y = x) (eval("var y = 2"), y);');
105
test('"use strict";return let (y = x) (eval("var y = 2"), y);');
94
test('this.y = x;return let (y = 1) this.eval("y");');
106
test('this.y = x;return let (y = 1) this.eval("y");');
95
test('try {let (x = x) eval("throw x");} catch (e) {return e;}');
107
test('try {let (x = x) eval("throw x");} catch (e) {return e;}');
96
test('try {return let (x = eval("throw x")) x;} catch (e) {return e;}');
108
test('try {return let (x = eval("throw x")) x;} catch (e) {return e;}');
97
isError('let (x = 1, x = 2) x');
109
isParseError('let (x = 1, x = 2) x');
98
isError('let ([x, y] = a, {a:x} = b) x');
110
isParseError('let ([x, y] = a, {a:x} = b) x');
99
isError('let ([x, y, x] = a) x');
111
isParseError('let ([x, y, x] = a) x');
100
isError('let ([x, [y, [x]]] = a) x');
112
isParseError('let ([x, [y, [x]]] = a) x');
101
isError('let (x = function() { return x}) x()return x;');
113
isParseError('let (x = function() { return x}) x()return x;');
102
isError('(let (x = function() { return x}) x())return x;');
114
isParseError('(let (x = function() { return x}) x())return x;');
103
115
104
// let block
116
// let block
105
test('let (y) {return x;}');
117
test('let (y) {return x;}');
106
test('let (y = x) {y++;return "" + y;}', 'unicorns', 'NaN');
118
test('let (y = x) {y++;return "" + y;}', 'unicorns', 'NaN');
107
test('let (y = 1) {y = x;return y;}');
119
test('let (y = 1) {y = x;return y;}');
108
test('let (x) {return "" + x;}', 'unicorns', 'undefined');
120
test('let (x) {return "" + x;}', 'unicorns', 'undefined');
109
test('let ([] = x) {return x;}');
121
test('let ([] = x) {return x;}');
110
test('let (x) {}return x;');
122
test('let (x) {}return x;');
 Lines 144-163   test('let ([{x: [x]}, {y1: y, z1: z}] = [x, x + 1]) {return x;}',{x:['ponies']}) Link Here 
144
test('let (y = x[1]) {let (x = x[0]) {try {let (y = "unicorns") {throw y;}} catch (e) {return x + y;}}}', ['pon','ies']);
156
test('let (y = x[1]) {let (x = x[0]) {try {let (y = "unicorns") {throw y;}} catch (e) {return x + y;}}}', ['pon','ies']);
145
test('let (x = x) {try {let (x = "unicorns") eval("throw x");} catch (e) {return x;}}');
157
test('let (x = x) {try {let (x = "unicorns") eval("throw x");} catch (e) {return x;}}');
146
test('let ([] = [[]] = {}) {return x;}');
158
test('let ([] = [[]] = {}) {return x;}');
147
test('let (y = x) {return function () {return eval("y");}();}');
159
test('let (y = x) {return function () {return eval("y");}();}');
148
test('return eval("let (y = x) {y;}");');
160
test('return eval("let (y = x) {y;}");');
149
test('let (y = x) {eval("var y = 2");return y;}', 'ponies', 2);
161
test('let (y = x) {eval("var y = 2");return y;}', 'ponies', 2);
150
test('"use strict";let (y = x) {eval("var y = 2");return y;}');
162
test('"use strict";let (y = x) {eval("var y = 2");return y;}');
151
test('this.y = x;let (y = 1) {return this.eval("y");}');
163
test('this.y = x;let (y = 1) {return this.eval("y");}');
152
isError('let (x = 1, x = 2) {x}');
164
isParseError('let (x = 1, x = 2) {x}');
153
isError('let ([x, y] = a, {a:x} = b) {x}');
165
isParseError('let ([x, y] = a, {a:x} = b) {x}');
154
isError('let ([x, y, x] = a) {x}');
166
isParseError('let ([x, y, x] = a) {x}');
155
isError('let ([x, [y, [x]]] = a) {x}');
167
isParseError('let ([x, [y, [x]]] = a) {x}');
156
168
157
// var declarations
169
// var declarations
158
test('var y;return x;');
170
test('var y;return x;');
159
test('var y = x;return x;');
171
test('var y = x;return x;');
160
test('var [] = x;return x;');
172
test('var [] = x;return x;');
161
test('var [, ] = x;return x;');
173
test('var [, ] = x;return x;');
162
test('var [, , , , ] = x;return x;');
174
test('var [, , , , ] = x;return x;');
163
test('var [[]] = x;return x;');
175
test('var [[]] = x;return x;');
 Lines 190-221   test('var [] = [[]] = {};return x;'); Link Here 
190
test('if (x) {var y = x;return x;}');
202
test('if (x) {var y = x;return x;}');
191
test('if (x) {y = x;var y = y;return y;}');
203
test('if (x) {y = x;var y = y;return y;}');
192
test('if (x) {var z = y;var [y] = x;z += y;}return z;', ['-'], 'undefined-');
204
test('if (x) {var z = y;var [y] = x;z += y;}return z;', ['-'], 'undefined-');
193
205
194
// let declaration in context
206
// let declaration in context
195
test('if (x) {let y;return x;}');
207
test('if (x) {let y;return x;}');
196
test('if (x) {let x;return "" + x;}', 'unicorns', 'undefined');
208
test('if (x) {let x;return "" + x;}', 'unicorns', 'undefined');
197
test('if (x) {let y = x;return x;}');
209
test('if (x) {let y = x;return x;}');
198
test('if (x) {y = x;let y = y;return y;}');
199
test('if (x) {var z = y;let [y] = x;z += y;}return z;', ['-'], 'undefined-');
200
test('if (x) {let y = x;return x;}');
210
test('if (x) {let y = x;return x;}');
201
test('if (x) {let [] = x;return x;}');
211
test('if (x) {let [] = x;return x;}');
202
test('if (x) {let [, ] = x;return x;}');
212
test('if (x) {let [, ] = x;return x;}');
203
test('if (x) {let [, , , , ] = x;return x;}');
213
test('if (x) {let [, , , , ] = x;return x;}');
204
test('if (x) {let [[]] = x;return x;}');
214
test('if (x) {let [[]] = x;return x;}');
205
test('if (x) {let [[[[[[[[[[[[[]]]]]]]]]]]]] = x;return x;}');
215
test('if (x) {let [[[[[[[[[[[[[]]]]]]]]]]]]] = x;return x;}');
206
test('if (x) {let [[], []] = x;return x;}');
216
test('if (x) {let [[], []] = x;return x;}');
207
test('if (x) {let [[[[]]], [], , [], [[]]] = x;return x;}');
217
test('if (x) {let [[[[]]], [], , [], [[]]] = x;return x;}');
208
test('if (x) {let {x: []} = x;return x;}');
218
test('if (x) {let {x: []} = x;return x;}');
209
test('if (x) {let {x: [], y: {x: []}} = x;return "ponies";}', {y:{}});
219
test('if (x) {let {x: [], y: {x: []}} = x;return "ponies";}', {y:{}});
210
test('if (x) {let {x: []} = x, [{x: []}] = x;return "ponies";}');
220
test('if (x) {let {x: []} = x, [{x: []}] = x;return "ponies";}');
211
test('if (x) {let x = x;return "" + x;}', 'unicorns', 'undefined');
212
test('if (x) {let y = y;return "" + y;}', 'unicorns', 'undefined');
213
test('if (x) {let x = eval("x");return "" + x;}', 'unicorns', 'undefined');
214
test('if (x) {let y = (let (x = x + 1) x) + 1;return y;}', 1, 3);
221
test('if (x) {let y = (let (x = x + 1) x) + 1;return y;}', 1, 3);
215
test('if (x) {let y = (let (x = eval("x") + 1) eval("x")) + 1;return eval("y");}', 1, 3);
222
test('if (x) {let y = (let (x = eval("x") + 1) eval("x")) + 1;return eval("y");}', 1, 3);
216
test('if (x) {let X = x + 1, y = x;return y;}');
223
test('if (x) {let X = x + 1, y = x;return y;}');
217
test('if (x) {let X = x + 1, [] = X, [[, , ]] = X, y = x;return y;}');
224
test('if (x) {let X = x + 1, [] = X, [[, , ]] = X, y = x;return y;}');
218
test('if (x) {let [{a: X}] = x, [, {b: Y}] = x;var XX = X + 1, YY = Y + 2;return XX + YY;}', [{a:"p"},{b:"p"}], "p1p2");
225
test('if (x) {let [{a: X}] = x, [, {b: Y}] = x;var XX = X + 1, YY = Y + 2;return XX + YY;}', [{a:"p"},{b:"p"}], "p1p2");
219
test('if (x) {let [[a, [b, c]]] = [[x, []]];return a;}');
226
test('if (x) {let [[a, [b, c]]] = [[x, []]];return a;}');
220
test('if (x) {let [X] = [x];return X;}');
227
test('if (x) {let [X] = [x];return X;}');
221
test('if (x) {let [y] = [x];return y;}');
228
test('if (x) {let [y] = [x];return y;}');
 Lines 241-261   test('x.foo;{let y = x;return y;}'); Link Here 
241
test('x.foo;if (x) {x.bar;let y = x;return y;}');
248
test('x.foo;if (x) {x.bar;let y = x;return y;}');
242
test('if (x) {let y = x;return function () {return eval("y");}();}');
249
test('if (x) {let y = x;return function () {return eval("y");}();}');
243
test('return eval("let y = x; y");');
250
test('return eval("let y = x; y");');
244
test('if (x) {let y = x;eval("var y = 2");return y;}', 'ponies', 2);
251
test('if (x) {let y = x;eval("var y = 2");return y;}', 'ponies', 2);
245
test('"use strict";if (x) {let y = x;eval("var y = 2");return y;}');
252
test('"use strict";if (x) {let y = x;eval("var y = 2");return y;}');
246
test('"use strict";if (x) {let y = x;eval("let y = 2");return y;}');
253
test('"use strict";if (x) {let y = x;eval("let y = 2");return y;}');
247
test('"use strict";if (x) {let y = 1;return eval("let y = x;y;");}');
254
test('"use strict";if (x) {let y = 1;return eval("let y = x;y;");}');
248
test('this.y = x;if (x) {let y = 1;return this.eval("y");}');
255
test('this.y = x;if (x) {let y = 1;return this.eval("y");}');
249
isError('if (x) {let (x = 1, x = 2) {x}}');
256
isParseError('if (x) {let (x = 1, x = 2) {x}}');
250
isError('if (x) {let ([x, y] = a, {a:x} = b) {x}}');
257
isParseError('if (x) {let ([x, y] = a, {a:x} = b) {x}}');
251
isError('if (x) {let ([x, y, x] = a) {x}}');
258
isParseError('if (x) {let ([x, y, x] = a) {x}}');
252
isError('if (x) {let ([x, [y, [x]]] = a) {x}}');
259
isParseError('if (x) {let ([x, [y, [x]]] = a) {x}}');
253
isError('let ([x, y] = x) {let x;}');
260
isParseError('let ([x, y] = x) {let x;}');
254
261
255
// for(;;)
262
// for(;;)
256
test('for (;;) {return x;}');
263
test('for (;;) {return x;}');
257
test('for (let y = 1;;) {return x;}');
264
test('for (let y = 1;;) {return x;}');
258
test('for (let y = 1;; ++y) {return x;}');
265
test('for (let y = 1;; ++y) {return x;}');
259
test('for (let y = 1; ++y;) {return x;}');
266
test('for (let y = 1; ++y;) {return x;}');
260
test('for (let (x = 1) x; x != 1; ++x) {return x;}');
267
test('for (let (x = 1) x; x != 1; ++x) {return x;}');
261
test('for (let [, {a: [], b: []}] = x, [] = x; x;) {return x;}');
268
test('for (let [, {a: [], b: []}] = x, [] = x; x;) {return x;}');
 Lines 284-303   test('try {for (let x = x + "s"; eval("throw x");) {}} catch (e) {return e;}', ' Link Here 
284
test('for (let y = x;;) {let x;return y;}');
291
test('for (let y = x;;) {let x;return y;}');
285
test('for (let y = x;;) {let y;return x;}');
292
test('for (let y = x;;) {let y;return x;}');
286
test('for (let y;;) {let y;return x;}');
293
test('for (let y;;) {let y;return x;}');
287
test('for (let a = x;;) {let c = x, d = x;return c;}');
294
test('for (let a = x;;) {let c = x, d = x;return c;}');
288
test('for (let [a, b] = x;;) {let c = x, d = x;return c;}');
295
test('for (let [a, b] = x;;) {let c = x, d = x;return c;}');
289
test('for (let [] = [[]] = {};;) {return x;}');
296
test('for (let [] = [[]] = {};;) {return x;}');
290
test('for (let [a] = (1, [x]);;) {return a;}');
297
test('for (let [a] = (1, [x]);;) {return a;}');
291
test('for (let [a] = (1, x, 1, x);;) {return a;}', ['ponies']);
298
test('for (let [a] = (1, x, 1, x);;) {return a;}', ['ponies']);
292
isError('for (let x = 1, x = 2;;) {}');
299
isParseError('for (let x = 1, x = 2;;) {}');
293
isError('for (let [x, y] = a, {a:x} = b;;) {}');
300
isParseError('for (let [x, y] = a, {a:x} = b;;) {}');
294
isError('for (let [x, y, x] = a;;) {}');
301
isParseError('for (let [x, y, x] = a;;) {}');
295
isError('for (let [x, [y, [x]]] = a;;) {}');
302
isParseError('for (let [x, [y, [x]]] = a;;) {}');
296
303
297
// for(in)
304
// for(in)
298
test('for (let i in x) {return x;}');
305
test('for (let i in x) {return x;}');
299
test('for (let i in x) {let y;return x;}');
306
test('for (let i in x) {let y;return x;}');
300
test('for each (let [a, b] in x) {let y;return x;}');
307
test('for each (let [a, b] in x) {let y;return x;}');
301
test('for (let i in x) {let (i = x) {return i;}}');
308
test('for (let i in x) {let (i = x) {return i;}}');
302
test('for (let i in x) {let i = x;return i;}');
309
test('for (let i in x) {let i = x;return i;}');
303
test('for each (let [x, y] in x) {return x + y;}', [['ponies', '']]);
310
test('for each (let [x, y] in x) {return x + y;}', [['ponies', '']]);
 Lines 314-343   test('for (let i in x) {break;}return x;'); Link Here 
314
test('for (let i in x) {break;}return eval("x");');
321
test('for (let i in x) {break;}return eval("x");');
315
test('for (let x in x) {break;}return x;');
322
test('for (let x in x) {break;}return x;');
316
test('for (let x in x) {break;}return eval("x");');
323
test('for (let x in x) {break;}return eval("x");');
317
test('a:for (let i in x) {for (let j in x) {break a;}}return x;');
324
test('a:for (let i in x) {for (let j in x) {break a;}}return x;');
318
test('a:for (let i in x) {for (let j in x) {break a;}}return eval("x");');
325
test('a:for (let i in x) {for (let j in x) {break a;}}return eval("x");');
319
test('var j;for (let i in x) {j = i;break;}return j;', {ponies:true});
326
test('var j;for (let i in x) {j = i;break;}return j;', {ponies:true});
320
test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}');
327
test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}');
321
test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies']);
328
test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies']);
322
isError('for (let [x, x] in o) {}');
329
isParseError('for (let [x, x] in o) {}');
323
isError('for (let [x, y, x] in o) {}');
330
isParseError('for (let [x, y, x] in o) {}');
324
isError('for (let [x, [y, [x]]] in o) {}');
331
isParseError('for (let [x, [y, [x]]] in o) {}');
325
332
326
// genexps
333
// genexps
327
test('return (i for (i in x)).next();', {ponies:true});
334
test('return (i for (i in x)).next();', {ponies:true});
328
test('return (eval("i") for (i in x)).next();', {ponies:true});
335
test('return (eval("i") for (i in x)).next();', {ponies:true});
329
test('return (eval("i") for (i in eval("x"))).next();', {ponies:true});
336
test('return (eval("i") for (i in eval("x"))).next();', {ponies:true});
330
test('try {return (eval("throw i") for (i in x)).next();} catch (e) {return e;}', {ponies:true});
337
test('try {return (eval("throw i") for (i in x)).next();} catch (e) {return e;}', {ponies:true});
331
338
332
// array comprehension
339
// array comprehension
333
test('return [i for (i in x)][0];', {ponies:true});
340
test('return [i for (i in x)][0];', {ponies:true});
334
test('return [eval("i") for (i in x)][0];', {ponies:true});
341
test('return [eval("i") for (i in x)][0];', {ponies:true});
335
test('return [eval("i") for (i in eval("x"))][0];', {ponies:true});
342
test('return [eval("i") for (i in eval("x"))][0];', {ponies:true});
336
test('try {return [eval("throw i") for (i in x)][0];} catch (e) {return e;}', {ponies:true});
343
test('try {return [eval("throw i") for (i in x)][0];} catch (e) {return e;}', {ponies:true});
337
344
338
// don't forget about switch craziness
345
// don't forget about switch craziness
339
test('var y = 3;switch (function () {return eval("y");}()) {case 3:let y;return x;default:;}');
346
test('var y = 3;switch (function () {return eval("y");}()) {case 3:let y;return x;default:;}');
340
test('switch (x) {case 3:let y;return 3;case 4:let z;return 4;default:return x;}');
347
test('switch (x) {case 3:let y;return 3;case 4:let z;return 4;default:return x;}');
341
test('switch (x) {case 3:let x;break;default:if (x === undefined) {return "ponies";}}');
342
test('switch (x) {case 3:default:let y;let (y = x) {return y;}}');
348
test('switch (x) {case 3:default:let y;let (y = x) {return y;}}');
343
isError('switch (x) {case 3:let y;return 3;case 4:let y;return 4;default:;}');
349
isParseError('switch (x) {case 3:let y;return 3;case 4:let y;return 4;default:;}');
350
351
// TDZ checks
352
isReferenceError('x + 1; let x = 42;');
353
isReferenceError('x = 42; let x;');
354
isReferenceError('inner(); function inner() { x++; } let x;');
355
isReferenceError('inner(); let x; function inner() { x++; }');
356
isReferenceError('inner(); let x; function inner() { function innerer() { x++; } innerer(); }');
357
isReferenceError('let x; var inner = function () { y++; }; inner(); let y;');
358
isReferenceError('let x = x;');
359
isReferenceError('let [x] = [x];');
360
isReferenceError('let {x} = {x:x};');
361
isReferenceError('switch (x) {case 3:let x;break;default:if (x === undefined) {return "ponies";}}');
(-)a/js/src/jit-test/tests/debug/Environment-variables.js (-2 lines)
Line     Link Here 
 Lines 25-42   var cases = [ Link Here 
25
    "function f(x) { @@ } f(VAL);",
25
    "function f(x) { @@ } f(VAL);",
26
    "function f([w, x]) { @@ } f([0, VAL]);",
26
    "function f([w, x]) { @@ } f([0, VAL]);",
27
    "function f({v: x}) { @@ } f({v: VAL});",
27
    "function f({v: x}) { @@ } f({v: VAL});",
28
    "function f([w, {v: x}]) { @@ } f([0, {v: VAL}]);",
28
    "function f([w, {v: x}]) { @@ } f([0, {v: VAL}]);",
29
29
30
    // bindings in functions
30
    // bindings in functions
31
    "function f() { var x = VAL; @@ } f();",
31
    "function f() { var x = VAL; @@ } f();",
32
    "function f() { let x = VAL; @@ } f();",
32
    "function f() { let x = VAL; @@ } f();",
33
    "function f([x]) { let x = VAL; @@ } f(['fail']);",
34
    "function f(x) { { let x = VAL; @@ } } f('fail');",
35
    "function f() { function x() {} x = VAL; @@ } f();",
33
    "function f() { function x() {} x = VAL; @@ } f();",
36
34
37
    // dynamic bindings
35
    // dynamic bindings
38
    "function f(s) { eval(s); @@ } f('var x = VAL');",
36
    "function f(s) { eval(s); @@ } f('var x = VAL');",
39
    "function f(s) { let (x = 'fail') { eval(s); } x = VAL; @@ } f('var x;');",
37
    "function f(s) { let (x = 'fail') { eval(s); } x = VAL; @@ } f('var x;');",
40
    "var x = VAL; function f(s) { eval('var x = 0;'); eval(s); @@ } f('delete x;');",
38
    "var x = VAL; function f(s) { eval('var x = 0;'); eval(s); @@ } f('delete x;');",
41
    "function f(obj) { with (obj) { @@ } } f({x: VAL});",
39
    "function f(obj) { with (obj) { @@ } } f({x: VAL});",
42
    "function f(obj) { with (obj) { @@ } } f(Object.create({x: VAL}));",
40
    "function f(obj) { with (obj) { @@ } } f(Object.create({x: VAL}));",
(-)a/js/src/jit-test/tests/jaeger/bug583672.js (-2 / +2 lines)
Line     Link Here 
 Lines 4-30    Link Here 
4
        this.y = w
4
        this.y = w
5
        this.y = (void 0)
5
        this.y = (void 0)
6
        Object
6
        Object
7
    }
7
    }
8
    for (a in [0, 0, 0, 0])
8
    for (a in [0, 0, 0, 0])
9
    {
9
    {
10
        new f
10
        new f
11
    }
11
    }
12
    let w = {}
12
    var w = {}
13
})()
13
})()
14
14
15
/* Make sure that MICs don't have the same bug. */
15
/* Make sure that MICs don't have the same bug. */
16
x = Object();
16
x = Object();
17
(function () {
17
(function () {
18
    function f()
18
    function f()
19
    {
19
    {
20
        x = w
20
        x = w
21
        x = (void 0)
21
        x = (void 0)
22
        Object
22
        Object
23
    }
23
    }
24
    for (a in [0, 0, 0, 0])
24
    for (a in [0, 0, 0, 0])
25
    {
25
    {
26
        new f
26
        new f
27
    }
27
    }
28
    let w = {}
28
    var w = {}
29
})()
29
})()
30
/* Don't assert. */
30
/* Don't assert. */
(-)a/js/src/jit-test/tests/parallel/write-array.js (-1 / +1 lines)
Line     Link Here 
 Lines 1-14    Link Here 
1
load(libdir + "parallelarray-helpers.js");
1
load(libdir + "parallelarray-helpers.js");
2
2
3
function buildSimple() {
3
function buildSimple() {
4
  assertParallelModesCommute(["seq", "par"], function(m) {
4
  assertParallelModesCommute(["seq", "par"], function(m) {
5
    return Array.buildPar(256, function(i) {
5
    return Array.buildPar(256, function(i) {
6
      let obj = [0, 1, 2];
6
      var obj = [0, 1, 2];
7
      obj[0] += 1;
7
      obj[0] += 1;
8
      obj[1] += 1;
8
      obj[1] += 1;
9
      obj[2] += 1;
9
      obj[2] += 1;
10
      return obj;
10
      return obj;
11
    }, m);
11
    }, m);
12
  });
12
  });
13
}
13
}
14
14
(-)a/js/src/jit-test/tests/parallel/write-obj.js (-1 / +1 lines)
Line     Link Here 
 Lines 1-14    Link Here 
1
load(libdir + "parallelarray-helpers.js");
1
load(libdir + "parallelarray-helpers.js");
2
2
3
function buildSimple() {
3
function buildSimple() {
4
  assertParallelModesCommute(["seq", "par"], function(m) {
4
  assertParallelModesCommute(["seq", "par"], function(m) {
5
    Array.buildPar(256, function(i) {
5
    Array.buildPar(256, function(i) {
6
      let obj = { x: i, y: i + 1, z: i + 2 };
6
      var obj = { x: i, y: i + 1, z: i + 2 };
7
      obj.x += 1;
7
      obj.x += 1;
8
      obj.y += 1;
8
      obj.y += 1;
9
      obj.z += 1;
9
      obj.z += 1;
10
      return obj;
10
      return obj;
11
    }, m);
11
    }, m);
12
  });
12
  });
13
}
13
}
14
14
(-)a/js/src/jit/BaselineCompiler.cpp (-29 / +86 lines)
Line     Link Here 
 Lines 260-275   BaselineCompiler::compile() Link Here 
260
        code->setHasBytecodeMap();
260
        code->setHasBytecodeMap();
261
    }
261
    }
262
262
263
    script->setBaselineScript(cx, baselineScript);
263
    script->setBaselineScript(cx, baselineScript);
264
264
265
    return Method_Compiled;
265
    return Method_Compiled;
266
}
266
}
267
267
268
void
269
BaselineCompiler::emitInitializeLocals(size_t n, const Value &v)
270
{
271
    MOZ_ASSERT(frame.nlocals() > 0 && n <= frame.nlocals());
272
273
    // Use R0 to minimize code size. If the number of locals to push is <
274
    // LOOP_UNROLL_FACTOR, then the initialization pushes are emitted directly
275
    // and inline.  Otherwise, they're emitted in a partially unrolled loop.
276
    static const size_t LOOP_UNROLL_FACTOR = 4;
277
    size_t toPushExtra = n % LOOP_UNROLL_FACTOR;
278
279
    masm.moveValue(v, R0);
280
281
    // Handle any extra pushes left over by the optional unrolled loop below.
282
    for (size_t i = 0; i < toPushExtra; i++)
283
        masm.pushValue(R0);
284
285
    // Partially unrolled loop of pushes.
286
    if (n >= LOOP_UNROLL_FACTOR) {
287
        size_t toPush = n - toPushExtra;
288
        JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0);
289
        JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR);
290
        masm.move32(Imm32(toPush), R1.scratchReg());
291
        // Emit unrolled loop with 4 pushes per iteration.
292
        Label pushLoop;
293
        masm.bind(&pushLoop);
294
        for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++)
295
            masm.pushValue(R0);
296
        masm.branchSub32(Assembler::NonZero,
297
                         Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop);
298
    }
299
}
300
268
bool
301
bool
269
BaselineCompiler::emitPrologue()
302
BaselineCompiler::emitPrologue()
270
{
303
{
271
    masm.push(BaselineFrameReg);
304
    masm.push(BaselineFrameReg);
272
    masm.mov(BaselineStackReg, BaselineFrameReg);
305
    masm.mov(BaselineStackReg, BaselineFrameReg);
273
306
274
    masm.subPtr(Imm32(BaselineFrame::Size()), BaselineStackReg);
307
    masm.subPtr(Imm32(BaselineFrame::Size()), BaselineStackReg);
275
    masm.checkStackAlignment();
308
    masm.checkStackAlignment();
 Lines 316-360   BaselineCompiler::emitPrologue() Link Here 
316
        if (!emitStackCheck(/* earlyCheck = */ true))
349
        if (!emitStackCheck(/* earlyCheck = */ true))
317
            return false;
350
            return false;
318
        masm.branchTest32(Assembler::NonZero,
351
        masm.branchTest32(Assembler::NonZero,
319
                          frame.addressOfFlags(),
352
                          frame.addressOfFlags(),
320
                          Imm32(BaselineFrame::OVER_RECURSED),
353
                          Imm32(BaselineFrame::OVER_RECURSED),
321
                          &earlyStackCheckFailed);
354
                          &earlyStackCheckFailed);
322
    }
355
    }
323
356
324
    // Initialize locals to |undefined|. Use R0 to minimize code size.
357
    // Initialize local vars to |undefined| and local lets to a magic value
325
    // If the number of locals to push is < LOOP_UNROLL_FACTOR, then the
358
    // that throws on touch.
326
    // initialization pushes are emitted directly and inline.  Otherwise,
359
    if (frame.nvars() > 0)
327
    // they're emitted in a partially unrolled loop.
360
        emitInitializeLocals(frame.nvars(), UndefinedValue());
328
    if (frame.nlocals() > 0) {
361
    if (frame.nlets() > 0)
329
        size_t LOOP_UNROLL_FACTOR = 4;
362
        emitInitializeLocals(frame.nlets(), MagicValue(JS_UNINITIALIZED_LET));
330
        size_t toPushExtra = frame.nlocals() % LOOP_UNROLL_FACTOR;
331
332
        masm.moveValue(UndefinedValue(), R0);
333
334
        // Handle any extra pushes left over by the optional unrolled loop below.
335
        for (size_t i = 0; i < toPushExtra; i++)
336
            masm.pushValue(R0);
337
338
        // Partially unrolled loop of pushes.
339
        if (frame.nlocals() >= LOOP_UNROLL_FACTOR) {
340
            size_t toPush = frame.nlocals() - toPushExtra;
341
            JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0);
342
            JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR);
343
            masm.move32(Imm32(toPush), R1.scratchReg());
344
            // Emit unrolled loop with 4 pushes per iteration.
345
            Label pushLoop;
346
            masm.bind(&pushLoop);
347
            for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++)
348
                masm.pushValue(R0);
349
            masm.branchSub32(Assembler::NonZero,
350
                             Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop);
351
        }
352
    }
353
363
354
    if (needsEarlyStackCheck())
364
    if (needsEarlyStackCheck())
355
        masm.bind(&earlyStackCheckFailed);
365
        masm.bind(&earlyStackCheckFailed);
356
366
357
#ifdef JS_TRACE_LOGGING
367
#ifdef JS_TRACE_LOGGING
358
    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
368
    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
359
    Register loggerReg = RegisterSet::Volatile().takeGeneral();
369
    Register loggerReg = RegisterSet::Volatile().takeGeneral();
360
    masm.Push(loggerReg);
370
    masm.Push(loggerReg);
 Lines 2512-2527   BaselineCompiler::emit_JSOP_SETARG() Link Here 
2512
        script->setUninlineable();
2522
        script->setUninlineable();
2513
2523
2514
    modifiesArguments_ = true;
2524
    modifiesArguments_ = true;
2515
2525
2516
    uint32_t arg = GET_ARGNO(pc);
2526
    uint32_t arg = GET_ARGNO(pc);
2517
    return emitFormalArgAccess(arg, /* get = */ false);
2527
    return emitFormalArgAccess(arg, /* get = */ false);
2518
}
2528
}
2519
2529
2530
typedef bool (*ThrowUninitializedLetFn)(JSContext *cx);
2531
static const VMFunction ThrowUninitializedLetInfo =
2532
    FunctionInfo<ThrowUninitializedLetFn>(jit::ThrowUninitializedLet);
2533
2534
bool
2535
BaselineCompiler::emitUninitializedLetCheck(const ValueOperand &val)
2536
{
2537
    Label done;
2538
    masm.branchTestMagicValue(Assembler::NotEqual, val, JS_UNINITIALIZED_LET, &done);
2539
2540
    prepareVMCall();
2541
    if (!callVM(ThrowUninitializedLetInfo))
2542
        return false;
2543
2544
    masm.bind(&done);
2545
    return true;
2546
}
2547
2548
2549
bool
2550
BaselineCompiler::emit_JSOP_CHECKLET()
2551
{
2552
    frame.syncStack(0);
2553
    masm.loadValue(frame.addressOfLocal(GET_LOCALNO(pc)), R0);
2554
    return emitUninitializedLetCheck(R0);
2555
}
2556
2557
bool
2558
BaselineCompiler::emit_JSOP_INITLET()
2559
{
2560
    return emit_JSOP_SETLOCAL();
2561
}
2562
2563
bool
2564
BaselineCompiler::emit_JSOP_CHECKALIASEDLET()
2565
{
2566
    frame.syncStack(0);
2567
    masm.loadValue(getScopeCoordinateAddress(R0.scratchReg()), R0);
2568
    return emitUninitializedLetCheck(R0);
2569
}
2570
2571
bool
2572
BaselineCompiler::emit_JSOP_INITALIASEDLET()
2573
{
2574
    return emit_JSOP_SETALIASEDVAR();
2575
}
2576
2520
bool
2577
bool
2521
BaselineCompiler::emitCall()
2578
BaselineCompiler::emitCall()
2522
{
2579
{
2523
    JS_ASSERT(IsCallPC(pc));
2580
    JS_ASSERT(IsCallPC(pc));
2524
2581
2525
    uint32_t argc = GET_ARGC(pc);
2582
    uint32_t argc = GET_ARGC(pc);
2526
2583
2527
    frame.syncStack(0);
2584
    frame.syncStack(0);
(-)a/js/src/jit/BaselineCompiler.h (+7 lines)
Line     Link Here 
 Lines 129-144   namespace jit { Link Here 
129
    _(JSOP_DEFVAR)             \
129
    _(JSOP_DEFVAR)             \
130
    _(JSOP_DEFCONST)           \
130
    _(JSOP_DEFCONST)           \
131
    _(JSOP_SETCONST)           \
131
    _(JSOP_SETCONST)           \
132
    _(JSOP_DEFFUN)             \
132
    _(JSOP_DEFFUN)             \
133
    _(JSOP_GETLOCAL)           \
133
    _(JSOP_GETLOCAL)           \
134
    _(JSOP_SETLOCAL)           \
134
    _(JSOP_SETLOCAL)           \
135
    _(JSOP_GETARG)             \
135
    _(JSOP_GETARG)             \
136
    _(JSOP_SETARG)             \
136
    _(JSOP_SETARG)             \
137
    _(JSOP_CHECKLET)           \
138
    _(JSOP_INITLET)            \
139
    _(JSOP_CHECKALIASEDLET)    \
140
    _(JSOP_INITALIASEDLET)     \
137
    _(JSOP_CALL)               \
141
    _(JSOP_CALL)               \
138
    _(JSOP_FUNCALL)            \
142
    _(JSOP_FUNCALL)            \
139
    _(JSOP_FUNAPPLY)           \
143
    _(JSOP_FUNAPPLY)           \
140
    _(JSOP_NEW)                \
144
    _(JSOP_NEW)                \
141
    _(JSOP_EVAL)               \
145
    _(JSOP_EVAL)               \
142
    _(JSOP_SPREADCALL)         \
146
    _(JSOP_SPREADCALL)         \
143
    _(JSOP_SPREADNEW)          \
147
    _(JSOP_SPREADNEW)          \
144
    _(JSOP_SPREADEVAL)         \
148
    _(JSOP_SPREADEVAL)         \
 Lines 208-223   class BaselineCompiler : public BaselineCompilerSpecific Link Here 
208
    BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script);
212
    BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script);
209
    bool init();
213
    bool init();
210
214
211
    MethodStatus compile();
215
    MethodStatus compile();
212
216
213
  private:
217
  private:
214
    MethodStatus emitBody();
218
    MethodStatus emitBody();
215
219
220
    void emitInitializeLocals(size_t n, const Value &v);
216
    bool emitPrologue();
221
    bool emitPrologue();
217
    bool emitEpilogue();
222
    bool emitEpilogue();
218
#ifdef JSGC_GENERATIONAL
223
#ifdef JSGC_GENERATIONAL
219
    bool emitOutOfLinePostBarrierSlot();
224
    bool emitOutOfLinePostBarrierSlot();
220
#endif
225
#endif
221
    bool emitIC(ICStub *stub, ICEntry::Kind kind);
226
    bool emitIC(ICStub *stub, ICEntry::Kind kind);
222
    bool emitOpIC(ICStub *stub) {
227
    bool emitOpIC(ICStub *stub) {
223
        return emitIC(stub, ICEntry::Kind_Op);
228
        return emitIC(stub, ICEntry::Kind_Op);
 Lines 261-276   class BaselineCompiler : public BaselineCompilerSpecific Link Here 
261
    bool emitCall();
266
    bool emitCall();
262
    bool emitSpreadCall();
267
    bool emitSpreadCall();
263
268
264
    bool emitInitPropGetterSetter();
269
    bool emitInitPropGetterSetter();
265
    bool emitInitElemGetterSetter();
270
    bool emitInitElemGetterSetter();
266
271
267
    bool emitFormalArgAccess(uint32_t arg, bool get);
272
    bool emitFormalArgAccess(uint32_t arg, bool get);
268
273
274
    bool emitUninitializedLetCheck(const ValueOperand &val);
275
269
    bool addPCMappingEntry(bool addIndexEntry);
276
    bool addPCMappingEntry(bool addIndexEntry);
270
277
271
    void getScopeCoordinateObject(Register reg);
278
    void getScopeCoordinateObject(Register reg);
272
    Address getScopeCoordinateAddressFromObject(Register objReg, Register reg);
279
    Address getScopeCoordinateAddressFromObject(Register objReg, Register reg);
273
    Address getScopeCoordinateAddress(Register reg);
280
    Address getScopeCoordinateAddress(Register reg);
274
};
281
};
275
282
276
} // namespace jit
283
} // namespace jit
(-)a/js/src/jit/BaselineFrame.cpp (-2 / +2 lines)
Line     Link Here 
 Lines 52-68   BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) Link Here 
52
        gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript");
52
        gc::MarkScriptRoot(trc, &evalScript_, "baseline-evalscript");
53
53
54
    if (hasArgsObj())
54
    if (hasArgsObj())
55
        gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj");
55
        gc::MarkObjectRoot(trc, &argsObj_, "baseline-args-obj");
56
56
57
    // Mark locals and stack values.
57
    // Mark locals and stack values.
58
    JSScript *script = this->script();
58
    JSScript *script = this->script();
59
    size_t nfixed = script->nfixed();
59
    size_t nfixed = script->nfixed();
60
    size_t nlivefixed = script->nfixedvars();
60
    size_t nlivefixed = script->nbodyfixed();
61
61
62
    if (nfixed != nlivefixed) {
62
    if (nfixed != nlivefixed) {
63
        jsbytecode *pc;
63
        jsbytecode *pc;
64
        NestedScopeObject *staticScope;
64
        NestedScopeObject *staticScope;
65
65
66
        frameIterator.baselineScriptAndPc(nullptr, &pc);
66
        frameIterator.baselineScriptAndPc(nullptr, &pc);
67
        staticScope = script->getStaticScope(pc);
67
        staticScope = script->getStaticScope(pc);
68
        while (staticScope && !staticScope->is<StaticBlockObject>())
68
        while (staticScope && !staticScope->is<StaticBlockObject>())
 Lines 70-86   BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) Link Here 
70
70
71
        if (staticScope) {
71
        if (staticScope) {
72
            StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
72
            StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
73
            nlivefixed = blockObj.localOffset() + blockObj.numVariables();
73
            nlivefixed = blockObj.localOffset() + blockObj.numVariables();
74
        }
74
        }
75
    }
75
    }
76
76
77
    JS_ASSERT(nlivefixed <= nfixed);
77
    JS_ASSERT(nlivefixed <= nfixed);
78
    JS_ASSERT(nlivefixed >= script->nfixedvars());
78
    JS_ASSERT(nlivefixed >= script->nbodyfixed());
79
79
80
    // NB: It is possible that numValueSlots() could be zero, even if nfixed is
80
    // NB: It is possible that numValueSlots() could be zero, even if nfixed is
81
    // nonzero.  This is the case if the function has an early stack check.
81
    // nonzero.  This is the case if the function has an early stack check.
82
    if (numValueSlots() == 0)
82
    if (numValueSlots() == 0)
83
        return;
83
        return;
84
84
85
    JS_ASSERT(nfixed <= numValueSlots());
85
    JS_ASSERT(nfixed <= numValueSlots());
86
86
(-)a/js/src/jit/BaselineFrameInfo.h (-2 / +8 lines)
Line     Link Here 
 Lines 171-192   class FrameInfo Link Here 
171
      : script(script),
171
      : script(script),
172
        masm(masm),
172
        masm(masm),
173
        stack(),
173
        stack(),
174
        spIndex(0)
174
        spIndex(0)
175
    { }
175
    { }
176
176
177
    bool init(TempAllocator &alloc);
177
    bool init(TempAllocator &alloc);
178
178
179
    uint32_t nlocals() const {
179
    size_t nlocals() const {
180
        return script->nfixed();
180
        return script->nfixed();
181
    }
181
    }
182
    uint32_t nargs() const {
182
    size_t nargs() const {
183
        return script->functionNonDelazifying()->nargs();
183
        return script->functionNonDelazifying()->nargs();
184
    }
184
    }
185
    size_t nvars() const {
186
        return script->nfixedvars();
187
    }
188
    size_t nlets() const {
189
        return script->fixedLetEnd() - script->fixedLetBegin();
190
    }
185
191
186
  private:
192
  private:
187
    inline StackValue *rawPush() {
193
    inline StackValue *rawPush() {
188
        StackValue *val = &stack[spIndex++];
194
        StackValue *val = &stack[spIndex++];
189
        val->reset();
195
        val->reset();
190
        return val;
196
        return val;
191
    }
197
    }
192
198
(-)a/js/src/jit/BaselineIC.cpp (-5 / +7 lines)
Line     Link Here 
 Lines 1531-1547   DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H Link Here 
1531
        id = JSID_VOID;
1531
        id = JSID_VOID;
1532
        types::AddTypePropertyId(cx, obj, id, value);
1532
        types::AddTypePropertyId(cx, obj, id, value);
1533
        break;
1533
        break;
1534
      }
1534
      }
1535
      case ICStub::SetProp_Native:
1535
      case ICStub::SetProp_Native:
1536
      case ICStub::SetProp_NativeAdd: {
1536
      case ICStub::SetProp_NativeAdd: {
1537
        JS_ASSERT(obj->isNative());
1537
        JS_ASSERT(obj->isNative());
1538
        jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
1538
        jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
1539
        if (*pc == JSOP_SETALIASEDVAR)
1539
        if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLET)
1540
            id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
1540
            id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
1541
        else
1541
        else
1542
            id = NameToId(script->getName(pc));
1542
            id = NameToId(script->getName(pc));
1543
        types::AddTypePropertyId(cx, obj, id, value);
1543
        types::AddTypePropertyId(cx, obj, id, value);
1544
        break;
1544
        break;
1545
      }
1545
      }
1546
      default:
1546
      default:
1547
        MOZ_ASSUME_UNREACHABLE("Invalid stub");
1547
        MOZ_ASSUME_UNREACHABLE("Invalid stub");
 Lines 5971-5987   DoBindNameFallback(JSContext *cx, BaselineFrame *frame, ICBindName_Fallback *stu Link Here 
5971
    mozilla::DebugOnly<JSOp> op = JSOp(*pc);
5971
    mozilla::DebugOnly<JSOp> op = JSOp(*pc);
5972
    FallbackICSpew(cx, stub, "BindName(%s)", js_CodeName[JSOp(*pc)]);
5972
    FallbackICSpew(cx, stub, "BindName(%s)", js_CodeName[JSOp(*pc)]);
5973
5973
5974
    JS_ASSERT(op == JSOP_BINDNAME);
5974
    JS_ASSERT(op == JSOP_BINDNAME);
5975
5975
5976
    RootedPropertyName name(cx, frame->script()->getName(pc));
5976
    RootedPropertyName name(cx, frame->script()->getName(pc));
5977
5977
5978
    RootedObject scope(cx);
5978
    RootedObject scope(cx);
5979
    if (!LookupNameUnqualified(cx, name, scopeChain, &scope))
5979
    RootedShape shape(cx);
5980
    if (!LookupNameUnqualified(cx, name, scopeChain, &scope, &shape))
5980
        return false;
5981
        return false;
5981
5982
5982
    res.setObject(*scope);
5983
    res.setObject(*scope);
5983
    return true;
5984
    return true;
5984
}
5985
}
5985
5986
5986
typedef bool (*DoBindNameFallbackFn)(JSContext *, BaselineFrame *, ICBindName_Fallback *,
5987
typedef bool (*DoBindNameFallbackFn)(JSContext *, BaselineFrame *, ICBindName_Fallback *,
5987
                                     HandleObject, MutableHandleValue);
5988
                                     HandleObject, MutableHandleValue);
 Lines 7522-7541   DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ Link Here 
7522
    jsbytecode *pc = stub->icEntry()->pc(script);
7523
    jsbytecode *pc = stub->icEntry()->pc(script);
7523
    JSOp op = JSOp(*pc);
7524
    JSOp op = JSOp(*pc);
7524
    FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
7525
    FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
7525
7526
7526
    JS_ASSERT(op == JSOP_SETPROP ||
7527
    JS_ASSERT(op == JSOP_SETPROP ||
7527
              op == JSOP_SETNAME ||
7528
              op == JSOP_SETNAME ||
7528
              op == JSOP_SETGNAME ||
7529
              op == JSOP_SETGNAME ||
7529
              op == JSOP_INITPROP ||
7530
              op == JSOP_INITPROP ||
7530
              op == JSOP_SETALIASEDVAR);
7531
              op == JSOP_SETALIASEDVAR ||
7532
              op == JSOP_INITALIASEDLET);
7531
7533
7532
    RootedPropertyName name(cx);
7534
    RootedPropertyName name(cx);
7533
    if (op == JSOP_SETALIASEDVAR)
7535
    if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLET)
7534
        name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
7536
        name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
7535
    else
7537
    else
7536
        name = script->getName(pc);
7538
        name = script->getName(pc);
7537
    RootedId id(cx, NameToId(name));
7539
    RootedId id(cx, NameToId(name));
7538
7540
7539
    RootedObject obj(cx, ToObjectFromStack(cx, lhs));
7541
    RootedObject obj(cx, ToObjectFromStack(cx, lhs));
7540
    if (!obj)
7542
    if (!obj)
7541
        return false;
7543
        return false;
 Lines 7545-7561   DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ Link Here 
7545
    if (op == JSOP_INITPROP) {
7547
    if (op == JSOP_INITPROP) {
7546
        MOZ_ASSERT(name != cx->names().proto, "should have used JSOP_MUTATEPROTO");
7548
        MOZ_ASSERT(name != cx->names().proto, "should have used JSOP_MUTATEPROTO");
7547
        MOZ_ASSERT(obj->is<JSObject>());
7549
        MOZ_ASSERT(obj->is<JSObject>());
7548
        if (!DefineNativeProperty(cx, obj, id, rhs, nullptr, nullptr, JSPROP_ENUMERATE))
7550
        if (!DefineNativeProperty(cx, obj, id, rhs, nullptr, nullptr, JSPROP_ENUMERATE))
7549
            return false;
7551
            return false;
7550
    } else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
7552
    } else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
7551
        if (!SetNameOperation(cx, script, pc, obj, rhs))
7553
        if (!SetNameOperation(cx, script, pc, obj, rhs))
7552
            return false;
7554
            return false;
7553
    } else if (op == JSOP_SETALIASEDVAR) {
7555
    } else if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLET) {
7554
        obj->as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs);
7556
        obj->as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs);
7555
    } else {
7557
    } else {
7556
        MOZ_ASSERT(op == JSOP_SETPROP);
7558
        MOZ_ASSERT(op == JSOP_SETPROP);
7557
        if (script->strict()) {
7559
        if (script->strict()) {
7558
            if (!js::SetProperty<true>(cx, obj, id, rhs))
7560
            if (!js::SetProperty<true>(cx, obj, id, rhs))
7559
                return false;
7561
                return false;
7560
        } else {
7562
        } else {
7561
            if (!js::SetProperty<false>(cx, obj, id, rhs))
7563
            if (!js::SetProperty<false>(cx, obj, id, rhs))
(-)a/js/src/jit/CodeGenerator.cpp (+22 lines)
Line     Link Here 
 Lines 8988-8997   CodeGenerator::visitRecompileCheck(LRecompileCheck *ins) Link Here 
8988
                  Imm32(0),
8988
                  Imm32(0),
8989
                  ool->entry());
8989
                  ool->entry());
8990
    masm.bind(ool->rejoin());
8990
    masm.bind(ool->rejoin());
8991
    masm.bind(&done);
8991
    masm.bind(&done);
8992
8992
8993
    return true;
8993
    return true;
8994
}
8994
}
8995
8995
8996
typedef bool (*ThrowUninitializedLetFn)(JSContext *);
8997
static const VMFunction ThrowUninitializedLetInfo =
8998
    FunctionInfo<ThrowUninitializedLetFn>(ThrowUninitializedLet);
8999
9000
bool
9001
CodeGenerator::visitLetCheck(LLetCheck *ins)
9002
{
9003
    OutOfLineCode *ool = oolCallVM(ThrowUninitializedLetInfo, ins, (ArgList()), StoreNothing());
9004
    if (!ool)
9005
        return false;
9006
    ValueOperand inputValue = ToValue(ins, LLetCheck::Input);
9007
    masm.branchTestMagicValue(Assembler::Equal, inputValue, JS_UNINITIALIZED_LET, ool->entry());
9008
    masm.bind(ool->rejoin());
9009
    return true;
9010
}
9011
9012
bool
9013
CodeGenerator::visitThrowUninitializedLet(LThrowUninitializedLet *ins)
9014
{
9015
    return callVM(ThrowUninitializedLetInfo, ins);
9016
}
9017
8996
} // namespace jit
9018
} // namespace jit
8997
} // namespace js
9019
} // namespace js
(-)a/js/src/jit/CodeGenerator.h (+2 lines)
Line     Link Here 
 Lines 295-310   class CodeGenerator : public CodeGeneratorSpecific Link Here 
295
    bool visitIsCallable(LIsCallable *lir);
295
    bool visitIsCallable(LIsCallable *lir);
296
    bool visitIsObject(LIsObject *lir);
296
    bool visitIsObject(LIsObject *lir);
297
    bool visitHaveSameClass(LHaveSameClass *lir);
297
    bool visitHaveSameClass(LHaveSameClass *lir);
298
    bool visitHasClass(LHasClass *lir);
298
    bool visitHasClass(LHasClass *lir);
299
    bool visitAsmJSCall(LAsmJSCall *lir);
299
    bool visitAsmJSCall(LAsmJSCall *lir);
300
    bool visitAsmJSParameter(LAsmJSParameter *lir);
300
    bool visitAsmJSParameter(LAsmJSParameter *lir);
301
    bool visitAsmJSReturn(LAsmJSReturn *ret);
301
    bool visitAsmJSReturn(LAsmJSReturn *ret);
302
    bool visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
302
    bool visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
303
    bool visitLetCheck(LLetCheck *ins);
304
    bool visitThrowUninitializedLet(LThrowUninitializedLet *ins);
303
305
304
    bool visitCheckOverRecursed(LCheckOverRecursed *lir);
306
    bool visitCheckOverRecursed(LCheckOverRecursed *lir);
305
    bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
307
    bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
306
308
307
    bool visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
309
    bool visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
308
310
309
    bool visitInterruptCheckPar(LInterruptCheckPar *lir);
311
    bool visitInterruptCheckPar(LInterruptCheckPar *lir);
310
    bool visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
312
    bool visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
(-)a/js/src/jit/CompileInfo.h (-10 / +17 lines)
Line     Link Here 
 Lines 182-214   class CompileInfo Link Here 
182
            JS_ASSERT(fun_->isTenured());
182
            JS_ASSERT(fun_->isTenured());
183
        }
183
        }
184
184
185
        osrStaticScope_ = osrPc ? script->getStaticScope(osrPc) : nullptr;
185
        osrStaticScope_ = osrPc ? script->getStaticScope(osrPc) : nullptr;
186
186
187
        nimplicit_ = StartArgSlot(script)                   /* scope chain and argument obj */
187
        nimplicit_ = StartArgSlot(script)                   /* scope chain and argument obj */
188
                   + (fun ? 1 : 0);                         /* this */
188
                   + (fun ? 1 : 0);                         /* this */
189
        nargs_ = fun ? fun->nargs() : 0;
189
        nargs_ = fun ? fun->nargs() : 0;
190
        nfixedvars_ = script->nfixedvars();
190
        nbodyfixed_ = script->nbodyfixed();
191
        nlocals_ = script->nfixed();
191
        nlocals_ = script->nfixed();
192
        fixedLetBegin_ = script->fixedLetBegin();
192
        nstack_ = script->nslots() - script->nfixed();
193
        nstack_ = script->nslots() - script->nfixed();
193
        nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
194
        nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
194
    }
195
    }
195
196
196
    CompileInfo(unsigned nlocals, ExecutionMode executionMode)
197
    CompileInfo(unsigned nlocals, ExecutionMode executionMode)
197
      : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr),
198
      : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr),
198
        constructing_(false), executionMode_(executionMode), scriptNeedsArgsObj_(false),
199
        constructing_(false), executionMode_(executionMode), scriptNeedsArgsObj_(false),
199
        inlineScriptTree_(nullptr)
200
        inlineScriptTree_(nullptr)
200
    {
201
    {
201
        nimplicit_ = 0;
202
        nimplicit_ = 0;
202
        nargs_ = 0;
203
        nargs_ = 0;
203
        nfixedvars_ = 0;
204
        nbodyfixed_ = 0;
204
        nlocals_ = nlocals;
205
        nlocals_ = nlocals;
205
        nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
206
        nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
206
        nslots_ = nlocals_ + nstack_;
207
        nslots_ = nlocals_ + nstack_;
208
        fixedLetBegin_ = nlocals;
207
    }
209
    }
208
210
209
    JSScript *script() const {
211
    JSScript *script() const {
210
        return script_;
212
        return script_;
211
    }
213
    }
212
    bool compilingAsmJS() const {
214
    bool compilingAsmJS() const {
213
        return script() == nullptr;
215
        return script() == nullptr;
214
    }
216
    }
 Lines 286-314   class CompileInfo Link Here 
286
    // maybe argumentsobject and this value.
288
    // maybe argumentsobject and this value.
287
    unsigned nimplicit() const {
289
    unsigned nimplicit() const {
288
        return nimplicit_;
290
        return nimplicit_;
289
    }
291
    }
290
    // Number of arguments (without counting this value).
292
    // Number of arguments (without counting this value).
291
    unsigned nargs() const {
293
    unsigned nargs() const {
292
        return nargs_;
294
        return nargs_;
293
    }
295
    }
294
    // Number of slots needed for "fixed vars".  Note that this is only non-zero
296
    // Number of slots needed for fixed body-level bindings.  Note that this
295
    // for function code.
297
    // is only non-zero for function code.
296
    unsigned nfixedvars() const {
298
    unsigned nbodyfixed() const {
297
        return nfixedvars_;
299
        return nbodyfixed_;
298
    }
300
    }
299
    // Number of slots needed for all local variables.  This includes "fixed
301
    // Number of slots needed for all local variables.  This includes "fixed
300
    // vars" (see above) and also block-scoped locals.
302
    // vars" (see above) and also block-scoped locals.
301
    unsigned nlocals() const {
303
    unsigned nlocals() const {
302
        return nlocals_;
304
        return nlocals_;
303
    }
305
    }
304
    unsigned ninvoke() const {
306
    unsigned ninvoke() const {
305
        return nslots_ - nstack_;
307
        return nslots_ - nstack_;
306
    }
308
    }
309
    // The slot number at which fixed lets begin.
310
    unsigned fixedLetBegin() const {
311
        return fixedLetBegin_;
312
    }
307
313
308
    uint32_t scopeChainSlot() const {
314
    uint32_t scopeChainSlot() const {
309
        JS_ASSERT(script());
315
        JS_ASSERT(script());
310
        return 0;
316
        return 0;
311
    }
317
    }
312
    uint32_t returnValueSlot() const {
318
    uint32_t returnValueSlot() const {
313
        JS_ASSERT(script());
319
        JS_ASSERT(script());
314
        return 1;
320
        return 1;
 Lines 372-390   class CompileInfo Link Here 
372
            return false;
378
            return false;
373
379
374
        uint32_t arg = index - firstArgSlot();
380
        uint32_t arg = index - firstArgSlot();
375
        if (arg < nargs())
381
        if (arg < nargs())
376
            return script()->formalIsAliased(arg);
382
            return script()->formalIsAliased(arg);
377
383
378
        uint32_t local = index - firstLocalSlot();
384
        uint32_t local = index - firstLocalSlot();
379
        if (local < nlocals()) {
385
        if (local < nlocals()) {
380
            // First, check if this local is a var.
386
            // First, check if this local is body-level.
381
            if (local < nfixedvars())
387
            if (local < nbodyfixed())
382
                return script()->varIsAliased(local);
388
                return script()->bodyLevelLocalIsAliased(local);
383
389
384
            // Otherwise, it might be part of a block scope.
390
            // Otherwise, it might be part of a block scope.
385
            for (; staticScope; staticScope = staticScope->enclosingNestedScope()) {
391
            for (; staticScope; staticScope = staticScope->enclosingNestedScope()) {
386
                if (!staticScope->is<StaticBlockObject>())
392
                if (!staticScope->is<StaticBlockObject>())
387
                    continue;
393
                    continue;
388
                StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
394
                StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
389
                if (blockObj.localOffset() < local) {
395
                if (blockObj.localOffset() < local) {
390
                    if (local - blockObj.localOffset() < blockObj.numVariables())
396
                    if (local - blockObj.localOffset() < blockObj.numVariables())
 Lines 461-480   class CompileInfo Link Here 
461
        }
467
        }
462
468
463
        return false;
469
        return false;
464
    }
470
    }
465
471
466
  private:
472
  private:
467
    unsigned nimplicit_;
473
    unsigned nimplicit_;
468
    unsigned nargs_;
474
    unsigned nargs_;
469
    unsigned nfixedvars_;
475
    unsigned nbodyfixed_;
470
    unsigned nlocals_;
476
    unsigned nlocals_;
471
    unsigned nstack_;
477
    unsigned nstack_;
472
    unsigned nslots_;
478
    unsigned nslots_;
479
    unsigned fixedLetBegin_;
473
    JSScript *script_;
480
    JSScript *script_;
474
    JSFunction *fun_;
481
    JSFunction *fun_;
475
    jsbytecode *osrPc_;
482
    jsbytecode *osrPc_;
476
    NestedScopeObject *osrStaticScope_;
483
    NestedScopeObject *osrStaticScope_;
477
    bool constructing_;
484
    bool constructing_;
478
    ExecutionMode executionMode_;
485
    ExecutionMode executionMode_;
479
486
480
    // Whether a script needs an arguments object is unstable over compilation
487
    // Whether a script needs an arguments object is unstable over compilation
(-)a/js/src/jit/IonAnalysis.cpp (-1 / +5 lines)
Line     Link Here 
 Lines 1086-1101   TypeAnalyzer::replaceRedundantPhi(MPhi *phi) Link Here 
1086
        v = NullValue();
1086
        v = NullValue();
1087
        break;
1087
        break;
1088
      case MIRType_MagicOptimizedArguments:
1088
      case MIRType_MagicOptimizedArguments:
1089
        v = MagicValue(JS_OPTIMIZED_ARGUMENTS);
1089
        v = MagicValue(JS_OPTIMIZED_ARGUMENTS);
1090
        break;
1090
        break;
1091
      case MIRType_MagicOptimizedOut:
1091
      case MIRType_MagicOptimizedOut:
1092
        v = MagicValue(JS_OPTIMIZED_OUT);
1092
        v = MagicValue(JS_OPTIMIZED_OUT);
1093
        break;
1093
        break;
1094
      case MIRType_MagicUninitializedLet:
1095
        v = MagicValue(JS_UNINITIALIZED_LET);
1096
        break;
1094
      default:
1097
      default:
1095
        MOZ_ASSUME_UNREACHABLE("unexpected type");
1098
        MOZ_ASSUME_UNREACHABLE("unexpected type");
1096
    }
1099
    }
1097
    MConstant *c = MConstant::New(alloc(), v);
1100
    MConstant *c = MConstant::New(alloc(), v);
1098
    // The instruction pass will insert the box
1101
    // The instruction pass will insert the box
1099
    block->insertBefore(*(block->begin()), c);
1102
    block->insertBefore(*(block->begin()), c);
1100
    phi->replaceAllUsesWith(c);
1103
    phi->replaceAllUsesWith(c);
1101
}
1104
}
 Lines 1109-1125   TypeAnalyzer::insertConversions() Link Here 
1109
    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
1112
    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
1110
        if (mir->shouldCancel("Insert Conversions"))
1113
        if (mir->shouldCancel("Insert Conversions"))
1111
            return false;
1114
            return false;
1112
1115
1113
        for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
1116
        for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
1114
            if (phi->type() == MIRType_Undefined ||
1117
            if (phi->type() == MIRType_Undefined ||
1115
                phi->type() == MIRType_Null ||
1118
                phi->type() == MIRType_Null ||
1116
                phi->type() == MIRType_MagicOptimizedArguments ||
1119
                phi->type() == MIRType_MagicOptimizedArguments ||
1117
                phi->type() == MIRType_MagicOptimizedOut)
1120
                phi->type() == MIRType_MagicOptimizedOut ||
1121
                phi->type() == MIRType_MagicUninitializedLet)
1118
            {
1122
            {
1119
                replaceRedundantPhi(*phi);
1123
                replaceRedundantPhi(*phi);
1120
                phi = block->discardPhiAt(phi);
1124
                phi = block->discardPhiAt(phi);
1121
            } else {
1125
            } else {
1122
                adjustPhiInputs(*phi);
1126
                adjustPhiInputs(*phi);
1123
                phi++;
1127
                phi++;
1124
            }
1128
            }
1125
        }
1129
        }
(-)a/js/src/jit/IonBuilder.cpp (-37 / +129 lines)
Line     Link Here 
 Lines 62-109   jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, Compil Link Here 
62
    BaselineFrameInspector *inspector = temp->lifoAlloc()->new_<BaselineFrameInspector>(temp);
62
    BaselineFrameInspector *inspector = temp->lifoAlloc()->new_<BaselineFrameInspector>(temp);
63
    if (!inspector)
63
    if (!inspector)
64
        return nullptr;
64
        return nullptr;
65
65
66
    // Note: copying the actual values into a temporary structure for use
66
    // Note: copying the actual values into a temporary structure for use
67
    // during compilation could capture nursery pointers, so the values' types
67
    // during compilation could capture nursery pointers, so the values' types
68
    // are recorded instead.
68
    // are recorded instead.
69
69
70
    inspector->thisType = types::GetMaybeOptimizedOutValueType(frame->thisValue());
70
    inspector->thisType = types::GetMaybeUntrackedValueType(frame->thisValue());
71
71
72
    if (frame->scopeChain()->hasSingletonType())
72
    if (frame->scopeChain()->hasSingletonType())
73
        inspector->singletonScopeChain = frame->scopeChain();
73
        inspector->singletonScopeChain = frame->scopeChain();
74
74
75
    JSScript *script = frame->script();
75
    JSScript *script = frame->script();
76
76
77
    if (script->functionNonDelazifying()) {
77
    if (script->functionNonDelazifying()) {
78
        if (!inspector->argTypes.reserve(frame->numFormalArgs()))
78
        if (!inspector->argTypes.reserve(frame->numFormalArgs()))
79
            return nullptr;
79
            return nullptr;
80
        for (size_t i = 0; i < frame->numFormalArgs(); i++) {
80
        for (size_t i = 0; i < frame->numFormalArgs(); i++) {
81
            if (script->formalIsAliased(i)) {
81
            if (script->formalIsAliased(i)) {
82
                inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
82
                inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
83
            } else if (!script->argsObjAliasesFormals()) {
83
            } else if (!script->argsObjAliasesFormals()) {
84
                types::Type type = types::GetMaybeOptimizedOutValueType(frame->unaliasedFormal(i));
84
                types::Type type = types::GetMaybeUntrackedValueType(frame->unaliasedFormal(i));
85
                inspector->argTypes.infallibleAppend(type);
85
                inspector->argTypes.infallibleAppend(type);
86
            } else if (frame->hasArgsObj()) {
86
            } else if (frame->hasArgsObj()) {
87
                types::Type type = types::GetMaybeOptimizedOutValueType(frame->argsObj().arg(i));
87
                types::Type type = types::GetMaybeUntrackedValueType(frame->argsObj().arg(i));
88
                inspector->argTypes.infallibleAppend(type);
88
                inspector->argTypes.infallibleAppend(type);
89
            } else {
89
            } else {
90
                inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
90
                inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
91
            }
91
            }
92
        }
92
        }
93
    }
93
    }
94
94
95
    if (!inspector->varTypes.reserve(frame->script()->nfixed()))
95
    if (!inspector->varTypes.reserve(frame->script()->nfixed()))
96
        return nullptr;
96
        return nullptr;
97
    for (size_t i = 0; i < frame->script()->nfixed(); i++) {
97
    for (size_t i = 0; i < frame->script()->nfixed(); i++) {
98
        if (info->isSlotAliasedAtOsr(i + info->firstLocalSlot())) {
98
        if (info->isSlotAliasedAtOsr(i + info->firstLocalSlot())) {
99
            inspector->varTypes.infallibleAppend(types::Type::UndefinedType());
99
            inspector->varTypes.infallibleAppend(types::Type::UndefinedType());
100
        } else {
100
        } else {
101
            types::Type type = types::GetMaybeOptimizedOutValueType(frame->unaliasedLocal(i));
101
            types::Type type = types::GetMaybeUntrackedValueType(frame->unaliasedLocal(i));
102
            inspector->varTypes.infallibleAppend(type);
102
            inspector->varTypes.infallibleAppend(type);
103
        }
103
        }
104
    }
104
    }
105
105
106
    return inspector;
106
    return inspector;
107
}
107
}
108
108
109
IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
109
IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
 Lines 120-135   IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Link Here 
120
    constraints_(constraints),
120
    constraints_(constraints),
121
    analysis_(*temp, info->script()),
121
    analysis_(*temp, info->script()),
122
    thisTypes(nullptr),
122
    thisTypes(nullptr),
123
    argTypes(nullptr),
123
    argTypes(nullptr),
124
    typeArray(nullptr),
124
    typeArray(nullptr),
125
    typeArrayHint(0),
125
    typeArrayHint(0),
126
    bytecodeTypeMap(nullptr),
126
    bytecodeTypeMap(nullptr),
127
    loopDepth_(loopDepth),
127
    loopDepth_(loopDepth),
128
    letCheck_(nullptr),
128
    callerResumePoint_(nullptr),
129
    callerResumePoint_(nullptr),
129
    callerBuilder_(nullptr),
130
    callerBuilder_(nullptr),
130
    cfgStack_(*temp),
131
    cfgStack_(*temp),
131
    loops_(*temp),
132
    loops_(*temp),
132
    switches_(*temp),
133
    switches_(*temp),
133
    labels_(*temp),
134
    labels_(*temp),
134
    iterators_(*temp),
135
    iterators_(*temp),
135
    loopHeaders_(*temp),
136
    loopHeaders_(*temp),
 Lines 656-678   IonBuilder::build() Link Here 
656
    } else {
657
    } else {
657
        IonSpew(IonSpew_Scripts, "Compiling script %s:%d (%p) (usecount=%d, level=%s)",
658
        IonSpew(IonSpew_Scripts, "Compiling script %s:%d (%p) (usecount=%d, level=%s)",
658
                script()->filename(), script()->lineno(), (void *)script(),
659
                script()->filename(), script()->lineno(), (void *)script(),
659
                (int)script()->getUseCount(), OptimizationLevelString(optimizationInfo().level()));
660
                (int)script()->getUseCount(), OptimizationLevelString(optimizationInfo().level()));
660
    }
661
    }
661
#endif
662
#endif
662
663
663
    initParameters();
664
    initParameters();
664
665
    initLocals();
665
    // Initialize local variables.
666
    for (uint32_t i = 0; i < info().nlocals(); i++) {
667
        MConstant *undef = MConstant::New(alloc(), UndefinedValue());
668
        current->add(undef);
669
        current->initSlot(info().localSlot(i), undef);
670
    }
671
666
672
    // Initialize something for the scope chain. We can bail out before the
667
    // Initialize something for the scope chain. We can bail out before the
673
    // start instruction, but the snapshot is encoded *at* the start
668
    // start instruction, but the snapshot is encoded *at* the start
674
    // instruction, which means generating any code that could load into
669
    // instruction, which means generating any code that could load into
675
    // registers is illegal.
670
    // registers is illegal.
676
    MInstruction *scope = MConstant::New(alloc(), UndefinedValue());
671
    MInstruction *scope = MConstant::New(alloc(), UndefinedValue());
677
    current->add(scope);
672
    current->add(scope);
678
    current->initSlot(info().scopeChainSlot(), scope);
673
    current->initSlot(info().scopeChainSlot(), scope);
 Lines 870-893   IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi Link Here 
870
        current->add(arg);
865
        current->add(arg);
871
        current->initSlot(info().argSlot(i), arg);
866
        current->initSlot(info().argSlot(i), arg);
872
    }
867
    }
873
868
874
    // Initialize the scope chain now that args are initialized.
869
    // Initialize the scope chain now that args are initialized.
875
    if (!initScopeChain(callInfo.fun()))
870
    if (!initScopeChain(callInfo.fun()))
876
        return false;
871
        return false;
877
872
878
    IonSpew(IonSpew_Inlining, "Initializing %u local slots", info().nlocals());
873
    IonSpew(IonSpew_Inlining, "Initializing %u local slots; fixed lets starting at %u",
874
            info().nlocals(), info().fixedLetBegin());
879
875
880
    // Initialize local variables.
876
    initLocals();
881
    for (uint32_t i = 0; i < info().nlocals(); i++) {
882
        MConstant *undef = MConstant::New(alloc(), UndefinedValue());
883
        current->add(undef);
884
        current->initSlot(info().localSlot(i), undef);
885
    }
886
877
887
    IonSpew(IonSpew_Inlining, "Inline entry block MResumePoint %p, %u operands",
878
    IonSpew(IonSpew_Inlining, "Inline entry block MResumePoint %p, %u operands",
888
            (void *) current->entryResumePoint(), current->entryResumePoint()->numOperands());
879
            (void *) current->entryResumePoint(), current->entryResumePoint()->numOperands());
889
880
890
    // +2 for the scope chain and |this|, maybe another +1 for arguments object slot.
881
    // +2 for the scope chain and |this|, maybe another +1 for arguments object slot.
891
    JS_ASSERT(current->entryResumePoint()->numOperands() == info().totalSlots());
882
    JS_ASSERT(current->entryResumePoint()->numOperands() == info().totalSlots());
892
883
893
    if (script_->argumentsHasVarBinding()) {
884
    if (script_->argumentsHasVarBinding()) {
 Lines 968-983   IonBuilder::initParameters() Link Here 
968
        }
959
        }
969
960
970
        param = MParameter::New(alloc(), i, types);
961
        param = MParameter::New(alloc(), i, types);
971
        current->add(param);
962
        current->add(param);
972
        current->initSlot(info().argSlotUnchecked(i), param);
963
        current->initSlot(info().argSlotUnchecked(i), param);
973
    }
964
    }
974
}
965
}
975
966
967
void
968
IonBuilder::initLocals()
969
{
970
    if (info().nlocals() == 0)
971
        return;
972
973
    MConstant *undef = nullptr;
974
    if (info().fixedLetBegin() > 0) {
975
        undef = MConstant::New(alloc(), UndefinedValue());
976
        current->add(undef);
977
    }
978
979
    MConstant *uninitLet = nullptr;
980
    if (info().fixedLetBegin() < info().nlocals()) {
981
        uninitLet = MConstant::New(alloc(), MagicValue(JS_UNINITIALIZED_LET));
982
        current->add(uninitLet);
983
    }
984
985
    for (uint32_t i = 0; i < info().nlocals(); i++)
986
        current->initSlot(info().localSlot(i), i < info().fixedLetBegin() ? undef : uninitLet);
987
}
988
976
bool
989
bool
977
IonBuilder::initScopeChain(MDefinition *callee)
990
IonBuilder::initScopeChain(MDefinition *callee)
978
{
991
{
979
    MInstruction *scope = nullptr;
992
    MInstruction *scope = nullptr;
980
993
981
    // If the script doesn't use the scopechain, then it's already initialized
994
    // If the script doesn't use the scopechain, then it's already initialized
982
    // from earlier.  However, always make a scope chain when |needsArgsObj| is true
995
    // from earlier.  However, always make a scope chain when |needsArgsObj| is true
983
    // for the script, since arguments object construction requires the scope chain
996
    // for the script, since arguments object construction requires the scope chain
 Lines 1289-1304   IonBuilder::traverseBytecode() Link Here 
1289
              case JSOP_POPN:
1302
              case JSOP_POPN:
1290
              case JSOP_DUPAT:
1303
              case JSOP_DUPAT:
1291
              case JSOP_DUP:
1304
              case JSOP_DUP:
1292
              case JSOP_DUP2:
1305
              case JSOP_DUP2:
1293
              case JSOP_PICK:
1306
              case JSOP_PICK:
1294
              case JSOP_SWAP:
1307
              case JSOP_SWAP:
1295
              case JSOP_SETARG:
1308
              case JSOP_SETARG:
1296
              case JSOP_SETLOCAL:
1309
              case JSOP_SETLOCAL:
1310
              case JSOP_INITLET:
1297
              case JSOP_SETRVAL:
1311
              case JSOP_SETRVAL:
1298
              case JSOP_VOID:
1312
              case JSOP_VOID:
1299
                // Don't require SSA uses for values popped by these ops.
1313
                // Don't require SSA uses for values popped by these ops.
1300
                break;
1314
                break;
1301
1315
1302
              case JSOP_POS:
1316
              case JSOP_POS:
1303
              case JSOP_TOID:
1317
              case JSOP_TOID:
1304
                // These ops may leave their input on the stack without setting
1318
                // These ops may leave their input on the stack without setting
 Lines 1514-1529   IonBuilder::inspectOpcode(JSOp op) Link Here 
1514
      case JSOP_GETLOCAL:
1528
      case JSOP_GETLOCAL:
1515
        current->pushLocal(GET_LOCALNO(pc));
1529
        current->pushLocal(GET_LOCALNO(pc));
1516
        return true;
1530
        return true;
1517
1531
1518
      case JSOP_SETLOCAL:
1532
      case JSOP_SETLOCAL:
1519
        current->setLocal(GET_LOCALNO(pc));
1533
        current->setLocal(GET_LOCALNO(pc));
1520
        return true;
1534
        return true;
1521
1535
1536
      case JSOP_CHECKLET:
1537
        return jsop_checklet();
1538
1539
      case JSOP_INITLET:
1540
        current->setLocal(GET_LOCALNO(pc));
1541
        return true;
1542
1543
      case JSOP_CHECKALIASEDLET:
1544
        return jsop_checkaliasedlet(ScopeCoordinate(pc));
1545
1546
      case JSOP_INITALIASEDLET:
1547
        return jsop_setaliasedvar(ScopeCoordinate(pc));
1548
1522
      case JSOP_POP:
1549
      case JSOP_POP:
1523
        current->pop();
1550
        current->pop();
1524
1551
1525
        // POP opcodes frequently appear where values are killed, e.g. after
1552
        // POP opcodes frequently appear where values are killed, e.g. after
1526
        // SET* opcodes. Place a resume point afterwards to avoid capturing
1553
        // SET* opcodes. Place a resume point afterwards to avoid capturing
1527
        // the dead value in later snapshots, except in places where that
1554
        // the dead value in later snapshots, except in places where that
1528
        // resume point is obviously unnecessary.
1555
        // resume point is obviously unnecessary.
1529
        if (pc[JSOP_POP_LENGTH] == JSOP_POP)
1556
        if (pc[JSOP_POP_LENGTH] == JSOP_POP)
 Lines 6436-6461   NumFixedSlots(JSObject *object) Link Here 
6436
    // shape and can race with the main thread if we are building off thread.
6463
    // shape and can race with the main thread if we are building off thread.
6437
    // The allocation kind and object class (which goes through the type) can
6464
    // The allocation kind and object class (which goes through the type) can
6438
    // be read freely, however.
6465
    // be read freely, however.
6439
    gc::AllocKind kind = object->tenuredGetAllocKind();
6466
    gc::AllocKind kind = object->tenuredGetAllocKind();
6440
    return gc::GetGCKindSlots(kind, object->getClass());
6467
    return gc::GetGCKindSlots(kind, object->getClass());
6441
}
6468
}
6442
6469
6443
bool
6470
bool
6444
IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded)
6471
IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, MDefinition *letCheck,
6472
                          bool *psucceeded)
6445
{
6473
{
6446
    jsid id = NameToId(name);
6474
    jsid id = NameToId(name);
6447
6475
6448
    JS_ASSERT(staticObject->is<GlobalObject>() || staticObject->is<CallObject>());
6476
    JS_ASSERT(staticObject->is<GlobalObject>() || staticObject->is<CallObject>());
6449
    JS_ASSERT(staticObject->hasSingletonType());
6477
    JS_ASSERT(staticObject->hasSingletonType());
6450
6478
6451
    *psucceeded = true;
6479
    *psucceeded = true;
6452
6480
6453
    if (staticObject->is<GlobalObject>()) {
6481
    if (staticObject->is<GlobalObject>()) {
6482
        // Known values on the global definitely don't need TDZ checks.
6483
        if (letCheck)
6484
            letCheck->setNotGuardUnchecked();
6485
6454
        // Optimize undefined, NaN, and Infinity.
6486
        // Optimize undefined, NaN, and Infinity.
6455
        if (name == names().undefined)
6487
        if (name == names().undefined)
6456
            return pushConstant(UndefinedValue());
6488
            return pushConstant(UndefinedValue());
6457
        if (name == names().NaN)
6489
        if (name == names().NaN)
6458
            return pushConstant(compartment->runtime()->NaNValue());
6490
            return pushConstant(compartment->runtime()->NaNValue());
6459
        if (name == names().Infinity)
6491
        if (name == names().Infinity)
6460
            return pushConstant(compartment->runtime()->positiveInfinityValue());
6492
            return pushConstant(compartment->runtime()->positiveInfinityValue());
6461
    }
6493
    }
 Lines 6598-6614   IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name) Link Here 
6598
                     value, needsBarrier, slotType);
6630
                     value, needsBarrier, slotType);
6599
}
6631
}
6600
6632
6601
bool
6633
bool
6602
IonBuilder::jsop_getgname(PropertyName *name)
6634
IonBuilder::jsop_getgname(PropertyName *name)
6603
{
6635
{
6604
    JSObject *obj = &script()->global();
6636
    JSObject *obj = &script()->global();
6605
    bool succeeded;
6637
    bool succeeded;
6606
    if (!getStaticName(obj, name, &succeeded))
6638
    if (!getStaticName(obj, name, /* letCheck = */ nullptr, &succeeded))
6607
        return false;
6639
        return false;
6608
    if (succeeded)
6640
    if (succeeded)
6609
        return true;
6641
        return true;
6610
6642
6611
    types::TemporaryTypeSet *types = bytecodeTypes(pc);
6643
    types::TemporaryTypeSet *types = bytecodeTypes(pc);
6612
    MDefinition *globalObj = constant(ObjectValue(*obj));
6644
    MDefinition *globalObj = constant(ObjectValue(*obj));
6613
    if (!getPropTryCommonGetter(&succeeded, globalObj, name, types))
6645
    if (!getPropTryCommonGetter(&succeeded, globalObj, name, types))
6614
        return false;
6646
        return false;
 Lines 9224-9240   IonBuilder::getPropTryInnerize(bool *emitted, MDefinition *obj, PropertyName *na Link Here 
9224
    // Also note that we don't call getPropTryCommonGetter below, because
9256
    // Also note that we don't call getPropTryCommonGetter below, because
9225
    // (a) it requires a Baseline getter stub, which we don't have for outer
9257
    // (a) it requires a Baseline getter stub, which we don't have for outer
9226
    // window proxies and (b) we have to be careful not to pass the inner
9258
    // window proxies and (b) we have to be careful not to pass the inner
9227
    // object to scripted getters etc. See bug 1007631.
9259
    // object to scripted getters etc. See bug 1007631.
9228
9260
9229
    if (!getPropTryConstant(emitted, inner, name, types) || *emitted)
9261
    if (!getPropTryConstant(emitted, inner, name, types) || *emitted)
9230
        return *emitted;
9262
        return *emitted;
9231
9263
9232
    if (!getStaticName(&script()->global(), name, emitted) || *emitted)
9264
    if (!getStaticName(&script()->global(), name, /* letCheck = */ nullptr, emitted) || *emitted)
9233
        return *emitted;
9265
        return *emitted;
9234
9266
9235
    // Passing the inner object to GetProperty IC is safe, see the
9267
    // Passing the inner object to GetProperty IC is safe, see the
9236
    // needsOuterizedThisObject check in IsCacheableGetPropCallNative.
9268
    // needsOuterizedThisObject check in IsCacheableGetPropCallNative.
9237
    BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
9269
    BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
9238
                                                       inner, name, types);
9270
                                                       inner, name, types);
9239
    if (!getPropTryCache(emitted, inner, name, barrier, types) || *emitted)
9271
    if (!getPropTryCache(emitted, inner, name, barrier, types) || *emitted)
9240
        return *emitted;
9272
        return *emitted;
 Lines 9842-9857   IonBuilder::jsop_deffun(uint32_t index) Link Here 
9842
9874
9843
    MDefFun *deffun = MDefFun::New(alloc(), fun, current->scopeChain());
9875
    MDefFun *deffun = MDefFun::New(alloc(), fun, current->scopeChain());
9844
    current->add(deffun);
9876
    current->add(deffun);
9845
9877
9846
    return resumeAfter(deffun);
9878
    return resumeAfter(deffun);
9847
}
9879
}
9848
9880
9849
bool
9881
bool
9882
IonBuilder::jsop_checklet()
9883
{
9884
    uint32_t slot = info().localSlot(GET_LOCALNO(pc));
9885
    MDefinition *let = addLetCheck(current->getSlot(slot));
9886
    if (!let)
9887
        return false;
9888
    current->setSlot(slot, let);
9889
    return true;
9890
}
9891
9892
bool
9893
IonBuilder::jsop_checkaliasedlet(ScopeCoordinate sc)
9894
{
9895
    MDefinition *let = addLetCheck(getAliasedVar(sc));
9896
    if (!let)
9897
        return false;
9898
9899
    jsbytecode *nextPc = pc + JSOP_CHECKALIASEDLET_LENGTH;
9900
    MOZ_ASSERT(JSOp(*nextPc) == JSOP_GETALIASEDVAR || JSOp(*nextPc) == JSOP_SETALIASEDVAR);
9901
    MOZ_ASSERT(sc == ScopeCoordinate(nextPc));
9902
9903
    // If we are checking for a load, push the checked let so that the load
9904
    // can use it.
9905
    if (JSOp(*nextPc) == JSOP_GETALIASEDVAR)
9906
        setLetCheck(let);
9907
9908
    return true;
9909
}
9910
9911
bool
9850
IonBuilder::jsop_this()
9912
IonBuilder::jsop_this()
9851
{
9913
{
9852
    if (!info().funMaybeLazy())
9914
    if (!info().funMaybeLazy())
9853
        return abort("JSOP_THIS outside of a JSFunction.");
9915
        return abort("JSOP_THIS outside of a JSFunction.");
9854
9916
9855
    if (info().funMaybeLazy()->isArrow()) {
9917
    if (info().funMaybeLazy()->isArrow()) {
9856
        // Arrow functions store their lexical |this| in an extended slot.
9918
        // Arrow functions store their lexical |this| in an extended slot.
9857
        MLoadArrowThis *thisObj = MLoadArrowThis::New(alloc(), getCallee());
9919
        MLoadArrowThis *thisObj = MLoadArrowThis::New(alloc(), getCallee());
 Lines 10061-10104   IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) Link Here 
10061
            *pcall = singletonScope;
10123
            *pcall = singletonScope;
10062
            return true;
10124
            return true;
10063
        }
10125
        }
10064
    }
10126
    }
10065
10127
10066
    return true;
10128
    return true;
10067
}
10129
}
10068
10130
10131
MDefinition *
10132
IonBuilder::getAliasedVar(ScopeCoordinate sc)
10133
{
10134
    MDefinition *obj = walkScopeChain(sc.hops());
10135
10136
    Shape *shape = ScopeCoordinateToStaticScopeShape(script(), pc);
10137
10138
    MInstruction *load;
10139
    if (shape->numFixedSlots() <= sc.slot()) {
10140
        MInstruction *slots = MSlots::New(alloc(), obj);
10141
        current->add(slots);
10142
10143
        load = MLoadSlot::New(alloc(), slots, sc.slot() - shape->numFixedSlots());
10144
    } else {
10145
        load = MLoadFixedSlot::New(alloc(), obj, sc.slot());
10146
    }
10147
10148
    current->add(load);
10149
    return load;
10150
}
10151
10069
bool
10152
bool
10070
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
10153
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
10071
{
10154
{
10072
    JSObject *call = nullptr;
10155
    JSObject *call = nullptr;
10073
    if (hasStaticScopeObject(sc, &call) && call) {
10156
    if (hasStaticScopeObject(sc, &call) && call) {
10074
        PropertyName *name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc);
10157
        PropertyName *name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc);
10075
        bool succeeded;
10158
        bool succeeded;
10076
        if (!getStaticName(call, name, &succeeded))
10159
        if (!getStaticName(call, name, takeLetCheck(), &succeeded))
10077
            return false;
10160
            return false;
10078
        if (succeeded)
10161
        if (succeeded)
10079
            return true;
10162
            return true;
10080
    }
10163
    }
10081
10164
10082
    MDefinition *obj = walkScopeChain(sc.hops());
10165
    // See jsop_checkaliasedlet.
10083
10166
    MDefinition *load = takeLetCheck();
10084
    Shape *shape = ScopeCoordinateToStaticScopeShape(script(), pc);
10167
    if (!load)
10085
10168
        load = getAliasedVar(sc);
10086
    MInstruction *load;
10087
    if (shape->numFixedSlots() <= sc.slot()) {
10088
        MInstruction *slots = MSlots::New(alloc(), obj);
10089
        current->add(slots);
10090
10091
        load = MLoadSlot::New(alloc(), slots, sc.slot() - shape->numFixedSlots());
10092
    } else {
10093
        load = MLoadFixedSlot::New(alloc(), obj, sc.slot());
10094
    }
10095
10096
    current->add(load);
10097
    current->push(load);
10169
    current->push(load);
10098
10170
10099
    types::TemporaryTypeSet *types = bytecodeTypes(pc);
10171
    types::TemporaryTypeSet *types = bytecodeTypes(pc);
10100
    return pushTypeBarrier(load, types, BarrierKind::TypeSet);
10172
    return pushTypeBarrier(load, types, BarrierKind::TypeSet);
10101
}
10173
}
10102
10174
10103
bool
10175
bool
10104
IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
10176
IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
 Lines 10552-10559   IonBuilder::getCallee() Link Here 
10552
    if (inliningDepth_ == 0) {
10624
    if (inliningDepth_ == 0) {
10553
        MInstruction *callee = MCallee::New(alloc());
10625
        MInstruction *callee = MCallee::New(alloc());
10554
        current->add(callee);
10626
        current->add(callee);
10555
        return callee;
10627
        return callee;
10556
    }
10628
    }
10557
10629
10558
    return inlineCallInfo_->fun();
10630
    return inlineCallInfo_->fun();
10559
}
10631
}
10632
10633
MDefinition *
10634
IonBuilder::addLetCheck(MDefinition *input)
10635
{
10636
    MOZ_ASSERT(JSOp(*pc) == JSOP_CHECKLET || JSOp(*pc) == JSOP_CHECKALIASEDLET);
10637
10638
    // If we're guaranteed to not be JS_UNINITIALIZED_MAGIC, no need to check.
10639
    MInstruction *letCheck;
10640
    if (input->type() == MIRType_MagicUninitializedLet)
10641
        letCheck = MThrowUninitializedLet::New(alloc());
10642
    else if (input->type() == MIRType_Value)
10643
        letCheck = MLetCheck::New(alloc(), input);
10644
    else
10645
        return input;
10646
10647
    current->add(letCheck);
10648
    if (!resumeAfter(letCheck))
10649
        return nullptr;
10650
    return letCheck->isLetCheck() ? letCheck : constant(UndefinedValue());
10651
}
(-)a/js/src/jit/IonBuilder.h (-1 / +19 lines)
Line     Link Here 
 Lines 329-344   class IonBuilder : public MIRGenerator Link Here 
329
    bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode);
329
    bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode);
330
    bool resumeAt(MInstruction *ins, jsbytecode *pc);
330
    bool resumeAt(MInstruction *ins, jsbytecode *pc);
331
    bool resumeAfter(MInstruction *ins);
331
    bool resumeAfter(MInstruction *ins);
332
    bool maybeInsertResume();
332
    bool maybeInsertResume();
333
333
334
    void insertRecompileCheck();
334
    void insertRecompileCheck();
335
335
336
    void initParameters();
336
    void initParameters();
337
    void initLocals();
337
    void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
338
    void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
338
    void rewriteParameters();
339
    void rewriteParameters();
339
    bool initScopeChain(MDefinition *callee = nullptr);
340
    bool initScopeChain(MDefinition *callee = nullptr);
340
    bool initArgumentsObject();
341
    bool initArgumentsObject();
341
    bool pushConstant(const Value &v);
342
    bool pushConstant(const Value &v);
342
343
343
    MConstant *constant(const Value &v);
344
    MConstant *constant(const Value &v);
344
    MConstant *constantInt(int32_t i);
345
    MConstant *constantInt(int32_t i);
 Lines 557-598   class IonBuilder : public MIRGenerator Link Here 
557
    MInstruction *addTypedArrayLength(MDefinition *obj) {
558
    MInstruction *addTypedArrayLength(MDefinition *obj) {
558
        MInstruction *length;
559
        MInstruction *length;
559
        addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
560
        addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
560
        return length;
561
        return length;
561
    }
562
    }
562
563
563
564
564
    MDefinition *getCallee();
565
    MDefinition *getCallee();
566
    MDefinition *getAliasedVar(ScopeCoordinate sc);
567
    MDefinition *addLetCheck(MDefinition *input);
565
568
566
    bool jsop_add(MDefinition *left, MDefinition *right);
569
    bool jsop_add(MDefinition *left, MDefinition *right);
567
    bool jsop_bitnot();
570
    bool jsop_bitnot();
568
    bool jsop_bitop(JSOp op);
571
    bool jsop_bitop(JSOp op);
569
    bool jsop_binary(JSOp op);
572
    bool jsop_binary(JSOp op);
570
    bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
573
    bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
571
    bool jsop_pos();
574
    bool jsop_pos();
572
    bool jsop_neg();
575
    bool jsop_neg();
573
    bool jsop_setarg(uint32_t arg);
576
    bool jsop_setarg(uint32_t arg);
574
    bool jsop_defvar(uint32_t index);
577
    bool jsop_defvar(uint32_t index);
575
    bool jsop_deffun(uint32_t index);
578
    bool jsop_deffun(uint32_t index);
576
    bool jsop_notearg();
579
    bool jsop_notearg();
580
    bool jsop_checklet();
581
    bool jsop_checkaliasedlet(ScopeCoordinate sc);
577
    bool jsop_funcall(uint32_t argc);
582
    bool jsop_funcall(uint32_t argc);
578
    bool jsop_funapply(uint32_t argc);
583
    bool jsop_funapply(uint32_t argc);
579
    bool jsop_funapplyarguments(uint32_t argc);
584
    bool jsop_funapplyarguments(uint32_t argc);
580
    bool jsop_call(uint32_t argc, bool constructing);
585
    bool jsop_call(uint32_t argc, bool constructing);
581
    bool jsop_eval(uint32_t argc);
586
    bool jsop_eval(uint32_t argc);
582
    bool jsop_ifeq(JSOp op);
587
    bool jsop_ifeq(JSOp op);
583
    bool jsop_try();
588
    bool jsop_try();
584
    bool jsop_label();
589
    bool jsop_label();
585
    bool jsop_condswitch();
590
    bool jsop_condswitch();
586
    bool jsop_andor(JSOp op);
591
    bool jsop_andor(JSOp op);
587
    bool jsop_dup2();
592
    bool jsop_dup2();
588
    bool jsop_loophead(jsbytecode *pc);
593
    bool jsop_loophead(jsbytecode *pc);
589
    bool jsop_compare(JSOp op);
594
    bool jsop_compare(JSOp op);
590
    bool getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded);
595
    bool getStaticName(JSObject *staticObject, PropertyName *name, MDefinition *letCheck,
596
                       bool *psucceeded);
591
    bool setStaticName(JSObject *staticObject, PropertyName *name);
597
    bool setStaticName(JSObject *staticObject, PropertyName *name);
592
    bool jsop_getgname(PropertyName *name);
598
    bool jsop_getgname(PropertyName *name);
593
    bool jsop_getname(PropertyName *name);
599
    bool jsop_getname(PropertyName *name);
594
    bool jsop_intrinsic(PropertyName *name);
600
    bool jsop_intrinsic(PropertyName *name);
595
    bool jsop_bindname(PropertyName *name);
601
    bool jsop_bindname(PropertyName *name);
596
    bool jsop_getelem();
602
    bool jsop_getelem();
597
    bool jsop_getelem_dense(MDefinition *obj, MDefinition *index);
603
    bool jsop_getelem_dense(MDefinition *obj, MDefinition *index);
598
    bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeDescr::Type arrayType);
604
    bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeDescr::Type arrayType);
 Lines 875-890   class IonBuilder : public MIRGenerator Link Here 
875
    MBasicBlock *current;
881
    MBasicBlock *current;
876
    uint32_t loopDepth_;
882
    uint32_t loopDepth_;
877
883
878
    BytecodeSite bytecodeSite(jsbytecode *pc) {
884
    BytecodeSite bytecodeSite(jsbytecode *pc) {
879
        JS_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
885
        JS_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
880
        return BytecodeSite(info().inlineScriptTree(), pc);
886
        return BytecodeSite(info().inlineScriptTree(), pc);
881
    }
887
    }
882
888
889
    MDefinition *letCheck_;
890
891
    void setLetCheck(MDefinition *let) {
892
        MOZ_ASSERT(!letCheck_);
893
        letCheck_ = let;
894
    }
895
    MDefinition *takeLetCheck() {
896
        MDefinition *let = letCheck_;
897
        letCheck_ = nullptr;
898
        return let;
899
    }
900
883
    /* Information used for inline-call builders. */
901
    /* Information used for inline-call builders. */
884
    MResumePoint *callerResumePoint_;
902
    MResumePoint *callerResumePoint_;
885
    jsbytecode *callerPC() {
903
    jsbytecode *callerPC() {
886
        return callerResumePoint_ ? callerResumePoint_->pc() : nullptr;
904
        return callerResumePoint_ ? callerResumePoint_->pc() : nullptr;
887
    }
905
    }
888
    IonBuilder *callerBuilder_;
906
    IonBuilder *callerBuilder_;
889
907
890
    bool oom() {
908
    bool oom() {
(-)a/js/src/jit/IonCaches.cpp (-1 / +2 lines)
Line     Link Here 
 Lines 4195-4211   BindNameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain) Link Here 
4195
    IonScript *ion = outerScript->ionScript();
4195
    IonScript *ion = outerScript->ionScript();
4196
    BindNameIC &cache = ion->getCache(cacheIndex).toBindName();
4196
    BindNameIC &cache = ion->getCache(cacheIndex).toBindName();
4197
    HandlePropertyName name = cache.name();
4197
    HandlePropertyName name = cache.name();
4198
4198
4199
    RootedObject holder(cx);
4199
    RootedObject holder(cx);
4200
    if (scopeChain->is<GlobalObject>()) {
4200
    if (scopeChain->is<GlobalObject>()) {
4201
        holder = scopeChain;
4201
        holder = scopeChain;
4202
    } else {
4202
    } else {
4203
        if (!LookupNameUnqualified(cx, name, scopeChain, &holder))
4203
        RootedShape shape(cx);
4204
        if (!LookupNameUnqualified(cx, name, scopeChain, &holder, &shape))
4204
            return nullptr;
4205
            return nullptr;
4205
    }
4206
    }
4206
4207
4207
    // Stop generating new stubs once we hit the stub count limit, see
4208
    // Stop generating new stubs once we hit the stub count limit, see
4208
    // GetPropertyCache.
4209
    // GetPropertyCache.
4209
    if (cache.canAttachStub()) {
4210
    if (cache.canAttachStub()) {
4210
        if (scopeChain->is<GlobalObject>()) {
4211
        if (scopeChain->is<GlobalObject>()) {
4211
            if (!cache.attachGlobal(cx, outerScript, ion, scopeChain))
4212
            if (!cache.attachGlobal(cx, outerScript, ion, scopeChain))
(-)a/js/src/jit/IonFrames.cpp (-1 / +1 lines)
Line     Link Here 
 Lines 552-568   HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFrom Link Here 
552
        // See the big comment in TryNoteIter::settle for more info.
552
        // See the big comment in TryNoteIter::settle for more info.
553
        JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
553
        JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
554
        size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
554
        size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
555
        if (tn->stackDepth > stackDepth)
555
        if (tn->stackDepth > stackDepth)
556
            continue;
556
            continue;
557
557
558
        // Unwind scope chain (pop block objects).
558
        // Unwind scope chain (pop block objects).
559
        if (cx->isExceptionPending()) {
559
        if (cx->isExceptionPending()) {
560
            *unwoundScopeToPc = script->main() + tn->start;
560
            *unwoundScopeToPc = UnwindScopeToTryPc(script, tn);
561
            UnwindScope(cx, si, *unwoundScopeToPc);
561
            UnwindScope(cx, si, *unwoundScopeToPc);
562
        }
562
        }
563
563
564
        // Compute base pointer and stack pointer.
564
        // Compute base pointer and stack pointer.
565
        rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
565
        rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
566
        rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
566
        rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
567
            (script->nfixed() + tn->stackDepth) * sizeof(Value);
567
            (script->nfixed() + tn->stackDepth) * sizeof(Value);
568
568
(-)a/js/src/jit/IonTypes.h (+4 lines)
Line     Link Here 
 Lines 351-366   enum MIRType Link Here 
351
    MIRType_Float32,
351
    MIRType_Float32,
352
    MIRType_String,
352
    MIRType_String,
353
    MIRType_Symbol,
353
    MIRType_Symbol,
354
    MIRType_Object,
354
    MIRType_Object,
355
    MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
355
    MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
356
    MIRType_MagicOptimizedOut,       // JS_OPTIMIZED_OUT magic value.
356
    MIRType_MagicOptimizedOut,       // JS_OPTIMIZED_OUT magic value.
357
    MIRType_MagicHole,               // JS_ELEMENTS_HOLE magic value.
357
    MIRType_MagicHole,               // JS_ELEMENTS_HOLE magic value.
358
    MIRType_MagicIsConstructing,     // JS_IS_CONSTRUCTING magic value.
358
    MIRType_MagicIsConstructing,     // JS_IS_CONSTRUCTING magic value.
359
    MIRType_MagicUninitializedLet,   // JS_UNINITIALIZED_LET magic value.
359
    MIRType_Value,
360
    MIRType_Value,
360
    MIRType_None,                    // Invalid, used as a placeholder.
361
    MIRType_None,                    // Invalid, used as a placeholder.
361
    MIRType_Slots,                   // A slots vector
362
    MIRType_Slots,                   // A slots vector
362
    MIRType_Elements,                // An elements vector
363
    MIRType_Elements,                // An elements vector
363
    MIRType_Pointer,                 // An opaque pointer that receives no special treatment
364
    MIRType_Pointer,                 // An opaque pointer that receives no special treatment
364
    MIRType_Shape,                   // A Shape pointer.
365
    MIRType_Shape,                   // A Shape pointer.
365
    MIRType_ForkJoinContext,         // js::ForkJoinContext*
366
    MIRType_ForkJoinContext,         // js::ForkJoinContext*
366
    MIRType_Last = MIRType_ForkJoinContext,
367
    MIRType_Last = MIRType_ForkJoinContext,
 Lines 429-444   ValueTypeFromMIRType(MIRType type) Link Here 
429
    case MIRType_String:
430
    case MIRType_String:
430
      return JSVAL_TYPE_STRING;
431
      return JSVAL_TYPE_STRING;
431
    case MIRType_Symbol:
432
    case MIRType_Symbol:
432
      return JSVAL_TYPE_SYMBOL;
433
      return JSVAL_TYPE_SYMBOL;
433
    case MIRType_MagicOptimizedArguments:
434
    case MIRType_MagicOptimizedArguments:
434
    case MIRType_MagicOptimizedOut:
435
    case MIRType_MagicOptimizedOut:
435
    case MIRType_MagicHole:
436
    case MIRType_MagicHole:
436
    case MIRType_MagicIsConstructing:
437
    case MIRType_MagicIsConstructing:
438
    case MIRType_MagicUninitializedLet:
437
      return JSVAL_TYPE_MAGIC;
439
      return JSVAL_TYPE_MAGIC;
438
    default:
440
    default:
439
      JS_ASSERT(type == MIRType_Object);
441
      JS_ASSERT(type == MIRType_Object);
440
      return JSVAL_TYPE_OBJECT;
442
      return JSVAL_TYPE_OBJECT;
441
  }
443
  }
442
}
444
}
443
445
444
static inline JSValueTag
446
static inline JSValueTag
 Lines 472-487   StringFromMIRType(MIRType type) Link Here 
472
    case MIRType_MagicOptimizedArguments:
474
    case MIRType_MagicOptimizedArguments:
473
      return "MagicOptimizedArguments";
475
      return "MagicOptimizedArguments";
474
    case MIRType_MagicOptimizedOut:
476
    case MIRType_MagicOptimizedOut:
475
      return "MagicOptimizedOut";
477
      return "MagicOptimizedOut";
476
    case MIRType_MagicHole:
478
    case MIRType_MagicHole:
477
      return "MagicHole";
479
      return "MagicHole";
478
    case MIRType_MagicIsConstructing:
480
    case MIRType_MagicIsConstructing:
479
      return "MagicIsConstructing";
481
      return "MagicIsConstructing";
482
    case MIRType_MagicUninitializedLet:
483
      return "MagicUninitializedLet";
480
    case MIRType_Value:
484
    case MIRType_Value:
481
      return "Value";
485
      return "Value";
482
    case MIRType_None:
486
    case MIRType_None:
483
      return "None";
487
      return "None";
484
    case MIRType_Slots:
488
    case MIRType_Slots:
485
      return "Slots";
489
      return "Slots";
486
    case MIRType_Elements:
490
    case MIRType_Elements:
487
      return "Elements";
491
      return "Elements";
(-)a/js/src/jit/LIR-Common.h (+22 lines)
Line     Link Here 
 Lines 6328-6339   class LRecompileCheck : public LInstructionHelper<0, 0, 1> Link Here 
6328
    const LDefinition *scratch() {
6328
    const LDefinition *scratch() {
6329
        return getTemp(0);
6329
        return getTemp(0);
6330
    }
6330
    }
6331
    MRecompileCheck *mir() {
6331
    MRecompileCheck *mir() {
6332
        return mir_->toRecompileCheck();
6332
        return mir_->toRecompileCheck();
6333
    }
6333
    }
6334
};
6334
};
6335
6335
6336
class LLetCheck : public LInstructionHelper<0, BOX_PIECES, 0>
6337
{
6338
  public:
6339
    LIR_HEADER(LetCheck)
6340
6341
    MLetCheck *mir() {
6342
        return mir_->toLetCheck();
6343
    }
6344
6345
    static const size_t Input = 0;
6346
};
6347
6348
class LThrowUninitializedLet : public LCallInstructionHelper<0, 0, 0>
6349
{
6350
  public:
6351
    LIR_HEADER(ThrowUninitializedLet)
6352
6353
    MLetCheck *mir() {
6354
        return mir_->toLetCheck();
6355
    }
6356
};
6357
6336
} // namespace jit
6358
} // namespace jit
6337
} // namespace js
6359
} // namespace js
6338
6360
6339
#endif /* jit_LIR_Common_h */
6361
#endif /* jit_LIR_Common_h */
(-)a/js/src/jit/LOpcodes.h (-1 / +3 lines)
Line     Link Here 
 Lines 304-320    Link Here 
304
    _(AsmJSVoidReturn)              \
304
    _(AsmJSVoidReturn)              \
305
    _(AsmJSPassStackArg)            \
305
    _(AsmJSPassStackArg)            \
306
    _(AsmJSCall)                    \
306
    _(AsmJSCall)                    \
307
    _(InterruptCheckPar)            \
307
    _(InterruptCheckPar)            \
308
    _(RecompileCheck)               \
308
    _(RecompileCheck)               \
309
    _(AssertRangeI)                 \
309
    _(AssertRangeI)                 \
310
    _(AssertRangeD)                 \
310
    _(AssertRangeD)                 \
311
    _(AssertRangeF)                 \
311
    _(AssertRangeF)                 \
312
    _(AssertRangeV)
312
    _(AssertRangeV)                 \
313
    _(LetCheck)                     \
314
    _(ThrowUninitializedLet)
313
315
314
#if defined(JS_CODEGEN_X86)
316
#if defined(JS_CODEGEN_X86)
315
# include "jit/x86/LOpcodes-x86.h"
317
# include "jit/x86/LOpcodes-x86.h"
316
#elif defined(JS_CODEGEN_X64)
318
#elif defined(JS_CODEGEN_X64)
317
# include "jit/x64/LOpcodes-x64.h"
319
# include "jit/x64/LOpcodes-x64.h"
318
#elif defined(JS_CODEGEN_ARM)
320
#elif defined(JS_CODEGEN_ARM)
319
# include "jit/arm/LOpcodes-arm.h"
321
# include "jit/arm/LOpcodes-arm.h"
320
#elif defined(JS_CODEGEN_MIPS)
322
#elif defined(JS_CODEGEN_MIPS)
(-)a/js/src/jit/Lowering.cpp (+17 lines)
Line     Link Here 
 Lines 3709-3724   LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith *ins) Link Here 
3709
        LSimdBinaryArithFx4 *add = new(alloc()) LSimdBinaryArithFx4();
3709
        LSimdBinaryArithFx4 *add = new(alloc()) LSimdBinaryArithFx4();
3710
        return lowerForFPU(add, ins, ins->lhs(), ins->rhs());
3710
        return lowerForFPU(add, ins, ins->lhs(), ins->rhs());
3711
    }
3711
    }
3712
3712
3713
    MOZ_ASSUME_UNREACHABLE("Unknown SIMD kind when adding values");
3713
    MOZ_ASSUME_UNREACHABLE("Unknown SIMD kind when adding values");
3714
    return false;
3714
    return false;
3715
}
3715
}
3716
3716
3717
bool
3718
LIRGenerator::visitLetCheck(MLetCheck *ins)
3719
{
3720
    MDefinition *input = ins->input();
3721
    MOZ_ASSERT(input->type() == MIRType_Value);
3722
    LLetCheck *lir = new(alloc()) LLetCheck();
3723
    return redefine(ins, input) && useBox(lir, LLetCheck::Input, input) &&
3724
           add(lir, ins) && assignSafepoint(lir, ins);
3725
}
3726
3727
bool
3728
LIRGenerator::visitThrowUninitializedLet(MThrowUninitializedLet *ins)
3729
{
3730
    LThrowUninitializedLet *lir = new(alloc()) LThrowUninitializedLet();
3731
    return add(lir, ins) && assignSafepoint(lir, ins);
3732
}
3733
3717
static void
3734
static void
3718
SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
3735
SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
3719
{
3736
{
3720
    fprintf(IonSpewFile, "Current resume point %p details:\n", (void *)resumePoint);
3737
    fprintf(IonSpewFile, "Current resume point %p details:\n", (void *)resumePoint);
3721
    fprintf(IonSpewFile, "    frame count: %u\n", resumePoint->frameCount());
3738
    fprintf(IonSpewFile, "    frame count: %u\n", resumePoint->frameCount());
3722
3739
3723
    if (ins) {
3740
    if (ins) {
3724
        fprintf(IonSpewFile, "    taken after: ");
3741
        fprintf(IonSpewFile, "    taken after: ");
(-)a/js/src/jit/Lowering.h (+2 lines)
Line     Link Here 
 Lines 267-280   class LIRGenerator : public LIRGeneratorSpecific Link Here 
267
    bool visitSimdExtractElement(MSimdExtractElement *ins);
267
    bool visitSimdExtractElement(MSimdExtractElement *ins);
268
    bool visitSimdBinaryArith(MSimdBinaryArith *ins);
268
    bool visitSimdBinaryArith(MSimdBinaryArith *ins);
269
    bool visitSimdValueX4(MSimdValueX4 *ins);
269
    bool visitSimdValueX4(MSimdValueX4 *ins);
270
    bool visitSimdConstant(MSimdConstant *ins);
270
    bool visitSimdConstant(MSimdConstant *ins);
271
    bool visitPhi(MPhi *ins);
271
    bool visitPhi(MPhi *ins);
272
    bool visitBeta(MBeta *ins);
272
    bool visitBeta(MBeta *ins);
273
    bool visitObjectState(MObjectState *ins);
273
    bool visitObjectState(MObjectState *ins);
274
    bool visitArrayState(MArrayState *ins);
274
    bool visitArrayState(MArrayState *ins);
275
    bool visitLetCheck(MLetCheck *ins);
276
    bool visitThrowUninitializedLet(MThrowUninitializedLet *ins);
275
};
277
};
276
278
277
} // namespace jit
279
} // namespace jit
278
} // namespace js
280
} // namespace js
279
281
280
#endif /* jit_Lowering_h */
282
#endif /* jit_Lowering_h */
(-)a/js/src/jit/MIR.cpp (+3 lines)
Line     Link Here 
 Lines 566-581   MConstant::printOpcode(FILE *fp) const Link Here 
566
        fprintf(fp, "magic hole");
566
        fprintf(fp, "magic hole");
567
        break;
567
        break;
568
      case MIRType_MagicIsConstructing:
568
      case MIRType_MagicIsConstructing:
569
        fprintf(fp, "magic is-constructing");
569
        fprintf(fp, "magic is-constructing");
570
        break;
570
        break;
571
      case MIRType_MagicOptimizedOut:
571
      case MIRType_MagicOptimizedOut:
572
        fprintf(fp, "magic optimized-out");
572
        fprintf(fp, "magic optimized-out");
573
        break;
573
        break;
574
      case MIRType_MagicUninitializedLet:
575
        fprintf(fp, "magic uninitialized-let");
576
        break;
574
      default:
577
      default:
575
        MOZ_ASSUME_UNREACHABLE("unexpected type");
578
        MOZ_ASSUME_UNREACHABLE("unexpected type");
576
    }
579
    }
577
}
580
}
578
581
579
bool
582
bool
580
MConstant::canProduceFloat32() const
583
MConstant::canProduceFloat32() const
581
{
584
{
(-)a/js/src/jit/MIR.h (+51 lines)
Line     Link Here 
 Lines 45-60   MIRType MIRTypeFromValue(const js::Value &vp) Link Here 
45
          case JS_OPTIMIZED_ARGUMENTS:
45
          case JS_OPTIMIZED_ARGUMENTS:
46
            return MIRType_MagicOptimizedArguments;
46
            return MIRType_MagicOptimizedArguments;
47
          case JS_OPTIMIZED_OUT:
47
          case JS_OPTIMIZED_OUT:
48
            return MIRType_MagicOptimizedOut;
48
            return MIRType_MagicOptimizedOut;
49
          case JS_ELEMENTS_HOLE:
49
          case JS_ELEMENTS_HOLE:
50
            return MIRType_MagicHole;
50
            return MIRType_MagicHole;
51
          case JS_IS_CONSTRUCTING:
51
          case JS_IS_CONSTRUCTING:
52
            return MIRType_MagicIsConstructing;
52
            return MIRType_MagicIsConstructing;
53
          case JS_UNINITIALIZED_LET:
54
            return MIRType_MagicUninitializedLet;
53
          default:
55
          default:
54
            MOZ_ASSERT(!"Unexpected magic constant");
56
            MOZ_ASSERT(!"Unexpected magic constant");
55
        }
57
        }
56
    }
58
    }
57
    return MIRTypeFromValueType(vp.extractNonDoubleType());
59
    return MIRTypeFromValueType(vp.extractNonDoubleType());
58
}
60
}
59
61
60
#define MIR_FLAG_LIST(_)                                                        \
62
#define MIR_FLAG_LIST(_)                                                        \
 Lines 5848-5863   class MAsmJSInterruptCheck : public MNullaryInstruction Link Here 
5848
    Label *interruptExit() const {
5850
    Label *interruptExit() const {
5849
        return interruptExit_;
5851
        return interruptExit_;
5850
    }
5852
    }
5851
    const CallSiteDesc &funcDesc() const {
5853
    const CallSiteDesc &funcDesc() const {
5852
        return funcDesc_;
5854
        return funcDesc_;
5853
    }
5855
    }
5854
};
5856
};
5855
5857
5858
// Checks if a value is an uninitialized let, throwing if so.
5859
class MLetCheck
5860
  : public MUnaryInstruction,
5861
    public BoxPolicy<0>
5862
{
5863
    explicit MLetCheck(MDefinition *input)
5864
      : MUnaryInstruction(input)
5865
    {
5866
        setGuard();
5867
        setResultType(MIRType_Value);
5868
        setResultTypeSet(input->resultTypeSet());
5869
    }
5870
5871
  public:
5872
    INSTRUCTION_HEADER(LetCheck)
5873
5874
    static MLetCheck *New(TempAllocator &alloc, MDefinition *input) {
5875
        return new(alloc) MLetCheck(input);
5876
    }
5877
5878
    AliasSet getAliasSet() const {
5879
        return AliasSet::None();
5880
    }
5881
5882
    MDefinition *input() const {
5883
        return getOperand(0);
5884
    }
5885
};
5886
5887
// Unconditionally throw an uninitialized let error.
5888
class MThrowUninitializedLet : public MNullaryInstruction
5889
{
5890
    MThrowUninitializedLet() {
5891
        setGuard();
5892
        setResultType(MIRType_None);
5893
    }
5894
5895
  public:
5896
    INSTRUCTION_HEADER(ThrowUninitializedLet)
5897
5898
    static MThrowUninitializedLet *New(TempAllocator &alloc) {
5899
        return new(alloc) MThrowUninitializedLet();
5900
    }
5901
5902
    AliasSet getAliasSet() const {
5903
        return AliasSet::None();
5904
    }
5905
};
5906
5856
// If not defined, set a global variable to |undefined|.
5907
// If not defined, set a global variable to |undefined|.
5857
class MDefVar : public MUnaryInstruction
5908
class MDefVar : public MUnaryInstruction
5858
{
5909
{
5859
    CompilerRootPropertyName name_; // Target name to be defined.
5910
    CompilerRootPropertyName name_; // Target name to be defined.
5860
    unsigned attrs_; // Attributes to be set.
5911
    unsigned attrs_; // Attributes to be set.
5861
5912
5862
  private:
5913
  private:
5863
    MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
5914
    MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
(-)a/js/src/jit/MOpcodes.h (-1 / +3 lines)
Line     Link Here 
 Lines 228-244   namespace jit { Link Here 
228
    _(NewDenseArrayPar)                                                     \
228
    _(NewDenseArrayPar)                                                     \
229
    _(NewDerivedTypedObject)                                                \
229
    _(NewDerivedTypedObject)                                                \
230
    _(LambdaPar)                                                            \
230
    _(LambdaPar)                                                            \
231
    _(RestPar)                                                              \
231
    _(RestPar)                                                              \
232
    _(ForkJoinContext)                                                      \
232
    _(ForkJoinContext)                                                      \
233
    _(ForkJoinGetSlice)                                                     \
233
    _(ForkJoinGetSlice)                                                     \
234
    _(GuardThreadExclusive)                                                 \
234
    _(GuardThreadExclusive)                                                 \
235
    _(InterruptCheckPar)                                                    \
235
    _(InterruptCheckPar)                                                    \
236
    _(RecompileCheck)
236
    _(RecompileCheck)                                                       \
237
    _(LetCheck)                                                             \
238
    _(ThrowUninitializedLet)
237
239
238
// Forward declarations of MIR types.
240
// Forward declarations of MIR types.
239
#define FORWARD_DECLARE(op) class M##op;
241
#define FORWARD_DECLARE(op) class M##op;
240
 MIR_OPCODE_LIST(FORWARD_DECLARE)
242
 MIR_OPCODE_LIST(FORWARD_DECLARE)
241
#undef FORWARD_DECLARE
243
#undef FORWARD_DECLARE
242
244
243
class MDefinitionVisitor // interface i.e. pure abstract class
245
class MDefinitionVisitor // interface i.e. pure abstract class
244
{
246
{
(-)a/js/src/jit/ParallelSafetyAnalysis.cpp (+2 lines)
Line     Link Here 
 Lines 328-343   class ParallelSafetyVisitor : public MDefinitionVisitor Link Here 
328
    UNSAFE_OP(AsmJSLoadFuncPtr)
328
    UNSAFE_OP(AsmJSLoadFuncPtr)
329
    UNSAFE_OP(AsmJSLoadFFIFunc)
329
    UNSAFE_OP(AsmJSLoadFFIFunc)
330
    UNSAFE_OP(AsmJSReturn)
330
    UNSAFE_OP(AsmJSReturn)
331
    UNSAFE_OP(AsmJSVoidReturn)
331
    UNSAFE_OP(AsmJSVoidReturn)
332
    UNSAFE_OP(AsmJSPassStackArg)
332
    UNSAFE_OP(AsmJSPassStackArg)
333
    UNSAFE_OP(AsmJSParameter)
333
    UNSAFE_OP(AsmJSParameter)
334
    UNSAFE_OP(AsmJSCall)
334
    UNSAFE_OP(AsmJSCall)
335
    DROP_OP(RecompileCheck)
335
    DROP_OP(RecompileCheck)
336
    UNSAFE_OP(LetCheck)
337
    UNSAFE_OP(ThrowUninitializedLet)
336
338
337
    // It looks like this could easily be made safe:
339
    // It looks like this could easily be made safe:
338
    UNSAFE_OP(ConvertElementsToDoubles)
340
    UNSAFE_OP(ConvertElementsToDoubles)
339
};
341
};
340
342
341
static void
343
static void
342
TransplantResumePoint(MInstruction *oldInstruction, MInstruction *replacementInstruction)
344
TransplantResumePoint(MInstruction *oldInstruction, MInstruction *replacementInstruction)
343
{
345
{
(-)a/js/src/jit/VMFunctions.cpp (-1 / +10 lines)
Line     Link Here 
 Lines 817-834   DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *p Link Here 
817
    return true;
817
    return true;
818
}
818
}
819
819
820
bool
820
bool
821
DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
821
DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
822
{
822
{
823
    // Unwind scope chain to stack depth 0.
823
    // Unwind scope chain to stack depth 0.
824
    ScopeIter si(frame, pc, cx);
824
    ScopeIter si(frame, pc, cx);
825
    UnwindAllScopes(cx, si);
825
    jsbytecode *unwindPc = frame->script()->main();
826
    jsbytecode *unwindPc = frame->script()->main();
826
    UnwindScope(cx, si, unwindPc);
827
    frame->setUnwoundScopeOverridePc(unwindPc);
827
    frame->setUnwoundScopeOverridePc(unwindPc);
828
828
829
    // If ScriptDebugEpilogue returns |true| we have to return the frame's
829
    // If ScriptDebugEpilogue returns |true| we have to return the frame's
830
    // return value. If it returns |false|, the debugger threw an exception.
830
    // return value. If it returns |false|, the debugger threw an exception.
831
    // In both cases we have to pop debug scopes.
831
    // In both cases we have to pop debug scopes.
832
    ok = ScriptDebugEpilogue(cx, frame, pc, ok);
832
    ok = ScriptDebugEpilogue(cx, frame, pc, ok);
833
833
834
    if (frame->isNonEvalFunctionFrame()) {
834
    if (frame->isNonEvalFunctionFrame()) {
 Lines 1219-1228   AssertValidValue(JSContext *cx, Value *v) Link Here 
1219
JSObject *
1219
JSObject *
1220
TypedObjectProto(JSObject *obj)
1220
TypedObjectProto(JSObject *obj)
1221
{
1221
{
1222
    JS_ASSERT(obj->is<TypedObject>());
1222
    JS_ASSERT(obj->is<TypedObject>());
1223
    TypedObject &typedObj = obj->as<TypedObject>();
1223
    TypedObject &typedObj = obj->as<TypedObject>();
1224
    return &typedObj.typedProto();
1224
    return &typedObj.typedProto();
1225
}
1225
}
1226
1226
1227
bool
1228
ThrowUninitializedLet(JSContext *cx)
1229
{
1230
    ScriptFrameIter iter(cx);
1231
    RootedScript script(cx, iter.script());
1232
    ReportUninitializedLet(cx, script, iter.pc());
1233
    return false;
1234
}
1235
1227
} // namespace jit
1236
} // namespace jit
1228
} // namespace js
1237
} // namespace js
(-)a/js/src/jit/VMFunctions.h (+2 lines)
Line     Link Here 
 Lines 711-722   bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue Link Here 
711
void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
711
void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
712
void AssertValidStringPtr(JSContext *cx, JSString *str);
712
void AssertValidStringPtr(JSContext *cx, JSString *str);
713
void AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym);
713
void AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym);
714
void AssertValidValue(JSContext *cx, Value *v);
714
void AssertValidValue(JSContext *cx, Value *v);
715
#endif
715
#endif
716
716
717
JSObject *TypedObjectProto(JSObject *obj);
717
JSObject *TypedObjectProto(JSObject *obj);
718
718
719
bool ThrowUninitializedLet(JSContext *cx);
720
719
} // namespace jit
721
} // namespace jit
720
} // namespace js
722
} // namespace js
721
723
722
#endif /* jit_VMFunctions_h */
724
#endif /* jit_VMFunctions_h */
(-)a/js/src/jit/shared/CodeGenerator-shared.cpp (-4 / +6 lines)
Line     Link Here 
 Lines 372-393   CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir, Link Here 
372
            if (!graph.addConstantToPool(constant->value(), &index))
372
            if (!graph.addConstantToPool(constant->value(), &index))
373
                return false;
373
                return false;
374
            alloc = RValueAllocation::ConstantPool(index);
374
            alloc = RValueAllocation::ConstantPool(index);
375
        }
375
        }
376
        break;
376
        break;
377
      }
377
      }
378
      case MIRType_MagicOptimizedArguments:
378
      case MIRType_MagicOptimizedArguments:
379
      case MIRType_MagicOptimizedOut:
379
      case MIRType_MagicOptimizedOut:
380
      case MIRType_MagicUninitializedLet:
380
      {
381
      {
381
        uint32_t index;
382
        uint32_t index;
382
        JSWhyMagic why = (type == MIRType_MagicOptimizedArguments
383
        Value v = MagicValue(type == MIRType_MagicOptimizedArguments
383
                          ? JS_OPTIMIZED_ARGUMENTS
384
                             ? JS_OPTIMIZED_ARGUMENTS
384
                          : JS_OPTIMIZED_OUT);
385
                             : (type == MIRType_MagicOptimizedOut
385
        Value v = MagicValue(why);
386
                                ? JS_OPTIMIZED_OUT
387
                                : JS_UNINITIALIZED_LET));
386
        if (!graph.addConstantToPool(v, &index))
388
        if (!graph.addConstantToPool(v, &index))
387
            return false;
389
            return false;
388
        alloc = RValueAllocation::ConstantPool(index);
390
        alloc = RValueAllocation::ConstantPool(index);
389
        break;
391
        break;
390
      }
392
      }
391
      default:
393
      default:
392
      {
394
      {
393
        JS_ASSERT(mir->type() == MIRType_Value);
395
        JS_ASSERT(mir->type() == MIRType_Value);
(-)a/js/src/js.msg (+1 lines)
Line     Link Here 
 Lines 104-119   MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 1, JSEXN_TYPEERR, "cyclic {0} value") Link Here 
104
104
105
// Runtime errors
105
// Runtime errors
106
MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
106
MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
107
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,     0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
107
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,     0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
108
MSG_DEF(JSMSG_BAD_PROTOTYPE,           1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object")
108
MSG_DEF(JSMSG_BAD_PROTOTYPE,           1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object")
109
MSG_DEF(JSMSG_IN_NOT_OBJECT,           1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
109
MSG_DEF(JSMSG_IN_NOT_OBJECT,           1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
110
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments")
110
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments")
111
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments")
111
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments")
112
MSG_DEF(JSMSG_UNINITIALIZED_LET,       1, JSEXN_REFERENCEERR, "can't access let declaration `{0}' before initialization")
112
113
113
// Date
114
// Date
114
MSG_DEF(JSMSG_INVALID_DATE,            0, JSEXN_RANGEERR, "invalid date")
115
MSG_DEF(JSMSG_INVALID_DATE,            0, JSEXN_RANGEERR, "invalid date")
115
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP,    0, JSEXN_TYPEERR, "toISOString property is not callable")
116
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP,    0, JSEXN_TYPEERR, "toISOString property is not callable")
116
117
117
// String
118
// String
118
MSG_DEF(JSMSG_BAD_URI,                 0, JSEXN_URIERR, "malformed URI sequence")
119
MSG_DEF(JSMSG_BAD_URI,                 0, JSEXN_URIERR, "malformed URI sequence")
119
MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM,  0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
120
MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM,  0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
(-)a/js/src/jsinfer.h (-4 / +4 lines)
Line     Link Here 
 Lines 313-333   class Type Link Here 
313
313
314
    static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
314
    static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
315
};
315
};
316
316
317
/* Get the type of a jsval, or zero for an unknown special value. */
317
/* Get the type of a jsval, or zero for an unknown special value. */
318
inline Type GetValueType(const Value &val);
318
inline Type GetValueType(const Value &val);
319
319
320
/*
320
/*
321
 * Get the type of a possibly optimized out value. This generally only
321
 * Get the type of a possibly optimized out or uninitialized let value. This
322
 * happens on unconditional type monitors on bailing out of Ion, such as
322
 * generally only happens on unconditional type monitors on bailing out of
323
 * for argument and local types.
323
 * Ion, such as for argument and local types.
324
 */
324
 */
325
inline Type GetMaybeOptimizedOutValueType(const Value &val);
325
inline Type GetMaybeUntrackedValueType(const Value &val);
326
326
327
/*
327
/*
328
 * Type inference memory management overview.
328
 * Type inference memory management overview.
329
 *
329
 *
330
 * Type information about the values observed within scripts and about the
330
 * Type information about the values observed within scripts and about the
331
 * contents of the heap is accumulated as the program executes. Compilation
331
 * contents of the heap is accumulated as the program executes. Compilation
332
 * accumulates constraints relating type information on the heap with the
332
 * accumulates constraints relating type information on the heap with the
333
 * compilations that should be invalidated when those types change. Type
333
 * compilations that should be invalidated when those types change. Type
(-)a/js/src/jsinferinlines.h (-2 / +5 lines)
Line     Link Here 
 Lines 132-151   GetValueType(const Value &val) Link Here 
132
    if (val.isDouble())
132
    if (val.isDouble())
133
        return Type::DoubleType();
133
        return Type::DoubleType();
134
    if (val.isObject())
134
    if (val.isObject())
135
        return Type::ObjectType(&val.toObject());
135
        return Type::ObjectType(&val.toObject());
136
    return Type::PrimitiveType(val.extractNonDoubleType());
136
    return Type::PrimitiveType(val.extractNonDoubleType());
137
}
137
}
138
138
139
inline Type
139
inline Type
140
GetMaybeOptimizedOutValueType(const Value &val)
140
GetMaybeUntrackedValueType(const Value &val)
141
{
141
{
142
    if (val.isMagic() && val.whyMagic() == JS_OPTIMIZED_OUT)
142
    if (val.isMagic() && (val.whyMagic() == JS_OPTIMIZED_OUT ||
143
                          val.whyMagic() == JS_UNINITIALIZED_LET))
144
    {
143
        return Type::UnknownType();
145
        return Type::UnknownType();
146
    }
144
    return GetValueType(val);
147
    return GetValueType(val);
145
}
148
}
146
149
147
inline TypeFlags
150
inline TypeFlags
148
PrimitiveTypeFlag(JSValueType type)
151
PrimitiveTypeFlag(JSValueType type)
149
{
152
{
150
    switch (type) {
153
    switch (type) {
151
      case JSVAL_TYPE_UNDEFINED:
154
      case JSVAL_TYPE_UNDEFINED:
(-)a/js/src/jsobj.cpp (-10 / +8 lines)
Line     Link Here 
 Lines 4450-4498   js::LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain, Link Here 
4450
        }
4450
        }
4451
    }
4451
    }
4452
4452
4453
    return true;
4453
    return true;
4454
}
4454
}
4455
4455
4456
bool
4456
bool
4457
js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
4457
js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
4458
                                MutableHandleObject objp)
4458
                                MutableHandleObject objp, MutableHandleShape propp)
4459
{
4459
{
4460
    RootedId id(cx, NameToId(name));
4460
    RootedId id(cx, NameToId(name));
4461
4461
4462
    RootedObject pobj(cx);
4462
    RootedObject pobj(cx);
4463
    RootedShape prop(cx);
4464
4463
4465
    RootedObject scope(cx, scopeChain);
4464
    RootedObject scope(cx, scopeChain);
4466
    for (; !scope->is<GlobalObject>(); scope = scope->enclosingScope()) {
4465
    for (; !scope->is<GlobalObject>(); scope = scope->enclosingScope()) {
4467
        if (!JSObject::lookupGeneric(cx, scope, id, &pobj, &prop))
4466
        if (!JSObject::lookupGeneric(cx, scope, id, &pobj, propp))
4468
            return false;
4467
            return false;
4469
        if (prop)
4468
        if (propp)
4470
            break;
4469
            break;
4471
    }
4470
    }
4472
4471
4473
    objp.set(scope);
4472
    objp.set(scope);
4474
    return true;
4473
    return true;
4475
}
4474
}
4476
4475
4477
bool
4476
bool
4478
js::LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
4477
js::LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
4479
                          MutableHandleObject objp)
4478
                          MutableHandleObject objp, MutableHandleShape propp)
4480
{
4479
{
4481
    RootedId id(cx, NameToId(name));
4480
    RootedId id(cx, NameToId(name));
4482
4481
4483
    RootedObject pobj(cx);
4482
    RootedObject pobj(cx);
4484
    RootedShape prop(cx);
4485
4483
4486
    RootedObject scope(cx, scopeChain);
4484
    RootedObject scope(cx, scopeChain);
4487
    for (; !scope->isUnqualifiedVarObj(); scope = scope->enclosingScope()) {
4485
    for (; !scope->isUnqualifiedVarObj(); scope = scope->enclosingScope()) {
4488
        if (!JSObject::lookupGeneric(cx, scope, id, &pobj, &prop))
4486
        if (!JSObject::lookupGeneric(cx, scope, id, &pobj, propp))
4489
            return false;
4487
            return false;
4490
        if (prop)
4488
        if (propp)
4491
            break;
4489
            break;
4492
    }
4490
    }
4493
4491
4494
    objp.set(scope);
4492
    objp.set(scope);
4495
    return true;
4493
    return true;
4496
}
4494
}
4497
4495
4498
template <AllowGC allowGC>
4496
template <AllowGC allowGC>
 Lines 4575-4592   NativeGetInline(JSContext *cx, Link Here 
4575
                typename MaybeRooted<JSObject*, allowGC>::HandleType pobj,
4573
                typename MaybeRooted<JSObject*, allowGC>::HandleType pobj,
4576
                typename MaybeRooted<Shape*, allowGC>::HandleType shape,
4574
                typename MaybeRooted<Shape*, allowGC>::HandleType shape,
4577
                typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
4575
                typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
4578
{
4576
{
4579
    JS_ASSERT(pobj->isNative());
4577
    JS_ASSERT(pobj->isNative());
4580
4578
4581
    if (shape->hasSlot()) {
4579
    if (shape->hasSlot()) {
4582
        vp.set(pobj->nativeGetSlot(shape->slot()));
4580
        vp.set(pobj->nativeGetSlot(shape->slot()));
4583
        JS_ASSERT(!vp.isMagic());
4581
        JS_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LET) &&
4584
        JS_ASSERT_IF(!pobj->hasSingletonType() &&
4582
                     !pobj->hasSingletonType() &&
4585
                     !pobj->template is<ScopeObject>() &&
4583
                     !pobj->template is<ScopeObject>() &&
4586
                     shape->hasDefaultGetter(),
4584
                     shape->hasDefaultGetter(),
4587
                     js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
4585
                     js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
4588
    } else {
4586
    } else {
4589
        vp.setUndefined();
4587
        vp.setUndefined();
4590
    }
4588
    }
4591
    if (shape->hasDefaultGetter())
4589
    if (shape->hasDefaultGetter())
4592
        return true;
4590
        return true;
(-)a/js/src/jsobj.h (-4 / +3 lines)
Line     Link Here 
 Lines 1412-1439   LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain, Link Here 
1412
 * Like LookupName except returns the global object if 'name' is not found in
1412
 * Like LookupName except returns the global object if 'name' is not found in
1413
 * any preceding scope.
1413
 * any preceding scope.
1414
 *
1414
 *
1415
 * Additionally, pobjp and propp are not needed by callers so they are not
1415
 * Additionally, pobjp and propp are not needed by callers so they are not
1416
 * returned.
1416
 * returned.
1417
 */
1417
 */
1418
extern bool
1418
extern bool
1419
LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
1419
LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
1420
                            MutableHandleObject objp);
1420
                            MutableHandleObject objp, MutableHandleShape propp);
1421
1421
1422
/*
1422
/*
1423
 * Like LookupName except returns the unqualified var object if 'name' is not found in
1423
 * Like LookupName except returns the unqualified var object if 'name' is not found in
1424
 * any preceding scope. Normally the unqualified var object is the global.
1424
 * any preceding scope. Normally the unqualified var object is the global.
1425
 *
1425
 *
1426
 * Additionally, pobjp and propp are not needed by callers so they are not
1426
 * Additionally, pobjp is not needed by callers so it is not returned.
1427
 * returned.
1428
 */
1427
 */
1429
extern bool
1428
extern bool
1430
LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
1429
LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
1431
                      MutableHandleObject objp);
1430
                      MutableHandleObject objp, MutableHandleShape propp);
1432
1431
1433
}
1432
}
1434
1433
1435
extern JSObject *
1434
extern JSObject *
1436
js_FindVariableScope(JSContext *cx, JSFunction **funp);
1435
js_FindVariableScope(JSContext *cx, JSFunction **funp);
1437
1436
1438
1437
1439
namespace js {
1438
namespace js {
(-)a/js/src/jsopcode.cpp (-1 / +1 lines)
Line     Link Here 
 Lines 1628-1644   ExpressionDecompiler::getArg(unsigned slot) Link Here 
1628
    JS_ASSERT(slot < script->bindings.count());
1628
    JS_ASSERT(slot < script->bindings.count());
1629
    return (*localNames)[slot].name();
1629
    return (*localNames)[slot].name();
1630
}
1630
}
1631
1631
1632
JSAtom *
1632
JSAtom *
1633
ExpressionDecompiler::getLocal(uint32_t local, jsbytecode *pc)
1633
ExpressionDecompiler::getLocal(uint32_t local, jsbytecode *pc)
1634
{
1634
{
1635
    JS_ASSERT(local < script->nfixed());
1635
    JS_ASSERT(local < script->nfixed());
1636
    if (local < script->nfixedvars()) {
1636
    if (local < script->nbodyfixed()) {
1637
        JS_ASSERT(fun);
1637
        JS_ASSERT(fun);
1638
        uint32_t slot = local + fun->nargs();
1638
        uint32_t slot = local + fun->nargs();
1639
        JS_ASSERT(slot < script->bindings.count());
1639
        JS_ASSERT(slot < script->bindings.count());
1640
        return (*localNames)[slot].name();
1640
        return (*localNames)[slot].name();
1641
    }
1641
    }
1642
    for (NestedScopeObject *chain = script->getStaticScope(pc);
1642
    for (NestedScopeObject *chain = script->getStaticScope(pc);
1643
         chain;
1643
         chain;
1644
         chain = chain->enclosingNestedScope()) {
1644
         chain = chain->enclosingNestedScope()) {
(-)a/js/src/jsscript.cpp (-23 / +60 lines)
Line     Link Here 
 Lines 70-100   Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle binding Link Here 
70
    BindingIter bi(bindings);
70
    BindingIter bi(bindings);
71
    while (bi->name() != arguments)
71
    while (bi->name() != arguments)
72
        bi++;
72
        bi++;
73
    return bi.frameIndex();
73
    return bi.frameIndex();
74
}
74
}
75
75
76
bool
76
bool
77
Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
77
Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
78
                                   unsigned numArgs, uint32_t numVars,
78
                                   uint32_t numArgs, uint32_t numVars,
79
                                   Binding *bindingArray, uint32_t numBlockScoped)
79
                                   uint32_t numBodyLevelLets, uint32_t numBlockScoped,
80
                                   Binding *bindingArray)
80
{
81
{
81
    JS_ASSERT(!self->callObjShape_);
82
    JS_ASSERT(!self->callObjShape_);
82
    JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
83
    JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
83
    JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
84
    JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
84
    JS_ASSERT(numArgs <= ARGC_LIMIT);
85
    JS_ASSERT(numArgs <= ARGC_LIMIT);
85
    JS_ASSERT(numVars <= LOCALNO_LIMIT);
86
    JS_ASSERT(numVars <= LOCALNO_LIMIT);
86
    JS_ASSERT(numBlockScoped <= LOCALNO_LIMIT);
87
    JS_ASSERT(numBlockScoped <= LOCALNO_LIMIT);
87
    JS_ASSERT(numVars <= LOCALNO_LIMIT - numBlockScoped);
88
    JS_ASSERT(numBodyLevelLets <= LOCALNO_LIMIT);
88
    JS_ASSERT(UINT32_MAX - numArgs >= numVars + numBlockScoped);
89
    uint64_t totalSlots = uint64_t(numVars) + uint64_t(numBodyLevelLets) + uint64_t(numBlockScoped);
90
    JS_ASSERT(totalSlots <= LOCALNO_LIMIT);
91
    JS_ASSERT(UINT32_MAX - numArgs >= totalSlots);
89
92
90
    self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
93
    self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
91
    self->numArgs_ = numArgs;
94
    self->numArgs_ = numArgs;
92
    self->numVars_ = numVars;
95
    self->numVars_ = numVars;
96
    self->numBodyLevelLets_ = numBodyLevelLets;
93
    self->numBlockScoped_ = numBlockScoped;
97
    self->numBlockScoped_ = numBlockScoped;
94
98
95
    // Get the initial shape to use when creating CallObjects for this script.
99
    // Get the initial shape to use when creating CallObjects for this script.
96
    // After creation, a CallObject's shape may change completely (via direct eval() or
100
    // After creation, a CallObject's shape may change completely (via direct eval() or
97
    // other operations that mutate the lexical scope). However, since the
101
    // other operations that mutate the lexical scope). However, since the
98
    // lexical bindings added to the initial shape are permanent and the
102
    // lexical bindings added to the initial shape are permanent and the
99
    // allocKind/nfixed of a CallObject cannot change, one may assume that the
103
    // allocKind/nfixed of a CallObject cannot change, one may assume that the
100
    // slot location (whether in the fixed or dynamic slots) of a variable is
104
    // slot location (whether in the fixed or dynamic slots) of a variable is
 Lines 102-121   Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle Link Here 
102
    // JITs when interpreting/compiling aliasedvar ops.)
106
    // JITs when interpreting/compiling aliasedvar ops.)
103
107
104
    // Since unaliased variables are, by definition, only accessed by local
108
    // Since unaliased variables are, by definition, only accessed by local
105
    // operations and never through the scope chain, only give shapes to
109
    // operations and never through the scope chain, only give shapes to
106
    // aliased variables. While the debugger may observe any scope object at
110
    // aliased variables. While the debugger may observe any scope object at
107
    // any time, such accesses are mediated by DebugScopeProxy (see
111
    // any time, such accesses are mediated by DebugScopeProxy (see
108
    // DebugScopeProxy::handleUnaliasedAccess).
112
    // DebugScopeProxy::handleUnaliasedAccess).
109
    uint32_t nslots = CallObject::RESERVED_SLOTS;
113
    uint32_t nslots = CallObject::RESERVED_SLOTS;
114
    uint32_t aliasedBodyLevelLetStart = UINT16_MAX;
110
    for (BindingIter bi(self); bi; bi++) {
115
    for (BindingIter bi(self); bi; bi++) {
111
        if (bi->aliased())
116
        if (bi->aliased()) {
117
            // Per ES6, lets cannot be accessed until initialized. Remember
118
            // the first aliased slot that is a body-level let, so that they
119
            // may be initialized to sentinel magic values.
120
            if (numBodyLevelLets > 0 &&
121
                nslots < aliasedBodyLevelLetStart &&
122
                bi->kind() == Binding::VARIABLE &&
123
                bi.frameIndex() >= numVars)
124
            {
125
                aliasedBodyLevelLetStart = nslots;
126
            }
127
112
            nslots++;
128
            nslots++;
129
        }
113
    }
130
    }
131
    self->aliasedBodyLevelLetStart_ = aliasedBodyLevelLetStart;
114
132
115
    // Put as many of nslots inline into the object header as possible.
133
    // Put as many of nslots inline into the object header as possible.
116
    uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots));
134
    uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots));
117
135
118
    // Start with the empty shape and then append one shape per aliased binding.
136
    // Start with the empty shape and then append one shape per aliased binding.
119
    RootedShape shape(cx,
137
    RootedShape shape(cx,
120
        EmptyShape::getInitialShape(cx, &CallObject::class_, TaggedProto(nullptr), nullptr, nullptr,
138
        EmptyShape::getInitialShape(cx, &CallObject::class_, TaggedProto(nullptr), nullptr, nullptr,
121
                                    nfixed, BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE));
139
                                    nfixed, BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE));
 Lines 188-237   Bindings::clone(JSContext *cx, InternalBindingsHandle self, Link Here 
188
    JS_ASSERT(off >= 0);
206
    JS_ASSERT(off >= 0);
189
    JS_ASSERT(size_t(off) <= srcScript->dataSize());
207
    JS_ASSERT(size_t(off) <= srcScript->dataSize());
190
    Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
208
    Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
191
209
192
    /*
210
    /*
193
     * Since atoms are shareable throughout the runtime, we can simply copy
211
     * Since atoms are shareable throughout the runtime, we can simply copy
194
     * the source's bindingArray directly.
212
     * the source's bindingArray directly.
195
     */
213
     */
196
    if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray(),
214
    if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(),
197
                                  src.numBlockScoped()))
215
                                  src.numBodyLevelLets(), src.numBlockScoped(),
216
                                  src.bindingArray()))
217
    {
198
        return false;
218
        return false;
219
    }
220
199
    self->switchToScriptStorage(dstPackedBindings);
221
    self->switchToScriptStorage(dstPackedBindings);
200
    return true;
222
    return true;
201
}
223
}
202
224
203
/* static */ Bindings
225
/* static */ Bindings
204
GCMethods<Bindings>::initial()
226
GCMethods<Bindings>::initial()
205
{
227
{
206
    return Bindings();
228
    return Bindings();
207
}
229
}
208
230
209
template<XDRMode mode>
231
template<XDRMode mode>
210
static bool
232
static bool
211
XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, uint32_t numVars,
233
XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, uint16_t numArgs, uint32_t numVars,
212
                  HandleScript script, unsigned numBlockScoped)
234
                  uint16_t numBodyLevelLets, uint16_t numBlockScoped, HandleScript script)
213
{
235
{
214
    JSContext *cx = xdr->cx();
236
    JSContext *cx = xdr->cx();
215
237
216
    if (mode == XDR_ENCODE) {
238
    if (mode == XDR_ENCODE) {
217
        for (BindingIter bi(script); bi; bi++) {
239
        for (BindingIter bi(script); bi; bi++) {
218
            RootedAtom atom(cx, bi->name());
240
            RootedAtom atom(cx, bi->name());
219
            if (!XDRAtom(xdr, &atom))
241
            if (!XDRAtom(xdr, &atom))
220
                return false;
242
                return false;
221
        }
243
        }
222
244
223
        for (BindingIter bi(script); bi; bi++) {
245
        for (BindingIter bi(script); bi; bi++) {
224
            uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
246
            uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
225
            if (!xdr->codeUint8(&u8))
247
            if (!xdr->codeUint8(&u8))
226
                return false;
248
                return false;
227
        }
249
        }
228
    } else {
250
    } else {
229
        uint32_t nameCount = numArgs + numVars;
251
        uint32_t nameCount = numArgs + numVars + numBodyLevelLets;
230
252
231
        AutoValueVector atoms(cx);
253
        AutoValueVector atoms(cx);
232
        if (!atoms.resize(nameCount))
254
        if (!atoms.resize(nameCount))
233
            return false;
255
            return false;
234
        for (uint32_t i = 0; i < nameCount; i++) {
256
        for (uint32_t i = 0; i < nameCount; i++) {
235
            RootedAtom atom(cx);
257
            RootedAtom atom(cx);
236
            if (!XDRAtom(xdr, &atom))
258
            if (!XDRAtom(xdr, &atom))
237
                return false;
259
                return false;
 Lines 249-267   XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, ui Link Here 
249
            PropertyName *name = atoms[i].toString()->asAtom().asPropertyName();
271
            PropertyName *name = atoms[i].toString()->asAtom().asPropertyName();
250
            Binding::Kind kind = Binding::Kind(u8 >> 1);
272
            Binding::Kind kind = Binding::Kind(u8 >> 1);
251
            bool aliased = bool(u8 & 1);
273
            bool aliased = bool(u8 & 1);
252
274
253
            bindingArray[i] = Binding(name, kind, aliased);
275
            bindingArray[i] = Binding(name, kind, aliased);
254
        }
276
        }
255
277
256
        InternalBindingsHandle bindings(script, &script->bindings);
278
        InternalBindingsHandle bindings(script, &script->bindings);
257
        if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray,
279
        if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, numBodyLevelLets,
258
                                                numBlockScoped))
280
                                                numBlockScoped, bindingArray))
281
        {
259
            return false;
282
            return false;
283
        }
260
    }
284
    }
261
285
262
    return true;
286
    return true;
263
}
287
}
264
288
265
bool
289
bool
266
Bindings::bindingIsAliased(uint32_t bindingIndex)
290
Bindings::bindingIsAliased(uint32_t bindingIndex)
267
{
291
{
 Lines 425-451   js::XDRScriptConst(XDRState<XDR_DECODE> *, MutableHandleValue); Link Here 
425
449
426
// Code LazyScript's free variables.
450
// Code LazyScript's free variables.
427
template<XDRMode mode>
451
template<XDRMode mode>
428
static bool
452
static bool
429
XDRLazyFreeVariables(XDRState<mode> *xdr, MutableHandle<LazyScript *> lazy)
453
XDRLazyFreeVariables(XDRState<mode> *xdr, MutableHandle<LazyScript *> lazy)
430
{
454
{
431
    JSContext *cx = xdr->cx();
455
    JSContext *cx = xdr->cx();
432
    RootedAtom atom(cx);
456
    RootedAtom atom(cx);
433
    HeapPtrAtom *freeVariables = lazy->freeVariables();
457
    LazyScript::FreeVariable *freeVariables = lazy->freeVariables();
434
    size_t numFreeVariables = lazy->numFreeVariables();
458
    size_t numFreeVariables = lazy->numFreeVariables();
435
    for (size_t i = 0; i < numFreeVariables; i++) {
459
    for (size_t i = 0; i < numFreeVariables; i++) {
436
        if (mode == XDR_ENCODE)
460
        if (mode == XDR_ENCODE)
437
            atom = freeVariables[i];
461
            atom = freeVariables[i].atom();
438
462
439
        if (!XDRAtom(xdr, &atom))
463
        if (!XDRAtom(xdr, &atom))
440
            return false;
464
            return false;
441
465
442
        if (mode == XDR_DECODE)
466
        if (mode == XDR_DECODE)
443
            freeVariables[i] = atom;
467
            freeVariables[i] = LazyScript::FreeVariable(atom);
444
    }
468
    }
445
469
446
    return true;
470
    return true;
447
}
471
}
448
472
449
// Code the missing part needed to re-create a LazyScript from a JSScript.
473
// Code the missing part needed to re-create a LazyScript from a JSScript.
450
template<XDRMode mode>
474
template<XDRMode mode>
451
static bool
475
static bool
 Lines 556-584   js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc Link Here 
556
    JSContext *cx = xdr->cx();
580
    JSContext *cx = xdr->cx();
557
    RootedScript script(cx);
581
    RootedScript script(cx);
558
    natoms = nsrcnotes = 0;
582
    natoms = nsrcnotes = 0;
559
    nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
583
    nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
560
584
561
    /* XDR arguments and vars. */
585
    /* XDR arguments and vars. */
562
    uint16_t nargs = 0;
586
    uint16_t nargs = 0;
563
    uint16_t nblocklocals = 0;
587
    uint16_t nblocklocals = 0;
588
    uint16_t nbodylevellets = 0;
564
    uint32_t nvars = 0;
589
    uint32_t nvars = 0;
565
    if (mode == XDR_ENCODE) {
590
    if (mode == XDR_ENCODE) {
566
        script = scriptp.get();
591
        script = scriptp.get();
567
        JS_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
592
        JS_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
568
593
569
        nargs = script->bindings.numArgs();
594
        nargs = script->bindings.numArgs();
570
        nblocklocals = script->bindings.numBlockScoped();
595
        nblocklocals = script->bindings.numBlockScoped();
596
        nbodylevellets = script->bindings.numBodyLevelLets();
571
        nvars = script->bindings.numVars();
597
        nvars = script->bindings.numVars();
572
    }
598
    }
573
    if (!xdr->codeUint16(&nargs))
599
    if (!xdr->codeUint16(&nargs))
574
        return false;
600
        return false;
575
    if (!xdr->codeUint16(&nblocklocals))
601
    if (!xdr->codeUint16(&nblocklocals))
576
        return false;
602
        return false;
603
    if (!xdr->codeUint16(&nbodylevellets))
604
        return false;
577
    if (!xdr->codeUint32(&nvars))
605
    if (!xdr->codeUint32(&nvars))
578
        return false;
606
        return false;
579
607
580
    if (mode == XDR_ENCODE)
608
    if (mode == XDR_ENCODE)
581
        length = script->length();
609
        length = script->length();
582
    if (!xdr->codeUint32(&length))
610
    if (!xdr->codeUint32(&length))
583
        return false;
611
        return false;
584
612
 Lines 714-730   js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc Link Here 
714
        script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
742
        script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
715
                                  options, /* staticLevel = */ 0, sourceObject, 0, 0);
743
                                  options, /* staticLevel = */ 0, sourceObject, 0, 0);
716
        if (!script)
744
        if (!script)
717
            return false;
745
            return false;
718
    }
746
    }
719
747
720
    /* JSScript::partiallyInit assumes script->bindings is fully initialized. */
748
    /* JSScript::partiallyInit assumes script->bindings is fully initialized. */
721
    LifoAllocScope las(&cx->tempLifoAlloc());
749
    LifoAllocScope las(&cx->tempLifoAlloc());
722
    if (!XDRScriptBindings(xdr, las, nargs, nvars, script, nblocklocals))
750
    if (!XDRScriptBindings(xdr, las, nargs, nvars, nbodylevellets, nblocklocals, script))
723
        return false;
751
        return false;
724
752
725
    if (mode == XDR_DECODE) {
753
    if (mode == XDR_DECODE) {
726
        if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
754
        if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
727
                                     nblockscopes, nTypeSets))
755
                                     nblockscopes, nTypeSets))
728
        {
756
        {
729
            return false;
757
            return false;
730
        }
758
        }
 Lines 3375-3393   LazyScript::markChildren(JSTracer *trc) Link Here 
3375
        MarkObject(trc, &sourceObject_, "sourceObject");
3403
        MarkObject(trc, &sourceObject_, "sourceObject");
3376
3404
3377
    if (enclosingScope_)
3405
    if (enclosingScope_)
3378
        MarkObject(trc, &enclosingScope_, "enclosingScope");
3406
        MarkObject(trc, &enclosingScope_, "enclosingScope");
3379
3407
3380
    if (script_)
3408
    if (script_)
3381
        MarkScript(trc, &script_, "realScript");
3409
        MarkScript(trc, &script_, "realScript");
3382
3410
3383
    HeapPtrAtom *freeVariables = this->freeVariables();
3411
    // We rely on the fact that atoms are always tenured.
3384
    for (size_t i = 0; i < numFreeVariables(); i++)
3412
    FreeVariable *freeVariables = this->freeVariables();
3385
        MarkString(trc, &freeVariables[i], "lazyScriptFreeVariable");
3413
    for (size_t i = 0; i < numFreeVariables(); i++) {
3414
        JSAtom *atom = freeVariables[i].atom();
3415
        MarkStringUnbarriered(trc, &atom, "lazyScriptFreeVariable");
3416
    }
3386
3417
3387
    HeapPtrFunction *innerFunctions = this->innerFunctions();
3418
    HeapPtrFunction *innerFunctions = this->innerFunctions();
3388
    for (size_t i = 0; i < numInnerFunctions(); i++)
3419
    for (size_t i = 0; i < numInnerFunctions(); i++)
3389
        MarkObject(trc, &innerFunctions[i], "lazyScriptInnerFunction");
3420
        MarkObject(trc, &innerFunctions[i], "lazyScriptInnerFunction");
3390
}
3421
}
3391
3422
3392
void
3423
void
3393
LazyScript::finalize(FreeOp *fop)
3424
LazyScript::finalize(FreeOp *fop)
 Lines 3570-3586   JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) Link Here 
3570
    }
3601
    }
3571
3602
3572
    return true;
3603
    return true;
3573
}
3604
}
3574
3605
3575
bool
3606
bool
3576
JSScript::varIsAliased(uint32_t varSlot)
3607
JSScript::varIsAliased(uint32_t varSlot)
3577
{
3608
{
3578
    return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
3609
    return bodyLevelLocalIsAliased(varSlot);
3610
}
3611
3612
bool
3613
JSScript::bodyLevelLocalIsAliased(uint32_t localSlot)
3614
{
3615
    return bindings.bindingIsAliased(bindings.numArgs() + localSlot);
3579
}
3616
}
3580
3617
3581
bool
3618
bool
3582
JSScript::formalIsAliased(unsigned argSlot)
3619
JSScript::formalIsAliased(unsigned argSlot)
3583
{
3620
{
3584
    return bindings.bindingIsAliased(argSlot);
3621
    return bindings.bindingIsAliased(argSlot);
3585
}
3622
}
3586
3623
 Lines 3647-3663   LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun, Link Here 
3647
    };
3684
    };
3648
3685
3649
    packed = packedFields;
3686
    packed = packedFields;
3650
3687
3651
    // Reset runtime flags to obtain a fresh LazyScript.
3688
    // Reset runtime flags to obtain a fresh LazyScript.
3652
    p.hasBeenCloned = false;
3689
    p.hasBeenCloned = false;
3653
    p.treatAsRunOnce = false;
3690
    p.treatAsRunOnce = false;
3654
3691
3655
    size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom))
3692
    size_t bytes = (p.numFreeVariables * sizeof(FreeVariable))
3656
                 + (p.numInnerFunctions * sizeof(HeapPtrFunction));
3693
                 + (p.numInnerFunctions * sizeof(HeapPtrFunction));
3657
3694
3658
    ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
3695
    ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
3659
    if (bytes && !table)
3696
    if (bytes && !table)
3660
        return nullptr;
3697
        return nullptr;
3661
3698
3662
    LazyScript *res = js_NewGCLazyScript(cx);
3699
    LazyScript *res = js_NewGCLazyScript(cx);
3663
    if (!res)
3700
    if (!res)
 Lines 3707-3725   LazyScript::Create(ExclusiveContext *cx, HandleFunction fun, Link Here 
3707
3744
3708
    LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
3745
    LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
3709
    if (!res)
3746
    if (!res)
3710
        return nullptr;
3747
        return nullptr;
3711
3748
3712
    // Fill with dummies, to be GC-safe after the initialization of the free
3749
    // Fill with dummies, to be GC-safe after the initialization of the free
3713
    // variables and inner functions.
3750
    // variables and inner functions.
3714
    size_t i, num;
3751
    size_t i, num;
3715
    HeapPtrAtom *variables = res->freeVariables();
3752
    FreeVariable *variables = res->freeVariables();
3716
    for (i = 0, num = res->numFreeVariables(); i < num; i++)
3753
    for (i = 0, num = res->numFreeVariables(); i < num; i++)
3717
        variables[i].init(dummyAtom);
3754
        variables[i] = FreeVariable(dummyAtom);
3718
3755
3719
    HeapPtrFunction *functions = res->innerFunctions();
3756
    HeapPtrFunction *functions = res->innerFunctions();
3720
    for (i = 0, num = res->numInnerFunctions(); i < num; i++)
3757
    for (i = 0, num = res->numInnerFunctions(); i < num; i++)
3721
        functions[i].init(dummyFun);
3758
        functions[i].init(dummyFun);
3722
3759
3723
    return res;
3760
    return res;
3724
}
3761
}
3725
3762
(-)a/js/src/jsscript.h (-14 / +74 lines)
Line     Link Here 
 Lines 132-149   class Binding Link Here 
132
    // packed-word representation.
132
    // packed-word representation.
133
    uintptr_t bits_;
133
    uintptr_t bits_;
134
134
135
    static const uintptr_t KIND_MASK = 0x3;
135
    static const uintptr_t KIND_MASK = 0x3;
136
    static const uintptr_t ALIASED_BIT = 0x4;
136
    static const uintptr_t ALIASED_BIT = 0x4;
137
    static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
137
    static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT);
138
138
139
  public:
139
  public:
140
    // A "binding" is a formal, 'var', or 'const' declaration. A function's
140
    // A "binding" is a formal, 'var' (also a stand in for body-level 'let'
141
    // lexical scope is composed of these three kinds of bindings.
141
    // declarations), or 'const' declaration. A function's lexical scope is
142
    // composed of these three kinds of bindings.
142
    enum Kind { ARGUMENT, VARIABLE, CONSTANT };
143
    enum Kind { ARGUMENT, VARIABLE, CONSTANT };
143
144
144
    explicit Binding() : bits_(0) {}
145
    explicit Binding() : bits_(0) {}
145
146
146
    Binding(PropertyName *name, Kind kind, bool aliased) {
147
    Binding(PropertyName *name, Kind kind, bool aliased) {
147
        JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
148
        JS_STATIC_ASSERT(CONSTANT <= KIND_MASK);
148
        JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
149
        JS_ASSERT((uintptr_t(name) & ~NAME_MASK) == 0);
149
        JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
150
        JS_ASSERT((uintptr_t(kind) & ~KIND_MASK) == 0);
 Lines 178-195   class Bindings Link Here 
178
{
179
{
179
    friend class BindingIter;
180
    friend class BindingIter;
180
    friend class AliasedFormalIter;
181
    friend class AliasedFormalIter;
181
182
182
    HeapPtrShape callObjShape_;
183
    HeapPtrShape callObjShape_;
183
    uintptr_t bindingArrayAndFlag_;
184
    uintptr_t bindingArrayAndFlag_;
184
    uint16_t numArgs_;
185
    uint16_t numArgs_;
185
    uint16_t numBlockScoped_;
186
    uint16_t numBlockScoped_;
187
    uint16_t numBodyLevelLets_;
188
    uint16_t aliasedBodyLevelLetStart_;
186
    uint32_t numVars_;
189
    uint32_t numVars_;
187
190
191
#if JS_BITS_PER_WORD == 32
192
    // Bindings is allocated inline inside JSScript, which needs to be
193
    // gc::Cell aligned.
194
    uint32_t padding_;
195
#endif
196
188
    /*
197
    /*
189
     * During parsing, bindings are allocated out of a temporary LifoAlloc.
198
     * During parsing, bindings are allocated out of a temporary LifoAlloc.
190
     * After parsing, a JSScript object is created and the bindings are
199
     * After parsing, a JSScript object is created and the bindings are
191
     * permanently transferred to it. On error paths, the JSScript object may
200
     * permanently transferred to it. On error paths, the JSScript object may
192
     * end up with bindings that still point to the (new released) LifoAlloc
201
     * end up with bindings that still point to the (new released) LifoAlloc
193
     * memory. To avoid tracing these bindings during GC, we keep track of
202
     * memory. To avoid tracing these bindings during GC, we keep track of
194
     * whether the bindings are temporary or permanent in the low bit of
203
     * whether the bindings are temporary or permanent in the low bit of
195
     * bindingArrayAndFlag_.
204
     * bindingArrayAndFlag_.
 Lines 204-226   class Bindings Link Here 
204
    Binding *bindingArray() const {
213
    Binding *bindingArray() const {
205
        return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
214
        return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
206
    }
215
    }
207
216
208
    inline Bindings();
217
    inline Bindings();
209
218
210
    /*
219
    /*
211
     * Initialize a Bindings with a pointer into temporary storage.
220
     * Initialize a Bindings with a pointer into temporary storage.
212
     * bindingArray must have length numArgs+numVars. Before the temporary
221
     * bindingArray must have length numArgs+numVars+numBodyLevelLets. Before
213
     * storage is release, switchToScriptStorage must be called, providing a
222
     * the temporary storage is release, switchToScriptStorage must be called,
214
     * pointer into the Binding array stored in script->data.
223
     * providing a pointer into the Binding array stored in script->data.
215
     */
224
     */
216
    static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
225
    static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
217
                                         unsigned numArgs, uint32_t numVars,
226
                                         uint32_t numArgs, uint32_t numVars,
218
                                         Binding *bindingArray, unsigned numBlockScoped);
227
                                         uint32_t numBodyLevelLets, uint32_t numBlockScoped,
228
                                         Binding *bindingArray);
219
229
220
    // CompileScript parses and compiles one statement at a time, but the result
230
    // CompileScript parses and compiles one statement at a time, but the result
221
    // is one Script object.  There will be no vars or bindings, because those
231
    // is one Script object.  There will be no vars or bindings, because those
222
    // go on the global, but there may be block-scoped locals, and the number of
232
    // go on the global, but there may be block-scoped locals, and the number of
223
    // block-scoped locals may increase as we parse more expressions.  This
233
    // block-scoped locals may increase as we parse more expressions.  This
224
    // helper updates the number of block scoped variables in a script as it is
234
    // helper updates the number of block scoped variables in a script as it is
225
    // being parsed.
235
    // being parsed.
226
    void updateNumBlockScoped(unsigned numBlockScoped) {
236
    void updateNumBlockScoped(unsigned numBlockScoped) {
 Lines 235-257   class Bindings Link Here 
235
245
236
    /*
246
    /*
237
     * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
247
     * Clone srcScript's bindings (as part of js::CloneScript). dstScriptData
238
     * is the pointer to what will eventually be dstScript->data.
248
     * is the pointer to what will eventually be dstScript->data.
239
     */
249
     */
240
    static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData,
250
    static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData,
241
                      HandleScript srcScript);
251
                      HandleScript srcScript);
242
252
243
    unsigned numArgs() const { return numArgs_; }
253
    uint32_t numArgs() const { return numArgs_; }
244
    uint32_t numVars() const { return numVars_; }
254
    uint32_t numVars() const { return numVars_; }
245
    unsigned numBlockScoped() const { return numBlockScoped_; }
255
    uint32_t numBodyLevelLets() const { return numBodyLevelLets_; }
246
    uint32_t numLocals() const { return numVars() + numBlockScoped(); }
256
    uint32_t numBlockScoped() const { return numBlockScoped_; }
257
    uint32_t numBodyLevelLocals() const { return numVars_ + numBodyLevelLets_; }
258
    uint32_t numLocals() const { return numVars() + numBodyLevelLets() + numBlockScoped(); }
259
    uint32_t aliasedBodyLevelLetStart() const { return aliasedBodyLevelLetStart_; }
247
260
248
    // Return the size of the bindingArray.
261
    // Return the size of the bindingArray.
249
    uint32_t count() const { return numArgs() + numVars(); }
262
    uint32_t count() const { return numArgs() + numVars() + numBodyLevelLets(); }
250
263
251
    /* Return the initial shape of call objects created for this scope. */
264
    /* Return the initial shape of call objects created for this scope. */
252
    Shape *callObjShape() const { return callObjShape_; }
265
    Shape *callObjShape() const { return callObjShape_; }
253
266
254
    /* Convenience method to get the var index of 'arguments'. */
267
    /* Convenience method to get the var index of 'arguments'. */
255
    static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
268
    static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
256
269
257
    /* Return whether the binding at bindingIndex is aliased. */
270
    /* Return whether the binding at bindingIndex is aliased. */
 Lines 1030-1050   class JSScript : public js::gc::BarrieredCell<JSScript> Link Here 
1030
    void setColumn(size_t column) { column_ = column; }
1043
    void setColumn(size_t column) { column_ = column; }
1031
1044
1032
    // The fixed part of a stack frame is comprised of vars (in function code)
1045
    // The fixed part of a stack frame is comprised of vars (in function code)
1033
    // and block-scoped locals (in all kinds of code).
1046
    // and block-scoped locals (in all kinds of code).
1034
    size_t nfixed() const {
1047
    size_t nfixed() const {
1035
        return function_ ? bindings.numLocals() : bindings.numBlockScoped();
1048
        return function_ ? bindings.numLocals() : bindings.numBlockScoped();
1036
    }
1049
    }
1037
1050
1038
    // Number of fixed slots reserved for vars.  Only nonzero for function code.
1051
    // Number of fixed slots reserved for vars.  Only nonzero for function
1052
    // code.
1039
    size_t nfixedvars() const {
1053
    size_t nfixedvars() const {
1040
        return function_ ? bindings.numVars() : 0;
1054
        return function_ ? bindings.numVars() : 0;
1041
    }
1055
    }
1042
1056
1057
    // Number of fixed slots reserved for body-level lets and vars. This value
1058
    // minus nfixedvars() is the number of body-level lets. Only nonzero for
1059
    // function code.
1060
    size_t nbodyfixed() const {
1061
        return function_ ? bindings.numBodyLevelLocals() : 0;
1062
    }
1063
1064
    // Aliases for clarity when dealing with let slots.
1065
    size_t fixedLetBegin() const {
1066
        return nfixedvars();
1067
    }
1068
1069
    size_t fixedLetEnd() const {
1070
        return nfixed();
1071
    }
1072
1043
    size_t nslots() const {
1073
    size_t nslots() const {
1044
        return nslots_;
1074
        return nslots_;
1045
    }
1075
    }
1046
1076
1047
    size_t staticLevel() const {
1077
    size_t staticLevel() const {
1048
        return staticLevel_;
1078
        return staticLevel_;
1049
    }
1079
    }
1050
1080
 Lines 1547-1562   class JSScript : public js::gc::BarrieredCell<JSScript> Link Here 
1547
1577
1548
        jsbytecode *pc = code();
1578
        jsbytecode *pc = code();
1549
        if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
1579
        if (noScriptRval() && JSOp(*pc) == JSOP_FALSE)
1550
            ++pc;
1580
            ++pc;
1551
        return JSOp(*pc) == JSOP_RETRVAL;
1581
        return JSOp(*pc) == JSOP_RETRVAL;
1552
    }
1582
    }
1553
1583
1554
    bool varIsAliased(uint32_t varSlot);
1584
    bool varIsAliased(uint32_t varSlot);
1585
    bool bodyLevelLocalIsAliased(uint32_t localSlot);
1555
    bool formalIsAliased(unsigned argSlot);
1586
    bool formalIsAliased(unsigned argSlot);
1556
    bool formalLivesInArgumentsObject(unsigned argSlot);
1587
    bool formalLivesInArgumentsObject(unsigned argSlot);
1557
1588
1558
  private:
1589
  private:
1559
    /* Change this->stepMode to |newValue|. */
1590
    /* Change this->stepMode to |newValue|. */
1560
    void setNewStepMode(js::FreeOp *fop, uint32_t newValue);
1591
    void setNewStepMode(js::FreeOp *fop, uint32_t newValue);
1561
1592
1562
    bool ensureHasDebugScript(JSContext *cx);
1593
    bool ensureHasDebugScript(JSContext *cx);
 Lines 1685-1700   class AliasedFormalIter Link Here 
1685
    unsigned frameIndex() const { JS_ASSERT(!done()); return p_ - begin_; }
1716
    unsigned frameIndex() const { JS_ASSERT(!done()); return p_ - begin_; }
1686
    unsigned scopeSlot() const { JS_ASSERT(!done()); return slot_; }
1717
    unsigned scopeSlot() const { JS_ASSERT(!done()); return slot_; }
1687
};
1718
};
1688
1719
1689
// Information about a script which may be (or has been) lazily compiled to
1720
// Information about a script which may be (or has been) lazily compiled to
1690
// bytecode from its source.
1721
// bytecode from its source.
1691
class LazyScript : public gc::BarrieredCell<LazyScript>
1722
class LazyScript : public gc::BarrieredCell<LazyScript>
1692
{
1723
{
1724
  public:
1725
    class FreeVariable
1726
    {
1727
        // Free variable names are possible tagged JSAtom *s.
1728
        uintptr_t bits_;
1729
1730
        static const uintptr_t HOISTED_USE_BIT = 0x1;
1731
        static const uintptr_t MASK = ~HOISTED_USE_BIT;
1732
1733
      public:
1734
        explicit FreeVariable()
1735
          : bits_(0)
1736
        { }
1737
1738
        explicit FreeVariable(JSAtom *name)
1739
          : bits_(uintptr_t(name))
1740
        {
1741
            // We rely on not requiring any write barriers so we can tag the
1742
            // pointer. This code needs to change if we start allocating
1743
            // JSAtoms inside the nursery.
1744
            MOZ_ASSERT(!IsInsideNursery(name));
1745
        }
1746
1747
        JSAtom *atom() const { return (JSAtom *)(bits_ & MASK); }
1748
        void setIsHoistedUse() { bits_ |= HOISTED_USE_BIT; }
1749
        bool isHoistedUse() const { return bool(bits_ & HOISTED_USE_BIT); }
1750
    };
1751
1752
  private:
1693
    // If non-nullptr, the script has been compiled and this is a forwarding
1753
    // If non-nullptr, the script has been compiled and this is a forwarding
1694
    // pointer to the result.
1754
    // pointer to the result.
1695
    HeapPtrScript script_;
1755
    HeapPtrScript script_;
1696
1756
1697
    // Original function with which the lazy script is associated.
1757
    // Original function with which the lazy script is associated.
1698
    HeapPtrFunction function_;
1758
    HeapPtrFunction function_;
1699
1759
1700
    // Function or block chain in which the script is nested, or nullptr.
1760
    // Function or block chain in which the script is nested, or nullptr.
 Lines 1796-1813   class LazyScript : public gc::BarrieredCell<LazyScript> Link Here 
1796
        return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
1856
        return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
1797
    }
1857
    }
1798
1858
1799
    void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject);
1859
    void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject);
1800
1860
1801
    uint32_t numFreeVariables() const {
1861
    uint32_t numFreeVariables() const {
1802
        return p_.numFreeVariables;
1862
        return p_.numFreeVariables;
1803
    }
1863
    }
1804
    HeapPtrAtom *freeVariables() {
1864
    FreeVariable *freeVariables() {
1805
        return (HeapPtrAtom *)table_;
1865
        return (FreeVariable *)table_;
1806
    }
1866
    }
1807
1867
1808
    uint32_t numInnerFunctions() const {
1868
    uint32_t numInnerFunctions() const {
1809
        return p_.numInnerFunctions;
1869
        return p_.numInnerFunctions;
1810
    }
1870
    }
1811
    HeapPtrFunction *innerFunctions() {
1871
    HeapPtrFunction *innerFunctions() {
1812
        return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
1872
        return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
1813
    }
1873
    }
(-)a/js/src/tests/js1_7/block/order-of-operation.js (-1 / +2 lines)
Line     Link Here 
 Lines 80-107   function f6() { Link Here 
80
    var i=3;
80
    var i=3;
81
    for (let i=i;;) { if (i != 3) throw "f6(): fail 1"; i = 7; break; }
81
    for (let i=i;;) { if (i != 3) throw "f6(): fail 1"; i = 7; break; }
82
    if (i != 3) throw "f6(): fail 2";
82
    if (i != 3) throw "f6(): fail 2";
83
  }
83
  }
84
}
84
}
85
85
86
try
86
try
87
{
87
{
88
/*
88
  var rv = f1(5);
89
  var rv = f1(5);
89
  if (!isNaN(rv))
90
  if (!isNaN(rv))
90
    throw "f1(5):\n" +
91
    throw "f1(5):\n" +
91
      "  expected:  NaN\n" +
92
      "  expected:  NaN\n" +
92
      "  actual:    " + rv;
93
      "  actual:    " + rv;
93
94
94
  rv = f2(5);
95
  rv = f2(5);
95
  if (!isNaN(rv))
96
  if (!isNaN(rv))
96
    throw "f2(5):\n" +
97
    throw "f2(5):\n" +
97
      "  expected:  NaN\n" +
98
      "  expected:  NaN\n" +
98
      "  actual:    " + rv;
99
      "  actual:    " + rv;
99
/*
100
100
  rv = f3(8);
101
  rv = f3(8);
101
  if (rv != 9)
102
  if (rv != 9)
102
  throw "f3(8):\n" +
103
  throw "f3(8):\n" +
103
  "  expected:  9\n" +
104
  "  expected:  9\n" +
104
  "  actual:    " + rv;
105
  "  actual:    " + rv;
105
*/
106
*/
106
107
107
  rv = f4(13);
108
  rv = f4(13);
(-)a/js/src/tests/js1_7/block/regress-411279.js (-56 lines)
Line     Link Here 
 Lines 1-56    Link Here 
1
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
//-----------------------------------------------------------------------------
7
var BUGNUMBER = 411279;
8
var summary = 'let declaration as direct child of switch body block';
9
var actual = 'No Crash';
10
var expect = 'No Crash';
11
12
13
//-----------------------------------------------------------------------------
14
test();
15
//-----------------------------------------------------------------------------
16
17
function test()
18
{
19
  enterFunc ('test');
20
  printBugNumber(BUGNUMBER);
21
  printStatus (summary);
22
23
  function f(x) 
24
  {
25
    var value = '';
26
27
    switch(x)
28
    {
29
    case 1:
30
      value = "1 " + y; 
31
      break; 
32
    case 2: 
33
      let y = 42;
34
      value = "2 " + y; 
35
      break; 
36
    default:
37
      value = "default " + y;
38
    }
39
40
    return value;
41
  }
42
43
  expect = '1 undefined';
44
  actual = f(1);
45
  reportCompare(expect, actual, summary + ': f(1)');
46
47
  expect = '2 42';
48
  actual = f(2);
49
  reportCompare(expect, actual, summary + ': f(2)');
50
51
  expect = 'default undefined';
52
  actual = f(3);
53
  reportCompare(expect, actual, summary + ': f(3)');
54
 
55
  exitFunc ('test');
56
}
(-)a/js/src/tests/js1_8_1/extensions/regress-353214-02.js (-2 / +2 lines)
Line     Link Here 
 Lines 15-30   test(); Link Here 
15
//-----------------------------------------------------------------------------
15
//-----------------------------------------------------------------------------
16
16
17
function test()
17
function test()
18
{
18
{
19
  enterFunc ('test');
19
  enterFunc ('test');
20
  printBugNumber(BUGNUMBER);
20
  printBugNumber(BUGNUMBER);
21
  printStatus (summary);
21
  printStatus (summary);
22
22
23
  var f = function ([x]) { let x; }
23
  var f = function ([x]) { let y; }
24
  expect = 'function ([x]) { let x; }';
24
  expect = 'function ([x]) { let y; }';
25
  actual = f + '';
25
  actual = f + '';
26
26
27
  compareSource(expect, actual, summary);
27
  compareSource(expect, actual, summary);
28
28
29
  exitFunc ('test');
29
  exitFunc ('test');
30
}
30
}
(-)a/js/src/tests/js1_8_1/regress/regress-452498-103.js (-31 lines)
Line     Link Here 
 Lines 1-31    Link Here 
1
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
//-----------------------------------------------------------------------------
7
var BUGNUMBER = 452498;
8
var summary = 'TM: upvar2 regression tests';
9
var actual = '';
10
var expect = '';
11
12
13
//-----------------------------------------------------------------------------
14
test();
15
//-----------------------------------------------------------------------------
16
17
function test()
18
{
19
  enterFunc ('test');
20
  printBugNumber(BUGNUMBER);
21
  printStatus (summary);
22
23
// ------- Comment #103 From Jesse Ruderman
24
25
  (function(a) { v = 5; let [v] = [3]; (function(){ v; })(); })();
26
// Assertion failure: !(pn->pn_dflags & flag), at ../jsparse.h:638
27
28
  reportCompare(expect, actual, summary);
29
30
  exitFunc ('test');
31
}
(-)a/js/src/vm/CommonPropertyNames.h (+1 lines)
Line     Link Here 
 Lines 180-195    Link Here 
180
    macro(toJSON, toJSON, "toJSON") \
180
    macro(toJSON, toJSON, "toJSON") \
181
    macro(toLocaleString, toLocaleString, "toLocaleString") \
181
    macro(toLocaleString, toLocaleString, "toLocaleString") \
182
    macro(toSource, toSource, "toSource") \
182
    macro(toSource, toSource, "toSource") \
183
    macro(toString, toString, "toString") \
183
    macro(toString, toString, "toString") \
184
    macro(toUTCString, toUTCString, "toUTCString") \
184
    macro(toUTCString, toUTCString, "toUTCString") \
185
    macro(true, true_, "true") \
185
    macro(true, true_, "true") \
186
    macro(unescape, unescape, "unescape") \
186
    macro(unescape, unescape, "unescape") \
187
    macro(uneval, uneval, "uneval") \
187
    macro(uneval, uneval, "uneval") \
188
    macro(uninitialized, uninitialized, "uninitialized") \
188
    macro(uint8, uint8, "uint8") \
189
    macro(uint8, uint8, "uint8") \
189
    macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
190
    macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
190
    macro(uint16, uint16, "uint16") \
191
    macro(uint16, uint16, "uint16") \
191
    macro(uint32, uint32, "uint32") \
192
    macro(uint32, uint32, "uint32") \
192
    macro(unsized, unsized, "unsized") \
193
    macro(unsized, unsized, "unsized") \
193
    macro(unwatch, unwatch, "unwatch") \
194
    macro(unwatch, unwatch, "unwatch") \
194
    macro(url, url, "url") \
195
    macro(url, url, "url") \
195
    macro(usage, usage, "usage") \
196
    macro(usage, usage, "usage") \
(-)a/js/src/vm/Debugger.cpp (-7 / +9 lines)
Line     Link Here 
 Lines 720-744   Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp) Link Here 
720
720
721
            vp.setObject(*dobj);
721
            vp.setObject(*dobj);
722
        }
722
        }
723
    } else if (vp.isMagic()) {
723
    } else if (vp.isMagic()) {
724
        RootedObject optObj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
724
        RootedObject optObj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
725
        if (!optObj)
725
        if (!optObj)
726
            return false;
726
            return false;
727
727
728
        // We handle two sentinel values: missing arguments (overloading
728
        // We handle three sentinel values: missing arguments (overloading
729
        // JS_OPTIMIZED_ARGUMENTS) and optimized out slots (JS_OPTIMIZED_OUT).
729
        // JS_OPTIMIZED_ARGUMENTS), optimized out slots (JS_OPTIMIZED_OUT),
730
        // and uninitialized bindings (JS_UNINITIALIZED_LET).
731
        //
730
        // Other magic values should not have escaped.
732
        // Other magic values should not have escaped.
731
        PropertyName *name;
733
        PropertyName *name;
732
        if (vp.whyMagic() == JS_OPTIMIZED_ARGUMENTS) {
734
        switch (vp.whyMagic()) {
733
            name = cx->names().missingArguments;
735
          case JS_OPTIMIZED_ARGUMENTS: name = cx->names().missingArguments; break;
734
        } else {
736
          case JS_OPTIMIZED_OUT:       name = cx->names().optimizedOut; break;
735
            MOZ_ASSERT(vp.whyMagic() == JS_OPTIMIZED_OUT);
737
          case JS_UNINITIALIZED_LET:   name = cx->names().uninitialized; break;
736
            name = cx->names().optimizedOut;
738
          default: MOZ_CRASH("Unsupported magic value escaped to Debugger");
737
        }
739
        }
738
740
739
        RootedValue trueVal(cx, BooleanValue(true));
741
        RootedValue trueVal(cx, BooleanValue(true));
740
        if (!JSObject::defineProperty(cx, optObj, name, trueVal))
742
        if (!JSObject::defineProperty(cx, optObj, name, trueVal))
741
            return false;
743
            return false;
742
744
743
        vp.setObject(*optObj);
745
        vp.setObject(*optObj);
744
    } else if (!cx->compartment()->wrap(cx, vp)) {
746
    } else if (!cx->compartment()->wrap(cx, vp)) {
(-)a/js/src/vm/Debugger.h (+4 lines)
Line     Link Here 
 Lines 503-518   class Debugger : private mozilla::LinkedListElement<Debugger> Link Here 
503
     * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
503
     * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
504
     *
504
     *
505
     * If *vp is a magic JS_OPTIMIZED_OUT value, this produces a plain object
505
     * If *vp is a magic JS_OPTIMIZED_OUT value, this produces a plain object
506
     * of the form { optimizedOut: true }.
506
     * of the form { optimizedOut: true }.
507
     *
507
     *
508
     * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing
508
     * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing
509
     * arguments, this produces a plain object of the form { missingArguments:
509
     * arguments, this produces a plain object of the form { missingArguments:
510
     * true }.
510
     * true }.
511
     *
512
     * If *vp is a magic JS_UNINITIALIZED_LET value signifying an unaccessible
513
     * uninitialized binding, this produces a plain object of the form
514
     * { uninitialized: true }.
511
     */
515
     */
512
    bool wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp);
516
    bool wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp);
513
517
514
    /*
518
    /*
515
     * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
519
     * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
516
     * compartment.
520
     * compartment.
517
     *
521
     *
518
     * Preconditions: cx is in the debugger compartment. *vp is a value in that
522
     * Preconditions: cx is in the debugger compartment. *vp is a value in that
(-)a/js/src/vm/Interpreter-inl.h (+62 lines)
Line     Link Here 
 Lines 17-32    Link Here 
17
#include "jit/Ion.h"
17
#include "jit/Ion.h"
18
#include "vm/ArgumentsObject.h"
18
#include "vm/ArgumentsObject.h"
19
#include "vm/ForkJoin.h"
19
#include "vm/ForkJoin.h"
20
20
21
#include "jsatominlines.h"
21
#include "jsatominlines.h"
22
#include "jsinferinlines.h"
22
#include "jsinferinlines.h"
23
#include "jsobjinlines.h"
23
#include "jsobjinlines.h"
24
24
25
#include "vm/ScopeObject-inl.h"
25
#include "vm/Stack-inl.h"
26
#include "vm/Stack-inl.h"
26
#include "vm/String-inl.h"
27
#include "vm/String-inl.h"
27
28
28
namespace js {
29
namespace js {
29
30
30
inline bool
31
inline bool
31
ComputeThis(JSContext *cx, AbstractFramePtr frame)
32
ComputeThis(JSContext *cx, AbstractFramePtr frame)
32
{
33
{
 Lines 102-117   GuardFunApplyArgumentsOptimization(JSContext *cx, AbstractFramePtr frame, Handle Link Here 
102
            args[1] = ObjectValue(frame.argsObj());
103
            args[1] = ObjectValue(frame.argsObj());
103
        }
104
        }
104
    }
105
    }
105
106
106
    return true;
107
    return true;
107
}
108
}
108
109
109
/*
110
/*
111
 * Per ES6, 'let' declarations may not be accessed in any fashion until they
112
 * are initialized (i.e., until the actual declaring statement is
113
 * executed). The various LET opcodes need to check if the slot is an
114
 * uninitialized let declaration, represented by the magic value
115
 * JS_UNINITIALIZED_LET.
116
 */
117
static inline bool
118
IsUninitializedLet(const Value &val)
119
{
120
    // Use whyMagic here because JS_OPTIMIZED_ARGUMENTS could flow into here.
121
    return val.isMagic() && val.whyMagic() == JS_UNINITIALIZED_LET;
122
}
123
124
static inline bool
125
IsUninitializedLetSlot(HandleObject obj, HandleShape shape)
126
{
127
    if (obj->is<DynamicWithObject>())
128
        return false;
129
    if (!shape || IsImplicitDenseOrTypedArrayElement(shape) || !shape->hasSlot())
130
        return false;
131
    return IsUninitializedLet(obj->nativeGetSlot(shape->slot()));
132
}
133
134
static inline bool
135
CheckUninitializedLet(JSContext *cx, PropertyName *name_, HandleValue val)
136
{
137
    if (IsUninitializedLet(val)) {
138
        RootedPropertyName name(cx, name_);
139
        ReportUninitializedLet(cx, name);
140
        return false;
141
    }
142
    return true;
143
}
144
145
static inline bool
146
CheckUninitializedLet(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue val)
147
{
148
    if (IsUninitializedLet(val)) {
149
        ReportUninitializedLet(cx, script, pc);
150
        return false;
151
    }
152
    return true;
153
}
154
155
/*
110
 * Return an object on which we should look for the properties of |value|.
156
 * Return an object on which we should look for the properties of |value|.
111
 * This helps us implement the custom [[Get]] method that ES5's GetValue
157
 * This helps us implement the custom [[Get]] method that ES5's GetValue
112
 * algorithm uses for primitive values, without actually constructing the
158
 * algorithm uses for primitive values, without actually constructing the
113
 * temporary object that the specification does.
159
 * temporary object that the specification does.
114
 *
160
 *
115
 * For objects, return the object itself. For string, boolean, and number
161
 * For objects, return the object itself. For string, boolean, and number
116
 * primitive values, return the appropriate constructor's prototype. For
162
 * primitive values, return the appropriate constructor's prototype. For
117
 * undefined and null, throw an error and return nullptr, attributing the
163
 * undefined and null, throw an error and return nullptr, attributing the
 Lines 220-235   GetIntrinsicOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp) Link Here 
220
266
221
inline bool
267
inline bool
222
SetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleValue val)
268
SetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleValue val)
223
{
269
{
224
    RootedPropertyName name(cx, script->getName(pc));
270
    RootedPropertyName name(cx, script->getName(pc));
225
    return cx->global()->setIntrinsicValue(cx, name, val);
271
    return cx->global()->setIntrinsicValue(cx, name, val);
226
}
272
}
227
273
274
inline void
275
SetAliasedVarOperation(JSContext *cx, JSScript *script, jsbytecode *pc,
276
                       ScopeObject &obj, ScopeCoordinate sc, const Value &val,
277
                       bool checkUninitializedLet)
278
{
279
    MOZ_ASSERT_IF(checkUninitializedLet, !IsUninitializedLet(obj.aliasedVar(sc)));
280
281
    // Avoid computing the name if no type updates are needed, as this may be
282
    // expensive on scopes with large numbers of variables.
283
    PropertyName *name = (obj.hasSingletonType() && !obj.hasLazyType())
284
                         ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc)
285
                         : nullptr;
286
287
    obj.setAliasedVar(cx, sc, name, val);
288
}
289
228
inline bool
290
inline bool
229
SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject scope,
291
SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject scope,
230
                 HandleValue val)
292
                 HandleValue val)
231
{
293
{
232
    JS_ASSERT(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME);
294
    JS_ASSERT(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME);
233
    JS_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
295
    JS_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
234
296
235
    bool strict = script->strict();
297
    bool strict = script->strict();
(-)a/js/src/vm/Interpreter.cpp (-40 / +195 lines)
Line     Link Here 
 Lines 281-311   NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle Link Here 
281
     */
281
     */
282
    if (IsGlobalOp(JSOp(*pc)))
282
    if (IsGlobalOp(JSOp(*pc)))
283
        obj = &obj->global();
283
        obj = &obj->global();
284
284
285
    Shape *shape = nullptr;
285
    Shape *shape = nullptr;
286
    JSObject *scope = nullptr, *pobj = nullptr;
286
    JSObject *scope = nullptr, *pobj = nullptr;
287
    if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) {
287
    if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) {
288
        if (FetchNameNoGC(pobj, shape, vp))
288
        if (FetchNameNoGC(pobj, shape, vp))
289
            return true;
289
            return CheckUninitializedLet(cx, name, vp);
290
    }
290
    }
291
291
292
    RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx);
292
    RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx);
293
    RootedPropertyName nameRoot(cx, name);
293
    RootedPropertyName nameRoot(cx, name);
294
    RootedShape shapeRoot(cx);
294
    RootedShape shapeRoot(cx);
295
295
296
    if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot))
296
    if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot))
297
        return false;
297
        return false;
298
298
299
    /* Kludge to allow (typeof foo == "undefined") tests. */
299
    /* Kludge to allow (typeof foo == "undefined") tests. */
300
    JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
300
    JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
301
    if (op2 == JSOP_TYPEOF)
301
    if (op2 == JSOP_TYPEOF) {
302
        return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
302
        if (!FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
303
    return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
303
            return false;
304
    } else {
305
        if (!FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp))
306
            return false;
307
    }
308
309
    // NAME operations are the slow paths already, so unconditionally check
310
    // for uninitialized lets.
311
    return CheckUninitializedLet(cx, nameRoot, vp);
304
}
312
}
305
313
306
static inline bool
314
static inline bool
307
SetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lval,
315
SetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lval,
308
                     HandleValue rval)
316
                     HandleValue rval)
309
{
317
{
310
    JS_ASSERT(*pc == JSOP_SETPROP);
318
    JS_ASSERT(*pc == JSOP_SETPROP);
311
319
 Lines 835-882   js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, Link Here 
835
    DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, staticWith);
843
    DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, staticWith);
836
    if (!withobj)
844
    if (!withobj)
837
        return false;
845
        return false;
838
846
839
    frame.pushOnScopeChain(*withobj);
847
    frame.pushOnScopeChain(*withobj);
840
    return true;
848
    return true;
841
}
849
}
842
850
851
static void
852
PopScope(JSContext *cx, ScopeIter &si)
853
{
854
    switch (si.type()) {
855
      case ScopeIter::Block:
856
        if (cx->compartment()->debugMode())
857
            DebugScopes::onPopBlock(cx, si);
858
        if (si.staticBlock().needsClone())
859
            si.frame().popBlock(cx);
860
        break;
861
      case ScopeIter::With:
862
        si.frame().popWith(cx);
863
        break;
864
      case ScopeIter::Call:
865
      case ScopeIter::StrictEvalScope:
866
        break;
867
    }
868
}
869
843
// Unwind scope chain and iterator to match the static scope corresponding to
870
// Unwind scope chain and iterator to match the static scope corresponding to
844
// the given bytecode position.
871
// the given bytecode position.
845
void
872
void
846
js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc)
873
js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc)
847
{
874
{
848
    if (si.done())
875
    if (si.done())
849
        return;
876
        return;
850
877
851
    Rooted<NestedScopeObject *> staticScope(cx, si.frame().script()->getStaticScope(pc));
878
    Rooted<NestedScopeObject *> staticScope(cx, si.frame().script()->getStaticScope(pc));
852
879
853
    for (; si.staticScope() != staticScope; ++si) {
880
    for (; si.staticScope() != staticScope; ++si)
854
        switch (si.type()) {
881
        PopScope(cx, si);
855
          case ScopeIter::Block:
882
}
856
            if (cx->compartment()->debugMode())
883
857
                DebugScopes::onPopBlock(cx, si);
884
// Unwind all scopes. This is needed because block scopes may cover the
858
            if (si.staticBlock().needsClone())
885
// first bytecode at a script's main(). e.g.,
859
                si.frame().popBlock(cx);
886
//
860
            break;
887
//     function f() { { let i = 0; } }
861
          case ScopeIter::With:
888
//
862
            si.frame().popWith(cx);
889
// will have no pc location distinguishing the first block scope from the
863
            break;
890
// outermost function scope.
864
          case ScopeIter::Call:
891
void
865
          case ScopeIter::StrictEvalScope:
892
js::UnwindAllScopes(JSContext *cx, ScopeIter &si)
866
            break;
893
{
867
        }
894
    for (; !si.done(); ++si)
868
    }
895
        PopScope(cx, si);
896
}
897
898
// Compute the pc needed to unwind the scope to the beginning of a try
899
// block. We cannot unwind to *after* the JSOP_TRY, because that might be the
900
// first opcode of an inner scope, with the same problem as above. e.g.,
901
//
902
// try { { let x; } }
903
//
904
// will have no pc location distinguishing the try block scope from the inner
905
// let block scope.
906
jsbytecode *
907
js::UnwindScopeToTryPc(JSScript *script, JSTryNote *tn)
908
{
909
    return script->main() + tn->start - js_CodeSpec[JSOP_TRY].length;
869
}
910
}
870
911
871
static void
912
static void
872
ForcedReturn(JSContext *cx, ScopeIter &si, InterpreterRegs &regs)
913
ForcedReturn(JSContext *cx, ScopeIter &si, InterpreterRegs &regs)
873
{
914
{
874
    UnwindScope(cx, si, regs.fp()->script()->main());
915
    UnwindAllScopes(cx, si);
875
    regs.setToEndOfScript();
916
    regs.setToEndOfScript();
876
}
917
}
877
918
878
static void
919
static void
879
ForcedReturn(JSContext *cx, InterpreterRegs &regs)
920
ForcedReturn(JSContext *cx, InterpreterRegs &regs)
880
{
921
{
881
    ScopeIter si(regs.fp(), regs.pc, cx);
922
    ScopeIter si(regs.fp(), regs.pc, cx);
882
    ForcedReturn(cx, si, regs);
923
    ForcedReturn(cx, si, regs);
 Lines 991-1007   HandleError(JSContext *cx, InterpreterRegs &regs) Link Here 
991
                MOZ_CRASH("Invalid trap status");
1032
                MOZ_CRASH("Invalid trap status");
992
            }
1033
            }
993
        }
1034
        }
994
1035
995
        RootedValue exception(cx);
1036
        RootedValue exception(cx);
996
        for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
1037
        for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
997
            JSTryNote *tn = *tni;
1038
            JSTryNote *tn = *tni;
998
1039
999
            UnwindScope(cx, si, regs.fp()->script()->main() + tn->start);
1040
            // Unwind the scope to the beginning of the JSOP_TRY.
1041
            UnwindScope(cx, si, UnwindScopeToTryPc(regs.fp()->script(), tn));
1000
1042
1001
            /*
1043
            /*
1002
             * Set pc to the first bytecode after the the try note to point
1044
             * Set pc to the first bytecode after the the try note to point
1003
             * to the beginning of catch or finally or to [enditer] closing
1045
             * to the beginning of catch or finally or to [enditer] closing
1004
             * the for-in loop.
1046
             * the for-in loop.
1005
             */
1047
             */
1006
            regs.pc = regs.fp()->script()->main() + tn->start + tn->length;
1048
            regs.pc = regs.fp()->script()->main() + tn->start + tn->length;
1007
            regs.sp = regs.spForStackDepth(tn->stackDepth);
1049
            regs.sp = regs.spForStackDepth(tn->stackDepth);
 Lines 1599-1618   CASE(JSOP_UNUSED83) Link Here 
1599
CASE(JSOP_UNUSED102)
1641
CASE(JSOP_UNUSED102)
1600
CASE(JSOP_UNUSED103)
1642
CASE(JSOP_UNUSED103)
1601
CASE(JSOP_UNUSED104)
1643
CASE(JSOP_UNUSED104)
1602
CASE(JSOP_UNUSED105)
1644
CASE(JSOP_UNUSED105)
1603
CASE(JSOP_UNUSED107)
1645
CASE(JSOP_UNUSED107)
1604
CASE(JSOP_UNUSED124)
1646
CASE(JSOP_UNUSED124)
1605
CASE(JSOP_UNUSED125)
1647
CASE(JSOP_UNUSED125)
1606
CASE(JSOP_UNUSED126)
1648
CASE(JSOP_UNUSED126)
1607
CASE(JSOP_UNUSED138)
1608
CASE(JSOP_UNUSED139)
1609
CASE(JSOP_UNUSED140)
1610
CASE(JSOP_UNUSED141)
1611
CASE(JSOP_UNUSED142)
1649
CASE(JSOP_UNUSED142)
1612
CASE(JSOP_UNUSED146)
1650
CASE(JSOP_UNUSED146)
1613
CASE(JSOP_UNUSED147)
1651
CASE(JSOP_UNUSED147)
1614
CASE(JSOP_UNUSED148)
1652
CASE(JSOP_UNUSED148)
1615
CASE(JSOP_BACKPATCH)
1653
CASE(JSOP_BACKPATCH)
1616
CASE(JSOP_UNUSED150)
1654
CASE(JSOP_UNUSED150)
1617
CASE(JSOP_UNUSED156)
1655
CASE(JSOP_UNUSED156)
1618
CASE(JSOP_UNUSED157)
1656
CASE(JSOP_UNUSED157)
 Lines 2008-2027   CASE(JSOP_BINDNAME) Link Here 
2008
    RootedObject &scopeChain = rootObject0;
2046
    RootedObject &scopeChain = rootObject0;
2009
    scopeChain = REGS.fp()->scopeChain();
2047
    scopeChain = REGS.fp()->scopeChain();
2010
2048
2011
    RootedPropertyName &name = rootName0;
2049
    RootedPropertyName &name = rootName0;
2012
    name = script->getName(REGS.pc);
2050
    name = script->getName(REGS.pc);
2013
2051
2014
    /* Assigning to an undeclared name adds a property to the global object. */
2052
    /* Assigning to an undeclared name adds a property to the global object. */
2015
    RootedObject &scope = rootObject1;
2053
    RootedObject &scope = rootObject1;
2016
    if (!LookupNameUnqualified(cx, name, scopeChain, &scope))
2054
    RootedShape &shape = rootShape0;
2055
    if (!LookupNameUnqualified(cx, name, scopeChain, &scope, &shape))
2017
        goto error;
2056
        goto error;
2018
2057
2019
    PUSH_OBJECT(*scope);
2058
    // ES6 lets cannot be accessed until initialized. NAME operations, being
2059
    // the slow paths already, unconditionally check for uninitialized
2060
    // lets. The error, however, is thrown after evaluating the RHS in
2061
    // assignments. Thus if the LHS resolves to an uninitialized let, return a
2062
    // nullptr scope.
2063
    if (IsUninitializedLetSlot(scope, shape))
2064
        PUSH_NULL();
2065
    else
2066
        PUSH_OBJECT(*scope);
2020
}
2067
}
2021
END_CASE(JSOP_BINDNAME)
2068
END_CASE(JSOP_BINDNAME)
2022
2069
2023
#define BITWISE_OP(OP)                                                        \
2070
#define BITWISE_OP(OP)                                                        \
2024
    JS_BEGIN_MACRO                                                            \
2071
    JS_BEGIN_MACRO                                                            \
2025
        int32_t i, j;                                                         \
2072
        int32_t i, j;                                                         \
2026
        if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))                         \
2073
        if (!ToInt32(cx, REGS.stackHandleAt(-2), &i))                         \
2027
            goto error;                                                       \
2074
            goto error;                                                       \
 Lines 2397-2413   CASE(JSOP_SETINTRINSIC) Link Here 
2397
    REGS.sp--;
2444
    REGS.sp--;
2398
}
2445
}
2399
END_CASE(JSOP_SETINTRINSIC)
2446
END_CASE(JSOP_SETINTRINSIC)
2400
2447
2401
CASE(JSOP_SETGNAME)
2448
CASE(JSOP_SETGNAME)
2402
CASE(JSOP_SETNAME)
2449
CASE(JSOP_SETNAME)
2403
{
2450
{
2404
    RootedObject &scope = rootObject0;
2451
    RootedObject &scope = rootObject0;
2405
    scope = &REGS.sp[-2].toObject();
2452
    scope = REGS.sp[-2].toObjectOrNull();
2453
2454
    // A nullptr scope is pushed if the name is an uninitialized let. See
2455
    // CASE(JSOP_BINDNAME).
2456
    if (!scope) {
2457
        RootedPropertyName &name = rootName0;
2458
        name = script->getName(REGS.pc);
2459
        ReportUninitializedLet(cx, name);
2460
        goto error;
2461
    }
2406
2462
2407
    HandleValue value = REGS.stackHandleAt(-1);
2463
    HandleValue value = REGS.stackHandleAt(-1);
2408
2464
2409
    if (!SetNameOperation(cx, script, REGS.pc, scope, value))
2465
    if (!SetNameOperation(cx, script, REGS.pc, scope, value))
2410
        goto error;
2466
        goto error;
2411
2467
2412
    REGS.sp[-2] = REGS.sp[-1];
2468
    REGS.sp[-2] = REGS.sp[-1];
2413
    REGS.sp--;
2469
    REGS.sp--;
 Lines 2635-2651   CASE(JSOP_IMPLICITTHIS) Link Here 
2635
{
2691
{
2636
    RootedPropertyName &name = rootName0;
2692
    RootedPropertyName &name = rootName0;
2637
    name = script->getName(REGS.pc);
2693
    name = script->getName(REGS.pc);
2638
2694
2639
    RootedObject &scopeObj = rootObject0;
2695
    RootedObject &scopeObj = rootObject0;
2640
    scopeObj = REGS.fp()->scopeChain();
2696
    scopeObj = REGS.fp()->scopeChain();
2641
2697
2642
    RootedObject &scope = rootObject1;
2698
    RootedObject &scope = rootObject1;
2643
    if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope))
2699
    RootedShape &shape = rootShape0;
2700
    if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope, &shape))
2644
        goto error;
2701
        goto error;
2645
2702
2646
    RootedValue &v = rootValue0;
2703
    RootedValue &v = rootValue0;
2647
    if (!ComputeImplicitThis(cx, scope, &v))
2704
    if (!ComputeImplicitThis(cx, scope, &v))
2648
        goto error;
2705
        goto error;
2649
    PUSH_COPY(v);
2706
    PUSH_COPY(v);
2650
}
2707
}
2651
END_CASE(JSOP_IMPLICITTHIS)
2708
END_CASE(JSOP_IMPLICITTHIS)
 Lines 2846-2881   CASE(JSOP_REST) Link Here 
2846
        goto error;
2903
        goto error;
2847
    PUSH_COPY(ObjectValue(*rest));
2904
    PUSH_COPY(ObjectValue(*rest));
2848
}
2905
}
2849
END_CASE(JSOP_REST)
2906
END_CASE(JSOP_REST)
2850
2907
2851
CASE(JSOP_GETALIASEDVAR)
2908
CASE(JSOP_GETALIASEDVAR)
2852
{
2909
{
2853
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2910
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2854
    PUSH_COPY(REGS.fp()->aliasedVarScope(sc).aliasedVar(sc));
2911
    RootedValue &val = rootValue0;
2912
    val = REGS.fp()->aliasedVarScope(sc).aliasedVar(sc);
2913
    MOZ_ASSERT(!IsUninitializedLet(val));
2914
    PUSH_COPY(val);
2855
    TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
2915
    TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
2856
}
2916
}
2857
END_CASE(JSOP_GETALIASEDVAR)
2917
END_CASE(JSOP_GETALIASEDVAR)
2858
2918
2859
CASE(JSOP_SETALIASEDVAR)
2919
CASE(JSOP_SETALIASEDVAR)
2860
{
2920
{
2861
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2921
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2862
    ScopeObject &obj = REGS.fp()->aliasedVarScope(sc);
2922
    ScopeObject &obj = REGS.fp()->aliasedVarScope(sc);
2863
2923
    SetAliasedVarOperation(cx, script, REGS.pc, obj, sc, REGS.sp[-1],
2864
    // Avoid computing the name if no type updates are needed, as this may be
2924
                           /* checkUninitializedLet = */ true);
2865
    // expensive on scopes with large numbers of variables.
2866
    PropertyName *name = (obj.hasSingletonType() && !obj.hasLazyType())
2867
                         ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, REGS.pc)
2868
                         : nullptr;
2869
2870
    obj.setAliasedVar(cx, sc, name, REGS.sp[-1]);
2871
}
2925
}
2872
END_CASE(JSOP_SETALIASEDVAR)
2926
END_CASE(JSOP_SETALIASEDVAR)
2873
2927
2928
CASE(JSOP_CHECKLET)
2929
{
2930
    uint32_t i = GET_LOCALNO(REGS.pc);
2931
    RootedValue &val = rootValue0;
2932
    val = REGS.fp()->unaliasedLocal(i);
2933
    if (!CheckUninitializedLet(cx, script, REGS.pc, val))
2934
        goto error;
2935
}
2936
END_CASE(JSOP_CHECKLET)
2937
2938
CASE(JSOP_INITLET)
2939
{
2940
    uint32_t i = GET_LOCALNO(REGS.pc);
2941
    REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
2942
}
2943
END_CASE(JSOP_INITLET)
2944
2945
CASE(JSOP_CHECKALIASEDLET)
2946
{
2947
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2948
    RootedValue &val = rootValue0;
2949
    val = REGS.fp()->aliasedVarScope(sc).aliasedVar(sc);
2950
    if (!CheckUninitializedLet(cx, script, REGS.pc, val))
2951
        goto error;
2952
}
2953
END_CASE(JSOP_CHECKALIASEDLET)
2954
2955
CASE(JSOP_INITALIASEDLET)
2956
{
2957
    ScopeCoordinate sc = ScopeCoordinate(REGS.pc);
2958
    ScopeObject &obj = REGS.fp()->aliasedVarScope(sc);
2959
    SetAliasedVarOperation(cx, script, REGS.pc, obj, sc, REGS.sp[-1],
2960
                           /* checkUninitializedLet = */ false);
2961
}
2962
END_CASE(JSOP_INITALIASEDLET)
2963
2874
CASE(JSOP_GETARG)
2964
CASE(JSOP_GETARG)
2875
{
2965
{
2876
    unsigned i = GET_ARGNO(REGS.pc);
2966
    unsigned i = GET_ARGNO(REGS.pc);
2877
    if (script->argsObjAliasesFormals())
2967
    if (script->argsObjAliasesFormals())
2878
        PUSH_COPY(REGS.fp()->argsObj().arg(i));
2968
        PUSH_COPY(REGS.fp()->argsObj().arg(i));
2879
    else
2969
    else
2880
        PUSH_COPY(REGS.fp()->unaliasedFormal(i));
2970
        PUSH_COPY(REGS.fp()->unaliasedFormal(i));
2881
}
2971
}
 Lines 2890-2920   CASE(JSOP_SETARG) Link Here 
2890
        REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
2980
        REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
2891
}
2981
}
2892
END_CASE(JSOP_SETARG)
2982
END_CASE(JSOP_SETARG)
2893
2983
2894
CASE(JSOP_GETLOCAL)
2984
CASE(JSOP_GETLOCAL)
2895
{
2985
{
2896
    uint32_t i = GET_LOCALNO(REGS.pc);
2986
    uint32_t i = GET_LOCALNO(REGS.pc);
2897
    PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
2987
    PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
2988
    MOZ_ASSERT(!IsUninitializedLet(REGS.sp[-1]));
2898
2989
2899
    /*
2990
    /*
2900
     * Skip the same-compartment assertion if the local will be immediately
2991
     * Skip the same-compartment assertion if the local will be immediately
2901
     * popped. We do not guarantee sync for dead locals when coming in from the
2992
     * popped. We do not guarantee sync for dead locals when coming in from the
2902
     * method JIT, and a GETLOCAL followed by POP is not considered to be
2993
     * method JIT, and a GETLOCAL followed by POP is not considered to be
2903
     * a use of the variable.
2994
     * a use of the variable.
2904
     */
2995
     */
2905
    if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
2996
    if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
2906
        assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
2997
        assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
2907
}
2998
}
2908
END_CASE(JSOP_GETLOCAL)
2999
END_CASE(JSOP_GETLOCAL)
2909
3000
2910
CASE(JSOP_SETLOCAL)
3001
CASE(JSOP_SETLOCAL)
2911
{
3002
{
2912
    uint32_t i = GET_LOCALNO(REGS.pc);
3003
    uint32_t i = GET_LOCALNO(REGS.pc);
3004
    MOZ_ASSERT(!IsUninitializedLet(REGS.fp()->unaliasedLocal(i)));
2913
    REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3005
    REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
2914
}
3006
}
2915
END_CASE(JSOP_SETLOCAL)
3007
END_CASE(JSOP_SETLOCAL)
2916
3008
2917
CASE(JSOP_DEFCONST)
3009
CASE(JSOP_DEFCONST)
2918
CASE(JSOP_DEFVAR)
3010
CASE(JSOP_DEFVAR)
2919
{
3011
{
2920
    /* ES5 10.5 step 8 (with subsequent errata). */
3012
    /* ES5 10.5 step 8 (with subsequent errata). */
 Lines 3805-3821   js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco Link Here 
3805
    return true;
3897
    return true;
3806
}
3898
}
3807
3899
3808
bool
3900
bool
3809
js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name,
3901
js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name,
3810
                          MutableHandleValue res)
3902
                          MutableHandleValue res)
3811
{
3903
{
3812
    RootedObject obj(cx);
3904
    RootedObject obj(cx);
3813
    if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj))
3905
    RootedShape shape(cx);
3906
    if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj, &shape))
3814
        return false;
3907
        return false;
3815
3908
3816
    return ComputeImplicitThis(cx, obj, res);
3909
    return ComputeImplicitThis(cx, obj, res);
3817
}
3910
}
3818
3911
3819
bool
3912
bool
3820
js::RunOnceScriptPrologue(JSContext *cx, HandleScript script)
3913
js::RunOnceScriptPrologue(JSContext *cx, HandleScript script)
3821
{
3914
{
 Lines 3937-3944   js::SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, Hand Link Here 
3937
      default:
4030
      default:
3938
        MOZ_CRASH("bad spread opcode");
4031
        MOZ_CRASH("bad spread opcode");
3939
    }
4032
    }
3940
4033
3941
    res.set(args.rval());
4034
    res.set(args.rval());
3942
    TypeScript::Monitor(cx, script, pc, res);
4035
    TypeScript::Monitor(cx, script, pc, res);
3943
    return true;
4036
    return true;
3944
}
4037
}
4038
4039
void
4040
js::ReportUninitializedLet(JSContext *cx, HandlePropertyName name)
4041
{
4042
    JSAutoByteString printable;
4043
    if (AtomToPrintableString(cx, name, &printable)) {
4044
        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_LET,
4045
                             printable.ptr());
4046
    }
4047
}
4048
4049
void
4050
js::ReportUninitializedLet(JSContext *cx, HandleScript script, jsbytecode *pc)
4051
{
4052
    RootedPropertyName name(cx);
4053
4054
    if (JSOp(*pc) == JSOP_CHECKLET) {
4055
        uint32_t slot = GET_LOCALNO(pc);
4056
4057
        // First search for a name among body-level lets.
4058
        for (BindingIter bi(script); bi; bi++) {
4059
            if (bi->kind() != Binding::ARGUMENT && bi.frameIndex() == slot) {
4060
                name = bi->name();
4061
                break;
4062
            }
4063
        }
4064
4065
        // Failing that, it must be a block-local let.
4066
        if (!name) {
4067
            // Skip to the right scope.
4068
            Rooted<NestedScopeObject *> scope(cx, script->getStaticScope(pc));
4069
            MOZ_ASSERT(scope && scope->is<StaticBlockObject>());
4070
            Rooted<StaticBlockObject *> block(cx, &scope->as<StaticBlockObject>());
4071
            while (slot < block->localOffset())
4072
                block = &block->enclosingNestedScope()->as<StaticBlockObject>();
4073
4074
            // Translate the frame slot to the block slot, then find the name
4075
            // of the slot.
4076
            uint32_t blockSlot = block->localIndexToSlot(slot);
4077
            RootedShape shape(cx, block->lastProperty());
4078
            Shape::Range<CanGC> r(cx, shape);
4079
            while (r.front().slot() != blockSlot)
4080
                r.popFront();
4081
            jsid id = r.front().propidRaw();
4082
            MOZ_ASSERT(JSID_IS_ATOM(id));
4083
            name = JSID_TO_ATOM(id)->asPropertyName();
4084
        }
4085
    } else {
4086
        MOZ_ASSERT(JSOp(*pc) == JSOP_CHECKALIASEDLET);
4087
        name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
4088
    }
4089
4090
    ReportUninitializedLet(cx, name);
4091
}
4092
4093
void
4094
js::ReportUninitializedLet(JSContext *cx, HandleScript script, jsbytecode *pc, ScopeCoordinate sc)
4095
{
4096
    RootedPropertyName name(cx, ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache,
4097
                                                    script, pc));
4098
    ReportUninitializedLet(cx, name);
4099
}
(-)a/js/src/vm/Interpreter.h (+18 lines)
Line     Link Here 
 Lines 318-333   TypeOfValue(const Value &v); Link Here 
318
extern bool
318
extern bool
319
HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
319
HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
320
320
321
// Unwind scope chain and iterator to match the static scope corresponding to
321
// Unwind scope chain and iterator to match the static scope corresponding to
322
// the given bytecode position.
322
// the given bytecode position.
323
extern void
323
extern void
324
UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc);
324
UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc);
325
325
326
// Unwind all scopes.
327
extern void
328
UnwindAllScopes(JSContext *cx, ScopeIter &si);
329
330
// Compute the pc needed to unwind the scope to the beginning of the block
331
// pointed to by the try note.
332
extern jsbytecode *
333
UnwindScopeToTryPc(JSScript *script, JSTryNote *tn);
334
326
/*
335
/*
327
 * Unwind for an uncatchable exception. This means not running finalizers, etc;
336
 * Unwind for an uncatchable exception. This means not running finalizers, etc;
328
 * just preserving the basic engine stack invariants.
337
 * just preserving the basic engine stack invariants.
329
 */
338
 */
330
extern void
339
extern void
331
UnwindForUncatchableException(JSContext *cx, const InterpreterRegs &regs);
340
UnwindForUncatchableException(JSContext *cx, const InterpreterRegs &regs);
332
341
333
extern bool
342
extern bool
 Lines 469-479   SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleVa Link Here 
469
inline bool
478
inline bool
470
SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
479
SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
471
{
480
{
472
    return JSObject::defineProperty(cx, varobj, name, rval,
481
    return JSObject::defineProperty(cx, varobj, name, rval,
473
                                    JS_PropertyStub, JS_StrictPropertyStub,
482
                                    JS_PropertyStub, JS_StrictPropertyStub,
474
                                    JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
483
                                    JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
475
}
484
}
476
485
486
void
487
ReportUninitializedLet(JSContext *cx, HandlePropertyName name);
488
489
void
490
ReportUninitializedLet(JSContext *cx, HandleScript script, jsbytecode *pc);
491
492
void
493
ReportUninitializedLet(JSContext *cx, HandleScript script, jsbytecode *pc, ScopeCoordinate sc);
494
477
}  /* namespace js */
495
}  /* namespace js */
478
496
479
#endif /* vm_Interpreter_h */
497
#endif /* vm_Interpreter_h */
(-)a/js/src/vm/Opcodes.h (-5 / +38 lines)
Line     Link Here 
 Lines 1246-1266    Link Here 
1246
     * Sets aliased variable as the top of stack value.
1246
     * Sets aliased variable as the top of stack value.
1247
     *   Category: Variables and Scopes
1247
     *   Category: Variables and Scopes
1248
     *   Type: Aliased Variables
1248
     *   Type: Aliased Variables
1249
     *   Operands: uint8_t hops, uint24_t slot
1249
     *   Operands: uint8_t hops, uint24_t slot
1250
     *   Stack: v => v
1250
     *   Stack: v => v
1251
     */ \
1251
     */ \
1252
    macro(JSOP_SETALIASEDVAR, 137,"setaliasedvar",NULL,      5,  1,  1,  JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
1252
    macro(JSOP_SETALIASEDVAR, 137,"setaliasedvar",NULL,      5,  1,  1,  JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
1253
    \
1253
    \
1254
    macro(JSOP_UNUSED138,  138, "unused138",   NULL,         1,  0,  0,  JOF_BYTE) \
1254
    /*
1255
    macro(JSOP_UNUSED139,  139, "unused139",   NULL,         1,  0,  0,  JOF_BYTE) \
1255
     * Checks if the value of the local variable is the JS_UNINITIALIZED_LET
1256
    macro(JSOP_UNUSED140,  140, "unused140",   NULL,         1,  0,  0,  JOF_BYTE) \
1256
     * magic, throwing an error if so.
1257
    macro(JSOP_UNUSED141,  141, "unused141",   NULL,         1,  0,  0,  JOF_BYTE) \
1257
     *   Category: Variables and Scopes
1258
    macro(JSOP_UNUSED142,  142, "unused142",   NULL,         1,  0,  0,  JOF_BYTE) \
1258
     *   Type: Local Variables
1259
     *   Operands: uint32_t localno
1260
     *   Stack: =>
1261
     */ \
1262
    macro(JSOP_CHECKLET,        138, "checklet",        NULL, 4,  0,  0, JOF_LOCAL|JOF_NAME) \
1263
    /*
1264
     * Initializes an uninitialized local let binding with the top of stack
1265
     * value.
1266
     *   Category: Variables and Scopes
1267
     *   Type: Local Variables
1268
     *   Operands: uint32_t localno
1269
     *   Stack: v => v
1270
     */ \
1271
    macro(JSOP_INITLET,         139, "initlet",         NULL, 4,  1,  1, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \
1272
    /*
1273
     * Checks if the value of the aliased variable is the JS_UNINITIALIZED_LET
1274
     * magic, throwing an error if so.
1275
     *   Category: Variables and Scopes
1276
     *   Type: Aliased Variables
1277
     *   Operands: uint8_t hops, uint24_t slot
1278
     *   Stack: =>
1279
     */ \
1280
    macro(JSOP_CHECKALIASEDLET, 140, "checkaliasedlet", NULL, 5,  0,  0, JOF_SCOPECOORD|JOF_NAME) \
1281
    /*
1282
     * Initializes an uninitialized aliased let binding with the top of stack
1283
     * value.
1284
     *   Category: Variables and Scopes
1285
     *   Type: Aliased Variables
1286
     *   Operands: uint8_t hops, uint24_t slot
1287
     *   Stack: v => v
1288
     */ \
1289
    macro(JSOP_INITALIASEDLET,  141, "initaliasedlet",  NULL, 5,  1,  1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
1290
    /* Unused */ \
1291
    macro(JSOP_UNUSED142,     142,"unused142", NULL,      1,  0,  0,  JOF_BYTE) \
1259
    \
1292
    \
1260
    /*
1293
    /*
1261
     * Pushes the value of the intrinsic onto the stack.
1294
     * Pushes the value of the intrinsic onto the stack.
1262
     *
1295
     *
1263
     * Intrinsic names are emitted instead of JSOP_*NAME ops when the
1296
     * Intrinsic names are emitted instead of JSOP_*NAME ops when the
1264
     * 'CompileOptions' flag 'selfHostingMode' is set.
1297
     * 'CompileOptions' flag 'selfHostingMode' is set.
1265
     *
1298
     *
1266
     * They are used in self-hosted code to access other self-hosted values and
1299
     * They are used in self-hosted code to access other self-hosted values and
(-)a/js/src/vm/ScopeObject-inl.h (+9 lines)
Line     Link Here 
 Lines 40-55   CallObject::setAliasedVar(JSContext *cx, AliasedFormalIter fi, PropertyName *nam Link Here 
40
inline void
40
inline void
41
CallObject::setAliasedVarFromArguments(JSContext *cx, const Value &argsValue, jsid id, const Value &v)
41
CallObject::setAliasedVarFromArguments(JSContext *cx, const Value &argsValue, jsid id, const Value &v)
42
{
42
{
43
    setSlot(argsValue.magicUint32(), v);
43
    setSlot(argsValue.magicUint32(), v);
44
    if (hasSingletonType())
44
    if (hasSingletonType())
45
        types::AddTypePropertyId(cx, this, id, v);
45
        types::AddTypePropertyId(cx, this, id, v);
46
}
46
}
47
47
48
inline void
49
CallObject::setAliasedLetsToThrowOnTouch(JSScript *script)
50
{
51
    uint32_t aliasedLetStart = script->bindings.aliasedBodyLevelLetStart();
52
    uint32_t aliasedLetEnd = numFixedSlots();
53
    for (uint32_t slot = aliasedLetStart; slot < aliasedLetEnd; slot++)
54
        initFixedSlot(slot, MagicValue(JS_UNINITIALIZED_LET));
55
}
56
48
template <AllowGC allowGC>
57
template <AllowGC allowGC>
49
inline bool
58
inline bool
50
StaticScopeIter<allowGC>::done() const
59
StaticScopeIter<allowGC>::done() const
51
{
60
{
52
    return !obj;
61
    return !obj;
53
}
62
}
54
63
55
template <AllowGC allowGC>
64
template <AllowGC allowGC>
(-)a/js/src/vm/ScopeObject.cpp (-4 / +5 lines)
Line     Link Here 
 Lines 212-227   CallObject::create(JSContext *cx, HandleScript script, HandleObject enclosing, H Link Here 
212
{
212
{
213
    gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
213
    gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
214
    CallObject *callobj = CallObject::createTemplateObject(cx, script, heap);
214
    CallObject *callobj = CallObject::createTemplateObject(cx, script, heap);
215
    if (!callobj)
215
    if (!callobj)
216
        return nullptr;
216
        return nullptr;
217
217
218
    callobj->as<ScopeObject>().setEnclosingScope(enclosing);
218
    callobj->as<ScopeObject>().setEnclosingScope(enclosing);
219
    callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
219
    callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
220
    callobj->setAliasedLetsToThrowOnTouch(script);
220
221
221
    if (script->treatAsRunOnce()) {
222
    if (script->treatAsRunOnce()) {
222
        Rooted<CallObject*> ncallobj(cx, callobj);
223
        Rooted<CallObject*> ncallobj(cx, callobj);
223
        if (!JSObject::setSingletonType(cx, ncallobj))
224
        if (!JSObject::setSingletonType(cx, ncallobj))
224
            return nullptr;
225
            return nullptr;
225
        return ncallobj;
226
        return ncallobj;
226
    }
227
    }
227
228
 Lines 1152-1192   class DebugScopeProxy : public BaseProxyHandler Link Here 
1152
    bool handleUnaliasedAccess(JSContext *cx, Handle<DebugScopeObject*> debugScope,
1153
    bool handleUnaliasedAccess(JSContext *cx, Handle<DebugScopeObject*> debugScope,
1153
                               Handle<ScopeObject*> scope, jsid id, Action action,
1154
                               Handle<ScopeObject*> scope, jsid id, Action action,
1154
                               MutableHandleValue vp, AccessResult *accessResult) const
1155
                               MutableHandleValue vp, AccessResult *accessResult) const
1155
    {
1156
    {
1156
        JS_ASSERT(&debugScope->scope() == scope);
1157
        JS_ASSERT(&debugScope->scope() == scope);
1157
        *accessResult = ACCESS_GENERIC;
1158
        *accessResult = ACCESS_GENERIC;
1158
        ScopeIterVal *maybeLiveScope = DebugScopes::hasLiveScope(*scope);
1159
        ScopeIterVal *maybeLiveScope = DebugScopes::hasLiveScope(*scope);
1159
1160
1160
        /* Handle unaliased formals, vars, and consts at function scope. */
1161
        /* Handle unaliased formals, vars, lets, and consts at function scope. */
1161
        if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
1162
        if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
1162
            CallObject &callobj = scope->as<CallObject>();
1163
            CallObject &callobj = scope->as<CallObject>();
1163
            RootedScript script(cx, callobj.callee().nonLazyScript());
1164
            RootedScript script(cx, callobj.callee().nonLazyScript());
1164
            if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
1165
            if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
1165
                return false;
1166
                return false;
1166
1167
1167
            Bindings &bindings = script->bindings;
1168
            Bindings &bindings = script->bindings;
1168
            BindingIter bi(script);
1169
            BindingIter bi(script);
1169
            while (bi && NameToId(bi->name()) != id)
1170
            while (bi && NameToId(bi->name()) != id)
1170
                bi++;
1171
                bi++;
1171
            if (!bi)
1172
            if (!bi)
1172
                return true;
1173
                return true;
1173
1174
1174
            if (bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT) {
1175
            if (bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT) {
1175
                uint32_t i = bi.frameIndex();
1176
                uint32_t i = bi.frameIndex();
1176
                if (script->varIsAliased(i))
1177
                if (script->bodyLevelLocalIsAliased(i))
1177
                    return true;
1178
                    return true;
1178
1179
1179
                if (maybeLiveScope) {
1180
                if (maybeLiveScope) {
1180
                    AbstractFramePtr frame = maybeLiveScope->frame();
1181
                    AbstractFramePtr frame = maybeLiveScope->frame();
1181
                    if (action == GET)
1182
                    if (action == GET)
1182
                        vp.set(frame.unaliasedVar(i));
1183
                        vp.set(frame.unaliasedLocal(i));
1183
                    else
1184
                    else
1184
                        frame.unaliasedVar(i) = vp;
1185
                        frame.unaliasedLocal(i) = vp;
1185
                } else if (JSObject *snapshot = debugScope->maybeSnapshot()) {
1186
                } else if (JSObject *snapshot = debugScope->maybeSnapshot()) {
1186
                    if (action == GET)
1187
                    if (action == GET)
1187
                        vp.set(snapshot->getDenseElement(bindings.numArgs() + i));
1188
                        vp.set(snapshot->getDenseElement(bindings.numArgs() + i));
1188
                    else
1189
                    else
1189
                        snapshot->setDenseElement(bindings.numArgs() + i, vp);
1190
                        snapshot->setDenseElement(bindings.numArgs() + i, vp);
1190
                } else {
1191
                } else {
1191
                    /* The unaliased value has been lost to the debugger. */
1192
                    /* The unaliased value has been lost to the debugger. */
1192
                    if (action == GET) {
1193
                    if (action == GET) {
(-)a/js/src/vm/ScopeObject.h (+6 lines)
Line     Link Here 
 Lines 125-140   class ScopeCoordinate Link Here 
125
125
126
    inline ScopeCoordinate() {}
126
    inline ScopeCoordinate() {}
127
127
128
    void setHops(uint32_t hops) { JS_ASSERT(hops < SCOPECOORD_HOPS_LIMIT); hops_ = hops; }
128
    void setHops(uint32_t hops) { JS_ASSERT(hops < SCOPECOORD_HOPS_LIMIT); hops_ = hops; }
129
    void setSlot(uint32_t slot) { JS_ASSERT(slot < SCOPECOORD_SLOT_LIMIT); slot_ = slot; }
129
    void setSlot(uint32_t slot) { JS_ASSERT(slot < SCOPECOORD_SLOT_LIMIT); slot_ = slot; }
130
130
131
    uint32_t hops() const { JS_ASSERT(hops_ < SCOPECOORD_HOPS_LIMIT); return hops_; }
131
    uint32_t hops() const { JS_ASSERT(hops_ < SCOPECOORD_HOPS_LIMIT); return hops_; }
132
    uint32_t slot() const { JS_ASSERT(slot_ < SCOPECOORD_SLOT_LIMIT); return slot_; }
132
    uint32_t slot() const { JS_ASSERT(slot_ < SCOPECOORD_SLOT_LIMIT); return slot_; }
133
134
    bool operator==(const ScopeCoordinate &rhs) const {
135
        return hops() == rhs.hops() && slot() == rhs.slot();
136
    }
133
};
137
};
134
138
135
/*
139
/*
136
 * Return a shape representing the static scope containing the variable
140
 * Return a shape representing the static scope containing the variable
137
 * accessed by the ALIASEDVAR op at 'pc'.
141
 * accessed by the ALIASEDVAR op at 'pc'.
138
 */
142
 */
139
extern Shape *
143
extern Shape *
140
ScopeCoordinateToStaticScopeShape(JSScript *script, jsbytecode *pc);
144
ScopeCoordinateToStaticScopeShape(JSScript *script, jsbytecode *pc);
 Lines 228-243   class ScopeObject : public JSObject Link Here 
228
232
229
class CallObject : public ScopeObject
233
class CallObject : public ScopeObject
230
{
234
{
231
    static const uint32_t CALLEE_SLOT = 1;
235
    static const uint32_t CALLEE_SLOT = 1;
232
236
233
    static CallObject *
237
    static CallObject *
234
    create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
238
    create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
235
239
240
    inline void setAliasedLetsToThrowOnTouch(JSScript *script);
241
236
  public:
242
  public:
237
    static const Class class_;
243
    static const Class class_;
238
244
239
    /* These functions are internal and are exposed only for JITs. */
245
    /* These functions are internal and are exposed only for JITs. */
240
246
241
    /*
247
    /*
242
     * Construct a bare-bones call object given a shape and a non-singleton
248
     * Construct a bare-bones call object given a shape and a non-singleton
243
     * type.  The call object must be further initialized to be usable.
249
     * type.  The call object must be further initialized to be usable.
(-)a/js/src/vm/Stack-inl.h (+10 lines)
Line     Link Here 
 Lines 84-107   InterpreterFrame::initCallFrame(JSContext *cx, InterpreterFrame *prev, jsbytecod Link Here 
84
    exec.fun = &callee;
84
    exec.fun = &callee;
85
    u.nactual = nactual;
85
    u.nactual = nactual;
86
    scopeChain_ = callee.environment();
86
    scopeChain_ = callee.environment();
87
    prev_ = prev;
87
    prev_ = prev;
88
    prevpc_ = prevpc;
88
    prevpc_ = prevpc;
89
    prevsp_ = prevsp;
89
    prevsp_ = prevsp;
90
90
91
    initVarsToUndefined();
91
    initVarsToUndefined();
92
    setLetsToThrowOnTouch();
92
}
93
}
93
94
94
inline void
95
inline void
95
InterpreterFrame::initVarsToUndefined()
96
InterpreterFrame::initVarsToUndefined()
96
{
97
{
97
    SetValueRangeToUndefined(slots(), script()->nfixed());
98
    SetValueRangeToUndefined(slots(), script()->nfixed());
98
}
99
}
99
100
101
inline void
102
InterpreterFrame::setLetsToThrowOnTouch()
103
{
104
    // 'let' declaration throw ReferenceErrors if they are used before
105
    // initialization. See ES6 8.1.1.1.6.
106
    for (size_t slot = script()->fixedLetBegin(), end = script()->fixedLetEnd(); slot < end; slot++)
107
        slots()[slot].setMagic(JS_UNINITIALIZED_LET);
108
}
109
100
inline Value &
110
inline Value &
101
InterpreterFrame::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
111
InterpreterFrame::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
102
{
112
{
103
    JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
113
    JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
104
    JS_ASSERT(i < script()->nfixedvars());
114
    JS_ASSERT(i < script()->nfixedvars());
105
    return slots()[i];
115
    return slots()[i];
106
}
116
}
107
117
(-)a/js/src/vm/Stack.cpp (-1 / +2 lines)
Line     Link Here 
 Lines 393-409   InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc) Link Here 
393
393
394
    size_t nfixed = script()->nfixed();
394
    size_t nfixed = script()->nfixed();
395
    size_t nlivefixed;
395
    size_t nlivefixed;
396
396
397
    if (staticScope) {
397
    if (staticScope) {
398
        StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
398
        StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
399
        nlivefixed = blockObj.localOffset() + blockObj.numVariables();
399
        nlivefixed = blockObj.localOffset() + blockObj.numVariables();
400
    } else {
400
    } else {
401
        nlivefixed = script()->nfixedvars();
401
        nlivefixed = script()->nbodyfixed();
402
    }
402
    }
403
403
404
    if (nfixed == nlivefixed) {
404
    if (nfixed == nlivefixed) {
405
        // All locals are live.
405
        // All locals are live.
406
        markValues(trc, 0, sp - slots());
406
        markValues(trc, 0, sp - slots());
407
    } else {
407
    } else {
408
        // Mark operand stack.
408
        // Mark operand stack.
409
        markValues(trc, nfixed, sp - slots());
409
        markValues(trc, nfixed, sp - slots());
 Lines 491-506   InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Val Link Here 
491
    uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
491
    uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
492
    if (!buffer)
492
    if (!buffer)
493
        return nullptr;
493
        return nullptr;
494
494
495
    InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value));
495
    InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value));
496
    fp->mark_ = mark;
496
    fp->mark_ = mark;
497
    fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
497
    fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
498
    fp->initVarsToUndefined();
498
    fp->initVarsToUndefined();
499
    fp->setLetsToThrowOnTouch();
499
500
500
    return fp;
501
    return fp;
501
}
502
}
502
503
503
/*****************************************************************************/
504
/*****************************************************************************/
504
505
505
/* MSVC PGO causes xpcshell startup crashes. */
506
/* MSVC PGO causes xpcshell startup crashes. */
506
#if defined(_MSC_VER)
507
#if defined(_MSC_VER)
(-)a/js/src/vm/Stack.h (+1 lines)
Line     Link Here 
 Lines 420-435   class InterpreterFrame Link Here 
420
420
421
    bool prologue(JSContext *cx);
421
    bool prologue(JSContext *cx);
422
    void epilogue(JSContext *cx);
422
    void epilogue(JSContext *cx);
423
423
424
    bool initFunctionScopeObjects(JSContext *cx);
424
    bool initFunctionScopeObjects(JSContext *cx);
425
425
426
    /* Initialize local variables of newly-pushed frame. */
426
    /* Initialize local variables of newly-pushed frame. */
427
    void initVarsToUndefined();
427
    void initVarsToUndefined();
428
    void setLetsToThrowOnTouch();
428
429
429
    /*
430
    /*
430
     * Stack frame type
431
     * Stack frame type
431
     *
432
     *
432
     * A stack frame may have one of three types, which determines which
433
     * A stack frame may have one of three types, which determines which
433
     * members of the frame may be accessed and other invariants:
434
     * members of the frame may be accessed and other invariants:
434
     *
435
     *
435
     *  global frame:   execution of global code or an eval in global code
436
     *  global frame:   execution of global code or an eval in global code

Return to bug 1001090