mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 973238 Part 4 -- Use prototype rather than reserved slot to uncover descriptor r=jandem
This commit is contained in:
parent
a51d6e0272
commit
00a3b11d2e
3
CLOBBER
3
CLOBBER
@ -22,5 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 904723 (Array.from) needs a clobber once again because of changes to js.msg
|
||||
and self-hosted code (see bug 1019955).
|
||||
Bug 973238 part 4 needs clobber due to self-hosted code (bug 1019955).
|
||||
|
@ -1483,7 +1483,6 @@ TypedObject::createUnattachedWithClass(JSContext *cx,
|
||||
obj->initReservedSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(length));
|
||||
obj->initReservedSlot(JS_BUFVIEW_SLOT_OWNER, NullValue());
|
||||
obj->initReservedSlot(JS_BUFVIEW_SLOT_NEXT_VIEW, PrivateValue(nullptr));
|
||||
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type));
|
||||
|
||||
// Tag the type object for this instance with the type
|
||||
// representation, if that has not been done already.
|
||||
@ -1637,9 +1636,6 @@ ReportTypedObjTypeError(JSContext *cx,
|
||||
/*static*/ void
|
||||
TypedObject::obj_trace(JSTracer *trace, JSObject *object)
|
||||
{
|
||||
gc::MarkSlot(trace, &object->getReservedSlotRef(JS_TYPEDOBJ_SLOT_TYPE_DESCR),
|
||||
"TypedObjectTypeDescr");
|
||||
|
||||
ArrayBufferViewObject::trace(trace, object);
|
||||
|
||||
JS_ASSERT(object->is<TypedObject>());
|
||||
|
@ -652,8 +652,12 @@ class TypedObject : public ArrayBufferViewObject
|
||||
return getReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObject().as<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
TypedProto &typedProto() const {
|
||||
return getProto()->as<TypedProto>();
|
||||
}
|
||||
|
||||
TypeDescr &typeDescr() const {
|
||||
return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
|
||||
return typedProto().typeDescr();
|
||||
}
|
||||
|
||||
uint8_t *typedMem() const {
|
||||
|
@ -28,12 +28,15 @@
|
||||
#define DESCR_STRUCT_FIELD_OFFSETS(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
|
||||
|
||||
// Typed prototype slots
|
||||
|
||||
#define TYPROTO_DESCR(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_TYPROTO_SLOT_DESCR)
|
||||
|
||||
// Typed object slots
|
||||
|
||||
#define TYPEDOBJ_BYTEOFFSET(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_BUFVIEW_SLOT_BYTEOFFSET))
|
||||
#define TYPEDOBJ_TYPE_DESCR(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_DESCR)
|
||||
#define TYPEDOBJ_OWNER(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_BUFVIEW_SLOT_OWNER)
|
||||
#define TYPEDOBJ_LENGTH(obj) \
|
||||
@ -42,6 +45,10 @@
|
||||
#define HAS_PROPERTY(obj, prop) \
|
||||
callFunction(std_Object_hasOwnProperty, obj, prop)
|
||||
|
||||
function TypedObjectTypeDescr(typedObj) {
|
||||
return TYPROTO_DESCR(typedObj.__proto__);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Getting values
|
||||
//
|
||||
@ -192,7 +199,7 @@ function TypedObjectSet(descr, typedObj, offset, fromValue) {
|
||||
// representation as the destination. In that case, we can just do a
|
||||
// memcpy.
|
||||
if (IsObject(fromValue) && ObjectIsTypedObject(fromValue)) {
|
||||
if (!descr.variable && DescrsEquiv(descr, TYPEDOBJ_TYPE_DESCR(fromValue))) {
|
||||
if (!descr.variable && DescrsEquiv(descr, TypedObjectTypeDescr(fromValue))) {
|
||||
if (!TypedObjectIsAttached(fromValue))
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
|
||||
|
||||
@ -386,7 +393,7 @@ function FillTypedArrayWithValue(destArray, fromValue) {
|
||||
assert(IsObject(handle) && ObjectIsTypedObject(destArray),
|
||||
"FillTypedArrayWithValue: not typed handle");
|
||||
|
||||
var descr = TYPEDOBJ_TYPE_DESCR(destArray);
|
||||
var descr = TypedObjectTypeDescr(destArray);
|
||||
var length = DESCR_SIZED_ARRAY_LENGTH(descr);
|
||||
if (length === 0)
|
||||
return;
|
||||
@ -440,7 +447,7 @@ function TypedArrayRedimension(newArrayType) {
|
||||
|
||||
// Peel away the outermost array layers from the type of `this` to find
|
||||
// the core element type. In the process, count the number of elements.
|
||||
var oldArrayType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var oldArrayType = TypedObjectTypeDescr(this);
|
||||
var oldArrayReprKind = DESCR_KIND(oldArrayType);
|
||||
var oldElementType = oldArrayType;
|
||||
var oldElementCount = 1;
|
||||
@ -507,7 +514,7 @@ function X4ToSource() {
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
|
||||
|
||||
var descr = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var descr = TypedObjectTypeDescr(this);
|
||||
|
||||
if (DESCR_KIND(descr) != JS_TYPEREPR_X4_KIND)
|
||||
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
|
||||
@ -570,7 +577,7 @@ function StorageOfTypedObject(obj) {
|
||||
return null;
|
||||
|
||||
if (ObjectIsTransparentTypedObject(obj)) {
|
||||
var descr = TYPEDOBJ_TYPE_DESCR(obj);
|
||||
var descr = TypedObjectTypeDescr(obj);
|
||||
var byteLength;
|
||||
if (DESCR_KIND(descr) == JS_TYPEREPR_UNSIZED_ARRAY_KIND)
|
||||
byteLength = DESCR_SIZE(descr.elementType) * obj.length;
|
||||
@ -593,7 +600,7 @@ function StorageOfTypedObject(obj) {
|
||||
// Warning: user exposed!
|
||||
function TypeOfTypedObject(obj) {
|
||||
if (IsObject(obj) && ObjectIsTypedObject(obj))
|
||||
return TYPEDOBJ_TYPE_DESCR(obj);
|
||||
return TypedObjectTypeDescr(obj);
|
||||
|
||||
// Note: Do not create bindings for `Any`, `String`, etc in
|
||||
// Utilities.js, but rather access them through
|
||||
@ -687,7 +694,7 @@ function TypedObjectArrayTypeFrom(a, b, c) {
|
||||
function TypedArrayMap(a, b) {
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
var thisType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var thisType = TypedObjectTypeDescr(this);
|
||||
if (!TypeDescrIsArrayType(thisType))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
|
||||
@ -707,7 +714,7 @@ function TypedArrayMapPar(a, b) {
|
||||
// when not working with typed objects.
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
return callFunction(TypedArrayMap, this, a, b);
|
||||
var thisType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var thisType = TypedObjectTypeDescr(this);
|
||||
if (!TypeDescrIsArrayType(thisType))
|
||||
return callFunction(TypedArrayMap, this, a, b);
|
||||
|
||||
@ -723,7 +730,7 @@ function TypedArrayReduce(a, b) {
|
||||
// Arguments: func, [initial]
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
var thisType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var thisType = TypedObjectTypeDescr(this);
|
||||
if (!TypeDescrIsArrayType(thisType))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
|
||||
@ -739,7 +746,7 @@ function TypedArrayScatter(a, b, c, d) {
|
||||
// Arguments: outputArrayType, indices, defaultValue, conflictFunction
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
var thisType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var thisType = TypedObjectTypeDescr(this);
|
||||
if (!TypeDescrIsArrayType(thisType))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
|
||||
@ -757,7 +764,7 @@ function TypedArrayFilter(func) {
|
||||
// Arguments: predicate
|
||||
if (!IsObject(this) || !ObjectIsTypedObject(this))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
var thisType = TYPEDOBJ_TYPE_DESCR(this);
|
||||
var thisType = TypedObjectTypeDescr(this);
|
||||
if (!TypeDescrIsArrayType(thisType))
|
||||
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
|
||||
@ -1140,7 +1147,7 @@ function RedirectPointer(typedObj, offset, outputIsScalar) {
|
||||
// is an overapproximation: users can manually declare opaque
|
||||
// types that nonetheless only contain scalar data.
|
||||
|
||||
typedObj = NewDerivedTypedObject(TYPEDOBJ_TYPE_DESCR(typedObj),
|
||||
typedObj = NewDerivedTypedObject(TypedObjectTypeDescr(typedObj),
|
||||
typedObj, 0);
|
||||
}
|
||||
|
||||
|
@ -108,9 +108,8 @@
|
||||
#define JS_TYPEDARR_SLOTS 5 // Number of slots for typed arrays
|
||||
|
||||
// Specific to typed objects:
|
||||
#define JS_TYPEDOBJ_SLOT_TYPE_DESCR 4 // A ScalarTypeDescr::Type constant
|
||||
#define JS_TYPEDOBJ_SLOT_DATA 7
|
||||
#define JS_TYPEDOBJ_SLOTS 5 // Number of slots for typed objs
|
||||
#define JS_TYPEDOBJ_SLOTS 4 // Number of slots for typed objs
|
||||
|
||||
// (*) The interpretation of the JS_BUFVIEW_SLOT_LENGTH slot depends on
|
||||
// the kind of view:
|
||||
|
13
js/src/jit-test/tests/TypedObject/prototypes.js
vendored
13
js/src/jit-test/tests/TypedObject/prototypes.js
vendored
@ -1,9 +1,12 @@
|
||||
// API Surface Test: check that mutating prototypes
|
||||
// of type descriptors has no effect.
|
||||
// of type objects has no effect, and that mutating
|
||||
// the prototypes of typed objects is an error.
|
||||
|
||||
if (!this.hasOwnProperty("TypedObject"))
|
||||
quit();
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
|
||||
|
||||
function main() { // once a C programmer, always a C programmer.
|
||||
@ -12,6 +15,14 @@ function main() { // once a C programmer, always a C programmer.
|
||||
Uints.prototype = {}; // no effect
|
||||
assertEq(p, Uints.prototype);
|
||||
|
||||
var uints = new Uints();
|
||||
assertEq(uints.__proto__, p);
|
||||
assertThrowsInstanceOf(function() uints.__proto__ = {},
|
||||
TypeError);
|
||||
assertThrowsInstanceOf(function() Object.setPrototypeOf(uints, {}),
|
||||
TypeError);
|
||||
assertEq(uints.__proto__, p);
|
||||
|
||||
var Uintss = Uints.array(2);
|
||||
var p = Uintss.prototype;
|
||||
Uintss.prototype = {}; // no effect
|
||||
|
@ -4383,6 +4383,23 @@ CodeGenerator::visitNeuterCheck(LNeuterCheck *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitTypedObjectProto(LTypedObjectProto *lir)
|
||||
{
|
||||
Register obj = ToRegister(lir->object());
|
||||
JS_ASSERT(ToRegister(lir->output()) == ReturnReg);
|
||||
|
||||
// Eventually we ought to inline this helper function for
|
||||
// efficiency, but it's mildly non-trivial since we must reach
|
||||
// into the type object and so on.
|
||||
|
||||
const Register tempReg = ToRegister(lir->temp());
|
||||
masm.setupUnalignedABICall(1, tempReg);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, TypedObjectProto));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
|
||||
{
|
||||
|
@ -174,6 +174,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitNeuterCheck(LNeuterCheck *lir);
|
||||
bool visitTypedObjectElements(LTypedObjectElements *lir);
|
||||
bool visitSetTypedObjectOffset(LSetTypedObjectOffset *lir);
|
||||
bool visitTypedObjectProto(LTypedObjectProto *ins);
|
||||
bool visitStringLength(LStringLength *lir);
|
||||
bool visitInitializedLength(LInitializedLength *lir);
|
||||
bool visitSetInitializedLength(LSetInitializedLength *lir);
|
||||
|
@ -10288,10 +10288,16 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
|
||||
if (typedObj->isNewDerivedTypedObject())
|
||||
return typedObj->toNewDerivedTypedObject()->type();
|
||||
|
||||
MInstruction *load = MLoadFixedSlot::New(alloc(), typedObj,
|
||||
JS_TYPEDOBJ_SLOT_TYPE_DESCR);
|
||||
MInstruction *proto = MTypedObjectProto::New(alloc(), typedObj);
|
||||
current->add(proto);
|
||||
|
||||
MInstruction *load = MLoadFixedSlot::New(alloc(), proto, JS_TYPROTO_SLOT_DESCR);
|
||||
current->add(load);
|
||||
return load;
|
||||
|
||||
MInstruction *unbox = MUnbox::New(alloc(), load, MIRType_Object, MUnbox::Infallible);
|
||||
current->add(unbox);
|
||||
|
||||
return unbox;
|
||||
}
|
||||
|
||||
// Given a typed object `typedObj` and an offset `offset` into that
|
||||
|
@ -3676,6 +3676,25 @@ class LTypedArrayElements : public LInstructionHelper<1, 1, 0>
|
||||
}
|
||||
};
|
||||
|
||||
// Load a typed object's prototype, which is guaranteed to be a
|
||||
// TypedProto object.
|
||||
class LTypedObjectProto : public LCallInstructionHelper<1, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(TypedObjectProto)
|
||||
|
||||
LTypedObjectProto(const LAllocation &object, const LDefinition &temp1) {
|
||||
setOperand(0, object);
|
||||
setTemp(0, temp1);
|
||||
}
|
||||
const LAllocation *object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Load a typed array's elements vector.
|
||||
class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
|
@ -249,6 +249,7 @@
|
||||
_(SetArrayLength) \
|
||||
_(TypedArrayLength) \
|
||||
_(TypedArrayElements) \
|
||||
_(TypedObjectProto) \
|
||||
_(TypedObjectElements) \
|
||||
_(SetTypedObjectOffset) \
|
||||
_(StringLength) \
|
||||
|
@ -2384,6 +2384,16 @@ LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
|
||||
return define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitTypedObjectProto(MTypedObjectProto *ins)
|
||||
{
|
||||
JS_ASSERT(ins->type() == MIRType_Object);
|
||||
return defineReturn(new(alloc()) LTypedObjectProto(
|
||||
useFixed(ins->object(), CallTempReg0),
|
||||
tempFixed(CallTempReg1)),
|
||||
ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
|
||||
{
|
||||
|
@ -182,6 +182,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitNeuterCheck(MNeuterCheck *lir);
|
||||
bool visitTypedObjectElements(MTypedObjectElements *ins);
|
||||
bool visitSetTypedObjectOffset(MSetTypedObjectOffset *ins);
|
||||
bool visitTypedObjectProto(MTypedObjectProto *ins);
|
||||
bool visitInitializedLength(MInitializedLength *ins);
|
||||
bool visitSetInitializedLength(MSetInitializedLength *ins);
|
||||
bool visitNot(MNot *ins);
|
||||
|
@ -1697,6 +1697,39 @@ class MNewPar : public MUnaryInstruction
|
||||
}
|
||||
};
|
||||
|
||||
class MTypedObjectProto
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy
|
||||
{
|
||||
private:
|
||||
MTypedObjectProto(MDefinition *object)
|
||||
: MUnaryInstruction(object)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(TypedObjectProto)
|
||||
|
||||
static MTypedObjectProto *New(TempAllocator &alloc, MDefinition *object) {
|
||||
return new(alloc) MTypedObjectProto(object);
|
||||
}
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
MDefinition *object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Load(AliasSet::ObjectFields);
|
||||
}
|
||||
};
|
||||
|
||||
// Creates a new derived type object. At runtime, this is just a call
|
||||
// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
|
||||
// compile to particularly optimized code. However, using a distinct
|
||||
|
@ -136,6 +136,7 @@ namespace jit {
|
||||
_(SetArrayLength) \
|
||||
_(TypedArrayLength) \
|
||||
_(TypedArrayElements) \
|
||||
_(TypedObjectProto) \
|
||||
_(TypedObjectElements) \
|
||||
_(SetTypedObjectOffset) \
|
||||
_(InitializedLength) \
|
||||
|
@ -224,6 +224,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
WRITE_GUARDED_OP(SetArrayLength, elements)
|
||||
SAFE_OP(TypedArrayLength)
|
||||
SAFE_OP(TypedArrayElements)
|
||||
SAFE_OP(TypedObjectProto)
|
||||
SAFE_OP(TypedObjectElements)
|
||||
SAFE_OP(SetTypedObjectOffset)
|
||||
SAFE_OP(InitializedLength)
|
||||
|
@ -1155,5 +1155,14 @@ AssertValidValue(JSContext *cx, Value *v)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Definition of the MTypedObjectProto MIR.
|
||||
JSObject *
|
||||
TypedObjectProto(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->is<TypedObject>());
|
||||
TypedObject &typedObj = obj->as<TypedObject>();
|
||||
return &typedObj.typedProto();
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -690,6 +690,8 @@ void AssertValidStringPtr(JSContext *cx, JSString *str);
|
||||
void AssertValidValue(JSContext *cx, Value *v);
|
||||
#endif
|
||||
|
||||
JSObject *TypedObjectProto(JSObject *obj);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user