mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 977126 Part 3 -- Inline SetTypedObjectOffset intrinsic r=shu
This commit is contained in:
parent
b766546539
commit
76a3bcf041
@ -2215,18 +2215,24 @@ TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
TypedObject::ownerOffset()
|
||||
TypedObject::offsetOfOwnerSlot()
|
||||
{
|
||||
return JSObject::getFixedSlotOffset(JS_TYPEDOBJ_SLOT_OWNER);
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
TypedObject::dataOffset()
|
||||
TypedObject::offsetOfDataSlot()
|
||||
{
|
||||
// the offset of 7 is based on the alloc kind
|
||||
return JSObject::getPrivateDataOffset(JS_TYPEDOBJ_SLOT_DATA);
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
TypedObject::offsetOfByteOffsetSlot()
|
||||
{
|
||||
return JSObject::getFixedSlotOffset(JS_TYPEDOBJ_SLOT_BYTEOFFSET);
|
||||
}
|
||||
|
||||
void
|
||||
TypedObject::neuter(void *newData)
|
||||
{
|
||||
@ -2712,12 +2718,21 @@ js::SetTypedObjectOffset(ThreadSafeContext *, unsigned argc, Value *vp)
|
||||
|
||||
typedObj.setPrivate(typedObj.owner().dataPointer() + offset);
|
||||
typedObj.setReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(offset));
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::SetTypedObjectOffsetJitInfo,
|
||||
bool
|
||||
js::intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
// Do not use JSNativeThreadSafeWrapper<> so that ion can reference
|
||||
// this function more easily when inlining.
|
||||
return SetTypedObjectOffset(cx, argc, vp);
|
||||
}
|
||||
|
||||
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::intrinsic_SetTypedObjectOffsetJitInfo,
|
||||
SetTypedObjectJitInfo,
|
||||
js::SetTypedObjectOffset);
|
||||
SetTypedObjectOffset);
|
||||
|
||||
bool
|
||||
js::ObjectIsTypeDescr(ThreadSafeContext *, unsigned argc, Value *vp)
|
||||
|
@ -585,7 +585,7 @@ class TypedObject : public ArrayBufferViewObject
|
||||
MutableHandleValue statep, MutableHandleId idp);
|
||||
|
||||
public:
|
||||
static size_t ownerOffset();
|
||||
static size_t offsetOfOwnerSlot();
|
||||
|
||||
// Each typed object contains a void* pointer pointing at the
|
||||
// binary data that it represents. (That data may be owned by this
|
||||
@ -593,7 +593,10 @@ class TypedObject : public ArrayBufferViewObject
|
||||
// This function returns the offset in bytes within the object
|
||||
// where the `void*` pointer can be found. It is intended for use
|
||||
// by the JIT.
|
||||
static size_t dataOffset();
|
||||
static size_t offsetOfDataSlot();
|
||||
|
||||
// Offset of the byte offset slot.
|
||||
static size_t offsetOfByteOffsetSlot();
|
||||
|
||||
// Helper for createUnattached()
|
||||
static TypedObject *createUnattachedWithClass(JSContext *cx,
|
||||
@ -742,8 +745,9 @@ extern const JSJitInfo AttachTypedObjectJitInfo;
|
||||
* Changes the offset for `typedObj` within its buffer to `offset`.
|
||||
* `typedObj` must already be attached.
|
||||
*/
|
||||
bool SetTypedObjectOffset(ThreadSafeContext *cx, unsigned argc, Value *vp);
|
||||
extern const JSJitInfo SetTypedObjectOffsetJitInfo;
|
||||
bool intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool SetTypedObjectOffset(ThreadSafeContext *, unsigned argc, Value *vp);
|
||||
extern const JSJitInfo intrinsic_SetTypedObjectOffsetJitInfo;
|
||||
|
||||
/*
|
||||
* Usage: ObjectIsTypeDescr(obj)
|
||||
|
@ -4112,7 +4112,7 @@ CodeGenerator::visitNeuterCheck(LNeuterCheck *lir)
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
masm.extractObject(Address(obj, TypedObject::ownerOffset()), temp);
|
||||
masm.extractObject(Address(obj, TypedObject::offsetOfOwnerSlot()), temp);
|
||||
masm.unboxInt32(Address(temp, ArrayBufferObject::flagsOffset()), temp);
|
||||
masm.and32(Imm32(ArrayBufferObject::neuteredFlag()), temp);
|
||||
|
||||
@ -4126,7 +4126,56 @@ CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
|
||||
{
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register out = ToRegister(lir->output());
|
||||
masm.loadPtr(Address(obj, TypedObject::dataOffset()), out);
|
||||
masm.loadPtr(Address(obj, TypedObject::offsetOfDataSlot()), out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset *lir)
|
||||
{
|
||||
Register object = ToRegister(lir->object());
|
||||
Register offset = ToRegister(lir->offset());
|
||||
Register temp0 = ToRegister(lir->temp0());
|
||||
|
||||
// `offset` is an absolute offset into the base buffer. One way
|
||||
// to implement this instruction would be load the base address
|
||||
// from the buffer and add `offset`. But that'd be an extra load.
|
||||
// We can instead load the current base pointer and current
|
||||
// offset, compute the difference with `offset`, and then adjust
|
||||
// the current base pointer. This is two loads but to adjacent
|
||||
// fields in the same object, which should come in the same cache
|
||||
// line.
|
||||
//
|
||||
// The C code I would probably write is the following:
|
||||
//
|
||||
// void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
|
||||
// int32_t temp0 = obj->byteOffset;
|
||||
// obj->pointer = obj->pointer - temp0 + offset;
|
||||
// obj->byteOffset = offset;
|
||||
// }
|
||||
//
|
||||
// But what we actually compute is more like this, because it
|
||||
// saves us a temporary to do it this way:
|
||||
//
|
||||
// void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
|
||||
// int32_t temp0 = obj->byteOffset;
|
||||
// obj->pointer = obj->pointer - (temp0 - offset);
|
||||
// obj->byteOffset = offset;
|
||||
// }
|
||||
|
||||
// temp0 = typedObj->byteOffset;
|
||||
masm.unboxInt32(Address(object, TypedObject::offsetOfByteOffsetSlot()), temp0);
|
||||
|
||||
// temp0 -= offset;
|
||||
masm.subPtr(offset, temp0);
|
||||
|
||||
// obj->pointer -= temp0;
|
||||
masm.subPtr(temp0, Address(object, TypedObject::offsetOfDataSlot()));
|
||||
|
||||
// obj->byteOffset = offset;
|
||||
masm.storeValue(JSVAL_TYPE_INT32, offset,
|
||||
Address(object, TypedObject::offsetOfByteOffsetSlot()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -167,6 +167,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitTypedArrayElements(LTypedArrayElements *lir);
|
||||
bool visitNeuterCheck(LNeuterCheck *lir);
|
||||
bool visitTypedObjectElements(LTypedObjectElements *lir);
|
||||
bool visitSetTypedObjectOffset(LSetTypedObjectOffset *lir);
|
||||
bool visitStringLength(LStringLength *lir);
|
||||
bool visitInitializedLength(LInitializedLength *lir);
|
||||
bool visitSetInitializedLength(LSetInitializedLength *lir);
|
||||
|
@ -696,6 +696,7 @@ class IonBuilder : public MIRGenerator
|
||||
|
||||
// TypedObject intrinsics.
|
||||
InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
|
||||
InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
|
||||
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
|
||||
ScalarTypeDescr::Type *arrayType);
|
||||
|
||||
|
@ -3725,6 +3725,31 @@ class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
|
||||
}
|
||||
};
|
||||
|
||||
// Load a typed array's elements vector.
|
||||
class LSetTypedObjectOffset : public LInstructionHelper<0, 2, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SetTypedObjectOffset)
|
||||
|
||||
LSetTypedObjectOffset(const LAllocation &object,
|
||||
const LAllocation &offset,
|
||||
const LDefinition &temp0)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, offset);
|
||||
setTemp(0, temp0);
|
||||
}
|
||||
const LAllocation *object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation *offset() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LDefinition *temp0() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Check whether a typed object has a neutered owner buffer.
|
||||
class LNeuterCheck : public LInstructionHelper<0, 1, 1>
|
||||
{
|
||||
|
@ -249,6 +249,7 @@
|
||||
_(TypedArrayLength) \
|
||||
_(TypedArrayElements) \
|
||||
_(TypedObjectElements) \
|
||||
_(SetTypedObjectOffset) \
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetFrameArgument) \
|
||||
|
@ -2378,6 +2378,16 @@ LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
|
||||
return define(new(alloc()) LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset *ins)
|
||||
{
|
||||
return add(new(alloc()) LSetTypedObjectOffset(
|
||||
useRegister(ins->object()),
|
||||
useRegister(ins->offset()),
|
||||
temp()),
|
||||
ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitInitializedLength(MInitializedLength *ins)
|
||||
{
|
||||
|
@ -178,6 +178,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitTypedArrayElements(MTypedArrayElements *ins);
|
||||
bool visitNeuterCheck(MNeuterCheck *lir);
|
||||
bool visitTypedObjectElements(MTypedObjectElements *ins);
|
||||
bool visitSetTypedObjectOffset(MSetTypedObjectOffset *ins);
|
||||
bool visitInitializedLength(MInitializedLength *ins);
|
||||
bool visitSetInitializedLength(MSetInitializedLength *ins);
|
||||
bool visitNot(MNot *ins);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "jsmath.h"
|
||||
|
||||
#include "builtin/TestingFunctions.h"
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "jit/BaselineInspector.h"
|
||||
#include "jit/IonBuilder.h"
|
||||
#include "jit/Lowering.h"
|
||||
@ -177,6 +178,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
|
||||
return inlineHasClass(callInfo, &SizedArrayTypeDescr::class_);
|
||||
if (native == intrinsic_TypeDescrIsUnsizedArrayType)
|
||||
return inlineHasClass(callInfo, &UnsizedArrayTypeDescr::class_);
|
||||
if (native == intrinsic_SetTypedObjectOffset)
|
||||
return inlineSetTypedObjectOffset(callInfo);
|
||||
|
||||
// Testing Functions
|
||||
if (native == testingFunc_inParallelSection)
|
||||
@ -1649,6 +1652,48 @@ IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSetTypedObjectOffset(CallInfo &callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinition *typedObj = callInfo.getArg(0);
|
||||
MDefinition *offset = callInfo.getArg(1);
|
||||
|
||||
// Return type should be undefined or something wacky is going on.
|
||||
if (getInlineReturnType() != MIRType_Undefined)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// Check typedObj is a, well, typed object. Go ahead and use TI
|
||||
// data. If this check should fail, that is almost certainly a bug
|
||||
// in self-hosted code -- either because it's not being careful
|
||||
// with TI or because of something else -- but we'll just let it
|
||||
// fall through to the SetTypedObjectOffset intrinsic in such
|
||||
// cases.
|
||||
types::TemporaryTypeSet *types = typedObj->resultTypeSet();
|
||||
if (typedObj->type() != MIRType_Object || !types)
|
||||
return InliningStatus_NotInlined;
|
||||
switch (types->forAllClasses(IsTypedObjectClass)) {
|
||||
case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
|
||||
case types::TemporaryTypeSet::ForAllResult::EMPTY:
|
||||
case types::TemporaryTypeSet::ForAllResult::MIXED:
|
||||
return InliningStatus_NotInlined;
|
||||
case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
|
||||
break;
|
||||
}
|
||||
|
||||
// Check type of offset argument is an integer.
|
||||
if (offset->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
MInstruction *ins = MSetTypedObjectOffset::New(alloc(), typedObj, offset);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
|
||||
{
|
||||
|
@ -1561,7 +1561,7 @@ class MAbortPar : public MAryControlInstruction<0, 0>
|
||||
MAbortPar()
|
||||
: MAryControlInstruction<0, 0>()
|
||||
{
|
||||
setResultType(MIRType_Undefined);
|
||||
setResultType(MIRType_None);
|
||||
setGuard();
|
||||
}
|
||||
|
||||
@ -5593,6 +5593,44 @@ class MTypedObjectElements
|
||||
}
|
||||
};
|
||||
|
||||
// Inlined version of the js::SetTypedObjectOffset() intrinsic.
|
||||
class MSetTypedObjectOffset
|
||||
: public MBinaryInstruction
|
||||
{
|
||||
private:
|
||||
MSetTypedObjectOffset(MDefinition *object, MDefinition *offset)
|
||||
: MBinaryInstruction(object, offset)
|
||||
{
|
||||
JS_ASSERT(object->type() == MIRType_Object);
|
||||
JS_ASSERT(offset->type() == MIRType_Int32);
|
||||
setResultType(MIRType_None);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SetTypedObjectOffset)
|
||||
|
||||
static MSetTypedObjectOffset *New(TempAllocator &alloc,
|
||||
MDefinition *object,
|
||||
MDefinition *offset)
|
||||
{
|
||||
return new(alloc) MSetTypedObjectOffset(object, offset);
|
||||
}
|
||||
|
||||
MDefinition *object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
MDefinition *offset() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const {
|
||||
// This affects the result of MTypedObjectElements,
|
||||
// which is described as a load of ObjectFields.
|
||||
return AliasSet::Store(AliasSet::ObjectFields);
|
||||
}
|
||||
};
|
||||
|
||||
// Perform !-operation
|
||||
class MNot
|
||||
: public MUnaryInstruction,
|
||||
|
@ -135,6 +135,7 @@ namespace jit {
|
||||
_(TypedArrayLength) \
|
||||
_(TypedArrayElements) \
|
||||
_(TypedObjectElements) \
|
||||
_(SetTypedObjectOffset) \
|
||||
_(InitializedLength) \
|
||||
_(SetInitializedLength) \
|
||||
_(Not) \
|
||||
|
@ -223,6 +223,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
SAFE_OP(TypedArrayLength)
|
||||
SAFE_OP(TypedArrayElements)
|
||||
SAFE_OP(TypedObjectElements)
|
||||
SAFE_OP(SetTypedObjectOffset)
|
||||
SAFE_OP(InitializedLength)
|
||||
WRITE_GUARDED_OP(SetInitializedLength, elements)
|
||||
SAFE_OP(Not)
|
||||
|
@ -748,8 +748,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JSNativeThreadSafeWrapper<js::AttachTypedObject>,
|
||||
&js::AttachTypedObjectJitInfo, 3, 0),
|
||||
JS_FNINFO("SetTypedObjectOffset",
|
||||
JSNativeThreadSafeWrapper<js::SetTypedObjectOffset>,
|
||||
&js::SetTypedObjectOffsetJitInfo, 2, 0),
|
||||
intrinsic_SetTypedObjectOffset,
|
||||
&js::intrinsic_SetTypedObjectOffsetJitInfo, 2, 0),
|
||||
JS_FNINFO("ObjectIsTypeDescr",
|
||||
intrinsic_ObjectIsTypeDescr,
|
||||
&js::ObjectIsTypeDescrJitInfo, 1, 0),
|
||||
|
Loading…
Reference in New Issue
Block a user