Files
palemoon27/js/src/jit/BytecodeAnalysis.cpp
T
roytam1 3931475e3b import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1071646 - Light refactoring of lexical binding helpers in Parser. (r=jorendorff) (08dd35a4aa)
- Bug 1230710 - Reenable direct eval and arrow functions in derived class constructors. (r=jorendorff, r=shu) (8767ca1400)
- Bug 1071646 - Make functions block-scoped in JS and implement Annex B semantics for compatibility. (r=jorendorff) (3a4b960615)
- Bug 1071646 - Support labelled function declarations in sloppy mode per Annex B.3.2. (r=jorendorff) (7688ce37ca)
- Bug 1071646 - Introduce JSOP_BINDVAR to support Annex B.3.3.3. (r=jorendorff) (6f19a9c7c9)
- Bug 1071646 - Cast ParseNode to Definition using as<T>. (r=jorendorff) (c96ca0203c)
- Bug 1071646 - Support JSOP_BINDVAR in Baseline. (r=jandem) (d7912d6cd7)
- Bug 1071646 - Support JSOP_BINDVAR in Ion. (r=jandem) (9c76c0f995)
- Bug 1227677 - Emit code for PNK_COMPREHENSIONFOR using separate code from that used for for-loops. r=shu (d565e9e21d)
- Bug 1227677 - Minor renaming. r=shu (ec3a477823)
- Bug 1227677 - Rename the misnomer |letDecl| variable associated with for-in/of loop variables to |letBlockScope|, as that's much closer to its actual meaning. (Notably, |for (let x of []);| does *not* mean |*letDecl|.) r=shu (c9feaa68c2)
- Bug 1227677 - Simplify code in light of the fact that for-in/of loops never have a PNK_LEXICALSCOPE declaration node and therefore never have a letBlockScope requiring pushing and popping. r=shu (19ff248532)
- Bug 1225298 - Use GCHashSet for SavedStack set of frames, r=terrence (9ed6c0f4c3)
- Bug 1225474: Ensure we only ever seed the js::SavedStacks PRNG state with valid states. r=fitzgen (99c858644b)
- Bug 1230162 - allocate less, when we can. r=luke (563337bc70)
- Bug 1225298 - Use GCHashSet for SymbolRegistry, r=terrence (4d0cfc2931)
- Bug 1227028: TraceLogger - Fix when to keep the payload of a TraceLogger event, r=bbouvier (cb3bea30fc)
- Bug 1228238 - "TraceLogger: don't enable tracelogger unless TLOPTIONS is set". r=hv1989 (c9d56ad367)
- Bug 1224809 - "TraceLogger: Document what are enabled in 'TLLOG=Default' and 'TLLOG=IonCompiler'". r=hv1989 (64b6ebceea)
- Bug 1223767 - "TraceLogger: Assertion failure: i < size_, at js/src/vm/TraceLoggingTypes.h:210". r=hv1989 (1b50e8acb7)
- Bug 1227914: TraceLogger - Limit the memory tracelogger can take, r=bbouvier (458da9b2f7)
- Bug 1259403 - Tracelogger: Only increase capacity by multiples of 2, r=bbouvier (1e4bf23eab)
- Bug 1225346 - Fix parseModule() error handling r=terrence (b100c793dc)
- bug 1224308 - Remove some Makefile cruft. r=gps (f094c44df9)
- Bug 1217911 - Use correct scope when bailing out a module script r=shu (c4f39cf294)
- Bug 1230039 - IonMonkey: MIPS: Implement cacheFlush for Loongson3. r=jandem (01c5af81f2)
- Bug 922406 - Ion-compile global scripts that use 'this'. r=shu (cb66effddf)
- Bug 1227567 - Add Ion cache for module namepsace imports r=shu (72f4a4e971)
- Bug 1216107 - Remove bogus assert. (r=arai) (bad84d1795)
- Bug 1225367 - Fix bogus asserts when storing symbols to typed arrays. r=h4writer (0220c4ca3b)
- Bug 1226188 - Define the DEFINED_ON_DISPATCH_RESULT macro such that it can be called with no arguments as well as with one argument. r=nbp (69138260f3)
- Bug 1227567 - Add baseline IC to optimise module namespace imports r=shu (692aaf3e8a)
- Bug 1226816: SharedStubs - Don't enable the call scripted get prop shared stub in ionmonkey yet, r=jandem (b71ff142f4)
- Bug 1229396: Templatize get{Float,Double,SimdData}; r=jandem (3b75e4e4ff)
- Bug 1229396: Templatize constants merging in the shared x86 masm; r=jandem (d32cdb2b1b)
- Bug 1229396: Templatize Float/Double/SimdData in MacroAssembler-x86-shared.h; r=jandem (0ae16c027a)
- Bug 1229396: Propagate OOM when pushing elements to the uses array; r=jandem (8ddb05d926)
- bits of  Backed out 2 changesets (bug 1229604) (1285191abd)
- Bug 1229821 - IonMonkey: MIPS: Fix merge macro assemblers. r=bbouvier (078b702c7d)
- Bug 1230404 - IonMonkey: MIPS32: Fix load32(wasm::SymbolicAddress, Register). r=bbouvier (c7861440e2)
- Bug 1213165 - IonMonkey: MIPS32: Fix ion/bug901086.js failed. r=nbp f=rankov (63d3f07b39)
- Bug 1230403 - IonMonkey: MIPS: Add add64 to mips32. r=arai (105e49c927)
- Bug 1208259 - ARM64: Handle an empty nursery in branchValueIsNurseryObject(). r=bhackett (95d6a15432)
- Bug 1207827 - Fix OOM error in ARM64 simulator. r=nbp (076d2a5a5e)
- Bug 1204700 - ARM: Use a different scratch register for store32. r=sstangl (b6e70c4d26)
- Bug 1221359 - Fix ARM assembler assertion that doesn't hold if we are OOM r=jolesen (7e79f2b4f9)
- No bug. Remove some long obsolete files. r=woof! (c95a1f341b)
2023-05-29 11:32:23 +08:00

