Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-05-24 21:59:29 +08:00
commit 8495414910
53 changed files with 351 additions and 1527 deletions

View file

@ -4481,14 +4481,15 @@ nsBrowserAccess.prototype = {
} }
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground"); let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
let referrer = aOpener ? makeURI(aOpener.location.href) : null; let openerWindow = (aContext & Ci.nsIBrowserDOMWindow.OPEN_NO_OPENER) ? null : aOpener;
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", { let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
triggeringPrincipal: triggeringPrincipal, triggeringPrincipal: triggeringPrincipal,
referrerURI: referrer, referrerURI: referrer,
referrerPolicy: referrerPolicy, referrerPolicy: referrerPolicy,
fromExternal: isExternal, fromExternal: isExternal,
inBackground: loadInBackground}); inBackground: loadInBackground,
opener: openerWindow });
let browser = win.gBrowser.getBrowserForTab(tab); let browser = win.gBrowser.getBrowserForTab(tab);
if (gPrefService.getBoolPref("browser.tabs.noWindowActivationOnExternal")) { if (gPrefService.getBoolPref("browser.tabs.noWindowActivationOnExternal")) {

View file

@ -1339,6 +1339,7 @@
var aFromExternal; var aFromExternal;
var aRelatedToCurrent; var aRelatedToCurrent;
var aOriginPrincipal; var aOriginPrincipal;
var aOpener;
if (arguments.length == 2 && if (arguments.length == 2 &&
typeof arguments[1] == "object" && typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) { !(arguments[1] instanceof Ci.nsIURI)) {
@ -1353,6 +1354,7 @@
aFromExternal = params.fromExternal; aFromExternal = params.fromExternal;
aRelatedToCurrent = params.relatedToCurrent; aRelatedToCurrent = params.relatedToCurrent;
aOriginPrincipal = params.originPrincipal; aOriginPrincipal = params.originPrincipal;
aOpener = params.opener;
} }
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground : var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
@ -1368,7 +1370,8 @@
allowThirdPartyFixup: aAllowThirdPartyFixup, allowThirdPartyFixup: aAllowThirdPartyFixup,
fromExternal: aFromExternal, fromExternal: aFromExternal,
originPrincipal: aOriginPrincipal, originPrincipal: aOriginPrincipal,
relatedToCurrent: aRelatedToCurrent}); relatedToCurrent: aRelatedToCurrent,
opener: aOpener });
if (!bgLoad) if (!bgLoad)
this.selectedTab = tab; this.selectedTab = tab;
@ -1495,6 +1498,7 @@
var aSkipAnimation; var aSkipAnimation;
var aOriginPrincipal; var aOriginPrincipal;
var aSkipBackgroundNotify; var aSkipBackgroundNotify;
var aOpener;
if (arguments.length == 2 && if (arguments.length == 2 &&
typeof arguments[1] == "object" && typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) { !(arguments[1] instanceof Ci.nsIURI)) {
@ -1510,6 +1514,7 @@
aRelatedToCurrent = params.relatedToCurrent; aRelatedToCurrent = params.relatedToCurrent;
aSkipAnimation = params.skipAnimation; aSkipAnimation = params.skipAnimation;
aOriginPrincipal = params.originPrincipal; aOriginPrincipal = params.originPrincipal;
aOpener = params.opener;
aSkipBackgroundNotify = params.skipBackgroundNotify; aSkipBackgroundNotify = params.skipBackgroundNotify;
} }
@ -1584,6 +1589,10 @@
b.setAttribute("showresizer", "true"); b.setAttribute("showresizer", "true");
} }
if (aOpener) {
b.QueryInterface(Ci.nsIFrameLoaderOwner).presetOpenerWindow(aOpener);
}
if (this.hasAttribute("autocompletepopup")) if (this.hasAttribute("autocompletepopup"))
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup")); b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id); b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);

View file

@ -78,8 +78,21 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
// We can't use double buffering when using image content with // We can't use double buffering when using image content with
// Xrender support on Linux, as ContentHostDoubleBuffered is not // Xrender support on Linux, as ContentHostDoubleBuffered is not
// suited for direct uploads to the server. // suited for direct uploads to the server.
// FIXME: Even though the comment above suggests that double buffering
// is supposed to be disabled when Xrender support is being enabled
// (and used), it really wasn't. Historically,
// UseImageOffscreenSurfaces() was always false in GTK2 builds, thus
// triggering the check, regardless of UseXRender().
// Some time later, offscreen surfaces were always enabled, but the
// Xrender functionality broke due to not using Xlib-based surfaces.
// Using Xlib-based surfaces compatible with Xrender operations seems
// to lead to weird graphical artifacts (bars and stripes) on some
// hardware (Intel-based?) when displaying quickly-changing content,
// so contrary to the statement above we'd better enable double
// buffering - which also seems to not have any negative performance
// impact.
if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() || if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() ||
!gfxVars::UseXRender()) gfxVars::UseXRender())
#endif #endif
{ {
useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() && useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() &&

View file

@ -31,6 +31,7 @@
#include "nsSMILAnimationController.h" #include "nsSMILAnimationController.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "harfbuzz/hb.h" #include "harfbuzz/hb.h"
#include "zlib.h"
#include "mozilla/dom/ImageTracker.h" #include "mozilla/dom/ImageTracker.h"
#define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml") #define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
@ -285,7 +286,44 @@ gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer,
gfxSVGGlyphs *aSVGGlyphs) gfxSVGGlyphs *aSVGGlyphs)
: mOwner(aSVGGlyphs) : mOwner(aSVGGlyphs)
{ {
if (aBufLen >= 14 && aBuffer[0] == 31 && aBuffer[1] == 139) {
// It's a gzip-compressed document; decompress it before parsing.
// The original length (modulo 2^32) is found in the last 4 bytes
// of the data, stored in little-endian format. We read it as
// individual bytes to avoid possible alignment issues.
// (Note that if the original length was >2^32, then origLen here
// will be incorrect; but then the inflate() call will not return
// Z_STREAM_END and we'll bail out safely.)
size_t origLen = (size_t(aBuffer[aBufLen - 1]) << 24) +
(size_t(aBuffer[aBufLen - 2]) << 16) +
(size_t(aBuffer[aBufLen - 3]) << 8) +
size_t(aBuffer[aBufLen - 4]);
AutoTArray<uint8_t, 4096> outBuf;
if (outBuf.SetLength(origLen, mozilla::fallible)) {
z_stream s = {0};
s.next_in = const_cast<Byte*>(aBuffer);
s.avail_in = aBufLen;
s.next_out = outBuf.Elements();
s.avail_out = outBuf.Length();
// The magic number 16 here is the zlib flag to expect gzip format,
// see http://www.zlib.net/manual.html#Advanced
if (Z_OK == inflateInit2(&s, 16 + MAX_WBITS)) {
int result = inflate(&s, Z_FINISH);
if (Z_STREAM_END == result) {
MOZ_ASSERT(size_t(s.next_out - outBuf.Elements()) == origLen);
ParseDocument(outBuf.Elements(), outBuf.Length());
} else {
NS_WARNING("Failed to decompress SVG glyphs document");
}
inflateEnd(&s);
}
} else {
NS_WARNING("Failed to allocate memory for SVG glyphs document");
}
} else {
ParseDocument(aBuffer, aBufLen); ParseDocument(aBuffer, aBufLen);
}
if (!mDocument) { if (!mDocument) {
NS_WARNING("Could not parse SVG glyphs document"); NS_WARNING("Could not parse SVG glyphs document");
return; return;

View file

@ -1073,6 +1073,114 @@ function ArrayConcat(arg1) {
return A; return A;
} }
// https://tc39.github.io/proposal-flatMap/
// January 4, 2019
function ArrayFlatMap(mapperFunction/*, thisArg*/) {
// Step 1.
var O = ToObject(this);
// Step 2.
var sourceLen = ToLength(O.length);
// Step 3.
if (!IsCallable(mapperFunction))
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
// Step 4.
var T = arguments.length > 1 ? arguments[1] : undefined;
// Step 5.
var A = ArraySpeciesCreate(O, 0);
// Step 6.
FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
// Step 7.
return A;
}
// https://tc39.github.io/proposal-flatMap/
// January 4, 2019
function ArrayFlat(/* depth */) {
// Step 1.
var O = ToObject(this);
// Step 2.
var sourceLen = ToLength(O.length);
// Step 3.
var depthNum = 1;
// Step 4.
if (arguments.length > 0 && arguments[0] !== undefined)
depthNum = ToInteger(arguments[0]);
// Step 5.
var A = ArraySpeciesCreate(O, 0);
// Step 6.
FlattenIntoArray(A, O, sourceLen, 0, depthNum);
// Step 7.
return A;
}
// https://tc39.github.io/proposal-flatMap/
// January 4, 2019
function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) {
// Step 1.
var targetIndex = start;
// Steps 2-3.
for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
// Steps 3.a-c.
if (sourceIndex in source) {
// Step 3.c.i.
var element = source[sourceIndex];
if (mapperFunction) {
// Step 3.c.ii.1.
assert(arguments.length === 7, "thisArg is present");
// Step 3.c.ii.2.
element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source);
}
// Step 3.c.iii.
var shouldFlatten = false;
// Step 3.c.iv.
if (depth > 0) {
// Step 3.c.iv.1.
shouldFlatten = IsArray(element);
}
// Step 3.c.v.
if (shouldFlatten) {
// Step 3.c.v.1.
var elementLen = ToLength(element.length);
// Step 3.c.v.2.
// Recursive call to walk the depth.
targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1);
} else {
// Step 3.c.vi.1.
if (targetIndex >= MAX_NUMERIC_INDEX)
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
// Step 3.c.vi.2.
_DefineDataProperty(target, targetIndex, element);
// Step 3.c.vi.3.
targetIndex++;
}
}
}
// Step 4.
return targetIndex;
}
function ArrayStaticConcat(arr, arg1) { function ArrayStaticConcat(arr, arg1) {
if (arguments.length < 1) if (arguments.length < 1)
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat'); ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat');

View file

@ -33,6 +33,7 @@ SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol)
} }
const JSPropertySpec SymbolObject::properties[] = { const JSPropertySpec SymbolObject::properties[] = {
JS_PSG("description", descriptionGetter, 0),
JS_PS_END JS_PS_END
}; };
@ -227,6 +228,34 @@ SymbolObject::toPrimitive(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args); return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args);
} }
// ES2019 Stage 4 Draft / November 28, 2018
// Symbol description accessor
// See: https://tc39.github.io/proposal-Symbol-description/
bool
SymbolObject::descriptionGetter_impl(JSContext* cx, const CallArgs& args)
{
// Get symbol object pointer.
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsSymbol(thisv));
Rooted<Symbol*> sym(cx, thisv.isSymbol()
? thisv.toSymbol()
: thisv.toObject().as<SymbolObject>().unbox());
// Return the symbol's description if present, otherwise return undefined.
if (JSString* str = sym->description())
args.rval().setString(str);
else
args.rval().setUndefined();
return true;
}
bool
SymbolObject::descriptionGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsSymbol, descriptionGetter_impl>(cx, args);
}
JSObject* JSObject*
js::InitSymbolClass(JSContext* cx, HandleObject obj) js::InitSymbolClass(JSContext* cx, HandleObject obj)
{ {

View file

@ -52,6 +52,10 @@ class SymbolObject : public NativeObject
static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp);
// Properties defined on Symbol.prototype.
static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx, const CallArgs& args);
static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc, Value *vp);
static const JSPropertySpec properties[]; static const JSPropertySpec properties[];
static const JSFunctionSpec methods[]; static const JSFunctionSpec methods[];
static const JSFunctionSpec staticMethods[]; static const JSFunctionSpec staticMethods[];

View file

