From eb36b16c2d41a66f41c7f9d3028cb54ea2ea1daa Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Thu, 6 Oct 2016 14:58:35 +0200 Subject: [PATCH] Bug 1267163 - Port primitive value getprop stub to CacheIR. r=efaust --HG-- extra : rebase_source : 1a6d1a66695288fdfd83ea9f10f6d8aa60ad3c06 --- js/src/jit/BaselineCacheIR.cpp | 30 ++++++++ js/src/jit/BaselineInspector.cpp | 14 ++-- js/src/jit/CacheIR.cpp | 54 +++++++++++++ js/src/jit/CacheIR.h | 8 ++ js/src/jit/SharedIC.cpp | 125 ------------------------------- js/src/jit/SharedIC.h | 68 ----------------- js/src/jit/SharedICList.h | 1 - 7 files changed, 99 insertions(+), 201 deletions(-) diff --git a/js/src/jit/BaselineCacheIR.cpp b/js/src/jit/BaselineCacheIR.cpp index 63a982fe9cba..24023b45e5ef 100644 --- a/js/src/jit/BaselineCacheIR.cpp +++ b/js/src/jit/BaselineCacheIR.cpp @@ -694,6 +694,36 @@ BaselineCacheIRCompiler::emitGuardIsObject() return true; } +bool +BaselineCacheIRCompiler::emitGuardType() +{ + ValueOperand input = allocator.useRegister(masm, reader.valOperandId()); + JSValueType type = reader.valueType(); + + FailurePath* failure; + if (!addFailurePath(&failure)) + return false; + + switch (type) { + case JSVAL_TYPE_STRING: + masm.branchTestString(Assembler::NotEqual, input, failure->label()); + break; + case JSVAL_TYPE_SYMBOL: + masm.branchTestSymbol(Assembler::NotEqual, input, failure->label()); + break; + case JSVAL_TYPE_DOUBLE: + masm.branchTestNumber(Assembler::NotEqual, input, failure->label()); + break; + case JSVAL_TYPE_BOOLEAN: + masm.branchTestBoolean(Assembler::NotEqual, input, failure->label()); + break; + default: + MOZ_CRASH("Unexpected type"); + } + + return true; +} + bool BaselineCacheIRCompiler::emitGuardShape() { diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index afef10215cf6..6c12323ffb94 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -814,9 +814,13 @@ GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub) { CacheIRReader reader(stub->stubInfo()); - // For now, all CacheIR stubs expect an object. - MOZ_ALWAYS_TRUE(reader.matchOp(CacheOp::GuardIsObject, ObjOperandId(0))); - return MIRType::Object; + if (reader.matchOp(CacheOp::GuardIsObject, ValOperandId(0))) + return MIRType::Object; + if (reader.matchOp(CacheOp::GuardType, ValOperandId(0))) { + JSValueType type = reader.valueType(); + return MIRTypeFromValueType(type); + } + MOZ_CRASH("Unexpected instruction"); } MIRType @@ -870,10 +874,6 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) stubType = MIRType::Object; break; - case ICStub::GetProp_Primitive: - stubType = MIRTypeFromValueType(stub->toGetProp_Primitive()->primitiveType()); - break; - case ICStub::GetProp_StringLength: stubType = MIRType::String; break; diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 075f4b0eaefc..e1b44a09471f 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -68,8 +68,12 @@ GetPropIRGenerator::tryAttachStub(Maybe& writer) return false; if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId)) return false; + return true; } + if (!emitted_ && !tryAttachPrimitive(*writer, valId)) + return false; + return true; } @@ -415,3 +419,53 @@ GetPropIRGenerator::tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject EmitLoadSlotResult(writer, envId, env, shape); return true; } + +bool +GetPropIRGenerator::tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId) +{ + MOZ_ASSERT(!emitted_); + + JSValueType primitiveType; + RootedNativeObject proto(cx_); + if (val_.isString()) { + if (name_ == cx_->names().length) { + // String length is special-cased, see js::GetProperty. + return true; + } + primitiveType = JSVAL_TYPE_STRING; + proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_String)); + } else if (val_.isNumber()) { + primitiveType = JSVAL_TYPE_DOUBLE; + proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Number)); + } else if (val_.isBoolean()) { + primitiveType = JSVAL_TYPE_BOOLEAN; + proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Boolean)); + } else if (val_.isSymbol()) { + primitiveType = JSVAL_TYPE_SYMBOL; + proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Symbol)); + } else { + MOZ_ASSERT(val_.isNullOrUndefined() || val_.isMagic()); + return true; + } + if (!proto) + return true; + + // Instantiate this property, for use during Ion compilation. + RootedId id(cx_, NameToId(name_)); + if (IsIonEnabled(cx_)) + EnsureTrackPropertyTypes(cx_, proto, id); + + // For now, only look for properties directly set on the prototype. + Shape* shape = proto->lookup(cx_, id); + if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter()) + return true; + + writer.guardType(valId, primitiveType); + + ObjOperandId protoId = writer.loadObject(proto); + writer.guardShape(protoId, proto->lastProperty()); + EmitLoadSlotResult(writer, protoId, proto, shape); + + emitted_ = true; + return true; +} diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index d2c286269daf..e89db9968db3 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -80,6 +80,7 @@ class ObjOperandId : public OperandId #define CACHE_IR_OPS(_) \ _(GuardIsObject) \ + _(GuardType) \ _(GuardShape) \ _(GuardGroup) \ _(GuardProto) \ @@ -247,6 +248,11 @@ class MOZ_RAII CacheIRWriter writeOpWithOperandId(CacheOp::GuardIsObject, val); return ObjOperandId(val.id()); } + void guardType(ValOperandId val, JSValueType type) { + writeOpWithOperandId(CacheOp::GuardType, val); + MOZ_ASSERT(uint32_t(type) <= UINT8_MAX); + buffer_.writeByte(uint32_t(type)); + } void guardShape(ObjOperandId obj, Shape* shape) { writeOpWithOperandId(CacheOp::GuardShape, obj); addStubWord(uintptr_t(shape), StubField::GCType::Shape); @@ -422,6 +428,8 @@ class MOZ_RAII GetPropIRGenerator MOZ_MUST_USE bool tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId); + MOZ_MUST_USE bool tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId); + GetPropIRGenerator(const GetPropIRGenerator&) = delete; GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 8a99b231ce05..dd59df382b21 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -400,11 +400,6 @@ ICStub::trace(JSTracer* trc) TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value"); break; } - case ICStub::GetProp_Primitive: { - ICGetProp_Primitive* propStub = toGetProp_Primitive(); - TraceEdge(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape"); - break; - } case ICStub::GetProp_CallDOMProxyNative: case ICStub::GetProp_CallDOMProxyWithGenerationNative: { ICGetPropCallDOMProxyNativeStub* propStub; @@ -2544,61 +2539,6 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info, return true; } -static bool -TryAttachPrimitiveGetPropStub(JSContext* cx, SharedStubInfo* info, - ICGetProp_Fallback* stub, HandlePropertyName name, - HandleValue val, HandleValue res, bool* attached) -{ - MOZ_ASSERT(!*attached); - - JSValueType primitiveType; - RootedNativeObject proto(cx); - Rooted global(cx, &info->script()->global()); - if (val.isString()) { - primitiveType = JSVAL_TYPE_STRING; - proto = GlobalObject::getOrCreateStringPrototype(cx, global); - } else if (val.isSymbol()) { - primitiveType = JSVAL_TYPE_SYMBOL; - proto = GlobalObject::getOrCreateSymbolPrototype(cx, global); - } else if (val.isNumber()) { - primitiveType = JSVAL_TYPE_DOUBLE; - proto = GlobalObject::getOrCreateNumberPrototype(cx, global); - } else { - MOZ_ASSERT(val.isBoolean()); - primitiveType = JSVAL_TYPE_BOOLEAN; - proto = GlobalObject::getOrCreateBooleanPrototype(cx, global); - } - if (!proto) - return false; - - // Instantiate this property, for use during Ion compilation. - RootedId id(cx, NameToId(name)); - if (IsIonEnabled(cx)) - EnsureTrackPropertyTypes(cx, proto, id); - - // For now, only look for properties directly set on the prototype. - RootedShape shape(cx, proto->lookup(cx, id)); - if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter()) - return true; - - bool isFixedSlot; - uint32_t offset; - GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset); - - ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); - - JitSpew(JitSpew_BaselineIC, " Generating GetProp_Primitive stub"); - ICGetProp_Primitive::Compiler compiler(cx, info->engine(), monitorStub, primitiveType, proto, - isFixedSlot, offset); - ICStub* newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx))); - if (!newStub) - return false; - - stub->addNewStub(newStub); - *attached = true; - return true; -} - bool CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, JSObject** lastProto, size_t* protoChainDepthOut) @@ -2777,13 +2717,6 @@ DoGetPropFallback(JSContext* cx, void* payload, ICGetProp_Fallback* stub_, return true; - if (val.isString() || val.isNumber() || val.isBoolean()) { - if (!TryAttachPrimitiveGetPropStub(cx, &info, stub, name, val, res, &attached)) - return false; - if (attached) - return true; - } - MOZ_ASSERT(!attached); if (!isTemporarilyUnoptimizable) stub->noteUnoptimizableAccess(); @@ -2868,53 +2801,6 @@ ICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler& masm) return true; } -bool -ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler& masm) -{ - Label failure; - switch (primitiveType_) { - case JSVAL_TYPE_STRING: - masm.branchTestString(Assembler::NotEqual, R0, &failure); - break; - case JSVAL_TYPE_SYMBOL: - masm.branchTestSymbol(Assembler::NotEqual, R0, &failure); - break; - case JSVAL_TYPE_DOUBLE: // Also used for int32. - masm.branchTestNumber(Assembler::NotEqual, R0, &failure); - break; - case JSVAL_TYPE_BOOLEAN: - masm.branchTestBoolean(Assembler::NotEqual, R0, &failure); - break; - default: - MOZ_CRASH("unexpected type"); - } - - AllocatableGeneralRegisterSet regs(availableGeneralRegs(1)); - Register holderReg = regs.takeAny(); - Register scratchReg = regs.takeAny(); - - // Verify the shape of the prototype. - masm.movePtr(ImmGCPtr(prototype_.get()), holderReg); - - Address shapeAddr(ICStubReg, ICGetProp_Primitive::offsetOfProtoShape()); - masm.loadPtr(Address(holderReg, ShapedObject::offsetOfShape()), scratchReg); - masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure); - - if (!isFixedSlot_) - masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg); - - masm.load32(Address(ICStubReg, ICGetProp_Primitive::offsetOfOffset()), scratchReg); - masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0); - - // Enter type monitor IC to type-check result. - EmitEnterTypeMonitorIC(masm); - - // Failure case - jump to next stub - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - ICGetPropNativeStub* ICGetPropNativeCompiler::getStub(ICStubSpace* space) { @@ -3704,17 +3590,6 @@ BaselineScript::noteAccessedGetter(uint32_t pcOffset) stub->toGetProp_Fallback()->noteAccessedGetter(); } -ICGetProp_Primitive::ICGetProp_Primitive(JitCode* stubCode, ICStub* firstMonitorStub, - JSValueType primitiveType, Shape* protoShape, - uint32_t offset) - : ICMonitoredStub(GetProp_Primitive, stubCode, firstMonitorStub), - protoShape_(protoShape), - offset_(offset) -{ - extra_ = uint16_t(primitiveType); - MOZ_ASSERT(JSValueType(extra_) == primitiveType); -} - ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, uint32_t offset) diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index bece46d09bce..5399c3d3379d 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -2374,74 +2374,6 @@ class ICGetProp_Generic : public ICMonitoredStub }; }; -// Stub for accessing a property on a primitive's prototype. -class ICGetProp_Primitive : public ICMonitoredStub -{ - friend class ICStubSpace; - - protected: // Protected to silence Clang warning. - // Shape of String.prototype/Number.prototype to check for. - GCPtrShape protoShape_; - - // Fixed or dynamic slot offset. - uint32_t offset_; - - ICGetProp_Primitive(JitCode* stubCode, ICStub* firstMonitorStub, JSValueType primitiveType, - Shape* protoShape, uint32_t offset); - - public: - GCPtrShape& protoShape() { - return protoShape_; - } - JSValueType primitiveType() const { - return JSValueType(extra_); - } - - static size_t offsetOfProtoShape() { - return offsetof(ICGetProp_Primitive, protoShape_); - } - - static size_t offsetOfOffset() { - return offsetof(ICGetProp_Primitive, offset_); - } - - class Compiler : public ICStubCompiler { - ICStub* firstMonitorStub_; - JSValueType primitiveType_; - RootedObject prototype_; - bool isFixedSlot_; - uint32_t offset_; - - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm); - - protected: - virtual int32_t getKey() const { - static_assert(sizeof(JSValueType) == 1, "JSValueType should fit in one byte"); - return static_cast(engine_) | - (static_cast(kind) << 1) | - (static_cast(isFixedSlot_) << 17) | - (static_cast(primitiveType_) << 25); - } - - public: - Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub, JSValueType primitiveType, - HandleObject prototype, bool isFixedSlot, uint32_t offset) - : ICStubCompiler(cx, ICStub::GetProp_Primitive, engine), - firstMonitorStub_(firstMonitorStub), - primitiveType_(primitiveType), - prototype_(cx, prototype), - isFixedSlot_(isFixedSlot), - offset_(offset) - {} - - ICStub* getStub(ICStubSpace* space) { - RootedShape protoShape(cx, prototype_->as().lastProperty()); - return newStub(space, getStubCode(), firstMonitorStub_, - primitiveType_, protoShape, offset_); - } - }; -}; - // Stub for accessing a string's length. class ICGetProp_StringLength : public ICStub { diff --git a/js/src/jit/SharedICList.h b/js/src/jit/SharedICList.h index c71ad26f931e..08e4e2705cbd 100644 --- a/js/src/jit/SharedICList.h +++ b/js/src/jit/SharedICList.h @@ -35,7 +35,6 @@ namespace jit { _(Compare_Int32WithBoolean) \ \ _(GetProp_Fallback) \ - _(GetProp_Primitive) \ _(GetProp_StringLength) \ _(GetProp_CallScripted) \ _(GetProp_CallNative) \