Files
palemoon27/js/src/jit/SharedIC.cpp
T
roytam1 34bb7a462c import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1171405 - Add baseline and ion ICs for GETELEM on unboxed plain objects, r=jandem. (1b83760e1)
- Bug 1094491 - Generate baseline getProp ICs for accessor properties before calling the getter. r=efaust (8fd5fbf93)
- Bug 1094491 - Generate baseline getGName ICs for accessor properties before calling the getter. r=efaust (6b2b1699f)
- Bug 1094491 - Add assertion in UpdateExistingGetPropCallStubs that should hold now. r=efaust (70c31131b)
- Bug 1038859 - Add symbol-support to Baseline GetElem ICs. r=djvj (e77aa66d3)
- Bug 1153458 - Fix decompiler issue with DoCallNativeGetter. r=efaust (dacb12a63)
- Bug 1145924 - Ensure JSRuntime is kept in sync with the profiler. (r=djvj) (d17e158d0)
- Bug 1156317 - Change the onOutOfMemory() interface is make it harder to misuse r=terrence (374165af5)
- Bug 1131043 - Part 3: Fix ecma_6/TypedArray/slice.js to check %TypedArray%[@@species] instead of Symbol.species. r=bustage (81a8342af)
- bits of Bug 761261 - Add JS profiling to SPS (7304b7e29)
- Bug 1164664 - Swap out the 'default JSContext callback' for something capable of setting up an AutoEntryScript. v3 r=jimb (16d44cea8)
- Bug 1164664 - Switch to new-style error-reporting for PrepareScriptEnvironment. r=jimb (32f6dbedf)
- Bug 1164664 - Defang PushJSContextNoScriptContext. r=jimb (60d3ce9e6)
- Bug 887030 - Remove the volatile from heapState; r=jonco (0bfe003a8)
- pointer style (eb2fba373)
- Bug 887030 - Allow inlining of heapState checks from outside JSAPI; r=jonco (02cd0c2d6)
- Bug 887030 - Remove JS::shadow::Runtime::needsIncrementalBarrier and use heapState directly; r=jonco (99d924c37)
2020-11-06 11:12:50 +08:00