@ -18,6 +18,7 @@
#include "builtin/ModuleObject.h" #include "builtin/ModuleObject.h"
#include "gc/GCInternals.h" #include "gc/GCInternals.h"
#include "gc/Policy.h" #include "gc/Policy.h"
#include "gc/StoreBuffer-inl.h"
#include "jit/IonCode.h" #include "jit/IonCode.h"
#include "js/SliceBudget.h" #include "js/SliceBudget.h"
#include "vm/ArgumentsObject.h" #include "vm/ArgumentsObject.h"
@ -28,7 +29,6 @@
#include "vm/Shape.h" #include "vm/Shape.h"
#include "vm/Symbol.h" #include "vm/Symbol.h"
#include "vm/TypedArrayObject.h" #include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
#include "wasm/WasmJS.h" #include "wasm/WasmJS.h"
#include "jscompartmentinlines.h" #include "jscompartmentinlines.h"
@ -37,7 +37,6 @@
#include "gc/Nursery-inl.h" #include "gc/Nursery-inl.h"
#include "vm/String-inl.h" #include "vm/String-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js; using namespace js;
using namespace js::gc; using namespace js::gc;
@ -1395,14 +1394,6 @@ js::ObjectGroup::traceChildren(JSTracer* trc)
if (maybePreliminaryObjects()) if (maybePreliminaryObjects())
maybePreliminaryObjects()->trace(trc); maybePreliminaryObjects()->trace(trc);
if (maybeUnboxedLayout())
unboxedLayout().trace(trc);
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group");
setOriginalUnboxedGroup(unboxedGroup);
}
if (JSObject* descr = maybeTypeDescr()) { if (JSObject* descr = maybeTypeDescr()) {
TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr"); TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr");
setTypeDescr(&descr->as<TypeDescr>()); setTypeDescr(&descr->as<TypeDescr>());
@ -1436,12 +1427,6 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
if (group->maybePreliminaryObjects()) if (group->maybePreliminaryObjects())
group->maybePreliminaryObjects()->trace(this); group->maybePreliminaryObjects()->trace(this);
if (group->maybeUnboxedLayout())
group->unboxedLayout().trace(this);
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
traverseEdge(group, unboxedGroup);
if (TypeDescr* descr = group->maybeTypeDescr()) if (TypeDescr* descr = group->maybeTypeDescr())
traverseEdge(group, static_cast<JSObject*>(descr)); traverseEdge(group, static_cast<JSObject*>(descr));
@ -1484,23 +1469,6 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar
return nullptr; return nullptr;
} }
if (clasp == &UnboxedPlainObject::class_) {
JSObject** pexpando = obj->as<UnboxedPlainObject>().addressOfExpando();
if (*pexpando)
f(pexpando, mozilla::Forward<Args>(args)...);
UnboxedPlainObject& unboxed = obj->as<UnboxedPlainObject>();
const UnboxedLayout& layout = check == CheckGeneration::DoChecks
? unboxed.layout()
: unboxed.layoutDontCheckGeneration();
if (layout.traceList()) {
VisitTraceList(f, layout.traceList(), unboxed.data(),
mozilla::Forward<Args>(args)...);
}
return nullptr;
}
clasp->doTrace(trc, obj); clasp->doTrace(trc, obj);
if (!clasp->isNative()) if (!clasp->isNative())
@ -2293,18 +2261,6 @@ static inline void
TraceWholeCell(TenuringTracer& mover, JSObject* object) TraceWholeCell(TenuringTracer& mover, JSObject* object)
{ {
mover.traceObject(object); mover.traceObject(object);
// Additionally trace the expando object attached to any unboxed plain
// objects. Baseline and Ion can write properties to the expando while
// only adding a post barrier to the owning unboxed object. Note that
// it isn't possible for a nursery unboxed object to have a tenured
// expando, so that adding a post barrier on the original object will
// capture any tenured->nursery edges in the expando as well.
if (object->is<UnboxedPlainObject>()) {
if (UnboxedExpandoObject* expando = object->as<UnboxedPlainObject>().maybeExpando())
expando->traceChildren(&mover);
}
} }
static inline void static inline void

View file

@ -201,80 +201,15 @@ gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape)
} while (shape); } while (shape);
} }
// Object groups can point to other object groups via an UnboxedLayout or the
// the original unboxed group link. There can potentially be deep or cyclic
// chains of such groups to trace through without going through a thing that
// participates in cycle collection. These need to be handled iteratively to
// avoid blowing the stack when running the cycle collector's callback tracer.
struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
{
explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer)
: JS::CallbackTracer(innerTracer->runtime(), DoNotTraceWeakMaps),
innerTracer(innerTracer)
{}
void onChild(const JS::GCCellPtr& thing) override;
JS::CallbackTracer* innerTracer;
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
};
void
ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing)
{
if (thing.is<BaseShape>()) {
// The CC does not care about BaseShapes, and no additional GC things
// will be reached by following this edge.
return;
}
if (thing.is<JSObject>() || thing.is<JSScript>()) {
// Invoke the inner cycle collector callback on this child. It will not
// recurse back into TraceChildren.
innerTracer->onChild(thing);
return;
}
if (thing.is<ObjectGroup>()) {
// If this group is required to be in an ObjectGroup chain, trace it
// via the provided worklist rather than continuing to recurse.
ObjectGroup& group = thing.as<ObjectGroup>();
if (group.maybeUnboxedLayout()) {
for (size_t i = 0; i < seen.length(); i++) {
if (seen[i] == &group)
return;
}
if (seen.append(&group) && worklist.append(&group)) {
return;
} else {
// If append fails, keep tracing normally. The worst that will
// happen is we end up overrecursing.
}
}
}
TraceChildren(this, thing.asCell(), thing.kind());
}
void void
gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group) gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group)
{ {
MOZ_ASSERT(trc->isCallbackTracer()); MOZ_ASSERT(trc->isCallbackTracer());
// Early return if this group is not required to be in an ObjectGroup chain. group->traceChildren(trc);
if (!group->maybeUnboxedLayout())
return group->traceChildren(trc);
ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer());
group->traceChildren(&groupTracer);
while (!groupTracer.worklist.empty()) {
ObjectGroup* innerGroup = groupTracer.worklist.popCopy();
innerGroup->traceChildren(&groupTracer);
}
} }
/*** Traced Edge Printer *************************************************************************/ /*** Traced Edge Printer *************************************************************************/
static size_t static size_t

View file

@ -114,8 +114,6 @@ GetObject(const MDefinition* ins)
case MDefinition::Op_GuardObjectGroup: case MDefinition::Op_GuardObjectGroup:
case MDefinition::Op_GuardObjectIdentity: case MDefinition::Op_GuardObjectIdentity:
case MDefinition::Op_GuardClass: case MDefinition::Op_GuardClass:
case MDefinition::Op_GuardUnboxedExpando:
case MDefinition::Op_LoadUnboxedExpando:
case MDefinition::Op_LoadSlot: case MDefinition::Op_LoadSlot:
case MDefinition::Op_StoreSlot: case MDefinition::Op_StoreSlot:
case MDefinition::Op_InArray: case MDefinition::Op_InArray:

View file

@ -96,13 +96,8 @@ VectorAppendNoDuplicate(S& list, T value)
static bool static bool
AddReceiver(const ReceiverGuard& receiver, AddReceiver(const ReceiverGuard& receiver,
BaselineInspector::ReceiverVector& receivers, BaselineInspector::ReceiverVector& receivers)
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
{ {
if (receiver.group && receiver.group->maybeUnboxedLayout()) {
if (receiver.group->unboxedLayout().nativeGroup())
return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
}
return VectorAppendNoDuplicate(receivers, receiver); return VectorAppendNoDuplicate(receivers, receiver);
} }
@ -170,16 +165,12 @@ GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* r
} }
bool bool
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers)
ObjectGroupVector& convertUnboxedGroups)
{ {
// Return a list of the receivers seen by the baseline IC for the current // Return a list of the receivers seen by the baseline IC for the current
// op. Empty lists indicate no receivers are known, or there was an // op. Empty lists indicate no receivers are known, or there was an
// uncacheable access. convertUnboxedGroups is used for unboxed object // uncacheable access.
// groups which have been seen, but have had instances converted to native
// objects and should be eagerly converted by Ion.
MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
if (!hasBaselineScript()) if (!hasBaselineScript())
return true; return true;
@ -207,7 +198,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
return true; return true;
} }
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) if (!AddReceiver(receiver, receivers))
return false; return false;
stub = stub->next(); stub = stub->next();
@ -700,14 +691,12 @@ bool
BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonGetter, Shape** globalShape, JSFunction** commonGetter, Shape** globalShape,
bool* isOwnProperty, bool* isOwnProperty,
ReceiverVector& receivers, ReceiverVector& receivers)
ObjectGroupVector& convertUnboxedGroups)
{ {
if (!hasBaselineScript()) if (!hasBaselineScript())
return false; return false;
MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
*holder = nullptr; *holder = nullptr;
const ICEntry& entry = icEntryFromPC(pc); const ICEntry& entry = icEntryFromPC(pc);
@ -719,7 +708,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
{ {
ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub); ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub);
bool isOwn = nstub->isOwnGetter(); bool isOwn = nstub->isOwnGetter();
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
return false; return false;
if (!*holder) { if (!*holder) {
@ -751,21 +740,19 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
if (!*holder) if (!*holder)
return false; return false;
MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty())); MOZ_ASSERT(*isOwnProperty == (receivers.empty()));
return true; return true;
} }
bool bool
BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonSetter, bool* isOwnProperty, JSFunction** commonSetter, bool* isOwnProperty,
ReceiverVector& receivers, ReceiverVector& receivers)
ObjectGroupVector& convertUnboxedGroups)
{ {
if (!hasBaselineScript()) if (!hasBaselineScript())
return false; return false;
MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(receivers.empty());
MOZ_ASSERT(convertUnboxedGroups.empty());
*holder = nullptr; *holder = nullptr;
const ICEntry& entry = icEntryFromPC(pc); const ICEntry& entry = icEntryFromPC(pc);
@ -774,7 +761,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) { if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub); ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub);
bool isOwn = nstub->isOwnSetter(); bool isOwn = nstub->isOwnSetter();
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups)) if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
return false; return false;
if (!*holder) { if (!*holder) {

View file

@ -95,8 +95,7 @@ class BaselineInspector
public: public:
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector; typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector; typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers, MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers);
ObjectGroupVector& convertUnboxedGroups);
SetElemICInspector setElemICInspector(jsbytecode* pc) { SetElemICInspector setElemICInspector(jsbytecode* pc) {
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback); return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
@ -131,12 +130,10 @@ class BaselineInspector
MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonGetter, Shape** globalShape, JSFunction** commonGetter, Shape** globalShape,
bool* isOwnProperty, ReceiverVector& receivers, bool* isOwnProperty, ReceiverVector& receivers);
ObjectGroupVector& convertUnboxedGroups);
MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape, MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
JSFunction** commonSetter, bool* isOwnProperty, JSFunction** commonSetter, bool* isOwnProperty,
ReceiverVector& receivers, ReceiverVector& receivers);
ObjectGroupVector& convertUnboxedGroups);
MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot, MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
JSObject** prototypeObject); JSObject** prototypeObject);

View file

@ -3031,15 +3031,6 @@ GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard,
{ {
if (guard.group) { if (guard.group) {
masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss); masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss);
Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando());
if (guard.shape) {
masm.loadPtr(expandoAddress, scratch);
masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss);
masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss);
} else if (checkNullExpando) {
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss);
}
} else { } else {
masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss); masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss);
} }
@ -3077,13 +3068,6 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch); masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
masm.loadTypedOrValue(Address(scratch, offset), output); masm.loadTypedOrValue(Address(scratch, offset), output);
} }
} else {
masm.comment("loadUnboxedProperty");
const UnboxedLayout::Property* property =
receiver.group->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(propertyAddr, property->type, output);
} }
if (i == mir->numReceivers() - 1) { if (i == mir->numReceivers() - 1) {
@ -3124,8 +3108,6 @@ EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type)
masm.patchableCallPreBarrier(address, MIRType::Object); masm.patchableCallPreBarrier(address, MIRType::Object);
else if (type == JSVAL_TYPE_STRING) else if (type == JSVAL_TYPE_STRING)
masm.patchableCallPreBarrier(address, MIRType::String); masm.patchableCallPreBarrier(address, MIRType::String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
} }
void void
@ -3161,13 +3143,6 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
emitPreBarrier(addr); emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr); masm.storeConstantOrRegister(value, addr);
} }
} else {
const UnboxedLayout::Property* property =
receiver.group->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
EmitUnboxedPreBarrier(masm, propertyAddr, property->type);
masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
} }
if (i == mir->numReceivers() - 1) { if (i == mir->numReceivers() - 1) {
@ -3332,27 +3307,6 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
masm.bind(&done); masm.bind(&done);
} }
void
CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir)
{
Label miss;
Register obj = ToRegister(lir->object());
masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual,
Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss);
bailoutFrom(&miss, lir->snapshot());
}
void
CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->getDef(0));
masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
}
void void
CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
{ {
@ -8576,21 +8530,6 @@ static const VMFunction ConvertUnboxedArrayObjectToNativeInfo =
FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative, FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative,
"UnboxedArrayObject::convertToNative"); "UnboxedArrayObject::convertToNative");
void
CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir)
{
Register object = ToRegister(lir->getOperand(0));
OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
? ConvertUnboxedArrayObjectToNativeInfo
: ConvertUnboxedPlainObjectToNativeInfo,
lir, ArgList(object), StoreNothing());
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(lir->mir()->group()), ool->entry());
masm.bind(ool->rejoin());
}
typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue); typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue);
static const VMFunction ArrayPopDenseInfo = static const VMFunction ArrayPopDenseInfo =
FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense, "ArrayPopDense"); FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense, "ArrayPopDense");