228 lines
7.5 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/. */
#include "jit/BytecodeAnalysis.h"
#include "jsopcode.h"
#include "jit/JitSpewer.h"
#include "jsopcodeinlines.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::jit;
BytecodeAnalysis::BytecodeAnalysis(TempAllocator& alloc, JSScript* script)
: script_(script),
infos_(alloc),
usesScopeChain_(false),
hasTryFinally_(false),
hasSetArg_(false)
{
}
// Bytecode range containing only catch or finally code.
struct CatchFinallyRange
{
uint32_t start; // Inclusive.
uint32_t end; // Exclusive.
CatchFinallyRange(uint32_t start, uint32_t end)
: start(start), end(end)
{
MOZ_ASSERT(end > start);
}
bool contains(uint32_t offset) const {
return start <= offset && offset < end;
}
};
bool
BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
{
if (!infos_.growByUninitialized(script_->length()))
return false;
// Initialize the scope chain slot if either the function needs a CallObject
// or the script uses the scope chain. The latter case is handled below.
usesScopeChain_ = script_->module() ||
(script_->functionDelazifying() &&
script_->functionDelazifying()->needsCallObject());
MOZ_ASSERT_IF(script_->hasAnyAliasedBindings(), usesScopeChain_);
jsbytecode* end = script_->codeEnd();
// Clear all BytecodeInfo.
mozilla::PodZero(infos_.begin(), infos_.length());
infos_[0].init(/*stackDepth=*/0);
Vector<CatchFinallyRange, 0, JitAllocPolicy> catchFinallyRanges(alloc);
jsbytecode* nextpc;
for (jsbytecode* pc = script_->code(); pc < end; pc = nextpc) {
JSOp op = JSOp(*pc);
nextpc = pc + GetBytecodeLength(pc);
unsigned offset = script_->pcToOffset(pc);
JitSpew(JitSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
int(script_->pcToOffset(pc)), int(script_->length()), CodeName[op]);
// If this bytecode info has not yet been initialized, it's not reachable.
if (!infos_[offset].initialized)
continue;
unsigned stackDepth = infos_[offset].stackDepth;
#ifdef DEBUG
for (jsbytecode* chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
MOZ_ASSERT(!infos_[script_->pcToOffset(chkpc)].initialized);
#endif
unsigned nuses = GetUseCount(script_, offset);
unsigned ndefs = GetDefCount(script_, offset);
MOZ_ASSERT(stackDepth >= nuses);
stackDepth -= nuses;
stackDepth += ndefs;
// If stack depth exceeds max allowed by analysis, fail fast.
MOZ_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
switch (op) {
case JSOP_TABLESWITCH: {
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
int32_t low = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
int32_t high = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
infos_[defaultOffset].init(stackDepth);
infos_[defaultOffset].jumpTarget = true;
for (int32_t i = low; i <= high; i++) {
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
if (targetOffset != offset) {
infos_[targetOffset].init(stackDepth);
infos_[targetOffset].jumpTarget = true;
}
pc2 += JUMP_OFFSET_LEN;
}
break;
}
case JSOP_TRY: {
JSTryNote* tn = script_->trynotes()->vector;
JSTryNote* tnlimit = tn + script_->trynotes()->length;
for (; tn < tnlimit; tn++) {
unsigned startOffset = script_->mainOffset() + tn->start;
if (startOffset == offset + 1) {
unsigned catchOffset = startOffset + tn->length;
if (tn->kind != JSTRY_FOR_IN) {
infos_[catchOffset].init(stackDepth);
infos_[catchOffset].jumpTarget = true;
}
}
}
// Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
// jump over the catch/finally blocks.
jssrcnote* sn = GetSrcNote(gsn, script_, pc);
MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
jsbytecode* endOfTry = pc + GetSrcNoteOffset(sn, 0);
MOZ_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
jsbytecode* afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
MOZ_ASSERT(afterTry > endOfTry);
// Pop CatchFinallyRanges that are no longer needed.
while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
catchFinallyRanges.popBack();
CatchFinallyRange range(script_->pcToOffset(endOfTry), script_->pcToOffset(afterTry));
if (!catchFinallyRanges.append(range))
return false;
break;
}
case JSOP_LOOPENTRY:
for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
if (catchFinallyRanges[i].contains(offset))
infos_[offset].loopEntryInCatchOrFinally = true;
}
break;
case JSOP_GETNAME:
case JSOP_BINDNAME:
case JSOP_BINDVAR:
case JSOP_SETNAME:
case JSOP_STRICTSETNAME:
case JSOP_DELNAME:
case JSOP_GETALIASEDVAR:
case JSOP_SETALIASEDVAR:
case JSOP_LAMBDA:
case JSOP_LAMBDA_ARROW:
case JSOP_DEFFUN:
case JSOP_DEFVAR:
usesScopeChain_ = true;
break;
case JSOP_GETGNAME:
case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME:
if (script_->hasNonSyntacticScope())
usesScopeChain_ = true;
break;
case JSOP_FINALLY:
hasTryFinally_ = true;
break;
case JSOP_SETARG:
hasSetArg_ = true;
break;
default:
break;
}
bool jump = IsJumpOpcode(op);
if (jump) {
// Case instructions do not push the lvalue back when branching.
unsigned newStackDepth = stackDepth;
if (op == JSOP_CASE)
newStackDepth--;
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
// If this is a a backedge to an un-analyzed segment, analyze from there.
bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;
infos_[targetOffset].init(newStackDepth);
infos_[targetOffset].jumpTarget = true;
if (jumpBack)
nextpc = script_->offsetToPC(targetOffset);
}
// Handle any fallthrough from this opcode.
if (BytecodeFallsThrough(op)) {
jsbytecode* fallthrough = pc + GetBytecodeLength(pc);
MOZ_ASSERT(fallthrough < end);
unsigned fallthroughOffset = script_->pcToOffset(fallthrough);
infos_[fallthroughOffset].init(stackDepth);
// Treat the fallthrough of a branch instruction as a jump target.
if (jump)
infos_[fallthroughOffset].jumpTarget = true;
}
}
return true;
}