Files
palemoon27/js/src/frontend/BytecodeEmitter.h
T
roytam1 7adb8133f5 import changes from `dev' branch of rmottola/Arctic-Fox:
- missing bit of 989499 and some other files (23b0597ba6)
- Bug 1233666 - Remove hacks for getting frame pointer for x86/x64 gcc. r=glandium (bfe8f59916)
- Bug 1176266: In TimeStamp_posix.cpp, check for XP_LINUX instead of LINUX, and add missing #include, to allow strrchr usage. r=BenWa (56c725cffa)
- Bug 1167230 - Don't pack ProfileEntry on ARM. r=shu (89f880e0cb)
- Bug 1209779 - Ensure that all null elements are written when streaming profiler JSON; r=shu (2bae5addc6)
- missing bit of Bug 1141712 - Make LUL (55f1276545)
- Bug 1061800 - Add breakpad ids to profiler in Linux. r=BenWa (994fd1a941)
- Bug 829621 - Compute the breakpad-id for OS X. r=BenWa. (e129580174)
- missing of  Bug 938157 - Lightweight CFI/EXIDX (b355dc3140)
- Bug 1193838 - Allow ProfileGatherer to gather profiles from exiting processes. r=BenWa (5ab1a6a3c9)
- align some missing stuff (5ebecd2364)
- align some missing stuff (b8ff7aa361)
- Bug 1164315 - Update key fingerprint for bitbucket.org; r=me (c1a3fbd930)
- Bug 1178955 - Refactor config path selection; r=smacleod (89552bb0ac)
- Bug 1195445 - Update host key fingerprint for bugzilla.mozilla.org (3783541088)
- Bug 1218903 - Update bmo fingerprint. r=fubar, a=Tomcat (5b836fc585)
- Bug 1178955 - Print config path on failure; r=smacleod (f5499f3771)
- Bug 1185113 - Support setting more secure file permissions; r=smacleod (7dbf6b22fd)
- Bug 1184229 - Detect multiple version-control-tools repos in Mercurial config; r=smacleod (16c24072a9)
- Bug 978514 - mach mercurial-setup: Use mqext from the version-control-tools repo (1fa5765e8a)
- Bug 1178955 - Don't pass config paths to updater; r=smacleod (80fcb05121)
- Bug 1197527 - Don't unnecessarily attempt to create extensions directory in MercurialUpdater; r=gps (9b049c3ff8)
- Bug 1164812 - mach mercurial-setup: Always mark the v-c-t repo as needing update (bd631208bd)
- Bug 1197527 - Always clone version-control-tools in MercurialSetupWizard; r=gps (6990e8f589)
- Bug 1197527 - Consolidate obtaining hg path into mozversioncontrol.get_hg_path; r=gps (e0b029a8e9)
- Bug 1200458 - Skip permission check for .hgrc on Windows in hgsetup wizard. r=gps DONTBUILD (cc5b0d6daf)
- Bug 1168466 - Bump minimum Mercurial version; r=smacleod (7fde47cfbe)
- Bug 1185113 - Clarify language around Bugzilla credentials; r=smacleod (9166fdfbf9)
- Bug 1185112 - Don't prompt for Bugzilla username/password if cookies defined; r=smacleod (cd87c96823)
- Bug 1188931 - Fix hgsetup wizard. r=gps (68a6b46be4)
- Bug 1200461 - Prompt for Bugzilla API Key instead of password; r=smacleod (780fb5d85d)
- Bug 1228580 - ./mach mercurial-setup should use ~ to set up extension paths, not my literal home directory. r=gps (7a0c839880)
- Bug 1231192 - Mark Mercurial 3.5.2 as oldest non-legacy version; r=smacleod (8f69483333)
- Bug 1231192 - Bump some minimum Mercurial version; r=smacleod (916c56a852)
- Bug 1162093 - Add "push-to-try" from version-control-tools to the mercurial setup wizard prompt.;r=gps (d29c7cf63a)
- Bug 1168466 - Prompt to install bundleclone extension; r=smacleod (780ce90a08)
- Bug 1185557 - Print relevant config options; r=smacleod (2f3f7e0161)
- Bug 1231192 - Support clonebundles feature; r=smacleod (dcba1ccd34)
- Bug 1231192 - Offer to install hg wip; r=smacleod (c42ebce5c8)
- Bug 1231192 - Only install host fingerprints if not running secure Python+hg; r=smacleod (3154a2497b)
- Bug 1178955 - Error when semicolon comments are seen; r=smacleod (e1f7081bb6)
- Bug 1231989 - Prompt to install hgwatchman extension; r=ahal (0eddf0c1c8)
- Bug 1178955 - Print line number for parse errors; r=smacleod (5369468cf1)
- Bug 1185557 - Only prompt to install progress on Mercurial <3.5; r=smacleod (401f362265)
- Bug 1232747 - Check for ssl.SSLContext existence; r=dminor (d505b07c5c)
- Bug 1144629 - UnicodeDecodeError in ./mach mercurial-setup. r=gps, r=glandium (611d3ec83e)
- Bug 1216970 - Make the copying more obvious in ProfilerImpl::GetStacktrace. r=froydnj (085625e113)
- Bug 1190466 - tools/rb/find-leakers.pl re-written in Python r=mccr8 (4bfdcad13e)
- Bug 1116478 - Open web content handlers in the proper tab in e10s. r=billm (ff8e11f45e)
- Bug 1213437 - Less data copying when handling structured clones in MessageManager, r=baku (c4e2a13253)
- const-var (69d17f312d)
- Bug 1203090 - Ensure we always use '/' as the starting path separator for the DOM path of the Directorys initially returned by HTMLInputElement.getFilesAndDirectories. r=baku (1325bbc40c)
- Bug 1209975 - Stop using dom::Promise::MaybeRejectBrokenly() in GetDirectoryListingTask. r=baku (2106790950)
- Bug 1209924 - Implement a general filtering mechanism for Directory::GetFilesAndDirectories, and add filtering of sensitive files/directories. r=baku (27b4a26262)
- Force a repaint after DXGI device resets. (bug 1188019, r=bas) (09c999e6e5)
- Bug 1163911 - Make responsive images block the document load event while the load task is queued. r=jst (0ee0e3db79)
- Bug 1166138 - Make img srcset react to resize/viewport changes, r=jdm (91674519e6)
- Bug 1194893 - Pref for default file upload directory. r=smaug (ec6d33d983)
- bug 1116409: switch update server to sha2 cert; update in-tree pinning. r=rstrong,snorp,mfinkle,dkeeler (7c8f631f27)
- bug 1116409: fix cert pinning on backup cert for aus5.mozilla.org. r=typofix (3c690cbc6d)
- Bug 1167048 - Change default font for Thai script from serif to sans-serif. r=smontagu (15dc86c389)
- Bug 1205570 - fix up font prefs for x-math lang group. r=heycam (03f1820752)
- Bug 1071769: Use DrawTargetTiled on B2G. r=Bas (b80ce768f1)
- fix misspatch of 1149343 (541dd7aac8)
- Bug 1199766 - Disable ICE TCP SO gathering via user pref. r=bwc (80cdc9c662)
- Bug 1187472 - only log UDP and TCP candidate gathering failures. r=bwc (bc3dcb02d0)
- Bug 1190615 - Skip non-UDP STUN servers for UDP sockets. r=bwc (a2d1d914b5)
- Bug 1187775 - skip host and reflexive ICE candidates if relay-only. r=bwc (7e2cba1685)
- Bug 1185198 - use port 9 for TCP active candidates. r=bwc (0a89cb199d)
- Bug 1177921 - Fix typo in STUN server name. r=drno (1ad43ced6b)
- Bug 1178349 - Enable ice_unittests on desktop linux on CI. r=bwc (ce5ece8264)
- Bug 1189041 - Add option to only gather addresses for default route. r=bwc (3651f2ff06)
- Bug 1189040: add a whitelist for network interfaces to use with ICE/webrtc r=ekr (6f693af72c)
- Bug 1189198 - don't start STUN transactions with a protocol mis-match. r=mtseng (a3b410e2a8)
- Bug 1208096 - Handle various failure cases for TURN gathering better. r=drno (1d8e173448)
- Bug 1211389 - Make absolutely sure the relay->srflx pointer doesn't dangle. r=drno (d59b0bf08d)
- Bug 1215616: use base address for server rflx ICE candidates r=bwc (89d07331ac)
- Bug 1207451 - removed framing from multi_tcp API. r=bwc (317f40f490)
- Bug 1186590 - Part 1 - Enable interface prioritizer on all platforms. r=drno (036a69fdb3)
- Bug 1194019 - New defaults for gather tests. r=bwc (8343ceab56)
- Bug 1144933: Only check that remote candidate is loopback in TestLoopbackOnlySortOf. r=drno (1f53d824e4)
- Bug 1186590 - Part 2 - Move hard-coded interface priority list into nrinterfaceprioritizer, and simplify some functions. r=drno (9f20fad21b)
- Bug 1152137 - Part 1: Test case. r=ekr (6b50f06d90)
- Bug 1152137 - Part 2: Remove attributes that could not be initted properly instead of just freeing them. r=ekr (ccdf81294a)
- Bug 1200763 - Remove hard-coded STUN IP address from ice_unittest, and do a DNS lookup instead. r=drno (ae54a83363)
- Bug 1208176 - Part 1: Add a couple of interface names. r=drno (b7ead0b476)
- Bug 1208176 - Part 2: Add a one-sided trickle test case to ice_unittest. r=drno (ad6afedb1c)
- Bug 1037618 - Relax candidate verification for TCP. r=bwc (0cad14c89e)
- Bug 1208176 - Part 3: Be forgiving when we see prflx instead of host candidates in ice_unittest. r=drno (50bdec2ba3)
- Bug 1035428: Re-register writeable callback after partially servicing the send queue. r=drno (2fdb7880fa)
- Bug 1135753 - Mark some overridden virtual functions in WebRTC as MOZ_OVERRIDE; r=mt (97f451c97d)
- Bug 950660: Part 4: Bridge TCPSocketChild to nr_socket r=bwc,jdm (654587b321)
- Bug 971357: Log STUN responses at INFO instead of DEBUG. r=ekr (81b500df17)
- Bug 1006809 - update triggered check behavior to RFC 5245. r+bwc r=mjf (31b718b5e5)
- Bug 1208278 - improved STUN request timeout handling. r=bwc (cf470fb12f)
- Bug 1142964 - Fix ICE tiebreaker on Windows. r=bwc (0d2fd78252)
- Bug 1219557 - don't pair candidates from different reserved networks. r=mt r=bwc (24d3e5106c)
- Bug 1220441 - Improve gather trickle ice unit tests. r=bwc r=mjf (96f76c6c8c)
- Bug 1205421 - fix DNS resolution of STUN server in ice_unittest. r=bwc (5d5b153358)
- Bug 1206465 - removed ice_ctx from TestStunTcpServer. r=bwc (9a0df03894)
- ug 1008792 - Check for valid pointer before using. r=bwc (7660fd0a71)
- Bug 1233101 - Use MOZ_LIKELY in js_new etc to help branch prediction; r=terrence (31fb244734)
- Bug 1225565 - Fix module import cycle detection r=shu (370dc26ee8)
- Bug 1225558 - Improve module error messages r=shu (83b6038bb3)
- Bug 1225561 - Don't allow a module to export non-existent local bindings r=shu (41f065891a)
- Bug 1233124 - Remove mis-named duplicate typedefs for rooted import and export entries r=terrence (17a60bdb39)
- Bug 1208464 - Implement proposed ES7 functions Object.values and Object.entries. r=evilpie (615193d0fb)
- Bug 1226549 - added assert check for matches pointer in for prevent null dereference. r=hv1989 (d321ad0385)
- Bug 1232113 - "Make the format specifiers in JS_snprintf() invocations more portable". r=jcoppeard (7c58b79a53)
- Bug 1232446 - Re-enable method calls in SelfHosted code using new anti-content checks. (r=till) (ba7dc22ff8)
- Bug 1232159 - Stop using pseudo-Uint32Array in SelfHosted code. (r=till) (c325f8ff58)
- Bug 1226235 - Print file and line info for failing assert in self-hosted code. r=efaust (4a8d54d38b)
- fix misspatch (fca2efc1f1)
- Bug 1186003 - Switch automated builds to Gtk+3. r=mshal (658ad843b7)
- Bug 1181342 - tooltool manifests and build-clang config for clang 3.6 r=rail (6264b4df68)
- Bug 1181342 - Follow up to use the unpack feature of tooltool instead of setup.sh r=glandium (96bb3b2062)
- Bug 1181255 - Mozconfigs for tsan builds. r=glandium (19250f4cc1)
- Bug 1181255 - Get tsan builds on gtk3. r=glandium (e5ffd1c02f)
- Bug 1187664 - Create a fontconfig cache so that Firefox doesn't have to do it itself when run on build automation. r=mshal (8ce567bd4c)
- Bug 1188780 - Include debug symbols in gtk3 tooltool package. r=mshal (a5b573aa58)
- Bug 1188780: remove setup.sh invocations, as they fail outside the mock environment; r=glandium a=RyanVM (058e306cac)
- Bug 1178513 - Fix non-unified bustage. r=wchen (543d1e5497)
- Bug 1162789 - Add a comment explaining why mForm is not set to null during unlink (eaa2a82048)
- Bug 1189655 - Define MOZ_HAVE_CXX11_CONSTEXPR on VS2015 or later. r=Waldo (2d134e3b41)
- Bug 1231758 - Fix bogus assertion in BCE for Annex B function assignment. (r=jorendorff) (701b2530b9)
- Bug 1233100 - Ensure that derived constructor bad return value errors are thrown before leaving the containing block. (r=shu) (52f5bcf0a5)
- Bug 1232022, 1232449 - Address forgotten review nits and fix bogus error message. (rs=Waldo) (dfd9d5e388)
- Bug 1233121 - Refactor ObjectBox tracing r=terrence (876a140535)
- Bug 1231647 - Check for duplicate exported let and const in modules r=shu (99f53ad443)
2023-06-22 10:38:22 +08:00

667 lines
26 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef frontend_BytecodeEmitter_h
#define frontend_BytecodeEmitter_h
/*
* JS bytecode generation.
*/
#include "jscntxt.h"
#include "jsopcode.h"
#include "jsscript.h"
#include "frontend/ParseMaps.h"
#include "frontend/Parser.h"
#include "frontend/SharedContext.h"
#include "frontend/SourceNotes.h"
namespace js {
class ScopeObject;
namespace frontend {
class FullParseHandler;
class ObjectBox;
class ParseNode;
template <typename ParseHandler> class Parser;
class SharedContext;
class TokenStream;
class CGConstList {
Vector<Value> list;
public:
explicit CGConstList(ExclusiveContext* cx) : list(cx) {}
bool append(Value v) { MOZ_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
size_t length() const { return list.length(); }
void finish(ConstArray* array);
};
struct CGObjectList {
uint32_t length; /* number of emitted so far objects */
ObjectBox* lastbox; /* last emitted object */
CGObjectList() : length(0), lastbox(nullptr) {}
unsigned add(ObjectBox* objbox);
unsigned indexOf(JSObject* obj);
void finish(ObjectArray* array);
ObjectBox* find(uint32_t index);
};
struct CGTryNoteList {
Vector<JSTryNote> list;
explicit CGTryNoteList(ExclusiveContext* cx) : list(cx) {}
bool append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end);
size_t length() const { return list.length(); }
void finish(TryNoteArray* array);
};
struct CGBlockScopeNote : public BlockScopeNote
{
// The end offset. Used to compute the length; may need adjusting first if
// in the prologue.
uint32_t end;
// Is the start offset in the prologue?
bool startInPrologue;
// Is the end offset in the prologue?
bool endInPrologue;
};
struct CGBlockScopeList {
Vector<CGBlockScopeNote> list;
explicit CGBlockScopeList(ExclusiveContext* cx) : list(cx) {}
bool append(uint32_t scopeObject, uint32_t offset, bool inPrologue, uint32_t parent);
uint32_t findEnclosingScope(uint32_t index);
void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
size_t length() const { return list.length(); }
void finish(BlockScopeArray* array, uint32_t prologueLength);
};
struct CGYieldOffsetList {
Vector<uint32_t> list;
explicit CGYieldOffsetList(ExclusiveContext* cx) : list(cx) {}
bool append(uint32_t offset) { return list.append(offset); }
size_t length() const { return list.length(); }
void finish(YieldOffsetArray& array, uint32_t prologueLength);
};
struct LoopStmtInfo;
struct StmtInfoBCE;
// Use zero inline elements because these go on the stack and affect how many
// nested functions are possible.
typedef Vector<jsbytecode, 0> BytecodeVector;
typedef Vector<jssrcnote, 0> SrcNotesVector;
// This enum tells BytecodeEmitter::emitVariables and the destructuring
// methods how emit the given Parser::variables parse tree.
enum VarEmitOption {
// The normal case. Emit code to evaluate initializer expressions and
// assign them to local variables. Also emit JSOP_DEF{VAR,LET,CONST}
// opcodes in the prologue if the declaration occurs at toplevel.
InitializeVars,
// Emit only JSOP_DEFVAR opcodes, in the prologue, if necessary. This is
// used in one case: `for (var $BindingPattern in/of obj)`. If we're at
// toplevel, the variable(s) must be defined with JSOP_DEFVAR, but they're
// populated inside the loop, via emitAssignment.
DefineVars,
// Emit code to evaluate initializer expressions and leave those values on
// the stack. This is used to implement `for (let/const ...;;)` and
// deprecated `let` blocks.
PushInitialValues,
// Like InitializeVars, but bind using BINDVAR instead of
// BINDNAME/BINDGNAME. Only used for emitting declarations synthesized for
// Annex B block-scoped function semantics.
AnnexB,
};
struct BytecodeEmitter
{
SharedContext* const sc; /* context shared between parsing and bytecode generation */
ExclusiveContext* const cx;
BytecodeEmitter* const parent; /* enclosing function or global context */
Rooted<JSScript*> script; /* the JSScript we're ultimately producing */
Rooted<LazyScript*> lazyScript; /* the lazy script if mode is LazyFunction,
nullptr otherwise. */
struct EmitSection {
BytecodeVector code; /* bytecode */
SrcNotesVector notes; /* source notes, see below */
ptrdiff_t lastNoteOffset; /* code offset for last source note */
uint32_t currentLine; /* line number for tree-based srcnote gen */
uint32_t lastColumn; /* zero-based column index on currentLine of
last SRC_COLSPAN-annotated opcode */
EmitSection(ExclusiveContext* cx, uint32_t lineNum)
: code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0)
{}
};
EmitSection prologue, main, *current;
/* the parser */
Parser<FullParseHandler>* const parser;
HandleScript evalCaller; /* scripted caller info for eval and dbgapi */
StmtInfoStack<StmtInfoBCE> stmtStack;
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
unsigned firstLine; /* first line, for JSScript::initFromEmitter */
/*
* Only unaliased locals have stack slots assigned to them. This vector is
* used to map a local index (which includes unaliased and aliased locals)
* to its stack slot index.
*/
Vector<uint32_t, 16> localsToFrameSlots_;
int32_t stackDepth; /* current stack depth in script frame */
uint32_t maxStackDepth; /* maximum stack depth so far */
uint32_t arrayCompDepth; /* stack depth of array in comprehension */
unsigned emitLevel; /* emitTree recursion level */
CGConstList constList; /* constants to be included with the script */
CGObjectList objectList; /* list of emitted objects */
CGObjectList regexpList; /* list of emitted regexp that will be
cloned during execution */
CGTryNoteList tryNoteList; /* list of emitted try notes */
CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
/*
* For each yield op, map the yield index (stored as bytecode operand) to
* the offset of the next op.
*/
CGYieldOffsetList yieldOffsetList;
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
bool hasSingletons:1; /* script contains singleton initializer JSOP_OBJECT */
bool hasTryFinally:1; /* script contains finally block */
bool emittingForInit:1; /* true while emitting init expr of for; exclude 'in' */
bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only
expected to run once. */
bool isRunOnceLambda();
bool insideEval:1; /* True if compiling an eval-expression or a function
nested inside an eval. */
const bool insideNonGlobalEval:1; /* True if this is a direct eval
call in some non-global scope. */
bool insideModule:1; /* True if compiling inside a module. */
enum EmitterMode {
Normal,
/*
* Emit JSOP_GETINTRINSIC instead of JSOP_GETNAME and assert that
* JSOP_GETNAME and JSOP_*GNAME don't ever get emitted. See the comment
* for the field |selfHostingMode| in Parser.h for details.
*/
SelfHosting,
/*
* Check the static scope chain of the root function for resolving free
* variable accesses in the script.
*/
LazyFunction
};
const EmitterMode emitterMode;
/*
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
* space above their tempMark points. This means that you cannot alloc from
* tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
* destruction.
*/
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
HandleScript script, Handle<LazyScript*> lazyScript,
bool insideEval, HandleScript evalCaller,
bool insideNonGlobalEval, uint32_t lineNum, EmitterMode emitterMode = Normal);
bool init();
bool updateLocalsToFrameSlots();
StmtInfoBCE* innermostStmt() const { return stmtStack.innermost(); }
StmtInfoBCE* innermostScopeStmt() const { return stmtStack.innermostScopeStmt(); }
JSObject* innermostStaticScope() const;
JSObject* blockScopeOfDef(Definition* dn) const {
return parser->blockScopes[dn->pn_blockid];
}
bool atBodyLevel(StmtInfoBCE* stmt) const;
bool atBodyLevel() const {
return atBodyLevel(innermostStmt());
}
uint32_t computeHops(ParseNode* pn, BytecodeEmitter** bceOfDefOut);
bool isAliasedName(BytecodeEmitter* bceOfDef, ParseNode* pn);
bool computeDefinitionIsAliased(BytecodeEmitter* bceOfDef, Definition* dn, JSOp* op);
MOZ_ALWAYS_INLINE
bool makeAtomIndex(JSAtom* atom, jsatomid* indexp) {
AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
if (p) {
*indexp = p.value();
return true;
}
jsatomid index = atomIndices->count();
if (!atomIndices->add(p, atom, index))
return false;
*indexp = index;
return true;
}
bool isInLoop();
bool checkSingletonContext();
// Check whether our function is in a run-once context (a toplevel
// run-one script or a run-once lambda).
bool checkRunOnceContext();
bool needsImplicitThis();
void tellDebuggerAboutCompiledScript(ExclusiveContext* cx);
inline TokenStream* tokenStream();
BytecodeVector& code() const { return current->code; }
jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; }
ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
ptrdiff_t prologueOffset() const { return prologue.code.end() - prologue.code.begin(); }
void switchToMain() { current = &main; }
void switchToPrologue() { current = &prologue; }
bool inPrologue() const { return current == &prologue; }
SrcNotesVector& notes() const { return current->notes; }
ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
unsigned currentLine() const { return current->currentLine; }
unsigned lastColumn() const { return current->lastColumn; }
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
// If pn contains a useful expression, return true with *answer set to true.
// If pn contains a useless expression, return true with *answer set to
// false. Return false on error.
//
// The caller should initialize *answer to false and invoke this function on
// an expression statement or similar subtree to decide whether the tree
// could produce code that has any side effects. For an expression
// statement, we define useless code as code with no side effects, because
// the main effect, the value left on the stack after the code executes,
// will be discarded by a pop bytecode.
bool checkSideEffects(ParseNode* pn, bool* answer);
#ifdef DEBUG
bool checkStrictOrSloppy(JSOp op);
#endif
// Append a new source note of the given type (and therefore size) to the
// notes dynamic array, updating noteCount. Return the new note's index
// within the array pointed at by current->notes as outparam.
bool newSrcNote(SrcNoteType type, unsigned* indexp = nullptr);
bool newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned* indexp = nullptr);
bool newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2,
unsigned* indexp = nullptr);
void copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes);
bool setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset);
// NB: this function can add at most one extra extended delta note.
bool addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta);
// Finish taking source notes in cx's notePool. If successful, the final
// source note count is stored in the out outparam.
bool finishTakingSrcNotes(uint32_t* out);
void setJumpOffsetAt(ptrdiff_t off);
// Control whether emitTree emits a line number note.
enum EmitLineNumberNote {
EMIT_LINENOTE,
SUPPRESS_LINENOTE
};
// Emit code for the tree rooted at pn.
bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
// Emit function code for the tree rooted at body.
bool emitFunctionScript(ParseNode* body);
// Emit module code for the tree rooted at body.
bool emitModuleScript(ParseNode* body);
// If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
// reserve a type set to store its result.
void checkTypeSet(JSOp op);
void updateDepth(ptrdiff_t target);
bool updateLineNumberNotes(uint32_t offset);
bool updateSourceCoordNotes(uint32_t offset);
bool bindNameToSlot(ParseNode* pn);
bool bindNameToSlotHelper(ParseNode* pn);
void strictifySetNameNode(ParseNode* pn);
JSOp strictifySetNameOp(JSOp op);
bool tryConvertFreeName(ParseNode* pn);
void popStatement();
void pushStatement(StmtInfoBCE* stmt, StmtType type, ptrdiff_t top);
void pushStatementInner(StmtInfoBCE* stmt, StmtType type, ptrdiff_t top);
void pushLoopStatement(LoopStmtInfo* stmt, StmtType type, ptrdiff_t top);
bool enterNestedScope(StmtInfoBCE* stmt, ObjectBox* objbox, StmtType stmtType);
bool leaveNestedScope(StmtInfoBCE* stmt);
bool enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp initialValueOp,
unsigned alreadyPushed = 0);
bool computeAliasedSlots(Handle<StaticBlockObject*> blockObj);
bool lookupAliasedName(HandleScript script, PropertyName* name, uint32_t* pslot,
ParseNode* pn = nullptr);
bool lookupAliasedNameSlot(PropertyName* name, ScopeCoordinate* sc);
// In a function, block-scoped locals go after the vars, and form part of the
// fixed part of a stack frame. Outside a function, there are no fixed vars,
// but block-scoped locals still form part of the fixed part of a stack frame
// and are thus addressable via GETLOCAL and friends.
void computeLocalOffset(Handle<StaticBlockObject*> blockObj);
bool flushPops(int* npops);
bool emitCheck(ptrdiff_t delta, ptrdiff_t* offset);
// Emit one bytecode.
bool emit1(JSOp op);
// Emit two bytecodes, an opcode (op) with a byte of immediate operand
// (op1).
bool emit2(JSOp op, uint8_t op1);
// Emit three bytecodes, an opcode with two bytes of immediate operands.
bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
// Helper to emit JSOP_DUPAT. The argument is the value's depth on the
// JS stack, as measured from the top.
bool emitDupAt(unsigned slotFromTop);
// Emit a bytecode followed by an uint16 immediate operand stored in
// big-endian order.
bool emitUint16Operand(JSOp op, uint32_t operand);
// Emit a bytecode followed by an uint32 immediate operand.
bool emitUint32Operand(JSOp op, uint32_t operand);
// Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
bool emitN(JSOp op, size_t extra, ptrdiff_t* offset = nullptr);
bool emitNumberOp(double dval);
bool emitThisLiteral(ParseNode* pn);
bool emitCreateFunctionThis();
bool emitGetFunctionThis(ParseNode* pn);
bool emitGetThisForSuperBase(ParseNode* pn);
bool emitSetThis(ParseNode* pn);
// These functions are used to emit GETLOCAL/GETALIASEDVAR or
// SETLOCAL/SETALIASEDVAR for a particular binding. The CallObject must be
// on top of the scope chain.
bool emitLoadFromTopScope(BindingIter& bi);
bool emitStoreToTopScope(BindingIter& bi);
bool emitJump(JSOp op, ptrdiff_t off, ptrdiff_t* jumpOffset = nullptr);
bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr);
bool emitLoopHead(ParseNode* nextpn);
bool emitLoopEntry(ParseNode* nextpn);
// Emit a backpatch op with offset pointing to the previous jump of this
// type, so that we can walk back up the chain fixing up the op and jump
// offset.
bool emitBackPatchOp(ptrdiff_t* lastp);
void backPatch(ptrdiff_t last, jsbytecode* target, jsbytecode op);
bool emitGoto(StmtInfoBCE* toStmt, ptrdiff_t* lastp, SrcNoteType noteType = SRC_NULL);
bool emitIndex32(JSOp op, uint32_t index);
bool emitIndexOp(JSOp op, uint32_t index);
bool emitAtomOp(JSAtom* atom, JSOp op);
bool emitAtomOp(ParseNode* pn, JSOp op);
bool emitArrayLiteral(ParseNode* pn);
bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
bool emitArrayComp(ParseNode* pn);
bool emitInternedObjectOp(uint32_t index, JSOp op);
bool emitObjectOp(ObjectBox* objbox, JSOp op);
bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
bool emitRegExp(uint32_t index);
MOZ_NEVER_INLINE bool emitFunction(ParseNode* pn, bool needsProto = false);
MOZ_NEVER_INLINE bool emitObject(ParseNode* pn);
bool emitHoistedFunctionsInList(ParseNode* pn);
bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type);
// To catch accidental misuse, emitUint16Operand/emit3 assert that they are
// not used to unconditionally emit JSOP_GETLOCAL. Variable access should
// instead be emitted using EmitVarOp. In special cases, when the caller
// definitely knows that a given local slot is unaliased, this function may be
// used as a non-asserting version of emitUint16Operand.
bool emitLocalOp(JSOp op, uint32_t slot);
bool emitScopeCoordOp(JSOp op, ScopeCoordinate sc);
bool emitAliasedVarOp(JSOp op, ParseNode* pn);
bool emitAliasedVarOp(JSOp op, ScopeCoordinate sc, MaybeCheckLexical checkLexical);
bool emitUnaliasedVarOp(JSOp op, uint32_t slot, MaybeCheckLexical checkLexical);
bool emitVarOp(ParseNode* pn, JSOp op);
bool emitVarIncDec(ParseNode* pn);
bool emitNameOp(ParseNode* pn, bool callContext);
bool emitNameIncDec(ParseNode* pn);
bool maybeEmitVarDecl(JSOp prologueOp, ParseNode* pn, jsatomid* result);
bool emitVariables(ParseNode* pn, VarEmitOption emitOption);
bool emitSingleVariable(ParseNode* pn, ParseNode* binding, ParseNode* initializer,
VarEmitOption emitOption);
bool emitNewInit(JSProtoKey key);
bool emitSingletonInitialiser(ParseNode* pn);
bool emitPrepareIteratorResult();
bool emitFinishIteratorResult(bool done);
bool iteratorResultShape(unsigned* shape);
bool emitYield(ParseNode* pn);
bool emitYieldOp(JSOp op);
bool emitYieldStar(ParseNode* iter, ParseNode* gen);
bool emitPropLHS(ParseNode* pn);
bool emitPropOp(ParseNode* pn, JSOp op);
bool emitPropIncDec(ParseNode* pn);
bool emitComputedPropertyName(ParseNode* computedPropName);
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
// opcode onto the stack in the right order. In the case of SETELEM, the
// value to be assigned must already be pushed.
enum class EmitElemOption { Get, Set, Call, IncDec };
bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
bool emitElemOpBase(JSOp op);
bool emitElemOp(ParseNode* pn, JSOp op);
bool emitElemIncDec(ParseNode* pn);
bool emitCatch(ParseNode* pn);
bool emitIf(ParseNode* pn);
bool emitWith(ParseNode* pn);
MOZ_NEVER_INLINE bool emitLabeledStatement(const LabeledStatement* pn);
MOZ_NEVER_INLINE bool emitLetBlock(ParseNode* pnLet);
MOZ_NEVER_INLINE bool emitLexicalScope(ParseNode* pn);
MOZ_NEVER_INLINE bool emitSwitch(ParseNode* pn);
MOZ_NEVER_INLINE bool emitTry(ParseNode* pn);
// EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
// the stack and emits code to destructure a single lhs expression (either a
// name or a compound []/{} expression).
//
// If emitOption is InitializeVars, the to-be-destructured value is assigned to
// locals and ultimately the initial slot is popped (-1 total depth change).
//
// If emitOption is PushInitialValues, the to-be-destructured value is replaced
// with the initial values of the N (where 0 <= N) variables assigned in the
// lhs expression. (Same post-condition as EmitDestructuringOpsHelper)
bool emitDestructuringLHS(ParseNode* target, VarEmitOption emitOption);
bool emitDestructuringOps(ParseNode* pattern, bool isLet = false);
bool emitDestructuringOpsHelper(ParseNode* pattern, VarEmitOption emitOption);
bool emitDestructuringOpsArrayHelper(ParseNode* pattern, VarEmitOption emitOption);
bool emitDestructuringOpsObjectHelper(ParseNode* pattern, VarEmitOption emitOption);
typedef bool
(*DestructuringDeclEmitter)(BytecodeEmitter* bce, JSOp prologueOp, ParseNode* pn);
template <DestructuringDeclEmitter EmitName>
bool emitDestructuringDeclsWithEmitter(JSOp prologueOp, ParseNode* pattern);
bool emitDestructuringDecls(JSOp prologueOp, ParseNode* pattern);
// Emit code to initialize all destructured names to the value on the top of
// the stack.
bool emitInitializeDestructuringDecls(JSOp prologueOp, ParseNode* pattern);
// Throw a TypeError if the value atop the stack isn't convertible to an
// object, with no overall effect on the stack.
bool emitRequireObjectCoercible();
// emitIterator expects the iterable to already be on the stack.
// It will replace that stack value with the corresponding iterator
bool emitIterator();
// Pops iterator from the top of the stack. Pushes the result of |.next()|
// onto the stack.
bool emitIteratorNext(ParseNode* pn);
// Check if the value on top of the stack is "undefined". If so, replace
// that value on the stack with the value defined by |defaultExpr|.
bool emitDefault(ParseNode* defaultExpr);
bool emitCallSiteObject(ParseNode* pn);
bool emitTemplateString(ParseNode* pn);
bool emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs);
bool emitReturn(ParseNode* pn);
bool emitStatement(ParseNode* pn);
bool emitStatementList(ParseNode* pn);
bool emitDeleteName(ParseNode* pn);
bool emitDeleteProperty(ParseNode* pn);
bool emitDeleteElement(ParseNode* pn);
bool emitDeleteExpression(ParseNode* pn);
// |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
bool emitTypeof(ParseNode* node, JSOp op);
bool emitUnary(ParseNode* pn);
bool emitRightAssociative(ParseNode* pn);
bool emitLeftAssociative(ParseNode* pn);
bool emitLogical(ParseNode* pn);
bool emitSequenceExpr(ParseNode* pn);
MOZ_NEVER_INLINE bool emitIncOrDec(ParseNode* pn);
bool emitConditionalExpression(ConditionalExpression& conditional);
bool emitCallOrNew(ParseNode* pn);
bool emitDebugOnlyCheckSelfHosted();
bool emitSelfHostedCallFunction(ParseNode* pn);
bool emitSelfHostedResumeGenerator(ParseNode* pn);
bool emitSelfHostedForceInterpreter(ParseNode* pn);
bool emitComprehensionFor(ParseNode* compFor);
bool emitComprehensionForIn(ParseNode* pn);
bool emitComprehensionForInOrOfVariables(ParseNode* pn, bool* letBlockScope);
bool emitComprehensionForOf(ParseNode* pn);
bool emitDo(ParseNode* pn);
bool emitFor(ParseNode* pn);
bool emitForIn(ParseNode* pn);
bool emitForInOrOfVariables(ParseNode* pn);
bool emitCStyleFor(ParseNode* pn);
bool emitWhile(ParseNode* pn);
bool emitBreak(PropertyName* label);
bool emitContinue(PropertyName* label);
bool emitArgsBody(ParseNode* pn);
bool emitDefaultsAndDestructuring(ParseNode* pn);
bool emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp);
bool pushInitialConstants(JSOp op, unsigned n);
bool initializeBlockScopedLocalsFromStack(Handle<StaticBlockObject*> blockObj);
// emitSpread expects the current index (I) of the array, the array itself
// and the iterator to be on the stack in that order (iterator on the bottom).
// It will pop the iterator and I, then iterate over the iterator by calling
// |.next()| and put the results into the I-th element of array with
// incrementing I, then push the result I (it will be original I +
// iteration count). The stack after iteration will look like |ARRAY INDEX|.
bool emitSpread();
// If type is StmtType::FOR_OF_LOOP, emit bytecode for a for-of loop.
// pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
//
// If type is StmtType::SPREAD, emit bytecode for spread operator.
// pn should be nullptr.
//
// Please refer the comment above emitSpread for additional information about
// stack convention.
bool emitForOf(StmtType type, ParseNode* pn);
bool emitClass(ParseNode* pn);
bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
bool emitSuperElemOperands(ParseNode* pn, EmitElemOption opts = EmitElemOption::Get);
bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
};
} /* namespace frontend */
} /* namespace js */
#endif /* frontend_BytecodeEmitter_h */