View file

@ -148,8 +148,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir); void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir);
void visitGuardObjectIdentity(LGuardObjectIdentity* guard); void visitGuardObjectIdentity(LGuardObjectIdentity* guard);
void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir); void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
void visitTypeBarrierV(LTypeBarrierV* lir); void visitTypeBarrierV(LTypeBarrierV* lir);
void visitTypeBarrierO(LTypeBarrierO* lir); void visitTypeBarrierO(LTypeBarrierO* lir);
void visitMonitorTypes(LMonitorTypes* lir); void visitMonitorTypes(LMonitorTypes* lir);
@ -310,7 +308,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitFallibleStoreElementV(LFallibleStoreElementV* lir); void visitFallibleStoreElementV(LFallibleStoreElementV* lir);
void visitFallibleStoreElementT(LFallibleStoreElementT* lir); void visitFallibleStoreElementT(LFallibleStoreElementT* lir);
void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir); void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir);
void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir);
void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj, void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
Register elementsTemp, Register lengthTemp, TypedOrValueRegister out); Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
void visitArrayPopShiftV(LArrayPopShiftV* lir); void visitArrayPopShiftV(LArrayPopShiftV* lir);

View file

@ -3515,8 +3515,6 @@ PassthroughOperand(MDefinition* def)
return def->toConvertElementsToDoubles()->elements(); return def->toConvertElementsToDoubles()->elements();
if (def->isMaybeCopyElementsForWrite()) if (def->isMaybeCopyElementsForWrite())
return def->toMaybeCopyElementsForWrite()->object(); return def->toMaybeCopyElementsForWrite()->object();
if (def->isConvertUnboxedObjectToNative())
return def->toConvertUnboxedObjectToNative()->object();
return nullptr; return nullptr;
} }

View file

@ -32,7 +32,6 @@
#include "vm/EnvironmentObject-inl.h" #include "vm/EnvironmentObject-inl.h"
#include "vm/NativeObject-inl.h" #include "vm/NativeObject-inl.h"
#include "vm/ObjectGroup-inl.h" #include "vm/ObjectGroup-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js; using namespace js;
using namespace js::jit; using namespace js::jit;
@ -6392,7 +6391,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee)
JSObject* templateObject = inspector->getTemplateObject(pc); JSObject* templateObject = inspector->getTemplateObject(pc);
if (!templateObject) if (!templateObject)
return nullptr; return nullptr;
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>()) if (!templateObject->is<PlainObject>())
return nullptr; return nullptr;
if (templateObject->staticPrototype() != proto) if (templateObject->staticPrototype() != proto)
return nullptr; return nullptr;
@ -6429,7 +6428,7 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
JSObject* templateObject = inspector->getTemplateObject(pc); JSObject* templateObject = inspector->getTemplateObject(pc);
if (!templateObject) if (!templateObject)
return nullptr; return nullptr;
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>()) if (!templateObject->is<PlainObject>())
return nullptr; return nullptr;
Shape* shape = target->lookupPure(compartment->runtime()->names().prototype); Shape* shape = target->lookupPure(compartment->runtime()->names().prototype);
@ -7718,8 +7717,6 @@ IonBuilder::jsop_initprop(PropertyName* name)
if (templateObject->is<PlainObject>()) { if (templateObject->is<PlainObject>()) {
if (!templateObject->as<PlainObject>().containsPure(name)) if (!templateObject->as<PlainObject>().containsPure(name))
useSlowPath = true; useSlowPath = true;
} else {
MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name));
} }
} else { } else {
useSlowPath = true; useSlowPath = true;
@ -8178,8 +8175,7 @@ IonBuilder::maybeMarkEmpty(MDefinition* ins)
static bool static bool
ClassHasEffectlessLookup(const Class* clasp) ClassHasEffectlessLookup(const Class* clasp)
{ {
return (clasp == &UnboxedPlainObject::class_) || return (clasp == &UnboxedArrayObject::class_) ||
(clasp == &UnboxedArrayObject::class_) ||
IsTypedObjectClass(clasp) || IsTypedObjectClass(clasp) ||
(clasp->isNative() && !clasp->getOpsLookupProperty()); (clasp->isNative() && !clasp->getOpsLookupProperty());
} }
@ -9012,8 +9008,6 @@ IonBuilder::jsop_getelem()
} }
obj = maybeUnboxForPropertyAccess(obj); obj = maybeUnboxForPropertyAccess(obj);
if (obj->type() == MIRType::Object)
obj = convertUnboxedObjects(obj);
bool emitted = false; bool emitted = false;
@ -10137,7 +10131,7 @@ IonBuilder::jsop_setelem()
MDefinition* value = current->pop(); MDefinition* value = current->pop();
MDefinition* index = current->pop(); MDefinition* index = current->pop();
MDefinition* object = convertUnboxedObjects(current->pop()); MDefinition* object = current->pop();
trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet()); trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet());
trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet()); trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet());
@ -10972,11 +10966,8 @@ IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_
} }
// Definite slots will always be fixed slots when they are in the // Definite slots will always be fixed slots when they are in the
// allowable range for fixed slots, except for objects which were // allowable range for fixed slots.
// converted from unboxed objects and have a smaller allocation size.
size_t nfixed = NativeObject::MAX_FIXED_SLOTS; size_t nfixed = NativeObject::MAX_FIXED_SLOTS;
if (ObjectGroup* group = key->group()->maybeOriginalUnboxedGroup())
nfixed = gc::GetGCKindSlots(group->unboxedLayout().getAllocKind());
uint32_t propertySlot = property.maybeTypes()->definiteSlot(); uint32_t propertySlot = property.maybeTypes()->definiteSlot();
if (slot == UINT32_MAX) { if (slot == UINT32_MAX) {
@ -11033,8 +11024,6 @@ IonBuilder::getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, JSValu
return UINT32_MAX; return UINT32_MAX;
} }
key->watchStateChangeForUnboxedConvertedToNative(constraints());
if (offset == UINT32_MAX) { if (offset == UINT32_MAX) {
offset = property->offset; offset = property->offset;
*punboxedType = property->type; *punboxedType = property->type;
@ -11496,8 +11485,6 @@ IonBuilder::jsop_getprop(PropertyName* name)
} }
obj = maybeUnboxForPropertyAccess(obj); obj = maybeUnboxForPropertyAccess(obj);
if (obj->type() == MIRType::Object)
obj = convertUnboxedObjects(obj);
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
obj, name, types); obj, name, types);
@ -11569,11 +11556,6 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted) if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
return emitted; return emitted;
// Try to emit loads from unboxed objects.
trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed);
if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted)
return emitted;
// Try to inline a common property getter, or make a call. // Try to inline a common property getter, or make a call.
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter); trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted) if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
@ -11939,49 +11921,6 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool* emitted,
fieldPrediction, fieldTypeObj); fieldPrediction, fieldTypeObj);
} }
MDefinition*
IonBuilder::convertUnboxedObjects(MDefinition* obj)
{
// If obj might be in any particular unboxed group which should be
// converted to a native representation, perform that conversion. This does
// not guarantee the object will not have such a group afterwards, if the
// object's possible groups are not precisely known.
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject() || !types->objectOrSentinel())
return obj;
BaselineInspector::ObjectGroupVector list(alloc());
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i);
if (!key || !key->isGroup())
continue;
if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout()) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (layout->nativeGroup() && !list.append(key->group()))
oomUnsafe.crash("IonBuilder::convertUnboxedObjects");
}
}
return convertUnboxedObjects(obj, list);
}
MDefinition*
IonBuilder::convertUnboxedObjects(MDefinition* obj,
const BaselineInspector::ObjectGroupVector& list)
{
for (size_t i = 0; i < list.length(); i++) {
ObjectGroup* group = list[i];
if (TemporaryTypeSet* types = obj->resultTypeSet()) {
if (!types->hasType(TypeSet::ObjectType(group)))
continue;
}
obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group);
current->add(obj->toInstruction());
}
return obj;
}
bool bool
IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types) BarrierKind barrier, TemporaryTypeSet* types)
@ -12132,45 +12071,14 @@ IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
return load; return load;
} }
bool
IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types)
{
MOZ_ASSERT(*emitted == false);
JSValueType unboxedType;
uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
if (offset == UINT32_MAX)
return true;
if (obj->type() != MIRType::Object) {
MGuardObject* guard = MGuardObject::New(alloc(), obj);
current->add(guard);
obj = guard;
}
MInstruction* load = loadUnboxedProperty(obj, offset, unboxedType, barrier, types);
current->push(load);
if (!pushTypeBarrier(load, types, barrier))
return false;
trackOptimizationSuccess();
*emitted = true;
return true;
}
MDefinition* MDefinition*
IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
const BaselineInspector::ReceiverVector& receivers, const BaselineInspector::ReceiverVector& receivers,
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
bool isOwnProperty) bool isOwnProperty)
{ {
MOZ_ASSERT(holder); MOZ_ASSERT(holder);
MOZ_ASSERT(holderShape); MOZ_ASSERT(holderShape);
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
if (isOwnProperty) { if (isOwnProperty) {
MOZ_ASSERT(receivers.empty()); MOZ_ASSERT(receivers.empty());
return addShapeGuard(obj, holderShape, Bailout_ShapeGuard); return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
@ -12194,10 +12102,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
JSObject* foundProto = nullptr; JSObject* foundProto = nullptr;
bool isOwnProperty = false; bool isOwnProperty = false;
BaselineInspector::ReceiverVector receivers(alloc()); BaselineInspector::ReceiverVector receivers(alloc());
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter, if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter,
&globalShape, &isOwnProperty, &globalShape, &isOwnProperty, receivers))
receivers, convertUnboxedGroups))
{ {
return true; return true;
} }
@ -12213,8 +12119,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
// If type information is bad, we can still optimize the getter if we // If type information is bad, we can still optimize the getter if we
// shape guard. // shape guard.
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
receivers, convertUnboxedGroups, receivers, isOwnProperty);
isOwnProperty);
if (!obj) if (!obj)
return false; return false;
} }
@ -12381,15 +12286,12 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
MOZ_ASSERT(*emitted == false); MOZ_ASSERT(*emitted == false);
BaselineInspector::ReceiverVector receivers(alloc()); BaselineInspector::ReceiverVector receivers(alloc());
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->maybeInfoForPropertyOp(pc, receivers))
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
return false; return false;
if (!canInlinePropertyOpShapes(receivers)) if (!canInlinePropertyOpShapes(receivers))
return true; return true;
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
MIRType rvalType = types->getKnownMIRType(); MIRType rvalType = types->getKnownMIRType();
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
rvalType = MIRType::Value; rvalType = MIRType::Value;
@ -12412,45 +12314,6 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
return true; return true;
} }
if (receivers[0].shape) {
// Monomorphic load from an unboxed object expando.
spew("Inlining monomorphic unboxed expando GETPROP");
obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard);
MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj);
current->add(expando);
expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard);
Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
MOZ_ASSERT(shape);
if (!loadSlot(expando, shape, rvalType, barrier, types))
return false;
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
*emitted = true;
return true;
}
// Monomorphic load from an unboxed object.
ObjectGroup* group = receivers[0].group;
if (obj->resultTypeSet() && !obj->resultTypeSet()->hasType(TypeSet::ObjectType(group)))
return true;
obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
MInstruction* load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types);
current->push(load);
if (!pushTypeBarrier(load, types, barrier))
return false;
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
*emitted = true;
return true; return true;
} }
@ -12692,7 +12555,7 @@ bool
IonBuilder::jsop_setprop(PropertyName* name) IonBuilder::jsop_setprop(PropertyName* name)
{ {
MDefinition* value = current->pop(); MDefinition* value = current->pop();
MDefinition* obj = convertUnboxedObjects(current->pop()); MDefinition* obj = current->pop();
bool emitted = false; bool emitted = false;
startTrackingOptimizations(); startTrackingOptimizations();
@ -12725,13 +12588,6 @@ IonBuilder::jsop_setprop(PropertyName* name)
bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value, bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
/* canModify = */ true); /* canModify = */ true);
if (!forceInlineCaches()) {
// Try to emit stores to unboxed objects.
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
}
// Add post barrier if needed. The instructions above manage any post // Add post barrier if needed. The instructions above manage any post
// barriers they need directly. // barriers they need directly.
if (NeedsPostBarrier(value)) if (NeedsPostBarrier(value))
@ -12765,10 +12621,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
JSObject* foundProto = nullptr; JSObject* foundProto = nullptr;
bool isOwnProperty; bool isOwnProperty;
BaselineInspector::ReceiverVector receivers(alloc()); BaselineInspector::ReceiverVector receivers(alloc());
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter, if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter,
&isOwnProperty, &isOwnProperty, receivers))
receivers, convertUnboxedGroups))
{ {
trackOptimizationOutcome(TrackedOutcome::NoProtoFound); trackOptimizationOutcome(TrackedOutcome::NoProtoFound);
return true; return true;
@ -12783,8 +12637,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
// If type information is bad, we can still optimize the setter if we // If type information is bad, we can still optimize the setter if we
// shape guard. // shape guard.
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
receivers, convertUnboxedGroups, receivers, isOwnProperty);
isOwnProperty);
if (!obj) if (!obj)
return false; return false;
} }
@ -13099,40 +12952,6 @@ IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t e
return store; return store;
} }
bool
IonBuilder::setPropTryUnboxed(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes)
{
MOZ_ASSERT(*emitted == false);
if (barrier) {
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
return true;
}
JSValueType unboxedType;
uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
if (offset == UINT32_MAX)
return true;
if (obj->type() != MIRType::Object) {
MGuardObject* guard = MGuardObject::New(alloc(), obj);
current->add(guard);
obj = guard;
}
MInstruction* store = storeUnboxedProperty(obj, offset, unboxedType, value);
current->push(value);
if (!resumeAfter(store))
return false;
*emitted = true;
return true;
}
bool bool
IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj, IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value, PropertyName* name, MDefinition* value,
@ -13146,15 +12965,12 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
} }
BaselineInspector::ReceiverVector receivers(alloc()); BaselineInspector::ReceiverVector receivers(alloc());
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc()); if (!inspector->maybeInfoForPropertyOp(pc, receivers))
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
return false; return false;
if (!canInlinePropertyOpShapes(receivers)) if (!canInlinePropertyOpShapes(receivers))
return true; return true;
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
if (receivers.length() == 1) { if (receivers.length() == 1) {
if (!receivers[0].group) { if (!receivers[0].group) {
// Monomorphic store to a native object. // Monomorphic store to a native object.
@ -13174,46 +12990,6 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
return true; return true;
} }
if (receivers[0].shape) {
// Monomorphic store to an unboxed object expando.
spew("Inlining monomorphic unboxed expando SETPROP");
obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
obj = addUnboxedExpandoGuard(obj, /* hasExpando = */ true, Bailout_ShapeGuard);
MInstruction* expando = MLoadUnboxedExpando::New(alloc(), obj);
current->add(expando);
expando = addShapeGuard(expando, receivers[0].shape, Bailout_ShapeGuard);
Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
MOZ_ASSERT(shape);
bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name));
if (!storeSlot(expando, shape, value, needsBarrier))
return false;
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
*emitted = true;
return true;
}
// Monomorphic store to an unboxed object.
spew("Inlining monomorphic unboxed SETPROP");
ObjectGroup* group = receivers[0].group;
if (!objTypes->hasType(TypeSet::ObjectType(group)))
return true;
obj = addGroupGuard(obj, group, Bailout_ShapeGuard);
const UnboxedLayout::Property* property = group->unboxedLayout().lookup(name);
storeUnboxedProperty(obj, property->offset, property->type, value);
current->push(value);
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
*emitted = true;
return true; return true;
} }
@ -13884,7 +13660,7 @@ IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec)
bool bool
IonBuilder::jsop_in() IonBuilder::jsop_in()
{ {
MDefinition* obj = convertUnboxedObjects(current->pop()); MDefinition* obj = current->pop();
MDefinition* id = current->pop(); MDefinition* id = current->pop();
bool emitted = false; bool emitted = false;
@ -14240,19 +14016,6 @@ IonBuilder::addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bail
return guard; return guard;
} }
MInstruction*
IonBuilder::addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind)
{
MGuardUnboxedExpando* guard = MGuardUnboxedExpando::New(alloc(), obj, hasExpando, bailoutKind);
current->add(guard);
// If a shape guard failed in the past, don't optimize group guards.
if (failedShapeGuard_)
guard->setNotMovable();
return guard;
}
MInstruction* MInstruction*
IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj, IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj,
const BaselineInspector::ReceiverVector& receivers) const BaselineInspector::ReceiverVector& receivers)
@ -14262,15 +14025,6 @@ IonBuilder::addGuardReceiverPolymorphic(MDefinition* obj,
// Monomorphic guard on a native object. // Monomorphic guard on a native object.
return addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard); return addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard);
} }
if (!receivers[0].shape) {
// Guard on an unboxed object that does not have an expando.
obj = addGroupGuard(obj, receivers[0].group, Bailout_ShapeGuard);
return addUnboxedExpandoGuard(obj, /* hasExpando = */ false, Bailout_ShapeGuard);
}
// Monomorphic receiver guards are not yet supported when the receiver
// is an unboxed object with an expando.
} }
MGuardReceiverPolymorphic* guard = MGuardReceiverPolymorphic::New(alloc(), obj); MGuardReceiverPolymorphic* guard = MGuardReceiverPolymorphic::New(alloc(), obj);

