mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-27 21:39:15 +00:00
8fa1300bcd
- Bug 1136925 part 1. Stop passing a parent to JS_CloneObject (02806f3cb) - Bug 1136925 part 2. Stop passing a parent to Wrapper::New. (1d51cbd34) - Bug 1136925 part 3. Stop passing parents to js::NewProxyObject. (dc13db8da) - Bug 1136925 part 4. Stop passing parents to ProxyObject::New. (e2d30e340) - Bug 1130679: IonMonkey: Make it possible to guard on type changes/bailouts (ecec18313) - Bug 1136980 part 1. Get rid of JS_SetParent uses in DOM/XPConnect. (5cad9c256) - Bug 1136980 part 2. Remove JS_SetParent, even though we have a CLOSED TREE (96cf58c85) - Bug 1066229 - Part 5: Emitter support for basic ES6 ClassStatements. (e2a3cc979) - Bug 1135423 - Use unboxed objects for object literals where possible, clean up object literal creation and property initialization code (1d9e381c2) - Bug 1137523 part 2 - Unprefix a few js_* functions I forgot in part 1 (e6beaf0d8) - Bug 1135816 - Handle unboxed object receivers when compiling getter/setter calls in baseline/Ion (82233087e) - Bug 1138265 - TraceLogger: Throw error when trying to enable in AsmJS (64c799042) - Bug 1113369, part 1 - Introduce JS::ObjectOpResult and use it in js::StandardDefineProperty. (15663c476) - Bug 1113369, part 1½ - Avoid regressing error messages by adding obj to the ObjectOpResult methods that could throw a TypeError. (e063faf08) - Bug 1113369, part 2 - js::SetArrayLength ObjectOpResult support. (cf8326017) - Bug 1113369, part 3 - [[DefineOwnProperty]] ObjectOpResult support. (e16605a90) - Bug 1113369, part 4 - [[Set]] ObjectOpResult support. (6f94604d4) - Bug 1077002 - Give a better error message when showModalDialog is used (18d8ecc12) - Bug 1135792. Stop assuming that every binding for a global with a non-worker descriptor is a binding for Window. (dd0260c12) - Bug 1135810. Add more explicit checks for whether a descriptor wants Xrays or not instead of assuming that Xrays are desired if and only if descriptor.workers is false. (17ef71544) - Bug 1050456 - Part 1: Prevent prerendered pages from showing the slow script dialog (173044922) - Bug 1050456 - Part 2: Add a nsGlobalWindow::GetIsPrerendered helper (ac680a5f7) hopefully we can re-apply them later.
218 lines
7.1 KiB
C++
218 lines
7.1 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"
|
|
|
|
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;
|
|
|
|
// We need a scope chain if the function is heavyweight.
|
|
usesScopeChain_ = (script_->functionDelazifying() &&
|
|
script_->functionDelazifying()->isHeavyweight());
|
|
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()), js_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 + js_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_SETNAME:
|
|
case JSOP_DELNAME:
|
|
case JSOP_GETALIASEDVAR:
|
|
case JSOP_SETALIASEDVAR:
|
|
case JSOP_LAMBDA:
|
|
case JSOP_LAMBDA_ARROW:
|
|
case JSOP_DEFFUN:
|
|
case JSOP_DEFVAR:
|
|
case JSOP_DEFCONST:
|
|
case JSOP_SETCONST:
|
|
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;
|
|
}
|