зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to autoland. r=merge a=merge
This commit is contained in:
Коммит
4c8fa6d5da
|
@ -3294,7 +3294,9 @@ dump(`callFromJSON: < ${JSON.stringify(call)}\n`);
|
||||||
PPB_KeyboardInputEvent_GetCharacterText: function(json) {
|
PPB_KeyboardInputEvent_GetCharacterText: function(json) {
|
||||||
let event = PP_Resource.lookup(json.character_event);
|
let event = PP_Resource.lookup(json.character_event);
|
||||||
let charCode = event.domEvent.charCode;
|
let charCode = event.domEvent.charCode;
|
||||||
if (charCode === 0) {
|
if (charCode === 0 ||
|
||||||
|
event.domEvent.getModifierState("Control") ||
|
||||||
|
event.domEvent.getModifierState("Meta")) {
|
||||||
return new PP_Var();
|
return new PP_Var();
|
||||||
}
|
}
|
||||||
return new String_PP_Var(String.fromCharCode(charCode));
|
return new String_PP_Var(String.fromCharCode(charCode));
|
||||||
|
|
|
@ -570,6 +570,9 @@ Promise::PerformWorkerMicroTaskCheckpoint()
|
||||||
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// For a normal microtask checkpoint, we try to use the debugger microtask
|
// For a normal microtask checkpoint, we try to use the debugger microtask
|
||||||
|
@ -604,6 +607,9 @@ Promise::PerformWorkerDebuggerMicroTaskCheckpoint()
|
||||||
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||||
|
if (!context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// For a debugger microtask checkpoint, we always use the debugger microtask
|
// For a debugger microtask checkpoint, we always use the debugger microtask
|
||||||
|
|
|
@ -170,6 +170,27 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This returns true if scrolling info is equivalent for the purposes of
|
||||||
|
// APZ hit testing.
|
||||||
|
bool HitTestingInfoIsEqual(const SimpleLayerAttributes& aOther) const {
|
||||||
|
if (mIsScrollbarContainer != aOther.mIsScrollbarContainer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mScrollbarTargetContainerId != aOther.mScrollbarTargetContainerId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mScrollbarDirection != aOther.mScrollbarDirection) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FixedPositionScrollContainerId() != aOther.FixedPositionScrollContainerId()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mTransform != aOther.mTransform) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Getters.
|
// Getters.
|
||||||
//
|
//
|
||||||
|
|
|
@ -480,6 +480,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
||||||
|
|
||||||
RefPtr<HitTestingTreeNode> node = nullptr;
|
RefPtr<HitTestingTreeNode> node = nullptr;
|
||||||
if (!needsApzc) {
|
if (!needsApzc) {
|
||||||
|
// Note: if layer properties must be propagated to nodes, RecvUpdate in
|
||||||
|
// LayerTransactionParent.cpp must ensure that APZ will be notified
|
||||||
|
// when those properties change.
|
||||||
node = RecycleOrCreateNode(aState, nullptr, aLayersId);
|
node = RecycleOrCreateNode(aState, nullptr, aLayersId);
|
||||||
AttachNodeToTree(node, aParent, aNextSibling);
|
AttachNodeToTree(node, aParent, aNextSibling);
|
||||||
node->SetHitTestData(
|
node->SetHitTestData(
|
||||||
|
@ -674,6 +677,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
||||||
GetEventRegionsOverride(aParent, aLayer));
|
GetEventRegionsOverride(aParent, aLayer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: if layer properties must be propagated to nodes, RecvUpdate in
|
||||||
|
// LayerTransactionParent.cpp must ensure that APZ will be notified
|
||||||
|
// when those properties change.
|
||||||
node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
|
node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
|
||||||
aLayer.GetScrollbarDirection(),
|
aLayer.GetScrollbarDirection(),
|
||||||
aLayer.GetScrollThumbLength(),
|
aLayer.GetScrollThumbLength(),
|
||||||
|
|
|
@ -172,8 +172,8 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
layer_manager()->BeginTransaction();
|
layer_manager()->BeginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
// not all edits require an update to the hit testing tree
|
// Not all edits require an update to the hit testing tree.
|
||||||
bool updateHitTestingTree = false;
|
mUpdateHitTestingTree = false;
|
||||||
|
|
||||||
for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) {
|
for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) {
|
||||||
const Edit& edit = const_cast<Edit&>(aInfo.cset()[i]);
|
const Edit& edit = const_cast<Edit&>(aInfo.cset()[i]);
|
||||||
|
@ -188,7 +188,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreatePaintedLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateContainerLayer: {
|
case Edit::TOpCreateContainerLayer: {
|
||||||
|
@ -199,7 +199,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateContainerLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateImageLayer: {
|
case Edit::TOpCreateImageLayer: {
|
||||||
|
@ -210,7 +210,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateImageLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateColorLayer: {
|
case Edit::TOpCreateColorLayer: {
|
||||||
|
@ -221,7 +221,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateColorLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateTextLayer: {
|
case Edit::TOpCreateTextLayer: {
|
||||||
|
@ -232,18 +232,18 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateTextLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateBorderLayer: {
|
case Edit::TOpCreateBorderLayer: {
|
||||||
MOZ_LAYERS_LOG(("[ParentSide] CreateTextLayer"));
|
MOZ_LAYERS_LOG(("[ParentSide] CreateBorderLayer"));
|
||||||
|
|
||||||
RefPtr<BorderLayer> layer = layer_manager()->CreateBorderLayer();
|
RefPtr<BorderLayer> layer = layer_manager()->CreateBorderLayer();
|
||||||
if (!BindLayer(layer, edit.get_OpCreateBorderLayer())) {
|
if (!BindLayer(layer, edit.get_OpCreateBorderLayer())) {
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateBorderLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateCanvasLayer: {
|
case Edit::TOpCreateCanvasLayer: {
|
||||||
|
@ -254,7 +254,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateCanvasLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpCreateRefLayer: {
|
case Edit::TOpCreateRefLayer: {
|
||||||
|
@ -265,7 +265,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "CreateRefLayer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpSetDiagnosticTypes: {
|
case Edit::TOpSetDiagnosticTypes: {
|
||||||
|
@ -291,7 +291,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
}
|
}
|
||||||
mRoot = newRoot;
|
mRoot = newRoot;
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(mRoot, "SetRoot");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpInsertAfter: {
|
case Edit::TOpInsertAfter: {
|
||||||
|
@ -309,7 +309,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "InsertAfter");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpPrependChild: {
|
case Edit::TOpPrependChild: {
|
||||||
|
@ -326,7 +326,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "PrependChild");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpRemoveChild: {
|
case Edit::TOpRemoveChild: {
|
||||||
|
@ -343,7 +343,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "RemoveChild");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpRepositionChild: {
|
case Edit::TOpRepositionChild: {
|
||||||
|
@ -361,7 +361,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "RepositionChild");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TOpRaiseToTopChild: {
|
case Edit::TOpRaiseToTopChild: {
|
||||||
|
@ -381,7 +381,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitTestingTree = true;
|
UpdateHitTestingTree(layer, "RaiseToTopChild");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Edit::TCompositableOperation: {
|
case Edit::TCompositableOperation: {
|
||||||
|
@ -446,8 +446,12 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
|
const SimpleLayerAttributes& attrs = op.attrs();
|
||||||
|
const SimpleLayerAttributes& orig = layer->GetSimpleAttributes();
|
||||||
|
if (!attrs.HitTestingInfoIsEqual(orig)) {
|
||||||
|
UpdateHitTestingTree(layer, "scrolling info changed");
|
||||||
|
}
|
||||||
layer->SetSimpleAttributes(op.attrs());
|
layer->SetSimpleAttributes(op.attrs());
|
||||||
updateHitTestingTree = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process attribute updates.
|
// Process attribute updates.
|
||||||
|
@ -456,7 +460,6 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
if (!SetLayerAttributes(op)) {
|
if (!SetLayerAttributes(op)) {
|
||||||
return IPC_FAIL_NO_REASON(this);
|
return IPC_FAIL_NO_REASON(this);
|
||||||
}
|
}
|
||||||
updateHitTestingTree = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process paints separately, after all normal edits.
|
// Process paints separately, after all normal edits.
|
||||||
|
@ -466,7 +469,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCompositorBridge->ShadowLayersUpdated(this, aInfo, updateHitTestingTree);
|
mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree);
|
||||||
|
|
||||||
{
|
{
|
||||||
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
|
AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
|
||||||
|
@ -521,16 +524,29 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp)
|
||||||
|
|
||||||
const LayerAttributes& attrs = aOp.attrs();
|
const LayerAttributes& attrs = aOp.attrs();
|
||||||
const CommonLayerAttributes& common = attrs.common();
|
const CommonLayerAttributes& common = attrs.common();
|
||||||
layer->SetVisibleRegion(common.visibleRegion());
|
if (common.visibleRegion() != layer->GetVisibleRegion()) {
|
||||||
layer->SetEventRegions(common.eventRegions());
|
UpdateHitTestingTree(layer, "visible region changed");
|
||||||
layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing());
|
layer->SetVisibleRegion(common.visibleRegion());
|
||||||
|
}
|
||||||
|
if (common.eventRegions() != layer->GetEventRegions()) {
|
||||||
|
UpdateHitTestingTree(layer, "event regions changed");
|
||||||
|
layer->SetEventRegions(common.eventRegions());
|
||||||
|
}
|
||||||
|
Maybe<ParentLayerIntRect> clipRect = common.useClipRect() ? Some(common.clipRect()) : Nothing();
|
||||||
|
if (clipRect != layer->GetClipRect()) {
|
||||||
|
UpdateHitTestingTree(layer, "clip rect changed");
|
||||||
|
layer->SetClipRect(clipRect);
|
||||||
|
}
|
||||||
if (LayerHandle maskLayer = common.maskLayer()) {
|
if (LayerHandle maskLayer = common.maskLayer()) {
|
||||||
layer->SetMaskLayer(AsLayer(maskLayer));
|
layer->SetMaskLayer(AsLayer(maskLayer));
|
||||||
} else {
|
} else {
|
||||||
layer->SetMaskLayer(nullptr);
|
layer->SetMaskLayer(nullptr);
|
||||||
}
|
}
|
||||||
layer->SetCompositorAnimations(common.compositorAnimations());
|
layer->SetCompositorAnimations(common.compositorAnimations());
|
||||||
layer->SetScrollMetadata(common.scrollMetadata());
|
if (common.scrollMetadata() != layer->GetAllScrollMetadata()) {
|
||||||
|
UpdateHitTestingTree(layer, "scroll metadata changed");
|
||||||
|
layer->SetScrollMetadata(common.scrollMetadata());
|
||||||
|
}
|
||||||
layer->SetDisplayListLog(common.displayListLog().get());
|
layer->SetDisplayListLog(common.displayListLog().get());
|
||||||
|
|
||||||
// The updated invalid region is added to the existing one, since we can
|
// The updated invalid region is added to the existing one, since we can
|
||||||
|
@ -579,8 +595,10 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp)
|
||||||
containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale());
|
containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale());
|
||||||
containerLayer->SetScaleToResolution(attrs.scaleToResolution(),
|
containerLayer->SetScaleToResolution(attrs.scaleToResolution(),
|
||||||
attrs.presShellResolution());
|
attrs.presShellResolution());
|
||||||
containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride());
|
if (attrs.eventRegionsOverride() != containerLayer->GetEventRegionsOverride()) {
|
||||||
|
UpdateHitTestingTree(layer, "event regions override changed");
|
||||||
|
containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Specific::TColorLayerAttributes: {
|
case Specific::TColorLayerAttributes: {
|
||||||
|
@ -640,6 +658,7 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp)
|
||||||
}
|
}
|
||||||
refLayer->SetReferentId(specific.get_RefLayerAttributes().id());
|
refLayer->SetReferentId(specific.get_RefLayerAttributes().id());
|
||||||
refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride());
|
refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride());
|
||||||
|
UpdateHitTestingTree(layer, "event regions override changed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Specific::TImageLayerAttributes: {
|
case Specific::TImageLayerAttributes: {
|
||||||
|
|
|
@ -171,6 +171,13 @@ protected:
|
||||||
friend class CrossProcessCompositorBridgeParent;
|
friend class CrossProcessCompositorBridgeParent;
|
||||||
friend class layout::RenderFrameParent;
|
friend class layout::RenderFrameParent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This is a function so we can log or breakpoint on why hit
|
||||||
|
// testing tree changes are made.
|
||||||
|
void UpdateHitTestingTree(Layer* aLayer, const char* aWhy) {
|
||||||
|
mUpdateHitTestingTree = true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<HostLayerManager> mLayerManager;
|
RefPtr<HostLayerManager> mLayerManager;
|
||||||
CompositorBridgeParentBase* mCompositorBridge;
|
CompositorBridgeParentBase* mCompositorBridge;
|
||||||
|
@ -216,8 +223,11 @@ private:
|
||||||
// transactions posted by the child.
|
// transactions posted by the child.
|
||||||
|
|
||||||
bool mDestroyed;
|
bool mDestroyed;
|
||||||
|
|
||||||
bool mIPCOpen;
|
bool mIPCOpen;
|
||||||
|
|
||||||
|
// This is set during RecvUpdate to track whether we'll need to update
|
||||||
|
// APZ's hit test regions.
|
||||||
|
bool mUpdateHitTestingTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|
|
@ -246,7 +246,6 @@ gc::GCRuntime::startVerifyPreBarriers()
|
||||||
|
|
||||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||||
MOZ_ASSERT(!zone->usedByHelperThread());
|
MOZ_ASSERT(!zone->usedByHelperThread());
|
||||||
PurgeJITCaches(zone);
|
|
||||||
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
|
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
|
||||||
zone->arenas.purge();
|
zone->arenas.purge();
|
||||||
}
|
}
|
||||||
|
@ -342,7 +341,6 @@ gc::GCRuntime::endVerifyPreBarriers()
|
||||||
compartmentCreated = true;
|
compartmentCreated = true;
|
||||||
|
|
||||||
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
|
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
|
||||||
PurgeJITCaches(zone);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -192,69 +192,67 @@ Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode)
|
||||||
if (!jitZone())
|
if (!jitZone())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isPreservingCode()) {
|
if (isPreservingCode())
|
||||||
PurgeJITCaches(this);
|
return;
|
||||||
} else {
|
|
||||||
|
|
||||||
if (discardBaselineCode) {
|
if (discardBaselineCode) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* Assert no baseline scripts are marked as active. */
|
/* Assert no baseline scripts are marked as active. */
|
||||||
for (auto script = cellIter<JSScript>(); !script.done(); script.next())
|
for (auto script = cellIter<JSScript>(); !script.done(); script.next())
|
||||||
MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
|
MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mark baseline scripts on the stack as active. */
|
/* Mark baseline scripts on the stack as active. */
|
||||||
jit::MarkActiveBaselineScripts(this);
|
jit::MarkActiveBaselineScripts(this);
|
||||||
}
|
|
||||||
|
|
||||||
/* Only mark OSI points if code is being discarded. */
|
|
||||||
jit::InvalidateAll(fop, this);
|
|
||||||
|
|
||||||
for (auto script = cellIter<JSScript>(); !script.done(); script.next()) {
|
|
||||||
jit::FinishInvalidation(fop, script);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard baseline script if it's not marked as active. Note that
|
|
||||||
* this also resets the active flag.
|
|
||||||
*/
|
|
||||||
if (discardBaselineCode)
|
|
||||||
jit::FinishDiscardBaselineScript(fop, script);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Warm-up counter for scripts are reset on GC. After discarding code we
|
|
||||||
* need to let it warm back up to get information such as which
|
|
||||||
* opcodes are setting array holes or accessing getter properties.
|
|
||||||
*/
|
|
||||||
script->resetWarmUpCounter();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make it impossible to use the control flow graphs cached on the
|
|
||||||
* BaselineScript. They get deleted.
|
|
||||||
*/
|
|
||||||
if (script->hasBaselineScript())
|
|
||||||
script->baselineScript()->setControlFlowGraph(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When scripts contains pointers to nursery things, the store buffer
|
|
||||||
* can contain entries that point into the optimized stub space. Since
|
|
||||||
* this method can be called outside the context of a GC, this situation
|
|
||||||
* could result in us trying to mark invalid store buffer entries.
|
|
||||||
*
|
|
||||||
* Defer freeing any allocated blocks until after the next minor GC.
|
|
||||||
*/
|
|
||||||
if (discardBaselineCode) {
|
|
||||||
jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this);
|
|
||||||
jitZone()->purgeIonCacheIRStubInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free all control flow graphs that are cached on BaselineScripts.
|
|
||||||
* Assuming this happens on the active thread and all control flow
|
|
||||||
* graph reads happen on the active thread, this is safe.
|
|
||||||
*/
|
|
||||||
jitZone()->cfgSpace()->lifoAlloc().freeAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only mark OSI points if code is being discarded. */
|
||||||
|
jit::InvalidateAll(fop, this);
|
||||||
|
|
||||||
|
for (auto script = cellIter<JSScript>(); !script.done(); script.next()) {
|
||||||
|
jit::FinishInvalidation(fop, script);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discard baseline script if it's not marked as active. Note that
|
||||||
|
* this also resets the active flag.
|
||||||
|
*/
|
||||||
|
if (discardBaselineCode)
|
||||||
|
jit::FinishDiscardBaselineScript(fop, script);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Warm-up counter for scripts are reset on GC. After discarding code we
|
||||||
|
* need to let it warm back up to get information such as which
|
||||||
|
* opcodes are setting array holes or accessing getter properties.
|
||||||
|
*/
|
||||||
|
script->resetWarmUpCounter();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make it impossible to use the control flow graphs cached on the
|
||||||
|
* BaselineScript. They get deleted.
|
||||||
|
*/
|
||||||
|
if (script->hasBaselineScript())
|
||||||
|
script->baselineScript()->setControlFlowGraph(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When scripts contains pointers to nursery things, the store buffer
|
||||||
|
* can contain entries that point into the optimized stub space. Since
|
||||||
|
* this method can be called outside the context of a GC, this situation
|
||||||
|
* could result in us trying to mark invalid store buffer entries.
|
||||||
|
*
|
||||||
|
* Defer freeing any allocated blocks until after the next minor GC.
|
||||||
|
*/
|
||||||
|
if (discardBaselineCode) {
|
||||||
|
jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this);
|
||||||
|
jitZone()->purgeIonCacheIRStubInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free all control flow graphs that are cached on BaselineScripts.
|
||||||
|
* Assuming this happens on the active thread and all control flow
|
||||||
|
* graph reads happen on the active thread, this is safe.
|
||||||
|
*/
|
||||||
|
jitZone()->cfgSpace()->lifoAlloc().freeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSGC_HASH_TABLE_CHECKS
|
#ifdef JSGC_HASH_TABLE_CHECKS
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
const x = 1;
|
||||||
|
function testConst() {
|
||||||
|
for (var i = 0; i < 20; i++) {
|
||||||
|
try {
|
||||||
|
x = 2;
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw "Fail1";
|
||||||
|
}
|
||||||
|
assertEq(x, 1);
|
||||||
|
}
|
||||||
|
testConst();
|
||||||
|
|
||||||
|
function testUninit() {
|
||||||
|
for (var i = 0; i < 20; i++) {
|
||||||
|
try {
|
||||||
|
y = 2;
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw "Fail2";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testUninit();
|
||||||
|
let y;
|
|
@ -1855,10 +1855,11 @@ BaselineCacheIRCompiler::init(CacheKind kind)
|
||||||
allocator.initInputLocation(2, BaselineFrameSlot(0));
|
allocator.initInputLocation(2, BaselineFrameSlot(0));
|
||||||
break;
|
break;
|
||||||
case CacheKind::GetName:
|
case CacheKind::GetName:
|
||||||
|
case CacheKind::BindName:
|
||||||
MOZ_ASSERT(numInputs == 1);
|
MOZ_ASSERT(numInputs == 1);
|
||||||
allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_OBJECT);
|
allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_OBJECT);
|
||||||
#if defined(JS_NUNBOX32)
|
#if defined(JS_NUNBOX32)
|
||||||
// availableGeneralRegs can't know that GetName is only using
|
// availableGeneralRegs can't know that GetName/BindName is only using
|
||||||
// the payloadReg and not typeReg on x86.
|
// the payloadReg and not typeReg on x86.
|
||||||
available.add(R0.typeReg());
|
available.add(R0.typeReg());
|
||||||
#endif
|
#endif
|
||||||
|
@ -1900,6 +1901,7 @@ jit::AttachBaselineCacheIRStub(JSContext* cx, const CacheIRWriter& writer,
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case CacheKind::In:
|
case CacheKind::In:
|
||||||
case CacheKind::HasOwn:
|
case CacheKind::HasOwn:
|
||||||
|
case CacheKind::BindName:
|
||||||
stubDataOffset = sizeof(ICCacheIR_Regular);
|
stubDataOffset = sizeof(ICCacheIR_Regular);
|
||||||
stubKind = CacheIRStubKind::Regular;
|
stubKind = CacheIRStubKind::Regular;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1426,6 +1426,24 @@ DoBindNameFallback(JSContext* cx, BaselineFrame* frame, ICBindName_Fallback* stu
|
||||||
|
|
||||||
RootedPropertyName name(cx, frame->script()->getName(pc));
|
RootedPropertyName name(cx, frame->script()->getName(pc));
|
||||||
|
|
||||||
|
if (stub->state().maybeTransition())
|
||||||
|
stub->discardStubs(cx);
|
||||||
|
|
||||||
|
if (stub->state().canAttachStub()) {
|
||||||
|
bool attached = false;
|
||||||
|
RootedScript script(cx, frame->script());
|
||||||
|
BindNameIRGenerator gen(cx, script, pc, stub->state().mode(), envChain, name);
|
||||||
|
if (gen.tryAttachStub()) {
|
||||||
|
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||||
|
ICStubEngine::Baseline, script, stub,
|
||||||
|
&attached);
|
||||||
|
if (newStub)
|
||||||
|
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
|
||||||
|
}
|
||||||
|
if (!attached)
|
||||||
|
stub->state().trackNotAttached();
|
||||||
|
}
|
||||||
|
|
||||||
RootedObject scope(cx);
|
RootedObject scope(cx);
|
||||||
if (!LookupNameUnqualified(cx, name, envChain, &scope))
|
if (!LookupNameUnqualified(cx, name, envChain, &scope))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1857,6 +1857,130 @@ GetNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId, HandleId id)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BindNameIRGenerator::BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||||
|
ICState::Mode mode, HandleObject env,
|
||||||
|
HandlePropertyName name)
|
||||||
|
: IRGenerator(cx, script, pc, CacheKind::BindName, mode),
|
||||||
|
env_(env),
|
||||||
|
name_(name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BindNameIRGenerator::tryAttachStub()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(cacheKind_ == CacheKind::BindName);
|
||||||
|
|
||||||
|
AutoAssertNoPendingException aanpe(cx_);
|
||||||
|
|
||||||
|
ObjOperandId envId(writer.setInputOperandId(0));
|
||||||
|
RootedId id(cx_, NameToId(name_));
|
||||||
|
|
||||||
|
if (tryAttachGlobalName(envId, id))
|
||||||
|
return true;
|
||||||
|
if (tryAttachEnvironmentName(envId, id))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BindNameIRGenerator::tryAttachGlobalName(ObjOperandId objId, HandleId id)
|
||||||
|
{
|
||||||
|
if (!IsGlobalOp(JSOp(*pc_)) || script_->hasNonSyntacticScope())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Handle<LexicalEnvironmentObject*> globalLexical = env_.as<LexicalEnvironmentObject>();
|
||||||
|
MOZ_ASSERT(globalLexical->isGlobal());
|
||||||
|
|
||||||
|
JSObject* result = nullptr;
|
||||||
|
if (Shape* shape = globalLexical->lookup(cx_, id)) {
|
||||||
|
// If this is an uninitialized lexical or a const, we need to return a
|
||||||
|
// RuntimeLexicalErrorObject.
|
||||||
|
if (globalLexical->getSlot(shape->slot()).isMagic() || !shape->writable())
|
||||||
|
return false;
|
||||||
|
result = globalLexical;
|
||||||
|
} else {
|
||||||
|
result = &globalLexical->global();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == globalLexical) {
|
||||||
|
// Lexical bindings are non-configurable so we can just return the
|
||||||
|
// global lexical.
|
||||||
|
writer.loadObjectResult(objId);
|
||||||
|
} else {
|
||||||
|
// If the property exists on the global and is non-configurable, it cannot be
|
||||||
|
// shadowed by the lexical scope so we can just return the global without a
|
||||||
|
// shape guard.
|
||||||
|
Shape* shape = result->as<GlobalObject>().lookup(cx_, id);
|
||||||
|
if (!shape || shape->configurable())
|
||||||
|
writer.guardShape(objId, globalLexical->lastProperty());
|
||||||
|
ObjOperandId globalId = writer.loadEnclosingEnvironment(objId);
|
||||||
|
writer.loadObjectResult(globalId);
|
||||||
|
}
|
||||||
|
writer.returnFromIC();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BindNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId, HandleId id)
|
||||||
|
{
|
||||||
|
if (IsGlobalOp(JSOp(*pc_)) || script_->hasNonSyntacticScope())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedObject env(cx_, env_);
|
||||||
|
RootedShape shape(cx_);
|
||||||
|
while (true) {
|
||||||
|
if (!env->is<GlobalObject>() && !env->is<EnvironmentObject>())
|
||||||
|
return false;
|
||||||
|
if (env->is<WithEnvironmentObject>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MOZ_ASSERT(!env->hasUncacheableProto());
|
||||||
|
|
||||||
|
// When we reach an unqualified variables object (like the global) we
|
||||||
|
// have to stop looking and return that object.
|
||||||
|
if (env->isUnqualifiedVarObj())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Check for an 'own' property on the env. There is no need to
|
||||||
|
// check the prototype as non-with scopes do not inherit properties
|
||||||
|
// from any prototype.
|
||||||
|
shape = env->as<NativeObject>().lookup(cx_, id);
|
||||||
|
if (shape)
|
||||||
|
break;
|
||||||
|
|
||||||
|
env = env->enclosingEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is an uninitialized lexical or a const, we need to return a
|
||||||
|
// RuntimeLexicalErrorObject.
|
||||||
|
RootedNativeObject holder(cx_, &env->as<NativeObject>());
|
||||||
|
if (shape &&
|
||||||
|
holder->is<EnvironmentObject>() &&
|
||||||
|
(holder->getSlot(shape->slot()).isMagic() || !shape->writable()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjOperandId lastObjId = objId;
|
||||||
|
env = env_;
|
||||||
|
while (env) {
|
||||||
|
if (NeedEnvironmentShapeGuard(env) && !env->is<GlobalObject>())
|
||||||
|
writer.guardShape(lastObjId, env->maybeShape());
|
||||||
|
|
||||||
|
if (env == holder)
|
||||||
|
break;
|
||||||
|
|
||||||
|
lastObjId = writer.loadEnclosingEnvironment(lastObjId);
|
||||||
|
env = env->enclosingEnvironment();
|
||||||
|
}
|
||||||
|
writer.loadObjectResult(lastObjId);
|
||||||
|
writer.returnFromIC();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
|
InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||||
ICState::Mode mode, HandleValue key, HandleObject obj)
|
ICState::Mode mode, HandleValue key, HandleObject obj)
|
||||||
: IRGenerator(cx, script, pc, CacheKind::In, mode),
|
: IRGenerator(cx, script, pc, CacheKind::In, mode),
|
||||||
|
|
|
@ -139,6 +139,7 @@ class TypedOperandId : public OperandId
|
||||||
_(GetName) \
|
_(GetName) \
|
||||||
_(SetProp) \
|
_(SetProp) \
|
||||||
_(SetElem) \
|
_(SetElem) \
|
||||||
|
_(BindName) \
|
||||||
_(In) \
|
_(In) \
|
||||||
_(HasOwn)
|
_(HasOwn)
|
||||||
|
|
||||||
|
@ -236,6 +237,7 @@ extern const char* CacheKindNames[];
|
||||||
_(LoadFrameArgumentResult) \
|
_(LoadFrameArgumentResult) \
|
||||||
_(LoadEnvironmentFixedSlotResult) \
|
_(LoadEnvironmentFixedSlotResult) \
|
||||||
_(LoadEnvironmentDynamicSlotResult) \
|
_(LoadEnvironmentDynamicSlotResult) \
|
||||||
|
_(LoadObjectResult) \
|
||||||
_(CallScriptedGetterResult) \
|
_(CallScriptedGetterResult) \
|
||||||
_(CallNativeGetterResult) \
|
_(CallNativeGetterResult) \
|
||||||
_(CallProxyGetResult) \
|
_(CallProxyGetResult) \
|
||||||
|
@ -891,6 +893,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
||||||
writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
|
writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
|
||||||
addStubField(offset, StubField::Type::RawWord);
|
addStubField(offset, StubField::Type::RawWord);
|
||||||
}
|
}
|
||||||
|
void loadObjectResult(ObjOperandId obj) {
|
||||||
|
writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
|
||||||
|
}
|
||||||
|
|
||||||
void typeMonitorResult() {
|
void typeMonitorResult() {
|
||||||
writeOp(CacheOp::TypeMonitorResult);
|
writeOp(CacheOp::TypeMonitorResult);
|
||||||
|
@ -1108,6 +1113,22 @@ class MOZ_RAII GetNameIRGenerator : public IRGenerator
|
||||||
bool tryAttachStub();
|
bool tryAttachStub();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BindNameIRGenerator generates CacheIR for a BindName IC.
|
||||||
|
class MOZ_RAII BindNameIRGenerator : public IRGenerator
|
||||||
|
{
|
||||||
|
HandleObject env_;
|
||||||
|
HandlePropertyName name_;
|
||||||
|
|
||||||
|
bool tryAttachGlobalName(ObjOperandId objId, HandleId id);
|
||||||
|
bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode,
|
||||||
|
HandleObject env, HandlePropertyName name);
|
||||||
|
|
||||||
|
bool tryAttachStub();
|
||||||
|
};
|
||||||
|
|
||||||
// Information used by SetProp/SetElem stubs to check/update property types.
|
// Information used by SetProp/SetElem stubs to check/update property types.
|
||||||
class MOZ_RAII PropertyTypeCheckInfo
|
class MOZ_RAII PropertyTypeCheckInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -2109,6 +2109,20 @@ CacheIRCompiler::emitLoadTypedObjectResultShared(const Address& fieldAddr, Regis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CacheIRCompiler::emitLoadObjectResult()
|
||||||
|
{
|
||||||
|
AutoOutputRegister output(*this);
|
||||||
|
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||||
|
|
||||||
|
if (output.hasValue())
|
||||||
|
masm.tagValue(JSVAL_TYPE_OBJECT, obj, output.valueReg());
|
||||||
|
else
|
||||||
|
masm.mov(obj, output.typedReg().gpr());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CacheIRCompiler::emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type,
|
CacheIRCompiler::emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type,
|
||||||
const Address& dest, Register scratch)
|
const Address& dest, Register scratch)
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace jit {
|
||||||
_(LoadDenseElementHoleExistsResult) \
|
_(LoadDenseElementHoleExistsResult) \
|
||||||
_(LoadUnboxedArrayElementResult) \
|
_(LoadUnboxedArrayElementResult) \
|
||||||
_(LoadTypedElementResult) \
|
_(LoadTypedElementResult) \
|
||||||
|
_(LoadObjectResult) \
|
||||||
_(MegamorphicLoadSlotByValueResult) \
|
_(MegamorphicLoadSlotByValueResult) \
|
||||||
_(MegamorphicHasOwnResult) \
|
_(MegamorphicHasOwnResult) \
|
||||||
_(WrapResult)
|
_(WrapResult)
|
||||||
|
|
|
@ -70,53 +70,6 @@ using JS::GenericNaN;
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace jit {
|
namespace jit {
|
||||||
|
|
||||||
// This out-of-line cache is used to do a double dispatch including it-self and
|
|
||||||
// the wrapped IonCache.
|
|
||||||
class OutOfLineUpdateCache :
|
|
||||||
public OutOfLineCodeBase<CodeGenerator>,
|
|
||||||
public IonCacheVisitor
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
LInstruction* lir_;
|
|
||||||
size_t cacheIndex_;
|
|
||||||
RepatchLabel entry_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
OutOfLineUpdateCache(LInstruction* lir, size_t cacheIndex)
|
|
||||||
: lir_(lir),
|
|
||||||
cacheIndex_(cacheIndex)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void bind(MacroAssembler* masm) {
|
|
||||||
// The binding of the initial jump is done in
|
|
||||||
// CodeGenerator::visitOutOfLineCache.
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getCacheIndex() const {
|
|
||||||
return cacheIndex_;
|
|
||||||
}
|
|
||||||
LInstruction* lir() const {
|
|
||||||
return lir_;
|
|
||||||
}
|
|
||||||
RepatchLabel& entry() {
|
|
||||||
return entry_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void accept(CodeGenerator* codegen) {
|
|
||||||
codegen->visitOutOfLineCache(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ICs' visit functions delegating the work to the CodeGen visit funtions.
|
|
||||||
#define VISIT_CACHE_FUNCTION(op) \
|
|
||||||
void visit##op##IC(CodeGenerator* codegen) { \
|
|
||||||
CodeGenerator::DataPtr<op##IC> ic(codegen, getCacheIndex()); \
|
|
||||||
codegen->visit##op##IC(this, ic); \
|
|
||||||
}
|
|
||||||
|
|
||||||
IONCACHE_KIND_LIST(VISIT_CACHE_FUNCTION)
|
|
||||||
#undef VISIT_CACHE_FUNCTION
|
|
||||||
};
|
|
||||||
|
|
||||||
class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
|
class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -151,33 +104,6 @@ class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This function is declared here because it needs to instantiate an
|
|
||||||
// OutOfLineUpdateCache, but we want to keep it visible inside the
|
|
||||||
// CodeGeneratorShared such as we can specialize inline caches in function of
|
|
||||||
// the architecture.
|
|
||||||
void
|
|
||||||
CodeGeneratorShared::addCache(LInstruction* lir, size_t cacheIndex)
|
|
||||||
{
|
|
||||||
if (cacheIndex == SIZE_MAX) {
|
|
||||||
masm.setOOM();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataPtr<IonCache> cache(this, cacheIndex);
|
|
||||||
MInstruction* mir = lir->mirRaw()->toInstruction();
|
|
||||||
if (mir->resumePoint())
|
|
||||||
cache->setScriptedLocation(mir->block()->info().script(),
|
|
||||||
mir->resumePoint()->pc());
|
|
||||||
else
|
|
||||||
cache->setIdempotent();
|
|
||||||
|
|
||||||
OutOfLineUpdateCache* ool = new(alloc()) OutOfLineUpdateCache(lir, cacheIndex);
|
|
||||||
addOutOfLineCode(ool, mir);
|
|
||||||
|
|
||||||
cache->emitInitialJump(masm, ool->entry());
|
|
||||||
masm.bind(ool->rejoin());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
|
CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
|
||||||
{
|
{
|
||||||
|
@ -208,19 +134,6 @@ CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
|
||||||
cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset()));
|
cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenerator::visitOutOfLineCache(OutOfLineUpdateCache* ool)
|
|
||||||
{
|
|
||||||
DataPtr<IonCache> cache(this, ool->getCacheIndex());
|
|
||||||
|
|
||||||
// Register the location of the OOL path in the IC.
|
|
||||||
cache->setFallbackLabel(masm.labelForPatch());
|
|
||||||
masm.bind(&ool->entry());
|
|
||||||
|
|
||||||
// Dispatch to ICs' accept functions.
|
|
||||||
cache->accept(this, ool);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue,
|
typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue,
|
||||||
MutableHandleValue);
|
MutableHandleValue);
|
||||||
static const VMFunction IonGetPropertyICInfo =
|
static const VMFunction IonGetPropertyICInfo =
|
||||||
|
@ -241,6 +154,10 @@ typedef bool (*IonHasOwnICFn)(JSContext*, HandleScript, IonHasOwnIC*, HandleValu
|
||||||
static const VMFunction IonHasOwnICInfo =
|
static const VMFunction IonHasOwnICInfo =
|
||||||
FunctionInfo<IonHasOwnICFn>(IonHasOwnIC::update, "IonHasOwnIC::update");
|
FunctionInfo<IonHasOwnICFn>(IonHasOwnIC::update, "IonHasOwnIC::update");
|
||||||
|
|
||||||
|
typedef JSObject* (*IonBindNameICFn)(JSContext*, HandleScript, IonBindNameIC*, HandleObject);
|
||||||
|
static const VMFunction IonBindNameICInfo =
|
||||||
|
FunctionInfo<IonBindNameICFn>(IonBindNameIC::update, "IonBindNameIC::update");
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
|
CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
|
||||||
{
|
{
|
||||||
|
@ -309,6 +226,23 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
|
||||||
masm.jump(ool->rejoin());
|
masm.jump(ool->rejoin());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case CacheKind::BindName: {
|
||||||
|
IonBindNameIC* bindNameIC = ic->asBindNameIC();
|
||||||
|
|
||||||
|
saveLive(lir);
|
||||||
|
|
||||||
|
pushArg(bindNameIC->environment());
|
||||||
|
icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
|
||||||
|
pushArg(ImmGCPtr(gen->info().script()));
|
||||||
|
|
||||||
|
callVM(IonBindNameICInfo, lir);
|
||||||
|
|
||||||
|
StoreRegisterTo(bindNameIC->output()).generate(this);
|
||||||
|
restoreLiveIgnore(lir, StoreRegisterTo(bindNameIC->output()).clobbered());
|
||||||
|
|
||||||
|
masm.jump(ool->rejoin());
|
||||||
|
return;
|
||||||
|
}
|
||||||
case CacheKind::In:
|
case CacheKind::In:
|
||||||
MOZ_CRASH("Baseline-specific for now");
|
MOZ_CRASH("Baseline-specific for now");
|
||||||
case CacheKind::HasOwn: {
|
case CacheKind::HasOwn: {
|
||||||
|
@ -9625,7 +9559,6 @@ CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffs
|
||||||
MOZ_ASSERT(graph.numConstants() == 0);
|
MOZ_ASSERT(graph.numConstants() == 0);
|
||||||
MOZ_ASSERT(safepointIndices_.empty());
|
MOZ_ASSERT(safepointIndices_.empty());
|
||||||
MOZ_ASSERT(osiIndices_.empty());
|
MOZ_ASSERT(osiIndices_.empty());
|
||||||
MOZ_ASSERT(cacheList_.empty());
|
|
||||||
MOZ_ASSERT(icList_.empty());
|
MOZ_ASSERT(icList_.empty());
|
||||||
MOZ_ASSERT(safepoints_.size() == 0);
|
MOZ_ASSERT(safepoints_.size() == 0);
|
||||||
MOZ_ASSERT(!scriptCounts_);
|
MOZ_ASSERT(!scriptCounts_);
|
||||||
|
@ -9847,7 +9780,7 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
||||||
snapshots_.listSize(), snapshots_.RVATableSize(),
|
snapshots_.listSize(), snapshots_.RVATableSize(),
|
||||||
recovers_.size(), bailouts_.length(), graph.numConstants(),
|
recovers_.size(), bailouts_.length(), graph.numConstants(),
|
||||||
safepointIndices_.length(), osiIndices_.length(),
|
safepointIndices_.length(), osiIndices_.length(),
|
||||||
cacheList_.length(), icList_.length(), runtimeData_.length(),
|
icList_.length(), runtimeData_.length(),
|
||||||
safepoints_.size(), patchableBackedges_.length(),
|
safepoints_.size(), patchableBackedges_.length(),
|
||||||
sharedStubs_.length(), optimizationLevel);
|
sharedStubs_.length(), optimizationLevel);
|
||||||
if (!ionScript)
|
if (!ionScript)
|
||||||
|
@ -10012,8 +9945,6 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
||||||
// for generating inline caches during the execution.
|
// for generating inline caches during the execution.
|
||||||
if (runtimeData_.length())
|
if (runtimeData_.length())
|
||||||
ionScript->copyRuntimeData(&runtimeData_[0]);
|
ionScript->copyRuntimeData(&runtimeData_[0]);
|
||||||
if (cacheList_.length())
|
|
||||||
ionScript->copyCacheEntries(&cacheList_[0], masm);
|
|
||||||
if (icList_.length())
|
if (icList_.length())
|
||||||
ionScript->copyICEntries(&icList_[0], masm);
|
ionScript->copyICEntries(&icList_[0], masm);
|
||||||
|
|
||||||
|
@ -10411,32 +10342,13 @@ CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
|
||||||
void
|
void
|
||||||
CodeGenerator::visitBindNameCache(LBindNameCache* ins)
|
CodeGenerator::visitBindNameCache(LBindNameCache* ins)
|
||||||
{
|
{
|
||||||
|
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
|
||||||
Register envChain = ToRegister(ins->environmentChain());
|
Register envChain = ToRegister(ins->environmentChain());
|
||||||
Register output = ToRegister(ins->output());
|
Register output = ToRegister(ins->output());
|
||||||
BindNameIC cache(envChain, ins->mir()->name(), output);
|
Register temp = ToRegister(ins->temp());
|
||||||
cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
|
|
||||||
|
|
||||||
addCache(ins, allocateCache(cache));
|
IonBindNameIC ic(liveRegs, envChain, output, temp);
|
||||||
}
|
addIC(ins, allocateIC(ic));
|
||||||
|
|
||||||
typedef JSObject* (*BindNameICFn)(JSContext*, HandleScript, size_t, HandleObject);
|
|
||||||
const VMFunction BindNameIC::UpdateInfo =
|
|
||||||
FunctionInfo<BindNameICFn>(BindNameIC::update, "BindNameIC::update");
|
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenerator::visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr<BindNameIC>& ic)
|
|
||||||
{
|
|
||||||
LInstruction* lir = ool->lir();
|
|
||||||
saveLive(lir);
|
|
||||||
|
|
||||||
pushArg(ic->environmentChainReg());
|
|
||||||
pushArg(Imm32(ool->getCacheIndex()));
|
|
||||||
pushArg(ImmGCPtr(gen->info().script()));
|
|
||||||
callVM(BindNameIC::UpdateInfo, lir);
|
|
||||||
StoreRegisterTo(ic->outputReg()).generate(this);
|
|
||||||
restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
|
|
||||||
|
|
||||||
masm.jump(ool->rejoin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -412,8 +412,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||||
void loadJSScriptForBlock(MBasicBlock* block, Register reg);
|
void loadJSScriptForBlock(MBasicBlock* block, Register reg);
|
||||||
void loadOutermostJSScript(Register reg);
|
void loadOutermostJSScript(Register reg);
|
||||||
|
|
||||||
// Inline caches visitors.
|
|
||||||
void visitOutOfLineCache(OutOfLineUpdateCache* ool);
|
|
||||||
void visitOutOfLineICFallback(OutOfLineICFallback* ool);
|
void visitOutOfLineICFallback(OutOfLineICFallback* ool);
|
||||||
|
|
||||||
void visitGetPropertyCacheV(LGetPropertyCacheV* ins);
|
void visitGetPropertyCacheV(LGetPropertyCacheV* ins);
|
||||||
|
@ -424,8 +422,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||||
void visitGetNameCache(LGetNameCache* ins);
|
void visitGetNameCache(LGetNameCache* ins);
|
||||||
void visitHasOwnCache(LHasOwnCache* ins);
|
void visitHasOwnCache(LHasOwnCache* ins);
|
||||||
|
|
||||||
void visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr<BindNameIC>& ic);
|
|
||||||
|
|
||||||
void visitAssertRangeI(LAssertRangeI* ins);
|
void visitAssertRangeI(LAssertRangeI* ins);
|
||||||
void visitAssertRangeD(LAssertRangeD* ins);
|
void visitAssertRangeD(LAssertRangeD* ins);
|
||||||
void visitAssertRangeF(LAssertRangeF* ins);
|
void visitAssertRangeF(LAssertRangeF* ins);
|
||||||
|
|
|
@ -859,8 +859,6 @@ IonScript::IonScript()
|
||||||
recompiling_(false),
|
recompiling_(false),
|
||||||
runtimeData_(0),
|
runtimeData_(0),
|
||||||
runtimeSize_(0),
|
runtimeSize_(0),
|
||||||
cacheIndex_(0),
|
|
||||||
cacheEntries_(0),
|
|
||||||
icIndex_(0),
|
icIndex_(0),
|
||||||
icEntries_(0),
|
icEntries_(0),
|
||||||
safepointIndexOffset_(0),
|
safepointIndexOffset_(0),
|
||||||
|
@ -893,7 +891,7 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo,
|
||||||
size_t snapshotsListSize, size_t snapshotsRVATableSize,
|
size_t snapshotsListSize, size_t snapshotsRVATableSize,
|
||||||
size_t recoversSize, size_t bailoutEntries,
|
size_t recoversSize, size_t bailoutEntries,
|
||||||
size_t constants, size_t safepointIndices,
|
size_t constants, size_t safepointIndices,
|
||||||
size_t osiIndices, size_t cacheEntries, size_t icEntries,
|
size_t osiIndices, size_t icEntries,
|
||||||
size_t runtimeSize, size_t safepointsSize,
|
size_t runtimeSize, size_t safepointsSize,
|
||||||
size_t backedgeEntries, size_t sharedStubEntries,
|
size_t backedgeEntries, size_t sharedStubEntries,
|
||||||
OptimizationLevel optimizationLevel)
|
OptimizationLevel optimizationLevel)
|
||||||
|
@ -916,7 +914,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo,
|
||||||
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
|
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
|
||||||
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
|
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
|
||||||
size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
|
size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
|
||||||
size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment);
|
|
||||||
size_t paddedICEntriesSize = AlignBytes(icEntries * sizeof(uint32_t), DataAlignment);
|
size_t paddedICEntriesSize = AlignBytes(icEntries * sizeof(uint32_t), DataAlignment);
|
||||||
size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
|
size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
|
||||||
size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
|
size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
|
||||||
|
@ -929,7 +926,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo,
|
||||||
paddedConstantsSize +
|
paddedConstantsSize +
|
||||||
paddedSafepointIndicesSize +
|
paddedSafepointIndicesSize +
|
||||||
paddedOsiIndicesSize +
|
paddedOsiIndicesSize +
|
||||||
paddedCacheEntriesSize +
|
|
||||||
paddedICEntriesSize +
|
paddedICEntriesSize +
|
||||||
paddedRuntimeSize +
|
paddedRuntimeSize +
|
||||||
paddedSafepointSize +
|
paddedSafepointSize +
|
||||||
|
@ -946,10 +942,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo,
|
||||||
script->runtimeSize_ = runtimeSize;
|
script->runtimeSize_ = runtimeSize;
|
||||||
offsetCursor += paddedRuntimeSize;
|
offsetCursor += paddedRuntimeSize;
|
||||||
|
|
||||||
script->cacheIndex_ = offsetCursor;
|
|
||||||
script->cacheEntries_ = cacheEntries;
|
|
||||||
offsetCursor += paddedCacheEntriesSize;
|
|
||||||
|
|
||||||
script->icIndex_ = offsetCursor;
|
script->icIndex_ = offsetCursor;
|
||||||
script->icEntries_ = icEntries;
|
script->icEntries_ = icEntries;
|
||||||
offsetCursor += paddedICEntriesSize;
|
offsetCursor += paddedICEntriesSize;
|
||||||
|
@ -1028,9 +1020,6 @@ IonScript::trace(JSTracer* trc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace caches so that the JSScript pointer can be updated if moved.
|
// Trace caches so that the JSScript pointer can be updated if moved.
|
||||||
for (size_t i = 0; i < numCaches(); i++)
|
|
||||||
getCacheFromIndex(i).trace(trc);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < numICs(); i++)
|
for (size_t i = 0; i < numICs(); i++)
|
||||||
getICFromIndex(i).trace(trc);
|
getICFromIndex(i).trace(trc);
|
||||||
}
|
}
|
||||||
|
@ -1133,18 +1122,6 @@ IonScript::copyRuntimeData(const uint8_t* data)
|
||||||
memcpy(runtimeData(), data, runtimeSize());
|
memcpy(runtimeData(), data, runtimeSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
IonScript::copyCacheEntries(const uint32_t* caches, MacroAssembler& masm)
|
|
||||||
{
|
|
||||||
memcpy(cacheIndex(), caches, numCaches() * sizeof(uint32_t));
|
|
||||||
|
|
||||||
// Jumps in the caches reflect the offset of those jumps in the compiled
|
|
||||||
// code, not the absolute positions of the jumps. Update according to the
|
|
||||||
// final code address now.
|
|
||||||
for (size_t i = 0; i < numCaches(); i++)
|
|
||||||
getCacheFromIndex(i).updateBaseAddress(method_, masm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
IonScript::copyICEntries(const uint32_t* icEntries, MacroAssembler& masm)
|
IonScript::copyICEntries(const uint32_t* icEntries, MacroAssembler& masm)
|
||||||
{
|
{
|
||||||
|
@ -1331,25 +1308,6 @@ IonScript::purgeOptimizedStubs(Zone* zone)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
IonScript::purgeCaches()
|
|
||||||
{
|
|
||||||
// Don't reset any ICs if we're invalidated, otherwise, repointing the
|
|
||||||
// inline jump could overwrite an invalidation marker. These ICs can
|
|
||||||
// no longer run, however, the IC slow paths may be active on the stack.
|
|
||||||
// ICs therefore are required to check for invalidation before patching,
|
|
||||||
// to ensure the same invariant.
|
|
||||||
if (invalidated())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (numCaches() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AutoWritableJitCode awjc(method());
|
|
||||||
for (size_t i = 0; i < numCaches(); i++)
|
|
||||||
getCacheFromIndex(i).reset(DontReprotect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
IonScript::purgeICs(Zone* zone)
|
IonScript::purgeICs(Zone* zone)
|
||||||
{
|
{
|
||||||
|
@ -3122,7 +3080,6 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||||
// Purge ICs before we mark this script as invalidated. This will
|
// Purge ICs before we mark this script as invalidated. This will
|
||||||
// prevent lastJump_ from appearing to be a bogus pointer, just
|
// prevent lastJump_ from appearing to be a bogus pointer, just
|
||||||
// in case anyone tries to read it.
|
// in case anyone tries to read it.
|
||||||
ionScript->purgeCaches();
|
|
||||||
ionScript->purgeICs(script->zone());
|
ionScript->purgeICs(script->zone());
|
||||||
ionScript->purgeOptimizedStubs(script->zone());
|
ionScript->purgeOptimizedStubs(script->zone());
|
||||||
|
|
||||||
|
@ -3531,13 +3488,6 @@ AutoFlushICache::~AutoFlushICache()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
jit::PurgeCaches(JSScript* script)
|
|
||||||
{
|
|
||||||
if (script->hasIonScript())
|
|
||||||
script->ionScript()->purgeCaches();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
jit::SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf)
|
jit::SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -214,7 +214,6 @@ bool OffThreadCompilationAvailable(JSContext* cx);
|
||||||
|
|
||||||
void ForbidCompilation(JSContext* cx, JSScript* script);
|
void ForbidCompilation(JSContext* cx, JSScript* script);
|
||||||
|
|
||||||
void PurgeCaches(JSScript* script);
|
|
||||||
size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf);
|
size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf);
|
||||||
void DestroyJitScripts(FreeOp* fop, JSScript* script);
|
void DestroyJitScripts(FreeOp* fop, JSScript* script);
|
||||||
void TraceJitScripts(JSTracer* trc, JSScript* script);
|
void TraceJitScripts(JSTracer* trc, JSScript* script);
|
||||||
|
|
|
@ -426,6 +426,20 @@ IonCacheIRCompiler::init()
|
||||||
allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT);
|
allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CacheKind::BindName: {
|
||||||
|
IonBindNameIC* ic = ic_->asBindNameIC();
|
||||||
|
Register output = ic->output();
|
||||||
|
|
||||||
|
available.add(output);
|
||||||
|
available.add(ic->temp());
|
||||||
|
|
||||||
|
liveRegs_.emplace(ic->liveRegs());
|
||||||
|
outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Object, AnyRegister(output)));
|
||||||
|
|
||||||
|
MOZ_ASSERT(numInputs == 1);
|
||||||
|
allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CacheKind::In:
|
case CacheKind::In:
|
||||||
MOZ_CRASH("Invalid cache");
|
MOZ_CRASH("Invalid cache");
|
||||||
case CacheKind::HasOwn: {
|
case CacheKind::HasOwn: {
|
||||||
|
|
|
@ -38,8 +38,6 @@ using namespace js::jit;
|
||||||
|
|
||||||
using mozilla::tl::FloorLog2;
|
using mozilla::tl::FloorLog2;
|
||||||
|
|
||||||
typedef Rooted<TypedArrayObject*> RootedTypedArrayObject;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeLocationJump::repoint(JitCode* code, MacroAssembler* masm)
|
CodeLocationJump::repoint(JitCode* code, MacroAssembler* masm)
|
||||||
{
|
{
|
||||||
|
@ -89,308 +87,6 @@ CodeOffsetJump::fixup(MacroAssembler* masm)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
IonCache::CacheName(IonCache::Kind kind)
|
|
||||||
{
|
|
||||||
static const char * const names[] =
|
|
||||||
{
|
|
||||||
#define NAME(x) #x,
|
|
||||||
IONCACHE_KIND_LIST(NAME)
|
|
||||||
#undef NAME
|
|
||||||
};
|
|
||||||
return names[kind];
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t IonCache::MAX_STUBS = 16;
|
|
||||||
|
|
||||||
// Helper class which encapsulates logic to attach a stub to an IC by hooking
|
|
||||||
// up rejoins and next stub jumps.
|
|
||||||
//
|
|
||||||
// The simplest stubs have a single jump to the next stub and look like the
|
|
||||||
// following:
|
|
||||||
//
|
|
||||||
// branch guard NEXTSTUB
|
|
||||||
// ... IC-specific code ...
|
|
||||||
// jump REJOIN
|
|
||||||
//
|
|
||||||
// This corresponds to:
|
|
||||||
//
|
|
||||||
// attacher.branchNextStub(masm, ...);
|
|
||||||
// ... emit IC-specific code ...
|
|
||||||
// attacher.jumpRejoin(masm);
|
|
||||||
//
|
|
||||||
// Whether the stub needs multiple next stub jumps look like:
|
|
||||||
//
|
|
||||||
// branch guard FAILURES
|
|
||||||
// ... IC-specific code ...
|
|
||||||
// branch another-guard FAILURES
|
|
||||||
// ... IC-specific code ...
|
|
||||||
// jump REJOIN
|
|
||||||
// FAILURES:
|
|
||||||
// jump NEXTSTUB
|
|
||||||
//
|
|
||||||
// This corresponds to:
|
|
||||||
//
|
|
||||||
// Label failures;
|
|
||||||
// masm.branchX(..., &failures);
|
|
||||||
// ... emit IC-specific code ...
|
|
||||||
// masm.branchY(..., failures);
|
|
||||||
// ... emit more IC-specific code ...
|
|
||||||
// attacher.jumpRejoin(masm);
|
|
||||||
// masm.bind(&failures);
|
|
||||||
// attacher.jumpNextStub(masm);
|
|
||||||
//
|
|
||||||
// A convenience function |branchNextStubOrLabel| is provided in the case that
|
|
||||||
// the stub sometimes has multiple next stub jumps and sometimes a single
|
|
||||||
// one. If a non-nullptr label is passed in, a |branchPtr| will be made to
|
|
||||||
// that label instead of a |branchPtrWithPatch| to the next stub.
|
|
||||||
class IonCache::StubAttacher
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
bool hasNextStubOffset_ : 1;
|
|
||||||
bool hasStubCodePatchOffset_ : 1;
|
|
||||||
|
|
||||||
IonCache& cache_;
|
|
||||||
|
|
||||||
CodeLocationLabel rejoinLabel_;
|
|
||||||
CodeOffsetJump nextStubOffset_;
|
|
||||||
CodeOffsetJump rejoinOffset_;
|
|
||||||
CodeOffset stubCodePatchOffset_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit StubAttacher(IonCache& cache)
|
|
||||||
: hasNextStubOffset_(false),
|
|
||||||
hasStubCodePatchOffset_(false),
|
|
||||||
cache_(cache),
|
|
||||||
rejoinLabel_(cache.rejoinLabel_),
|
|
||||||
nextStubOffset_(),
|
|
||||||
rejoinOffset_(),
|
|
||||||
stubCodePatchOffset_()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// Value used instead of the JitCode self-reference of generated
|
|
||||||
// stubs. This value is needed for marking calls made inside stubs. This
|
|
||||||
// value would be replaced by the attachStub function after the allocation
|
|
||||||
// of the JitCode. The self-reference is used to keep the stub path alive
|
|
||||||
// even if the IonScript is invalidated or if the IC is flushed.
|
|
||||||
static const void* const STUB_ADDR;
|
|
||||||
|
|
||||||
template <class T1, class T2>
|
|
||||||
void branchNextStub(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2) {
|
|
||||||
MOZ_ASSERT(!hasNextStubOffset_);
|
|
||||||
RepatchLabel nextStub;
|
|
||||||
nextStubOffset_ = masm.branchPtrWithPatch(cond, op1, op2, &nextStub);
|
|
||||||
hasNextStubOffset_ = true;
|
|
||||||
masm.bind(&nextStub);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T1, class T2>
|
|
||||||
void branchNextStubOrLabel(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2,
|
|
||||||
Label* label)
|
|
||||||
{
|
|
||||||
if (label != nullptr)
|
|
||||||
masm.branchPtr(cond, op1, op2, label);
|
|
||||||
else
|
|
||||||
branchNextStub(masm, cond, op1, op2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void jumpRejoin(MacroAssembler& masm) {
|
|
||||||
RepatchLabel rejoin;
|
|
||||||
rejoinOffset_ = masm.jumpWithPatch(&rejoin);
|
|
||||||
masm.bind(&rejoin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void jumpNextStub(MacroAssembler& masm) {
|
|
||||||
MOZ_ASSERT(!hasNextStubOffset_);
|
|
||||||
RepatchLabel nextStub;
|
|
||||||
nextStubOffset_ = masm.jumpWithPatch(&nextStub);
|
|
||||||
hasNextStubOffset_ = true;
|
|
||||||
masm.bind(&nextStub);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pushStubCodePointer(MacroAssembler& masm) {
|
|
||||||
// Push the JitCode pointer for the stub we're generating.
|
|
||||||
// WARNING:
|
|
||||||
// WARNING: If JitCode ever becomes relocatable, the following code is incorrect.
|
|
||||||
// WARNING: Note that we're not marking the pointer being pushed as an ImmGCPtr.
|
|
||||||
// WARNING: This location will be patched with the pointer of the generated stub,
|
|
||||||
// WARNING: such as it can be marked when a call is made with this stub. Be aware
|
|
||||||
// WARNING: that ICs are not marked and so this stub will only be kept alive iff
|
|
||||||
// WARNING: it is on the stack at the time of the GC. No ImmGCPtr is needed as the
|
|
||||||
// WARNING: stubs are flushed on GC.
|
|
||||||
// WARNING:
|
|
||||||
MOZ_ASSERT(!hasStubCodePatchOffset_);
|
|
||||||
stubCodePatchOffset_ = masm.PushWithPatch(ImmPtr(STUB_ADDR));
|
|
||||||
hasStubCodePatchOffset_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void patchRejoinJump(MacroAssembler& masm, JitCode* code) {
|
|
||||||
rejoinOffset_.fixup(&masm);
|
|
||||||
CodeLocationJump rejoinJump(code, rejoinOffset_);
|
|
||||||
PatchJump(rejoinJump, rejoinLabel_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void patchStubCodePointer(JitCode* code) {
|
|
||||||
if (hasStubCodePatchOffset_) {
|
|
||||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, stubCodePatchOffset_),
|
|
||||||
ImmPtr(code), ImmPtr(STUB_ADDR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void patchNextStubJump(MacroAssembler& masm, JitCode* code) {
|
|
||||||
// If this path is not taken, we are producing an entry which can no
|
|
||||||
// longer go back into the update function.
|
|
||||||
if (hasNextStubOffset_) {
|
|
||||||
nextStubOffset_.fixup(&masm);
|
|
||||||
CodeLocationJump nextStubJump(code, nextStubOffset_);
|
|
||||||
PatchJump(nextStubJump, cache_.fallbackLabel_);
|
|
||||||
|
|
||||||
// When the last stub fails, it fallback to the ool call which can
|
|
||||||
// produce a stub. Next time we generate a stub, we will patch the
|
|
||||||
// nextStub jump to try the new stub.
|
|
||||||
cache_.lastJump_ = nextStubJump;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const void* const IonCache::StubAttacher::STUB_ADDR = (void*)0xdeadc0de;
|
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::emitInitialJump(MacroAssembler& masm, RepatchLabel& entry)
|
|
||||||
{
|
|
||||||
initialJump_ = masm.jumpWithPatch(&entry);
|
|
||||||
lastJump_ = initialJump_;
|
|
||||||
Label label;
|
|
||||||
masm.bind(&label);
|
|
||||||
rejoinLabel_ = CodeOffset(label.offset());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
|
|
||||||
Handle<JitCode*> code)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(canAttachStub());
|
|
||||||
incrementStubCount();
|
|
||||||
|
|
||||||
// Patch the previous nextStubJump of the last stub, or the jump from the
|
|
||||||
// codeGen, to jump into the newly allocated code.
|
|
||||||
PatchJump(lastJump, CodeLocationLabel(code), Reprotect);
|
|
||||||
}
|
|
||||||
|
|
||||||
IonCache::LinkStatus
|
|
||||||
IonCache::linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
|
|
||||||
JitCode** code)
|
|
||||||
{
|
|
||||||
Linker linker(masm);
|
|
||||||
*code = linker.newCode<CanGC>(cx, ION_CODE);
|
|
||||||
if (!*code)
|
|
||||||
return LINK_ERROR;
|
|
||||||
|
|
||||||
if (ion->invalidated())
|
|
||||||
return CACHE_FLUSHED;
|
|
||||||
|
|
||||||
// Update the success path to continue after the IC initial jump.
|
|
||||||
attacher.patchRejoinJump(masm, *code);
|
|
||||||
|
|
||||||
// Replace the STUB_ADDR constant by the address of the generated stub, such
|
|
||||||
// as it can be kept alive even if the cache is flushed (see
|
|
||||||
// MarkJitExitFrame).
|
|
||||||
attacher.patchStubCodePointer(*code);
|
|
||||||
|
|
||||||
// Update the failure path.
|
|
||||||
attacher.patchNextStubJump(masm, *code);
|
|
||||||
|
|
||||||
return LINK_GOOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher,
|
|
||||||
IonScript* ion, const char* attachKind,
|
|
||||||
JS::TrackedOutcome trackedOutcome)
|
|
||||||
{
|
|
||||||
CodeLocationJump lastJumpBefore = lastJump_;
|
|
||||||
Rooted<JitCode*> code(cx);
|
|
||||||
{
|
|
||||||
// Need to exit the AutoFlushICache context to flush the cache
|
|
||||||
// before attaching the stub below.
|
|
||||||
AutoFlushICache afc("IonCache");
|
|
||||||
LinkStatus status = linkCode(cx, masm, attacher, ion, code.address());
|
|
||||||
if (status != LINK_GOOD)
|
|
||||||
return status != LINK_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc_) {
|
|
||||||
JitSpew(JitSpew_IonIC, "Cache %p(%s:%" PRIuSIZE "/%" PRIuSIZE ") generated %s %s stub at %p",
|
|
||||||
this, script_->filename(), script_->lineno(), script_->pcToOffset(pc_),
|
|
||||||
attachKind, CacheName(kind()), code->raw());
|
|
||||||
} else {
|
|
||||||
JitSpew(JitSpew_IonIC, "Cache %p generated %s %s stub at %p",
|
|
||||||
this, attachKind, CacheName(kind()), code->raw());
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_ION_PERF
|
|
||||||
writePerfSpewerJitCodeProfile(code, "IonCache");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
attachStub(masm, attacher, lastJumpBefore, code);
|
|
||||||
|
|
||||||
// Add entry to native => bytecode mapping for this stub if needed.
|
|
||||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
|
|
||||||
JitcodeGlobalEntry::IonCacheEntry entry;
|
|
||||||
entry.init(code, code->raw(), code->rawEnd(), rejoinAddress(), trackedOutcome);
|
|
||||||
|
|
||||||
// Add entry to the global table.
|
|
||||||
JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
|
||||||
if (!globalTable->addEntry(entry, cx->runtime())) {
|
|
||||||
entry.destroy();
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the jitcode as having a bytecode map.
|
|
||||||
code->setHasBytecodeMap();
|
|
||||||
} else {
|
|
||||||
JitcodeGlobalEntry::DummyEntry entry;
|
|
||||||
entry.init(code, code->raw(), code->rawEnd());
|
|
||||||
|
|
||||||
// Add entry to the global table.
|
|
||||||
JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
|
||||||
if (!globalTable->addEntry(entry, cx->runtime())) {
|
|
||||||
entry.destroy();
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the jitcode as having a bytecode map.
|
|
||||||
code->setHasBytecodeMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report masm OOM errors here, so all our callers can:
|
|
||||||
// return linkAndAttachStub(...);
|
|
||||||
if (masm.oom()) {
|
|
||||||
ReportOutOfMemory(cx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm)
|
|
||||||
{
|
|
||||||
fallbackLabel_.repoint(code, &masm);
|
|
||||||
initialJump_.repoint(code, &masm);
|
|
||||||
lastJump_.repoint(code, &masm);
|
|
||||||
rejoinLabel_.repoint(code, &masm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::trace(JSTracer* trc)
|
|
||||||
{
|
|
||||||
if (script_)
|
|
||||||
TraceManuallyBarrieredEdge(trc, &script_, "IonCache::script_");
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
jit::GetReturnAddressToIonCode(JSContext* cx)
|
jit::GetReturnAddressToIonCode(JSContext* cx)
|
||||||
{
|
{
|
||||||
|
@ -523,21 +219,6 @@ jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::disable()
|
|
||||||
{
|
|
||||||
reset(Reprotect);
|
|
||||||
this->disabled_ = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IonCache::reset(ReprotectCode reprotect)
|
|
||||||
{
|
|
||||||
this->stubCount_ = 0;
|
|
||||||
PatchJump(initialJump_, fallbackLabel_, reprotect);
|
|
||||||
lastJump_ = initialJump_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
|
jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
|
||||||
{
|
{
|
||||||
|
@ -642,171 +323,3 @@ jit::EmitIonStoreDenseElement(MacroAssembler& masm, const ConstantOrRegister& va
|
||||||
|
|
||||||
masm.bind(&done);
|
masm.bind(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
BindNameIC::attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
|
||||||
HandleObject envChain)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(envChain->is<GlobalObject>());
|
|
||||||
|
|
||||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
|
||||||
StubAttacher attacher(*this);
|
|
||||||
|
|
||||||
// Guard on the env chain.
|
|
||||||
attacher.branchNextStub(masm, Assembler::NotEqual, environmentChainReg(),
|
|
||||||
ImmGCPtr(envChain));
|
|
||||||
masm.movePtr(ImmGCPtr(envChain), outputReg());
|
|
||||||
|
|
||||||
attacher.jumpRejoin(masm);
|
|
||||||
|
|
||||||
return linkAndAttachStub(cx, masm, attacher, ion, "global");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
GenerateEnvironmentChainGuard(MacroAssembler& masm, JSObject* envObj,
|
|
||||||
Register envObjReg, Shape* shape, Label* failures)
|
|
||||||
{
|
|
||||||
if (envObj->is<CallObject>()) {
|
|
||||||
// We can skip a guard on the call object if the script's bindings are
|
|
||||||
// guaranteed to be immutable (and thus cannot introduce shadowing
|
|
||||||
// variables).
|
|
||||||
CallObject* callObj = &envObj->as<CallObject>();
|
|
||||||
JSFunction* fun = &callObj->callee();
|
|
||||||
// The function might have been relazified under rare conditions.
|
|
||||||
// In that case, we pessimistically create the guard, as we'd
|
|
||||||
// need to root various pointers to delazify,
|
|
||||||
if (fun->hasScript()) {
|
|
||||||
JSScript* script = fun->nonLazyScript();
|
|
||||||
if (!script->funHasExtensibleScope())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (envObj->is<GlobalObject>()) {
|
|
||||||
// If this is the last object on the scope walk, and the property we've
|
|
||||||
// found is not configurable, then we don't need a shape guard because
|
|
||||||
// the shape cannot be removed.
|
|
||||||
if (shape && !shape->configurable())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Address shapeAddr(envObjReg, ShapedObject::offsetOfShape());
|
|
||||||
masm.branchPtr(Assembler::NotEqual, shapeAddr,
|
|
||||||
ImmGCPtr(envObj->as<NativeObject>().lastProperty()), failures);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
GenerateEnvironmentChainGuards(MacroAssembler& masm, JSObject* envChain, JSObject* holder,
|
|
||||||
Register outputReg, Label* failures, bool skipLastGuard = false)
|
|
||||||
{
|
|
||||||
JSObject* tobj = envChain;
|
|
||||||
|
|
||||||
// Walk up the env chain. Note that IsCacheableEnvironmentChain guarantees the
|
|
||||||
// |tobj == holder| condition terminates the loop.
|
|
||||||
while (true) {
|
|
||||||
MOZ_ASSERT(IsCacheableEnvironment(tobj) || tobj->is<GlobalObject>());
|
|
||||||
|
|
||||||
if (skipLastGuard && tobj == holder)
|
|
||||||
break;
|
|
||||||
|
|
||||||
GenerateEnvironmentChainGuard(masm, tobj, outputReg, nullptr, failures);
|
|
||||||
|
|
||||||
if (tobj == holder)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Load the next link.
|
|
||||||
tobj = &tobj->as<EnvironmentObject>().enclosingEnvironment();
|
|
||||||
masm.extractObject(Address(outputReg, EnvironmentObject::offsetOfEnclosingEnvironment()),
|
|
||||||
outputReg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
BindNameIC::attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
|
||||||
HandleObject envChain, HandleObject holder)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsCacheableEnvironment(envChain));
|
|
||||||
|
|
||||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
|
||||||
StubAttacher attacher(*this);
|
|
||||||
|
|
||||||
// Guard on the shape of the env chain.
|
|
||||||
Label failures;
|
|
||||||
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
|
|
||||||
Address(environmentChainReg(), ShapedObject::offsetOfShape()),
|
|
||||||
ImmGCPtr(envChain->as<NativeObject>().lastProperty()),
|
|
||||||
holder != envChain ? &failures : nullptr);
|
|
||||||
|
|
||||||
if (holder != envChain) {
|
|
||||||
JSObject* parent = &envChain->as<EnvironmentObject>().enclosingEnvironment();
|
|
||||||
masm.extractObject(Address(environmentChainReg(),
|
|
||||||
EnvironmentObject::offsetOfEnclosingEnvironment()),
|
|
||||||
outputReg());
|
|
||||||
|
|
||||||
GenerateEnvironmentChainGuards(masm, parent, holder, outputReg(), &failures);
|
|
||||||
} else {
|
|
||||||
masm.movePtr(environmentChainReg(), outputReg());
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point outputReg holds the object on which the property
|
|
||||||
// was found, so we're done.
|
|
||||||
attacher.jumpRejoin(masm);
|
|
||||||
|
|
||||||
// All failures flow to here, so there is a common point to patch.
|
|
||||||
if (holder != envChain) {
|
|
||||||
masm.bind(&failures);
|
|
||||||
attacher.jumpNextStub(masm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return linkAndAttachStub(cx, masm, attacher, ion, "non-global");
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
IsCacheableNonGlobalEnvironmentChain(JSObject* envChain, JSObject* holder)
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
if (!IsCacheableEnvironment(envChain)) {
|
|
||||||
JitSpew(JitSpew_IonIC, "Non-cacheable object on env chain");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (envChain == holder)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
envChain = &envChain->as<EnvironmentObject>().enclosingEnvironment();
|
|
||||||
if (!envChain) {
|
|
||||||
JitSpew(JitSpew_IonIC, "env chain indirect hit");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_CRASH("Invalid env chain");
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
|
|
||||||
HandleObject envChain)
|
|
||||||
{
|
|
||||||
IonScript* ion = outerScript->ionScript();
|
|
||||||
BindNameIC& cache = ion->getCache(cacheIndex).toBindName();
|
|
||||||
HandlePropertyName name = cache.name();
|
|
||||||
|
|
||||||
RootedObject holder(cx);
|
|
||||||
if (!LookupNameUnqualified(cx, name, envChain, &holder))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// Stop generating new stubs once we hit the stub count limit, see
|
|
||||||
// GetPropertyCache.
|
|
||||||
if (cache.canAttachStub()) {
|
|
||||||
if (envChain->is<GlobalObject>()) {
|
|
||||||
if (!cache.attachGlobal(cx, outerScript, ion, envChain))
|
|
||||||
return nullptr;
|
|
||||||
} else if (IsCacheableNonGlobalEnvironmentChain(envChain, holder)) {
|
|
||||||
if (!cache.attachNonGlobal(cx, outerScript, ion, envChain, holder))
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
JitSpew(JitSpew_IonIC, "BINDNAME uncacheable env chain");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -26,392 +26,6 @@
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace jit {
|
namespace jit {
|
||||||
|
|
||||||
class LInstruction;
|
|
||||||
|
|
||||||
#define IONCACHE_KIND_LIST(_) \
|
|
||||||
_(BindName)
|
|
||||||
|
|
||||||
// Forward declarations of Cache kinds.
|
|
||||||
#define FORWARD_DECLARE(kind) class kind##IC;
|
|
||||||
IONCACHE_KIND_LIST(FORWARD_DECLARE)
|
|
||||||
#undef FORWARD_DECLARE
|
|
||||||
|
|
||||||
class IonCacheVisitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
#define VISIT_INS(op) \
|
|
||||||
virtual void visit##op##IC(CodeGenerator* codegen) { \
|
|
||||||
MOZ_CRASH("NYI: " #op "IC"); \
|
|
||||||
}
|
|
||||||
|
|
||||||
IONCACHE_KIND_LIST(VISIT_INS)
|
|
||||||
#undef VISIT_INS
|
|
||||||
};
|
|
||||||
|
|
||||||
// Common structure encoding the state of a polymorphic inline cache contained
|
|
||||||
// in the code for an IonScript. IonCaches are used for polymorphic operations
|
|
||||||
// where multiple implementations may be required.
|
|
||||||
//
|
|
||||||
// Roughly speaking, the cache initially jumps to an out of line fragment
|
|
||||||
// which invokes a cache function to perform the operation. The cache function
|
|
||||||
// may generate a stub to perform the operation in certain cases (e.g. a
|
|
||||||
// particular shape for an input object) and attach the stub to existing
|
|
||||||
// stubs, forming a daisy chain of tests for how to perform the operation in
|
|
||||||
// different circumstances.
|
|
||||||
//
|
|
||||||
// Eventually, if too many stubs are generated the cache function may disable
|
|
||||||
// the cache, by generating a stub to make a call and perform the operation
|
|
||||||
// within the VM.
|
|
||||||
//
|
|
||||||
// The caches initially generate a patchable jump to an out of line call
|
|
||||||
// to the cache function. Stubs are attached by appending: when attaching a
|
|
||||||
// new stub, we patch the any failure conditions in last generated stub to
|
|
||||||
// jump to the new stub. Failure conditions in the new stub jump to the cache
|
|
||||||
// function which may generate new stubs.
|
|
||||||
//
|
|
||||||
// Control flow Pointers
|
|
||||||
// =======# ----. .---->
|
|
||||||
// # | |
|
|
||||||
// #======> \-----/
|
|
||||||
//
|
|
||||||
// Initial state:
|
|
||||||
//
|
|
||||||
// JIT Code
|
|
||||||
// +--------+ .---------------.
|
|
||||||
// | | | |
|
|
||||||
// |========| v +----------+ |
|
|
||||||
// |== IC ==|====>| Cache Fn | |
|
|
||||||
// |========| +----------+ |
|
|
||||||
// | |<=# # |
|
|
||||||
// | | #=======# |
|
|
||||||
// +--------+ Rejoin path |
|
|
||||||
// |________ |
|
|
||||||
// | |
|
|
||||||
// IC | |
|
|
||||||
// Entry | |
|
|
||||||
// +------------+ |
|
|
||||||
// | lastJump_ |---------------/
|
|
||||||
// +------------+
|
|
||||||
// | ... |
|
|
||||||
// +------------+
|
|
||||||
//
|
|
||||||
// Attaching stubs:
|
|
||||||
//
|
|
||||||
// Patch the jump pointed to by lastJump_ to jump to the new stub. Update
|
|
||||||
// lastJump_ to be the new stub's failure jump. The failure jump of the new
|
|
||||||
// stub goes to the fallback label, which is the cache function. In this
|
|
||||||
// fashion, new stubs are _appended_ to the chain of stubs, as lastJump_
|
|
||||||
// points to the _tail_ of the stub chain.
|
|
||||||
//
|
|
||||||
// JIT Code
|
|
||||||
// +--------+ #=======================#
|
|
||||||
// | | # v
|
|
||||||
// |========| # +----------+ +------+
|
|
||||||
// |== IC ==|=# | Cache Fn |<====| Stub |
|
|
||||||
// |========| +----------+ ^ +------+
|
|
||||||
// | |<=# # | #
|
|
||||||
// | | #======#=========|=====#
|
|
||||||
// +--------+ Rejoin path |
|
|
||||||
// |________ |
|
|
||||||
// | |
|
|
||||||
// IC | |
|
|
||||||
// Entry | |
|
|
||||||
// +------------+ |
|
|
||||||
// | lastJump_ |---------------/
|
|
||||||
// +------------+
|
|
||||||
// | ... |
|
|
||||||
// +------------+
|
|
||||||
//
|
|
||||||
// While calls may be made to the cache function and other VM functions, the
|
|
||||||
// cache may still be treated as pure during optimization passes, such that
|
|
||||||
// LICM and GVN may be performed on operations around the cache as if the
|
|
||||||
// operation cannot reenter scripted code through an Invoke() or otherwise have
|
|
||||||
// unexpected behavior. This restricts the sorts of stubs which the cache can
|
|
||||||
// generate or the behaviors which called functions can have, and if a called
|
|
||||||
// function performs a possibly impure operation then the operation will be
|
|
||||||
// marked as such and the calling script will be recompiled.
|
|
||||||
//
|
|
||||||
// Similarly, despite the presence of functions and multiple stubs generated
|
|
||||||
// for a cache, the cache itself may be marked as idempotent and become hoisted
|
|
||||||
// or coalesced by LICM or GVN. This also constrains the stubs which can be
|
|
||||||
// generated for the cache.
|
|
||||||
//
|
|
||||||
// * IonCache usage
|
|
||||||
//
|
|
||||||
// IonCache is the base structure of an inline cache, which generates code stubs
|
|
||||||
// dynamically and attaches them to an IonScript.
|
|
||||||
//
|
|
||||||
// A cache must at least provide a static update function which will usualy have
|
|
||||||
// a JSContext*, followed by the cache index. The rest of the arguments of the
|
|
||||||
// update function are usualy corresponding to the register inputs of the cache,
|
|
||||||
// as it must perform the same operation as any of the stubs that it might
|
|
||||||
// produce. The update function call is handled by the visit function of
|
|
||||||
// CodeGenerator corresponding to this IC.
|
|
||||||
//
|
|
||||||
// The CodeGenerator visit function, as opposed to other visit functions, has
|
|
||||||
// two arguments. The first one is the OutOfLineUpdateCache which stores the LIR
|
|
||||||
// instruction. The second one is the IC object. This function would be called
|
|
||||||
// once the IC is registered with the addCache function of CodeGeneratorShared.
|
|
||||||
//
|
|
||||||
// To register a cache, you must call the addCache function as follow:
|
|
||||||
//
|
|
||||||
// MyCodeIC cache(inputReg1, inputValueReg2, outputReg);
|
|
||||||
// if (!addCache(lir, allocateCache(cache)))
|
|
||||||
// return false;
|
|
||||||
//
|
|
||||||
// Once the cache is allocated with the allocateCache function, any modification
|
|
||||||
// made to the cache would be ignored.
|
|
||||||
//
|
|
||||||
// The addCache function will produce a patchable jump at the location where
|
|
||||||
// it is called. This jump will execute generated stubs and fallback on the code
|
|
||||||
// of the visitMyCodeIC function if no stub match.
|
|
||||||
//
|
|
||||||
// Warning: As the addCache function fallback on a VMCall, calls to
|
|
||||||
// addCache should not be in the same path as another VMCall or in the same
|
|
||||||
// path of another addCache as this is not supported by the invalidation
|
|
||||||
// procedure.
|
|
||||||
class IonCache
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class StubAttacher;
|
|
||||||
|
|
||||||
enum Kind {
|
|
||||||
# define DEFINE_CACHEKINDS(ickind) Cache_##ickind,
|
|
||||||
IONCACHE_KIND_LIST(DEFINE_CACHEKINDS)
|
|
||||||
# undef DEFINE_CACHEKINDS
|
|
||||||
Cache_Invalid
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cache testing and cast.
|
|
||||||
# define CACHEKIND_CASTS(ickind) \
|
|
||||||
bool is##ickind() const { \
|
|
||||||
return kind() == Cache_##ickind; \
|
|
||||||
} \
|
|
||||||
inline ickind##IC& to##ickind(); \
|
|
||||||
inline const ickind##IC& to##ickind() const;
|
|
||||||
IONCACHE_KIND_LIST(CACHEKIND_CASTS)
|
|
||||||
# undef CACHEKIND_CASTS
|
|
||||||
|
|
||||||
virtual Kind kind() const = 0;
|
|
||||||
|
|
||||||
virtual void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static const char* CacheName(Kind kind);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool pure_ : 1;
|
|
||||||
bool idempotent_ : 1;
|
|
||||||
bool disabled_ : 1;
|
|
||||||
size_t stubCount_ : 5;
|
|
||||||
|
|
||||||
CodeLocationLabel fallbackLabel_;
|
|
||||||
|
|
||||||
// Location of this operation, nullptr for idempotent caches.
|
|
||||||
JSScript* script_;
|
|
||||||
jsbytecode* pc_;
|
|
||||||
|
|
||||||
// Location to use when updating profiler pseudostack when leaving this
|
|
||||||
// IC code to enter a callee.
|
|
||||||
jsbytecode* profilerLeavePc_;
|
|
||||||
|
|
||||||
CodeLocationJump initialJump_;
|
|
||||||
CodeLocationJump lastJump_;
|
|
||||||
CodeLocationLabel rejoinLabel_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const size_t MAX_STUBS;
|
|
||||||
void incrementStubCount() {
|
|
||||||
// The IC should stop generating stubs before wrapping stubCount.
|
|
||||||
stubCount_++;
|
|
||||||
MOZ_ASSERT(stubCount_);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
IonCache()
|
|
||||||
: pure_(false),
|
|
||||||
idempotent_(false),
|
|
||||||
disabled_(false),
|
|
||||||
stubCount_(0),
|
|
||||||
fallbackLabel_(),
|
|
||||||
script_(nullptr),
|
|
||||||
pc_(nullptr),
|
|
||||||
profilerLeavePc_(nullptr),
|
|
||||||
initialJump_(),
|
|
||||||
lastJump_(),
|
|
||||||
rejoinLabel_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable();
|
|
||||||
inline bool isDisabled() const {
|
|
||||||
return disabled_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
|
|
||||||
// the location of the out-of-line update (slow) path. This location will
|
|
||||||
// be set to the exitJump of the last generated stub.
|
|
||||||
void setFallbackLabel(CodeOffset fallbackLabel) {
|
|
||||||
fallbackLabel_ = fallbackLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProfilerLeavePC(jsbytecode* pc) {
|
|
||||||
MOZ_ASSERT(pc != nullptr);
|
|
||||||
profilerLeavePc_ = pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the address at which IC rejoins the mainline jitcode.
|
|
||||||
void* rejoinAddress() const {
|
|
||||||
return rejoinLabel_.raw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void emitInitialJump(MacroAssembler& masm, RepatchLabel& entry);
|
|
||||||
void updateBaseAddress(JitCode* code, MacroAssembler& masm);
|
|
||||||
|
|
||||||
// Reset the cache around garbage collection.
|
|
||||||
virtual void reset(ReprotectCode reprotect);
|
|
||||||
|
|
||||||
bool canAttachStub() const {
|
|
||||||
return stubCount_ < MAX_STUBS;
|
|
||||||
}
|
|
||||||
bool empty() const {
|
|
||||||
return stubCount_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LinkStatus {
|
|
||||||
LINK_ERROR,
|
|
||||||
CACHE_FLUSHED,
|
|
||||||
LINK_GOOD
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use the Linker to link the generated code and check if any
|
|
||||||
// monitoring/allocation caused an invalidation of the running ion script,
|
|
||||||
// this function returns CACHE_FLUSHED. In case of allocation issue this
|
|
||||||
// function returns LINK_ERROR.
|
|
||||||
LinkStatus linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
|
|
||||||
JitCode** code);
|
|
||||||
|
|
||||||
// Fixup variables and update jumps in the list of stubs. Increment the
|
|
||||||
// number of attached stubs accordingly.
|
|
||||||
void attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
|
|
||||||
Handle<JitCode*> code);
|
|
||||||
|
|
||||||
// Combine both linkStub and attachStub into one function. In addition, it
|
|
||||||
// produces a spew augmented with the attachKind string.
|
|
||||||
MOZ_MUST_USE bool linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher,
|
|
||||||
IonScript* ion, const char* attachKind,
|
|
||||||
JS::TrackedOutcome = JS::TrackedOutcome::ICOptStub_GenericSuccess);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
bool isAllocated() {
|
|
||||||
return fallbackLabel_.isSet();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool pure() const {
|
|
||||||
return pure_;
|
|
||||||
}
|
|
||||||
bool idempotent() const {
|
|
||||||
return idempotent_;
|
|
||||||
}
|
|
||||||
void setIdempotent() {
|
|
||||||
MOZ_ASSERT(!idempotent_);
|
|
||||||
MOZ_ASSERT(!script_);
|
|
||||||
MOZ_ASSERT(!pc_);
|
|
||||||
idempotent_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScriptedLocation(JSScript* script, jsbytecode* pc) {
|
|
||||||
MOZ_ASSERT(!idempotent_);
|
|
||||||
script_ = script;
|
|
||||||
pc_ = pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getScriptedLocation(MutableHandleScript pscript, jsbytecode** ppc) const {
|
|
||||||
pscript.set(script_);
|
|
||||||
*ppc = pc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsbytecode* pc() const {
|
|
||||||
MOZ_ASSERT(pc_);
|
|
||||||
return pc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace(JSTracer* trc);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define the cache kind and pre-declare data structures used for calling inline
|
|
||||||
// caches.
|
|
||||||
#define CACHE_HEADER(ickind) \
|
|
||||||
Kind kind() const { \
|
|
||||||
return IonCache::Cache_##ickind; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) { \
|
|
||||||
visitor->visit##ickind##IC(codegen); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
static const VMFunction UpdateInfo;
|
|
||||||
|
|
||||||
// Subclasses of IonCache for the various kinds of caches. These do not define
|
|
||||||
// new data members; all caches must be of the same size.
|
|
||||||
|
|
||||||
class BindNameIC : public IonCache
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
Register environmentChain_;
|
|
||||||
PropertyName* name_;
|
|
||||||
Register output_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BindNameIC(Register envChain, PropertyName* name, Register output)
|
|
||||||
: environmentChain_(envChain),
|
|
||||||
name_(name),
|
|
||||||
output_(output)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CACHE_HEADER(BindName)
|
|
||||||
|
|
||||||
Register environmentChainReg() const {
|
|
||||||
return environmentChain_;
|
|
||||||
}
|
|
||||||
HandlePropertyName name() const {
|
|
||||||
return HandlePropertyName::fromMarkedLocation(&name_);
|
|
||||||
}
|
|
||||||
Register outputReg() const {
|
|
||||||
return output_;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
|
||||||
HandleObject envChain);
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
|
||||||
HandleObject envChain, HandleObject holder);
|
|
||||||
|
|
||||||
static JSObject*
|
|
||||||
update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject envChain);
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef CACHE_HEADER
|
|
||||||
|
|
||||||
// Implement cache casts now that the compiler can see the inheritance.
|
|
||||||
#define CACHE_CASTS(ickind) \
|
|
||||||
ickind##IC& IonCache::to##ickind() \
|
|
||||||
{ \
|
|
||||||
MOZ_ASSERT(is##ickind()); \
|
|
||||||
return *static_cast<ickind##IC*>(this); \
|
|
||||||
} \
|
|
||||||
const ickind##IC& IonCache::to##ickind() const \
|
|
||||||
{ \
|
|
||||||
MOZ_ASSERT(is##ickind()); \
|
|
||||||
return *static_cast<const ickind##IC*>(this); \
|
|
||||||
}
|
|
||||||
IONCACHE_KIND_LIST(CACHE_CASTS)
|
|
||||||
#undef OPCODE_CASTS
|
|
||||||
|
|
||||||
bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
|
bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
|
||||||
bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
|
bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
|
||||||
PropertyResult prop);
|
PropertyResult prop);
|
||||||
|
|
|
@ -168,10 +168,8 @@ class RecoverWriter;
|
||||||
class SafepointWriter;
|
class SafepointWriter;
|
||||||
class SafepointIndex;
|
class SafepointIndex;
|
||||||
class OsiIndex;
|
class OsiIndex;
|
||||||
class IonCache;
|
|
||||||
class IonIC;
|
class IonIC;
|
||||||
struct PatchableBackedgeInfo;
|
struct PatchableBackedgeInfo;
|
||||||
struct CacheLocation;
|
|
||||||
|
|
||||||
// An IonScript attaches Ion-generated information to a JSScript.
|
// An IonScript attaches Ion-generated information to a JSScript.
|
||||||
struct IonScript
|
struct IonScript
|
||||||
|
@ -216,12 +214,6 @@ struct IonScript
|
||||||
uint32_t runtimeData_;
|
uint32_t runtimeData_;
|
||||||
uint32_t runtimeSize_;
|
uint32_t runtimeSize_;
|
||||||
|
|
||||||
// State for polymorphic caches in the compiled code. All caches are stored
|
|
||||||
// in the runtimeData buffer and indexed by the cacheIndex which gives a
|
|
||||||
// relative offset in the runtimeData array.
|
|
||||||
uint32_t cacheIndex_;
|
|
||||||
uint32_t cacheEntries_;
|
|
||||||
|
|
||||||
// State for polymorphic caches in the compiled code. All caches are stored
|
// State for polymorphic caches in the compiled code. All caches are stored
|
||||||
// in the runtimeData buffer and indexed by the icIndex which gives a
|
// in the runtimeData buffer and indexed by the icIndex which gives a
|
||||||
// relative offset in the runtimeData array.
|
// relative offset in the runtimeData array.
|
||||||
|
@ -322,9 +314,6 @@ struct IonScript
|
||||||
OsiIndex* osiIndices() {
|
OsiIndex* osiIndices() {
|
||||||
return (OsiIndex*) &bottomBuffer()[osiIndexOffset_];
|
return (OsiIndex*) &bottomBuffer()[osiIndexOffset_];
|
||||||
}
|
}
|
||||||
uint32_t* cacheIndex() {
|
|
||||||
return (uint32_t*) &bottomBuffer()[cacheIndex_];
|
|
||||||
}
|
|
||||||
uint32_t* icIndex() {
|
uint32_t* icIndex() {
|
||||||
return (uint32_t*) &bottomBuffer()[icIndex_];
|
return (uint32_t*) &bottomBuffer()[icIndex_];
|
||||||
}
|
}
|
||||||
|
@ -353,7 +342,7 @@ struct IonScript
|
||||||
size_t snapshotsListSize, size_t snapshotsRVATableSize,
|
size_t snapshotsListSize, size_t snapshotsRVATableSize,
|
||||||
size_t recoversSize, size_t bailoutEntries,
|
size_t recoversSize, size_t bailoutEntries,
|
||||||
size_t constants, size_t safepointIndexEntries,
|
size_t constants, size_t safepointIndexEntries,
|
||||||
size_t osiIndexEntries, size_t cacheEntries, size_t icEntries,
|
size_t osiIndexEntries, size_t icEntries,
|
||||||
size_t runtimeSize, size_t safepointsSize,
|
size_t runtimeSize, size_t safepointsSize,
|
||||||
size_t backedgeEntries, size_t sharedStubEntries,
|
size_t backedgeEntries, size_t sharedStubEntries,
|
||||||
OptimizationLevel optimizationLevel);
|
OptimizationLevel optimizationLevel);
|
||||||
|
@ -501,18 +490,7 @@ struct IonScript
|
||||||
}
|
}
|
||||||
const OsiIndex* getOsiIndex(uint32_t disp) const;
|
const OsiIndex* getOsiIndex(uint32_t disp) const;
|
||||||
const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
|
const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
|
||||||
inline IonCache& getCacheFromIndex(uint32_t index) {
|
|
||||||
MOZ_ASSERT(index < cacheEntries_);
|
|
||||||
uint32_t offset = cacheIndex()[index];
|
|
||||||
return getCache(offset);
|
|
||||||
}
|
|
||||||
inline IonCache& getCache(uint32_t offset) {
|
|
||||||
MOZ_ASSERT(offset < runtimeSize_);
|
|
||||||
return *(IonCache*) &runtimeData()[offset];
|
|
||||||
}
|
|
||||||
size_t numCaches() const {
|
|
||||||
return cacheEntries_;
|
|
||||||
}
|
|
||||||
IonIC& getICFromIndex(uint32_t index) {
|
IonIC& getICFromIndex(uint32_t index) {
|
||||||
MOZ_ASSERT(index < icEntries_);
|
MOZ_ASSERT(index < icEntries_);
|
||||||
uint32_t offset = icIndex()[index];
|
uint32_t offset = icIndex()[index];
|
||||||
|
@ -534,12 +512,7 @@ struct IonScript
|
||||||
size_t runtimeSize() const {
|
size_t runtimeSize() const {
|
||||||
return runtimeSize_;
|
return runtimeSize_;
|
||||||
}
|
}
|
||||||
CacheLocation* getCacheLocs(uint32_t locIndex) {
|
|
||||||
MOZ_ASSERT(locIndex < runtimeSize_);
|
|
||||||
return (CacheLocation*) &runtimeData()[locIndex];
|
|
||||||
}
|
|
||||||
void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect);
|
void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect);
|
||||||
void purgeCaches();
|
|
||||||
void purgeICs(Zone* zone);
|
void purgeICs(Zone* zone);
|
||||||
void unlinkFromRuntime(FreeOp* fop);
|
void unlinkFromRuntime(FreeOp* fop);
|
||||||
void copySnapshots(const SnapshotWriter* writer);
|
void copySnapshots(const SnapshotWriter* writer);
|
||||||
|
@ -549,7 +522,6 @@ struct IonScript
|
||||||
void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm);
|
void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm);
|
||||||
void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm);
|
void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm);
|
||||||
void copyRuntimeData(const uint8_t* data);
|
void copyRuntimeData(const uint8_t* data);
|
||||||
void copyCacheEntries(const uint32_t* caches, MacroAssembler& masm);
|
|
||||||
void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
|
void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
|
||||||
void copySafepoints(const SafepointWriter* writer);
|
void copySafepoints(const SafepointWriter* writer);
|
||||||
void copyPatchableBackedges(JSContext* cx, JitCode* code,
|
void copyPatchableBackedges(JSContext* cx, JitCode* code,
|
||||||
|
|
|
@ -46,6 +46,8 @@ IonIC::scratchRegisterForEntryJump()
|
||||||
return asSetPropertyIC()->temp();
|
return asSetPropertyIC()->temp();
|
||||||
case CacheKind::GetName:
|
case CacheKind::GetName:
|
||||||
return asGetNameIC()->temp();
|
return asGetNameIC()->temp();
|
||||||
|
case CacheKind::BindName:
|
||||||
|
return asBindNameIC()->temp();
|
||||||
case CacheKind::In:
|
case CacheKind::In:
|
||||||
MOZ_CRASH("Baseline-specific for now");
|
MOZ_CRASH("Baseline-specific for now");
|
||||||
case CacheKind::HasOwn:
|
case CacheKind::HasOwn:
|
||||||
|
@ -285,13 +287,12 @@ IonGetNameIC::update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic,
|
||||||
HandleObject envChain, MutableHandleValue res)
|
HandleObject envChain, MutableHandleValue res)
|
||||||
{
|
{
|
||||||
IonScript* ionScript = outerScript->ionScript();
|
IonScript* ionScript = outerScript->ionScript();
|
||||||
|
jsbytecode* pc = ic->pc();
|
||||||
|
RootedPropertyName name(cx, ic->script()->getName(pc));
|
||||||
|
|
||||||
if (ic->state().maybeTransition())
|
if (ic->state().maybeTransition())
|
||||||
ic->discardStubs(cx->zone());
|
ic->discardStubs(cx->zone());
|
||||||
|
|
||||||
jsbytecode* pc = ic->pc();
|
|
||||||
RootedPropertyName name(cx, ic->script()->getName(pc));
|
|
||||||
|
|
||||||
if (ic->state().canAttachStub()) {
|
if (ic->state().canAttachStub()) {
|
||||||
bool attached = false;
|
bool attached = false;
|
||||||
RootedScript script(cx, ic->script());
|
RootedScript script(cx, ic->script());
|
||||||
|
@ -323,6 +324,35 @@ IonGetNameIC::update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ JSObject*
|
||||||
|
IonBindNameIC::update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic,
|
||||||
|
HandleObject envChain)
|
||||||
|
{
|
||||||
|
IonScript* ionScript = outerScript->ionScript();
|
||||||
|
jsbytecode* pc = ic->pc();
|
||||||
|
RootedPropertyName name(cx, ic->script()->getName(pc));
|
||||||
|
|
||||||
|
if (ic->state().maybeTransition())
|
||||||
|
ic->discardStubs(cx->zone());
|
||||||
|
|
||||||
|
if (ic->state().canAttachStub()) {
|
||||||
|
bool attached = false;
|
||||||
|
RootedScript script(cx, ic->script());
|
||||||
|
BindNameIRGenerator gen(cx, script, pc, ic->state().mode(), envChain, name);
|
||||||
|
if (gen.tryAttachStub())
|
||||||
|
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
|
||||||
|
|
||||||
|
if (!attached)
|
||||||
|
ic->state().trackNotAttached();
|
||||||
|
}
|
||||||
|
|
||||||
|
RootedObject holder(cx);
|
||||||
|
if (!LookupNameUnqualified(cx, name, envChain, &holder))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
IonHasOwnIC::update(JSContext* cx, HandleScript outerScript, IonHasOwnIC* ic,
|
IonHasOwnIC::update(JSContext* cx, HandleScript outerScript, IonHasOwnIC* ic,
|
||||||
HandleValue val, HandleValue idVal, int32_t* res)
|
HandleValue val, HandleValue idVal, int32_t* res)
|
||||||
|
|
|
@ -59,6 +59,7 @@ class IonICStub
|
||||||
class IonGetPropertyIC;
|
class IonGetPropertyIC;
|
||||||
class IonSetPropertyIC;
|
class IonSetPropertyIC;
|
||||||
class IonGetNameIC;
|
class IonGetNameIC;
|
||||||
|
class IonBindNameIC;
|
||||||
class IonHasOwnIC;
|
class IonHasOwnIC;
|
||||||
|
|
||||||
class IonIC
|
class IonIC
|
||||||
|
@ -145,6 +146,10 @@ class IonIC
|
||||||
MOZ_ASSERT(kind_ == CacheKind::GetName);
|
MOZ_ASSERT(kind_ == CacheKind::GetName);
|
||||||
return (IonGetNameIC*)this;
|
return (IonGetNameIC*)this;
|
||||||
}
|
}
|
||||||
|
IonBindNameIC* asBindNameIC() {
|
||||||
|
MOZ_ASSERT(kind_ == CacheKind::BindName);
|
||||||
|
return (IonBindNameIC*)this;
|
||||||
|
}
|
||||||
IonHasOwnIC* asHasOwnIC() {
|
IonHasOwnIC* asHasOwnIC() {
|
||||||
MOZ_ASSERT(kind_ == CacheKind::HasOwn);
|
MOZ_ASSERT(kind_ == CacheKind::HasOwn);
|
||||||
return (IonHasOwnIC*)this;
|
return (IonHasOwnIC*)this;
|
||||||
|
@ -280,6 +285,32 @@ class IonGetNameIC : public IonIC
|
||||||
HandleObject envChain, MutableHandleValue res);
|
HandleObject envChain, MutableHandleValue res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IonBindNameIC : public IonIC
|
||||||
|
{
|
||||||
|
LiveRegisterSet liveRegs_;
|
||||||
|
|
||||||
|
Register environment_;
|
||||||
|
Register output_;
|
||||||
|
Register temp_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IonBindNameIC(LiveRegisterSet liveRegs, Register environment, Register output, Register temp)
|
||||||
|
: IonIC(CacheKind::BindName),
|
||||||
|
liveRegs_(liveRegs),
|
||||||
|
environment_(environment),
|
||||||
|
output_(output),
|
||||||
|
temp_(temp)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Register environment() const { return environment_; }
|
||||||
|
Register output() const { return output_; }
|
||||||
|
Register temp() const { return temp_; }
|
||||||
|
LiveRegisterSet liveRegs() const { return liveRegs_; }
|
||||||
|
|
||||||
|
static JSObject* update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic,
|
||||||
|
HandleObject envChain);
|
||||||
|
};
|
||||||
|
|
||||||
class IonHasOwnIC : public IonIC
|
class IonHasOwnIC : public IonIC
|
||||||
{
|
{
|
||||||
LiveRegisterSet liveRegs_;
|
LiveRegisterSet liveRegs_;
|
||||||
|
|
|
@ -3817,7 +3817,7 @@ LIRGenerator::visitBindNameCache(MBindNameCache* ins)
|
||||||
MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
|
MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
|
||||||
MOZ_ASSERT(ins->type() == MIRType::Object);
|
MOZ_ASSERT(ins->type() == MIRType::Object);
|
||||||
|
|
||||||
LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()));
|
LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()), temp());
|
||||||
define(lir, ins);
|
define(lir, ins);
|
||||||
assignSafepoint(lir, ins);
|
assignSafepoint(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ namespace jit {
|
||||||
class OutOfLineCode;
|
class OutOfLineCode;
|
||||||
class CodeGenerator;
|
class CodeGenerator;
|
||||||
class MacroAssembler;
|
class MacroAssembler;
|
||||||
class IonCache;
|
|
||||||
class IonIC;
|
class IonIC;
|
||||||
|
|
||||||
template <class ArgSeq, class StoreOutputTo>
|
template <class ArgSeq, class StoreOutputTo>
|
||||||
|
@ -102,9 +101,6 @@ class CodeGeneratorShared : public LElementVisitor
|
||||||
// Allocated data space needed at runtime.
|
// Allocated data space needed at runtime.
|
||||||
js::Vector<uint8_t, 0, SystemAllocPolicy> runtimeData_;
|
js::Vector<uint8_t, 0, SystemAllocPolicy> runtimeData_;
|
||||||
|
|
||||||
// Vector of information about generated polymorphic inline caches.
|
|
||||||
js::Vector<uint32_t, 0, SystemAllocPolicy> cacheList_;
|
|
||||||
|
|
||||||
// Vector mapping each IC index to its offset in runtimeData_.
|
// Vector mapping each IC index to its offset in runtimeData_.
|
||||||
js::Vector<uint32_t, 0, SystemAllocPolicy> icList_;
|
js::Vector<uint32_t, 0, SystemAllocPolicy> icList_;
|
||||||
|
|
||||||
|
@ -289,23 +285,6 @@ class CodeGeneratorShared : public LElementVisitor
|
||||||
return !masm.oom();
|
return !masm.oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the cache is an IonCache while expecting the size of the derived
|
|
||||||
// class. We only need the cache list at GC time. Everyone else can just take
|
|
||||||
// runtimeData offsets.
|
|
||||||
template <typename T>
|
|
||||||
inline size_t allocateCache(const T& cache) {
|
|
||||||
static_assert(mozilla::IsBaseOf<IonCache, T>::value, "T must inherit from IonCache");
|
|
||||||
size_t index;
|
|
||||||
masm.propagateOOM(allocateData(sizeof(mozilla::AlignedStorage2<T>), &index));
|
|
||||||
masm.propagateOOM(cacheList_.append(index));
|
|
||||||
if (masm.oom())
|
|
||||||
return SIZE_MAX;
|
|
||||||
// Use the copy constructor on the allocated space.
|
|
||||||
MOZ_ASSERT(index == cacheList_.back());
|
|
||||||
new (&runtimeData_[index]) T(cache);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline size_t allocateIC(const T& cache) {
|
inline size_t allocateIC(const T& cache) {
|
||||||
static_assert(mozilla::IsBaseOf<IonIC, T>::value, "T must inherit from IonIC");
|
static_assert(mozilla::IsBaseOf<IonIC, T>::value, "T must inherit from IonIC");
|
||||||
|
@ -497,7 +476,6 @@ class CodeGeneratorShared : public LElementVisitor
|
||||||
inline OutOfLineCode* oolCallVM(const VMFunction& fun, LInstruction* ins, const ArgSeq& args,
|
inline OutOfLineCode* oolCallVM(const VMFunction& fun, LInstruction* ins, const ArgSeq& args,
|
||||||
const StoreOutputTo& out);
|
const StoreOutputTo& out);
|
||||||
|
|
||||||
void addCache(LInstruction* lir, size_t cacheIndex);
|
|
||||||
void addIC(LInstruction* lir, size_t cacheIndex);
|
void addIC(LInstruction* lir, size_t cacheIndex);
|
||||||
|
|
||||||
ReciprocalMulConstants computeDivisionConstants(uint32_t d, int maxLog);
|
ReciprocalMulConstants computeDivisionConstants(uint32_t d, int maxLog);
|
||||||
|
|
|
@ -6850,17 +6850,21 @@ class LSetPropertyPolymorphicT : public LInstructionHelper<0, 2, 1>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LBindNameCache : public LInstructionHelper<1, 1, 0>
|
class LBindNameCache : public LInstructionHelper<1, 1, 1>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(BindNameCache)
|
LIR_HEADER(BindNameCache)
|
||||||
|
|
||||||
explicit LBindNameCache(const LAllocation& envChain) {
|
LBindNameCache(const LAllocation& envChain, const LDefinition& temp) {
|
||||||
setOperand(0, envChain);
|
setOperand(0, envChain);
|
||||||
|
setTemp(0, temp);
|
||||||
}
|
}
|
||||||
const LAllocation* environmentChain() {
|
const LAllocation* environmentChain() {
|
||||||
return getOperand(0);
|
return getOperand(0);
|
||||||
}
|
}
|
||||||
|
const LDefinition* temp() {
|
||||||
|
return getTemp(0);
|
||||||
|
}
|
||||||
const MBindNameCache* mir() const {
|
const MBindNameCache* mir() const {
|
||||||
return mir_->toBindNameCache();
|
return mir_->toBindNameCache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7243,14 +7243,6 @@ js::ReleaseAllJITCode(FreeOp* fop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
js::PurgeJITCaches(Zone* zone)
|
|
||||||
{
|
|
||||||
/* Discard Ion caches. */
|
|
||||||
for (auto script = zone->cellIter<JSScript>(); !script.done(); script.next())
|
|
||||||
jit::PurgeCaches(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind)
|
ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1405,9 +1405,6 @@ struct MOZ_RAII AutoDisableCompactingGC
|
||||||
JSContext* cx;
|
JSContext* cx;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
|
||||||
PurgeJITCaches(JS::Zone* zone);
|
|
||||||
|
|
||||||
// This is the same as IsInsideNursery, but not inlined.
|
// This is the same as IsInsideNursery, but not inlined.
|
||||||
bool
|
bool
|
||||||
UninlinedIsInsideNursery(const gc::Cell* cell);
|
UninlinedIsInsideNursery(const gc::Cell* cell);
|
||||||
|
|
|
@ -138,7 +138,6 @@ struct MOZ_STACK_CLASS BidiParagraphData
|
||||||
bool mIsVisual;
|
bool mIsVisual;
|
||||||
nsBidiLevel mParaLevel;
|
nsBidiLevel mParaLevel;
|
||||||
nsIContent* mPrevContent;
|
nsIContent* mPrevContent;
|
||||||
nsBidi mBidiEngine;
|
|
||||||
nsIFrame* mPrevFrame;
|
nsIFrame* mPrevFrame;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Only used for NOISY debug output.
|
// Only used for NOISY debug output.
|
||||||
|
@ -184,8 +183,9 @@ struct MOZ_STACK_CLASS BidiParagraphData
|
||||||
|
|
||||||
nsresult SetPara()
|
nsresult SetPara()
|
||||||
{
|
{
|
||||||
return mBidiEngine.SetPara(mBuffer.get(), BufferLength(),
|
return mPresContext->GetBidiEngine()
|
||||||
mParaLevel);
|
.SetPara(mBuffer.get(), BufferLength(),
|
||||||
|
mParaLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,7 +197,7 @@ struct MOZ_STACK_CLASS BidiParagraphData
|
||||||
{
|
{
|
||||||
nsBidiLevel paraLevel = mParaLevel;
|
nsBidiLevel paraLevel = mParaLevel;
|
||||||
if (paraLevel == NSBIDI_DEFAULT_LTR || paraLevel == NSBIDI_DEFAULT_RTL) {
|
if (paraLevel == NSBIDI_DEFAULT_LTR || paraLevel == NSBIDI_DEFAULT_RTL) {
|
||||||
mBidiEngine.GetParaLevel(¶Level);
|
mPresContext->GetBidiEngine().GetParaLevel(¶Level);
|
||||||
}
|
}
|
||||||
return paraLevel;
|
return paraLevel;
|
||||||
}
|
}
|
||||||
|
@ -205,18 +205,22 @@ struct MOZ_STACK_CLASS BidiParagraphData
|
||||||
nsBidiDirection GetDirection()
|
nsBidiDirection GetDirection()
|
||||||
{
|
{
|
||||||
nsBidiDirection dir;
|
nsBidiDirection dir;
|
||||||
mBidiEngine.GetDirection(&dir);
|
mPresContext->GetBidiEngine().GetDirection(&dir);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult CountRuns(int32_t *runCount){ return mBidiEngine.CountRuns(runCount); }
|
nsresult CountRuns(int32_t *runCount)
|
||||||
|
{
|
||||||
|
return mPresContext->GetBidiEngine().CountRuns(runCount);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult GetLogicalRun(int32_t aLogicalStart,
|
nsresult GetLogicalRun(int32_t aLogicalStart,
|
||||||
int32_t* aLogicalLimit,
|
int32_t* aLogicalLimit,
|
||||||
nsBidiLevel* aLevel)
|
nsBidiLevel* aLevel)
|
||||||
{
|
{
|
||||||
nsresult rv = mBidiEngine.GetLogicalRun(aLogicalStart,
|
nsresult rv =
|
||||||
aLogicalLimit, aLevel);
|
mPresContext->GetBidiEngine().GetLogicalRun(aLogicalStart,
|
||||||
|
aLogicalLimit, aLevel);
|
||||||
if (mIsVisual || NS_FAILED(rv))
|
if (mIsVisual || NS_FAILED(rv))
|
||||||
*aLevel = GetParaLevel();
|
*aLevel = GetParaLevel();
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -2152,7 +2156,8 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
|
||||||
const char16_t* visualLeftPart;
|
const char16_t* visualLeftPart;
|
||||||
const char16_t* visualRightSide;
|
const char16_t* visualRightSide;
|
||||||
if (dir == NSBIDI_RTL) {
|
if (dir == NSBIDI_RTL) {
|
||||||
// One day, son, this could all be replaced with mBidiEngine.GetVisualIndex ...
|
// One day, son, this could all be replaced with
|
||||||
|
// mPresContext->GetBidiEngine().GetVisualIndex() ...
|
||||||
posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start));
|
posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start));
|
||||||
// Skipping to the "left part".
|
// Skipping to the "left part".
|
||||||
visualLeftPart = text + posResolve->logicalIndex + 1;
|
visualLeftPart = text + posResolve->logicalIndex + 1;
|
||||||
|
@ -2275,9 +2280,9 @@ nsresult nsBidiPresUtils::ProcessTextForRenderingContext(const char16_t* a
|
||||||
aTextRunConstructionDrawTarget,
|
aTextRunConstructionDrawTarget,
|
||||||
&aFontMetrics,
|
&aFontMetrics,
|
||||||
nsPoint(aX, aY));
|
nsPoint(aX, aY));
|
||||||
nsBidi bidiEngine;
|
|
||||||
return ProcessText(aText, aLength, aBaseLevel, aPresContext, processor,
|
return ProcessText(aText, aLength, aBaseLevel, aPresContext, processor,
|
||||||
aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine);
|
aMode, aPosResolve, aPosResolveCount, aWidth,
|
||||||
|
&aPresContext->GetBidiEngine());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
|
|
@ -183,6 +183,10 @@ public:
|
||||||
static nsresult ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength,
|
static nsresult ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength,
|
||||||
int32_t* aIndexMap);
|
int32_t* aIndexMap);
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsBidi(const nsBidi&) = delete;
|
||||||
|
void operator=(const nsBidi&) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UBiDi* mBiDi;
|
UBiDi* mBiDi;
|
||||||
};
|
};
|
||||||
|
|
|
@ -704,6 +704,9 @@ private:
|
||||||
void ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel);
|
void ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel);
|
||||||
|
|
||||||
static bool PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel);
|
static bool PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel);
|
||||||
|
|
||||||
|
nsBidi(const nsBidi&) = delete;
|
||||||
|
void operator=(const nsBidi&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _nsBidi_noICU_h_
|
#endif // _nsBidi_noICU_h_
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
#include "nsCSSParser.h"
|
#include "nsCSSParser.h"
|
||||||
#include "nsBidiUtils.h"
|
#include "nsBidiUtils.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsBidi.h"
|
||||||
|
|
||||||
#include "mozilla/dom/URL.h"
|
#include "mozilla/dom/URL.h"
|
||||||
|
|
||||||
|
@ -3012,6 +3013,17 @@ nsPresContext::GetRestyleGeneration() const
|
||||||
return mRestyleManager->GetRestyleGeneration();
|
return mRestyleManager->GetRestyleGeneration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsBidi&
|
||||||
|
nsPresContext::GetBidiEngine()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (!mBidiEngine) {
|
||||||
|
mBidiEngine.reset(new nsBidi());
|
||||||
|
}
|
||||||
|
return *mBidiEngine;
|
||||||
|
}
|
||||||
|
|
||||||
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
|
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
|
||||||
nsPresContextType aType)
|
nsPresContextType aType)
|
||||||
: nsPresContext(aDocument, aType),
|
: nsPresContext(aDocument, aType),
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define nsPresContext_h___
|
#define nsPresContext_h___
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/WeakPtr.h"
|
#include "mozilla/WeakPtr.h"
|
||||||
#include "nsColor.h"
|
#include "nsColor.h"
|
||||||
#include "nsCoord.h"
|
#include "nsCoord.h"
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
#include "mozilla/StyleBackendType.h"
|
#include "mozilla/StyleBackendType.h"
|
||||||
|
|
||||||
class nsAString;
|
class nsAString;
|
||||||
|
class nsBidi;
|
||||||
class nsIPrintSettings;
|
class nsIPrintSettings;
|
||||||
class nsDocShell;
|
class nsDocShell;
|
||||||
class nsIDocShell;
|
class nsIDocShell;
|
||||||
|
@ -1193,6 +1195,8 @@ public:
|
||||||
mHasWarnedAboutTooLargeDashedOrDottedRadius = true;
|
mHasWarnedAboutTooLargeDashedOrDottedRadius = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsBidi& GetBidiEngine();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class nsRunnableMethod<nsPresContext>;
|
friend class nsRunnableMethod<nsPresContext>;
|
||||||
void ThemeChangedInternal();
|
void ThemeChangedInternal();
|
||||||
|
@ -1349,6 +1353,8 @@ protected:
|
||||||
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
||||||
nsCOMPtr<nsITimer> mPrefChangedTimer;
|
nsCOMPtr<nsITimer> mPrefChangedTimer;
|
||||||
|
|
||||||
|
mozilla::UniquePtr<nsBidi> mBidiEngine;
|
||||||
|
|
||||||
FramePropertyTable mPropertyTable;
|
FramePropertyTable mPropertyTable;
|
||||||
|
|
||||||
struct TransactionInvalidations {
|
struct TransactionInvalidations {
|
||||||
|
|
|
@ -29,11 +29,11 @@ skip-if = toolkit == 'android' # autocomplete
|
||||||
[test_basic_form_autocomplete.html]
|
[test_basic_form_autocomplete.html]
|
||||||
skip-if = toolkit == 'android' # android:autocomplete.
|
skip-if = toolkit == 'android' # android:autocomplete.
|
||||||
[test_insecure_form_field_autocomplete.html]
|
[test_insecure_form_field_autocomplete.html]
|
||||||
skip-if = toolkit == 'android' # android:autocomplete.
|
skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778
|
||||||
[test_password_field_autocomplete.html]
|
[test_password_field_autocomplete.html]
|
||||||
skip-if = toolkit == 'android' # android:autocomplete.
|
skip-if = toolkit == 'android' # android:autocomplete.
|
||||||
[test_insecure_form_field_no_saved_login.html]
|
[test_insecure_form_field_no_saved_login.html]
|
||||||
skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778
|
skip-if = toolkit == 'android' # android:autocomplete.
|
||||||
[test_basic_form_html5.html]
|
[test_basic_form_html5.html]
|
||||||
[test_basic_form_pwevent.html]
|
[test_basic_form_pwevent.html]
|
||||||
[test_basic_form_pwonly.html]
|
[test_basic_form_pwonly.html]
|
||||||
|
|
|
@ -246,19 +246,35 @@ Summariser::Rule(uintptr_t aAddress, int aNewReg,
|
||||||
// is the heart of the summarisation process.
|
// is the heart of the summarisation process.
|
||||||
switch (aNewReg) {
|
switch (aNewReg) {
|
||||||
|
|
||||||
case DW_REG_CFA:
|
case DW_REG_CFA: {
|
||||||
// This is a rule that defines the CFA. The only forms we can
|
// This is a rule that defines the CFA. The only forms we choose to
|
||||||
// represent are: = SP+offset or = FP+offset.
|
// represent are: = SP+offset, = FP+offset, or =prefix-expr.
|
||||||
if (how != NODEREF) {
|
switch (how) {
|
||||||
reason1 = "rule for DW_REG_CFA: invalid |how|";
|
case NODEREF:
|
||||||
goto cant_summarise;
|
if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) {
|
||||||
}
|
reason1 = "rule for DW_REG_CFA: invalid |oldReg|";
|
||||||
if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) {
|
goto cant_summarise;
|
||||||
reason1 = "rule for DW_REG_CFA: invalid |oldReg|";
|
}
|
||||||
goto cant_summarise;
|
break;
|
||||||
|
case DEREF:
|
||||||
|
reason1 = "rule for DW_REG_CFA: invalid |how|";
|
||||||
|
goto cant_summarise;
|
||||||
|
case PFXEXPR: {
|
||||||
|
// Check that the prefix expression only mentions tracked registers.
|
||||||
|
const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs();
|
||||||
|
reason2 = checkPfxExpr(pfxInstrs, offset);
|
||||||
|
if (reason2) {
|
||||||
|
reason1 = "rule for CFA: ";
|
||||||
|
goto cant_summarise;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto cant_summarise;
|
||||||
}
|
}
|
||||||
mCurrRules.mCfaExpr = LExpr(how, oldReg, offset);
|
mCurrRules.mCfaExpr = LExpr(how, oldReg, offset);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DW_REG_INTEL_XSP: case DW_REG_INTEL_XBP: case DW_REG_INTEL_XIP: {
|
case DW_REG_INTEL_XSP: case DW_REG_INTEL_XBP: case DW_REG_INTEL_XIP: {
|
||||||
// This is a new rule for XSP, XBP or XIP (the return address).
|
// This is a new rule for XSP, XBP or XIP (the return address).
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Firefox for Android", "Graphics, Panning and Zooming")
|
||||||
|
|
||||||
# List of stems to generate .cpp and .h files for. To add a stem, add it to
|
# List of stems to generate .cpp and .h files for. To add a stem, add it to
|
||||||
# this list and ensure that $(stem)-classes.txt exists in this directory.
|
# this list and ensure that $(stem)-classes.txt exists in this directory.
|
||||||
generated = [
|
generated = [
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Firefox for Android", "GeckoView")
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'FennecJNINatives.h',
|
'FennecJNINatives.h',
|
||||||
'FennecJNIWrappers.h',
|
'FennecJNIWrappers.h',
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Firefox for Android", "General")
|
||||||
|
|
||||||
EXPORTS.mozilla.jni += [
|
EXPORTS.mozilla.jni += [
|
||||||
'Accessors.h',
|
'Accessors.h',
|
||||||
'Natives.h',
|
'Natives.h',
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Android")
|
||||||
|
|
||||||
DIRS += [
|
DIRS += [
|
||||||
'bindings',
|
'bindings',
|
||||||
'fennec',
|
'fennec',
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
XPIDL_SOURCES += [
|
||||||
'nsPIWidgetCocoa.idl',
|
'nsPIWidgetCocoa.idl',
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gonk")
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'GeckoTouchDispatcher.h',
|
'GeckoTouchDispatcher.h',
|
||||||
'GonkPermission.h',
|
'GonkPermission.h',
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||||
|
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
|
||||||
DIRS += ['mozgtk']
|
DIRS += ['mozgtk']
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'gtk2xtbin.h',
|
'gtk2xtbin.h',
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
DIRS += ['tests']
|
DIRS += ['tests']
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
|
|
|
@ -4,6 +4,30 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
|
with Files("crashtests/*1128214*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Layout")
|
||||||
|
|
||||||
|
with Files("crashtests/*303901*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Graphics")
|
||||||
|
|
||||||
|
with Files("crashtests/*380359*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
|
with Files("reftests/**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("reftests/*fallback*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Layout: Form Controls")
|
||||||
|
|
||||||
|
with Files("*CompositorWidget*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Graphics")
|
||||||
|
|
||||||
|
with Files("*FontRange*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
|
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
|
||||||
|
|
||||||
if toolkit in ('cocoa', 'android', 'gonk', 'uikit'):
|
if toolkit in ('cocoa', 'android', 'gonk', 'uikit'):
|
||||||
|
|
|
@ -4,6 +4,121 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
|
with Files("unit/*macwebapputils*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("unit/*taskbar_jumplistitems*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("TestAppShellSteadyState.cpp"):
|
||||||
|
BUG_COMPONENT = ("Core", "DOM: IndexedDB")
|
||||||
|
|
||||||
|
with Files("TestChromeMargin.cpp"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: win32")
|
||||||
|
|
||||||
|
with Files("*1151186*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
with Files("*413277*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*428405*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*429954*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*444800*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("*466599*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*478536*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
with Files("*485118*"):
|
||||||
|
BUG_COMPONENT = ("Toolkit", "XUL Widgets")
|
||||||
|
|
||||||
|
with Files("*517396*"):
|
||||||
|
BUG_COMPONENT = ("Toolkit", "XUL Widgets")
|
||||||
|
|
||||||
|
with Files("*522217*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*538242*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*565392*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Serializers")
|
||||||
|
|
||||||
|
with Files("*586713*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*593307*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("*596600*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
with Files("*673301*"):
|
||||||
|
BUG_COMPONENT = ("Firefox", "Bookmarks & History")
|
||||||
|
|
||||||
|
with Files("test_assign_event_data.html"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
with Files("test_input_events_on_deactive_window.xul"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
with Files("*chrome_context_menus_win*"):
|
||||||
|
BUG_COMPONENT = ("Core", "General")
|
||||||
|
|
||||||
|
with Files("*composition_text_querycontent*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Internationalization")
|
||||||
|
|
||||||
|
with Files("*key_event_counts*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*imestate*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Internationalization")
|
||||||
|
|
||||||
|
with Files("*mouse_scroll*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("*native*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*panel_mouse_coords*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||||
|
|
||||||
|
with Files("*picker_no_crash*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("*platform_colors*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*plugin*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Plug-ins")
|
||||||
|
|
||||||
|
with Files("*position_on_resize*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||||
|
|
||||||
|
with Files("test_sizemode_events.xul"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*system_status_bar*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Cocoa")
|
||||||
|
|
||||||
|
with Files("*taskbar_progress*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
|
with Files("*wheeltransaction*"):
|
||||||
|
BUG_COMPONENT = ("Core", "Event Handling")
|
||||||
|
|
||||||
|
|
||||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
'GfxInfo.cpp',
|
'GfxInfo.cpp',
|
||||||
'nsAppShell.mm',
|
'nsAppShell.mm',
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Win32")
|
||||||
|
|
||||||
TEST_DIRS += ['tests']
|
TEST_DIRS += ['tests']
|
||||||
|
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
'keysym2ucs.c',
|
'keysym2ucs.c',
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
with Files("**"):
|
||||||
|
BUG_COMPONENT = ("Core", "Widget")
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
|
Загрузка…
Ссылка в новой задаче