View file

@ -401,7 +401,6 @@ class IonBuilder
MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind); MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind); MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
MInstruction* addSharedTypedArrayGuard(MDefinition* obj); MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
MInstruction* MInstruction*
@ -441,8 +440,6 @@ class IonBuilder
BarrierKind barrier, TemporaryTypeSet* types); BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name, MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types); BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
BarrierKind barrier, TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name, MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
TemporaryTypeSet* types); TemporaryTypeSet* types);
MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
@ -475,9 +472,6 @@ class IonBuilder
MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value, PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes); bool barrier, TemporaryTypeSet* objTypes);
MOZ_MUST_USE bool setPropTryUnboxed(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes);
MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj, MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value, PropertyName* name, MDefinition* value,
bool barrier, TemporaryTypeSet* objTypes); bool barrier, TemporaryTypeSet* objTypes);
@ -1041,7 +1035,6 @@ class IonBuilder
MDefinition* MDefinition*
addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
const BaselineInspector::ReceiverVector& receivers, const BaselineInspector::ReceiverVector& receivers,
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
bool isOwnProperty); bool isOwnProperty);
MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name, MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
@ -1059,9 +1052,6 @@ class IonBuilder
ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id); ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed); uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);
MDefinition* convertUnboxedObjects(MDefinition* obj,
const BaselineInspector::ObjectGroupVector& list);
uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name, uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
JSValueType* punboxedType); JSValueType* punboxedType);
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,

View file

@ -3251,14 +3251,6 @@ LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins)
add(lir, ins); add(lir, ins);
} }
void
LIRGenerator::visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins)
{
LInstruction* check = new(alloc()) LConvertUnboxedObjectToNative(useRegister(ins->object()));
add(check, ins);
assignSafepoint(check, ins);
}
void void
LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins)
{ {
@ -3776,24 +3768,6 @@ LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins)
redefine(ins, ins->object()); redefine(ins, ins->object());
} }
void
LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins)
{
LGuardUnboxedExpando* guard =
new(alloc()) LGuardUnboxedExpando(useRegister(ins->object()));
assignSnapshot(guard, ins->bailoutKind());
add(guard, ins);
redefine(ins, ins->object());
}
void
LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins)
{
LLoadUnboxedExpando* lir =
new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object()));
define(lir, ins);
}
void void
LIRGenerator::visitAssertRange(MAssertRange* ins) LIRGenerator::visitAssertRange(MAssertRange* ins)
{ {

View file

@ -232,7 +232,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitFallibleStoreElement(MFallibleStoreElement* ins); void visitFallibleStoreElement(MFallibleStoreElement* ins);
void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins); void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
void visitStoreUnboxedString(MStoreUnboxedString* ins); void visitStoreUnboxedString(MStoreUnboxedString* ins);
void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins);
void visitEffectiveAddress(MEffectiveAddress* ins); void visitEffectiveAddress(MEffectiveAddress* ins);
void visitArrayPopShift(MArrayPopShift* ins); void visitArrayPopShift(MArrayPopShift* ins);
void visitArrayPush(MArrayPush* ins); void visitArrayPush(MArrayPush* ins);
@ -256,8 +255,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitGuardObject(MGuardObject* ins); void visitGuardObject(MGuardObject* ins);
void visitGuardString(MGuardString* ins); void visitGuardString(MGuardString* ins);
void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins); void visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins);
void visitGuardUnboxedExpando(MGuardUnboxedExpando* ins);
void visitLoadUnboxedExpando(MLoadUnboxedExpando* ins);
void visitPolyInlineGuard(MPolyInlineGuard* ins); void visitPolyInlineGuard(MPolyInlineGuard* ins);
void visitAssertRange(MAssertRange* ins); void visitAssertRange(MAssertRange* ins);
void visitCallGetProperty(MCallGetProperty* ins); void visitCallGetProperty(MCallGetProperty* ins);

View file

@ -615,7 +615,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
OBJECT_FLAG_LENGTH_OVERFLOW | OBJECT_FLAG_LENGTH_OVERFLOW |
OBJECT_FLAG_ITERATED; OBJECT_FLAG_ITERATED;
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); MDefinition* obj = callInfo.thisArg();
TemporaryTypeSet* thisTypes = obj->resultTypeSet(); TemporaryTypeSet* thisTypes = obj->resultTypeSet();
if (!thisTypes) if (!thisTypes)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
@ -743,7 +743,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
} }
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); MDefinition* obj = callInfo.thisArg();
MDefinition* value = callInfo.getArg(0); MDefinition* value = callInfo.getArg(0);
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&obj, nullptr, &value, /* canModify = */ false)) &obj, nullptr, &value, /* canModify = */ false))
@ -822,7 +822,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
} }
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); MDefinition* obj = callInfo.thisArg();
// Ensure |this| and result are objects. // Ensure |this| and result are objects.
if (getInlineReturnType() != MIRType::Object) if (getInlineReturnType() != MIRType::Object)
@ -2152,7 +2152,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
if (callInfo.argc() != 3) if (callInfo.argc() != 3)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0)); MDefinition* obj = callInfo.getArg(0);
MDefinition* id = callInfo.getArg(1); MDefinition* id = callInfo.getArg(1);
MDefinition* value = callInfo.getArg(2); MDefinition* value = callInfo.getArg(2);

View file

