зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
809fb645df
|
@ -3022,7 +3022,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
// If the mousedown happened inside a popup, don't
|
||||
// try to set focus on one of its containing elements
|
||||
const nsStyleDisplay* display = currFrame->StyleDisplay();
|
||||
if (display->mDisplay == StyleDisplay::Popup) {
|
||||
if (display->mDisplay == StyleDisplay::MozPopup) {
|
||||
newFocus = nullptr;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_RefCounted_h
|
||||
#define js_RefCounted_h
|
||||
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
// Replacement for mozilla::RefCounted and mozilla::external::AtomicRefCounted
|
||||
// that default to JS::DeletePolicy.
|
||||
|
||||
template <typename T, typename D = JS::DeletePolicy<T>>
|
||||
using RefCounted = mozilla::RefCounted<T, D>;
|
||||
|
||||
template <typename T, typename D = JS::DeletePolicy<T>>
|
||||
using AtomicRefCounted = mozilla::external::AtomicRefCounted<T, D>;
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* js_RefCounted_h */
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete.
|
||||
// Replacement for mozilla::UniquePtr that defaults to JS::DeletePolicy.
|
||||
template <typename T, typename D = JS::DeletePolicy<T>>
|
||||
using UniquePtr = mozilla::UniquePtr<T, D>;
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ testBinary32('mul', 40, 2, 80);
|
|||
testBinary32('div_s', -40, 2, -20);
|
||||
testBinary32('div_u', -40, 2, 2147483628);
|
||||
testBinary32('rem_s', 40, -3, 1);
|
||||
testBinary32('rem_s', 0, -3, 0);
|
||||
testBinary32('rem_u', 40, -3, 40);
|
||||
testBinary32('and', 42, 6, 2);
|
||||
testBinary32('or', 42, 6, 46);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
load(libdir + "wasm.js");
|
||||
|
||||
let bodies = [
|
||||
`
|
||||
i32.const 1
|
||||
i32.const 0
|
||||
i32.div_s
|
||||
`,
|
||||
`
|
||||
i32.const 1
|
||||
i32.const 0
|
||||
i32.rem_s
|
||||
`,
|
||||
`
|
||||
f64.const 1797693134862315708145274e284
|
||||
i64.trunc_s/f64
|
||||
`,
|
||||
`
|
||||
f32.const 1797693134862315708145274e284
|
||||
i32.trunc_s/f32
|
||||
`
|
||||
];
|
||||
|
||||
for (let body of bodies) {
|
||||
wasmFullPass(`
|
||||
(module
|
||||
(func $f (param $x i32) (result i32)
|
||||
loop $top
|
||||
get_local $x
|
||||
if
|
||||
get_local $x
|
||||
br 2
|
||||
end
|
||||
${body}
|
||||
br $top
|
||||
end
|
||||
)
|
||||
(export "run" $f)
|
||||
)`, 42, {}, 42);
|
||||
}
|
|
@ -933,6 +933,17 @@ BaselineCacheIRCompiler::emitGuardIsString()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardIsSymbol()
|
||||
{
|
||||
ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardType()
|
||||
{
|
||||
|
@ -1091,6 +1102,67 @@ BaselineCacheIRCompiler::emitGuardSpecificObject()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardSpecificAtom()
|
||||
{
|
||||
Register str = allocator.useRegister(masm, reader.stringOperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address atomAddr(stubAddress(reader.stubOffset()));
|
||||
|
||||
Label done;
|
||||
masm.branchPtr(Assembler::Equal, atomAddr, str, &done);
|
||||
|
||||
// The pointers are not equal, so if the input string is also an atom it
|
||||
// must be a different string.
|
||||
masm.branchTest32(Assembler::NonZero, Address(str, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::ATOM_BIT), failure->label());
|
||||
|
||||
// Check the length.
|
||||
masm.loadPtr(atomAddr, scratch);
|
||||
masm.loadStringLength(scratch, scratch);
|
||||
masm.branch32(Assembler::NotEqual, Address(str, JSString::offsetOfLength()),
|
||||
scratch, failure->label());
|
||||
|
||||
// We have a non-atomized string with the same length. Call a helper
|
||||
// function to do the comparison.
|
||||
LiveRegisterSet volatileRegs(RegisterSet::Volatile());
|
||||
masm.PushRegsInMask(volatileRegs);
|
||||
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadPtr(atomAddr, scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(str);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelper));
|
||||
masm.mov(ReturnReg, scratch);
|
||||
|
||||
LiveRegisterSet ignore;
|
||||
ignore.add(scratch);
|
||||
masm.PopRegsInMaskIgnore(volatileRegs, ignore);
|
||||
masm.branchIfFalseBool(scratch, failure->label());
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardSpecificSymbol()
|
||||
{
|
||||
Register sym = allocator.useRegister(masm, reader.symbolOperandId());
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address addr(stubAddress(reader.stubOffset()));
|
||||
masm.branchPtr(Assembler::NotEqual, addr, sym, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardMagicValue()
|
||||
{
|
||||
|
@ -1286,6 +1358,34 @@ BaselineCacheIRCompiler::emitCallProxyGetResult()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ProxyGetPropertyByValueFn)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
|
||||
static const VMFunction ProxyGetPropertyByValueInfo =
|
||||
FunctionInfo<ProxyGetPropertyByValueFn>(ProxyGetPropertyByValue, "ProxyGetPropertyByValue");
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitCallProxyGetByValueResult()
|
||||
{
|
||||
AutoStubFrame stubFrame(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
allocator.discardStack(masm);
|
||||
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
masm.Push(idVal);
|
||||
masm.Push(obj);
|
||||
|
||||
if (!callVM(masm, ProxyGetPropertyByValueInfo))
|
||||
return false;
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
|
||||
{
|
||||
|
@ -1577,8 +1677,11 @@ BaselineCacheIRCompiler::init(CacheKind kind)
|
|||
if (!allocator.init(ICStubCompiler::availableGeneralRegs(numInputs)))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(numInputs == 1);
|
||||
allocator.initInputLocation(0, R0);
|
||||
if (numInputs >= 1) {
|
||||
allocator.initInputLocation(0, R0);
|
||||
if (numInputs >= 2)
|
||||
allocator.initInputLocation(1, R1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1631,6 +1734,12 @@ CacheIRWriter::copyStubData(uint8_t* dest) const
|
|||
case StubField::Type::ObjectGroup:
|
||||
InitGCPtr<ObjectGroup*>(destWords, stubFields_[i].asWord());
|
||||
break;
|
||||
case StubField::Type::Symbol:
|
||||
InitGCPtr<JS::Symbol*>(destWords, stubFields_[i].asWord());
|
||||
break;
|
||||
case StubField::Type::String:
|
||||
InitGCPtr<JSString*>(destWords, stubFields_[i].asWord());
|
||||
break;
|
||||
case StubField::Type::Id:
|
||||
InitGCPtr<jsid>(destWords, stubFields_[i].asWord());
|
||||
break;
|
||||
|
@ -1725,7 +1834,7 @@ jit::AttachBaselineCacheIRStub(JSContext* cx, const CacheIRWriter& writer,
|
|||
// unlimited number of stubs.
|
||||
MOZ_ASSERT(stub->numOptimizedStubs() < MaxOptimizedCacheIRStubs);
|
||||
|
||||
MOZ_ASSERT(kind == CacheKind::GetProp);
|
||||
MOZ_ASSERT(kind == CacheKind::GetProp || kind == CacheKind::GetElem);
|
||||
uint32_t stubDataOffset = sizeof(ICCacheIR_Monitored);
|
||||
|
||||
JitCompartment* jitCompartment = cx->compartment()->jitCompartment();
|
||||
|
@ -1805,6 +1914,14 @@ jit::TraceBaselineCacheIRStub(JSTracer* trc, ICStub* stub, const CacheIRStubInfo
|
|||
TraceNullableEdge(trc, &stubInfo->getStubField<JSObject*>(stub, offset),
|
||||
"baseline-cacheir-object");
|
||||
break;
|
||||
case StubField::Type::Symbol:
|
||||
TraceNullableEdge(trc, &stubInfo->getStubField<JS::Symbol*>(stub, offset),
|
||||
"baseline-cacheir-symbol");
|
||||
break;
|
||||
case StubField::Type::String:
|
||||
TraceNullableEdge(trc, &stubInfo->getStubField<JSString*>(stub, offset),
|
||||
"baseline-cacheir-string");
|
||||
break;
|
||||
case StubField::Type::Id:
|
||||
TraceEdge(trc, &stubInfo->getStubField<jsid>(stub, offset), "baseline-cacheir-id");
|
||||
break;
|
||||
|
@ -1861,6 +1978,12 @@ CacheIRStubInfo::copyStubData(ICStub* src, ICStub* dest) const
|
|||
case StubField::Type::ObjectGroup:
|
||||
getStubField<ObjectGroup*>(dest, offset).init(getStubField<ObjectGroup*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Symbol:
|
||||
getStubField<JS::Symbol*>(dest, offset).init(getStubField<JS::Symbol*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::String:
|
||||
getStubField<JSString*>(dest, offset).init(getStubField<JSString*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Id:
|
||||
getStubField<jsid>(dest, offset).init(getStubField<jsid>(src, offset));
|
||||
break;
|
||||
|
|
|
@ -698,10 +698,6 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script,
|
|||
_(Call_ScriptedApplyArray) \
|
||||
_(Call_ScriptedApplyArguments) \
|
||||
_(Call_ScriptedFunCall) \
|
||||
_(GetElem_NativePrototypeCallNativeName) \
|
||||
_(GetElem_NativePrototypeCallNativeSymbol) \
|
||||
_(GetElem_NativePrototypeCallScriptedName) \
|
||||
_(GetElem_NativePrototypeCallScriptedSymbol) \
|
||||
_(GetProp_CallNativeGlobal) \
|
||||
_(GetProp_Generic) \
|
||||
_(SetProp_CallScripted) \
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "builtin/Eval.h"
|
||||
#include "builtin/SIMD.h"
|
||||
#include "gc/Policy.h"
|
||||
#include "jit/BaselineCacheIR.h"
|
||||
#include "jit/BaselineDebugModeOSR.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/InlinableNatives.h"
|
||||
|
@ -852,179 +853,6 @@ IsCacheableSetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool
|
||||
GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject holder,
|
||||
Handle<T> key, bool needsAtomize)
|
||||
{
|
||||
bool indirect = (obj.get() != holder.get());
|
||||
MOZ_ASSERT_IF(indirect, holder->isNative());
|
||||
|
||||
for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
|
||||
if (iter->kind() != ICStub::GetElem_NativeSlotName &&
|
||||
iter->kind() != ICStub::GetElem_NativeSlotSymbol &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeSlotName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlotName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName &&
|
||||
iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(mozilla::IsSame<T, JS::Symbol*>::value !=
|
||||
static_cast<ICGetElemNativeStub*>(*iter)->isSymbol())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ICGetElemNativeStubImpl<T>* getElemNativeStub =
|
||||
reinterpret_cast<ICGetElemNativeStubImpl<T>*>(*iter);
|
||||
if (key != getElemNativeStub->key())
|
||||
continue;
|
||||
|
||||
if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard())
|
||||
continue;
|
||||
|
||||
// If the new stub needs atomization, and the old stub doesn't atomize, then
|
||||
// an appropriate stub doesn't exist.
|
||||
if (needsAtomize && !getElemNativeStub->needsAtomize())
|
||||
continue;
|
||||
|
||||
// For prototype gets, check the holder and holder shape.
|
||||
if (indirect) {
|
||||
if (iter->isGetElem_NativePrototypeSlotName() ||
|
||||
iter->isGetElem_NativePrototypeSlotSymbol()) {
|
||||
ICGetElem_NativePrototypeSlot<T>* protoStub =
|
||||
reinterpret_cast<ICGetElem_NativePrototypeSlot<T>*>(*iter);
|
||||
|
||||
if (holder != protoStub->holder())
|
||||
continue;
|
||||
|
||||
if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape())
|
||||
continue;
|
||||
} else {
|
||||
MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() ||
|
||||
iter->isGetElem_NativePrototypeCallNativeSymbol() ||
|
||||
iter->isGetElem_NativePrototypeCallScriptedName() ||
|
||||
iter->isGetElem_NativePrototypeCallScriptedSymbol());
|
||||
|
||||
ICGetElemNativePrototypeCallStub<T>* protoStub =
|
||||
reinterpret_cast<ICGetElemNativePrototypeCallStub<T>*>(*iter);
|
||||
|
||||
if (holder != protoStub->holder())
|
||||
continue;
|
||||
|
||||
if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape())
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void
|
||||
RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, HandleObject obj,
|
||||
HandleObject holder, Handle<T> key, bool needsAtomize)
|
||||
{
|
||||
bool indirect = (obj.get() != holder.get());
|
||||
MOZ_ASSERT_IF(indirect, holder->isNative());
|
||||
|
||||
for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
|
||||
switch (iter->kind()) {
|
||||
case ICStub::GetElem_NativeSlotName:
|
||||
case ICStub::GetElem_NativeSlotSymbol:
|
||||
if (indirect)
|
||||
continue;
|
||||
MOZ_FALLTHROUGH;
|
||||
case ICStub::GetElem_NativePrototypeSlotName:
|
||||
case ICStub::GetElem_NativePrototypeSlotSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeName:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedName:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if(mozilla::IsSame<T, JS::Symbol*>::value !=
|
||||
static_cast<ICGetElemNativeStub*>(*iter)->isSymbol())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ICGetElemNativeStubImpl<T>* getElemNativeStub =
|
||||
reinterpret_cast<ICGetElemNativeStubImpl<T>*>(*iter);
|
||||
if (key != getElemNativeStub->key())
|
||||
continue;
|
||||
|
||||
if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard())
|
||||
continue;
|
||||
|
||||
// For prototype gets, check the holder and holder shape.
|
||||
if (indirect) {
|
||||
if (iter->isGetElem_NativePrototypeSlotName() ||
|
||||
iter->isGetElem_NativePrototypeSlotSymbol()) {
|
||||
ICGetElem_NativePrototypeSlot<T>* protoStub =
|
||||
reinterpret_cast<ICGetElem_NativePrototypeSlot<T>*>(*iter);
|
||||
|
||||
if (holder != protoStub->holder())
|
||||
continue;
|
||||
|
||||
// If the holder matches, but the holder's lastProperty doesn't match, then
|
||||
// this stub is invalid anyway. Unlink it.
|
||||
if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape()) {
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() ||
|
||||
iter->isGetElem_NativePrototypeCallNativeSymbol() ||
|
||||
iter->isGetElem_NativePrototypeCallScriptedName() ||
|
||||
iter->isGetElem_NativePrototypeCallScriptedSymbol());
|
||||
ICGetElemNativePrototypeCallStub<T>* protoStub =
|
||||
reinterpret_cast<ICGetElemNativePrototypeCallStub<T>*>(*iter);
|
||||
|
||||
if (holder != protoStub->holder())
|
||||
continue;
|
||||
|
||||
// If the holder matches, but the holder's lastProperty doesn't match, then
|
||||
// this stub is invalid anyway. Unlink it.
|
||||
if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape()) {
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the new stub needs atomization, and the old stub doesn't atomize, then
|
||||
// remove the old stub.
|
||||
if (needsAtomize && !getElemNativeStub->needsAtomize()) {
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Should never get here, because this means a matching stub exists, and if
|
||||
// a matching stub exists, this procedure should never have been called.
|
||||
MOZ_CRASH("Procedure should never have been called.");
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
TypedArrayGetElemStubExists(ICGetElem_Fallback* stub, HandleObject obj)
|
||||
{
|
||||
|
@ -1049,31 +877,6 @@ ArgumentsGetElemStubExists(ICGetElem_Fallback* stub, ICGetElem_Arguments::Which
|
|||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static T
|
||||
getKey(jsid id)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
JS::Symbol* getKey<JS::Symbol*>(jsid id)
|
||||
{
|
||||
if (!JSID_IS_SYMBOL(id))
|
||||
return nullptr;
|
||||
return JSID_TO_SYMBOL(id);
|
||||
}
|
||||
|
||||
template <>
|
||||
PropertyName* getKey<PropertyName*>(jsid id)
|
||||
{
|
||||
uint32_t dummy;
|
||||
if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
|
||||
return nullptr;
|
||||
return JSID_TO_ATOM(id)->asPropertyName();
|
||||
}
|
||||
|
||||
static bool
|
||||
IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId idp)
|
||||
{
|
||||
|
@ -1091,227 +894,6 @@ IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool
|
||||
checkAtomize(HandleValue key)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool checkAtomize<JS::Symbol*>(HandleValue key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool checkAtomize<PropertyName*>(HandleValue key)
|
||||
{
|
||||
return !key.toString()->isAtom();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool
|
||||
TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
ICGetElem_Fallback* stub, HandleObject obj,
|
||||
HandleValue keyVal, bool* attached)
|
||||
{
|
||||
MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol());
|
||||
|
||||
// Convert to id.
|
||||
RootedId id(cx);
|
||||
if (!ValueToId<CanGC>(cx, keyVal, &id))
|
||||
return false;
|
||||
|
||||
Rooted<T> key(cx, getKey<T>(id));
|
||||
if (!key)
|
||||
return true;
|
||||
bool needsAtomize = checkAtomize<T>(keyVal);
|
||||
|
||||
RootedShape shape(cx);
|
||||
RootedObject holder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||
return false;
|
||||
if (!holder || (holder != obj && !holder->isNative()))
|
||||
return true;
|
||||
|
||||
// If a suitable stub already exists, nothing else to do.
|
||||
if (GetElemNativeStubExists<T>(stub, obj, holder, key, needsAtomize))
|
||||
return true;
|
||||
|
||||
// Remove any existing stubs that may interfere with the new stub being added.
|
||||
RemoveExistingGetElemNativeStubs<T>(cx, stub, obj, holder, key, needsAtomize);
|
||||
|
||||
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
|
||||
if (obj->is<UnboxedPlainObject>() && holder == obj) {
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
|
||||
|
||||
// Once unboxed objects support symbol-keys, we need to change the following accordingly
|
||||
MOZ_ASSERT_IF(!keyVal.isString(), !property);
|
||||
|
||||
if (property) {
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint)
|
||||
return true;
|
||||
|
||||
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||
ICGetElemNativeCompiler<PropertyName*> compiler(cx, ICStub::GetElem_UnboxedPropertyName,
|
||||
monitorStub, obj, holder,
|
||||
name,
|
||||
ICGetElemNativeStub::UnboxedProperty,
|
||||
needsAtomize, property->offset +
|
||||
UnboxedPlainObject::offsetOfData(),
|
||||
property->type);
|
||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Shape* shape = obj->as<UnboxedPlainObject>().maybeExpando()->lookup(cx, id);
|
||||
if (!shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return true;
|
||||
|
||||
bool isFixedSlot;
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
|
||||
|
||||
ICGetElemNativeStub::AccessType acctype =
|
||||
isFixedSlot ? ICGetElemNativeStub::FixedSlot
|
||||
: ICGetElemNativeStub::DynamicSlot;
|
||||
ICGetElemNativeCompiler<T> compiler(cx, getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
|
||||
monitorStub, obj, holder, key,
|
||||
acctype, needsAtomize, offset);
|
||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!holder->isNative())
|
||||
return true;
|
||||
|
||||
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
|
||||
bool isFixedSlot;
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
|
||||
|
||||
ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlotName
|
||||
: ICStub::GetElem_NativePrototypeSlotName;
|
||||
kind = getGetElemStubKind<T>(kind);
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " Generating GetElem(Native %s%s slot) stub "
|
||||
"(obj=%p, holder=%p, holderShape=%p)",
|
||||
(obj == holder) ? "direct" : "prototype",
|
||||
needsAtomize ? " atomizing" : "",
|
||||
obj.get(), holder.get(), holder->as<NativeObject>().lastProperty());
|
||||
|
||||
AccType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
|
||||
: ICGetElemNativeStub::DynamicSlot;
|
||||
ICGetElemNativeCompiler<T> compiler(cx, kind, monitorStub, obj, holder, key,
|
||||
acctype, needsAtomize, offset);
|
||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool
|
||||
TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
ICGetElem_Fallback* stub, HandleNativeObject obj,
|
||||
HandleValue keyVal, bool* attached,
|
||||
bool* isTemporarilyUnoptimizable)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol());
|
||||
|
||||
RootedId id(cx);
|
||||
if (!ValueToId<CanGC>(cx, keyVal, &id))
|
||||
return false;
|
||||
|
||||
Rooted<T> key(cx, getKey<T>(id));
|
||||
if (!key)
|
||||
return true;
|
||||
bool needsAtomize = checkAtomize<T>(keyVal);
|
||||
|
||||
RootedShape shape(cx);
|
||||
RootedObject baseHolder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape))
|
||||
return false;
|
||||
if (!baseHolder || !baseHolder->isNative())
|
||||
return true;
|
||||
|
||||
HandleNativeObject holder = baseHolder.as<NativeObject>();
|
||||
|
||||
bool getterIsScripted = false;
|
||||
if (IsCacheableGetPropCall(cx, obj, baseHolder, shape, &getterIsScripted,
|
||||
isTemporarilyUnoptimizable, /*isDOMProxy=*/false))
|
||||
{
|
||||
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
|
||||
|
||||
// For now, we do not handle own property getters
|
||||
if (obj == holder)
|
||||
return true;
|
||||
|
||||
// If a suitable stub already exists, nothing else to do.
|
||||
if (GetElemNativeStubExists<T>(stub, obj, holder, key, needsAtomize))
|
||||
return true;
|
||||
|
||||
// Remove any existing stubs that may interfere with the new stub being added.
|
||||
RemoveExistingGetElemNativeStubs<T>(cx, stub, obj, holder, key, needsAtomize);
|
||||
|
||||
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScriptedName
|
||||
: ICStub::GetElem_NativePrototypeCallNativeName;
|
||||
kind = getGetElemStubKind<T>(kind);
|
||||
|
||||
if (getterIsScripted) {
|
||||
JitSpew(JitSpew_BaselineIC,
|
||||
" Generating GetElem(Native %s%s call scripted %s:%" PRIuSIZE ") stub "
|
||||
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
|
||||
(obj == holder) ? "direct" : "prototype",
|
||||
needsAtomize ? " atomizing" : "",
|
||||
getter->nonLazyScript()->filename(), getter->nonLazyScript()->lineno(),
|
||||
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
|
||||
} else {
|
||||
JitSpew(JitSpew_BaselineIC,
|
||||
" Generating GetElem(Native %s%s call native) stub "
|
||||
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
|
||||
(obj == holder) ? "direct" : "prototype",
|
||||
needsAtomize ? " atomizing" : "",
|
||||
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
|
||||
}
|
||||
|
||||
AccType acctype = getterIsScripted ? ICGetElemNativeStub::ScriptedGetter
|
||||
: ICGetElemNativeStub::NativeGetter;
|
||||
ICGetElemNativeCompiler<T> compiler(cx, kind, monitorStub, obj, holder, key, acctype,
|
||||
needsAtomize, getter, script->pcToOffset(pc));
|
||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPrimitiveArrayTypedObject(JSObject* obj)
|
||||
{
|
||||
|
@ -1441,27 +1023,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
|
|||
return true;
|
||||
}
|
||||
|
||||
// Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses.
|
||||
if (obj->isNative() || obj->is<UnboxedPlainObject>()) {
|
||||
RootedScript rootedScript(cx, script);
|
||||
if (rhs.isString()) {
|
||||
if (!TryAttachNativeOrUnboxedGetValueElemStub<PropertyName*>(cx, rootedScript, pc, stub,
|
||||
obj, rhs, attached))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if (rhs.isSymbol()) {
|
||||
if (!TryAttachNativeOrUnboxedGetValueElemStub<JS::Symbol*>(cx, rootedScript, pc, stub,
|
||||
obj, rhs, attached))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (*attached)
|
||||
return true;
|
||||
script = rootedScript;
|
||||
}
|
||||
|
||||
// Check for UnboxedArray[int] accesses.
|
||||
if (obj->is<UnboxedArrayObject>() && rhs.isInt32() && rhs.toInt32() >= 0) {
|
||||
JitSpew(JitSpew_BaselineIC, " Generating GetElem(UnboxedArray[Int32]) stub");
|
||||
|
@ -1555,29 +1116,22 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_
|
|||
attached = true;
|
||||
}
|
||||
|
||||
// Try to attach an optimized getter stub.
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
if (!attached && lhs.isObject() && lhs.toObject().isNative()){
|
||||
if (rhs.isString()) {
|
||||
RootedScript rootedScript(cx, frame->script());
|
||||
RootedNativeObject obj(cx, &lhs.toObject().as<NativeObject>());
|
||||
if (!TryAttachNativeGetAccessorElemStub<PropertyName*>(cx, rootedScript, pc, stub,
|
||||
obj, rhs, &attached,
|
||||
&isTemporarilyUnoptimizable))
|
||||
{
|
||||
return false;
|
||||
if (!attached && !JitOptions.disableCacheIR) {
|
||||
ICStubEngine engine = ICStubEngine::Baseline;
|
||||
GetPropIRGenerator gen(cx, pc, engine, CacheKind::GetElem, &isTemporarilyUnoptimizable,
|
||||
lhs, rhs, res);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
engine, info.outerScript(cx), stub);
|
||||
if (newStub) {
|
||||
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
|
||||
attached = true;
|
||||
if (gen.shouldNotePreliminaryObjectStub())
|
||||
newStub->toCacheIR_Monitored()->notePreliminaryObject();
|
||||
else if (gen.shouldUnlinkPreliminaryObjectStubs())
|
||||
StripPreliminaryObjectStubs(cx, stub);
|
||||
}
|
||||
script = rootedScript;
|
||||
} else if (rhs.isSymbol()) {
|
||||
RootedScript rootedScript(cx, frame->script());
|
||||
RootedNativeObject obj(cx, &lhs.toObject().as<NativeObject>());
|
||||
if (!TryAttachNativeGetAccessorElemStub<JS::Symbol*>(cx, rootedScript, pc, stub,
|
||||
obj, rhs, &attached,
|
||||
&isTemporarilyUnoptimizable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
script = rootedScript;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1638,352 +1192,6 @@ ICGetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
return tailCallVM(DoGetElemFallbackInfo, masm);
|
||||
}
|
||||
|
||||
//
|
||||
// GetElem_NativeSlot
|
||||
//
|
||||
|
||||
static bool
|
||||
DoAtomizeString(JSContext* cx, HandleString string, MutableHandleValue result)
|
||||
{
|
||||
JitSpew(JitSpew_BaselineIC, " AtomizeString called");
|
||||
|
||||
RootedValue key(cx, StringValue(string));
|
||||
|
||||
// Convert to interned property name.
|
||||
RootedId id(cx);
|
||||
if (!ValueToId<CanGC>(cx, key, &id))
|
||||
return false;
|
||||
|
||||
if (!JSID_IS_ATOM(id)) {
|
||||
result.set(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
result.set(StringValue(JSID_TO_ATOM(id)));
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*DoAtomizeStringFn)(JSContext*, HandleString, MutableHandleValue);
|
||||
static const VMFunction DoAtomizeStringInfo = FunctionInfo<DoAtomizeStringFn>(DoAtomizeString,
|
||||
"DoAtomizeString");
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ICGetElemNativeCompiler<T>::emitCallNative(MacroAssembler& masm, Register objReg)
|
||||
{
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
|
||||
regs.takeUnchecked(objReg);
|
||||
regs.takeUnchecked(ICTailCallReg);
|
||||
|
||||
enterStubFrame(masm, regs.getAny());
|
||||
|
||||
// Push object.
|
||||
masm.push(objReg);
|
||||
|
||||
// Push native callee.
|
||||
masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()), objReg);
|
||||
masm.push(objReg);
|
||||
|
||||
regs.add(objReg);
|
||||
|
||||
// Call helper.
|
||||
if (!callVM(DoCallNativeGetterInfo, masm))
|
||||
return false;
|
||||
|
||||
leaveStubFrame(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ICGetElemNativeCompiler<T>::emitCallScripted(MacroAssembler& masm, Register objReg)
|
||||
{
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
|
||||
regs.takeUnchecked(objReg);
|
||||
regs.takeUnchecked(ICTailCallReg);
|
||||
|
||||
// Enter stub frame.
|
||||
enterStubFrame(masm, regs.getAny());
|
||||
|
||||
// Align the stack such that the JitFrameLayout is aligned on
|
||||
// JitStackAlignment.
|
||||
masm.alignJitStackBasedOnNArgs(0);
|
||||
|
||||
// Push |this| for getter (target object).
|
||||
{
|
||||
ValueOperand val = regs.takeAnyValue();
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
|
||||
masm.Push(val);
|
||||
regs.add(val);
|
||||
}
|
||||
|
||||
regs.add(objReg);
|
||||
|
||||
Register callee = regs.takeAny();
|
||||
masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()), callee);
|
||||
|
||||
// Push argc, callee, and descriptor.
|
||||
{
|
||||
Register callScratch = regs.takeAny();
|
||||
EmitBaselineCreateStubFrameDescriptor(masm, callScratch, JitFrameLayout::Size());
|
||||
masm.Push(Imm32(0)); // ActualArgc is 0
|
||||
masm.Push(callee);
|
||||
masm.Push(callScratch);
|
||||
regs.add(callScratch);
|
||||
}
|
||||
|
||||
Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
|
||||
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
|
||||
masm.loadBaselineOrIonRaw(code, code, nullptr);
|
||||
|
||||
Register scratch = regs.takeAny();
|
||||
|
||||
// Handle arguments underflow.
|
||||
Label noUnderflow;
|
||||
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
|
||||
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
MOZ_ASSERT(ArgumentsRectifierReg != code);
|
||||
|
||||
JitCode* argumentsRectifier =
|
||||
cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
|
||||
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
|
||||
masm.movePtr(ImmWord(0), ArgumentsRectifierReg);
|
||||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
masm.callJit(code);
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ICGetElemNativeCompiler<T>::emitCheckKey(MacroAssembler& masm, Label& failure)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
ICGetElemNativeCompiler<JS::Symbol*>::emitCheckKey(MacroAssembler& masm, Label& failure)
|
||||
{
|
||||
MOZ_ASSERT(!needsAtomize_);
|
||||
masm.branchTestSymbol(Assembler::NotEqual, R1, &failure);
|
||||
Address symbolAddr(ICStubReg, ICGetElemNativeStubImpl<JS::Symbol*>::offsetOfKey());
|
||||
Register symExtract = masm.extractObject(R1, ExtractTemp1);
|
||||
masm.branchPtr(Assembler::NotEqual, symbolAddr, symExtract, &failure);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
ICGetElemNativeCompiler<PropertyName*>::emitCheckKey(MacroAssembler& masm, Label& failure)
|
||||
{
|
||||
masm.branchTestString(Assembler::NotEqual, R1, &failure);
|
||||
// Check key identity. Don't automatically fail if this fails, since the incoming
|
||||
// key maybe a non-interned string. Switch to a slowpath vm-call based check.
|
||||
Address nameAddr(ICStubReg, ICGetElemNativeStubImpl<PropertyName*>::offsetOfKey());
|
||||
Register strExtract = masm.extractString(R1, ExtractTemp1);
|
||||
|
||||
// If needsAtomize_ is true, and the string is not already an atom, then atomize the
|
||||
// string before proceeding.
|
||||
if (needsAtomize_) {
|
||||
Label skipAtomize;
|
||||
|
||||
// If string is already an atom, skip the atomize.
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
Address(strExtract, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::ATOM_BIT),
|
||||
&skipAtomize);
|
||||
|
||||
// Stow R0.
|
||||
EmitStowICValues(masm, 1);
|
||||
|
||||
enterStubFrame(masm, R0.scratchReg());
|
||||
|
||||
// Atomize the string into a new value.
|
||||
masm.push(strExtract);
|
||||
if (!callVM(DoAtomizeStringInfo, masm))
|
||||
return false;
|
||||
|
||||
// Atomized string is now in JSReturnOperand (R0).
|
||||
// Leave stub frame, move atomized string into R1.
|
||||
MOZ_ASSERT(R0 == JSReturnOperand);
|
||||
leaveStubFrame(masm);
|
||||
masm.moveValue(JSReturnOperand, R1);
|
||||
|
||||
// Unstow R0
|
||||
EmitUnstowICValues(masm, 1);
|
||||
|
||||
// Extract string from R1 again.
|
||||
DebugOnly<Register> strExtract2 = masm.extractString(R1, ExtractTemp1);
|
||||
MOZ_ASSERT(Register(strExtract2) == strExtract);
|
||||
|
||||
masm.bind(&skipAtomize);
|
||||
}
|
||||
|
||||
// Key has been atomized if necessary. Do identity check on string pointer.
|
||||
masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
MOZ_ASSERT(engine_ == Engine::Baseline);
|
||||
|
||||
Label failure;
|
||||
Label failurePopR1;
|
||||
bool popR1 = false;
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratchReg = regs.takeAny();
|
||||
|
||||
// Unbox object.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
|
||||
// Check object shape/group.
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratchReg,
|
||||
ICGetElemNativeStub::offsetOfReceiverGuard(), &failure);
|
||||
|
||||
// Since this stub sometimes enters a stub frame, we manually set this to true (lie).
|
||||
#ifdef DEBUG
|
||||
entersStubFrame_ = true;
|
||||
#endif
|
||||
|
||||
if (!emitCheckKey(masm, failure))
|
||||
return false;
|
||||
|
||||
Register holderReg;
|
||||
if (obj_ == holder_) {
|
||||
holderReg = objReg;
|
||||
|
||||
if (obj_->is<UnboxedPlainObject>() && acctype_ != ICGetElemNativeStub::UnboxedProperty) {
|
||||
// The property will be loaded off the unboxed expando.
|
||||
masm.push(R1.scratchReg());
|
||||
popR1 = true;
|
||||
holderReg = R1.scratchReg();
|
||||
masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
|
||||
}
|
||||
} else {
|
||||
// Shape guard holder.
|
||||
if (regs.empty()) {
|
||||
masm.push(R1.scratchReg());
|
||||
popR1 = true;
|
||||
holderReg = R1.scratchReg();
|
||||
} else {
|
||||
holderReg = regs.takeAny();
|
||||
}
|
||||
|
||||
if (kind == ICStub::GetElem_NativePrototypeCallNativeName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol)
|
||||
{
|
||||
masm.loadPtr(Address(ICStubReg,
|
||||
ICGetElemNativePrototypeCallStub<T>::offsetOfHolder()),
|
||||
holderReg);
|
||||
masm.loadPtr(Address(ICStubReg,
|
||||
ICGetElemNativePrototypeCallStub<T>::offsetOfHolderShape()),
|
||||
scratchReg);
|
||||
} else {
|
||||
masm.loadPtr(Address(ICStubReg,
|
||||
ICGetElem_NativePrototypeSlot<T>::offsetOfHolder()),
|
||||
holderReg);
|
||||
masm.loadPtr(Address(ICStubReg,
|
||||
ICGetElem_NativePrototypeSlot<T>::offsetOfHolderShape()),
|
||||
scratchReg);
|
||||
}
|
||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
|
||||
popR1 ? &failurePopR1 : &failure);
|
||||
}
|
||||
|
||||
if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
|
||||
acctype_ == ICGetElemNativeStub::FixedSlot)
|
||||
{
|
||||
masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
|
||||
scratchReg);
|
||||
|
||||
// Load from object.
|
||||
if (acctype_ == ICGetElemNativeStub::DynamicSlot)
|
||||
masm.addPtr(Address(holderReg, NativeObject::offsetOfSlots()), scratchReg);
|
||||
else
|
||||
masm.addPtr(holderReg, scratchReg);
|
||||
|
||||
Address valAddr(scratchReg, 0);
|
||||
masm.loadValue(valAddr, R0);
|
||||
if (popR1)
|
||||
masm.addToStackPtr(ImmWord(sizeof(size_t)));
|
||||
|
||||
} else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) {
|
||||
masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
|
||||
scratchReg);
|
||||
masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_,
|
||||
TypedOrValueRegister(R0));
|
||||
if (popR1)
|
||||
masm.addToStackPtr(ImmWord(sizeof(size_t)));
|
||||
} else {
|
||||
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
|
||||
acctype_ == ICGetElemNativeStub::ScriptedGetter);
|
||||
MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
|
||||
|
||||
if (acctype_ == ICGetElemNativeStub::NativeGetter) {
|
||||
// If calling a native getter, there is no chance of failure now.
|
||||
|
||||
// GetElem key (R1) is no longer needed.
|
||||
if (popR1)
|
||||
masm.addToStackPtr(ImmWord(sizeof(size_t)));
|
||||
|
||||
if (!emitCallNative(masm, objReg))
|
||||
return false;
|
||||
|
||||
} else {
|
||||
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
|
||||
|
||||
// Load function in scratchReg and ensure that it has a jit script.
|
||||
masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()),
|
||||
scratchReg);
|
||||
masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure);
|
||||
masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
|
||||
masm.loadBaselineOrIonRaw(scratchReg, scratchReg, popR1 ? &failurePopR1 : &failure);
|
||||
|
||||
// At this point, we are guaranteed to successfully complete.
|
||||
if (popR1)
|
||||
masm.addToStackPtr(Imm32(sizeof(size_t)));
|
||||
|
||||
if (!emitCallScripted(masm, objReg))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Enter type monitor IC to type-check result.
|
||||
EmitEnterTypeMonitorIC(masm);
|
||||
|
||||
// Failure case - jump to next stub
|
||||
if (popR1) {
|
||||
masm.bind(&failurePopR1);
|
||||
masm.pop(R1.scratchReg());
|
||||
}
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// GetElem_String
|
||||
//
|
||||
|
@ -3364,7 +2572,7 @@ TryAttachNativeInDoesNotExistStub(JSContext* cx, HandleScript outerScript,
|
|||
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||
RootedObject lastProto(cx);
|
||||
size_t protoChainDepth = SIZE_MAX;
|
||||
if (!CheckHasNoSuchProperty(cx, obj.get(), name.get(), lastProto.address(), &protoChainDepth))
|
||||
if (!CheckHasNoSuchProperty(cx, obj.get(), id, lastProto.address(), &protoChainDepth))
|
||||
return true;
|
||||
MOZ_ASSERT(protoChainDepth < SIZE_MAX);
|
||||
|
||||
|
@ -8179,101 +7387,6 @@ ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGrou
|
|||
group_(group)
|
||||
{ }
|
||||
|
||||
ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode,
|
||||
ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, AccessType acctype,
|
||||
bool needsAtomize, bool isSymbol)
|
||||
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
|
||||
receiverGuard_(guard)
|
||||
{
|
||||
extra_ = (static_cast<uint16_t>(acctype) << ACCESSTYPE_SHIFT) |
|
||||
(static_cast<uint16_t>(needsAtomize) << NEEDS_ATOMIZE_SHIFT) |
|
||||
(static_cast<uint16_t>(isSymbol) << ISSYMBOL_SHIFT);
|
||||
}
|
||||
|
||||
ICGetElemNativeStub::~ICGetElemNativeStub()
|
||||
{ }
|
||||
|
||||
template <class T>
|
||||
ICGetElemNativeGetterStub<T>::ICGetElemNativeGetterStub(
|
||||
ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
|
||||
JSFunction* getter, uint32_t pcOffset)
|
||||
: ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
|
||||
getter_(getter),
|
||||
pcOffset_(pcOffset)
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
|
||||
MOZ_ASSERT(acctype == ICGetElemNativeStub::NativeGetter ||
|
||||
acctype == ICGetElemNativeStub::ScriptedGetter);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ICGetElem_NativePrototypeSlot<T>::ICGetElem_NativePrototypeSlot(
|
||||
JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
|
||||
JSObject* holder, Shape* holderShape)
|
||||
: ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativePrototypeSlotName),
|
||||
stubCode, firstMonitorStub, guard, key, acctype, needsAtomize, offset),
|
||||
holder_(holder),
|
||||
holderShape_(holderShape)
|
||||
{ }
|
||||
|
||||
template <class T>
|
||||
ICGetElemNativePrototypeCallStub<T>::ICGetElemNativePrototypeCallStub(
|
||||
ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype,
|
||||
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
|
||||
JSObject* holder, Shape* holderShape)
|
||||
: ICGetElemNativeGetterStub<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize,
|
||||
getter, pcOffset),
|
||||
holder_(holder),
|
||||
holderShape_(holderShape)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
/* static */ ICGetElem_NativePrototypeCallNative<T>*
|
||||
ICGetElem_NativePrototypeCallNative<T>::Clone(JSContext* cx,
|
||||
ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICGetElem_NativePrototypeCallNative<T>& other)
|
||||
{
|
||||
return ICStub::New<ICGetElem_NativePrototypeCallNative<T>>(cx, space, other.jitCode(),
|
||||
firstMonitorStub, other.receiverGuard(), &other.key().get(), other.accessType(),
|
||||
other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(),
|
||||
other.holderShape());
|
||||
}
|
||||
|
||||
template ICGetElem_NativePrototypeCallNative<JS::Symbol*>*
|
||||
ICGetElem_NativePrototypeCallNative<JS::Symbol*>::Clone(JSContext*, ICStubSpace*, ICStub*,
|
||||
ICGetElem_NativePrototypeCallNative<JS::Symbol*>&);
|
||||
template ICGetElem_NativePrototypeCallNative<js::PropertyName*>*
|
||||
ICGetElem_NativePrototypeCallNative<js::PropertyName*>::Clone(JSContext*, ICStubSpace*, ICStub*,
|
||||
ICGetElem_NativePrototypeCallNative<js::PropertyName*>&);
|
||||
|
||||
template <class T>
|
||||
/* static */ ICGetElem_NativePrototypeCallScripted<T>*
|
||||
ICGetElem_NativePrototypeCallScripted<T>::Clone(JSContext* cx,
|
||||
ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICGetElem_NativePrototypeCallScripted<T>& other)
|
||||
{
|
||||
return ICStub::New<ICGetElem_NativePrototypeCallScripted<T>>(cx, space, other.jitCode(),
|
||||
firstMonitorStub, other.receiverGuard(), &other.key().get(), other.accessType(),
|
||||
other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(),
|
||||
other.holderShape());
|
||||
}
|
||||
|
||||
template ICGetElem_NativePrototypeCallScripted<JS::Symbol*>*
|
||||
ICGetElem_NativePrototypeCallScripted<JS::Symbol*>::Clone(JSContext*, ICStubSpace*, ICStub*,
|
||||
ICGetElem_NativePrototypeCallScripted<JS::Symbol*>&);
|
||||
template ICGetElem_NativePrototypeCallScripted<js::PropertyName*>*
|
||||
ICGetElem_NativePrototypeCallScripted<js::PropertyName*>::Clone(JSContext*, ICStubSpace*, ICStub*,
|
||||
ICGetElem_NativePrototypeCallScripted<js::PropertyName*>&);
|
||||
|
||||
ICGetElem_Dense::ICGetElem_Dense(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape)
|
||||
: ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
|
||||
shape_(shape)
|
||||
|
|
|
@ -419,411 +419,6 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
|
|||
};
|
||||
};
|
||||
|
||||
class ICGetElemNativeStub : public ICMonitoredStub
|
||||
{
|
||||
public:
|
||||
enum AccessType { FixedSlot = 0, DynamicSlot, UnboxedProperty, NativeGetter, ScriptedGetter, NumAccessTypes };
|
||||
|
||||
protected:
|
||||
HeapReceiverGuard receiverGuard_;
|
||||
|
||||
static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
|
||||
static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
|
||||
|
||||
static const unsigned ACCESSTYPE_SHIFT = 1;
|
||||
static const uint16_t ACCESSTYPE_MASK = 0x7;
|
||||
|
||||
static const unsigned ISSYMBOL_SHIFT = 4;
|
||||
static const uint16_t ISSYMBOL_MASK = 0x1;
|
||||
|
||||
static_assert(ACCESSTYPE_MASK >= NumAccessTypes, "ACCESSTYPE_MASK must cover all possible AccessType values");
|
||||
|
||||
ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, AccessType acctype, bool needsAtomize, bool isSymbol);
|
||||
|
||||
~ICGetElemNativeStub();
|
||||
|
||||
public:
|
||||
HeapReceiverGuard& receiverGuard() {
|
||||
return receiverGuard_;
|
||||
}
|
||||
static size_t offsetOfReceiverGuard() {
|
||||
return offsetof(ICGetElemNativeStub, receiverGuard_);
|
||||
}
|
||||
|
||||
AccessType accessType() const {
|
||||
return static_cast<AccessType>((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK);
|
||||
}
|
||||
|
||||
bool needsAtomize() const {
|
||||
return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
|
||||
}
|
||||
|
||||
bool isSymbol() const {
|
||||
return (extra_ >> ISSYMBOL_SHIFT) & ISSYMBOL_MASK;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ICGetElemNativeStubImpl : public ICGetElemNativeStub
|
||||
{
|
||||
protected:
|
||||
GCPtr<T> key_;
|
||||
|
||||
ICGetElemNativeStubImpl(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccessType acctype, bool needsAtomize)
|
||||
: ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, acctype, needsAtomize,
|
||||
mozilla::IsSame<T, JS::Symbol*>::value),
|
||||
key_(*key)
|
||||
{}
|
||||
|
||||
public:
|
||||
GCPtr<T>& key() {
|
||||
return key_;
|
||||
}
|
||||
static size_t offsetOfKey() {
|
||||
return offsetof(ICGetElemNativeStubImpl, key_);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ICGetElemNativeStub::AccessType AccType;
|
||||
|
||||
template <class T>
|
||||
class ICGetElemNativeSlotStub : public ICGetElemNativeStubImpl<T>
|
||||
{
|
||||
protected:
|
||||
uint32_t offset_;
|
||||
|
||||
ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
|
||||
uint32_t offset)
|
||||
: ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
|
||||
offset_(offset)
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
|
||||
kind == ICStub::GetElem_NativeSlotSymbol ||
|
||||
kind == ICStub::GetElem_NativePrototypeSlotName ||
|
||||
kind == ICStub::GetElem_NativePrototypeSlotSymbol ||
|
||||
kind == ICStub::GetElem_UnboxedPropertyName);
|
||||
MOZ_ASSERT(acctype == ICGetElemNativeStub::FixedSlot ||
|
||||
acctype == ICGetElemNativeStub::DynamicSlot ||
|
||||
acctype == ICGetElemNativeStub::UnboxedProperty);
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t offset() const {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
static size_t offsetOfOffset() {
|
||||
return offsetof(ICGetElemNativeSlotStub, offset_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ICGetElemNativeGetterStub : public ICGetElemNativeStubImpl<T>
|
||||
{
|
||||
protected:
|
||||
GCPtrFunction getter_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
|
||||
JSFunction* getter, uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
GCPtrFunction& getter() {
|
||||
return getter_;
|
||||
}
|
||||
static size_t offsetOfGetter() {
|
||||
return offsetof(ICGetElemNativeGetterStub, getter_);
|
||||
}
|
||||
|
||||
static size_t offsetOfPCOffset() {
|
||||
return offsetof(ICGetElemNativeGetterStub, pcOffset_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ICStub::Kind
|
||||
getGetElemStubKind(ICStub::Kind kind)
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
|
||||
kind == ICStub::GetElem_NativePrototypeSlotName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNativeName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedName);
|
||||
return static_cast<ICStub::Kind>(kind + mozilla::IsSame<T, JS::Symbol*>::value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
const T* key, AccType acctype, bool needsAtomize, uint32_t offset)
|
||||
: ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
|
||||
stubCode, firstMonitorStub, guard,
|
||||
key, acctype, needsAtomize, offset)
|
||||
{}
|
||||
};
|
||||
|
||||
class ICGetElem_NativeSlotName :
|
||||
public ICGetElem_NativeSlot<PropertyName*>
|
||||
{};
|
||||
class ICGetElem_NativeSlotSymbol :
|
||||
public ICGetElem_NativeSlot<JS::Symbol*>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
ICGetElem_UnboxedProperty(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype,
|
||||
bool needsAtomize, uint32_t offset)
|
||||
: ICGetElemNativeSlotStub<T>(ICStub::GetElem_UnboxedPropertyName, stubCode, firstMonitorStub,
|
||||
guard, key, acctype, needsAtomize, offset)
|
||||
{}
|
||||
};
|
||||
|
||||
class ICGetElem_UnboxedPropertyName :
|
||||
public ICGetElem_UnboxedProperty<PropertyName*>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
GCPtrObject holder_;
|
||||
GCPtrShape holderShape_;
|
||||
|
||||
ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
|
||||
JSObject* holder, Shape* holderShape);
|
||||
|
||||
public:
|
||||
GCPtrObject& holder() {
|
||||
return holder_;
|
||||
}
|
||||
static size_t offsetOfHolder() {
|
||||
return offsetof(ICGetElem_NativePrototypeSlot, holder_);
|
||||
}
|
||||
|
||||
GCPtrShape& holderShape() {
|
||||
return holderShape_;
|
||||
}
|
||||
static size_t offsetOfHolderShape() {
|
||||
return offsetof(ICGetElem_NativePrototypeSlot, holderShape_);
|
||||
}
|
||||
};
|
||||
|
||||
class ICGetElem_NativePrototypeSlotName :
|
||||
public ICGetElem_NativePrototypeSlot<PropertyName*>
|
||||
{};
|
||||
class ICGetElem_NativePrototypeSlotSymbol :
|
||||
public ICGetElem_NativePrototypeSlot<JS::Symbol*>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
GCPtrObject holder_;
|
||||
GCPtrShape holderShape_;
|
||||
|
||||
protected:
|
||||
ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype,
|
||||
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
|
||||
JSObject* holder, Shape* holderShape);
|
||||
|
||||
public:
|
||||
GCPtrObject& holder() {
|
||||
return holder_;
|
||||
}
|
||||
static size_t offsetOfHolder() {
|
||||
return offsetof(ICGetElemNativePrototypeCallStub, holder_);
|
||||
}
|
||||
|
||||
GCPtrShape& holderShape() {
|
||||
return holderShape_;
|
||||
}
|
||||
static size_t offsetOfHolderShape() {
|
||||
return offsetof(ICGetElemNativePrototypeCallStub, holderShape_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
ICGetElem_NativePrototypeCallNative(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype,
|
||||
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
|
||||
JSObject* holder, Shape* holderShape)
|
||||
: ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
|
||||
ICStub::GetElem_NativePrototypeCallNativeName),
|
||||
stubCode, firstMonitorStub, guard, key,
|
||||
acctype, needsAtomize, getter, pcOffset, holder,
|
||||
holderShape)
|
||||
{}
|
||||
|
||||
public:
|
||||
static ICGetElem_NativePrototypeCallNative<T>* Clone(JSContext* cx, ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICGetElem_NativePrototypeCallNative<T>& other);
|
||||
};
|
||||
|
||||
class ICGetElem_NativePrototypeCallNativeName :
|
||||
public ICGetElem_NativePrototypeCallNative<PropertyName*>
|
||||
{};
|
||||
class ICGetElem_NativePrototypeCallNativeSymbol :
|
||||
public ICGetElem_NativePrototypeCallNative<JS::Symbol*>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub<T>
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
ICGetElem_NativePrototypeCallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, const T* key, AccType acctype,
|
||||
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
|
||||
JSObject* holder, Shape* holderShape)
|
||||
: ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
|
||||
ICStub::GetElem_NativePrototypeCallScriptedName),
|
||||
stubCode, firstMonitorStub, guard, key, acctype,
|
||||
needsAtomize, getter, pcOffset, holder, holderShape)
|
||||
{}
|
||||
|
||||
public:
|
||||
static ICGetElem_NativePrototypeCallScripted<T>*
|
||||
Clone(JSContext* cx, ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICGetElem_NativePrototypeCallScripted<T>& other);
|
||||
};
|
||||
|
||||
class ICGetElem_NativePrototypeCallScriptedName :
|
||||
public ICGetElem_NativePrototypeCallScripted<PropertyName*>
|
||||
{};
|
||||
class ICGetElem_NativePrototypeCallScriptedSymbol :
|
||||
public ICGetElem_NativePrototypeCallScripted<JS::Symbol*>
|
||||
{};
|
||||
|
||||
// Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
|
||||
template <class T>
|
||||
class ICGetElemNativeCompiler : public ICStubCompiler
|
||||
{
|
||||
ICStub* firstMonitorStub_;
|
||||
HandleObject obj_;
|
||||
HandleObject holder_;
|
||||
Handle<T> key_;
|
||||
AccType acctype_;
|
||||
bool needsAtomize_;
|
||||
uint32_t offset_;
|
||||
JSValueType unboxedType_;
|
||||
HandleFunction getter_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
MOZ_MUST_USE bool emitCheckKey(MacroAssembler& masm, Label& failure);
|
||||
MOZ_MUST_USE bool emitCallNative(MacroAssembler& masm, Register objReg);
|
||||
MOZ_MUST_USE bool emitCallScripted(MacroAssembler& masm, Register objReg);
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
|
||||
protected:
|
||||
virtual int32_t getKey() const {
|
||||
MOZ_ASSERT(static_cast<int32_t>(acctype_) <= 7);
|
||||
MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 15);
|
||||
return static_cast<int32_t>(engine_) |
|
||||
(static_cast<int32_t>(kind) << 1) |
|
||||
(static_cast<int32_t>(needsAtomize_) << 17) |
|
||||
(static_cast<int32_t>(acctype_) << 18) |
|
||||
(static_cast<int32_t>(unboxedType_) << 21) |
|
||||
(static_cast<int32_t>(mozilla::IsSame<JS::Symbol*, T>::value) << 25) |
|
||||
(HeapReceiverGuard::keyBits(obj_) << 26);
|
||||
}
|
||||
|
||||
public:
|
||||
ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
|
||||
HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
|
||||
bool needsAtomize, uint32_t offset,
|
||||
JSValueType unboxedType = JSVAL_TYPE_MAGIC)
|
||||
: ICStubCompiler(cx, kind, Engine::Baseline),
|
||||
firstMonitorStub_(firstMonitorStub),
|
||||
obj_(obj),
|
||||
holder_(holder),
|
||||
key_(key),
|
||||
acctype_(acctype),
|
||||
needsAtomize_(needsAtomize),
|
||||
offset_(offset),
|
||||
unboxedType_(unboxedType),
|
||||
getter_(nullptr),
|
||||
pcOffset_(0)
|
||||
{}
|
||||
|
||||
ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
|
||||
HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
|
||||
bool needsAtomize, HandleFunction getter, uint32_t pcOffset)
|
||||
: ICStubCompiler(cx, kind, Engine::Baseline),
|
||||
firstMonitorStub_(firstMonitorStub),
|
||||
obj_(obj),
|
||||
holder_(holder),
|
||||
key_(key),
|
||||
acctype_(acctype),
|
||||
needsAtomize_(needsAtomize),
|
||||
offset_(0),
|
||||
unboxedType_(JSVAL_TYPE_MAGIC),
|
||||
getter_(getter),
|
||||
pcOffset_(pcOffset)
|
||||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
RootedReceiverGuard guard(cx, ReceiverGuard(obj_));
|
||||
if (kind == ICStub::GetElem_NativeSlotName || kind == ICStub::GetElem_NativeSlotSymbol) {
|
||||
MOZ_ASSERT(obj_ == holder_);
|
||||
return newStub<ICGetElem_NativeSlot<T>>(
|
||||
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
|
||||
needsAtomize_, offset_);
|
||||
}
|
||||
|
||||
if (kind == ICStub::GetElem_UnboxedPropertyName) {
|
||||
MOZ_ASSERT(obj_ == holder_);
|
||||
return newStub<ICGetElem_UnboxedProperty<T>>(
|
||||
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
|
||||
needsAtomize_, offset_);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(obj_ != holder_);
|
||||
RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
|
||||
if (kind == ICStub::GetElem_NativePrototypeSlotName ||
|
||||
kind == ICStub::GetElem_NativePrototypeSlotSymbol)
|
||||
{
|
||||
return newStub<ICGetElem_NativePrototypeSlot<T>>(
|
||||
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
|
||||
needsAtomize_, offset_, holder_, holderShape);
|
||||
}
|
||||
|
||||
if (kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNativeName) {
|
||||
return newStub<ICGetElem_NativePrototypeCallNative<T>>(
|
||||
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
|
||||
needsAtomize_, getter_, pcOffset_, holder_, holderShape);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
|
||||
if (kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) {
|
||||
return newStub<ICGetElem_NativePrototypeCallScripted<T>>(
|
||||
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
|
||||
needsAtomize_, getter_, pcOffset_, holder_, holderShape);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Invalid kind.");
|
||||
}
|
||||
};
|
||||
|
||||
class ICGetElem_String : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
|
|
@ -49,15 +49,6 @@ namespace jit {
|
|||
_(Call_IsSuspendedStarGenerator) \
|
||||
\
|
||||
_(GetElem_Fallback) \
|
||||
_(GetElem_NativeSlotName) \
|
||||
_(GetElem_NativeSlotSymbol) \
|
||||
_(GetElem_NativePrototypeSlotName) \
|
||||
_(GetElem_NativePrototypeSlotSymbol) \
|
||||
_(GetElem_NativePrototypeCallNativeName) \
|
||||
_(GetElem_NativePrototypeCallNativeSymbol) \
|
||||
_(GetElem_NativePrototypeCallScriptedName) \
|
||||
_(GetElem_NativePrototypeCallScriptedSymbol) \
|
||||
_(GetElem_UnboxedPropertyName) \
|
||||
_(GetElem_String) \
|
||||
_(GetElem_Dense) \
|
||||
_(GetElem_UnboxedArray) \
|
||||
|
|
|
@ -1020,15 +1020,6 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
|
|||
// Either an object or magic arguments.
|
||||
return MIRType::Value;
|
||||
|
||||
case ICStub::GetElem_NativeSlotName:
|
||||
case ICStub::GetElem_NativeSlotSymbol:
|
||||
case ICStub::GetElem_NativePrototypeSlotName:
|
||||
case ICStub::GetElem_NativePrototypeSlotSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeName:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedName:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
|
||||
case ICStub::GetElem_UnboxedPropertyName:
|
||||
case ICStub::GetElem_String:
|
||||
case ICStub::GetElem_Dense:
|
||||
case ICStub::GetElem_TypedArray:
|
||||
|
|
|
@ -19,16 +19,18 @@ using namespace js::jit;
|
|||
using mozilla::Maybe;
|
||||
|
||||
GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
|
||||
CacheKind cacheKind,
|
||||
bool* isTemporarilyUnoptimizable,
|
||||
HandleValue val, HandlePropertyName name,
|
||||
HandleValue val, HandleValue idVal,
|
||||
MutableHandleValue res)
|
||||
: writer(cx),
|
||||
cx_(cx),
|
||||
pc_(pc),
|
||||
val_(val),
|
||||
name_(name),
|
||||
idVal_(idVal),
|
||||
res_(res),
|
||||
engine_(engine),
|
||||
cacheKind_(cacheKind),
|
||||
isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
|
||||
preliminaryObjectAction_(PreliminaryObjectAction::None)
|
||||
{}
|
||||
|
@ -51,36 +53,50 @@ GetPropIRGenerator::tryAttachStub()
|
|||
AutoAssertNoPendingException aanpe(cx_);
|
||||
|
||||
ValOperandId valId(writer.setInputOperandId(0));
|
||||
if (cacheKind_ == CacheKind::GetElem) {
|
||||
MOZ_ASSERT(getElemKeyValueId().id() == 1);
|
||||
writer.setInputOperandId(1);
|
||||
}
|
||||
|
||||
RootedId id(cx_);
|
||||
bool nameOrSymbol;
|
||||
if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
|
||||
cx_->clearPendingException();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val_.isObject()) {
|
||||
RootedObject obj(cx_, &val_.toObject());
|
||||
ObjOperandId objId = writer.guardIsObject(valId);
|
||||
|
||||
if (tryAttachObjectLength(obj, objId))
|
||||
return true;
|
||||
if (tryAttachNative(obj, objId))
|
||||
return true;
|
||||
if (tryAttachUnboxed(obj, objId))
|
||||
return true;
|
||||
if (tryAttachUnboxedExpando(obj, objId))
|
||||
return true;
|
||||
if (tryAttachTypedObject(obj, objId))
|
||||
return true;
|
||||
if (tryAttachModuleNamespace(obj, objId))
|
||||
return true;
|
||||
if (tryAttachWindowProxy(obj, objId))
|
||||
return true;
|
||||
if (tryAttachProxy(obj, objId))
|
||||
return true;
|
||||
if (nameOrSymbol) {
|
||||
if (tryAttachObjectLength(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachNative(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachUnboxed(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachUnboxedExpando(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachTypedObject(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachModuleNamespace(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachWindowProxy(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachProxy(obj, objId, id))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tryAttachPrimitive(valId))
|
||||
return true;
|
||||
if (tryAttachStringLength(valId))
|
||||
return true;
|
||||
if (tryAttachMagicArguments(valId))
|
||||
return true;
|
||||
if (nameOrSymbol) {
|
||||
if (tryAttachPrimitive(valId, id))
|
||||
return true;
|
||||
if (tryAttachStringLength(valId, id))
|
||||
return true;
|
||||
if (tryAttachMagicArguments(valId, id))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +114,7 @@ IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sha
|
|||
if (*pc == JSOP_GETXPROP)
|
||||
return false;
|
||||
|
||||
return CheckHasNoSuchProperty(cx, obj, JSID_TO_ATOM(id)->asPropertyName());
|
||||
return CheckHasNoSuchProperty(cx, obj, id);
|
||||
}
|
||||
|
||||
enum NativeGetPropCacheability {
|
||||
|
@ -301,20 +317,20 @@ EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
|
||||
engine_, isTemporarilyUnoptimizable_);
|
||||
switch (type) {
|
||||
case CanAttachNone:
|
||||
return false;
|
||||
case CanAttachReadSlot:
|
||||
maybeEmitIdGuard(id);
|
||||
if (holder) {
|
||||
EnsureTrackPropertyTypes(cx_, holder, NameToId(name_));
|
||||
EnsureTrackPropertyTypes(cx_, holder, id);
|
||||
if (obj == holder) {
|
||||
// See the comment in StripPreliminaryObjectStubs.
|
||||
if (IsPreliminaryObject(obj))
|
||||
|
@ -327,6 +343,7 @@ GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId)
|
|||
EmitReadSlotReturn(writer, obj, holder, shape);
|
||||
return true;
|
||||
case CanAttachCallGetter:
|
||||
maybeEmitIdGuard(id);
|
||||
EmitCallGetterResult(writer, obj, holder, shape, objId);
|
||||
return true;
|
||||
}
|
||||
|
@ -335,7 +352,7 @@ GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
// Attach a stub when the receiver is a WindowProxy and we are calling some
|
||||
// kinds of JSNative getters on the Window object (the global object).
|
||||
|
@ -354,7 +371,6 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
|
|||
HandleObject windowObj = cx_->global();
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
|
||||
engine_, isTemporarilyUnoptimizable_);
|
||||
if (type != CanAttachCallGetter ||
|
||||
|
@ -372,6 +388,7 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
|
|||
|
||||
// Guard the incoming object is a WindowProxy and inline a getter call based
|
||||
// on the Window object.
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardClass(objId, GuardClassKind::WindowProxy);
|
||||
ObjOperandId windowObjId = writer.loadObject(windowObj);
|
||||
EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
|
||||
|
@ -379,7 +396,7 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
MOZ_ASSERT(obj->is<ProxyObject>());
|
||||
|
||||
|
@ -389,22 +406,32 @@ GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId)
|
|||
// the specialized stubs
|
||||
writer.guardNotDOMProxy(objId);
|
||||
|
||||
writer.callProxyGetResult(objId, NameToId(name_));
|
||||
if (cacheKind_ == CacheKind::GetProp) {
|
||||
writer.callProxyGetResult(objId, id);
|
||||
} else {
|
||||
// We could call maybeEmitIdGuard here and then emit CallProxyGetResult,
|
||||
// but for GetElem we prefer to attach a stub that can handle any Value
|
||||
// so we don't attach a new stub for every id.
|
||||
MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
|
||||
writer.callProxyGetByValueResult(objId, getElemKeyValueId());
|
||||
}
|
||||
|
||||
writer.typeMonitorResult();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
MOZ_ASSERT(IsCacheableDOMProxy(obj));
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardShape(objId, obj->maybeShape());
|
||||
|
||||
// No need for more guards: we know this is a DOM proxy, since the shape
|
||||
// guard enforces a given JSClass, so just go ahead and emit the call to
|
||||
// ProxyGet.
|
||||
writer.callProxyGetResult(objId, NameToId(name_));
|
||||
writer.callProxyGetResult(objId, id);
|
||||
writer.typeMonitorResult();
|
||||
return true;
|
||||
}
|
||||
|
@ -444,7 +471,7 @@ CheckDOMProxyExpandoDoesNotShadow(CacheIRWriter& writer, JSObject* obj, jsid id,
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
MOZ_ASSERT(IsCacheableDOMProxy(obj));
|
||||
|
||||
|
@ -452,13 +479,13 @@ GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId o
|
|||
RootedNativeObject holder(cx_);
|
||||
RootedShape shape(cx_);
|
||||
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
|
||||
pc_, engine_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
if (canCache == CanAttachNone)
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardShape(objId, obj->maybeShape());
|
||||
|
||||
// Guard that our expando object hasn't started shadowing this property.
|
||||
|
@ -495,42 +522,42 @@ GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId o
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (!obj->is<ProxyObject>())
|
||||
return false;
|
||||
|
||||
// Skim off DOM proxies.
|
||||
if (IsCacheableDOMProxy(obj)) {
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx_, obj, id);
|
||||
if (shadows == ShadowCheckFailed) {
|
||||
cx_->clearPendingException();
|
||||
return false;
|
||||
}
|
||||
if (DOMProxyIsShadowing(shadows))
|
||||
return tryAttachDOMProxyShadowed(obj, objId);
|
||||
return tryAttachDOMProxyShadowed(obj, objId, id);
|
||||
|
||||
MOZ_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique);
|
||||
return tryAttachDOMProxyUnshadowed(obj, objId);
|
||||
return tryAttachDOMProxyUnshadowed(obj, objId, id);
|
||||
}
|
||||
|
||||
return tryAttachGenericProxy(obj, objId);
|
||||
return tryAttachGenericProxy(obj, objId, id);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(name_);
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
|
||||
if (!property)
|
||||
return false;
|
||||
|
||||
if (!cx_->runtime()->jitSupportsFloatingPoint)
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardGroup(objId, obj->group());
|
||||
writer.loadUnboxedPropertyResult(objId, property->type,
|
||||
UnboxedPlainObject::offsetOfData() + property->offset);
|
||||
|
@ -544,7 +571,7 @@ GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
|
@ -553,17 +580,18 @@ GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId
|
|||
if (!expando)
|
||||
return false;
|
||||
|
||||
Shape* shape = expando->lookup(cx_, NameToId(name_));
|
||||
Shape* shape = expando->lookup(cx_, id);
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
EmitReadSlotResult(writer, obj, obj, shape, objId);
|
||||
EmitReadSlotReturn(writer, obj, obj, shape);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (!obj->is<TypedObject>() ||
|
||||
!cx_->runtime()->jitSupportsFloatingPoint ||
|
||||
|
@ -578,7 +606,7 @@ GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
|
|||
|
||||
StructTypeDescr* structDescr = &typedObj->typeDescr().as<StructTypeDescr>();
|
||||
size_t fieldIndex;
|
||||
if (!structDescr->fieldIndex(NameToId(name_), &fieldIndex))
|
||||
if (!structDescr->fieldIndex(id, &fieldIndex))
|
||||
return false;
|
||||
|
||||
TypeDescr* fieldDescr = &structDescr->fieldDescr(fieldIndex);
|
||||
|
@ -591,6 +619,7 @@ GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
|
|||
uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
|
||||
uint32_t typeDescr = SimpleTypeDescrKey(&fieldDescr->as<SimpleTypeDescr>());
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardNoDetachedTypedObjects();
|
||||
writer.guardShape(objId, shape);
|
||||
writer.loadTypedObjectResult(objId, fieldOffset, layout, typeDescr);
|
||||
|
@ -614,9 +643,9 @@ GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (name_ != cx_->names().length)
|
||||
if (!JSID_IS_ATOM(id, cx_->names().length))
|
||||
return false;
|
||||
|
||||
if (obj->is<ArrayObject>()) {
|
||||
|
@ -625,6 +654,7 @@ GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
|
|||
if (obj->as<ArrayObject>().length() > INT32_MAX)
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardClass(objId, GuardClassKind::Array);
|
||||
writer.loadInt32ArrayLengthResult(objId);
|
||||
writer.returnFromIC();
|
||||
|
@ -632,6 +662,7 @@ GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
if (obj->is<UnboxedArrayObject>()) {
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardClass(objId, GuardClassKind::UnboxedArray);
|
||||
writer.loadUnboxedArrayLengthResult(objId);
|
||||
writer.returnFromIC();
|
||||
|
@ -639,6 +670,7 @@ GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
if (obj->is<ArgumentsObject>() && !obj->as<ArgumentsObject>().hasOverriddenLength()) {
|
||||
maybeEmitIdGuard(id);
|
||||
if (obj->is<MappedArgumentsObject>()) {
|
||||
writer.guardClass(objId, GuardClassKind::MappedArguments);
|
||||
} else {
|
||||
|
@ -654,7 +686,7 @@ GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId)
|
||||
GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
if (!obj->is<ModuleNamespaceObject>())
|
||||
return false;
|
||||
|
@ -662,7 +694,7 @@ GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objI
|
|||
Rooted<ModuleNamespaceObject*> ns(cx_, &obj->as<ModuleNamespaceObject>());
|
||||
RootedModuleEnvironmentObject env(cx_);
|
||||
RootedShape shape(cx_);
|
||||
if (!ns->bindings().lookup(NameToId(name_), env.address(), shape.address()))
|
||||
if (!ns->bindings().lookup(id, env.address(), shape.address()))
|
||||
return false;
|
||||
|
||||
// Don't emit a stub until the target binding has been initialized.
|
||||
|
@ -673,6 +705,7 @@ GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objI
|
|||
EnsureTrackPropertyTypes(cx_, env, shape->propid());
|
||||
|
||||
// Check for the specific namespace object.
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardSpecificObject(objId, ns);
|
||||
|
||||
ObjOperandId envId = writer.loadObject(env);
|
||||
|
@ -682,12 +715,12 @@ GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objI
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
|
||||
GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId, HandleId id)
|
||||
{
|
||||
JSValueType primitiveType;
|
||||
RootedNativeObject proto(cx_);
|
||||
if (val_.isString()) {
|
||||
if (name_ == cx_->names().length) {
|
||||
if (JSID_IS_ATOM(id, cx_->names().length)) {
|
||||
// String length is special-cased, see js::GetProperty.
|
||||
return false;
|
||||
}
|
||||
|
@ -710,7 +743,6 @@ GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
|
|||
return false;
|
||||
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
if (IsIonEnabled(cx_))
|
||||
EnsureTrackPropertyTypes(cx_, proto, id);
|
||||
|
||||
|
@ -720,6 +752,7 @@ GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
|
|||
return false;
|
||||
|
||||
writer.guardType(valId, primitiveType);
|
||||
maybeEmitIdGuard(id);
|
||||
|
||||
ObjOperandId protoId = writer.loadObject(proto);
|
||||
writer.guardShape(protoId, proto->lastProperty());
|
||||
|
@ -729,37 +762,61 @@ GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
|
|||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachStringLength(ValOperandId valId)
|
||||
GetPropIRGenerator::tryAttachStringLength(ValOperandId valId, HandleId id)
|
||||
{
|
||||
if (!val_.isString() || name_ != cx_->names().length)
|
||||
if (!val_.isString() || !JSID_IS_ATOM(id, cx_->names().length))
|
||||
return false;
|
||||
|
||||
StringOperandId strId = writer.guardIsString(valId);
|
||||
maybeEmitIdGuard(id);
|
||||
writer.loadStringLengthResult(strId);
|
||||
writer.returnFromIC();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachMagicArguments(ValOperandId valId)
|
||||
GetPropIRGenerator::tryAttachMagicArguments(ValOperandId valId, HandleId id)
|
||||
{
|
||||
if (!val_.isMagic(JS_OPTIMIZED_ARGUMENTS))
|
||||
return false;
|
||||
|
||||
if (name_ != cx_->names().length && name_ != cx_->names().callee)
|
||||
if (!JSID_IS_ATOM(id, cx_->names().length) && !JSID_IS_ATOM(id, cx_->names().callee))
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardMagicValue(valId, JS_OPTIMIZED_ARGUMENTS);
|
||||
writer.guardFrameHasNoArgumentsObject();
|
||||
|
||||
if (name_ == cx_->names().length) {
|
||||
if (JSID_IS_ATOM(id, cx_->names().length)) {
|
||||
writer.loadFrameNumActualArgsResult();
|
||||
writer.returnFromIC();
|
||||
} else {
|
||||
MOZ_ASSERT(name_ == cx_->names().callee);
|
||||
MOZ_ASSERT(JSID_IS_ATOM(id, cx_->names().callee));
|
||||
writer.loadFrameCalleeResult();
|
||||
writer.typeMonitorResult();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GetPropIRGenerator::maybeEmitIdGuard(jsid id)
|
||||
{
|
||||
if (cacheKind_ == CacheKind::GetProp) {
|
||||
// Constant PropertyName, no guards necessary.
|
||||
MOZ_ASSERT(&idVal_.toString()->asAtom() == JSID_TO_ATOM(id));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
|
||||
|
||||
ValOperandId valId = getElemKeyValueId();
|
||||
if (JSID_IS_SYMBOL(id)) {
|
||||
SymbolOperandId symId = writer.guardIsSymbol(valId);
|
||||
writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
|
||||
} else {
|
||||
MOZ_ASSERT(JSID_IS_ATOM(id));
|
||||
StringOperandId strId = writer.guardIsString(valId);
|
||||
writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,13 @@ class StringOperandId : public OperandId
|
|||
explicit StringOperandId(uint16_t id) : OperandId(id) {}
|
||||
};
|
||||
|
||||
class SymbolOperandId : public OperandId
|
||||
{
|
||||
public:
|
||||
SymbolOperandId() = default;
|
||||
explicit SymbolOperandId(uint16_t id) : OperandId(id) {}
|
||||
};
|
||||
|
||||
class TypedOperandId : public OperandId
|
||||
{
|
||||
JSValueType type_;
|
||||
|
@ -97,13 +104,23 @@ class TypedOperandId : public OperandId
|
|||
MOZ_IMPLICIT TypedOperandId(StringOperandId id)
|
||||
: OperandId(id.id()), type_(JSVAL_TYPE_STRING)
|
||||
{}
|
||||
MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
|
||||
: OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL)
|
||||
{}
|
||||
|
||||
JSValueType type() const { return type_; }
|
||||
};
|
||||
|
||||
enum class CacheKind : uint8_t
|
||||
{
|
||||
GetProp,
|
||||
GetElem,
|
||||
};
|
||||
|
||||
#define CACHE_IR_OPS(_) \
|
||||
_(GuardIsObject) \
|
||||
_(GuardIsString) \
|
||||
_(GuardIsSymbol) \
|
||||
_(GuardType) \
|
||||
_(GuardShape) \
|
||||
_(GuardGroup) \
|
||||
|
@ -112,6 +129,8 @@ class TypedOperandId : public OperandId
|
|||
_(GuardIsProxy) \
|
||||
_(GuardNotDOMProxy) \
|
||||
_(GuardSpecificObject) \
|
||||
_(GuardSpecificAtom) \
|
||||
_(GuardSpecificSymbol) \
|
||||
_(GuardNoDetachedTypedObjects) \
|
||||
_(GuardMagicValue) \
|
||||
_(GuardFrameHasNoArgumentsObject) \
|
||||
|
@ -138,6 +157,7 @@ class TypedOperandId : public OperandId
|
|||
_(CallScriptedGetterResult) \
|
||||
_(CallNativeGetterResult) \
|
||||
_(CallProxyGetResult) \
|
||||
_(CallProxyGetByValueResult) \
|
||||
_(LoadUndefinedResult) \
|
||||
\
|
||||
_(TypeMonitorResult) \
|
||||
|
@ -158,6 +178,8 @@ class StubField
|
|||
Shape,
|
||||
ObjectGroup,
|
||||
JSObject,
|
||||
Symbol,
|
||||
String,
|
||||
Id,
|
||||
|
||||
// These fields take up 64 bits on all platforms.
|
||||
|
@ -342,6 +364,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
writeOpWithOperandId(CacheOp::GuardIsString, val);
|
||||
return StringOperandId(val.id());
|
||||
}
|
||||
SymbolOperandId guardIsSymbol(ValOperandId val) {
|
||||
writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
|
||||
return SymbolOperandId(val.id());
|
||||
}
|
||||
void guardType(ValOperandId val, JSValueType type) {
|
||||
writeOpWithOperandId(CacheOp::GuardType, val);
|
||||
static_assert(sizeof(type) == sizeof(uint8_t), "JSValueType should fit in a byte");
|
||||
|
@ -375,6 +401,14 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
|
||||
addStubField(uintptr_t(expected), StubField::Type::JSObject);
|
||||
}
|
||||
void guardSpecificAtom(StringOperandId str, JSAtom* expected) {
|
||||
writeOpWithOperandId(CacheOp::GuardSpecificAtom, str);
|
||||
addStubField(uintptr_t(expected), StubField::Type::String);
|
||||
}
|
||||
void guardSpecificSymbol(SymbolOperandId sym, JS::Symbol* expected) {
|
||||
writeOpWithOperandId(CacheOp::GuardSpecificSymbol, sym);
|
||||
addStubField(uintptr_t(expected), StubField::Type::Symbol);
|
||||
}
|
||||
void guardMagicValue(ValOperandId val, JSWhyMagic magic) {
|
||||
writeOpWithOperandId(CacheOp::GuardMagicValue, val);
|
||||
buffer_.writeByte(uint32_t(magic));
|
||||
|
@ -485,6 +519,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
|
||||
addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
|
||||
}
|
||||
void callProxyGetByValueResult(ObjOperandId obj, ValOperandId idVal) {
|
||||
writeOpWithOperandId(CacheOp::CallProxyGetByValueResult, obj);
|
||||
writeOperandId(idVal);
|
||||
}
|
||||
|
||||
void typeMonitorResult() {
|
||||
writeOp(CacheOp::TypeMonitorResult);
|
||||
|
@ -522,6 +560,7 @@ class MOZ_RAII CacheIRReader
|
|||
ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
|
||||
ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
|
||||
StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
|
||||
SymbolOperandId symbolOperandId() { return SymbolOperandId(buffer_.readByte()); }
|
||||
|
||||
uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
|
||||
GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
|
||||
|
@ -561,38 +600,48 @@ class MOZ_RAII GetPropIRGenerator
|
|||
JSContext* cx_;
|
||||
jsbytecode* pc_;
|
||||
HandleValue val_;
|
||||
HandlePropertyName name_;
|
||||
HandleValue idVal_;
|
||||
MutableHandleValue res_;
|
||||
ICStubEngine engine_;
|
||||
CacheKind cacheKind_;
|
||||
bool* isTemporarilyUnoptimizable_;
|
||||
|
||||
enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
|
||||
PreliminaryObjectAction preliminaryObjectAction_;
|
||||
|
||||
bool tryAttachNative(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
||||
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachProxy(HandleObject obj, ObjOperandId objId);
|
||||
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
||||
bool tryAttachPrimitive(ValOperandId valId);
|
||||
bool tryAttachStringLength(ValOperandId valId);
|
||||
bool tryAttachMagicArguments(ValOperandId valId);
|
||||
bool tryAttachPrimitive(ValOperandId valId, HandleId id);
|
||||
bool tryAttachStringLength(ValOperandId valId, HandleId id);
|
||||
bool tryAttachMagicArguments(ValOperandId valId, HandleId id);
|
||||
|
||||
ValOperandId getElemKeyValueId() const {
|
||||
MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
|
||||
return ValOperandId(1);
|
||||
}
|
||||
|
||||
// If this is a GetElem cache, emit instructions to guard the incoming Value
|
||||
// matches |id|.
|
||||
void maybeEmitIdGuard(jsid id);
|
||||
|
||||
GetPropIRGenerator(const GetPropIRGenerator&) = delete;
|
||||
GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
|
||||
|
||||
public:
|
||||
GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
|
||||
GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine, CacheKind cacheKind,
|
||||
bool* isTemporarilyUnoptimizable,
|
||||
HandleValue val, HandlePropertyName name, MutableHandleValue res);
|
||||
HandleValue val, HandleValue idVal, MutableHandleValue res);
|
||||
|
||||
bool tryAttachStub();
|
||||
|
||||
|
@ -602,14 +651,9 @@ class MOZ_RAII GetPropIRGenerator
|
|||
bool shouldNotePreliminaryObjectStub() const {
|
||||
return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
|
||||
}
|
||||
const CacheIRWriter& writerRef() const {
|
||||
return writer;
|
||||
}
|
||||
};
|
||||
|
||||
enum class CacheKind : uint8_t
|
||||
{
|
||||
GetProp
|
||||
const CacheIRWriter& writerRef() const { return writer; }
|
||||
CacheKind cacheKind() const { return cacheKind_; }
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -1358,20 +1358,6 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache,
|
|||
return GetPropertyIC::CanAttachNone;
|
||||
}
|
||||
|
||||
static bool
|
||||
EqualStringsHelper(JSString* str1, JSString* str2)
|
||||
{
|
||||
MOZ_ASSERT(str1->isAtom());
|
||||
MOZ_ASSERT(!str2->isAtom());
|
||||
MOZ_ASSERT(str1->length() == str2->length());
|
||||
|
||||
JSLinearString* str2Linear = str2->ensureLinear(nullptr);
|
||||
if (!str2Linear)
|
||||
return false;
|
||||
|
||||
return EqualChars(&str1->asLinear(), str2Linear);
|
||||
}
|
||||
|
||||
static void
|
||||
EmitIdGuard(MacroAssembler& masm, jsid id, TypedOrValueRegister idReg, Register objReg,
|
||||
Register scratchReg, Label* failures)
|
||||
|
@ -2144,8 +2130,9 @@ GetPropertyIC::tryAttachModuleNamespace(JSContext* cx, HandleScript outerScript,
|
|||
JS::TrackedOutcome::ICGetPropStub_ReadSlot);
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id, bool* nameOrSymbol)
|
||||
bool
|
||||
jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
|
||||
bool* nameOrSymbol)
|
||||
{
|
||||
*nameOrSymbol = false;
|
||||
|
||||
|
|
|
@ -846,6 +846,9 @@ bool IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shap
|
|||
bool* isTemporarilyUnoptimizable = nullptr);
|
||||
bool IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape);
|
||||
|
||||
bool ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
|
||||
bool* nameOrSymbol);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -5439,8 +5439,7 @@ class MWasmTruncateToInt64
|
|||
trapOffset_(trapOffset)
|
||||
{
|
||||
setResultType(MIRType::Int64);
|
||||
setGuard(); // not removable because of possible side-effects.
|
||||
setMovable();
|
||||
setGuard(); // neither removable nor movable because of possible side-effects.
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -5472,8 +5471,7 @@ class MWasmTruncateToInt32
|
|||
: MUnaryInstruction(def), isUnsigned_(isUnsigned), trapOffset_(trapOffset)
|
||||
{
|
||||
setResultType(MIRType::Int32);
|
||||
setGuard(); // not removable because of possible side-effects.
|
||||
setMovable();
|
||||
setGuard(); // neither removable nor movable because of possible side-effects.
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -7032,8 +7030,10 @@ class MDiv : public MBinaryArithInstruction
|
|||
div->unsigned_ = unsignd;
|
||||
div->trapOnError_ = trapOnError;
|
||||
div->trapOffset_ = trapOffset;
|
||||
if (trapOnError)
|
||||
if (trapOnError) {
|
||||
div->setGuard(); // not removable because of possible side-effects.
|
||||
div->setNotMovable();
|
||||
}
|
||||
div->setMustPreserveNaN(mustPreserveNaN);
|
||||
if (type == MIRType::Int32)
|
||||
div->setTruncateKind(Truncate);
|
||||
|
@ -7166,8 +7166,10 @@ class MMod : public MBinaryArithInstruction
|
|||
mod->unsigned_ = unsignd;
|
||||
mod->trapOnError_ = trapOnError;
|
||||
mod->trapOffset_ = trapOffset;
|
||||
if (trapOnError)
|
||||
if (trapOnError) {
|
||||
mod->setGuard(); // not removable because of possible side-effects.
|
||||
mod->setNotMovable();
|
||||
}
|
||||
if (type == MIRType::Int32)
|
||||
mod->setTruncateKind(Truncate);
|
||||
return mod;
|
||||
|
|
|
@ -175,15 +175,6 @@ ICStub::NonCacheIRStubMakesGCCalls(Kind kind)
|
|||
case Call_ScriptedFunCall:
|
||||
case Call_StringSplit:
|
||||
case WarmUpCounter_Fallback:
|
||||
case GetElem_NativeSlotName:
|
||||
case GetElem_NativeSlotSymbol:
|
||||
case GetElem_NativePrototypeSlotName:
|
||||
case GetElem_NativePrototypeSlotSymbol:
|
||||
case GetElem_NativePrototypeCallNativeName:
|
||||
case GetElem_NativePrototypeCallNativeSymbol:
|
||||
case GetElem_NativePrototypeCallScriptedName:
|
||||
case GetElem_NativePrototypeCallScriptedSymbol:
|
||||
case GetElem_UnboxedPropertyName:
|
||||
case GetProp_CallNativeGlobal:
|
||||
case GetProp_Generic:
|
||||
case SetProp_CallScripted:
|
||||
|
@ -272,63 +263,6 @@ ICStub::trace(JSTracer* trc)
|
|||
TraceEdge(trc, &callStub->expectedStr(), "baseline-callstringsplit-str");
|
||||
break;
|
||||
}
|
||||
case ICStub::GetElem_NativeSlotName:
|
||||
case ICStub::GetElem_NativeSlotSymbol:
|
||||
case ICStub::GetElem_UnboxedPropertyName: {
|
||||
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
|
||||
getElemStub->receiverGuard().trace(trc);
|
||||
if (getElemStub->isSymbol()) {
|
||||
ICGetElem_NativeSlot<JS::Symbol*>* typedGetElemStub = toGetElem_NativeSlotSymbol();
|
||||
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
|
||||
} else {
|
||||
ICGetElemNativeSlotStub<PropertyName*>* typedGetElemStub =
|
||||
reinterpret_cast<ICGetElemNativeSlotStub<PropertyName*>*>(this);
|
||||
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::GetElem_NativePrototypeSlotName:
|
||||
case ICStub::GetElem_NativePrototypeSlotSymbol: {
|
||||
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
|
||||
getElemStub->receiverGuard().trace(trc);
|
||||
if (getElemStub->isSymbol()) {
|
||||
ICGetElem_NativePrototypeSlot<JS::Symbol*>* typedGetElemStub
|
||||
= toGetElem_NativePrototypeSlotSymbol();
|
||||
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
|
||||
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
|
||||
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
|
||||
} else {
|
||||
ICGetElem_NativePrototypeSlot<PropertyName*>* typedGetElemStub
|
||||
= toGetElem_NativePrototypeSlotName();
|
||||
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
|
||||
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
|
||||
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::GetElem_NativePrototypeCallNativeName:
|
||||
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedName:
|
||||
case ICStub::GetElem_NativePrototypeCallScriptedSymbol: {
|
||||
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
|
||||
getElemStub->receiverGuard().trace(trc);
|
||||
if (getElemStub->isSymbol()) {
|
||||
ICGetElemNativePrototypeCallStub<JS::Symbol*>* callStub =
|
||||
reinterpret_cast<ICGetElemNativePrototypeCallStub<JS::Symbol*>*>(this);
|
||||
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
|
||||
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
|
||||
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
|
||||
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
|
||||
} else {
|
||||
ICGetElemNativePrototypeCallStub<PropertyName*>* callStub =
|
||||
reinterpret_cast<ICGetElemNativePrototypeCallStub<PropertyName*>*>(this);
|
||||
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
|
||||
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
|
||||
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
|
||||
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::GetElem_Dense: {
|
||||
ICGetElem_Dense* getElemStub = toGetElem_Dense();
|
||||
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
|
||||
|
@ -2281,7 +2215,7 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
|
|||
}
|
||||
|
||||
bool
|
||||
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
|
||||
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, jsid id,
|
||||
JSObject** lastProto, size_t* protoChainDepthOut)
|
||||
{
|
||||
size_t depth = 0;
|
||||
|
@ -2289,9 +2223,9 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
|
|||
while (curObj) {
|
||||
if (curObj->isNative()) {
|
||||
// Don't handle proto chains with resolve hooks.
|
||||
if (ClassMayResolveId(cx->names(), curObj->getClass(), NameToId(name), curObj))
|
||||
if (ClassMayResolveId(cx->names(), curObj->getClass(), id, curObj))
|
||||
return false;
|
||||
if (curObj->as<NativeObject>().contains(cx, NameToId(name)))
|
||||
if (curObj->as<NativeObject>().contains(cx, id))
|
||||
return false;
|
||||
if (curObj->getClass()->getGetProperty())
|
||||
return false;
|
||||
|
@ -2299,13 +2233,13 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
|
|||
// Non-native objects are only handled as the original receiver.
|
||||
return false;
|
||||
} else if (curObj->is<UnboxedPlainObject>()) {
|
||||
if (curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, NameToId(name)))
|
||||
if (curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id))
|
||||
return false;
|
||||
} else if (curObj->is<UnboxedArrayObject>()) {
|
||||
if (name == cx->names().length)
|
||||
if (JSID_IS_ATOM(id, cx->names().length))
|
||||
return false;
|
||||
} else if (curObj->is<TypedObject>()) {
|
||||
if (curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(), NameToId(name)))
|
||||
if (curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -2404,9 +2338,11 @@ DoGetPropFallback(JSContext* cx, void* payload, ICGetProp_Fallback* stub_,
|
|||
}
|
||||
|
||||
if (!attached && !JitOptions.disableCacheIR) {
|
||||
GetPropIRGenerator gen(cx, pc, engine, &isTemporarilyUnoptimizable, val, name, res);
|
||||
RootedValue idVal(cx, StringValue(name));
|
||||
GetPropIRGenerator gen(cx, pc, engine, CacheKind::GetProp, &isTemporarilyUnoptimizable,
|
||||
val, idVal, res);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), CacheKind::GetProp,
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
engine, info.outerScript(cx), stub);
|
||||
if (newStub) {
|
||||
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
|
||||
|
|
|
@ -2238,7 +2238,7 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
|
|||
HandleObject receiver,
|
||||
HandleFunction getter);
|
||||
MOZ_MUST_USE bool
|
||||
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
|
||||
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, jsid id,
|
||||
JSObject** lastProto = nullptr, size_t* protoChainDepthOut = nullptr);
|
||||
|
||||
void
|
||||
|
|
|
@ -1362,5 +1362,31 @@ ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleVa
|
|||
return Proxy::get(cx, proxy, receiver, id, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
RootedId id(cx);
|
||||
if (!ValueToId<CanGC>(cx, idVal, &id))
|
||||
return false;
|
||||
|
||||
RootedValue receiver(cx, ObjectValue(*proxy));
|
||||
return Proxy::get(cx, proxy, receiver, id, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
EqualStringsHelper(JSString* str1, JSString* str2)
|
||||
{
|
||||
MOZ_ASSERT(str1->isAtom());
|
||||
MOZ_ASSERT(!str2->isAtom());
|
||||
MOZ_ASSERT(str1->length() == str2->length());
|
||||
|
||||
JSLinearString* str2Linear = str2->ensureLinear(nullptr);
|
||||
if (!str2Linear)
|
||||
return false;
|
||||
|
||||
return EqualChars(&str1->asLinear(), str2Linear);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
@ -812,6 +812,13 @@ BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue
|
|||
MOZ_MUST_USE bool
|
||||
ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
|
||||
MutableHandleValue vp);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
EqualStringsHelper(JSString* str1, JSString* str2);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -692,7 +692,7 @@ CodeGeneratorARM::modICommon(MMod* mir, Register lhs, Register rhs, Register out
|
|||
// 0/X (with X < 0) is bad because both of these values *should* be doubles,
|
||||
// and the result should be -0.0, which cannot be represented in integers.
|
||||
// X/0 is bad because it will give garbage (or abort), when it should give
|
||||
// either \infty, -\infty or NAN.
|
||||
// either \infty, -\infty or NaN.
|
||||
|
||||
// Prevent 0 / X (with X < 0) and X / 0
|
||||
// testing X / Y. Compare Y with 0.
|
||||
|
@ -704,19 +704,23 @@ CodeGeneratorARM::modICommon(MMod* mir, Register lhs, Register rhs, Register out
|
|||
// If (Y > 0), we don't set EQ, and we don't trigger LT, so we don't take
|
||||
// the bailout.
|
||||
if (mir->canBeDivideByZero() || mir->canBeNegativeDividend()) {
|
||||
if (mir->trapOnError()) {
|
||||
// wasm allows negative lhs and return 0 in this case.
|
||||
MOZ_ASSERT(mir->isTruncated());
|
||||
masm.as_cmp(rhs, Imm8(0));
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
return;
|
||||
}
|
||||
|
||||
masm.as_cmp(rhs, Imm8(0));
|
||||
masm.as_cmp(lhs, Imm8(0), Assembler::LessThan);
|
||||
if (mir->isTruncated()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
} else {
|
||||
// NaN|0 == 0 and (0 % -X)|0 == 0
|
||||
Label skip;
|
||||
masm.ma_b(&skip, Assembler::NotEqual);
|
||||
masm.ma_mov(Imm32(0), output);
|
||||
masm.ma_b(&done);
|
||||
masm.bind(&skip);
|
||||
}
|
||||
// NaN|0 == 0 and (0 % -X)|0 == 0
|
||||
Label skip;
|
||||
masm.ma_b(&skip, Assembler::NotEqual);
|
||||
masm.ma_mov(Imm32(0), output);
|
||||
masm.ma_b(&done);
|
||||
masm.bind(&skip);
|
||||
} else {
|
||||
MOZ_ASSERT(mir->fallible());
|
||||
bailoutIf(Assembler::Equal, snapshot);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
/* LegacyIntTypes.h is deliberately exempted from this requirement */
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/ProfilingStack.h"
|
||||
#include "js/RefCounted.h"
|
||||
#include "js/RequiredDefines.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/SliceBudget.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
|
@ -34,6 +33,7 @@
|
|||
#include "js/Id.h"
|
||||
#include "js/Principals.h"
|
||||
#include "js/Realm.h"
|
||||
#include "js/RefCounted.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
|
@ -6087,7 +6087,7 @@ SetBuildIdOp(JSContext* cx, BuildIdOp buildIdOp);
|
|||
* by calling createObject().
|
||||
*/
|
||||
|
||||
struct WasmModule : mozilla::external::AtomicRefCounted<WasmModule>
|
||||
struct WasmModule : js::AtomicRefCounted<WasmModule>
|
||||
{
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(WasmModule)
|
||||
virtual ~WasmModule() {}
|
||||
|
|
|
@ -133,6 +133,7 @@ EXPORTS.js += [
|
|||
'../public/ProfilingStack.h',
|
||||
'../public/Proxy.h',
|
||||
'../public/Realm.h',
|
||||
'../public/RefCounted.h',
|
||||
'../public/RequiredDefines.h',
|
||||
'../public/Result.h',
|
||||
'../public/RootingAPI.h',
|
||||
|
|
|
@ -4293,20 +4293,20 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
|
|||
static
|
||||
bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
|
||||
{
|
||||
return (aDisplay->mDisplay == StyleDisplay::InlineBox ||
|
||||
return (aDisplay->mDisplay == StyleDisplay::MozInlineBox ||
|
||||
#ifdef MOZ_XUL
|
||||
aDisplay->mDisplay == StyleDisplay::InlineXulGrid ||
|
||||
aDisplay->mDisplay == StyleDisplay::InlineStack ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozInlineGrid ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozInlineStack ||
|
||||
#endif
|
||||
aDisplay->mDisplay == StyleDisplay::Box
|
||||
aDisplay->mDisplay == StyleDisplay::MozBox
|
||||
#ifdef MOZ_XUL
|
||||
|| aDisplay->mDisplay == StyleDisplay::XulGrid ||
|
||||
aDisplay->mDisplay == StyleDisplay::Stack ||
|
||||
aDisplay->mDisplay == StyleDisplay::XulGridGroup ||
|
||||
aDisplay->mDisplay == StyleDisplay::XulGridLine ||
|
||||
aDisplay->mDisplay == StyleDisplay::Deck ||
|
||||
aDisplay->mDisplay == StyleDisplay::Popup ||
|
||||
aDisplay->mDisplay == StyleDisplay::Groupbox
|
||||
|| aDisplay->mDisplay == StyleDisplay::MozGrid ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozStack ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozGridGroup ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozGridLine ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozDeck ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozPopup ||
|
||||
aDisplay->mDisplay == StyleDisplay::MozGroupbox
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
@ -4485,7 +4485,7 @@ nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
|
|||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (aStyleContext->StyleDisplay()->mDisplay !=
|
||||
StyleDisplay::XulGridGroup) {
|
||||
StyleDisplay::MozGridGroup) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -4499,7 +4499,7 @@ const nsCSSFrameConstructor::FrameConstructionData*
|
|||
nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (aStyleContext->StyleDisplay()->mDisplay != StyleDisplay::XulGridLine) {
|
||||
if (aStyleContext->StyleDisplay()->mDisplay != StyleDisplay::MozGridLine) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -4517,36 +4517,36 @@ nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
|
|||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
static const FrameConstructionDataByDisplay sXULDisplayData[] = {
|
||||
SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::Box,
|
||||
SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozBox,
|
||||
NS_NewBoxFrame),
|
||||
SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::InlineBox,
|
||||
SCROLLABLE_ABSPOS_CONTAINER_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineBox,
|
||||
NS_NewBoxFrame),
|
||||
#ifdef MOZ_XUL
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::XulGrid, NS_NewGridBoxFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::InlineXulGrid, NS_NewGridBoxFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::XulGridGroup,
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGrid, NS_NewGridBoxFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineGrid, NS_NewGridBoxFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridGroup,
|
||||
NS_NewGridRowGroupFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::XulGridLine,
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGridLine,
|
||||
NS_NewGridRowLeafFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::Stack, NS_NewStackFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::InlineStack, NS_NewStackFrame),
|
||||
SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::Deck, NS_NewDeckFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::Groupbox, NS_NewGroupBoxFrame),
|
||||
FCDATA_FOR_DISPLAY(StyleDisplay::Popup,
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozStack, NS_NewStackFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozInlineStack, NS_NewStackFrame),
|
||||
SIMPLE_XUL_DISPLAY_CREATE(StyleDisplay::MozDeck, NS_NewDeckFrame),
|
||||
SCROLLABLE_XUL_DISPLAY_CREATE(StyleDisplay::MozGroupbox, NS_NewGroupBoxFrame),
|
||||
FCDATA_FOR_DISPLAY(StyleDisplay::MozPopup,
|
||||
FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
|
||||
FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame))
|
||||
#endif /* MOZ_XUL */
|
||||
};
|
||||
|
||||
if (aDisplay->mDisplay < StyleDisplay::Box) {
|
||||
if (aDisplay->mDisplay < StyleDisplay::MozBox) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::Popup,
|
||||
MOZ_ASSERT(aDisplay->mDisplay <= StyleDisplay::MozPopup,
|
||||
"Someone added a new display value?");
|
||||
|
||||
const FrameConstructionDataByDisplay& data =
|
||||
sXULDisplayData[size_t(aDisplay->mDisplay) - size_t(StyleDisplay::Box)];
|
||||
sXULDisplayData[size_t(aDisplay->mDisplay) - size_t(StyleDisplay::MozBox)];
|
||||
MOZ_ASSERT(aDisplay->mDisplay == data.mDisplay,
|
||||
"Did someone mess with the order?");
|
||||
|
||||
|
@ -4576,8 +4576,8 @@ nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
|
|||
const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay();
|
||||
if (IsXULDisplayType(displayStyle)) {
|
||||
gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot,
|
||||
displayStyle->mDisplay == StyleDisplay::Stack ||
|
||||
displayStyle->mDisplay == StyleDisplay::InlineStack);
|
||||
displayStyle->mDisplay == StyleDisplay::MozStack ||
|
||||
displayStyle->mDisplay == StyleDisplay::MozInlineStack);
|
||||
} else {
|
||||
gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
|
||||
}
|
||||
|
@ -6613,8 +6613,8 @@ nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
|
|||
}
|
||||
if (nsGkAtoms::menuFrame == parentType) {
|
||||
return
|
||||
(StyleDisplay::Popup == aDisplay) ==
|
||||
(StyleDisplay::Popup == siblingDisplay);
|
||||
(StyleDisplay::MozPopup == aDisplay) ==
|
||||
(StyleDisplay::MozPopup == siblingDisplay);
|
||||
}
|
||||
// To have decent performance we want to return false in cases in which
|
||||
// reordering the two siblings has no effect on display. To ensure
|
||||
|
@ -10902,7 +10902,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
|||
const char16_t* params[] = { parentTag.get(), kidTag.get() };
|
||||
const nsStyleDisplay *display = frameStyleContext->StyleDisplay();
|
||||
const char *message =
|
||||
(display->mDisplay == StyleDisplay::InlineBox)
|
||||
(display->mDisplay == StyleDisplay::MozInlineBox)
|
||||
? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Layout: FrameConstructor"),
|
||||
|
|
|
@ -509,7 +509,7 @@ nsFrameIterator::IsPopupFrame(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
return (aFrame &&
|
||||
aFrame->StyleDisplay()->mDisplay == StyleDisplay::Popup);
|
||||
aFrame->StyleDisplay()->mDisplay == StyleDisplay::MozPopup);
|
||||
}
|
||||
|
||||
// nsVisualIterator implementation
|
||||
|
|
|
@ -1407,7 +1407,7 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
|
|||
id = nsIFrame::kAbsoluteList;
|
||||
}
|
||||
#ifdef MOZ_XUL
|
||||
} else if (StyleDisplay::Popup == disp->mDisplay) {
|
||||
} else if (StyleDisplay::MozPopup == disp->mDisplay) {
|
||||
// Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
|
||||
#ifdef DEBUG
|
||||
nsIFrame* parent = aChildFrame->GetParent();
|
||||
|
|
|
@ -838,7 +838,7 @@ ReflowInput::InitFrameType(nsIAtom* aFrameType)
|
|||
else if (disp->IsFloating(mFrame)) {
|
||||
frameType = NS_CSS_FRAME_TYPE_FLOATING;
|
||||
} else {
|
||||
NS_ASSERTION(disp->mDisplay == StyleDisplay::Popup,
|
||||
NS_ASSERTION(disp->mDisplay == StyleDisplay::MozPopup,
|
||||
"unknown out of flow frame type");
|
||||
frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -859,9 +859,9 @@ ReflowInput::InitFrameType(nsIAtom* aFrameType)
|
|||
case StyleDisplay::Inline:
|
||||
case StyleDisplay::InlineBlock:
|
||||
case StyleDisplay::InlineTable:
|
||||
case StyleDisplay::InlineBox:
|
||||
case StyleDisplay::InlineXulGrid:
|
||||
case StyleDisplay::InlineStack:
|
||||
case StyleDisplay::MozInlineBox:
|
||||
case StyleDisplay::MozInlineGrid:
|
||||
case StyleDisplay::MozInlineStack:
|
||||
case StyleDisplay::InlineFlex:
|
||||
case StyleDisplay::WebkitInlineBox:
|
||||
case StyleDisplay::InlineGrid:
|
||||
|
|
|
@ -1302,18 +1302,18 @@ KTableEntry nsCSSProps::kDisplayKTable[] = {
|
|||
{ eCSSKeyword_table_caption, StyleDisplay::TableCaption },
|
||||
// Make sure this is kept in sync with the code in
|
||||
// nsCSSFrameConstructor::ConstructXULFrame
|
||||
{ eCSSKeyword__moz_box, StyleDisplay::Box },
|
||||
{ eCSSKeyword__moz_inline_box, StyleDisplay::InlineBox },
|
||||
{ eCSSKeyword__moz_box, StyleDisplay::MozBox },
|
||||
{ eCSSKeyword__moz_inline_box, StyleDisplay::MozInlineBox },
|
||||
#ifdef MOZ_XUL
|
||||
{ eCSSKeyword__moz_grid, StyleDisplay::XulGrid },
|
||||
{ eCSSKeyword__moz_inline_grid, StyleDisplay::InlineXulGrid },
|
||||
{ eCSSKeyword__moz_grid_group, StyleDisplay::XulGridGroup },
|
||||
{ eCSSKeyword__moz_grid_line, StyleDisplay::XulGridLine },
|
||||
{ eCSSKeyword__moz_stack, StyleDisplay::Stack },
|
||||
{ eCSSKeyword__moz_inline_stack, StyleDisplay::InlineStack },
|
||||
{ eCSSKeyword__moz_deck, StyleDisplay::Deck },
|
||||
{ eCSSKeyword__moz_popup, StyleDisplay::Popup },
|
||||
{ eCSSKeyword__moz_groupbox, StyleDisplay::Groupbox },
|
||||
{ eCSSKeyword__moz_grid, StyleDisplay::MozGrid },
|
||||
{ eCSSKeyword__moz_inline_grid, StyleDisplay::MozInlineGrid },
|
||||
{ eCSSKeyword__moz_grid_group, StyleDisplay::MozGridGroup },
|
||||
{ eCSSKeyword__moz_grid_line, StyleDisplay::MozGridLine },
|
||||
{ eCSSKeyword__moz_stack, StyleDisplay::MozStack },
|
||||
{ eCSSKeyword__moz_inline_stack, StyleDisplay::MozInlineStack },
|
||||
{ eCSSKeyword__moz_deck, StyleDisplay::MozDeck },
|
||||
{ eCSSKeyword__moz_popup, StyleDisplay::MozPopup },
|
||||
{ eCSSKeyword__moz_groupbox, StyleDisplay::MozGroupbox },
|
||||
#endif
|
||||
{ eCSSKeyword_flex, StyleDisplay::Flex },
|
||||
{ eCSSKeyword_inline_flex, StyleDisplay::InlineFlex },
|
||||
|
|
|
@ -289,11 +289,11 @@ nsRuleNode::EnsureInlineDisplay(StyleDisplay& display)
|
|||
case StyleDisplay::Grid:
|
||||
display = StyleDisplay::InlineGrid;
|
||||
break;
|
||||
case StyleDisplay::Box:
|
||||
display = StyleDisplay::InlineBox;
|
||||
case StyleDisplay::MozBox:
|
||||
display = StyleDisplay::MozInlineBox;
|
||||
break;
|
||||
case StyleDisplay::Stack:
|
||||
display = StyleDisplay::InlineStack;
|
||||
case StyleDisplay::MozStack:
|
||||
display = StyleDisplay::MozInlineStack;
|
||||
break;
|
||||
default:
|
||||
break; // Do nothing
|
||||
|
@ -1445,7 +1445,7 @@ struct SetEnumValueHelper
|
|||
DEFINE_ENUM_CLASS_SETTER(StyleWindowDragging, Default, NoDrag)
|
||||
DEFINE_ENUM_CLASS_SETTER(StyleOrient, Inline, Vertical)
|
||||
#ifdef MOZ_XUL
|
||||
DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None, Popup)
|
||||
DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None, MozPopup)
|
||||
#else
|
||||
DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None, InlineBox)
|
||||
#endif
|
||||
|
|
|
@ -514,18 +514,18 @@ enum class StyleDisplay : uint8_t {
|
|||
Contents,
|
||||
WebkitBox,
|
||||
WebkitInlineBox,
|
||||
Box,
|
||||
InlineBox,
|
||||
MozBox,
|
||||
MozInlineBox,
|
||||
#ifdef MOZ_XUL
|
||||
XulGrid,
|
||||
InlineXulGrid,
|
||||
XulGridGroup,
|
||||
XulGridLine,
|
||||
Stack,
|
||||
InlineStack,
|
||||
Deck,
|
||||
Groupbox,
|
||||
Popup,
|
||||
MozGrid,
|
||||
MozInlineGrid,
|
||||
MozGridGroup,
|
||||
MozGridLine,
|
||||
MozStack,
|
||||
MozInlineStack,
|
||||
MozDeck,
|
||||
MozGroupbox,
|
||||
MozPopup,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -2800,7 +2800,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
|
|||
// We guarantee that if mBinding is non-null, so are mBinding->GetURI() and
|
||||
// mBinding->mOriginPrincipal.
|
||||
RefPtr<mozilla::css::URLValue> mBinding; // [reset]
|
||||
mozilla::StyleDisplay mDisplay; // [reset] see nsStyleConsts.h SyleDisplay
|
||||
mozilla::StyleDisplay mDisplay; // [reset] see nsStyleConsts.h StyleDisplay
|
||||
mozilla::StyleDisplay mOriginalDisplay; // [reset] saved mDisplay for
|
||||
// position:absolute/fixed
|
||||
// and float:left/right;
|
||||
|
@ -2904,12 +2904,12 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
|
|||
return mozilla::StyleDisplay::Inline == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineBlock == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineTable == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineBox == aDisplay ||
|
||||
mozilla::StyleDisplay::MozInlineBox == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineFlex == aDisplay ||
|
||||
mozilla::StyleDisplay::WebkitInlineBox == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineGrid == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineXulGrid == aDisplay ||
|
||||
mozilla::StyleDisplay::InlineStack == aDisplay ||
|
||||
mozilla::StyleDisplay::MozInlineGrid == aDisplay ||
|
||||
mozilla::StyleDisplay::MozInlineStack == aDisplay ||
|
||||
mozilla::StyleDisplay::Ruby == aDisplay ||
|
||||
mozilla::StyleDisplay::RubyBase == aDisplay ||
|
||||
mozilla::StyleDisplay::RubyBaseContainer == aDisplay ||
|
||||
|
|
|
@ -1237,7 +1237,7 @@ nsBoxFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
// kPopupList and XULRelayoutChildAtOrdinal() only handles
|
||||
// principal children.
|
||||
if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
|
||||
StyleDisplay()->mDisplay != mozilla::StyleDisplay::Popup) {
|
||||
StyleDisplay()->mDisplay != mozilla::StyleDisplay::MozPopup) {
|
||||
parent->XULRelayoutChildAtOrdinal(this);
|
||||
// XXXldb Should this instead be a tree change on the child or parent?
|
||||
PresContext()->PresShell()->
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
#include "mozilla/RefCountType.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#include "nsXPCOM.h"
|
||||
|
@ -86,7 +87,7 @@ enum RefCountAtomicity
|
|||
NonAtomicRefCount
|
||||
};
|
||||
|
||||
template<typename T, RefCountAtomicity Atomicity>
|
||||
template<typename T, RefCountAtomicity Atomicity, typename D>
|
||||
class RefCounted
|
||||
{
|
||||
protected:
|
||||
|
@ -132,7 +133,7 @@ public:
|
|||
#ifdef DEBUG
|
||||
mRefCnt = detail::DEAD;
|
||||
#endif
|
||||
delete static_cast<const T*>(this);
|
||||
D()(const_cast<T*>(static_cast<const T*>(this)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,8 +172,8 @@ private:
|
|||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
|
||||
template<typename T, class D = DefaultDelete<T>>
|
||||
class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount, D>
|
||||
{
|
||||
public:
|
||||
~RefCounted()
|
||||
|
@ -191,9 +192,9 @@ namespace external {
|
|||
* NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING
|
||||
* instead.
|
||||
*/
|
||||
template<typename T>
|
||||
template<typename T, typename D = DefaultDelete<T>>
|
||||
class AtomicRefCounted :
|
||||
public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount>
|
||||
public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount, D>
|
||||
{
|
||||
public:
|
||||
~AtomicRefCounted()
|
||||
|
|
|
@ -81,9 +81,9 @@ class LibHandle;
|
|||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
|
||||
template <> inline void RefCounted<LibHandle, AtomicRefCount, DefaultDelete<LibHandle>>::Release() const;
|
||||
|
||||
template <> inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted()
|
||||
template <> inline RefCounted<LibHandle, AtomicRefCount, DefaultDelete<LibHandle>>::~RefCounted()
|
||||
{
|
||||
MOZ_ASSERT(mRefCnt == 0x7fffdead);
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ private:
|
|||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
|
||||
template <> inline void RefCounted<LibHandle, AtomicRefCount, DefaultDelete<LibHandle>>::Release() const {
|
||||
#ifdef DEBUG
|
||||
if (mRefCnt > 0x7fff0000)
|
||||
MOZ_ASSERT(mRefCnt > 0x7fffdead);
|
||||
|
|
|
@ -800,6 +800,19 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
|
|||
// The mConnectionBased flag is set later for the newly received challenge,
|
||||
// so here it reflects the previous 401/7 response schema.
|
||||
mAuthChannel->CloseStickyConnection();
|
||||
if (!proxyAuth) {
|
||||
// We must clear proxy ident in the following scenario + explanation:
|
||||
// - we are authenticating to an NTLM proxy and an NTLM server
|
||||
// - we successfully authenticated to the proxy, mProxyIdent keeps
|
||||
// the user name/domain and password, the identity has also been cached
|
||||
// - we just threw away the connection because we are now asking for
|
||||
// creds for the server (WWW auth)
|
||||
// - hence, we will have to auth to the proxy again as well
|
||||
// - if we didn't clear the proxy identity, it would be considered
|
||||
// as non-valid and we would ask the user again ; clearing it forces
|
||||
// use of the cached identity and not asking the user again
|
||||
mProxyIdent.Clear();
|
||||
}
|
||||
mConnectionBased = false;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче