Bug 977126 Part 3 -- Inline SetTypedObjectOffset intrinsic r=shu

This commit is contained in:
Nicholas D. Matsakis 2014-03-20 10:04:46 -04:00
parent b766546539
commit 76a3bcf041
14 changed files with 205 additions and 13 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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>
{

View File

@ -249,6 +249,7 @@
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(StringLength) \
_(ArgumentsLength) \
_(GetFrameArgument) \

View File

@ -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)
{

View File

@ -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);

View File

@ -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)
{

View File

@ -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,

View File

@ -135,6 +135,7 @@ namespace jit {
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(InitializedLength) \
_(SetInitializedLength) \
_(Not) \

View File

@ -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)

View File

@ -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),