@ -4810,35 +4810,8 @@ MBeta::printOpcode(GenericPrinter& out) const
bool bool
MCreateThisWithTemplate::canRecoverOnBailout() const MCreateThisWithTemplate::canRecoverOnBailout() const
{ {
MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>()); MOZ_ASSERT(templateObject()->is<PlainObject>());
MOZ_ASSERT_IF(templateObject()->is<PlainObject>(), MOZ_ASSERT(!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
return true;
}
bool
OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
{
const UnboxedLayout& layout =
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
const UnboxedLayout::PropertyVector& properties = layout.properties();
MOZ_ASSERT(properties.length() < 255);
// Allocate an array of indexes, where the top of each field correspond to
// the index of the operand in the MObjectState instance.
if (!map.init(alloc, layout.size()))
return false;
// Reset all indexes to 0, which is an error code.
for (size_t i = 0; i < map.length(); i++)
map[i] = 0;
// Map the property offsets to the indexes of MObjectState operands.
uint8_t index = 1;
for (size_t i = 0; i < properties.length(); i++, index++)
map[properties[i].offset] = index;
return true; return true;
} }
@ -4858,17 +4831,11 @@ MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandInd
setResultType(MIRType::Object); setResultType(MIRType::Object);
setRecoveredOnBailout(); setRecoveredOnBailout();
if (templateObject->is<NativeObject>()) { MOZ_ASSERT(templateObject->is<NativeObject>());
NativeObject* nativeObject = &templateObject->as<NativeObject>(); NativeObject* nativeObject = &templateObject->as<NativeObject>();
numSlots_ = nativeObject->slotSpan(); numSlots_ = nativeObject->slotSpan();
numFixedSlots_ = nativeObject->numFixedSlots(); numFixedSlots_ = nativeObject->numFixedSlots();
} else {
const UnboxedLayout& layout =
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
// Same as UnboxedLayout::makeNativeGroup
numSlots_ = layout.properties().length();
numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind());
}
operandIndex_ = operandIndex; operandIndex_ = operandIndex;
} }
@ -4905,27 +4872,10 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine
// the template object. This is needed to account values which are baked in // the template object. This is needed to account values which are baked in
// the template objects and not visible in IonMonkey, such as the // the template objects and not visible in IonMonkey, such as the
// uninitialized-lexical magic value of call objects. // uninitialized-lexical magic value of call objects.
if (templateObject->is<UnboxedPlainObject>()) {
UnboxedPlainObject& unboxedObject = templateObject->as<UnboxedPlainObject>();
const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration();
const UnboxedLayout::PropertyVector& properties = layout.properties();
for (size_t i = 0; i < properties.length(); i++) {
Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true);
MDefinition *def = undefinedVal;
if (!val.isUndefined()) {
MConstant* ins = val.isObject() ?
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
MConstant::New(alloc, val);
block()->insertBefore(this, ins);
def = ins;
}
initSlot(i, def);
}
} else {
NativeObject& nativeObject = templateObject->as<NativeObject>(); NativeObject& nativeObject = templateObject->as<NativeObject>();
MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
MOZ_ASSERT(templateObject->is<NativeObject>());
for (size_t i = 0; i < numSlots(); i++) { for (size_t i = 0; i < numSlots(); i++) {
Value val = nativeObject.getSlot(i); Value val = nativeObject.getSlot(i);
MDefinition *def = undefinedVal; MDefinition *def = undefinedVal;
@ -4938,7 +4888,6 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine
} }
initSlot(i, def); initSlot(i, def);
} }
}
return true; return true;
} }
@ -4948,14 +4897,7 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj)
JSObject* templateObject = templateObjectOf(obj); JSObject* templateObject = templateObjectOf(obj);
MOZ_ASSERT(templateObject, "Unexpected object creation."); MOZ_ASSERT(templateObject, "Unexpected object creation.");
OperandIndexMap* operandIndex = nullptr; MObjectState* res = new(alloc) MObjectState(templateObject, nullptr);
if (templateObject->is<UnboxedPlainObject>()) {
operandIndex = new(alloc) OperandIndexMap;
if (!operandIndex || !operandIndex->init(alloc, templateObject))
return nullptr;
}
MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
if (!res || !res->init(alloc, obj)) if (!res || !res->init(alloc, obj))
return nullptr; return nullptr;
return res; return res;
@ -5862,35 +5804,6 @@ MGetFirstDollarIndex::foldsTo(TempAllocator& alloc)
return MConstant::New(alloc, Int32Value(index)); return MConstant::New(alloc, Int32Value(index));
} }
MConvertUnboxedObjectToNative*
MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
{
MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group);
ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup();
// Make a new type set for the result of this instruction which replaces
// the input group with the native group we will convert it to.
TemporaryTypeSet* types = obj->resultTypeSet();
if (types && !types->unknownObject()) {
TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc());
if (newTypes) {
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
if (key->unknownProperties() || !key->isGroup() || key->group() != group)
newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc());
else
newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc());
}
res->setResultTypeSet(newTypes);
}
}
return res;
}
bool bool
jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id) MDefinition* obj, MDefinition* id)
@ -5945,8 +5858,6 @@ jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* o
elementType = layout.elementType(); elementType = layout.elementType();
else else
return JSVAL_TYPE_MAGIC; return JSVAL_TYPE_MAGIC;
key->watchStateChangeForUnboxedConvertedToNative(constraints);
} }
return elementType; return elementType;
@ -6581,23 +6492,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
} }
} }
// Perform additional filtering to make sure that any unboxed property
// being written can accommodate the value.
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) {
const UnboxedLayout& layout = key->group()->unboxedLayout();
if (name) {
const UnboxedLayout::Property* property = layout.lookup(name);
if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
return true;
} else {
if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
return true;
}
}
}
if (success) if (success)
return false; return false;
@ -6631,17 +6525,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
MOZ_ASSERT(excluded); MOZ_ASSERT(excluded);
// If the excluded object is a group with an unboxed layout, make sure it
// does not have a corresponding native group. Objects with the native
// group might appear even though they are not in the type set.
if (excluded->isGroup()) {
if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) {
if (layout->nativeGroup())
return true;
excluded->watchStateChangeForUnboxedConvertedToNative(constraints);
}
}
*pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true); *pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
return false; return false;
} }

View file

@ -30,7 +30,6 @@
#include "vm/EnvironmentObject.h" #include "vm/EnvironmentObject.h"
#include "vm/SharedMem.h" #include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h" #include "vm/TypedArrayCommon.h"
#include "vm/UnboxedObject.h"
// Undo windows.h damage on Win64 // Undo windows.h damage on Win64
#undef MemoryBarrier #undef MemoryBarrier
@ -9742,59 +9741,6 @@ class MStoreUnboxedString
ALLOW_CLONE(MStoreUnboxedString) ALLOW_CLONE(MStoreUnboxedString)
}; };
// Passes through an object, after ensuring it is converted from an unboxed
// object to a native representation.
class MConvertUnboxedObjectToNative
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
CompilerObjectGroup group_;
explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
: MUnaryInstruction(obj),
group_(group)
{
setGuard();
setMovable();
setResultType(MIRType::Object);
}
public:
INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
NAMED_OPERANDS((0, object))
static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
ObjectGroup* group);
ObjectGroup* group() const {
return group_;
}
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
return ins->toConvertUnboxedObjectToNative()->group() == group();
}
AliasSet getAliasSet() const override {
// This instruction can read and write to all parts of the object, but
// is marked as non-effectful so it can be consolidated by LICM and GVN
// and avoid inhibiting other optimizations.
//
// This is valid to do because when unboxed objects might have a native
// group they can be converted to, we do not optimize accesses to the
// unboxed objects and do not guard on their group or shape (other than
// in this opcode).
//
// Later accesses can assume the object has a native representation
// and optimize accordingly. Those accesses cannot be reordered before
// this instruction, however. This is prevented by chaining this
// instruction with the object itself, in the same way as MBoundsCheck.
return AliasSet::None();
}
bool appendRoots(MRootList& roots) const override {
return roots.append(group_);
}
};
// Array.prototype.pop or Array.prototype.shift on a dense array. // Array.prototype.pop or Array.prototype.shift on a dense array.
class MArrayPopShift class MArrayPopShift
: public MUnaryInstruction, : public MUnaryInstruction,
@ -11174,11 +11120,6 @@ class MGuardShape
setMovable(); setMovable();
setResultType(MIRType::Object); setResultType(MIRType::Object);
setResultTypeSet(obj->resultTypeSet()); setResultTypeSet(obj->resultTypeSet());
// Disallow guarding on unboxed object shapes. The group is better to
// guard on, and guarding on the shape can interact badly with
// MConvertUnboxedObjectToNative.
MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
} }
public: public:
@ -11273,11 +11214,6 @@ class MGuardObjectGroup
setGuard(); setGuard();
setMovable(); setMovable();
setResultType(MIRType::Object); setResultType(MIRType::Object);
// Unboxed groups which might be converted to natives can't be guarded
// on, due to MConvertUnboxedObjectToNative.
MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
!group->unboxedLayoutDontCheckGeneration().nativeGroup());
} }
public: public:
@ -11386,73 +11322,6 @@ class MGuardClass
ALLOW_CLONE(MGuardClass) ALLOW_CLONE(MGuardClass)
}; };
// Guard on the presence or absence of an unboxed object's expando.
class MGuardUnboxedExpando
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
bool requireExpando_;
BailoutKind bailoutKind_;
MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
: MUnaryInstruction(obj),
requireExpando_(requireExpando),
bailoutKind_(bailoutKind)
{
setGuard();
setMovable();
setResultType(MIRType::Object);
}
public:
INSTRUCTION_HEADER(GuardUnboxedExpando)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool requireExpando() const {
return requireExpando_;
}
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool congruentTo(const MDefinition* ins) const override {
if (!congruentIfOperandsEqual(ins))
return false;
if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
return false;
return true;
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Load an unboxed plain object's expando.
class MLoadUnboxedExpando
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
private:
explicit MLoadUnboxedExpando(MDefinition* object)
: MUnaryInstruction(object)
{
setResultType(MIRType::Object);
setMovable();
}
public:
INSTRUCTION_HEADER(LoadUnboxedExpando)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object))
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Load from vp[slot] (slots that are not inline in an object). // Load from vp[slot] (slots that are not inline in an object).
class MLoadSlot class MLoadSlot
: public MUnaryInstruction, : public MUnaryInstruction,

View file

