Merge mozilla-inbound to mozilla-central. a=merge
Merge mozilla-inbound to mozilla-central. a=merge
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1893,16 +1893,37 @@ BaselineCacheIRCompiler::emitCallAddOrUp
if (!callVM(masm, AddOrUpdateSparseElementHelperInfo)) {
return false;
}
stubFrame.leave(masm);
return true;
}
+bool
+BaselineCacheIRCompiler::emitCallGetSparseElementResult()
+{
+ Register obj = allocator.useRegister(masm, reader.objOperandId());
+ Register id = allocator.useRegister(masm, reader.int32OperandId());
+ AutoScratchRegister scratch(allocator, masm);
+
+ allocator.discardStack(masm);
+
+ AutoStubFrame stubFrame(*this);
+ stubFrame.enter(masm, scratch);
+
+ masm.Push(id);
+ masm.Push(obj);
+
+ if (!callVM(masm, GetSparseElementHelperInfo)) {
+ return false;
+ }
+ stubFrame.leave(masm);
+ return true;
+}
bool
BaselineCacheIRCompiler::emitMegamorphicSetElement()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
bool strict = reader.readBool();
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -279,16 +279,19 @@ GetPropIRGenerator::tryAttachStub()
return true;
}
if (tryAttachDenseElement(obj, objId, index, indexId)) {
return true;
}
if (tryAttachDenseElementHole(obj, objId, index, indexId)) {
return true;
}
+ if (tryAttachSparseElement(obj, objId, index, indexId)) {
+ return true;
+ }
if (tryAttachUnboxedElementHole(obj, objId, index, indexId)) {
return true;
}
if (tryAttachArgumentsObjectArg(obj, objId, indexId)) {
return true;
}
if (tryAttachGenericElement(obj, objId, index, indexId)) {
return true;
@@ -2208,16 +2211,80 @@ GetPropIRGenerator::tryAttachDenseElemen
GeneratePrototypeHoleGuards(writer, nobj, objId);
writer.loadDenseElementHoleResult(objId, indexId);
writer.typeMonitorResult();
trackAttached("DenseElementHole");
return true;
}
+bool
+GetPropIRGenerator::tryAttachSparseElement(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId)
+{
+ if (!obj->isNative()) {
+ return false;
+ }
+ NativeObject* nobj = &obj->as<NativeObject>();
+
+ // Stub doesn't handle negative indices.
+ if (index > INT_MAX) {
+ return false;
+ }
+
+ // We also need to be past the end of the dense capacity, to ensure sparse.
+ if (index < nobj->getDenseInitializedLength()) {
+ return false;
+ }
+
+ // Only handle Array objects in this stub.
+ if (!nobj->is<ArrayObject>()) {
+ return false;
+ }
+
+ // Here, we ensure that the prototype chain does not define any sparse
+ // indexed properties on the shape lineage. This allows us to guard on
+ // the shapes up the prototype chain to ensure that no indexed properties
+ // exist outside of the dense elements.
+ //
+ // The `GeneratePrototypeHoleGuards` call below will guard on the shapes,
+ // as well as ensure that no prototypes contain dense elements, allowing
+ // us to perform a pure shape-search for out-of-bounds integer-indexed
+ // properties on the recevier object.
+ if ((nobj->staticPrototype() != nullptr) &&
+ ObjectMayHaveExtraIndexedProperties(nobj->staticPrototype()))
+ {
+ return false;
+ }
+
+ // Ensure that obj is an Array.
+ writer.guardClass(objId, GuardClassKind::Array);
+
+ // The helper we are going to call only applies to non-dense elements.
+ writer.guardIndexGreaterThanDenseInitLength(objId, indexId);
+
+ // Ensures we are able to efficiently able to map to an integral jsid.
+ writer.guardIndexIsNonNegative(indexId);
+
+ // Shape guard the prototype chain to avoid shadowing indexes from appearing.
+ // The helper function also ensures that the index does not appear within the
+ // dense element set of the prototypes.
+ GeneratePrototypeHoleGuards(writer, nobj, objId);
+
+ // At this point, we are guaranteed that the indexed property will not
+ // be found on one of the prototypes. We are assured that we only have
+ // to check that the receiving object has the property.
+
+ writer.callGetSparseElementResult(objId, indexId);
+ writer.typeMonitorResult();
+
+ trackAttached("GetSparseElement");
+ return true;
+}
+
static bool
IsPrimitiveArrayTypedObject(JSObject* obj)
{
if (!obj->is<TypedObject>()) {
return false;
}
TypeDescr& descr = obj->as<TypedObject>().typeDescr();
return descr.is<ArrayTypeDescr>() &&
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -277,16 +277,17 @@ extern const char* const CacheKindNames[
\
/* The *Result ops load a value into the cache's result register. */ \
_(LoadFixedSlotResult) \
_(LoadDynamicSlotResult) \
_(LoadUnboxedPropertyResult) \
_(LoadTypedObjectResult) \
_(LoadDenseElementResult) \
_(LoadDenseElementHoleResult) \
+ _(CallGetSparseElementResult) \
_(LoadDenseElementExistsResult) \
_(LoadTypedElementExistsResult) \
_(LoadDenseElementHoleExistsResult) \
_(LoadTypedElementResult) \
_(LoadInt32ArrayLengthResult) \
_(LoadArgumentsObjectArgResult) \
_(LoadArgumentsObjectLengthResult) \
_(LoadFunctionLengthResult) \
@@ -1233,16 +1234,20 @@ class MOZ_RAII CacheIRWriter : public JS
void loadDenseElementResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementResult, obj);
writeOperandId(index);
}
void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj);
writeOperandId(index);
}
+ void callGetSparseElementResult(ObjOperandId obj, Int32OperandId index) {
+ writeOpWithOperandId(CacheOp::CallGetSparseElementResult, obj);
+ writeOperandId(index);
+ }
void loadDenseElementExistsResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementExistsResult, obj);
writeOperandId(index);
}
void loadTypedElementExistsResult(ObjOperandId obj, Int32OperandId index, TypedThingLayout layout) {
writeOpWithOperandId(CacheOp::LoadTypedElementExistsResult, obj);
writeOperandId(index);
buffer_.writeByte(uint32_t(layout));
@@ -1595,16 +1600,18 @@ class MOZ_RAII GetPropIRGenerator : publ
bool tryAttachMagicArgument(ValOperandId valId, ValOperandId indexId);
bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId,
Int32OperandId indexId);
bool tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
+ bool tryAttachSparseElement(HandleObject obj, ObjOperandId objId,
+ uint32_t index, Int32OperandId indexId);
bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachUnboxedElementHole(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachGenericElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -2281,16 +2281,38 @@ IonCacheIRCompiler::emitCallAddOrUpdateS
masm.Push(Imm32(strict));
masm.Push(val);
masm.Push(id);
masm.Push(obj);
return callVM(masm, AddOrUpdateSparseElementHelperInfo);
}
+bool
+IonCacheIRCompiler::emitCallGetSparseElementResult()
+{
+ AutoSaveLiveRegisters save(*this);
+ AutoOutputRegister output(*this);
+
+ Register obj = allocator.useRegister(masm, reader.objOperandId());
+ Register id = allocator.useRegister(masm, reader.int32OperandId());
+
+ allocator.discardStack(masm);
+ prepareVMCall(masm, save);
+ masm.Push(id);
+ masm.Push(obj);
+
+ if (!callVM(masm, GetSparseElementHelperInfo)) {
+ return false;
+ }
+
+ masm.storeCallResultValue(output);
+ return true;
+}
+
bool
IonCacheIRCompiler::emitMegamorphicSetElement()
{
AutoSaveLiveRegisters save(*this);
Register obj = allocator.useRegister(masm, reader.objOperandId());
ConstantOrRegister idVal = allocator.useConstantOrRegister(masm, reader.valOperandId());
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -2080,10 +2080,15 @@ typedef bool (*NativeGetElementFn)(JSCon
const VMFunction NativeGetElementInfo =
FunctionInfo<NativeGetElementFn>(NativeGetElement, "NativeGetProperty");
typedef bool (*AddOrUpdateSparseElementHelperFn)(JSContext* cx, HandleArrayObject obj,
int32_t int_id, HandleValue v, bool strict);
const VMFunction AddOrUpdateSparseElementHelperInfo =
FunctionInfo<AddOrUpdateSparseElementHelperFn>(AddOrUpdateSparseElementHelper, "AddOrUpdateSparseElementHelper");
+typedef bool (*GetSparseElementHelperFn)(JSContext* cx, HandleArrayObject obj,
+ int32_t int_id, MutableHandleValue result);
+const VMFunction GetSparseElementHelperInfo =
+ FunctionInfo<GetSparseElementHelperFn>(GetSparseElementHelper, "getSparseElementHelper");
+
} // namespace jit
} // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -978,16 +978,17 @@ extern const VMFunction ProxyGetProperty
extern const VMFunction ProxySetPropertyInfo;
extern const VMFunction ProxySetPropertyByValueInfo;
extern const VMFunction ProxyHasInfo;
extern const VMFunction ProxyHasOwnInfo;
extern const VMFunction NativeGetElementInfo;
extern const VMFunction AddOrUpdateSparseElementHelperInfo;
+extern const VMFunction GetSparseElementHelperInfo;
// TailCall VMFunctions
extern const VMFunction DoConcatStringObjectInfo;
} // namespace jit
} // namespace js
#endif /* jit_VMFunctions_h */
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2529,16 +2529,42 @@ GeneralizedGetProperty(JSContext* cx, JS
return false;
}
if (nameLookup) {
return false;
}
return GetPropertyNoGC(cx, obj, receiver, id, vp.address());
}
+bool
+js::GetSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
+ MutableHandleValue result)
+{
+ // Callers should have ensured that this object has a static prototype.
+ MOZ_ASSERT(obj->hasStaticPrototype());
+
+ // Indexed properties can not exist on the prototype chain.
+ MOZ_ASSERT_IF(obj->staticPrototype() != nullptr,
+ !ObjectMayHaveExtraIndexedProperties(obj->staticPrototype()));
+
+ MOZ_ASSERT(INT_FITS_IN_JSID(int_id));
+ RootedId id(cx, INT_TO_JSID(int_id));
+
+ Shape* rawShape = obj->lastProperty()->search(cx, id);
+ if (!rawShape) {
+ // Property not found, return directly.
+ result.setUndefined();
+ return true;
+ }
+
+ RootedValue receiver(cx, ObjectValue(*obj));
+ RootedShape shape(cx, rawShape);
+ return GetExistingProperty<CanGC>(cx, receiver, obj, shape, result);
+}
+
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
NativeGetPropertyInline(JSContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<Value, allowGC>::HandleType receiver,
typename MaybeRooted<jsid, allowGC>::HandleType id,
IsNameLookup nameLookup,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1610,16 +1610,20 @@ NativeGetProperty(JSContext* cx, HandleN
return NativeGetProperty(cx, obj, receiver, id, vp);
}
extern bool
NativeGetElement(JSContext* cx, HandleNativeObject obj, HandleValue reciever, int32_t index,
MutableHandleValue vp);
bool
+GetSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
+ MutableHandleValue result);
+
+bool
SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
ObjectOpResult& result);
bool
SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
bool
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -973,17 +973,17 @@ ModuleGenerator::finishCodeTier()
UniqueModuleSegment segment = ModuleSegment::create(tier(), masm_, *linkData_);
if (!segment) {
return nullptr;
}
return js::MakeUnique<CodeTier>(std::move(metadataTier_), std::move(segment));
}
-bool
+SharedMetadata
ModuleGenerator::finishMetadata(const Bytes& bytecode)
{
// Finish initialization of Metadata, which is only needed for constructing
// the initial Module, not for tier-2 compilation.
MOZ_ASSERT(mode() != CompileMode::Tier2);
// Copy over data from the ModuleEnvironment.
@@ -1000,38 +1000,43 @@ ModuleGenerator::finishMetadata(const By
// Copy over additional debug information.
if (env_->debugEnabled()) {
metadata_->debugEnabled = true;
const size_t numFuncTypes = env_->funcTypes.length();
if (!metadata_->debugFuncArgTypes.resize(numFuncTypes)) {
- return false;
+ return nullptr;
}
if (!metadata_->debugFuncReturnTypes.resize(numFuncTypes)) {
- return false;
+ return nullptr;
}
for (size_t i = 0; i < numFuncTypes; i++) {
if (!metadata_->debugFuncArgTypes[i].appendAll(env_->funcTypes[i]->args())) {
- return false;
+ return nullptr;
}
metadata_->debugFuncReturnTypes[i] = env_->funcTypes[i]->ret();
}
static_assert(sizeof(ModuleHash) <= sizeof(mozilla::SHA1Sum::Hash),
"The ModuleHash size shall not exceed the SHA1 hash size.");
mozilla::SHA1Sum::Hash hash;
mozilla::SHA1Sum sha1Sum;
sha1Sum.update(bytecode.begin(), bytecode.length());
sha1Sum.finish(hash);
memcpy(metadata_->debugHash, hash, sizeof(ModuleHash));
}
- return true;
+ MOZ_ASSERT_IF(env_->nameCustomSectionIndex, !!metadata_->namePayload);
+
+ // Metadata shouldn't be mutably modified after finishMetadata().
+ SharedMetadata metadata = metadata_;
+ metadata_ = nullptr;
+ return metadata;
}
SharedModule
ModuleGenerator::finishModule(const ShareableBytes& bytecode,
JS::OptimizedEncodingListener* maybeTier2Listener,
UniqueLinkData* maybeLinkDataOut)
{
MOZ_ASSERT(mode() == CompileMode::Once || mode() == CompileMode::Tier1);
@@ -1041,33 +1046,16 @@ ModuleGenerator::finishModule(const Shar
return nullptr;
}
JumpTables jumpTables;
if (!jumpTables.init(mode(), codeTier->segment(), codeTier->metadata().codeRanges)) {
return nullptr;
}
- if (!finishMetadata(bytecode.bytes)) {
- return nullptr;
- }
-
- StructTypeVector structTypes;
- for (TypeDef& td : env_->types) {
- if (td.isStructType() && !structTypes.append(std::move(td.structType()))) {
- return nullptr;
- }
- }
-
- MutableCode code = js_new<Code>(std::move(codeTier), *metadata_, std::move(jumpTables),
- std::move(structTypes));
- if (!code || !code->initialize(*linkData_)) {
- return nullptr;
- }
-
// Copy over data from the Bytecode, which is going away at the end of
// compilation.
DataSegmentVector dataSegments;
if (!dataSegments.reserve(env_->dataSegments.length())) {
return nullptr;
}
for (const DataSegmentEnv& srcSeg : env_->dataSegments) {
@@ -1100,16 +1088,34 @@ ModuleGenerator::finishModule(const Shar
sec.payload = std::move(payload);
customSections.infallibleAppend(std::move(sec));
}
if (env_->nameCustomSectionIndex) {
metadata_->namePayload = customSections[*env_->nameCustomSectionIndex].payload;
}
+ SharedMetadata metadata = finishMetadata(bytecode.bytes);
+ if (!metadata) {
+ return nullptr;
+ }
+
+ StructTypeVector structTypes;
+ for (TypeDef& td : env_->types) {
+ if (td.isStructType() && !structTypes.append(std::move(td.structType()))) {
+ return nullptr;
+ }
+ }
+
+ MutableCode code = js_new<Code>(std::move(codeTier), *metadata, std::move(jumpTables),
+ std::move(structTypes));
+ if (!code || !code->initialize(*linkData_)) {
+ return nullptr;
+ }
+
// See Module debugCodeClaimed_ comments for why we need to make a separate
// debug copy.
UniqueBytes debugUnlinkedCode;
UniqueLinkData debugLinkData;
const ShareableBytes* debugBytecode = nullptr;
if (env_->debugEnabled()) {
MOZ_ASSERT(mode() == CompileMode::Once);
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -197,17 +197,17 @@ class MOZ_STACK_CLASS ModuleGenerator
void noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRange);
bool linkCompiledCode(const CompiledCode& code);
bool finishTask(CompileTask* task);
bool launchBatchCompile();
bool finishOutstandingTask();
bool finishCodegen();
bool finishMetadataTier();
UniqueCodeTier finishCodeTier();
- bool finishMetadata(const Bytes& bytecode);
+ SharedMetadata finishMetadata(const Bytes& bytecode);
bool isAsmJS() const { return env_->isAsmJS(); }
Tier tier() const { return env_->tier(); }
CompileMode mode() const { return env_->mode(); }
bool debugEnabled() const { return env_->debugEnabled(); }
public:
ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env,
--- a/mobile/android/config/mozconfigs/android-aarch64/nightly
+++ b/mobile/android/config/mozconfigs/android-aarch64/nightly
@@ -1,13 +1,19 @@
. "$topsrcdir/mobile/android/config/mozconfigs/common"
# Android
ac_add_options --with-android-min-sdk=21
ac_add_options --target=aarch64-linux-android
ac_add_options --with-branding=mobile/android/branding/nightly
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
export MOZ_ANDROID_POCKET=1
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-16/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16/nightly
@@ -11,9 +11,15 @@ ac_add_options --target=arm-linux-androi
ac_add_options --with-branding=mobile/android/branding/nightly
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
export MOZ_ANDROID_MMA=1
export MOZ_ANDROID_POCKET=1
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-x86/nightly
+++ b/mobile/android/config/mozconfigs/android-x86/nightly
@@ -9,9 +9,15 @@ ac_add_options --target=i686-linux-andro
ac_add_options --with-android-min-sdk=16
ac_add_options --with-branding=mobile/android/branding/nightly
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
export MOZ_ANDROID_POCKET=1
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"