From eb0619d3c4c6cc6b8a84f1d0ea976c30d6aecd32 Mon Sep 17 00:00:00 2001 From: Matthew Gaudet Date: Fri, 22 Mar 2019 15:32:34 +0000 Subject: [PATCH] Bug 1505574 - Remove Unboxed Objects from jit/ - Part 2 r=iain Differential Revision: https://phabricator.services.mozilla.com/D24045 --HG-- extra : moz-landing-system : lando --- js/src/jit/BaselineCacheIRCompiler.cpp | 54 ---- js/src/jit/BaselineInspector.cpp | 181 ++----------- js/src/jit/CacheIR.cpp | 353 ++----------------------- js/src/jit/CacheIR.h | 31 +-- js/src/jit/CacheIRCompiler.cpp | 31 --- js/src/jit/CacheIRCompiler.h | 2 - js/src/jit/IonCacheIRCompiler.cpp | 43 --- js/src/jit/MacroAssembler.cpp | 286 -------------------- js/src/jit/MacroAssembler.h | 15 -- js/src/jit/TemplateObject-inl.h | 14 - js/src/jit/TemplateObject.h | 9 +- js/src/jit/VMFunctionList-inl.h | 2 - js/src/jit/VMFunctions.cpp | 7 - js/src/vm/UnboxedObject.cpp | 264 ------------------ 14 files changed, 56 insertions(+), 1236 deletions(-) diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index 9c4bf3285dc0..918024dca87a 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -730,20 +730,6 @@ bool BaselineCacheIRCompiler::emitCallNativeGetElementResult() { return true; } -bool BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - AutoOutputRegister output(*this); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - AutoScratchRegisterMaybeOutput scratch(allocator, masm, output); - - JSValueType fieldType = reader.jsValueType(); - Address fieldOffset(stubAddress(reader.stubOffset())); - masm.load32(fieldOffset, scratch); - masm.loadUnboxedProperty(BaseIndex(obj, scratch, TimesOne), fieldType, - output); - return true; -} - bool BaselineCacheIRCompiler::emitGuardFrameHasNoArgumentsObject() { JitSpew(JitSpew_Codegen, __FUNCTION__); FailurePath* failure; @@ -1180,46 +1166,6 @@ bool BaselineCacheIRCompiler::emitAllocateAndStoreDynamicSlot() { return emitAddAndStoreSlotShared(CacheOp::AllocateAndStoreDynamicSlot); } -bool BaselineCacheIRCompiler::emitStoreUnboxedProperty() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - ObjOperandId objId = reader.objOperandId(); - JSValueType fieldType = reader.jsValueType(); - Address offsetAddr = stubAddress(reader.stubOffset()); - - // Allocate the fixed registers first. These need to be fixed for - // callTypeUpdateIC. - AutoScratchRegister scratch(allocator, masm, R1.scratchReg()); - ValueOperand val = - allocator.useFixedValueRegister(masm, reader.valOperandId(), R0); - - Register obj = allocator.useRegister(masm, objId); - - // We only need the type update IC if we are storing an object. - if (fieldType == JSVAL_TYPE_OBJECT) { - LiveGeneralRegisterSet saveRegs; - saveRegs.add(obj); - saveRegs.add(val); - if (!callTypeUpdateIC(obj, val, scratch, saveRegs)) { - return false; - } - } - - masm.load32(offsetAddr, scratch); - BaseIndex fieldAddr(obj, scratch, TimesOne); - - // Note that the storeUnboxedProperty call here is infallible, as the - // IR emitter is responsible for guarding on |val|'s type. - EmitICUnboxedPreBarrier(masm, fieldAddr, fieldType); - masm.storeUnboxedProperty(fieldAddr, fieldType, - ConstantOrRegister(TypedOrValueRegister(val)), - /* failure = */ nullptr); - - if (UnboxedTypeNeedsPostBarrier(fieldType)) { - emitPostBarrierSlot(obj, val, scratch); - } - return true; -} - bool BaselineCacheIRCompiler::emitStoreTypedObjectReferenceProperty() { JitSpew(JitSpew_Codegen, __FUNCTION__); ObjOperandId objId = reader.objOperandId(); diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index d350335b109b..a3de098171d2 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -59,26 +59,18 @@ static bool VectorAppendNoDuplicate(S& list, T value) { return list.append(value); } -static bool AddReceiver( - const ReceiverGuard& receiver, BaselineInspector::ReceiverVector& receivers) { +static bool AddReceiver(const ReceiverGuard& receiver, + BaselineInspector::ReceiverVector& receivers) { return VectorAppendNoDuplicate(receivers, receiver); } static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* receiver) { - // We match either: + // We match: // // GuardIsObject 0 // GuardShape 0 // LoadFixedSlotResult 0 or LoadDynamicSlotResult 0 - // - // or - // - // GuardIsObject 0 - // GuardGroup 0 - // 1: GuardAndLoadUnboxedExpando 0 - // GuardShape 1 - // LoadFixedSlotResult 1 or LoadDynamicSlotResult 1 *receiver = ReceiverGuard(); CacheIRReader reader(stub->stubInfo()); @@ -88,16 +80,6 @@ static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, return false; } - if (reader.matchOp(CacheOp::GuardGroup, objId)) { - receiver->group = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) { - return false; - } - objId = reader.objOperandId(); - } - if (reader.matchOp(CacheOp::GuardShape, objId)) { receiver->shape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); @@ -108,48 +90,14 @@ static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, return false; } -static bool GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, - ReceiverGuard* receiver) { - // We match: - // - // GuardIsObject 0 - // GuardGroup 0 - // LoadUnboxedPropertyResult 0 .. - - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardIsObject, objId)) { - return false; - } - - if (!reader.matchOp(CacheOp::GuardGroup, objId)) { - return false; - } - receiver->group = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - return reader.matchOp(CacheOp::LoadUnboxedPropertyResult, objId); -} - static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub, ReceiverGuard* receiver) { - // We match either: + // We match: // // GuardIsObject 0 // GuardGroup 0 // GuardShape 0 // StoreFixedSlot 0 or StoreDynamicSlot 0 - // - // or - // - // GuardIsObject 0 - // GuardGroup 0 - // 1: GuardAndLoadUnboxedExpando 0 - // GuardShape 1 - // StoreFixedSlot 1 or StoreDynamicSlot 1 - *receiver = ReceiverGuard(); CacheIRReader reader(stub->stubInfo()); @@ -164,10 +112,6 @@ static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub, ObjectGroup* group = stub->stubInfo()->getStubField(stub, reader.stubOffset()); - if (reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) { - objId = reader.objOperandId(); - } - if (!reader.matchOp(CacheOp::GuardShape, objId)) { return false; } @@ -183,46 +127,6 @@ static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub, return true; } -static bool GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Updated* stub, - ReceiverGuard* receiver) { - // We match: - // - // GuardIsObject 0 - // GuardGroup 0 - // GuardType 1 type | GuardIsObjectOrNull 1 - // StoreUnboxedProperty 0 - - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - ValOperandId rhsId = ValOperandId(1); - if (!reader.matchOp(CacheOp::GuardIsObject, objId)) { - return false; - } - - if (!reader.matchOp(CacheOp::GuardGroup, objId)) { - return false; - } - ObjectGroup* group = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (reader.matchOp(CacheOp::GuardType, rhsId)) { - reader.valueType(); // Skip. - } else { - if (!reader.matchOp(CacheOp::GuardIsObjectOrNull, rhsId)) { - return false; - } - } - - if (!reader.matchOp(CacheOp::StoreUnboxedProperty)) { - return false; - } - - *receiver = ReceiverGuard(group, nullptr); - return true; -} - ICScript* BaselineInspector::icScript() const { return script->icScript(); } ICEntry& BaselineInspector::icEntryFromPC(jsbytecode* pc) { @@ -245,11 +149,11 @@ ICEntry* BaselineInspector::maybeICEntryFromPC(jsbytecode* pc) { return ent; } -bool BaselineInspector::maybeInfoForPropertyOp( - jsbytecode* pc, ReceiverVector& receivers) { +bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, + ReceiverVector& receivers) { // 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 - // uncacheable access. + // uncacheable access. MOZ_ASSERT(receivers.empty()); if (!hasICScript()) { @@ -264,17 +168,13 @@ bool BaselineInspector::maybeInfoForPropertyOp( ReceiverGuard receiver; if (stub->isCacheIR_Monitored()) { if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), - &receiver) && - !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), - &receiver)) { + &receiver)) { receivers.clear(); return true; } } else if (stub->isCacheIR_Updated()) { if (!GetCacheIRReceiverForNativeSetSlot(stub->toCacheIR_Updated(), - &receiver) && - !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Updated(), - &receiver)) { + &receiver)) { receivers.clear(); return true; } @@ -1031,17 +931,6 @@ static bool MatchCacheIRReceiverGuard(CacheIRReader& reader, ICStub* stub, // // GuardShape objId // - // or: - // - // GuardGroup objId - // [GuardNoUnboxedExpando objId] - // - // or: - // - // GuardGroup objId - // expandoId: GuardAndLoadUnboxedExpando - // GuardShape expandoId - *receiver = ReceiverGuard(); if (reader.matchOp(CacheOp::GuardShape, objId)) { @@ -1049,34 +938,15 @@ static bool MatchCacheIRReceiverGuard(CacheIRReader& reader, ICStub* stub, receiver->shape = stubInfo->getStubField(stub, reader.stubOffset()); return true; } - - if (!reader.matchOp(CacheOp::GuardGroup, objId)) { - return false; - } - receiver->group = - stubInfo->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) { - // Second case, just a group guard. - reader.matchOp(CacheOp::GuardNoUnboxedExpando, objId); - return true; - } - - // Third case. - ObjOperandId expandoId = reader.objOperandId(); - if (!reader.matchOp(CacheOp::GuardShape, expandoId)) { - return false; - } - - receiver->shape = stubInfo->getStubField(stub, reader.stubOffset()); - return true; + return false; } -static bool AddCacheIRGlobalGetter( - ICCacheIR_Monitored* stub, bool innerized, JSObject** holder_, - Shape** holderShape_, JSFunction** commonGetter, Shape** globalShape_, - bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers, - JSScript* script) { +static bool AddCacheIRGlobalGetter(ICCacheIR_Monitored* stub, bool innerized, + JSObject** holder_, Shape** holderShape_, + JSFunction** commonGetter, + Shape** globalShape_, bool* isOwnProperty, + BaselineInspector::ReceiverVector& receivers, + JSScript* script) { // We are matching on the IR generated by tryAttachGlobalNameGetter: // // GuardShape objId @@ -1376,9 +1246,9 @@ bool BaselineInspector::commonGetPropFunction( for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isCacheIR_Monitored()) { - if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), id, innerized, - holder, holderShape, commonGetter, - globalShape, isOwnProperty, receivers, script)) { + if (!AddCacheIRGetPropFunction( + stub->toCacheIR_Monitored(), id, innerized, holder, holderShape, + commonGetter, globalShape, isOwnProperty, receivers, script)) { return false; } } else if (stub->isFallback()) { @@ -1599,9 +1469,11 @@ static bool AddCacheIRSetPropFunction( return true; } -bool BaselineInspector::commonSetPropFunction( - jsbytecode* pc, JSObject** holder, Shape** holderShape, - JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers) { +bool BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, + Shape** holderShape, + JSFunction** commonSetter, + bool* isOwnProperty, + ReceiverVector& receivers) { if (!hasICScript()) { return false; } @@ -1693,8 +1565,9 @@ static bool GetCacheIRReceiverForProtoReadSlot(ICCacheIR_Monitored* stub, return true; } -bool BaselineInspector::maybeInfoForProtoReadSlot( - jsbytecode* pc, ReceiverVector& receivers, JSObject** holder) { +bool BaselineInspector::maybeInfoForProtoReadSlot(jsbytecode* pc, + ReceiverVector& receivers, + JSObject** holder) { // This is like maybeInfoForPropertyOp, but for when the property exists on // the prototype. diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 5ebf7aac60eb..6e1bfe946734 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -20,9 +20,9 @@ #include "vm/JSContext-inl.h" #include "vm/JSObject-inl.h" #include "vm/JSScript-inl.h" +#include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" #include "vm/TypeInference-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -268,12 +268,6 @@ bool GetPropIRGenerator::tryAttachStub() { if (tryAttachNative(obj, objId, id)) { return true; } - if (tryAttachUnboxed(obj, objId, id)) { - return true; - } - if (tryAttachUnboxedExpando(obj, objId, id)) { - return true; - } if (tryAttachTypedObject(obj, objId, id)) { return true; } @@ -322,9 +316,6 @@ bool GetPropIRGenerator::tryAttachStub() { if (tryAttachSparseElement(obj, objId, index, indexId)) { return true; } - if (tryAttachUnboxedElementHole(obj, objId, index, indexId)) { - return true; - } if (tryAttachArgumentsObjectArg(obj, objId, indexId)) { return true; } @@ -519,11 +510,6 @@ static bool CheckHasNoSuchOwnProperty(JSContext* cx, JSObject* obj, jsid id) { if (obj->as().contains(cx, id)) { return false; } - } else if (obj->is()) { - if (obj->as().containsUnboxedOrExpandoProperty(cx, - id)) { - return false; - } } else if (obj->is()) { if (obj->as().typeDescr().hasProperty(cx->names(), id)) { return false; @@ -674,23 +660,10 @@ static void GuardGroupProto(CacheIRWriter& writer, JSObject* obj, } // Guard that a given object has same class and same OwnProperties (excluding -// dense elements and dynamic properties). Returns an OperandId for the unboxed -// expando if it exists. +// dense elements and dynamic properties). static void TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, - ObjOperandId objId, - Maybe* expandoId) { - if (obj->is()) { - writer.guardGroupForLayout(objId, obj->group()); - - if (UnboxedExpandoObject* expando = - obj->as().maybeExpando()) { - expandoId->emplace(writer.guardAndLoadUnboxedExpando(objId)); - writer.guardShapeForOwnProperties(expandoId->ref(), - expando->lastProperty()); - } else { - writer.guardNoUnboxedExpando(objId); - } - } else if (obj->is()) { + ObjOperandId objId) { + if (obj->is()) { writer.guardGroupForLayout(objId, obj->group()); } else if (obj->is()) { writer.guardShapeForClass(objId, obj->as().shape()); @@ -728,9 +701,7 @@ static void GeneratePrototypeGuardsForReceiver(CacheIRWriter& writer, #ifdef DEBUG // The following cases already guaranteed the prototype is unchanged. - if (obj->is()) { - MOZ_ASSERT(!obj->group()->hasUncacheableProto()); - } else if (obj->is()) { + if (obj->is()) { MOZ_ASSERT(!obj->group()->hasUncacheableProto()); } else if (obj->is()) { MOZ_ASSERT(!obj->hasUncacheableProto()); @@ -956,8 +927,7 @@ template static void EmitReadSlotGuard(CacheIRWriter& writer, JSObject* obj, JSObject* holder, ObjOperandId objId, Maybe* holderId) { - Maybe expandoId; - TestMatchingReceiver(writer, obj, objId, &expandoId); + TestMatchingReceiver(writer, obj, objId); if (obj != holder) { if (holder) { @@ -981,8 +951,6 @@ static void EmitReadSlotGuard(CacheIRWriter& writer, JSObject* obj, // CanAttachNativeGetProp(). ShapeGuardProtoChain(writer, obj, objId); } - } else if (obj->is()) { - holderId->emplace(*expandoId); } else { holderId->emplace(objId); } @@ -996,10 +964,6 @@ static void EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, EmitReadSlotGuard(writer, obj, holder, objId, &holderId); - if (obj == holder && obj->is()) { - holder = obj->as().maybeExpando(); - } - // Slot access. if (holder) { MOZ_ASSERT(holderId->valid()); @@ -1056,8 +1020,7 @@ static void EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj, // is a Window as GuardHasGetterSetter doesn't support this yet (Window may // require outerizing). if (mode == ICState::Mode::Specialized || IsWindow(obj)) { - Maybe expandoId; - TestMatchingReceiver(writer, obj, objId, &expandoId); + TestMatchingReceiver(writer, obj, objId); if (obj != holder) { GeneratePrototypeGuards(writer, obj, holder, objId); @@ -1734,60 +1697,6 @@ bool GetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, MOZ_CRASH("Unexpected ProxyStubType"); } -bool GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId, - HandleId id) { - if (!obj->is()) { - return false; - } - - const UnboxedLayout::Property* property = - obj->as().layout().lookup(id); - if (!property) { - return false; - } - - maybeEmitIdGuard(id); - writer.guardGroupForLayout(objId, obj->group()); - writer.loadUnboxedPropertyResult( - objId, property->type, - UnboxedPlainObject::offsetOfData() + property->offset); - if (property->type == JSVAL_TYPE_OBJECT) { - writer.typeMonitorResult(); - } else { - writer.returnFromIC(); - } - - preliminaryObjectAction_ = PreliminaryObjectAction::Unlink; - - trackAttached("Unboxed"); - return true; -} - -bool GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, - ObjOperandId objId, - HandleId id) { - if (!obj->is()) { - return false; - } - - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (!expando) { - return false; - } - - Shape* shape = expando->lookup(cx_, id); - if (!shape || !shape->isDataProperty()) { - return false; - } - - maybeEmitIdGuard(id); - EmitReadSlotResult(writer, obj, obj, shape, objId); - EmitReadSlotReturn(writer, obj, obj, shape); - - trackAttached("UnboxedExpando"); - return true; -} - static TypedThingLayout GetTypedThingLayout(const Class* clasp) { if (IsTypedArrayClass(clasp)) { return Layout_TypedArray; @@ -2398,52 +2307,6 @@ bool GetPropIRGenerator::tryAttachTypedElement(HandleObject obj, return true; } -bool GetPropIRGenerator::tryAttachUnboxedElementHole(HandleObject obj, - ObjOperandId objId, - uint32_t index, - Int32OperandId indexId) { - if (!obj->is()) { - return false; - } - - // Only support unboxed objects with no elements (i.e. no expando) - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (expando) { - return false; - } - - if (JSObject* proto = obj->staticPrototype()) { - // Start the check at the first object on the [[Prototype]], - // which must be native now. - if (!proto->isNative()) { - return false; - } - - if (proto->as().getDenseInitializedLength() != 0) { - return false; - } - - if (!CanAttachDenseElementHole(&proto->as(), false)) { - return false; - } - } - - // Guard on the group and prevent expandos from appearing. - Maybe tempId; - TestMatchingReceiver(writer, obj, objId, &tempId); - - // Guard that the prototype chain has no elements. - GeneratePrototypeHoleGuards(writer, obj, objId, - /* alwaysGuardFirstProto = */ false); - - writer.loadUndefinedResult(); - // No monitor: We know undefined must be in the typeset already. - writer.returnFromIC(); - - trackAttached("UnboxedElementHole"); - return true; -} - bool GetPropIRGenerator::tryAttachGenericElement(HandleObject obj, ObjOperandId objId, uint32_t index, @@ -3091,15 +2954,9 @@ bool HasPropIRGenerator::tryAttachNamedProp(HandleObject obj, if (tryAttachNative(obj, objId, key, keyId, prop, holder)) { return true; } - if (tryAttachUnboxed(obj, objId, key, keyId)) { - return true; - } if (tryAttachTypedObject(obj, objId, key, keyId)) { return true; } - if (tryAttachUnboxedExpando(obj, objId, key, keyId)) { - return true; - } return false; } @@ -3140,54 +2997,6 @@ bool HasPropIRGenerator::tryAttachNative(JSObject* obj, ObjOperandId objId, return true; } -bool HasPropIRGenerator::tryAttachUnboxed(JSObject* obj, ObjOperandId objId, - jsid key, ValOperandId keyId) { - if (!obj->is()) { - return false; - } - - const UnboxedLayout::Property* prop = - obj->as().layout().lookup(key); - if (!prop) { - return false; - } - - emitIdGuard(keyId, key); - writer.guardGroupForLayout(objId, obj->group()); - writer.loadBooleanResult(true); - writer.returnFromIC(); - - trackAttached("UnboxedHasProp"); - return true; -} - -bool HasPropIRGenerator::tryAttachUnboxedExpando(JSObject* obj, - ObjOperandId objId, jsid key, - ValOperandId keyId) { - if (!obj->is()) { - return false; - } - - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (!expando) { - return false; - } - - Shape* shape = expando->lookup(cx_, key); - if (!shape) { - return false; - } - - Maybe tempId; - emitIdGuard(keyId, key); - EmitReadSlotGuard(writer, obj, obj, objId, &tempId); - writer.loadBooleanResult(true); - writer.returnFromIC(); - - trackAttached("UnboxedExpandoHasProp"); - return true; -} - bool HasPropIRGenerator::tryAttachTypedArray(HandleObject obj, ObjOperandId objId, Int32OperandId indexId) { @@ -3237,8 +3046,7 @@ bool HasPropIRGenerator::tryAttachSlotDoesNotExist(JSObject* obj, emitIdGuard(keyId, key); if (hasOwn) { - Maybe tempId; - TestMatchingReceiver(writer, obj, objId, &tempId); + TestMatchingReceiver(writer, obj, objId); } else { Maybe tempId; EmitReadSlotGuard(writer, obj, nullptr, objId, &tempId); @@ -3256,7 +3064,7 @@ bool HasPropIRGenerator::tryAttachDoesNotExist(HandleObject obj, bool hasOwn = (cacheKind_ == CacheKind::HasOwn); // Check that property doesn't exist on |obj| or it's prototype chain. These - // checks allow Native/Unboxed/Typed objects with a NativeObject prototype + // checks allow Native/Typed objects with a NativeObject prototype // chain. They return false if unknown such as resolve hooks or proxies. if (hasOwn) { if (!CheckHasNoSuchOwnProperty(cx_, obj, key)) { @@ -3456,12 +3264,6 @@ bool SetPropIRGenerator::tryAttachStub() { if (tryAttachNativeSetSlot(obj, objId, id, rhsValId)) { return true; } - if (tryAttachUnboxedExpandoSetSlot(obj, objId, id, rhsValId)) { - return true; - } - if (tryAttachUnboxedProperty(obj, objId, id, rhsValId)) { - return true; - } if (tryAttachTypedObjectProperty(obj, objId, id, rhsValId)) { return true; } @@ -3617,79 +3419,6 @@ bool SetPropIRGenerator::tryAttachNativeSetSlot(HandleObject obj, return true; } -bool SetPropIRGenerator::tryAttachUnboxedExpandoSetSlot(HandleObject obj, - ObjOperandId objId, - HandleId id, - ValOperandId rhsId) { - if (!obj->is()) { - return false; - } - - UnboxedExpandoObject* expando = obj->as().maybeExpando(); - if (!expando) { - return false; - } - - Shape* propShape = LookupShapeForSetSlot(JSOp(*pc_), expando, id); - if (!propShape) { - return false; - } - - maybeEmitIdGuard(id); - - Maybe expandoId; - TestMatchingReceiver(writer, obj, objId, &expandoId); - - // Property types must be added to the unboxed object's group, not the - // expando's group (it has unknown properties). - typeCheckInfo_.set(obj->group(), id); - EmitStoreSlotAndReturn(writer, expandoId.ref(), expando, propShape, rhsId); - - trackAttached("UnboxedExpando"); - return true; -} - -static void EmitGuardUnboxedPropertyType(CacheIRWriter& writer, - JSValueType propType, - ValOperandId valId) { - if (propType == JSVAL_TYPE_OBJECT) { - // Unboxed objects store NullValue as nullptr object. - writer.guardIsObjectOrNull(valId); - } else { - MOZ_ASSERT(propType <= JSVAL_TYPE_OBJECT); - writer.guardType(valId, ValueType(propType)); - } -} - -bool SetPropIRGenerator::tryAttachUnboxedProperty(HandleObject obj, - ObjOperandId objId, - HandleId id, - ValOperandId rhsId) { - if (!obj->is()) { - return false; - } - - const UnboxedLayout::Property* property = - obj->as().layout().lookup(id); - if (!property) { - return false; - } - - maybeEmitIdGuard(id); - writer.guardGroupForLayout(objId, obj->group()); - EmitGuardUnboxedPropertyType(writer, property->type, rhsId); - writer.storeUnboxedProperty( - objId, property->type, - UnboxedPlainObject::offsetOfData() + property->offset, rhsId); - writer.returnFromIC(); - - typeCheckInfo_.set(obj->group(), id); - preliminaryObjectAction_ = PreliminaryObjectAction::Unlink; - - trackAttached("Unboxed"); - return true; -} - bool SetPropIRGenerator::tryAttachTypedObjectProperty(HandleObject obj, ObjOperandId objId, HandleId id, @@ -3915,8 +3644,7 @@ bool SetPropIRGenerator::tryAttachSetter(HandleObject obj, ObjOperandId objId, // is a Window as GuardHasGetterSetter doesn't support this yet (Window may // require outerizing). if (mode_ == ICState::Mode::Specialized || IsWindow(obj)) { - Maybe expandoId; - TestMatchingReceiver(writer, obj, objId, &expandoId); + TestMatchingReceiver(writer, obj, objId); if (obj != holder) { GeneratePrototypeGuards(writer, obj, holder, objId); @@ -4639,32 +4367,17 @@ bool SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, return false; } - Shape* propShape = nullptr; - NativeObject* holderOrExpando = nullptr; - - if (obj->isNative()) { - propShape = prop.shape(); - holderOrExpando = &obj->as(); - } else { - if (!obj->is()) { - return false; - } - UnboxedExpandoObject* expando = - obj->as().maybeExpando(); - if (!expando) { - return false; - } - propShape = expando->lookupPure(id); - if (!propShape) { - return false; - } - holderOrExpando = expando; + if (!obj->isNative()) { + return false; } + Shape* propShape = prop.shape(); + NativeObject* holder = &obj->as(); + MOZ_ASSERT(propShape); // The property must be the last added property of the object. - MOZ_RELEASE_ASSERT(holderOrExpando->lastProperty() == propShape); + MOZ_RELEASE_ASSERT(holder->lastProperty() == propShape); // Old shape should be parent of new shape. Object flag updates may make this // false even for simple data properties. It may be possible to support these @@ -4705,31 +4418,25 @@ bool SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, // Shape guard the holder. ObjOperandId holderId = objId; - if (!obj->isNative()) { - MOZ_ASSERT(obj->as().maybeExpando()); - holderId = writer.guardAndLoadUnboxedExpando(objId); - } writer.guardShape(holderId, oldShape); ShapeGuardProtoChain(writer, obj, objId); ObjectGroup* newGroup = obj->group(); - // Check if we have to change the object's group. If we're adding an - // unboxed expando property, we pass the expando object to AddAndStore*Slot. - // That's okay because we only have to do a group change if the object is a - // PlainObject. + // Check if we have to change the object's group. We only have to change from + // a partially to fully initialized group if the object is a PlainObject. bool changeGroup = oldGroup != newGroup; MOZ_ASSERT_IF(changeGroup, obj->is()); - if (holderOrExpando->isFixedSlot(propShape->slot())) { + if (holder->isFixedSlot(propShape->slot())) { size_t offset = NativeObject::getFixedSlotOffset(propShape->slot()); writer.addAndStoreFixedSlot(holderId, offset, rhsValId, propShape, changeGroup, newGroup); trackAttached("AddSlot"); } else { size_t offset = - holderOrExpando->dynamicSlotIndex(propShape->slot()) * sizeof(Value); + holder->dynamicSlotIndex(propShape->slot()) * sizeof(Value); uint32_t numOldSlots = NativeObject::dynamicSlotsCount(oldShape); uint32_t numNewSlots = NativeObject::dynamicSlotsCount(propShape); if (numOldSlots == numNewSlots) { @@ -4939,18 +4646,13 @@ bool GetIteratorIRGenerator::tryAttachNativeIterator(ObjOperandId objId, return false; } - MOZ_ASSERT(obj->isNative() || obj->is()); + MOZ_ASSERT(obj->isNative()); - // Guard on the receiver's shape/group. - Maybe expandoId; - TestMatchingReceiver(writer, obj, objId, &expandoId); + // Guard on the receiver's shape. + TestMatchingNativeReceiver(writer, &obj->as(), objId); - // Ensure the receiver or its expando object has no dense elements. - if (obj->isNative()) { - writer.guardNoDenseElements(objId); - } else if (expandoId) { - writer.guardNoDenseElements(*expandoId); - } + // Ensure the receiver has no dense elements. + writer.guardNoDenseElements(objId); // Do the same for the objects on the proto chain. GeneratePrototypeHoleGuards(writer, obj, objId, @@ -5341,7 +5043,7 @@ bool CallIRGenerator::getTemplateObjectForScripted(HandleFunction calleeFunc, MOZ_ASSERT(thisObject->nonCCWRealm() == calleeFunc->realm()); - if (thisObject->is() || thisObject->is()) { + if (thisObject->is()) { result.set(thisObject); } @@ -6710,8 +6412,7 @@ void NewObjectIRGenerator::trackAttached(const char* name) { bool NewObjectIRGenerator::tryAttachStub() { AutoAssertNoPendingException aanpe(cx_); - if (!templateObject_->is() && - templateObject_->as().hasDynamicSlots()) { + if (templateObject_->as().hasDynamicSlots()) { trackAttached(IRGenerator::NotAttached); return false; } diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 7f5b34c27126..a574d296e476 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -232,8 +232,6 @@ extern const uint32_t ArgLengths[]; _(GuardMagicValue, Id, Byte) \ _(GuardFrameHasNoArgumentsObject, None) \ _(GuardNoDenseElements, Id) \ - _(GuardNoUnboxedExpando, Id) \ - _(GuardAndLoadUnboxedExpando, Id, Id) \ _(GuardAndGetIndexFromString, Id, Id) \ _(GuardAndGetNumberFromString, Id, Id) \ _(GuardAndGetIterator, Id, Id, Field, Field) \ @@ -279,7 +277,6 @@ extern const uint32_t ArgLengths[]; _(AllocateAndStoreDynamicSlot, Id, Field, Id, Byte, Field, Field, Field) \ _(StoreTypedObjectReferenceProperty, Id, Field, Byte, Byte, Id) \ _(StoreTypedObjectScalarProperty, Id, Field, Byte, Byte, Id) \ - _(StoreUnboxedProperty, Id, Byte, Field, Id) \ _(StoreDenseElement, Id, Id, Id) \ _(StoreDenseElementHole, Id, Id, Id, Byte) \ _(ArrayPush, Id, Id) \ @@ -303,7 +300,6 @@ extern const uint32_t ArgLengths[]; /* The *Result ops load a value into the cache's result register. */ \ _(LoadFixedSlotResult, Id, Field) \ _(LoadDynamicSlotResult, Id, Field) \ - _(LoadUnboxedPropertyResult, Id, Byte, Field) \ _(LoadTypedObjectResult, Id, Byte, Byte, Field) \ _(LoadDenseElementResult, Id, Id) \ _(LoadDenseElementHoleResult, Id, Id) \ @@ -770,8 +766,7 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { void guardGroupForLayout(ObjOperandId obj, ObjectGroup* group) { // NOTE: Comment in guardGroupForTypeBarrier also applies. MOZ_ASSERT(!group->hasUncacheableClass()); - MOZ_ASSERT(IsUnboxedObjectClass(group->clasp()) || - IsTypedObjectClass(group->clasp())); + MOZ_ASSERT(IsTypedObjectClass(group->clasp())); guardGroup(obj, group); } void guardProto(ObjOperandId obj, JSObject* proto) { @@ -918,15 +913,6 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { void guardNoDenseElements(ObjOperandId obj) { writeOpWithOperandId(CacheOp::GuardNoDenseElements, obj); } - void guardNoUnboxedExpando(ObjOperandId obj) { - writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj); - } - ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) { - ObjOperandId res(nextOperandId_++); - writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj); - writeOperandId(res); - return res; - } ValOperandId loadStackValue(uint32_t idx) { ValOperandId res(nextOperandId_++); @@ -1064,13 +1050,6 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { buffer_.writeByte(uint32_t(type)); writeOperandId(rhs); } - void storeUnboxedProperty(ObjOperandId obj, JSValueType type, size_t offset, - ValOperandId rhs) { - writeOpWithOperandId(CacheOp::StoreUnboxedProperty, obj); - buffer_.writeByte(uint32_t(type)); - addStubField(offset, StubField::Type::RawWord); - writeOperandId(rhs); - } void storeDenseElement(ObjOperandId obj, Int32OperandId index, ValOperandId rhs) { writeOpWithOperandId(CacheOp::StoreDenseElement, obj); @@ -1377,12 +1356,6 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj); addStubField(offset, StubField::Type::RawWord); } - void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, - size_t offset) { - writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj); - buffer_.writeByte(uint32_t(type)); - addStubField(offset, StubField::Type::RawWord); - } void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout, uint32_t typeDescr) { MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX); @@ -1806,8 +1779,6 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator { uint32_t index, Int32OperandId indexId); bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId, uint32_t index, Int32OperandId indexId); - bool tryAttachUnboxedElementHole(HandleObject obj, ObjOperandId objId, - uint32_t index, Int32OperandId indexId); bool tryAttachGenericElement(HandleObject obj, ObjOperandId objId, uint32_t index, Int32OperandId indexId); diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index a7960dc836dc..7c0ae57f1d1a 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -1815,37 +1815,6 @@ bool CacheIRCompiler::emitGuardMagicValue() { return true; } -bool CacheIRCompiler::emitGuardNoUnboxedExpando() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - - FailurePath* failure; - if (!addFailurePath(&failure)) { - return false; - } - - Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando()); - masm.branchPtr(Assembler::NotEqual, expandoAddr, ImmWord(0), - failure->label()); - return true; -} - -bool CacheIRCompiler::emitGuardAndLoadUnboxedExpando() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - Register output = allocator.defineRegister(masm, reader.objOperandId()); - - FailurePath* failure; - if (!addFailurePath(&failure)) { - return false; - } - - Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando()); - masm.loadPtr(expandoAddr, output); - masm.branchTestPtr(Assembler::Zero, output, output, failure->label()); - return true; -} - bool CacheIRCompiler::emitGuardNoDetachedTypedObjects() { JitSpew(JitSpew_Codegen, __FUNCTION__); FailurePath* failure; diff --git a/js/src/jit/CacheIRCompiler.h b/js/src/jit/CacheIRCompiler.h index ff99fa14ffea..198f4ea2fcbd 100644 --- a/js/src/jit/CacheIRCompiler.h +++ b/js/src/jit/CacheIRCompiler.h @@ -41,8 +41,6 @@ namespace jit { _(GuardNotDOMProxy) \ _(GuardSpecificInt32Immediate) \ _(GuardMagicValue) \ - _(GuardNoUnboxedExpando) \ - _(GuardAndLoadUnboxedExpando) \ _(GuardNoDetachedTypedObjects) \ _(GuardNoDenseElements) \ _(GuardAndGetNumberFromString) \ diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index d944ca374583..63ff216fa1f8 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -1213,17 +1213,6 @@ bool IonCacheIRCompiler::emitCallNativeGetElementResult() { return true; } -bool IonCacheIRCompiler::emitLoadUnboxedPropertyResult() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - AutoOutputRegister output(*this); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - - JSValueType fieldType = reader.jsValueType(); - int32_t fieldOffset = int32StubField(reader.stubOffset()); - masm.loadUnboxedProperty(Address(obj, fieldOffset), fieldType, output); - return true; -} - bool IonCacheIRCompiler::emitGuardFrameHasNoArgumentsObject() { MOZ_CRASH("Baseline-specific op"); } @@ -1674,38 +1663,6 @@ bool IonCacheIRCompiler::emitAllocateAndStoreDynamicSlot() { return emitAddAndStoreSlotShared(CacheOp::AllocateAndStoreDynamicSlot); } -bool IonCacheIRCompiler::emitStoreUnboxedProperty() { - JitSpew(JitSpew_Codegen, __FUNCTION__); - Register obj = allocator.useRegister(masm, reader.objOperandId()); - JSValueType fieldType = reader.jsValueType(); - int32_t offset = int32StubField(reader.stubOffset()); - ConstantOrRegister val = - allocator.useConstantOrRegister(masm, reader.valOperandId()); - - Maybe scratch; - if (needsPostBarrier() && UnboxedTypeNeedsPostBarrier(fieldType)) { - scratch.emplace(allocator, masm); - } - - if (fieldType == JSVAL_TYPE_OBJECT && typeCheckInfo_->isSet()) { - FailurePath* failure; - if (!addFailurePath(&failure)) { - return false; - } - EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, - failure->label()); - } - - // Note that the storeUnboxedProperty call here is infallible, as the - // IR emitter is responsible for guarding on |val|'s type. - Address fieldAddr(obj, offset); - EmitICUnboxedPreBarrier(masm, fieldAddr, fieldType); - masm.storeUnboxedProperty(fieldAddr, fieldType, val, /* failure = */ nullptr); - if (needsPostBarrier() && UnboxedTypeNeedsPostBarrier(fieldType)) { - emitPostBarrierSlot(obj, val, scratch.ref()); - } - return true; -} bool IonCacheIRCompiler::emitStoreTypedObjectReferenceProperty() { JitSpew(JitSpew_Codegen, __FUNCTION__); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index b499c70610bc..fb82cdea91d9 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -505,266 +505,6 @@ template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, bool allowDouble, Register temp, Label* fail); -template -void MacroAssembler::loadUnboxedProperty(T address, JSValueType type, - TypedOrValueRegister output) { - switch (type) { - case JSVAL_TYPE_INT32: { - // Handle loading an int32 into a double reg. - if (output.type() == MIRType::Double) { - convertInt32ToDouble(address, output.typedReg().fpu()); - break; - } - MOZ_FALLTHROUGH; - } - - case JSVAL_TYPE_BOOLEAN: - case JSVAL_TYPE_STRING: { - Register outReg; - if (output.hasValue()) { - outReg = output.valueReg().scratchReg(); - } else { - MOZ_ASSERT(output.type() == MIRTypeFromValueType(type)); - outReg = output.typedReg().gpr(); - } - - switch (type) { - case JSVAL_TYPE_BOOLEAN: - load8ZeroExtend(address, outReg); - break; - case JSVAL_TYPE_INT32: - load32(address, outReg); - break; - case JSVAL_TYPE_STRING: - loadPtr(address, outReg); - break; - default: - MOZ_CRASH(); - } - - if (output.hasValue()) { - tagValue(type, outReg, output.valueReg()); - } - break; - } - - case JSVAL_TYPE_OBJECT: - if (output.hasValue()) { - Register scratch = output.valueReg().scratchReg(); - loadPtr(address, scratch); - - Label notNull, done; - branchPtr(Assembler::NotEqual, scratch, ImmWord(0), ¬Null); - - moveValue(NullValue(), output.valueReg()); - jump(&done); - - bind(¬Null); - tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg()); - - bind(&done); - } else { - // Reading null can't be possible here, as otherwise the result - // would be a value (either because null has been read before or - // because there is a barrier). - Register reg = output.typedReg().gpr(); - loadPtr(address, reg); -#ifdef DEBUG - Label ok; - branchTestPtr(Assembler::NonZero, reg, reg, &ok); - assumeUnreachable("Null not possible"); - bind(&ok); -#endif - } - break; - - case JSVAL_TYPE_DOUBLE: - // Note: doubles in unboxed objects are not accessed through other - // views and do not need canonicalization. - if (output.hasValue()) { - loadValue(address, output.valueReg()); - } else { - loadDouble(address, output.typedReg().fpu()); - } - break; - - default: - MOZ_CRASH(); - } -} - -template void MacroAssembler::loadUnboxedProperty(Address address, - JSValueType type, - TypedOrValueRegister output); - -template void MacroAssembler::loadUnboxedProperty(BaseIndex address, - JSValueType type, - TypedOrValueRegister output); - -static void StoreUnboxedFailure(MacroAssembler& masm, Label* failure) { - // Storing a value to an unboxed property is a fallible operation and - // the caller must provide a failure label if a particular unboxed store - // might fail. Sometimes, however, a store that cannot succeed (such as - // storing a string to an int32 property) will be marked as infallible. - // This can only happen if the code involved is unreachable. - if (failure) { - masm.jump(failure); - } else { - masm.assumeUnreachable("Incompatible write to unboxed property"); - } -} - -template -void MacroAssembler::storeUnboxedProperty(T address, JSValueType type, - const ConstantOrRegister& value, - Label* failure) { - switch (type) { - case JSVAL_TYPE_BOOLEAN: - if (value.constant()) { - if (value.value().isBoolean()) { - store8(Imm32(value.value().toBoolean()), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Boolean) { - store8(value.reg().typedReg().gpr(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - if (failure) { - branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), - failure); - } - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1, - type); - } - break; - - case JSVAL_TYPE_INT32: - if (value.constant()) { - if (value.value().isInt32()) { - store32(Imm32(value.value().toInt32()), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Int32) { - store32(value.reg().typedReg().gpr(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - if (failure) { - branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure); - } - storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4, - type); - } - break; - - case JSVAL_TYPE_DOUBLE: - if (value.constant()) { - if (value.value().isNumber()) { - ScratchDoubleScope fpscratch(*this); - loadConstantDouble(value.value().toNumber(), fpscratch); - storeDouble(fpscratch, address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::Int32) { - ScratchDoubleScope fpscratch(*this); - convertInt32ToDouble(value.reg().typedReg().gpr(), fpscratch); - storeDouble(fpscratch, address); - } else if (value.reg().type() == MIRType::Double) { - storeDouble(value.reg().typedReg().fpu(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - ValueOperand reg = value.reg().valueReg(); - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, reg, ¬Int32); - { - ScratchDoubleScope fpscratch(*this); - int32ValueToDouble(reg, fpscratch); - storeDouble(fpscratch, address); - } - jump(&end); - bind(¬Int32); - if (failure) { - branchTestDouble(Assembler::NotEqual, reg, failure); - } - storeValue(reg, address); - bind(&end); - } - break; - - case JSVAL_TYPE_OBJECT: - if (value.constant()) { - if (value.value().isObjectOrNull()) { - storePtr(ImmGCPtr(value.value().toObjectOrNull()), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - MOZ_ASSERT(value.reg().type() != MIRType::Null); - if (value.reg().type() == MIRType::Object) { - storePtr(value.reg().typedReg().gpr(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - if (failure) { - Label ok; - branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok); - branchTestObject(Assembler::NotEqual, value.reg().valueReg(), - failure); - bind(&ok); - } - storeUnboxedPayload(value.reg().valueReg(), address, - /* width = */ sizeof(uintptr_t), type); - } - break; - - case JSVAL_TYPE_STRING: - if (value.constant()) { - if (value.value().isString()) { - storePtr(ImmGCPtr(value.value().toString()), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else if (value.reg().hasTyped()) { - if (value.reg().type() == MIRType::String) { - storePtr(value.reg().typedReg().gpr(), address); - } else { - StoreUnboxedFailure(*this, failure); - } - } else { - if (failure) { - branchTestString(Assembler::NotEqual, value.reg().valueReg(), - failure); - } - storeUnboxedPayload(value.reg().valueReg(), address, - /* width = */ sizeof(uintptr_t), type); - } - break; - - default: - MOZ_CRASH(); - } -} - -template void MacroAssembler::storeUnboxedProperty( - Address address, JSValueType type, const ConstantOrRegister& value, - Label* failure); - -template void MacroAssembler::storeUnboxedProperty( - BaseIndex address, JSValueType type, const ConstantOrRegister& value, - Label* failure); - // Inlined version of gc::CheckAllocatorState that checks the bare essentials // and bails for anything that cannot be handled with our jit allocators. void MacroAssembler::checkAllocatorState(Label* fail) { @@ -1447,13 +1187,6 @@ void MacroAssembler::initGCThing(Register obj, Register temp, nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t); offset += sizeof(uintptr_t); } - } else if (templateObj.isUnboxedPlainObject()) { - MOZ_ASSERT(!templateObj.unboxedObjectHasExpando()); - storePtr(ImmPtr(nullptr), - Address(obj, UnboxedPlainObject::offsetOfExpando())); - if (initContents) { - initUnboxedObjectContents(obj, templateObj.unboxedObjectLayout()); - } } else { MOZ_CRASH("Unknown object"); } @@ -1474,25 +1207,6 @@ void MacroAssembler::initGCThing(Register obj, Register temp, #endif } -void MacroAssembler::initUnboxedObjectContents(Register object, - const UnboxedLayout& layout) { - // Initialize reference fields of the object, per UnboxedPlainObject::create. - if (const int32_t* list = layout.traceList()) { - while (*list != -1) { - storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty), - Address(object, UnboxedPlainObject::offsetOfData() + *list)); - list++; - } - list++; - while (*list != -1) { - storePtr(ImmWord(0), - Address(object, UnboxedPlainObject::offsetOfData() + *list)); - list++; - } - // Unboxed objects don't have Values to initialize. - MOZ_ASSERT(*(list + 1) == -1); - } -} void MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result, Label* fail) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 04e9bd01a16c..ab093f9ad8a5 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -39,7 +39,6 @@ #include "vm/ProxyObject.h" #include "vm/Shape.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" // [SMDOC] MacroAssembler multi-platform overview // @@ -2710,18 +2709,6 @@ class MacroAssembler : public MacroAssemblerSpecific { void memoryBarrierBefore(const Synchronization& sync); void memoryBarrierAfter(const Synchronization& sync); - // Load a property from an UnboxedPlainObject or UnboxedArrayObject. - template - void loadUnboxedProperty(T address, JSValueType type, - TypedOrValueRegister output); - - // Store a property to an UnboxedPlainObject, without triggering barriers. - // If failure is null, the value definitely has a type suitable for storing - // in the property. - template - void storeUnboxedProperty(T address, JSValueType type, - const ConstantOrRegister& value, Label* failure); - void debugAssertIsObject(const ValueOperand& val); void debugAssertObjHasFixedSlots(Register obj, Register scratch); @@ -2826,8 +2813,6 @@ class MacroAssembler : public MacroAssemblerSpecific { TypedArrayObject* templateObj, TypedArrayLength lengthKind); - void initUnboxedObjectContents(Register object, const UnboxedLayout& layout); - void newGCString(Register result, Register temp, Label* fail, bool attemptNursery); void newGCFatInlineString(Register result, Register temp, Label* fail, diff --git a/js/src/jit/TemplateObject-inl.h b/js/src/jit/TemplateObject-inl.h index 870f2c481665..242164d923fc 100644 --- a/js/src/jit/TemplateObject-inl.h +++ b/js/src/jit/TemplateObject-inl.h @@ -42,10 +42,6 @@ inline bool TemplateObject::isInlineTypedObject() const { return obj_->is(); } -inline bool TemplateObject::isUnboxedPlainObject() const { - return obj_->is(); -} - inline bool TemplateObject::isCallObject() const { return obj_->is(); } @@ -77,16 +73,6 @@ inline uint8_t* TemplateObject::getInlineTypedObjectMem( return obj_->as().inlineTypedMem(nogc); } -inline const UnboxedLayout& TemplateObject::unboxedObjectLayout() const { - return obj_->as().layoutDontCheckGeneration(); -} - -#ifdef DEBUG -inline bool TemplateObject::unboxedObjectHasExpando() const { - return obj_->as().maybeExpando(); -} -#endif - inline const NativeTemplateObject& TemplateObject::asNativeTemplateObject() const { MOZ_ASSERT(isNative()); diff --git a/js/src/jit/TemplateObject.h b/js/src/jit/TemplateObject.h index 14cf2ed83526..11c4f7c427cc 100644 --- a/js/src/jit/TemplateObject.h +++ b/js/src/jit/TemplateObject.h @@ -9,7 +9,6 @@ #include "vm/NativeObject.h" #include "vm/Shape.h" -#include "vm/UnboxedObject.h" namespace js { namespace jit { @@ -43,7 +42,6 @@ class TemplateObject { inline bool isTypedArrayObject() const; inline bool isRegExpObject() const; inline bool isInlineTypedObject() const; - inline bool isUnboxedPlainObject() const; inline bool isCallObject() const; inline bool isPlainObject() const; @@ -52,15 +50,10 @@ class TemplateObject { inline gc::Cell* group() const; inline gc::Cell* maybeShape() const; - // Some TypedObject and UnboxedPlainObject methods that can be called - // off-thread. + // Some TypedObjec methods that can be called off-thread. inline uint32_t getInlineTypedObjectSize() const; inline uint8_t* getInlineTypedObjectMem( const JS::AutoRequireNoGC& nogc) const; - inline const UnboxedLayout& unboxedObjectLayout() const; -#ifdef DEBUG - inline bool unboxedObjectHasExpando() const; -#endif }; class NativeTemplateObject : public TemplateObject { diff --git a/js/src/jit/VMFunctionList-inl.h b/js/src/jit/VMFunctionList-inl.h index 09362b15b0a0..6c614f3d7988 100644 --- a/js/src/jit/VMFunctionList-inl.h +++ b/js/src/jit/VMFunctionList-inl.h @@ -244,8 +244,6 @@ namespace jit { _(ToObjectSlow, js::ToObjectSlow) \ _(ToStringSlow, js::ToStringSlow) \ _(TrySkipAwait, js::jit::TrySkipAwait) \ - _(UnboxedPlainObjectConvertToNative, \ - js::UnboxedPlainObject::convertToNative) \ _(UrshValues, js::UrshValues) // The list below is for tail calls. The third argument specifies the number of diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 4c2760ec3028..3dbcbbe97287 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -30,7 +30,6 @@ #include "vm/NativeObject-inl.h" #include "vm/StringObject-inl.h" #include "vm/TypeInference-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::jit; @@ -1764,12 +1763,6 @@ bool HasNativeDataPropertyPure(JSContext* cx, JSObject* obj, Value* vp) { ClassMayResolveId(cx->names(), obj->getClass(), id, obj))) { return false; } - } else if (obj->is()) { - if (obj->as().containsUnboxedOrExpandoProperty(cx, - id)) { - vp[1].setBoolean(true); - return true; - } } else if (obj->is()) { if (obj->as().typeDescr().hasProperty(cx->names(), id)) { vp[1].setBoolean(true); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index f026990d87de..96d67444ad17 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -68,271 +68,7 @@ static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1; /* static */ bool UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) { - gc::AutoSuppressGC suppress(cx); - - using namespace jit; - - if (!cx->realm()->ensureJitRealmExists(cx)) { return false; - } - - AutoSweepObjectGroup sweep(group); - UnboxedLayout& layout = group->unboxedLayout(sweep); - MOZ_ASSERT(!layout.constructorCode()); - - UnboxedPlainObject* templateObject = - UnboxedPlainObject::create(cx, group, TenuredObject); - if (!templateObject) { - return false; - } - - JitContext jitContext(cx, nullptr); - - StackMacroAssembler masm; - - Register propertiesReg, newKindReg; -#ifdef JS_CODEGEN_X86 - propertiesReg = eax; - newKindReg = ecx; - masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg); - masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg); -#else - propertiesReg = IntArgReg0; - newKindReg = IntArgReg1; -#endif - -#ifdef JS_CODEGEN_ARM64 - // ARM64 communicates stack address via sp, but uses a pseudo-sp (PSP) for - // addressing. The register we use for PSP may however also be used by - // calling code, and it is nonvolatile, so save it. Do this as a special - // case first because the generic save/restore code needs the PSP to be - // initialized already. - MOZ_ASSERT(PseudoStackPointer64.Is(masm.GetStackPointer64())); - masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex)); - - // Initialize the PSP from the SP. - masm.initPseudoStackPtr(); -#endif - - MOZ_ASSERT(propertiesReg.volatile_()); - MOZ_ASSERT(newKindReg.volatile_()); - - AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); - regs.take(propertiesReg); - regs.take(newKindReg); - Register object = regs.takeAny(), scratch1 = regs.takeAny(), - scratch2 = regs.takeAny(); - - LiveGeneralRegisterSet savedNonVolatileRegisters = - SavedNonVolatileRegisters(regs); - masm.PushRegsInMask(savedNonVolatileRegisters); - - // The scratch double register might be used by MacroAssembler methods. - if (ScratchDoubleReg.volatile_()) { - masm.push(ScratchDoubleReg); - } - - Label failure, tenuredObject, allocated, unknownProperties; - masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), - &tenuredObject); - - masm.load32(AbsoluteAddress(group->addressOfFlags()), scratch1); - masm.branchTest32(Assembler::NonZero, scratch1, - Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), &unknownProperties); - masm.branchTest32(Assembler::NonZero, scratch1, Imm32(OBJECT_FLAG_PRE_TENURE), - &tenuredObject); - masm.bind(&unknownProperties); - - // Allocate an object in the nursery - TemplateObject templateObj(templateObject); - masm.createGCObject(object, scratch1, templateObj, gc::DefaultHeap, &failure, - /* initFixedSlots = */ false); - - masm.jump(&allocated); - masm.bind(&tenuredObject); - - // Allocate an object in the tenured heap. - masm.createGCObject(object, scratch1, templateObj, gc::TenuredHeap, &failure, - /* initFixedSlots = */ false); - - // If any of the properties being stored are in the nursery, add a store - // buffer entry for the new object. - Label postBarrier; - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - if (!UnboxedTypeNeedsPostBarrier(property.type)) { - continue; - } - - Address valueAddress( - propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value)); - if (property.type == JSVAL_TYPE_OBJECT) { - Label notObject; - masm.branchTestObject(Assembler::NotEqual, valueAddress, ¬Object); - Register valueObject = masm.extractObject(valueAddress, scratch1); - masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, - &postBarrier); - masm.bind(¬Object); - } else { - MOZ_ASSERT(property.type == JSVAL_TYPE_STRING); - Label notString; - masm.branchTestString(Assembler::NotEqual, valueAddress, ¬String); - masm.unboxString(valueAddress, scratch1); - masm.branchPtrInNurseryChunk(Assembler::Equal, scratch1, scratch2, - &postBarrier); - masm.bind(¬String); - } - } - - masm.jump(&allocated); - masm.bind(&postBarrier); - - LiveGeneralRegisterSet liveVolatileRegisters; - liveVolatileRegisters.add(propertiesReg); - if (object.volatile_()) { - liveVolatileRegisters.add(object); - } - masm.PushRegsInMask(liveVolatileRegisters); - - masm.mov(ImmPtr(cx->runtime()), scratch1); - masm.setupUnalignedABICall(scratch2); - masm.passABIArg(scratch1); - masm.passABIArg(object); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier)); - - masm.PopRegsInMask(liveVolatileRegisters); - - masm.bind(&allocated); - - ValueOperand valueOperand; -#ifdef JS_NUNBOX32 - valueOperand = ValueOperand(scratch1, scratch2); -#else - valueOperand = ValueOperand(scratch1); -#endif - - Label failureStoreOther, failureStoreObject; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - Address valueAddress( - propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value)); - Address targetAddress(object, - UnboxedPlainObject::offsetOfData() + property.offset); - - masm.loadValue(valueAddress, valueOperand); - - if (property.type == JSVAL_TYPE_OBJECT) { - HeapTypeSet* types = - group->maybeGetProperty(sweep, IdToTypeId(NameToId(property.name))); - - Label notObject; - masm.branchTestObject(Assembler::NotEqual, valueOperand, - types->mightBeMIRType(MIRType::Null) - ? ¬Object - : &failureStoreObject); - - Register payloadReg = masm.extractObject(valueOperand, scratch1); - - if (!types->hasType(TypeSet::AnyObjectType())) { - Register scratch = (payloadReg == scratch1) ? scratch2 : scratch1; - masm.guardObjectType(payloadReg, types, scratch, payloadReg, - &failureStoreObject); - } - - masm.storeUnboxedProperty( - targetAddress, JSVAL_TYPE_OBJECT, - TypedOrValueRegister(MIRType::Object, AnyRegister(payloadReg)), - nullptr); - - if (notObject.used()) { - Label done; - masm.jump(&done); - masm.bind(¬Object); - masm.branchTestNull(Assembler::NotEqual, valueOperand, - &failureStoreOther); - masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, NullValue(), - nullptr); - masm.bind(&done); - } - } else { - masm.storeUnboxedProperty(targetAddress, property.type, - ConstantOrRegister(valueOperand), - &failureStoreOther); - } - } - - Label done; - masm.bind(&done); - - if (object != ReturnReg) { - masm.movePtr(object, ReturnReg); - } - - // Restore non-volatile registers which were saved on entry. - if (ScratchDoubleReg.volatile_()) { - masm.pop(ScratchDoubleReg); - } - masm.PopRegsInMask(savedNonVolatileRegisters); - -#ifdef JS_CODEGEN_ARM64 - // Now restore the value that was in the PSP register on entry, and return. - - // Obtain the correct SP from the PSP. - masm.Mov(sp, PseudoStackPointer64); - - // Restore the saved value of the PSP register, this value is whatever the - // caller had saved in it, not any actual SP value, and it must not be - // overwritten subsequently. - masm.Ldr(PseudoStackPointer64, vixl::MemOperand(sp, 16, vixl::PostIndex)); - - // Perform a plain Ret(), as abiret() will move SP <- PSP and that is wrong. - masm.Ret(vixl::lr); -#else - masm.abiret(); -#endif - - masm.bind(&failureStoreOther); - - // There was a failure while storing a value which cannot be stored at all - // in the unboxed object. Initialize the object so it is safe for GC and - // return null. - masm.initUnboxedObjectContents(object, - templateObject->layoutDontCheckGeneration()); - - masm.bind(&failure); - - masm.movePtr(ImmWord(0), object); - masm.jump(&done); - - masm.bind(&failureStoreObject); - - // There was a failure while storing a value to an object slot of the - // unboxed object. If the value is storable, the failure occurred due to - // incomplete type information in the object, so return a token to trigger - // regeneration of the jitcode after a new object is created in the VM. - { - Label isObject; - masm.branchTestObject(Assembler::Equal, valueOperand, &isObject); - masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther); - masm.bind(&isObject); - } - - // Initialize the object so it is safe for GC. - masm.initUnboxedObjectContents(object, - templateObject->layoutDontCheckGeneration()); - - masm.movePtr(ImmWord(CLEAR_CONSTRUCTOR_CODE_TOKEN), object); - masm.jump(&done); - - Linker linker(masm, "UnboxedObject"); - JitCode* code = linker.newCode(cx, CodeKind::Other); - if (!code) { - return false; - } - - layout.setConstructorCode(code); - return true; } void UnboxedLayout::detachFromRealm() {