@ -187,8 +187,6 @@ namespace jit {
_(GuardObjectGroup) \ _(GuardObjectGroup) \
_(GuardObjectIdentity) \ _(GuardObjectIdentity) \
_(GuardClass) \ _(GuardClass) \
_(GuardUnboxedExpando) \
_(LoadUnboxedExpando) \
_(ArrayLength) \ _(ArrayLength) \
_(SetArrayLength) \ _(SetArrayLength) \
_(GetNextEntryForIterator) \ _(GetNextEntryForIterator) \
@ -219,7 +217,6 @@ namespace jit {
_(StoreUnboxedScalar) \ _(StoreUnboxedScalar) \
_(StoreUnboxedObjectOrNull) \ _(StoreUnboxedObjectOrNull) \
_(StoreUnboxedString) \ _(StoreUnboxedString) \
_(ConvertUnboxedObjectToNative) \
_(ArrayPopShift) \ _(ArrayPopShift) \
_(ArrayPush) \ _(ArrayPush) \
_(ArraySlice) \ _(ArraySlice) \

View file

@ -15,9 +15,11 @@
#include "jit/JitcodeMap.h" #include "jit/JitcodeMap.h"
#include "jit/JitSpewer.h" #include "jit/JitSpewer.h"
#include "js/TrackedOptimizationInfo.h" #include "js/TrackedOptimizationInfo.h"
#include "vm/UnboxedObject.h"
#include "vm/ObjectGroup-inl.h" #include "vm/ObjectGroup-inl.h"
#include "vm/TypeInference-inl.h" #include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js; using namespace js;
using namespace js::jit; using namespace js::jit;

View file

@ -13,7 +13,6 @@
#include "jit/MIR.h" #include "jit/MIR.h"
#include "jit/MIRGenerator.h" #include "jit/MIRGenerator.h"
#include "jit/MIRGraph.h" #include "jit/MIRGraph.h"
#include "vm/UnboxedObject.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
@ -183,25 +182,6 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
JitSpewDef(JitSpew_Escape, "is escaped by\n", def); JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
return true; return true;
case MDefinition::Op_LoadUnboxedScalar:
case MDefinition::Op_StoreUnboxedScalar:
case MDefinition::Op_LoadUnboxedObjectOrNull:
case MDefinition::Op_StoreUnboxedObjectOrNull:
case MDefinition::Op_LoadUnboxedString:
case MDefinition::Op_StoreUnboxedString:
// Not escaped if it is the first argument.
if (def->indexOf(*i) != 0) {
JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
return true;
}
if (!def->getOperand(1)->isConstant()) {
JitSpewDef(JitSpew_Escape, "is addressed with unknown index\n", def);
return true;
}
break;
case MDefinition::Op_PostWriteBarrier: case MDefinition::Op_PostWriteBarrier:
break; break;
@ -305,12 +285,6 @@ class ObjectMemoryView : public MDefinitionVisitorDefaultNoop
void visitGuardShape(MGuardShape* ins); void visitGuardShape(MGuardShape* ins);
void visitFunctionEnvironment(MFunctionEnvironment* ins); void visitFunctionEnvironment(MFunctionEnvironment* ins);
void visitLambda(MLambda* ins); void visitLambda(MLambda* ins);
void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
void visitStoreUnboxedString(MStoreUnboxedString* ins);
void visitLoadUnboxedString(MLoadUnboxedString* ins);
private: private:
void storeOffset(MInstruction* ins, size_t offset, MDefinition* value); void storeOffset(MInstruction* ins, size_t offset, MDefinition* value);
@ -656,21 +630,6 @@ ObjectMemoryView::visitLambda(MLambda* ins)
ins->setIncompleteObject(); ins->setIncompleteObject();
} }
static size_t
GetOffsetOf(MDefinition* index, size_t width, int32_t baseOffset)
{
int32_t idx = index->toConstant()->toInt32();
MOZ_ASSERT(idx >= 0);
MOZ_ASSERT(baseOffset >= 0 && size_t(baseOffset) >= UnboxedPlainObject::offsetOfData());
return idx * width + baseOffset - UnboxedPlainObject::offsetOfData();
}
static size_t
GetOffsetOf(MDefinition* index, Scalar::Type type, int32_t baseOffset)
{
return GetOffsetOf(index, Scalar::byteSize(type), baseOffset);
}
void void
ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value) ObjectMemoryView::storeOffset(MInstruction* ins, size_t offset, MDefinition* value)
{ {
@ -700,77 +659,6 @@ ObjectMemoryView::loadOffset(MInstruction* ins, size_t offset)
ins->block()->discard(ins); ins->block()->discard(ins);
} }
void
ObjectMemoryView::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
loadOffset(ins, offset);
}
void
ObjectMemoryView::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
// Clone the state and update the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
loadOffset(ins, offset);
}
void
ObjectMemoryView::visitStoreUnboxedString(MStoreUnboxedString* ins)
{
// Skip stores made on other objects.
if (ins->elements() != obj_)
return;
// Clone the state and update the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
storeOffset(ins, offset, ins->value());
}
void
ObjectMemoryView::visitLoadUnboxedString(MLoadUnboxedString* ins)
{
// Skip loads made on other objects.
if (ins->elements() != obj_)
return;
// Replace load by the slot value.
size_t offset = GetOffsetOf(ins->index(), sizeof(uintptr_t), ins->offsetAdjustment());
loadOffset(ins, offset);
}
static bool static bool
IndexOf(MDefinition* ins, int32_t* res) IndexOf(MDefinition* ins, int32_t* res)
{ {

View file

@ -27,6 +27,7 @@
#endif #endif
#include "jit/VMFunctions.h" #include "jit/VMFunctions.h"
#include "vm/Interpreter.h" #include "vm/Interpreter.h"
#include "vm/NativeObject-inl.h"
#include "jit/MacroAssembler-inl.h" #include "jit/MacroAssembler-inl.h"
#include "vm/Interpreter-inl.h" #include "vm/Interpreter-inl.h"

View file

@ -5891,22 +5891,6 @@ class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
} }
}; };
// If necessary, convert an unboxed object in a particular group to its native
// representation.
class LConvertUnboxedObjectToNative : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(ConvertUnboxedObjectToNative)
explicit LConvertUnboxedObjectToNative(const LAllocation& object) {
setOperand(0, object);
}
MConvertUnboxedObjectToNative* mir() {
return mir_->toConvertUnboxedObjectToNative();
}
};
class LArrayPopShiftV : public LInstructionHelper<BOX_PIECES, 1, 2> class LArrayPopShiftV : public LInstructionHelper<BOX_PIECES, 1, 2>
{ {
public: public:
@ -7429,38 +7413,6 @@ class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1>
} }
}; };
class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(GuardUnboxedExpando)
explicit LGuardUnboxedExpando(const LAllocation& in) {
setOperand(0, in);
}
const LAllocation* object() {
return getOperand(0);
}
const MGuardUnboxedExpando* mir() const {
return mir_->toGuardUnboxedExpando();
}
};
class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(LoadUnboxedExpando)
explicit LLoadUnboxedExpando(const LAllocation& in) {
setOperand(0, in);
}
const LAllocation* object() {
return getOperand(0);
}
const MLoadUnboxedExpando* mir() const {
return mir_->toLoadUnboxedExpando();
}
};
// Guard that a value is in a TypeSet. // Guard that a value is in a TypeSet.
class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1> class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
{ {

View file

@ -258,8 +258,6 @@
_(GuardObjectGroup) \ _(GuardObjectGroup) \
_(GuardObjectIdentity) \ _(GuardObjectIdentity) \
_(GuardClass) \ _(GuardClass) \
_(GuardUnboxedExpando) \
_(LoadUnboxedExpando) \
_(TypeBarrierV) \ _(TypeBarrierV) \
_(TypeBarrierO) \ _(TypeBarrierO) \
_(MonitorTypes) \ _(MonitorTypes) \
@ -287,7 +285,6 @@
_(StoreElementT) \ _(StoreElementT) \
_(StoreUnboxedScalar) \ _(StoreUnboxedScalar) \
_(StoreUnboxedPointer) \ _(StoreUnboxedPointer) \
_(ConvertUnboxedObjectToNative) \
_(ArrayPopShiftV) \ _(ArrayPopShiftV) \
_(ArrayPopShiftT) \ _(ArrayPopShiftT) \
_(ArrayPushV) \ _(ArrayPushV) \

View file

@ -6434,9 +6434,6 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
} }
jit::JitOptions.jumpThreshold = value; jit::JitOptions.jumpThreshold = value;
break; break;
case JSJITCOMPILER_UNBOXED_OBJECTS:
jit::JitOptions.disableUnboxedObjects = !value;
break;
case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE: case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
jit::JitOptions.asmJSAtomicsEnable = !!value; jit::JitOptions.asmJSAtomicsEnable = !!value;
break; break;

View file

@ -5794,7 +5794,6 @@ JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
Register(BASELINE_ENABLE, "baseline.enable") \ Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(JUMP_THRESHOLD, "jump-threshold") \ Register(JUMP_THRESHOLD, "jump-threshold") \
Register(UNBOXED_OBJECTS, "unboxed_objects") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
Register(WASM_TEST_MODE, "wasm.test-mode") \ Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")

View file

@ -3169,6 +3169,11 @@ static const JSFunctionSpec array_methods[] = {
/* ES7 additions */ /* ES7 additions */
JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0), JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0),
/* ES2019 additions */
JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0,0),
JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0),
JS_FS_END JS_FS_END
}; };
@ -3333,6 +3338,8 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
!DefineProperty(cx, unscopables, cx->names().fill, value) || !DefineProperty(cx, unscopables, cx->names().fill, value) ||
!DefineProperty(cx, unscopables, cx->names().find, value) || !DefineProperty(cx, unscopables, cx->names().find, value) ||
!DefineProperty(cx, unscopables, cx->names().findIndex, value) || !DefineProperty(cx, unscopables, cx->names().findIndex, value) ||
!DefineProperty(cx, unscopables, cx->names().flat, value) ||
!DefineProperty(cx, unscopables, cx->names().flatMap, value) ||
!DefineProperty(cx, unscopables, cx->names().includes, value) || !DefineProperty(cx, unscopables, cx->names().includes, value) ||
!DefineProperty(cx, unscopables, cx->names().keys, value) || !DefineProperty(cx, unscopables, cx->names().keys, value) ||
!DefineProperty(cx, unscopables, cx->names().values, value)) !DefineProperty(cx, unscopables, cx->names().values, value))

View file

@ -6190,12 +6190,6 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
for (auto group = source->zone()->cellIter<ObjectGroup>(); !group.done(); group.next()) { for (auto group = source->zone()->cellIter<ObjectGroup>(); !group.done(); group.next()) {
group->setGeneration(target->zone()->types.generation); group->setGeneration(target->zone()->types.generation);
group->compartment_ = target; group->compartment_ = target;
// Remove any unboxed layouts from the list in the off thread
// compartment. These do not need to be reinserted in the target
// compartment's list, as the list is not required to be complete.
if (UnboxedLayout* layout = group->maybeUnboxedLayoutDontCheckGeneration())
layout->detachFromCompartment();
} }
// Fixup zone pointers in source's zone to refer to target's zone. // Fixup zone pointers in source's zone to refer to target's zone.

View file