823 lines
31 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/SharedIC.h"
#include "mozilla/SizePrintfMacros.h"
#include "jstypes.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/SharedICHelpers.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
#include "jit/VMFunctions.h"
namespace js {
namespace jit {
#ifdef DEBUG
void
FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
{
if (JitSpewEnabled(JitSpew_BaselineICFallback)) {
RootedScript script(cx, GetTopJitJSScript(cx));
jsbytecode* pc = stub->icEntry()->pc(script);
char fmtbuf[100];
va_list args;
va_start(args, fmt);
vsnprintf(fmtbuf, 100, fmt, args);
va_end(args);
JitSpew(JitSpew_BaselineICFallback,
"Fallback hit for (%s:%" PRIuSIZE ") (pc=%" PRIuSIZE ",line=%d,uses=%d,stubs=%" PRIuSIZE "): %s",
script->filename(),
script->lineno(),
script->pcToOffset(pc),
PCToLineNumber(script, pc),
script->getWarmUpCount(),
stub->numOptimizedStubs(),
fmtbuf);
}
}
void
TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, const char* fmt, ...)
{
if (JitSpewEnabled(JitSpew_BaselineICFallback)) {
RootedScript script(cx, GetTopJitJSScript(cx));
jsbytecode* pc = stub->icEntry()->pc(script);
char fmtbuf[100];
va_list args;
va_start(args, fmt);
vsnprintf(fmtbuf, 100, fmt, args);
va_end(args);
JitSpew(JitSpew_BaselineICFallback,
"Type monitor fallback hit for (%s:%" PRIuSIZE ") (pc=%" PRIuSIZE ",line=%d,uses=%d,stubs=%d): %s",
script->filename(),
script->lineno(),
script->pcToOffset(pc),
PCToLineNumber(script, pc),
script->getWarmUpCount(),
(int) stub->numOptimizedMonitorStubs(),
fmtbuf);
}
}
#endif
ICFallbackStub*
ICEntry::fallbackStub() const
{
return firstStub()->getChainFallback();
}
ICStubConstIterator&
ICStubConstIterator::operator++()
{
MOZ_ASSERT(currentStub_ != nullptr);
currentStub_ = currentStub_->next();
return *this;
}
ICStubIterator::ICStubIterator(ICFallbackStub* fallbackStub, bool end)
: icEntry_(fallbackStub->icEntry()),
fallbackStub_(fallbackStub),
previousStub_(nullptr),
currentStub_(end ? fallbackStub : icEntry_->firstStub()),
unlinked_(false)
{ }
ICStubIterator&
ICStubIterator::operator++()
{
MOZ_ASSERT(currentStub_->next() != nullptr);
if (!unlinked_)
previousStub_ = currentStub_;
currentStub_ = currentStub_->next();
unlinked_ = false;
return *this;
}
void
ICStubIterator::unlink(JSContext* cx)
{
MOZ_ASSERT(currentStub_->next() != nullptr);
MOZ_ASSERT(currentStub_ != fallbackStub_);
MOZ_ASSERT(!unlinked_);
fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
// Mark the current iterator position as unlinked, so operator++ works properly.
unlinked_ = true;
}
void
ICStub::markCode(JSTracer* trc, const char* name)
{
JitCode* stubJitCode = jitCode();
TraceManuallyBarrieredEdge(trc, &stubJitCode, name);
}
void
ICStub::updateCode(JitCode* code)
{
// Write barrier on the old code.
JitCode::writeBarrierPre(jitCode());
stubCode_ = code->raw();
}
/* static */ void
ICStub::trace(JSTracer* trc)
{
markCode(trc, "baseline-stub-jitcode");
// If the stub is a monitored fallback stub, then mark the monitor ICs hanging
// off of that stub. We don't need to worry about the regular monitored stubs,
// because the regular monitored stubs will always have a monitored fallback stub
// that references the same stub chain.
if (isMonitoredFallback()) {
ICTypeMonitor_Fallback* lastMonStub = toMonitoredFallbackStub()->fallbackMonitorStub();
for (ICStubConstIterator iter(lastMonStub->firstMonitorStub()); !iter.atEnd(); iter++) {
MOZ_ASSERT_IF(iter->next() == nullptr, *iter == lastMonStub);
iter->trace(trc);
}
}
if (isUpdated()) {
for (ICStubConstIterator iter(toUpdatedStub()->firstUpdateStub()); !iter.atEnd(); iter++) {
MOZ_ASSERT_IF(iter->next() == nullptr, iter->isTypeUpdate_Fallback());
iter->trace(trc);
}
}
switch (kind()) {
case ICStub::Call_Scripted: {
ICCall_Scripted* callStub = toCall_Scripted();
TraceEdge(trc, &callStub->callee(), "baseline-callscripted-callee");
if (callStub->templateObject())
TraceEdge(trc, &callStub->templateObject(), "baseline-callscripted-template");
break;
}
case ICStub::Call_Native: {
ICCall_Native* callStub = toCall_Native();
TraceEdge(trc, &callStub->callee(), "baseline-callnative-callee");
if (callStub->templateObject())
TraceEdge(trc, &callStub->templateObject(), "baseline-callnative-template");
break;
}
case ICStub::Call_ClassHook: {
ICCall_ClassHook* callStub = toCall_ClassHook();
if (callStub->templateObject())
TraceEdge(trc, &callStub->templateObject(), "baseline-callclasshook-template");
break;
}
case ICStub::Call_StringSplit: {
ICCall_StringSplit* callStub = toCall_StringSplit();
TraceEdge(trc, &callStub->templateObject(), "baseline-callstringsplit-template");
TraceEdge(trc, &callStub->expectedArg(), "baseline-callstringsplit-arg");
TraceEdge(trc, &callStub->expectedThis(), "baseline-callstringsplit-this");
break;
}
case ICStub::GetElem_NativeSlotName:
case ICStub::GetElem_NativeSlotSymbol:
case ICStub::GetElem_UnboxedPropertyName: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElem_NativeSlot<JS::Symbol*>* typedGetElemStub = toGetElem_NativeSlotSymbol();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
} else {
ICGetElemNativeSlotStub<PropertyName*>* typedGetElemStub =
reinterpret_cast<ICGetElemNativeSlotStub<PropertyName*>*>(this);
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
}
break;
}
case ICStub::GetElem_NativePrototypeSlotName:
case ICStub::GetElem_NativePrototypeSlotSymbol: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElem_NativePrototypeSlot<JS::Symbol*>* typedGetElemStub
= toGetElem_NativePrototypeSlotSymbol();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
} else {
ICGetElem_NativePrototypeSlot<PropertyName*>* typedGetElemStub
= toGetElem_NativePrototypeSlotName();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
}
break;
}
case ICStub::GetElem_NativePrototypeCallNativeName:
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
case ICStub::GetElem_NativePrototypeCallScriptedName:
case ICStub::GetElem_NativePrototypeCallScriptedSymbol: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElemNativePrototypeCallStub<JS::Symbol*>* callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub<JS::Symbol*>*>(this);
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
} else {
ICGetElemNativePrototypeCallStub<PropertyName*>* callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub<PropertyName*>*>(this);
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
}
break;
}
case ICStub::GetElem_Dense: {
ICGetElem_Dense* getElemStub = toGetElem_Dense();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
break;
}
case ICStub::GetElem_UnboxedArray: {
ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray();
TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group");
break;
}
case ICStub::GetElem_TypedArray: {
ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape");
break;
}
case ICStub::SetElem_DenseOrUnboxedArray: {
ICSetElem_DenseOrUnboxedArray* setElemStub = toSetElem_DenseOrUnboxedArray();
if (setElemStub->shape())
TraceEdge(trc, &setElemStub->shape(), "baseline-getelem-dense-shape");
TraceEdge(trc, &setElemStub->group(), "baseline-setelem-dense-group");
break;
}
case ICStub::SetElem_DenseOrUnboxedArrayAdd: {
ICSetElem_DenseOrUnboxedArrayAdd* setElemStub = toSetElem_DenseOrUnboxedArrayAdd();
TraceEdge(trc, &setElemStub->group(), "baseline-setelem-denseadd-group");
JS_STATIC_ASSERT(ICSetElem_DenseOrUnboxedArrayAdd::MAX_PROTO_CHAIN_DEPTH == 4);
switch (setElemStub->protoChainDepth()) {
case 0: setElemStub->toImpl<0>()->traceShapes(trc); break;
case 1: setElemStub->toImpl<1>()->traceShapes(trc); break;
case 2: setElemStub->toImpl<2>()->traceShapes(trc); break;
case 3: setElemStub->toImpl<3>()->traceShapes(trc); break;
case 4: setElemStub->toImpl<4>()->traceShapes(trc); break;
default: MOZ_CRASH("Invalid proto stub.");
}
break;
}
case ICStub::SetElem_TypedArray: {
ICSetElem_TypedArray* setElemStub = toSetElem_TypedArray();
TraceEdge(trc, &setElemStub->shape(), "baseline-setelem-typedarray-shape");
break;
}
case ICStub::TypeMonitor_SingleObject: {
ICTypeMonitor_SingleObject* monitorStub = toTypeMonitor_SingleObject();
TraceEdge(trc, &monitorStub->object(), "baseline-monitor-singleton");
break;
}
case ICStub::TypeMonitor_ObjectGroup: {
ICTypeMonitor_ObjectGroup* monitorStub = toTypeMonitor_ObjectGroup();
TraceEdge(trc, &monitorStub->group(), "baseline-monitor-group");
break;
}
case ICStub::TypeUpdate_SingleObject: {
ICTypeUpdate_SingleObject* updateStub = toTypeUpdate_SingleObject();
TraceEdge(trc, &updateStub->object(), "baseline-update-singleton");
break;
}
case ICStub::TypeUpdate_ObjectGroup: {
ICTypeUpdate_ObjectGroup* updateStub = toTypeUpdate_ObjectGroup();
TraceEdge(trc, &updateStub->group(), "baseline-update-group");
break;
}
case ICStub::In_Native: {
ICIn_Native* inStub = toIn_Native();
TraceEdge(trc, &inStub->shape(), "baseline-innative-stub-shape");
TraceEdge(trc, &inStub->name(), "baseline-innative-stub-name");
break;
}
case ICStub::In_NativePrototype: {
ICIn_NativePrototype* inStub = toIn_NativePrototype();
TraceEdge(trc, &inStub->shape(), "baseline-innativeproto-stub-shape");
TraceEdge(trc, &inStub->name(), "baseline-innativeproto-stub-name");
TraceEdge(trc, &inStub->holder(), "baseline-innativeproto-stub-holder");
TraceEdge(trc, &inStub->holderShape(), "baseline-innativeproto-stub-holdershape");
break;
}
case ICStub::In_NativeDoesNotExist: {
ICIn_NativeDoesNotExist* inStub = toIn_NativeDoesNotExist();
TraceEdge(trc, &inStub->name(), "baseline-innativedoesnotexist-stub-name");
JS_STATIC_ASSERT(ICIn_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8);
switch (inStub->protoChainDepth()) {
case 0: inStub->toImpl<0>()->traceShapes(trc); break;
case 1: inStub->toImpl<1>()->traceShapes(trc); break;
case 2: inStub->toImpl<2>()->traceShapes(trc); break;
case 3: inStub->toImpl<3>()->traceShapes(trc); break;
case 4: inStub->toImpl<4>()->traceShapes(trc); break;
case 5: inStub->toImpl<5>()->traceShapes(trc); break;
case 6: inStub->toImpl<6>()->traceShapes(trc); break;
case 7: inStub->toImpl<7>()->traceShapes(trc); break;
case 8: inStub->toImpl<8>()->traceShapes(trc); break;
default: MOZ_CRASH("Invalid proto stub.");
}
break;
}
case ICStub::In_Dense: {
ICIn_Dense* inStub = toIn_Dense();
TraceEdge(trc, &inStub->shape(), "baseline-in-dense-shape");
break;
}
case ICStub::GetName_Global: {
ICGetName_Global* globalStub = toGetName_Global();
TraceEdge(trc, &globalStub->shape(), "baseline-global-stub-shape");
break;
}
case ICStub::GetName_Scope0:
static_cast<ICGetName_Scope<0>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope1:
static_cast<ICGetName_Scope<1>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope2:
static_cast<ICGetName_Scope<2>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope3:
static_cast<ICGetName_Scope<3>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope4:
static_cast<ICGetName_Scope<4>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope5:
static_cast<ICGetName_Scope<5>*>(this)->traceScopes(trc);
break;
case ICStub::GetName_Scope6:
static_cast<ICGetName_Scope<6>*>(this)->traceScopes(trc);
break;
case ICStub::GetIntrinsic_Constant: {
ICGetIntrinsic_Constant* constantStub = toGetIntrinsic_Constant();
TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
break;
}
case ICStub::GetProp_Primitive: {
ICGetProp_Primitive* propStub = toGetProp_Primitive();
TraceEdge(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape");
break;
}
case ICStub::GetProp_Native: {
ICGetProp_Native* propStub = toGetProp_Native();
propStub->receiverGuard().trace(trc);
break;
}
case ICStub::GetProp_NativePrototype: {
ICGetProp_NativePrototype* propStub = toGetProp_NativePrototype();
propStub->receiverGuard().trace(trc);
TraceEdge(trc, &propStub->holder(), "baseline-getpropnativeproto-stub-holder");
TraceEdge(trc, &propStub->holderShape(), "baseline-getpropnativeproto-stub-holdershape");
break;
}
case ICStub::GetProp_NativeDoesNotExist: {
ICGetProp_NativeDoesNotExist* propStub = toGetProp_NativeDoesNotExist();
propStub->guard().trace(trc);
JS_STATIC_ASSERT(ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8);
switch (propStub->protoChainDepth()) {
case 0: propStub->toImpl<0>()->traceShapes(trc); break;
case 1: propStub->toImpl<1>()->traceShapes(trc); break;
case 2: propStub->toImpl<2>()->traceShapes(trc); break;
case 3: propStub->toImpl<3>()->traceShapes(trc); break;
case 4: propStub->toImpl<4>()->traceShapes(trc); break;
case 5: propStub->toImpl<5>()->traceShapes(trc); break;
case 6: propStub->toImpl<6>()->traceShapes(trc); break;
case 7: propStub->toImpl<7>()->traceShapes(trc); break;
case 8: propStub->toImpl<8>()->traceShapes(trc); break;
default: MOZ_CRASH("Invalid proto stub.");
}
break;
}
case ICStub::GetProp_Unboxed: {
ICGetProp_Unboxed* propStub = toGetProp_Unboxed();
TraceEdge(trc, &propStub->group(), "baseline-getprop-unboxed-stub-group");
break;
}
case ICStub::GetProp_TypedObject: {
ICGetProp_TypedObject* propStub = toGetProp_TypedObject();
TraceEdge(trc, &propStub->shape(), "baseline-getprop-typedobject-stub-shape");
break;
}
case ICStub::GetProp_CallDOMProxyNative:
case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
ICGetPropCallDOMProxyNativeStub* propStub;
if (kind() == ICStub::GetProp_CallDOMProxyNative)
propStub = toGetProp_CallDOMProxyNative();
else
propStub = toGetProp_CallDOMProxyWithGenerationNative();
propStub->receiverGuard().trace(trc);
if (propStub->expandoShape()) {
TraceEdge(trc, &propStub->expandoShape(),
"baseline-getproplistbasenative-stub-expandoshape");
}
TraceEdge(trc, &propStub->holder(), "baseline-getproplistbasenative-stub-holder");
TraceEdge(trc, &propStub->holderShape(), "baseline-getproplistbasenative-stub-holdershape");
TraceEdge(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
break;
}
case ICStub::GetProp_DOMProxyShadowed: {
ICGetProp_DOMProxyShadowed* propStub = toGetProp_DOMProxyShadowed();
TraceEdge(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
TraceEdge(trc, &propStub->name(), "baseline-getproplistbaseshadowed-stub-name");
break;
}
case ICStub::GetProp_CallScripted: {
ICGetProp_CallScripted* callStub = toGetProp_CallScripted();
callStub->receiverGuard().trace(trc);
TraceEdge(trc, &callStub->holder(), "baseline-getpropcallscripted-stub-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getpropcallscripted-stub-holdershape");
TraceEdge(trc, &callStub->getter(), "baseline-getpropcallscripted-stub-getter");
break;
}
case ICStub::GetProp_CallNative: {
ICGetProp_CallNative* callStub = toGetProp_CallNative();
callStub->receiverGuard().trace(trc);
TraceEdge(trc, &callStub->holder(), "baseline-getpropcallnative-stub-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getpropcallnative-stub-holdershape");
TraceEdge(trc, &callStub->getter(), "baseline-getpropcallnative-stub-getter");
break;
}
case ICStub::SetProp_Native: {
ICSetProp_Native* propStub = toSetProp_Native();
TraceEdge(trc, &propStub->shape(), "baseline-setpropnative-stub-shape");
TraceEdge(trc, &propStub->group(), "baseline-setpropnative-stub-group");
break;
}
case ICStub::SetProp_NativeAdd: {
ICSetProp_NativeAdd* propStub = toSetProp_NativeAdd();
TraceEdge(trc, &propStub->group(), "baseline-setpropnativeadd-stub-group");
TraceEdge(trc, &propStub->newShape(), "baseline-setpropnativeadd-stub-newshape");
if (propStub->newGroup())
TraceEdge(trc, &propStub->newGroup(), "baseline-setpropnativeadd-stub-new-group");
JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
switch (propStub->protoChainDepth()) {
case 0: propStub->toImpl<0>()->traceShapes(trc); break;
case 1: propStub->toImpl<1>()->traceShapes(trc); break;
case 2: propStub->toImpl<2>()->traceShapes(trc); break;
case 3: propStub->toImpl<3>()->traceShapes(trc); break;
case 4: propStub->toImpl<4>()->traceShapes(trc); break;
default: MOZ_CRASH("Invalid proto stub.");
}
break;
}
case ICStub::SetProp_Unboxed: {
ICSetProp_Unboxed* propStub = toSetProp_Unboxed();
TraceEdge(trc, &propStub->group(), "baseline-setprop-unboxed-stub-group");
break;
}
case ICStub::SetProp_TypedObject: {
ICSetProp_TypedObject* propStub = toSetProp_TypedObject();
TraceEdge(trc, &propStub->shape(), "baseline-setprop-typedobject-stub-shape");
TraceEdge(trc, &propStub->group(), "baseline-setprop-typedobject-stub-group");
break;
}
case ICStub::SetProp_CallScripted: {
ICSetProp_CallScripted* callStub = toSetProp_CallScripted();
callStub->receiverGuard().trace(trc);
TraceEdge(trc, &callStub->holder(), "baseline-setpropcallscripted-stub-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-setpropcallscripted-stub-holdershape");
TraceEdge(trc, &callStub->setter(), "baseline-setpropcallscripted-stub-setter");
break;
}
case ICStub::SetProp_CallNative: {
ICSetProp_CallNative* callStub = toSetProp_CallNative();
callStub->receiverGuard().trace(trc);
TraceEdge(trc, &callStub->holder(), "baseline-setpropcallnative-stub-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-setpropcallnative-stub-holdershape");
TraceEdge(trc, &callStub->setter(), "baseline-setpropcallnative-stub-setter");
break;
}
case ICStub::InstanceOf_Function: {
ICInstanceOf_Function* instanceofStub = toInstanceOf_Function();
TraceEdge(trc, &instanceofStub->shape(), "baseline-instanceof-fun-shape");
TraceEdge(trc, &instanceofStub->prototypeObject(), "baseline-instanceof-fun-prototype");
break;
}
case ICStub::NewArray_Fallback: {
ICNewArray_Fallback* stub = toNewArray_Fallback();
if (stub->templateObject())
TraceEdge(trc, &stub->templateObject(), "baseline-newarray-template");
TraceEdge(trc, &stub->templateGroup(), "baseline-newarray-template-group");
break;
}
case ICStub::NewObject_Fallback: {
ICNewObject_Fallback* stub = toNewObject_Fallback();
if (stub->templateObject())
TraceEdge(trc, &stub->templateObject(), "baseline-newobject-template");
break;
}
case ICStub::Rest_Fallback: {
ICRest_Fallback* stub = toRest_Fallback();
TraceEdge(trc, &stub->templateObject(), "baseline-rest-template");
break;
}
default:
break;
}
}
void
ICFallbackStub::unlinkStub(Zone* zone, ICStub* prev, ICStub* stub)
{
MOZ_ASSERT(stub->next());
// If stub is the last optimized stub, update lastStubPtrAddr.
if (stub->next() == this) {
MOZ_ASSERT(lastStubPtrAddr_ == stub->addressOfNext());
if (prev)
lastStubPtrAddr_ = prev->addressOfNext();
else
lastStubPtrAddr_ = icEntry()->addressOfFirstStub();
*lastStubPtrAddr_ = this;
} else {
if (prev) {
MOZ_ASSERT(prev->next() == stub);
prev->setNext(stub->next());
} else {
MOZ_ASSERT(icEntry()->firstStub() == stub);
icEntry()->setFirstStub(stub->next());
}
}
MOZ_ASSERT(numOptimizedStubs_ > 0);
numOptimizedStubs_--;
if (zone->needsIncrementalBarrier()) {
// We are removing edges from ICStub to gcthings. Perform one final trace
// of the stub for incremental GC, as it must know about those edges.
stub->trace(zone->barrierTracer());
}
if (ICStub::CanMakeCalls(stub->kind()) && stub->isMonitored()) {
// This stub can make calls so we can return to it if it's on the stack.
// We just have to reset its firstMonitorStub_ field to avoid a stale
// pointer when purgeOptimizedStubs destroys all optimized monitor
// stubs (unlinked stubs won't be updated).
ICTypeMonitor_Fallback* monitorFallback = toMonitoredFallbackStub()->fallbackMonitorStub();
stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);
}
#ifdef DEBUG
// Poison stub code to ensure we don't call this stub again. However, if this
// stub can make calls, a pointer to it may be stored in a stub frame on the
// stack, so we can't touch the stubCode_ or GC will crash when marking this
// pointer.
if (!ICStub::CanMakeCalls(stub->kind()))
stub->stubCode_ = (uint8_t*)0xbad;
#endif
}
void
ICFallbackStub::unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind)
{
for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
if (iter->kind() == kind)
iter.unlink(cx);
}
}
void
ICTypeMonitor_Fallback::resetMonitorStubChain(Zone* zone)
{
if (zone->needsIncrementalBarrier()) {
// We are removing edges from monitored stubs to gcthings (JitCode).
// Perform one final trace of all monitor stubs for incremental GC,
// as it must know about those edges.
for (ICStub* s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next())
s->trace(zone->barrierTracer());
}
firstMonitorStub_ = this;
numOptimizedMonitorStubs_ = 0;
if (hasFallbackStub_) {
lastMonitorStubPtrAddr_ = nullptr;
// Reset firstMonitorStub_ field of all monitored stubs.
for (ICStubConstIterator iter = mainFallbackStub_->beginChainConst();
!iter.atEnd(); iter++)
{
if (!iter->isMonitored())
continue;
iter->toMonitoredStub()->resetFirstMonitorStub(this);
}
} else {
icEntry_->setFirstStub(this);
lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
}
}
ICMonitoredStub::ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub)
: ICStub(kind, ICStub::Monitored, stubCode),
firstMonitorStub_(firstMonitorStub)
{
// If the first monitored stub is a ICTypeMonitor_Fallback stub, then
// double check that _its_ firstMonitorStub is the same as this one.
MOZ_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),
firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
firstMonitorStub_);
}
bool
ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx, ICStubSpace* space)
{
MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
ICTypeMonitor_Fallback::Compiler compiler(cx, this);
ICTypeMonitor_Fallback* stub = compiler.getStub(space);
if (!stub)
return false;
fallbackMonitorStub_ = stub;
return true;
}
bool
ICMonitoredFallbackStub::addMonitorStubForValue(JSContext* cx, JSScript* script, HandleValue val)
{
return fallbackMonitorStub_->addMonitorStubForValue(cx, script, val);
}
bool
ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space)
{
MOZ_ASSERT(firstUpdateStub_ == nullptr);
ICTypeUpdate_Fallback::Compiler compiler(cx);
ICTypeUpdate_Fallback* stub = compiler.getStub(space);
if (!stub)
return false;
firstUpdateStub_ = stub;
return true;
}
JitCode*
ICStubCompiler::getStubCode()
{
JitCompartment* comp = cx->compartment()->jitCompartment();
// Check for existing cached stubcode.
uint32_t stubKey = getKey();
JitCode* stubCode = comp->getStubCode(stubKey);
if (stubCode)
return stubCode;
// Compile new stubcode.
JitContext jctx(cx, nullptr);
MacroAssembler masm;
#ifdef JS_CODEGEN_ARM
masm.setSecondScratchReg(BaselineSecondScratchReg);
#endif
if (!generateStubCode(masm))
return nullptr;
Linker linker(masm);
AutoFlushICache afc("getStubCode");
Rooted<JitCode*> newStubCode(cx, linker.newCode<CanGC>(cx, BASELINE_CODE));
if (!newStubCode)
return nullptr;
// After generating code, run postGenerateStubCode()
if (!postGenerateStubCode(masm, newStubCode))
return nullptr;
// All barriers are emitted off-by-default, enable them if needed.
if (cx->zone()->needsIncrementalBarrier())
newStubCode->togglePreBarriers(true);
// Cache newly compiled stubcode.
if (!comp->putStubCode(stubKey, newStubCode))
return nullptr;
MOZ_ASSERT(entersStubFrame_ == ICStub::CanMakeCalls(kind));
MOZ_ASSERT(!inStubFrame_);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC");
#endif
return newStubCode;
}
bool
ICStubCompiler::tailCallVM(const VMFunction& fun, MacroAssembler& masm)
{
JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
if (!code)
return false;
MOZ_ASSERT(fun.expectTailCall == TailCall);
uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
EmitTailCallVM(code, masm, argSize);
return true;
}
bool
ICStubCompiler::callVM(const VMFunction& fun, MacroAssembler& masm)
{
MOZ_ASSERT(inStubFrame_);
JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
if (!code)
return false;
MOZ_ASSERT(fun.expectTailCall == NonTailCall);
EmitCallVM(code, masm);
return true;
}
bool
ICStubCompiler::callTypeUpdateIC(MacroAssembler& masm, uint32_t objectOffset)
{
JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(DoTypeUpdateFallbackInfo);
if (!code)
return false;
EmitCallTypeUpdateIC(masm, code, objectOffset);
return true;
}
void
ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch)
{
EmitEnterStubFrame(masm, scratch);
MOZ_ASSERT(!inStubFrame_);
inStubFrame_ = true;
#ifdef DEBUG
entersStubFrame_ = true;
#endif
}
void
ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon)
{
MOZ_ASSERT(entersStubFrame_ && inStubFrame_);
inStubFrame_ = false;
EmitLeaveStubFrame(masm, calledIntoIon);
}
void
ICStubCompiler::pushFramePtr(MacroAssembler& masm, Register scratch)
{
if (inStubFrame_) {
masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
masm.pushBaselineFramePtr(scratch, scratch);
} else {
masm.pushBaselineFramePtr(BaselineFrameReg, scratch);
}
}
bool
ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, ValueOperand val,
Register scratch, LiveGeneralRegisterSet saveRegs)
{
Label skipBarrier;
masm.branchPtrInNurseryRange(Assembler::Equal, obj, scratch, &skipBarrier);
masm.branchValueIsNurseryObject(Assembler::NotEqual, val, scratch, &skipBarrier);
// void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
saveRegs.add(ICTailCallReg);
#endif
saveRegs.set() = GeneralRegisterSet::Intersect(saveRegs.set(), GeneralRegisterSet::Volatile());
masm.PushRegsInMask(saveRegs);
masm.setupUnalignedABICall(2, scratch);
masm.movePtr(ImmPtr(cx->runtime()), scratch);
masm.passABIArg(scratch);
masm.passABIArg(obj);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
masm.PopRegsInMask(saveRegs);
masm.bind(&skipBarrier);
return true;
}
} // namespace jit
} // namespace js