Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/*
8
* JS bytecode generation.
9
*/
10
11
#include "frontend/BytecodeEmitter.h"
12
13
#include "mozilla/ArrayUtils.h" // mozilla::ArrayLength
14
#include "mozilla/Casting.h" // mozilla::AssertedCast
15
#include "mozilla/DebugOnly.h" // mozilla::DebugOnly
16
#include "mozilla/FloatingPoint.h" // mozilla::NumberEqualsInt32, mozilla::NumberIsInt32
17
#include "mozilla/Maybe.h" // mozilla::{Maybe,Nothing,Some}
18
#include "mozilla/PodOperations.h" // mozilla::PodCopy
19
#include "mozilla/Sprintf.h" // SprintfLiteral
20
#include "mozilla/Unused.h" // mozilla::Unused
21
#include "mozilla/Variant.h" // mozilla::AsVariant
22
23
#include <algorithm>
24
#include <string.h>
25
26
#include "jstypes.h" // JS_BIT
27
28
#include "ds/Nestable.h" // Nestable
29
#include "frontend/AbstractScope.h"
30
#include "frontend/BytecodeControlStructures.h" // NestableControl, BreakableControl, LabelControl, LoopControl, TryFinallyControl
31
#include "frontend/CallOrNewEmitter.h" // CallOrNewEmitter
32
#include "frontend/CForEmitter.h" // CForEmitter
33
#include "frontend/DefaultEmitter.h" // DefaultEmitter
34
#include "frontend/DoWhileEmitter.h" // DoWhileEmitter
35
#include "frontend/ElemOpEmitter.h" // ElemOpEmitter
36
#include "frontend/EmitterScope.h" // EmitterScope
37
#include "frontend/ExpressionStatementEmitter.h" // ExpressionStatementEmitter
38
#include "frontend/ForInEmitter.h" // ForInEmitter
39
#include "frontend/ForOfEmitter.h" // ForOfEmitter
40
#include "frontend/ForOfLoopControl.h" // ForOfLoopControl
41
#include "frontend/FunctionEmitter.h" // FunctionEmitter, FunctionScriptEmitter, FunctionParamsEmitter
42
#include "frontend/IfEmitter.h" // IfEmitter, InternalIfEmitter, CondEmitter
43
#include "frontend/LabelEmitter.h" // LabelEmitter
44
#include "frontend/LexicalScopeEmitter.h" // LexicalScopeEmitter
45
#include "frontend/ModuleSharedContext.h" // ModuleSharedContext
46
#include "frontend/NameFunctions.h" // NameFunctions
47
#include "frontend/NameOpEmitter.h" // NameOpEmitter
48
#include "frontend/ObjectEmitter.h" // PropertyEmitter, ObjectEmitter, ClassEmitter
49
#include "frontend/OptionalEmitter.h" // OptionalEmitter
50
#include "frontend/ParseNode.h" // ParseNodeKind, ParseNode and subclasses, ObjectBox
51
#include "frontend/Parser.h" // Parser
52
#include "frontend/PropOpEmitter.h" // PropOpEmitter
53
#include "frontend/SwitchEmitter.h" // SwitchEmitter
54
#include "frontend/TDZCheckCache.h" // TDZCheckCache
55
#include "frontend/TryEmitter.h" // TryEmitter
56
#include "frontend/WhileEmitter.h" // WhileEmitter
57
#include "js/CompileOptions.h" // TransitiveCompileOptions, CompileOptions
58
#include "vm/AsyncFunction.h" // AsyncFunctionResolveKind
59
#include "vm/BytecodeUtil.h" // IsArgOp, IsLocalOp, SET_UINT24, SET_ICINDEX, BytecodeFallsThrough, BytecodeIsJumpTarget
60
#include "vm/GeneratorObject.h" // AbstractGeneratorObject
61
#include "vm/JSAtom.h" // JSAtom, js_*_str
62
#include "vm/JSContext.h" // JSContext
63
#include "vm/JSFunction.h" // FunctionPrefixKind, JSFunction,
64
#include "vm/JSScript.h" // JSScript, ScopeNote, ScriptSourceObject, FieldInitializers, JSScript, LazyScript
65
#include "vm/Opcodes.h" // JSOp, JSOpLength_*
66
#include "wasm/AsmJS.h" // IsAsmJSModule
67
68
#include "vm/JSObject-inl.h" // JSObject
69
70
using namespace js;
71
using namespace js::frontend;
72
73
using mozilla::ArrayLength;
74
using mozilla::AssertedCast;
75
using mozilla::AsVariant;
76
using mozilla::DebugOnly;
77
using mozilla::Maybe;
78
using mozilla::Nothing;
79
using mozilla::NumberEqualsInt32;
80
using mozilla::NumberIsInt32;
81
using mozilla::PodCopy;
82
using mozilla::Some;
83
using mozilla::Unused;
84
85
static bool ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) {
86
// The few node types listed below are exceptions to the usual
87
// location-source-note-emitting code in BytecodeEmitter::emitTree().
88
// Single-line `while` loops and C-style `for` loops require careful
89
// handling to avoid strange stepping behavior.
90
// Functions usually shouldn't have location information (bug 1431202).
91
92
ParseNodeKind kind = pn->getKind();
93
return kind == ParseNodeKind::WhileStmt || kind == ParseNodeKind::ForStmt ||
94
kind == ParseNodeKind::Function;
95
}
96
97
BytecodeEmitter::BytecodeEmitter(
98
BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
99
Handle<LazyScript*> lazyScript, uint32_t line, uint32_t column,
100
ParseInfo& parseInfo, EmitterMode emitterMode,
101
FieldInitializers fieldInitializers /* = FieldInitializers::Invalid() */)
102
: sc(sc),
103
cx(sc->cx_),
104
parent(parent),
105
script(cx, script),
106
lazyScript(cx, lazyScript),
107
bytecodeSection_(cx, line),
108
perScriptData_(cx, parseInfo),
109
fieldInitializers_(fieldInitializers),
110
parseInfo(parseInfo),
111
firstLine(line),
112
firstColumn(column),
113
emitterMode(emitterMode) {
114
MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
115
116
if (sc->isFunctionBox()) {
117
// Functions have IC entries for type monitoring |this| and arguments.
118
bytecodeSection().setNumICEntries(sc->asFunctionBox()->nargs() + 1);
119
}
120
}
121
122
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
123
BCEParserHandle* handle, SharedContext* sc,
124
HandleScript script,
125
Handle<LazyScript*> lazyScript, uint32_t line,
126
uint32_t column, ParseInfo& parseInfo,
127
EmitterMode emitterMode,
128
FieldInitializers fieldInitializers)
129
: BytecodeEmitter(parent, sc, script, lazyScript, line, column, parseInfo,
130
emitterMode, fieldInitializers) {
131
parser = handle;
132
instrumentationKinds = parser->options().instrumentationKinds;
133
}
134
135
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
136
const EitherParser& parser, SharedContext* sc,
137
HandleScript script,
138
Handle<LazyScript*> lazyScript, uint32_t line,
139
uint32_t column, ParseInfo& parseInfo,
140
EmitterMode emitterMode,
141
FieldInitializers fieldInitializers)
142
: BytecodeEmitter(parent, sc, script, lazyScript, line, column, parseInfo,
143
emitterMode, fieldInitializers) {
144
ep_.emplace(parser);
145
this->parser = ep_.ptr();
146
instrumentationKinds = this->parser->options().instrumentationKinds;
147
}
148
149
void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) {
150
setScriptStartOffsetIfUnset(bodyPosition.begin);
151
setFunctionBodyEndPos(bodyPosition.end);
152
}
153
154
bool BytecodeEmitter::init() { return perScriptData_.init(cx); }
155
156
bool BytecodeEmitter::init(TokenPos bodyPosition) {
157
initFromBodyPosition(bodyPosition);
158
return init();
159
}
160
161
template <typename T>
162
T* BytecodeEmitter::findInnermostNestableControl() const {
163
return NestableControl::findNearest<T>(innermostNestableControl);
164
}
165
166
template <typename T, typename Predicate /* (T*) -> bool */>
167
T* BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const {
168
return NestableControl::findNearest<T>(innermostNestableControl, predicate);
169
}
170
171
NameLocation BytecodeEmitter::lookupName(JSAtom* name) {
172
return innermostEmitterScope()->lookup(this, name);
173
}
174
175
Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(
176
JSAtom* name, EmitterScope* target) {
177
return innermostEmitterScope()->locationBoundInScope(name, target);
178
}
179
180
Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInFunctionScope(
181
JSAtom* name, EmitterScope* source) {
182
EmitterScope* funScope = source;
183
while (!funScope->scope(this).is<FunctionScope>()) {
184
funScope = funScope->enclosingInFrame();
185
}
186
return source->locationBoundInScope(name, funScope);
187
}
188
189
bool BytecodeEmitter::markStepBreakpoint() {
190
if (inPrologue()) {
191
return true;
192
}
193
194
if (!emitInstrumentation(InstrumentationKind::Breakpoint)) {
195
return false;
196
}
197
198
if (!newSrcNote(SRC_STEP_SEP)) {
199
return false;
200
}
201
202
if (!newSrcNote(SRC_BREAKPOINT)) {
203
return false;
204
}
205
206
// We track the location of the most recent separator for use in
207
// markSimpleBreakpoint. Note that this means that the position must already
208
// be set before markStepBreakpoint is called.
209
bytecodeSection().updateSeparatorPosition();
210
211
return true;
212
}
213
214
bool BytecodeEmitter::markSimpleBreakpoint() {
215
if (inPrologue()) {
216
return true;
217
}
218
219
// If a breakable call ends up being the same location as the most recent
220
// expression start, we need to skip marking it breakable in order to avoid
221
// having two breakpoints with the same line/column position.
222
// Note: This assumes that the position for the call has already been set.
223
if (!bytecodeSection().isDuplicateLocation()) {
224
if (!emitInstrumentation(InstrumentationKind::Breakpoint)) {
225
return false;
226
}
227
228
if (!newSrcNote(SRC_BREAKPOINT)) {
229
return false;
230
}
231
}
232
233
return true;
234
}
235
236
bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta,
237
BytecodeOffset* offset) {
238
size_t oldLength = bytecodeSection().code().length();
239
*offset = BytecodeOffset(oldLength);
240
241
size_t newLength = oldLength + size_t(delta);
242
if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) {
243
ReportAllocationOverflow(cx);
244
return false;
245
}
246
247
if (!bytecodeSection().code().growByUninitialized(delta)) {
248
return false;
249
}
250
251
if (BytecodeOpHasTypeSet(op)) {
252
bytecodeSection().incrementNumTypeSets();
253
}
254
255
if (BytecodeOpHasIC(op)) {
256
// Even if every bytecode op is a JOF_IC op and the function has ARGC_LIMIT
257
// arguments, numICEntries cannot overflow.
258
static_assert(MaxBytecodeLength + 1 /* this */ + ARGC_LIMIT <= UINT32_MAX,
259
"numICEntries must not overflow");
260
bytecodeSection().incrementNumICEntries();
261
}
262
263
return true;
264
}
265
266
#ifdef DEBUG
267
bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
268
if (IsCheckStrictOp(op) && !sc->strict()) {
269
return false;
270
}
271
if (IsCheckSloppyOp(op) && sc->strict()) {
272
return false;
273
}
274
return true;
275
}
276
#endif
277
278
bool BytecodeEmitter::emit1(JSOp op) {
279
MOZ_ASSERT(checkStrictOrSloppy(op));
280
281
BytecodeOffset offset;
282
if (!emitCheck(op, 1, &offset)) {
283
return false;
284
}
285
286
jsbytecode* code = bytecodeSection().code(offset);
287
code[0] = jsbytecode(op);
288
bytecodeSection().updateDepth(offset);
289
return true;
290
}
291
292
bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
293
MOZ_ASSERT(checkStrictOrSloppy(op));
294
295
BytecodeOffset offset;
296
if (!emitCheck(op, 2, &offset)) {
297
return false;
298
}
299
300
jsbytecode* code = bytecodeSection().code(offset);
301
code[0] = jsbytecode(op);
302
code[1] = jsbytecode(op1);
303
bytecodeSection().updateDepth(offset);
304
return true;
305
}
306
307
bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
308
MOZ_ASSERT(checkStrictOrSloppy(op));
309
310
/* These should filter through emitVarOp. */
311
MOZ_ASSERT(!IsArgOp(op));
312
MOZ_ASSERT(!IsLocalOp(op));
313
314
BytecodeOffset offset;
315
if (!emitCheck(op, 3, &offset)) {
316
return false;
317
}
318
319
jsbytecode* code = bytecodeSection().code(offset);
320
code[0] = jsbytecode(op);
321
code[1] = op1;
322
code[2] = op2;
323
bytecodeSection().updateDepth(offset);
324
return true;
325
}
326
327
bool BytecodeEmitter::emitN(JSOp op, size_t extra, BytecodeOffset* offset) {
328
MOZ_ASSERT(checkStrictOrSloppy(op));
329
ptrdiff_t length = 1 + ptrdiff_t(extra);
330
331
BytecodeOffset off;
332
if (!emitCheck(op, length, &off)) {
333
return false;
334
}
335
336
jsbytecode* code = bytecodeSection().code(off);
337
code[0] = jsbytecode(op);
338
/* The remaining |extra| bytes are set by the caller */
339
340
/*
341
* Don't updateDepth if op's use-count comes from the immediate
342
* operand yet to be stored in the extra bytes after op.
343
*/
344
if (CodeSpec(op).nuses >= 0) {
345
bytecodeSection().updateDepth(off);
346
}
347
348
if (offset) {
349
*offset = off;
350
}
351
return true;
352
}
353
354
bool BytecodeEmitter::emitJumpTargetOp(JSOp op, BytecodeOffset* off) {
355
MOZ_ASSERT(BytecodeIsJumpTarget(op));
356
357
// Record the current IC-entry index at start of this op.
358
uint32_t numEntries = bytecodeSection().numICEntries();
359
360
size_t n = GetOpLength(op) - 1;
361
MOZ_ASSERT(GetOpLength(op) >= 1 + UINT32_INDEX_LEN);
362
363
if (!emitN(op, n, off)) {
364
return false;
365
}
366
367
SET_ICINDEX(bytecodeSection().code(*off), numEntries);
368
return true;
369
}
370
371
bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
372
BytecodeOffset off = bytecodeSection().offset();
373
374
// Alias consecutive jump targets.
375
if (bytecodeSection().lastTargetOffset().valid() &&
376
off == bytecodeSection().lastTargetOffset() +
377
BytecodeOffsetDiff(JSOpLength_JumpTarget)) {
378
target->offset = bytecodeSection().lastTargetOffset();
379
return true;
380
}
381
382
target->offset = off;
383
bytecodeSection().setLastTargetOffset(off);
384
385
BytecodeOffset opOff;
386
return emitJumpTargetOp(JSOp::JumpTarget, &opOff);
387
}
388
389
bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
390
BytecodeOffset offset;
391
if (!emitCheck(op, 5, &offset)) {
392
return false;
393
}
394
395
jsbytecode* code = bytecodeSection().code(offset);
396
code[0] = jsbytecode(op);
397
MOZ_ASSERT(!jump->offset.valid() ||
398
(0 <= jump->offset.value() && jump->offset < offset));
399
jump->push(bytecodeSection().code(BytecodeOffset(0)), offset);
400
bytecodeSection().updateDepth(offset);
401
return true;
402
}
403
404
bool BytecodeEmitter::emitJump(JSOp op, JumpList* jump) {
405
if (!emitJumpNoFallthrough(op, jump)) {
406
return false;
407
}
408
if (BytecodeFallsThrough(op)) {
409
JumpTarget fallthrough;
410
if (!emitJumpTarget(&fallthrough)) {
411
return false;
412
}
413
}
414
return true;
415
}
416
417
void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
418
MOZ_ASSERT(
419
!jump.offset.valid() ||
420
(0 <= jump.offset.value() && jump.offset <= bytecodeSection().offset()));
421
MOZ_ASSERT(0 <= target.offset.value() &&
422
target.offset <= bytecodeSection().offset());
423
MOZ_ASSERT_IF(
424
jump.offset.valid() &&
425
target.offset + BytecodeOffsetDiff(4) <= bytecodeSection().offset(),
426
BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target.offset))));
427
jump.patchAll(bytecodeSection().code(BytecodeOffset(0)), target);
428
}
429
430
bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
431
if (!jump.offset.valid()) {
432
return true;
433
}
434
JumpTarget target;
435
if (!emitJumpTarget(&target)) {
436
return false;
437
}
438
patchJumpsToTarget(jump, target);
439
return true;
440
}
441
442
bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc,
443
const Maybe<uint32_t>& sourceCoordOffset) {
444
if (sourceCoordOffset.isSome()) {
445
if (!updateSourceCoordNotes(*sourceCoordOffset)) {
446
return false;
447
}
448
}
449
return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
450
}
451
452
bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
453
return emitCall(op, argc, pn ? Some(pn->pn_pos.begin) : Nothing());
454
}
455
456
bool BytecodeEmitter::emitDupAt(unsigned slotFromTop, unsigned count) {
457
MOZ_ASSERT(slotFromTop < unsigned(bytecodeSection().stackDepth()));
458
MOZ_ASSERT(slotFromTop + 1 >= count);
459
460
if (slotFromTop == 0 && count == 1) {
461
return emit1(JSOp::Dup);
462
}
463
464
if (slotFromTop == 1 && count == 2) {
465
return emit1(JSOp::Dup2);
466
}
467
468
if (slotFromTop >= Bit(24)) {
469
reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
470
return false;
471
}
472
473
for (unsigned i = 0; i < count; i++) {
474
BytecodeOffset off;
475
if (!emitN(JSOp::DupAt, 3, &off)) {
476
return false;
477
}
478
479
jsbytecode* pc = bytecodeSection().code(off);
480
SET_UINT24(pc, slotFromTop);
481
}
482
483
return true;
484
}
485
486
bool BytecodeEmitter::emitPopN(unsigned n) {
487
MOZ_ASSERT(n != 0);
488
489
if (n == 1) {
490
return emit1(JSOp::Pop);
491
}
492
493
// 2 JSOp::Pop instructions (2 bytes) are shorter than JSOp::PopN (3 bytes).
494
if (n == 2) {
495
return emit1(JSOp::Pop) && emit1(JSOp::Pop);
496
}
497
498
return emitUint16Operand(JSOp::PopN, n);
499
}
500
501
bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind) {
502
return emit2(JSOp::CheckIsObj, uint8_t(kind));
503
}
504
505
bool BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind) {
506
return emit2(JSOp::CheckIsCallable, uint8_t(kind));
507
}
508
509
static inline unsigned LengthOfSetLine(unsigned line) {
510
return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1);
511
}
512
513
/* Updates line number notes, not column notes. */
514
bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
515
// Don't emit line/column number notes in the prologue.
516
if (inPrologue()) {
517
return true;
518
}
519
520
ErrorReporter* er = &parser->errorReporter();
521
bool onThisLine;
522
if (!er->isOnThisLine(offset, bytecodeSection().currentLine(), &onThisLine)) {
523
er->errorNoOffset(JSMSG_OUT_OF_MEMORY);
524
return false;
525
}
526
527
if (!onThisLine) {
528
unsigned line = er->lineAt(offset);
529
unsigned delta = line - bytecodeSection().currentLine();
530
531
/*
532
* Encode any change in the current source line number by using
533
* either several SRC_NEWLINE notes or just one SRC_SETLINE note,
534
* whichever consumes less space.
535
*
536
* NB: We handle backward line number deltas (possible with for
537
* loops where the update part is emitted after the body, but its
538
* line number is <= any line number in the body) here by letting
539
* unsigned delta_ wrap to a very large number, which triggers a
540
* SRC_SETLINE.
541
*/
542
bytecodeSection().setCurrentLine(line, offset);
543
if (delta >= LengthOfSetLine(line)) {
544
if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line))) {
545
return false;
546
}
547
} else {
548
do {
549
if (!newSrcNote(SRC_NEWLINE)) {
550
return false;
551
}
552
} while (--delta != 0);
553
}
554
555
bytecodeSection().updateSeparatorPositionIfPresent();
556
}
557
return true;
558
}
559
560
/* Updates the line number and column number information in the source notes. */
561
bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
562
if (!updateLineNumberNotes(offset)) {
563
return false;
564
}
565
566
// Don't emit line/column number notes in the prologue.
567
if (inPrologue()) {
568
return true;
569
}
570
571
uint32_t columnIndex = parser->errorReporter().columnAt(offset);
572
ptrdiff_t colspan =
573
ptrdiff_t(columnIndex) - ptrdiff_t(bytecodeSection().lastColumn());
574
if (colspan != 0) {
575
// If the column span is so large that we can't store it, then just
576
// discard this information. This can happen with minimized or otherwise
577
// machine-generated code. Even gigantic column numbers are still
578
// valuable if you have a source map to relate them to something real;
579
// but it's better to fail soft here.
580
if (!SN_REPRESENTABLE_COLSPAN(colspan)) {
581
return true;
582
}
583
if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan))) {
584
return false;
585
}
586
bytecodeSection().setLastColumn(columnIndex, offset);
587
bytecodeSection().updateSeparatorPositionIfPresent();
588
}
589
return true;
590
}
591
592
Maybe<uint32_t> BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn) {
593
if (!nextpn) {
594
return Nothing();
595
}
596
597
// Try to give the JSOp::LoopHead the same line number as the next
598
// instruction. nextpn is often a block, in which case the next instruction
599
// typically comes from the first statement inside.
600
if (nextpn->is<LexicalScopeNode>()) {
601
nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
602
}
603
if (nextpn->isKind(ParseNodeKind::StatementList)) {
604
if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
605
nextpn = firstStatement;
606
}
607
}
608
609
return Some(nextpn->pn_pos.begin);
610
}
611
612
bool BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand) {
613
MOZ_ASSERT(operand <= UINT16_MAX);
614
if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand))) {
615
return false;
616
}
617
return true;
618
}
619
620
bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
621
BytecodeOffset off;
622
if (!emitN(op, 4, &off)) {
623
return false;
624
}
625
SET_UINT32(bytecodeSection().code(off), operand);
626
return true;
627
}
628
629
namespace {
630
631
class NonLocalExitControl {
632
public:
633
enum Kind {
634
// IteratorClose is handled especially inside the exception unwinder.
635
Throw,
636
637
// A 'continue' statement does not call IteratorClose for the loop it
638
// is continuing, i.e. excluding the target loop.
639
Continue,
640
641
// A 'break' or 'return' statement does call IteratorClose for the
642
// loop it is breaking out of or returning from, i.e. including the
643
// target loop.
644
Break,
645
Return
646
};
647
648
private:
649
BytecodeEmitter* bce_;
650
const uint32_t savedScopeNoteIndex_;
651
const int savedDepth_;
652
uint32_t openScopeNoteIndex_;
653
Kind kind_;
654
655
NonLocalExitControl(const NonLocalExitControl&) = delete;
656
657
MOZ_MUST_USE bool leaveScope(EmitterScope* scope);
658
659
public:
660
NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
661
: bce_(bce),
662
savedScopeNoteIndex_(bce->bytecodeSection().scopeNoteList().length()),
663
savedDepth_(bce->bytecodeSection().stackDepth()),
664
openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
665
kind_(kind) {}
666
667
~NonLocalExitControl() {
668
for (uint32_t n = savedScopeNoteIndex_;
669
n < bce_->bytecodeSection().scopeNoteList().length(); n++) {
670
bce_->bytecodeSection().scopeNoteList().recordEnd(
671
n, bce_->bytecodeSection().offset());
672
}
673
bce_->bytecodeSection().setStackDepth(savedDepth_);
674
}
675
676
MOZ_MUST_USE bool prepareForNonLocalJump(NestableControl* target);
677
678
MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
679
return prepareForNonLocalJump(nullptr);
680
}
681
};
682
683
bool NonLocalExitControl::leaveScope(EmitterScope* es) {
684
if (!es->leave(bce_, /* nonLocal = */ true)) {
685
return false;
686
}
687
688
// As we pop each scope due to the non-local jump, emit notes that
689
// record the extent of the enclosing scope. These notes will have
690
// their ends recorded in ~NonLocalExitControl().
691
uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
692
if (es->enclosingInFrame()) {
693
enclosingScopeIndex = es->enclosingInFrame()->index();
694
}
695
if (!bce_->bytecodeSection().scopeNoteList().append(
696
enclosingScopeIndex, bce_->bytecodeSection().offset(),
697
openScopeNoteIndex_)) {
698
return false;
699
}
700
openScopeNoteIndex_ = bce_->bytecodeSection().scopeNoteList().length() - 1;
701
702
return true;
703
}
704
705
/*
706
* Emit additional bytecode(s) for non-local jumps.
707
*/
708
bool NonLocalExitControl::prepareForNonLocalJump(NestableControl* target) {
709
EmitterScope* es = bce_->innermostEmitterScope();
710
int npops = 0;
711
712
AutoCheckUnstableEmitterScope cues(bce_);
713
714
// For 'continue', 'break', and 'return' statements, emit IteratorClose
715
// bytecode inline. 'continue' statements do not call IteratorClose for
716
// the loop they are continuing.
717
bool emitIteratorClose =
718
kind_ == Continue || kind_ == Break || kind_ == Return;
719
bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
720
721
auto flushPops = [&npops](BytecodeEmitter* bce) {
722
if (npops && !bce->emitPopN(npops)) {
723
return false;
724
}
725
npops = 0;
726
return true;
727
};
728
729
// If we are closing multiple for-of loops, the resulting FOR_OF_ITERCLOSE
730
// trynotes must be appropriately nested. Each FOR_OF_ITERCLOSE starts when
731
// we close the corresponding for-of iterator, and continues until the
732
// actual jump.
733
Vector<BytecodeOffset, 4> forOfIterCloseScopeStarts(bce_->cx);
734
735
// Walk the nestable control stack and patch jumps.
736
for (NestableControl* control = bce_->innermostNestableControl;
737
control != target; control = control->enclosing()) {
738
// Walk the scope stack and leave the scopes we entered. Leaving a scope
739
// may emit administrative ops like JSOp::PopLexicalEnv but never anything
740
// that manipulates the stack.
741
for (; es != control->emitterScope(); es = es->enclosingInFrame()) {
742
if (!leaveScope(es)) {
743
return false;
744
}
745
}
746
747
switch (control->kind()) {
748
case StatementKind::Finally: {
749
TryFinallyControl& finallyControl = control->as<TryFinallyControl>();
750
if (finallyControl.emittingSubroutine()) {
751
/*
752
* There's a [exception or hole, retsub pc-index] pair and the
753
* possible return value on the stack that we need to pop.
754
*/
755
npops += 3;
756
} else {
757
if (!flushPops(bce_)) {
758
return false;
759
}
760
if (!bce_->emitGoSub(&finallyControl.gosubs)) {
761
// [stack] ...
762
return false;
763
}
764
}
765
break;
766
}
767
768
case StatementKind::ForOfLoop:
769
if (emitIteratorClose) {
770
if (!flushPops(bce_)) {
771
return false;
772
}
773
BytecodeOffset tryNoteStart;
774
ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
775
if (!loopinfo.emitPrepareForNonLocalJumpFromScope(
776
bce_, *es,
777
/* isTarget = */ false, &tryNoteStart)) {
778
// [stack] ...
779
return false;
780
}
781
if (!forOfIterCloseScopeStarts.append(tryNoteStart)) {
782
return false;
783
}
784
} else {
785
// The iterator next method, the iterator, and the current
786
// value are on the stack.
787
npops += 3;
788
}
789
break;
790
791
case StatementKind::ForInLoop:
792
if (!flushPops(bce_)) {
793
return false;
794
}
795
796
// The iterator and the current value are on the stack.
797
if (!bce_->emit1(JSOp::EndIter)) {
798
// [stack] ...
799
return false;
800
}
801
break;
802
803
default:
804
break;
805
}
806
}
807
808
if (!flushPops(bce_)) {
809
return false;
810
}
811
812
if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
813
BytecodeOffset tryNoteStart;
814
ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
815
if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
816
/* isTarget = */ true,
817
&tryNoteStart)) {
818
// [stack] ... UNDEF UNDEF UNDEF
819
return false;
820
}
821
if (!forOfIterCloseScopeStarts.append(tryNoteStart)) {
822
return false;
823
}
824
}
825
826
EmitterScope* targetEmitterScope =
827
target ? target->emitterScope() : bce_->varEmitterScope;
828
for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
829
if (!leaveScope(es)) {
830
return false;
831
}
832
}
833
834
// Close FOR_OF_ITERCLOSE trynotes.
835
BytecodeOffset end = bce_->bytecodeSection().offset();
836
for (BytecodeOffset start : forOfIterCloseScopeStarts) {
837
if (!bce_->addTryNote(JSTRY_FOR_OF_ITERCLOSE, 0, start, end)) {
838
return false;
839
}
840
}
841
842
return true;
843
}
844
845
} // anonymous namespace
846
847
bool BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist,
848
GotoKind kind) {
849
NonLocalExitControl nle(this, kind == GotoKind::Continue
850
? NonLocalExitControl::Continue
851
: NonLocalExitControl::Break);
852
853
if (!nle.prepareForNonLocalJump(target)) {
854
return false;
855
}
856
857
return emitJump(JSOp::Goto, jumplist);
858
}
859
860
AbstractScope BytecodeEmitter::innermostScope() const {
861
return innermostEmitterScope()->scope(this);
862
}
863
864
bool BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) {
865
MOZ_ASSERT(checkStrictOrSloppy(op));
866
867
constexpr size_t OpLength = 1 + UINT32_INDEX_LEN;
868
MOZ_ASSERT(GetOpLength(op) == OpLength);
869
870
BytecodeOffset offset;
871
if (!emitCheck(op, OpLength, &offset)) {
872
return false;
873
}
874
875
jsbytecode* code = bytecodeSection().code(offset);
876
code[0] = jsbytecode(op);
877
SET_UINT32_INDEX(code, index);
878
bytecodeSection().updateDepth(offset);
879
return true;
880
}
881
882
bool BytecodeEmitter::emitAtomOp(JSOp op, JSAtom* atom,
883
ShouldInstrument shouldInstrument) {
884
MOZ_ASSERT(atom);
885
886
// .generator lookups should be emitted as JSOp::GetAliasedVar instead of
887
// JSOp::GetName etc, to bypass |with| objects on the scope chain.
888
// It's safe to emit .this lookups though because |with| objects skip
889
// those.
890
MOZ_ASSERT_IF(op == JSOp::GetName || op == JSOp::GetGName,
891
atom != cx->names().dotGenerator);
892
893
if (op == JSOp::GetProp && atom == cx->names().length) {
894
/* Specialize length accesses for the interpreter. */
895
op = JSOp::Length;
896
}
897
898
uint32_t index;
899
if (!makeAtomIndex(atom, &index)) {
900
return false;
901
}
902
903
return emitAtomOp(op, index, shouldInstrument);
904
}
905
906
bool BytecodeEmitter::emitAtomOp(JSOp op, uint32_t atomIndex,
907
ShouldInstrument shouldInstrument) {
908
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
909
910
if (shouldInstrument != ShouldInstrument::No &&
911
!emitInstrumentationForOpcode(op, atomIndex)) {
912
return false;
913
}
914
915
return emitIndexOp(op, atomIndex);
916
}
917
918
bool BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op) {
919
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
920
MOZ_ASSERT(index < perScriptData().gcThingList().length());
921
return emitIndexOp(op, index);
922
}
923
924
bool BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op) {
925
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
926
MOZ_ASSERT(index < perScriptData().gcThingList().length());
927
return emitIndexOp(op, index);
928
}
929
930
bool BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op) {
931
uint32_t index;
932
if (!perScriptData().gcThingList().append(objbox, &index)) {
933
return false;
934
}
935
936
return emitInternedObjectOp(index, op);
937
}
938
939
bool BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2,
940
JSOp op) {
941
uint32_t index1, index2;
942
if (!perScriptData().gcThingList().append(objbox1, &index1) ||
943
!perScriptData().gcThingList().append(objbox2, &index2)) {
944
return false;
945
}
946
947
return emitInternedObjectOp(index1, op);
948
}
949
950
bool BytecodeEmitter::emitRegExp(uint32_t index) {
951
return emitIndexOp(JSOp::RegExp, index);
952
}
953
954
bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
955
MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
956
MOZ_ASSERT(IsLocalOp(op));
957
958
BytecodeOffset off;
959
if (!emitN(op, LOCALNO_LEN, &off)) {
960
return false;
961
}
962
963
SET_LOCALNO(bytecodeSection().code(off), slot);
964
return true;
965
}
966
967
bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
968
MOZ_ASSERT(IsArgOp(op));
969
BytecodeOffset off;
970
if (!emitN(op, ARGNO_LEN, &off)) {
971
return false;
972
}
973
974
SET_ARGNO(bytecodeSection().code(off), slot);
975
return true;
976
}
977
978
bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
979
MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD);
980
981
constexpr size_t N = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
982
MOZ_ASSERT(GetOpLength(op) == 1 + N);
983
984
BytecodeOffset off;
985
if (!emitN(op, N, &off)) {
986
return false;
987
}
988
989
jsbytecode* pc = bytecodeSection().code(off);
990
SET_ENVCOORD_HOPS(pc, ec.hops());
991
pc += ENVCOORD_HOPS_LEN;
992
SET_ENVCOORD_SLOT(pc, ec.slot());
993
pc += ENVCOORD_SLOT_LEN;
994
return true;
995
}
996
997
JSOp BytecodeEmitter::strictifySetNameOp(JSOp op) {
998
switch (op) {
999
case JSOp::SetName:
1000
if (sc->strict()) {
1001
op = JSOp::StrictSetName;
1002
}
1003
break;
1004
case JSOp::SetGName:
1005
if (sc->strict()) {
1006
op = JSOp::StrictSetGName;
1007
}
1008
break;
1009
default:;
1010
}
1011
return op;
1012
}
1013
1014
bool BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) {
1015
if (!CheckRecursionLimit(cx)) {
1016
return false;
1017
}
1018
1019
restart:
1020
1021
switch (pn->getKind()) {
1022
// Trivial cases with no side effects.
1023
case ParseNodeKind::EmptyStmt:
1024
case ParseNodeKind::TrueExpr:
1025
case ParseNodeKind::FalseExpr:
1026
case ParseNodeKind::NullExpr:
1027
case ParseNodeKind::RawUndefinedExpr:
1028
case ParseNodeKind::Elision:
1029
case ParseNodeKind::Generator:
1030
MOZ_ASSERT(pn->is<NullaryNode>());
1031
*answer = false;
1032
return true;
1033
1034
case ParseNodeKind::ObjectPropertyName:
1035
case ParseNodeKind::PrivateName: // no side effects, unlike
1036
// ParseNodeKind::Name
1037
case ParseNodeKind::StringExpr:
1038
case ParseNodeKind::TemplateStringExpr:
1039
MOZ_ASSERT(pn->is<NameNode>());
1040
*answer = false;
1041
return true;
1042
1043
case ParseNodeKind::RegExpExpr:
1044
MOZ_ASSERT(pn->is<RegExpLiteral>());
1045
*answer = false;
1046
return true;
1047
1048
case ParseNodeKind::NumberExpr:
1049
MOZ_ASSERT(pn->is<NumericLiteral>());
1050
*answer = false;
1051
return true;
1052
1053
case ParseNodeKind::BigIntExpr:
1054
MOZ_ASSERT(pn->is<BigIntLiteral>());
1055
*answer = false;
1056
return true;
1057
1058
// |this| can throw in derived class constructors, including nested arrow
1059
// functions or eval.
1060
case ParseNodeKind::ThisExpr:
1061
MOZ_ASSERT(pn->is<UnaryNode>());
1062
*answer = sc->needsThisTDZChecks();
1063
return true;
1064
1065
// Trivial binary nodes with more token pos holders.
1066
case ParseNodeKind::NewTargetExpr:
1067
case ParseNodeKind::ImportMetaExpr: {
1068
MOZ_ASSERT(pn->as<BinaryNode>().left()->isKind(ParseNodeKind::PosHolder));
1069
MOZ_ASSERT(
1070
pn->as<BinaryNode>().right()->isKind(ParseNodeKind::PosHolder));
1071
*answer = false;
1072
return true;
1073
}
1074
1075
case ParseNodeKind::BreakStmt:
1076
MOZ_ASSERT(pn->is<BreakStatement>());
1077
*answer = true;
1078
return true;
1079
1080
case ParseNodeKind::ContinueStmt:
1081
MOZ_ASSERT(pn->is<ContinueStatement>());
1082
*answer = true;
1083
return true;
1084
1085
case ParseNodeKind::DebuggerStmt:
1086
MOZ_ASSERT(pn->is<DebuggerStatement>());
1087
*answer = true;
1088
return true;
1089
1090
// Watch out for getters!
1091
case ParseNodeKind::OptionalDotExpr:
1092
case ParseNodeKind::DotExpr:
1093
MOZ_ASSERT(pn->is<BinaryNode>());
1094
*answer = true;
1095
return true;
1096
1097
// Unary cases with side effects only if the child has them.
1098
case ParseNodeKind::TypeOfExpr:
1099
case ParseNodeKind::VoidExpr:
1100
case ParseNodeKind::NotExpr:
1101
return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
1102
1103
// Even if the name expression is effect-free, performing ToPropertyKey on
1104
// it might not be effect-free:
1105
//
1106
// RegExp.prototype.toString = () => { throw 42; };
1107
// ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
1108
//
1109
// function Q() {
1110
// ({ [new.target]: 0 });
1111
// }
1112
// Q.toString = () => { throw 17; };
1113
// new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
1114
case ParseNodeKind::ComputedName:
1115
MOZ_ASSERT(pn->is<UnaryNode>());
1116
*answer = true;
1117
return true;
1118
1119
// Looking up or evaluating the associated name could throw.
1120
case ParseNodeKind::TypeOfNameExpr:
1121
MOZ_ASSERT(pn->is<UnaryNode>());
1122
*answer = true;
1123
return true;
1124
1125
// This unary case has side effects on the enclosing object, sure. But
1126
// that's not the question this function answers: it's whether the
1127
// operation may have a side effect on something *other* than the result
1128
// of the overall operation in which it's embedded. The answer to that
1129
// is no, because an object literal having a mutated prototype only
1130
// produces a value, without affecting anything else.
1131
case ParseNodeKind::MutateProto:
1132
return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
1133
1134
// Unary cases with obvious side effects.
1135
case ParseNodeKind::PreIncrementExpr:
1136
case ParseNodeKind::PostIncrementExpr:
1137
case ParseNodeKind::PreDecrementExpr:
1138
case ParseNodeKind::PostDecrementExpr:
1139
case ParseNodeKind::ThrowStmt:
1140
MOZ_ASSERT(pn->is<UnaryNode>());
1141
*answer = true;
1142
return true;
1143
1144
// These might invoke valueOf/toString, even with a subexpression without
1145
// side effects! Consider |+{ valueOf: null, toString: null }|.
1146
case ParseNodeKind::BitNotExpr:
1147
case ParseNodeKind::PosExpr:
1148
case ParseNodeKind::NegExpr:
1149
MOZ_ASSERT(pn->is<UnaryNode>());
1150
*answer = true;
1151
return true;
1152
1153
// This invokes the (user-controllable) iterator protocol.
1154
case ParseNodeKind::Spread:
1155
MOZ_ASSERT(pn->is<UnaryNode>());
1156
*answer = true;
1157
return true;
1158
1159
case ParseNodeKind::InitialYield:
1160
case ParseNodeKind::YieldStarExpr:
1161
case ParseNodeKind::YieldExpr:
1162
case ParseNodeKind::AwaitExpr:
1163
MOZ_ASSERT(pn->is<UnaryNode>());
1164
*answer = true;
1165
return true;
1166
1167
// Deletion generally has side effects, even if isolated cases have none.
1168
case ParseNodeKind::DeleteNameExpr:
1169
case ParseNodeKind::DeletePropExpr:
1170
case ParseNodeKind::DeleteElemExpr:
1171
case ParseNodeKind::DeleteOptionalChainExpr:
1172
MOZ_ASSERT(pn->is<UnaryNode>());
1173
*answer = true;
1174
return true;
1175
1176
// Deletion of a non-Reference expression has side effects only through
1177
// evaluating the expression.
1178
case ParseNodeKind::DeleteExpr: {
1179
ParseNode* expr = pn->as<UnaryNode>().kid();
1180
return checkSideEffects(expr, answer);
1181
}
1182
1183
case ParseNodeKind::ExpressionStmt:
1184
return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
1185
1186
// Binary cases with obvious side effects.
1187
case ParseNodeKind::InitExpr:
1188
*answer = true;
1189
return true;
1190
1191
case ParseNodeKind::AssignExpr:
1192
case ParseNodeKind::AddAssignExpr:
1193
case ParseNodeKind::SubAssignExpr:
1194
case ParseNodeKind::BitOrAssignExpr:
1195
case ParseNodeKind::BitXorAssignExpr:
1196
case ParseNodeKind::BitAndAssignExpr:
1197
case ParseNodeKind::LshAssignExpr:
1198
case ParseNodeKind::RshAssignExpr:
1199
case ParseNodeKind::UrshAssignExpr:
1200
case ParseNodeKind::MulAssignExpr:
1201
case ParseNodeKind::DivAssignExpr:
1202
case ParseNodeKind::ModAssignExpr:
1203
case ParseNodeKind::PowAssignExpr:
1204
MOZ_ASSERT(pn->is<AssignmentNode>());
1205
*answer = true;
1206
return true;
1207
1208
case ParseNodeKind::SetThis:
1209
MOZ_ASSERT(pn->is<BinaryNode>());
1210
*answer = true;
1211
return true;
1212
1213
case ParseNodeKind::StatementList:
1214
// Strict equality operations and short circuit operators are well-behaved
1215
// and perform no conversions.
1216
case ParseNodeKind::CoalesceExpr:
1217
case ParseNodeKind::OrExpr:
1218
case ParseNodeKind::AndExpr:
1219
case ParseNodeKind::StrictEqExpr:
1220
case ParseNodeKind::StrictNeExpr:
1221
// Any subexpression of a comma expression could be effectful.
1222
case ParseNodeKind::CommaExpr:
1223
MOZ_ASSERT(!pn->as<ListNode>().empty());
1224
[[fallthrough]];
1225
// Subcomponents of a literal may be effectful.
1226
case ParseNodeKind::ArrayExpr:
1227
case ParseNodeKind::ObjectExpr:
1228
for (ParseNode* item : pn->as<ListNode>().contents()) {
1229
if (!checkSideEffects(item, answer)) {
1230
return false;
1231
}
1232
if (*answer) {
1233
return true;
1234
}
1235
}
1236
return true;
1237
1238
// Most other binary operations (parsed as lists in SpiderMonkey) may
1239
// perform conversions triggering side effects. Math operations perform
1240
// ToNumber and may fail invoking invalid user-defined toString/valueOf:
1241
// |5 < { toString: null }|. |instanceof| throws if provided a
1242
// non-object constructor: |null instanceof null|. |in| throws if given
1243
// a non-object RHS: |5 in null|.
1244
case ParseNodeKind::BitOrExpr:
1245
case ParseNodeKind::BitXorExpr:
1246
case ParseNodeKind::BitAndExpr:
1247
case ParseNodeKind::EqExpr:
1248
case ParseNodeKind::NeExpr:
1249
case ParseNodeKind::LtExpr:
1250
case ParseNodeKind::LeExpr:
1251
case ParseNodeKind::GtExpr:
1252
case ParseNodeKind::GeExpr:
1253
case ParseNodeKind::InstanceOfExpr:
1254
case ParseNodeKind::InExpr:
1255
case ParseNodeKind::LshExpr:
1256
case ParseNodeKind::RshExpr:
1257
case ParseNodeKind::UrshExpr:
1258
case ParseNodeKind::AddExpr:
1259
case ParseNodeKind::SubExpr:
1260
case ParseNodeKind::MulExpr:
1261
case ParseNodeKind::DivExpr:
1262
case ParseNodeKind::ModExpr:
1263
case ParseNodeKind::PowExpr:
1264
MOZ_ASSERT(pn->as<ListNode>().count() >= 2);
1265
*answer = true;
1266
return true;
1267
1268
case ParseNodeKind::PropertyDefinition:
1269
case ParseNodeKind::Case: {
1270
BinaryNode* node = &pn->as<BinaryNode>();
1271
if (!checkSideEffects(node->left(), answer)) {
1272
return false;
1273
}
1274
if (*answer) {
1275
return true;
1276
}
1277
return checkSideEffects(node->right(), answer);
1278
}
1279
1280
// More getters.
1281
case ParseNodeKind::OptionalElemExpr:
1282
case ParseNodeKind::ElemExpr:
1283
MOZ_ASSERT(pn->is<BinaryNode>());
1284
*answer = true;
1285
return true;
1286
1287
// These affect visible names in this code, or in other code.
1288
case ParseNodeKind::ImportDecl:
1289
case ParseNodeKind::ExportFromStmt:
1290
case ParseNodeKind::ExportDefaultStmt:
1291
MOZ_ASSERT(pn->is<BinaryNode>());
1292
*answer = true;
1293
return true;
1294
1295
// Likewise.
1296
case ParseNodeKind::ExportStmt:
1297
MOZ_ASSERT(pn->is<UnaryNode>());
1298
*answer = true;
1299
return true;
1300
1301
case ParseNodeKind::CallImportExpr:
1302
MOZ_ASSERT(pn->is<BinaryNode>());
1303
*answer = true;
1304
return true;
1305
1306
// Every part of a loop might be effect-free, but looping infinitely *is*
1307
// an effect. (Language lawyer trivia: C++ says threads can be assumed
1308
// to exit or have side effects, C++14 [intro.multithread]p27, so a C++
1309
// implementation's equivalent of the below could set |*answer = false;|
1310
// if all loop sub-nodes set |*answer = false|!)
1311
case ParseNodeKind::DoWhileStmt:
1312
case ParseNodeKind::WhileStmt:
1313
case ParseNodeKind::ForStmt:
1314
MOZ_ASSERT(pn->is<BinaryNode>());
1315
*answer = true;
1316
return true;
1317
1318
// Declarations affect the name set of the relevant scope.
1319
case ParseNodeKind::VarStmt:
1320
case ParseNodeKind::ConstDecl:
1321
case ParseNodeKind::LetDecl:
1322
MOZ_ASSERT(pn->is<ListNode>());
1323
*answer = true;
1324
return true;
1325
1326
case ParseNodeKind::IfStmt:
1327
case ParseNodeKind::ConditionalExpr: {
1328
TernaryNode* node = &pn->as<TernaryNode>();
1329
if (!checkSideEffects(node->kid1(), answer)) {
1330
return false;
1331
}
1332
if (*answer) {
1333
return true;
1334
}
1335
if (!checkSideEffects(node->kid2(), answer)) {
1336
return false;
1337
}
1338
if (*answer) {
1339
return true;
1340
}
1341
if ((pn = node->kid3())) {
1342
goto restart;
1343
}
1344
return true;
1345
}
1346
1347
// Function calls can invoke non-local code.
1348
case ParseNodeKind::NewExpr:
1349
case ParseNodeKind::CallExpr:
1350
case ParseNodeKind::OptionalCallExpr:
1351
case ParseNodeKind::TaggedTemplateExpr:
1352
case ParseNodeKind::SuperCallExpr:
1353
MOZ_ASSERT(pn->is<BinaryNode>());
1354
*answer = true;
1355
return true;
1356
1357
// Function arg lists can contain arbitrary expressions. Technically
1358
// this only causes side-effects if one of the arguments does, but since
1359
// the call being made will always trigger side-effects, it isn't needed.
1360
case ParseNodeKind::Arguments:
1361
MOZ_ASSERT(pn->is<ListNode>());
1362
*answer = true;
1363
return true;
1364
1365
case ParseNodeKind::OptionalChain:
1366
MOZ_ASSERT(pn->is<UnaryNode>());
1367
*answer = true;
1368
return true;
1369
1370
case ParseNodeKind::PipelineExpr:
1371
MOZ_ASSERT(pn->as<ListNode>().count() >= 2);
1372
*answer = true;
1373
return true;
1374
1375
// Classes typically introduce names. Even if no name is introduced,
1376
// the heritage and/or class body (through computed property names)
1377
// usually have effects.
1378
case ParseNodeKind::ClassDecl:
1379
MOZ_ASSERT(pn->is<ClassNode>());
1380
*answer = true;
1381
return true;
1382
1383
// |with| calls |ToObject| on its expression and so throws if that value
1384
// is null/undefined.
1385
case ParseNodeKind::WithStmt:
1386
MOZ_ASSERT(pn->is<BinaryNode>());
1387
*answer = true;
1388
return true;
1389
1390
case ParseNodeKind::ReturnStmt:
1391
MOZ_ASSERT(pn->is<BinaryNode>());
1392
*answer = true;
1393
return true;
1394
1395
case ParseNodeKind::Name:
1396
MOZ_ASSERT(pn->is<NameNode>());
1397
*answer = true;
1398
return true;
1399
1400
// Shorthands could trigger getters: the |x| in the object literal in
1401
// |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
1402
// one. (Of course, it isn't necessary to use |with| for a shorthand to
1403
// trigger a getter.)
1404
case ParseNodeKind::Shorthand:
1405
MOZ_ASSERT(pn->is<BinaryNode>());
1406
*answer = true;
1407
return true;
1408
1409
case ParseNodeKind::Function:
1410
MOZ_ASSERT(pn->is<FunctionNode>());
1411
/*
1412
* A named function, contrary to ES3, is no longer effectful, because
1413
* we bind its name lexically (using JSOp::Callee) instead of creating
1414
* an Object instance and binding a readonly, permanent property in it
1415
* (the object and binding can be detected and hijacked or captured).
1416
* This is a bug fix to ES3; it is fixed in ES3.1 drafts.
1417
*/
1418
*answer = false;
1419
return true;
1420
1421
case ParseNodeKind::Module:
1422
*answer = false;
1423
return true;
1424
1425
case ParseNodeKind::TryStmt: {
1426
TryNode* tryNode = &pn->as<TryNode>();
1427
if (!checkSideEffects(tryNode->body(), answer)) {
1428
return false;
1429
}
1430
if (*answer) {
1431
return true;
1432
}
1433
if (LexicalScopeNode* catchScope = tryNode->catchScope()) {
1434
if (!checkSideEffects(catchScope, answer)) {
1435
return false;
1436
}
1437
if (*answer) {
1438
return true;
1439
}
1440
}
1441
if (ParseNode* finallyBlock = tryNode->finallyBlock()) {
1442
if (!checkSideEffects(finallyBlock, answer)) {
1443
return false;
1444
}
1445
}
1446
return true;
1447
}
1448
1449
case ParseNodeKind::Catch: {
1450
BinaryNode* catchClause = &pn->as<BinaryNode>();
1451
if (ParseNode* name = catchClause->left()) {
1452
if (!checkSideEffects(name, answer)) {
1453
return false;
1454
}
1455
if (*answer) {
1456
return true;
1457
}
1458
}
1459
return checkSideEffects(catchClause->right(), answer);
1460
}
1461
1462
case ParseNodeKind::SwitchStmt: {
1463
SwitchStatement* switchStmt = &pn->as<SwitchStatement>();
1464
if (!checkSideEffects(&switchStmt->discriminant(), answer)) {
1465
return false;
1466
}
1467
return *answer ||
1468
checkSideEffects(&switchStmt->lexicalForCaseList(), answer);
1469
}
1470
1471
case ParseNodeKind::LabelStmt:
1472
return checkSideEffects(pn->as<LabeledStatement>().statement(), answer);
1473
1474
case ParseNodeKind::LexicalScope:
1475
return checkSideEffects(pn->as<LexicalScopeNode>().scopeBody(), answer);
1476
1477
// We could methodically check every interpolated expression, but it's
1478
// probably not worth the trouble. Treat template strings as effect-free
1479
// only if they don't contain any substitutions.
1480
case ParseNodeKind::TemplateStringListExpr: {
1481
ListNode* list = &pn->as<ListNode>();
1482
MOZ_ASSERT(!list->empty());
1483
MOZ_ASSERT((list->count() % 2) == 1,
1484
"template strings must alternate template and substitution "
1485
"parts");
1486
*answer = list->count() > 1;
1487
return true;
1488
}
1489
1490
// This should be unreachable but is left as-is for now.
1491
case ParseNodeKind::ParamsBody:
1492
*answer = true;
1493
return true;
1494
1495
case ParseNodeKind::ForIn: // by ParseNodeKind::For
1496
case ParseNodeKind::ForOf: // by ParseNodeKind::For
1497
case ParseNodeKind::ForHead: // by ParseNodeKind::For
1498
case ParseNodeKind::ClassMethod: // by ParseNodeKind::ClassDecl
1499
case ParseNodeKind::ClassField: // by ParseNodeKind::ClassDecl
1500
case ParseNodeKind::ClassNames: // by ParseNodeKind::ClassDecl
1501
case ParseNodeKind::ClassMemberList: // by ParseNodeKind::ClassDecl
1502
case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
1503
case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
1504
case ParseNodeKind::ExportBatchSpecStmt: // by ParseNodeKind::Export
1505
case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
1506
case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
1507
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
1508
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
1509
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
1510
case ParseNodeKind::PropertyNameExpr: // by ParseNodeKind::Dot
1511
MOZ_CRASH("handled by parent nodes");
1512
1513
case ParseNodeKind::LastUnused:
1514
case ParseNodeKind::Limit:
1515
MOZ_CRASH("invalid node kind");
1516
}
1517
1518
MOZ_CRASH(
1519
"invalid, unenumerated ParseNodeKind value encountered in "
1520
"BytecodeEmitter::checkSideEffects");
1521
}
1522
1523
bool BytecodeEmitter::isInLoop() {
1524
return findInnermostNestableControl<LoopControl>();
1525
}
1526
1527
bool BytecodeEmitter::checkSingletonContext() {
1528
return script->treatAsRunOnce() && !sc->isFunctionBox() && !isInLoop();
1529
}
1530
1531
bool BytecodeEmitter::checkRunOnceContext() {
1532
return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
1533
}
1534
1535
bool BytecodeEmitter::needsImplicitThis() {
1536
// Short-circuit if there is an enclosing 'with' scope.
1537
if (sc->inWith()) {
1538
return true;
1539
}
1540
1541
// Otherwise see if the current point is under a 'with'.
1542
for (EmitterScope* es = innermostEmitterScope(); es;
1543
es = es->enclosingInFrame()) {
1544
if (es->scope(this).kind() == ScopeKind::With) {
1545
return true;
1546
}
1547
}
1548
1549
return false;
1550
}
1551
1552
bool BytecodeEmitter::emitThisEnvironmentCallee() {
1553
// Get the innermost enclosing function that has a |this| binding.
1554
1555
// Directly load callee from the frame if possible.
1556
if (sc->isFunctionBox() && !sc->asFunctionBox()->isArrow()) {
1557
return emit1(JSOp::Callee);
1558
}
1559
1560
// We have to load the callee from the environment chain.
1561
unsigned numHops = 0;
1562
for (AbstractScopeIter si(innermostScope()); si; si++) {
1563
if (si.hasSyntacticEnvironment() &&
1564
si.abstractScope().is<FunctionScope>()) {
1565
if (!si.abstractScope().isArrow()) {
1566
break;
1567
}
1568
}
1569
if (si.abstractScope().hasEnvironment()) {
1570
numHops++;
1571
}
1572
}
1573
1574
static_assert(
1575
ENVCOORD_HOPS_LIMIT - 1 <= UINT8_MAX,
1576
"JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT");
1577
1578
// Note: we need to check numHops here because we don't call
1579
// checkEnvironmentChainLength in all cases (like 'eval').
1580
if (numHops >= ENVCOORD_HOPS_LIMIT - 1) {
1581
reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
1582
return false;
1583
}
1584
1585
return emit2(JSOp::EnvCallee, numHops);
1586
}
1587
1588
bool BytecodeEmitter::emitSuperBase() {
1589
if (!emitThisEnvironmentCallee()) {
1590
return false;
1591
}
1592
1593
return emit1(JSOp::SuperBase);
1594
}
1595
1596
void BytecodeEmitter::reportNeedMoreArgsError(ParseNode* pn,
1597
const char* errorName,
1598
const char* requiredArgs,
1599
const char* pluralizer,
1600
const ListNode* argsList) {
1601
char actualArgsStr[40];
1602
SprintfLiteral(actualArgsStr, "%u", argsList->count());
1603
reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, requiredArgs, pluralizer,
1604
actualArgsStr);
1605
}
1606
1607
void BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) {
1608
uint32_t offset = pn ? pn->pn_pos.begin : *scriptStartOffset;
1609
1610
va_list args;
1611
va_start(args, errorNumber);
1612
1613
parser->errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset),
1614
errorNumber, &args);
1615
1616
va_end(args);
1617
}
1618
1619
void BytecodeEmitter::reportError(const Maybe<uint32_t>& maybeOffset,
1620
unsigned errorNumber, ...) {
1621
uint32_t offset = maybeOffset ? *maybeOffset : *scriptStartOffset;
1622
1623
va_list args;
1624
va_start(args, errorNumber);
1625
1626
parser->errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset),
1627
errorNumber, &args);
1628
1629
va_end(args);
1630
}
1631
1632
bool BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber,
1633
...) {
1634
uint32_t offset = pn ? pn->pn_pos.begin : *scriptStartOffset;
1635
1636
va_list args;
1637
va_start(args, errorNumber);
1638
1639
bool result = parser->errorReporter().extraWarningWithNotesAtVA(
1640
nullptr, AsVariant(offset), errorNumber, &args);
1641
1642
va_end(args);
1643
return result;
1644
}
1645
1646
bool BytecodeEmitter::reportExtraWarning(const Maybe<uint32_t>& maybeOffset,
1647
unsigned errorNumber, ...) {
1648
uint32_t offset = maybeOffset ? *maybeOffset : *scriptStartOffset;
1649
1650
va_list args;
1651
va_start(args, errorNumber);
1652
1653
bool result = parser->errorReporter().extraWarningWithNotesAtVA(
1654
nullptr, AsVariant(offset), errorNumber, &args);
1655
1656
va_end(args);
1657
return result;
1658
}
1659
1660
bool BytecodeEmitter::emitNewInit() {
1661
const size_t len = 1 + UINT32_INDEX_LEN;
1662
BytecodeOffset offset;
1663
if (!emitCheck(JSOp::NewInit, len, &offset)) {
1664
return false;
1665
}
1666
1667
jsbytecode* code = bytecodeSection().code(offset);
1668
code[0] = jsbytecode(JSOp::NewInit);
1669
code[1] = 0;
1670
code[2] = 0;
1671
code[3] = 0;
1672
code[4] = 0;
1673
bytecodeSection().updateDepth(offset);
1674
return true;
1675
}
1676
1677
bool BytecodeEmitter::iteratorResultShape(uint32_t* shape) {
1678
// No need to do any guessing for the object kind, since we know exactly how
1679
// many properties we plan to have.
1680
gc::AllocKind kind = gc::GetGCObjectKind(2);
1681
RootedPlainObject obj(
1682
cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
1683
if (!obj) {
1684
return false;
1685
}
1686
1687
Rooted<jsid> value_id(cx, NameToId(cx->names().value));
1688
Rooted<jsid> done_id(cx, NameToId(cx->names().done));
1689
if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue,
1690
JSPROP_ENUMERATE)) {
1691
return false;
1692
}
1693
if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue,
1694
JSPROP_ENUMERATE)) {
1695
return false;
1696
}
1697
1698
ObjectBox* objbox = parser->newObjectBox(obj);
1699
if (!objbox) {
1700
return false;
1701
}
1702
1703
return perScriptData().gcThingList().append(objbox, shape);
1704
}
1705
1706
bool BytecodeEmitter::emitPrepareIteratorResult() {
1707
uint32_t shape;
1708
if (!iteratorResultShape(&shape)) {
1709
return false;
1710
}
1711
return emitIndexOp(JSOp::NewObject, shape);
1712
}
1713
1714
bool BytecodeEmitter::emitFinishIteratorResult(bool done) {
1715
uint32_t value_id;
1716
if (!makeAtomIndex(cx->names().value, &value_id)) {
1717
return false;
1718
}
1719
uint32_t done_id;
1720
if (!makeAtomIndex(cx->names().done, &done_id)) {
1721
return false;
1722
}
1723
1724
if (!emitAtomOp(JSOp::InitProp, value_id)) {
1725
return false;
1726
}
1727
if (!emit1(done ? JSOp::True : JSOp::False)) {
1728
return false;
1729
}
1730
if (!emitAtomOp(JSOp::InitProp, done_id)) {
1731
return false;
1732
}
1733
return true;
1734
}
1735
1736
bool BytecodeEmitter::emitGetNameAtLocation(Handle<JSAtom*> name,
1737
const NameLocation& loc) {
1738
NameOpEmitter noe(this, name, loc, NameOpEmitter::Kind::Get);
1739
if (!noe.emitGet()) {
1740
return false;
1741
}
1742
1743
return true;
1744
}
1745
1746
bool BytecodeEmitter::emitGetName(NameNode* name) {
1747
RootedAtom nameAtom(cx, name->name());
1748
return emitGetName(nameAtom);
1749
}
1750
1751
bool BytecodeEmitter::emitTDZCheckIfNeeded(HandleAtom name,
1752
const NameLocation& loc) {
1753
// Dynamic accesses have TDZ checks built into their VM code and should
1754
// never emit explicit TDZ checks.
1755
MOZ_ASSERT(loc.hasKnownSlot());
1756
MOZ_ASSERT(loc.isLexical());
1757
1758
Maybe<MaybeCheckTDZ> check =
1759
innermostTDZCheckCache->needsTDZCheck(this, name);
1760
if (!check) {
1761
return false;
1762
}
1763
1764
// We've already emitted a check in this basic block.
1765
if (*check == DontCheckTDZ) {
1766
return true;
1767
}
1768
1769
if (loc.kind() == NameLocation::Kind::FrameSlot) {
1770
if (!emitLocalOp(JSOp::CheckLexical, loc.frameSlot())) {
1771
return false;
1772
}
1773
} else {
1774
if (!emitEnvCoordOp(JSOp::CheckAliasedLexical,
1775
loc.environmentCoordinate())) {
1776
return false;
1777
}
1778
}
1779
1780
return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
1781
}