@ -157,8 +157,11 @@ SortComparatorIntegerIds(jsid a, jsid b, bool* lessOrEqualp)
} }
static bool static bool
EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags, Maybe<IdSet>& ht, EnumerateNativeProperties(JSContext* cx,
AutoIdVector* props, Handle<UnboxedPlainObject*> unboxed = nullptr) HandleNativeObject pobj,
unsigned flags,
Maybe<IdSet>& ht,
AutoIdVector* props)
{ {
bool enumerateSymbols; bool enumerateSymbols;
if (flags & JSITER_SYMBOLSONLY) { if (flags & JSITER_SYMBOLSONLY) {
@ -220,16 +223,6 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags
return false; return false;
} }
if (unboxed) {
// If |unboxed| is set then |pobj| is the expando for an unboxed
// plain object we are enumerating. Add the unboxed properties
// themselves here since they are all property names that were
// given to the object before any of the expando's properties.
MOZ_ASSERT(pobj->is<UnboxedExpandoObject>());
if (!EnumerateExtraProperties(cx, unboxed, flags, ht, props))
return false;
}
size_t initialLength = props->length(); size_t initialLength = props->length();
/* Collect all unique property names from this object's shape. */ /* Collect all unique property names from this object's shape. */
@ -355,15 +348,6 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props)
do { do {
if (pobj->getOpsEnumerate()) { if (pobj->getOpsEnumerate()) {
if (pobj->is<UnboxedPlainObject>() && pobj->as<UnboxedPlainObject>().maybeExpando()) {
// Special case unboxed objects with an expando object.
RootedNativeObject expando(cx, pobj->as<UnboxedPlainObject>().maybeExpando());
if (!EnumerateNativeProperties(cx, expando, flags, ht, props,
pobj.as<UnboxedPlainObject>()))
{
return false;
}
} else {
if (!EnumerateExtraProperties(cx, pobj, flags, ht, props)) if (!EnumerateExtraProperties(cx, pobj, flags, ht, props))
return false; return false;
@ -371,7 +355,6 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props)
if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props)) if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
return false; return false;
} }
}
} else if (pobj->isNative()) { } else if (pobj->isNative()) {
// Give the object a chance to resolve all lazy properties // Give the object a chance to resolve all lazy properties
if (JSEnumerateOp enumerate = pobj->getClass()->getEnumerate()) { if (JSEnumerateOp enumerate = pobj->getClass()->getEnumerate()) {
@ -785,11 +768,6 @@ CanCompareIterableObjectToCache(JSObject* obj)
{ {
if (obj->isNative()) if (obj->isNative())
return obj->as<NativeObject>().hasEmptyElements(); return obj->as<NativeObject>().hasEmptyElements();
if (obj->is<UnboxedPlainObject>()) {
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
return expando->hasEmptyElements();
return true;
}
return false; return false;
} }

View file

@ -54,6 +54,7 @@
#include "vm/RegExpStaticsObject.h" #include "vm/RegExpStaticsObject.h"
#include "vm/Shape.h" #include "vm/Shape.h"
#include "vm/TypedArrayCommon.h" #include "vm/TypedArrayCommon.h"
#include "vm/UnboxedObject-inl.h"
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jsboolinlines.h" #include "jsboolinlines.h"
@ -869,9 +870,6 @@ static inline JSObject*
CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
NewObjectKind newKind) NewObjectKind newKind)
{ {
if (group->maybeUnboxedLayout() && newKind != SingletonObject)
return UnboxedPlainObject::create(cx, group, newKind);
if (TypeNewScript* newScript = group->newScript()) { if (TypeNewScript* newScript = group->newScript()) {
if (newScript->analyzed()) { if (newScript->analyzed()) {
// The definite properties analysis has been performed for this // The definite properties analysis has been performed for this
@ -1166,7 +1164,7 @@ static bool
GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj, GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj,
MutableHandle<IdValueVector> properties) MutableHandle<IdValueVector> properties)
{ {
if (obj->is<PlainObject>()) { MOZ_ASSERT(obj->is<PlainObject>());
PlainObject* nobj = &obj->as<PlainObject>(); PlainObject* nobj = &obj->as<PlainObject>();
if (!properties.appendN(IdValuePair(), nobj->slotSpan())) if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
@ -1189,25 +1187,6 @@ GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj,
return true; return true;
} }
if (obj->is<UnboxedPlainObject>()) {
UnboxedPlainObject* nobj = &obj->as<UnboxedPlainObject>();
const UnboxedLayout& layout = nobj->layout();
if (!properties.appendN(IdValuePair(), layout.properties().length()))
return false;
for (size_t i = 0; i < layout.properties().length(); i++) {
const UnboxedLayout::Property& property = layout.properties()[i];
properties[i].get().id = NameToId(property.name);
properties[i].get().value = nobj->getValue(property);
}
return true;
}
MOZ_CRASH("Bad object kind");
}
static bool static bool
DeepCloneValue(JSContext* cx, Value* vp, NewObjectKind newKind) DeepCloneValue(JSContext* cx, Value* vp, NewObjectKind newKind)
{ {
@ -1227,8 +1206,9 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin
/* NB: Keep this in sync with XDRObjectLiteral. */ /* NB: Keep this in sync with XDRObjectLiteral. */
MOZ_ASSERT_IF(obj->isSingleton(), MOZ_ASSERT_IF(obj->isSingleton(),
cx->compartment()->behaviors().getSingletonsAsTemplates()); cx->compartment()->behaviors().getSingletonsAsTemplates());
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() || MOZ_ASSERT(obj->is<PlainObject>() ||
obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()); obj->is<ArrayObject>() ||
obj->is<UnboxedArrayObject>());
MOZ_ASSERT(newKind != SingletonObject); MOZ_ASSERT(newKind != SingletonObject);
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) { if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
@ -1347,7 +1327,6 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
{ {
if (mode == XDR_ENCODE) { if (mode == XDR_ENCODE) {
MOZ_ASSERT(obj->is<PlainObject>() || MOZ_ASSERT(obj->is<PlainObject>() ||
obj->is<UnboxedPlainObject>() ||
obj->is<ArrayObject>() || obj->is<ArrayObject>() ||
obj->is<UnboxedArrayObject>()); obj->is<UnboxedArrayObject>());
isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0; isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
@ -2333,11 +2312,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
// us the resolve hook won't define a property with this id. // us the resolve hook won't define a property with this id.
if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
return false; return false;
} else if (obj->is<UnboxedPlainObject>()) {
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
MarkNonNativePropertyFound<NoGC>(propp);
return true;
}
} else if (obj->is<UnboxedArrayObject>()) { } else if (obj->is<UnboxedArrayObject>()) {
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) { if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
MarkNonNativePropertyFound<NoGC>(propp); MarkNonNativePropertyFound<NoGC>(propp);
@ -2590,11 +2564,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
break; break;
} }
// Convert unboxed objects to their native representations before changing
// their prototype/group, as they depend on the group for their layout.
if (!MaybeConvertUnboxedObjectToNative(cx, obj))
return false;
Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto)); Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto)) if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto))
return false; return false;
@ -2618,9 +2587,6 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I
if (!obj->nonProxyIsExtensible()) if (!obj->nonProxyIsExtensible())
return result.succeed(); return result.succeed();
if (!MaybeConvertUnboxedObjectToNative(cx, obj))
return false;
// Force lazy properties to be resolved. // Force lazy properties to be resolved.
AutoIdVector props(cx); AutoIdVector props(cx);
if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props)) if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
@ -3714,12 +3680,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const
if (IsProxy(this)) if (IsProxy(this))
return as<ProxyObject>().allocKindForTenure(); return as<ProxyObject>().allocKindForTenure();
// Unboxed plain objects are sized according to the data they store.
if (is<UnboxedPlainObject>()) {
size_t nbytes = as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
}
// Unboxed arrays use inline data if their size is small enough. // Unboxed arrays use inline data if their size is small enough.
if (is<UnboxedArrayObject>()) { if (is<UnboxedArrayObject>()) {
const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>(); const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>();

View file

@ -7276,9 +7276,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
if (op.getBoolOption("wasm-check-bce")) if (op.getBoolOption("wasm-check-bce"))
jit::JitOptions.wasmAlwaysCheckBounds = true; jit::JitOptions.wasmAlwaysCheckBounds = true;
if (op.getBoolOption("no-unboxed-objects"))
jit::JitOptions.disableUnboxedObjects = true;
if (const char* str = op.getStringOption("cache-ir-stubs")) { if (const char* str = op.getStringOption("cache-ir-stubs")) {
if (strcmp(str, "on") == 0) if (strcmp(str, "on") == 0)
jit::JitOptions.disableCacheIR = false; jit::JitOptions.disableCacheIR = false;

View file

@ -26,6 +26,8 @@ assertDeepEq(keys, [
"fill", "fill",
"find", "find",
"findIndex", "findIndex",
"flat",
"flatMap",
"includes", "includes",
"keys", "keys",
"values" "values"

View file

@ -115,6 +115,8 @@
macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \
macro(fix, fix, "fix") \ macro(fix, fix, "fix") \
macro(flags, flags, "flags") \ macro(flags, flags, "flags") \
macro(flat, flat, "flat") \
macro(flatMap, flatMap, "flatMap") \
macro(float32, float32, "float32") \ macro(float32, float32, "float32") \
macro(Float32x4, Float32x4, "Float32x4") \ macro(Float32x4, Float32x4, "Float32x4") \
macro(float64, float64, "float64") \ macro(float64, float64, "float64") \

View file

@ -22,7 +22,6 @@
#include "vm/EnvironmentObject-inl.h" #include "vm/EnvironmentObject-inl.h"
#include "vm/Stack-inl.h" #include "vm/Stack-inl.h"
#include "vm/String-inl.h" #include "vm/String-inl.h"
#include "vm/UnboxedObject-inl.h"
namespace js { namespace js {
@ -337,14 +336,10 @@ InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvAr
inline bool inline bool
InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs) InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs)
{ {
if (obj->is<PlainObject>() || obj->is<JSFunction>()) { MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
unsigned propAttrs = GetInitDataPropAttrs(op); unsigned propAttrs = GetInitDataPropAttrs(op);
return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs, nullptr, nullptr, return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs,
propAttrs); nullptr, nullptr, propAttrs);
}
MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));
return PutProperty(cx, obj, id, rhs, false);
} }
inline bool inline bool

View file

@ -4111,7 +4111,7 @@ CASE(JSOP_INITHOMEOBJECT)
/* Load the home object */ /* Load the home object */
ReservedRooted<JSObject*> obj(&rootObject0); ReservedRooted<JSObject*> obj(&rootObject0);
obj = &REGS.sp[int(-2 - skipOver)].toObject(); obj = &REGS.sp[int(-2 - skipOver)].toObject();
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() || obj->is<JSFunction>()); MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj)); func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj));
} }
@ -4927,15 +4927,10 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
return nullptr; return nullptr;
if (group->maybePreliminaryObjects()) { if (group->maybePreliminaryObjects()) {
group->maybePreliminaryObjects()->maybeAnalyze(cx, group); group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
if (group->maybeUnboxedLayout())
group->maybeUnboxedLayout()->setAllocationSite(script, pc);
} }
if (group->shouldPreTenure() || group->maybePreliminaryObjects()) if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject; newKind = TenuredObject;
if (group->maybeUnboxedLayout())
return UnboxedPlainObject::create(cx, group, newKind);
} }
RootedObject obj(cx); RootedObject obj(cx);

View file

@ -7,7 +7,6 @@
#include "vm/ReceiverGuard.h" #include "vm/ReceiverGuard.h"
#include "builtin/TypedObject.h" #include "builtin/TypedObject.h"
#include "vm/UnboxedObject.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
using namespace js; using namespace js;

View file

@ -28,11 +28,6 @@ namespace js {
// TypedObject: The structure of a typed object is determined by its group. // TypedObject: The structure of a typed object is determined by its group.
// All typed objects with the same group have the same class, prototype, and // All typed objects with the same group have the same class, prototype, and
// own properties. // own properties.
//
// UnboxedPlainObject: The structure of an unboxed plain object is determined
// by its group and its expando object's shape, if there is one. All unboxed
// plain objects with the same group and expando shape have the same
// properties except those stored in the expando's dense elements.
class HeapReceiverGuard; class HeapReceiverGuard;
class RootedReceiverGuard; class RootedReceiverGuard;

View file

@ -1995,17 +1995,6 @@ TypeSet::ObjectKey::watchStateChangeForTypedArrayData(CompilerConstraintList* co
ConstraintDataFreezeObjectForTypedArrayData(tarray))); ConstraintDataFreezeObjectForTypedArrayData(tarray)));
} }
void
TypeSet::ObjectKey::watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints)
{
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
LifoAlloc* alloc = constraints->alloc();
typedef CompilerConstraintInstance<ConstraintDataFreezeObjectForUnboxedConvertedToNative> T;
constraints->add(alloc->new_<T>(alloc, objectProperty,
ConstraintDataFreezeObjectForUnboxedConvertedToNative()));
}
static void static void
ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown) ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown)
{ {
@ -3577,7 +3566,6 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro
} }
} }
TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects);
if (group->maybeUnboxedLayout()) if (group->maybeUnboxedLayout())
return; return;
@ -3861,10 +3849,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
PodCopy(initializerList, initializerVector.begin(), initializerVector.length()); PodCopy(initializerList, initializerVector.begin(), initializerVector.length());
} }
// Try to use an unboxed representation for the group.
if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(), group, preliminaryObjects))
return false;
js_delete(preliminaryObjects); js_delete(preliminaryObjects);
preliminaryObjects = nullptr; preliminaryObjects = nullptr;

View file

@ -262,7 +262,6 @@ class TypeSet
bool hasStableClassAndProto(CompilerConstraintList* constraints); bool hasStableClassAndProto(CompilerConstraintList* constraints);
void watchStateChangeForInlinedCall(CompilerConstraintList* constraints); void watchStateChangeForInlinedCall(CompilerConstraintList* constraints);
void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints); void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
HeapTypeSetKey property(jsid id); HeapTypeSetKey property(jsid id);
void ensureTrackedProperty(JSContext* cx, jsid id); void ensureTrackedProperty(JSContext* cx, jsid id);

View file

@ -1655,227 +1655,12 @@ const Class UnboxedArrayObject::class_ = {
// API // API
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
static bool
UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype)
{
if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32)
return true;
if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL)
return true;
return false;
}
static bool
CombineUnboxedTypes(const Value& value, JSValueType* existing)
{
JSValueType type = value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType();
if (*existing == JSVAL_TYPE_MAGIC || *existing == type || UnboxedTypeIncludes(type, *existing)) {
*existing = type;
return true;
}
if (UnboxedTypeIncludes(*existing, type))
return true;
return false;
}
// Return whether the property names and types in layout are a subset of the
// specified vector.
static bool
PropertiesAreSuperset(const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout)
{
for (size_t i = 0; i < layout->properties().length(); i++) {
const UnboxedLayout::Property& layoutProperty = layout->properties()[i];
bool found = false;
for (size_t j = 0; j < properties.length(); j++) {
if (layoutProperty.name == properties[j].name) {
found = (layoutProperty.type == properties[j].type);
break;
}
}
if (!found)
return false;
}
return true;
}
static bool
CombinePlainObjectProperties(PlainObject* obj, Shape* templateShape,
UnboxedLayout::PropertyVector& properties)
{
// All preliminary objects must have been created with enough space to
// fill in their unboxed data inline. This is ensured either by using
// the largest allocation kind (which limits the maximum size of an
// unboxed object), or by using an allocation kind that covers all
// properties in the template, as the space used by unboxed properties
// is less than or equal to that used by boxed properties.
MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >=
Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan()));
if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) {
// Only use an unboxed representation if all created objects match
// the template shape exactly.
return false;
}
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
Value val = obj->getSlot(i);
JSValueType& existing = properties[i].type;
if (!CombineUnboxedTypes(val, &existing))
return false;
}
return true;
}
static bool
CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType)
{
if (obj->inDictionaryMode() ||
obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
!obj->lastProperty()->previous()->isEmptyShape())
{
// Only use an unboxed representation if the object has no properties.
return false;
}
for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
Value val = obj->getDenseElement(i);
// For now, unboxed arrays cannot have holes.
if (val.isMagic(JS_ELEMENTS_HOLE))
return false;
if (!CombineUnboxedTypes(val, elementType))
return false;
}
return true;
}
static size_t
ComputePlainObjectLayout(ExclusiveContext* cx, Shape* templateShape,
UnboxedLayout::PropertyVector& properties)
{
// Fill in the names for all the object's properties.
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
size_t slot = r.front().slot();
MOZ_ASSERT(!properties[slot].name);
properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
}
// Fill in all the unboxed object's property offsets.
uint32_t offset = 0;
// Search for an existing unboxed layout which is a subset of this one.
// If there are multiple such layouts, use the largest one. If we're able
// to find such a layout, use the same property offsets for the shared
// properties, which will allow us to generate better code if the objects
// have a subtype/supertype relation and are accessed at common sites.
UnboxedLayout* bestExisting = nullptr;
for (UnboxedLayout* existing : cx->compartment()->unboxedLayouts) {
if (PropertiesAreSuperset(properties, existing)) {
if (!bestExisting ||
existing->properties().length() > bestExisting->properties().length())
{
bestExisting = existing;
}
}
}
if (bestExisting) {
for (size_t i = 0; i < bestExisting->properties().length(); i++) {
const UnboxedLayout::Property& existingProperty = bestExisting->properties()[i];
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
if (existingProperty.name == properties[j].name) {
MOZ_ASSERT(existingProperty.type == properties[j].type);
properties[j].offset = existingProperty.offset;
}
}
}
offset = bestExisting->size();
}
// Order remaining properties from the largest down for the best space
// utilization.
static const size_t typeSizes[] = { 8, 4, 1 };
for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
size_t size = typeSizes[i];
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
if (properties[j].offset != UINT32_MAX)
continue;
JSValueType type = properties[j].type;
if (UnboxedTypeSize(type) == size) {
offset = JS_ROUNDUP(offset, size);
properties[j].offset = offset;
offset += size;
}
}
}
// The final offset is the amount of data needed by the object.
return offset;
}
static bool
SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout)
{
// Figure out the offsets of any objects or string properties.
Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
for (size_t i = 0; i < layout->properties().length(); i++) {
const UnboxedLayout::Property& property = layout->properties()[i];
MOZ_ASSERT(property.offset != UINT32_MAX);
if (property.type == JSVAL_TYPE_OBJECT) {
if (!objectOffsets.append(property.offset))
return false;
} else if (property.type == JSVAL_TYPE_STRING) {
if (!stringOffsets.append(property.offset))
return false;
}
}
// Construct the layout's trace list.
if (!objectOffsets.empty() || !stringOffsets.empty()) {
Vector<int32_t, 8, SystemAllocPolicy> entries;
if (!entries.appendAll(stringOffsets) ||
!entries.append(-1) ||
!entries.appendAll(objectOffsets) ||
!entries.append(-1) ||
!entries.append(-1))
{
return false;
}
int32_t* traceList = cx->zone()->pod_malloc<int32_t>(entries.length());
if (!traceList)
return false;
PodCopy(traceList, entries.begin(), entries.length());
layout->setTraceList(traceList);
}
return true;
}
static inline Value static inline Value
NextValue(Handle<GCVector<Value>> values, size_t* valueCursor) NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
{ {
return values[(*valueCursor)++]; return values[(*valueCursor)++];
} }
static bool
GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle<GCVector<Value>> values)
{
if (!values.append(Int32Value(obj->length())))
return false;
if (!values.append(Int32Value(obj->getDenseInitializedLength())))
return false;
for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
if (!values.append(obj->getDenseElement(i)))
return false;
}
return true;
}
void void
UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor) Handle<GCVector<Value>> values, size_t* valueCursor)
@ -1901,16 +1686,6 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor))); JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
} }
static bool
GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle<GCVector<Value>> values)
{
for (size_t i = 0; i < obj->slotSpan(); i++) {
if (!values.append(obj->getSlot(i)))
return false;
}
return true;
}
void void
UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor) Handle<GCVector<Value>> values, size_t* valueCursor)
@ -1921,181 +1696,6 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
} }
bool
js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
ObjectGroup* group, PreliminaryObjectArray* objects)
{
bool isArray = !templateShape;
// Unboxed arrays are nightly only for now. The getenv() call will be
// removed when they are on by default. See bug 1153266.
if (isArray) {
#ifdef NIGHTLY_BUILD
if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) {
if (!cx->options().unboxedArrays())
return true;
}
#else
return true;
#endif
} else {
if (jit::JitOptions.disableUnboxedObjects)
return true;
}
MOZ_ASSERT_IF(templateShape, !templateShape->getObjectFlags());
if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global()))
return true;
if (!isArray && templateShape->slotSpan() == 0)
return true;
UnboxedLayout::PropertyVector properties;
if (!isArray) {
if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan()))
return false;
}
JSValueType elementType = JSVAL_TYPE_MAGIC;
size_t objectCount = 0;
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
JSObject* obj = objects->get(i);
if (!obj)
continue;
if (obj->isSingleton() || obj->group() != group)
return true;
objectCount++;
if (isArray) {
if (!CombineArrayObjectElements(cx, &obj->as<ArrayObject>(), &elementType))
return true;
} else {
if (!CombinePlainObjectProperties(&obj->as<PlainObject>(), templateShape, properties))
return true;
}
}
size_t layoutSize = 0;
if (isArray) {
// Don't use an unboxed representation if we couldn't determine an
// element type for the objects.
if (UnboxedTypeSize(elementType) == 0)
return true;
} else {
if (objectCount <= 1) {
// If only one of the objects has been created, it is more likely
// to have new properties added later. This heuristic is not used
// for array objects, where we might want an unboxed representation
// even if there is only one large array.
return true;
}
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
// We can't use an unboxed representation if e.g. all the objects have
// a null value for one of the properties, as we can't decide what type
// it is supposed to have.
if (UnboxedTypeSize(properties[i].type) == 0)
return true;
}
// Make sure that all properties on the template shape are property
// names, and not indexes.
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
jsid id = r.front().propid();
uint32_t dummy;
if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
return true;
}
layoutSize = ComputePlainObjectLayout(cx, templateShape, properties);
// The entire object must be allocatable inline.
if (UnboxedPlainObject::offsetOfData() + layoutSize > JSObject::MAX_BYTE_SIZE)
return true;
}
UniquePtr<UnboxedLayout>& layout = enter.unboxedLayoutToCleanUp;
MOZ_ASSERT(!layout);
layout = group->zone()->make_unique<UnboxedLayout>();
if (!layout)
return false;
if (isArray) {
layout->initArray(elementType);
} else {
if (!layout->initProperties(properties, layoutSize))
return false;
// The unboxedLayouts list only tracks layouts for plain objects.
cx->compartment()->unboxedLayouts.insertFront(layout.get());
if (!SetLayoutTraceList(cx, layout.get()))
return false;
}
// We've determined that all the preliminary objects can use the new layout
// just constructed, so convert the existing group to use the unboxed class,
// and update the preliminary objects to use the new layout. Do the
// fallible stuff first before modifying any objects.
// Get an empty shape which we can use for the preliminary objects.
const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_;
Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0);
if (!newShape) {
cx->recoverFromOutOfMemory();
return false;
}
// Accumulate a list of all the values in each preliminary object, and
// update their shapes.
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
JSObject* obj = objects->get(i);
if (!obj)
continue;
bool ok;
if (isArray)
ok = GetValuesFromPreliminaryArrayObject(&obj->as<ArrayObject>(), &values);
else
ok = GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(), &values);
if (!ok) {
cx->recoverFromOutOfMemory();
return false;
}
}
if (TypeNewScript* newScript = group->newScript())
layout->setNewScript(newScript);
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
if (JSObject* obj = objects->get(i))
obj->as<NativeObject>().setLastPropertyMakeNonNative(newShape);
}
group->setClasp(clasp);
group->setUnboxedLayout(layout.release());
size_t valueCursor = 0;
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
JSObject* obj = objects->get(i);
if (!obj)
continue;
if (isArray)
obj->as<UnboxedArrayObject>().fillAfterConvert(cx, values, &valueCursor);
else
obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
}
MOZ_ASSERT(valueCursor == values.length());
return true;
}
DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
ShouldUpdateTypes); ShouldUpdateTypes);

View file

@ -317,13 +317,6 @@ class UnboxedPlainObject : public JSObject
} }
}; };
// Try to construct an UnboxedLayout for each of the preliminary objects,
// provided they all match the template shape. If successful, converts the
// preliminary objects and their group to the new unboxed representation.
bool
TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
ObjectGroup* group, PreliminaryObjectArray* objects);
inline gc::AllocKind inline gc::AllocKind
UnboxedLayout::getAllocKind() const UnboxedLayout::getAllocKind() const
{ {

View file

@ -1427,8 +1427,6 @@ ReloadPrefsCallback(const char* pref, void* data)
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict"); bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory"); sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
#ifdef DEBUG #ifdef DEBUG
@ -1457,8 +1455,6 @@ ReloadPrefsCallback(const char* pref, void* data)
useBaselineEager ? 0 : -1); useBaselineEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER, JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER,
useIonEager ? 0 : -1); useIonEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS,
unboxedObjects);
} }
XPCJSContext::~XPCJSContext() XPCJSContext::~XPCJSContext()

View file

@ -198,7 +198,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
"includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find", "includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
"findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys", "findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys",
"values", "constructor"]; "values", "constructor", "flat", "flatMap"];
if (isNightlyBuild) { if (isNightlyBuild) {
// ...nothing now // ...nothing now
} }

View file

@ -21,3 +21,4 @@ pref(gfx.font_rendering.opentype_svg.enabled,true) fails == svg-glyph-mask.sv
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-paint-server.svg svg-glyph-paint-server-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-paint-server.svg svg-glyph-paint-server-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-transform.svg svg-glyph-transform-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-transform.svg svg-glyph-transform-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-extents.html svg-glyph-extents-ref.html pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-extents.html svg-glyph-extents-ref.html
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-compressed.html svg-glyph-compressed-ref.html

Binary file not shown.

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Test for compressed SVG glyphs</title>
<style>
@font-face {
font-family: test;
src: url(resources/svg.woff); /* uses uncompressed SVG documents */
}
html { width: 400px; height: 400px; background-color: white; }
body { margin: 0; }
div { font: 200px test; color: fuchsia; line-height: 1; stroke: none; }
</style>
</head><body><div>abcdefg</div>
<div>LMNOPQR</div>
</body></html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Test for compressed SVG glyphs</title>
<style>
@font-face {
font-family: test;
src: url(resources/svg-gz.ttf); /* copy of svg.woff using gzip-compressed SVG documents */
}
html { width: 400px; height: 400px; background-color: white; }
body { margin: 0; }
div { font: 200px test; color: fuchsia; line-height: 1; stroke: none; }
</style>
</head><body><div>abcdefg</div>
<div>LMNOPQR</div>
</body></html>

View file

@ -1264,7 +1264,6 @@ pref("javascript.options.strict", false);
#ifdef DEBUG #ifdef DEBUG
pref("javascript.options.strict.debug", false); pref("javascript.options.strict.debug", false);
#endif #endif
pref("javascript.options.unboxed_objects", false);
pref("javascript.options.baselinejit", true); pref("javascript.options.baselinejit", true);
pref("javascript.options.ion", true); pref("javascript.options.ion", true);
pref("javascript.options.asmjs", true); pref("javascript.options.asmjs", true);

View file

@ -948,9 +948,6 @@ function handleFallbackToCompleteUpdate(update, postStaging) {
update.setProperty("patchingFailed", oldType); update.setProperty("patchingFailed", oldType);
} }
function pingStateAndStatusCodes(aUpdate, aStartup, aStatus) {
}
/** /**
* Update Patch * Update Patch
* @param patch * @param patch
@ -1538,7 +1535,6 @@ UpdateService.prototype = {
getService(Ci.nsIUpdateManager); getService(Ci.nsIUpdateManager);
var update = um.activeUpdate; var update = um.activeUpdate;
var status = readStatusFile(getUpdatesDir()); var status = readStatusFile(getUpdatesDir());
pingStateAndStatusCodes(update, true, status);
// STATE_NONE status typically means that the update.status file is present // STATE_NONE status typically means that the update.status file is present
// but a background download error occurred. // but a background download error occurred.
if (status == STATE_NONE) { if (status == STATE_NONE) {
@ -2146,8 +2142,6 @@ UpdateService.prototype = {
if (!osApplyToDir) { if (!osApplyToDir) {
LOG("UpdateService:applyOsUpdate - Error: osApplyToDir is not defined" + LOG("UpdateService:applyOsUpdate - Error: osApplyToDir is not defined" +
"in the nsIUpdate!"); "in the nsIUpdate!");
pingStateAndStatusCodes(aUpdate, false,
STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR);
handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR);
return; return;
} }
@ -2157,8 +2151,6 @@ UpdateService.prototype = {
if (!updateFile.exists()) { if (!updateFile.exists()) {
LOG("UpdateService:applyOsUpdate - Error: OS update is not found at " + LOG("UpdateService:applyOsUpdate - Error: OS update is not found at " +
updateFile.path); updateFile.path);
pingStateAndStatusCodes(aUpdate, false,
STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR);
handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR);
return; return;
} }
@ -2173,8 +2165,6 @@ UpdateService.prototype = {
} catch (e) { } catch (e) {
LOG("UpdateService:applyOsUpdate - Error: Couldn't reboot into recovery" + LOG("UpdateService:applyOsUpdate - Error: Couldn't reboot into recovery" +
" to apply FOTA update " + updateFile.path); " to apply FOTA update " + updateFile.path);
pingStateAndStatusCodes(aUpdate, false,
STATE_FAILED + ": " + FOTA_RECOVERY_ERROR);
writeStatusFile(getUpdatesDir(), aUpdate.state = STATE_APPLIED); writeStatusFile(getUpdatesDir(), aUpdate.state = STATE_APPLIED);
handleUpdateFailure(aUpdate, FOTA_RECOVERY_ERROR); handleUpdateFailure(aUpdate, FOTA_RECOVERY_ERROR);
} }
@ -2476,7 +2466,6 @@ UpdateManager.prototype = {
return; return;
} }
var status = readStatusFile(getUpdatesDir()); var status = readStatusFile(getUpdatesDir());
pingStateAndStatusCodes(update, false, status);
var parts = status.split(":"); var parts = status.split(":");
update.state = parts[0]; update.state = parts[0];
if (update.state == STATE_FAILED && parts[1]) { if (update.state == STATE_FAILED && parts[1]) {