mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Specialize big typed arrays with singleton types, bug 762561. r=dvander
This commit is contained in:
parent
947d4ffd7e
commit
3a5a434a81
@ -771,6 +771,8 @@ TypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter)
|
||||
static inline const Shape *
|
||||
GetSingletonShape(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
return NULL;
|
||||
const Shape *shape = obj->nativeLookup(cx, id);
|
||||
if (shape && shape->hasDefaultGetter() && shape->hasSlot())
|
||||
return shape;
|
||||
@ -1932,27 +1934,26 @@ types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
}
|
||||
|
||||
bool
|
||||
types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey key)
|
||||
{
|
||||
/*
|
||||
* Objects created outside loops in global and eval scripts should have
|
||||
* singleton types. For now this is only done for plain objects, not arrays.
|
||||
* singleton types. For now this is only done for plain objects and typed
|
||||
* arrays, but not normal arrays.
|
||||
*/
|
||||
|
||||
if (!cx->typeInferenceEnabled() || script->function())
|
||||
return false;
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
if (op == JSOP_NEWOBJECT || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Object)) {
|
||||
AutoEnterTypeInference enter(cx);
|
||||
if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
|
||||
return false;
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL))
|
||||
return false;
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
return !script->analysis()->getCode(pc).inLoop;
|
||||
}
|
||||
if (!script->ensureRanAnalysis(cx, NULL))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
return !script->analysis()->getCode(pc).inLoop;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2701,7 +2702,7 @@ TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
|
||||
UpdatePropertyType(cx, &base->types, singleton, shape, true);
|
||||
shape = shape->previous();
|
||||
}
|
||||
} else if (!JSID_IS_EMPTY(id)) {
|
||||
} else if (!JSID_IS_EMPTY(id) && singleton->isNative()) {
|
||||
const Shape *shape = singleton->nativeLookup(cx, id);
|
||||
if (shape)
|
||||
UpdatePropertyType(cx, &base->types, singleton, shape, false);
|
||||
@ -3110,14 +3111,16 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
if (!script->hasGlobal())
|
||||
return NULL;
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc))
|
||||
return NULL;
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
|
||||
|
||||
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
|
||||
return TypeScript::InitObject(cx, script, pc, isArray ? JSProto_Array : JSProto_Object);
|
||||
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc, key))
|
||||
return NULL;
|
||||
|
||||
return TypeScript::InitObject(cx, script, pc, key);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3756,7 +3759,10 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
TypeSet *types = script->analysis()->bytecodeTypes(pc);
|
||||
types->addSubset(cx, &pushed[0]);
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc)) {
|
||||
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
|
||||
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc, key)) {
|
||||
/* Defer types pushed by this bytecode until runtime. */
|
||||
break;
|
||||
}
|
||||
@ -5534,8 +5540,8 @@ JSObject::makeLazyType(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(hasLazyType());
|
||||
|
||||
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
|
||||
JSProto_Object, getProto());
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(getClass());
|
||||
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, key, getProto());
|
||||
if (!type) {
|
||||
if (cx->typeInferenceEnabled())
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
@ -5578,16 +5584,6 @@ JSObject::makeLazyType(JSContext *cx)
|
||||
if (getClass()->ext.equality)
|
||||
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
|
||||
|
||||
if (type->unknownProperties()) {
|
||||
type_ = type;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not yet generating singleton arrays. */
|
||||
type->flags |= OBJECT_FLAG_NON_DENSE_ARRAY
|
||||
| OBJECT_FLAG_NON_PACKED_ARRAY
|
||||
| OBJECT_FLAG_NON_TYPED_ARRAY;
|
||||
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
|
@ -871,7 +871,7 @@ UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
/* Whether to use a new type object for an initializer opcode at script/pc. */
|
||||
bool
|
||||
UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey key);
|
||||
|
||||
/*
|
||||
* Whether Array.prototype, or an object on its proto chain, has an
|
||||
|
@ -531,7 +531,7 @@ struct AllocationSiteKey {
|
||||
/* static */ inline TypeObject *
|
||||
TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
|
||||
{
|
||||
JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc));
|
||||
JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc, kind));
|
||||
|
||||
/* :XXX: Limit script->length so we don't need to check the offset up front? */
|
||||
uint32_t offset = pc - script->code;
|
||||
@ -561,7 +561,10 @@ SetInitializerObjectType(JSContext *cx, JSScript *script, jsbytecode *pc, JSObje
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return true;
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc)) {
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
||||
JS_ASSERT(key != JSProto_Null);
|
||||
|
||||
if (UseNewTypeForInitializer(cx, script, pc, key)) {
|
||||
if (!obj->setSingletonType(cx))
|
||||
return false;
|
||||
|
||||
@ -572,7 +575,6 @@ SetInitializerObjectType(JSContext *cx, JSScript *script, jsbytecode *pc, JSObje
|
||||
*/
|
||||
TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
|
||||
} else {
|
||||
JSProtoKey key = obj->isDenseArray() ? JSProto_Array : JSProto_Object;
|
||||
types::TypeObject *type = TypeScript::InitObject(cx, script, pc, key);
|
||||
if (!type)
|
||||
return false;
|
||||
@ -1333,35 +1335,29 @@ TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
|
||||
TypeObjectFlags flags = 0;
|
||||
|
||||
switch (key) {
|
||||
case JSProto_Function:
|
||||
JS_ASSERT(isFunction());
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case JSProto_Object:
|
||||
flags = OBJECT_FLAG_NON_DENSE_ARRAY
|
||||
| OBJECT_FLAG_NON_PACKED_ARRAY
|
||||
| OBJECT_FLAG_NON_TYPED_ARRAY;
|
||||
break;
|
||||
|
||||
case JSProto_Array:
|
||||
flags = OBJECT_FLAG_NON_TYPED_ARRAY;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* :XXX: abstract */
|
||||
JS_ASSERT(key == JSProto_Int8Array ||
|
||||
key == JSProto_Uint8Array ||
|
||||
key == JSProto_Int16Array ||
|
||||
key == JSProto_Uint16Array ||
|
||||
key == JSProto_Int32Array ||
|
||||
key == JSProto_Uint32Array ||
|
||||
key == JSProto_Float32Array ||
|
||||
key == JSProto_Float64Array ||
|
||||
key == JSProto_Uint8ClampedArray ||
|
||||
key == JSProto_DataView);
|
||||
case JSProto_Int8Array:
|
||||
case JSProto_Uint8Array:
|
||||
case JSProto_Int16Array:
|
||||
case JSProto_Uint16Array:
|
||||
case JSProto_Int32Array:
|
||||
case JSProto_Uint32Array:
|
||||
case JSProto_Float32Array:
|
||||
case JSProto_Float64Array:
|
||||
case JSProto_Uint8ClampedArray:
|
||||
case JSProto_DataView:
|
||||
flags = OBJECT_FLAG_NON_DENSE_ARRAY
|
||||
| OBJECT_FLAG_NON_PACKED_ARRAY;
|
||||
break;
|
||||
|
||||
default:
|
||||
flags = OBJECT_FLAG_NON_DENSE_ARRAY
|
||||
| OBJECT_FLAG_NON_PACKED_ARRAY
|
||||
| OBJECT_FLAG_NON_TYPED_ARRAY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasAllFlags(flags))
|
||||
|
@ -2786,10 +2786,13 @@ js_Object(JSContext *cx, unsigned argc, Value *vp)
|
||||
obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Object);
|
||||
if (!type)
|
||||
return JS_FALSE;
|
||||
obj->setType(type);
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
if (script) {
|
||||
/* Try to specialize the type of the object to the scripted call site. */
|
||||
if (!types::SetInitializerObjectType(cx, script, pc, obj))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
vp->setObject(*obj);
|
||||
return JS_TRUE;
|
||||
|
@ -1414,20 +1414,24 @@ class TypedArrayTemplate
|
||||
return NULL;
|
||||
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
|
||||
|
||||
types::TypeObject *type;
|
||||
if (proto) {
|
||||
type = proto->getNewType(cx);
|
||||
} else {
|
||||
/*
|
||||
* Specialize the type of the object on the current scripted location,
|
||||
* and mark the type as definitely a typed array.
|
||||
*/
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(protoClass());
|
||||
type = types::GetTypeCallerInitObject(cx, key);
|
||||
types::TypeObject *type = proto->getNewType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
obj->setType(type);
|
||||
} else if (cx->typeInferenceEnabled()) {
|
||||
if (len * sizeof(NativeType) >= TypedArray::SINGLETON_TYPE_BYTE_LENGTH) {
|
||||
if (!obj->setSingletonType(cx))
|
||||
return NULL;
|
||||
} else {
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
if (script) {
|
||||
if (!types::SetInitializerObjectType(cx, script, pc, obj))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->setType(type);
|
||||
|
||||
obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
|
||||
obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
|
||||
|
@ -251,6 +251,12 @@ struct TypedArray {
|
||||
return slotWidth(getType(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* Byte length above which created typed arrays and data views will have
|
||||
* singleton types regardless of the context in which they are created.
|
||||
*/
|
||||
static const uint32_t SINGLETON_TYPE_BYTE_LENGTH = 1024 * 1024 * 10;
|
||||
|
||||
static int lengthOffset();
|
||||
static int dataOffset();
|
||||
};
|
||||
|
@ -105,20 +105,24 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
types::TypeObject *type;
|
||||
if (proto) {
|
||||
type = proto->getNewType(cx);
|
||||
} else {
|
||||
/*
|
||||
* Specialize the type of the object on the current scripted location,
|
||||
* and mark the type as definitely a data view
|
||||
*/
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewClass);
|
||||
type = types::GetTypeCallerInitObject(cx, key);
|
||||
types::TypeObject *type = proto->getNewType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
obj->setType(type);
|
||||
} else if (cx->typeInferenceEnabled()) {
|
||||
if (byteLength >= TypedArray::SINGLETON_TYPE_BYTE_LENGTH) {
|
||||
if (!obj->setSingletonType(cx))
|
||||
return NULL;
|
||||
} else {
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
if (script) {
|
||||
if (!types::SetInitializerObjectType(cx, script, pc, obj))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->setType(type);
|
||||
|
||||
JS_ASSERT(arrayBuffer->isArrayBuffer());
|
||||
|
||||
|
@ -4784,6 +4784,13 @@ mjit::Compiler::jsop_getprop(PropertyName *name, JSValueType knownType,
|
||||
* The typed array length always fits in an int32.
|
||||
*/
|
||||
if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
|
||||
if (top->isConstant()) {
|
||||
JSObject *obj = &top->getValue().toObject();
|
||||
uint32_t length = TypedArray::getLength(obj);
|
||||
frame.pop();
|
||||
frame.push(Int32Value(length));
|
||||
return true;
|
||||
}
|
||||
bool isObject = top->isTypeKnown();
|
||||
if (!isObject) {
|
||||
Jump notObject = frame.testObject(Assembler::NotEqual, top);
|
||||
@ -6684,14 +6691,15 @@ mjit::Compiler::jsop_newinit()
|
||||
stubArg = (void *) baseobj;
|
||||
}
|
||||
|
||||
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
|
||||
|
||||
/*
|
||||
* Don't bake in types for non-compileAndGo scripts, or at initializers
|
||||
* producing objects with singleton types.
|
||||
*/
|
||||
RootedTypeObject type(cx);
|
||||
if (globalObj && !types::UseNewTypeForInitializer(cx, script, PC)) {
|
||||
type = types::TypeScript::InitObject(cx, script, PC,
|
||||
isArray ? JSProto_Array : JSProto_Object);
|
||||
if (globalObj && !types::UseNewTypeForInitializer(cx, script, PC, key)) {
|
||||
type = types::TypeScript::InitObject(cx, script, PC, key);
|
||||
if (!type)
|
||||
return false;
|
||||
}
|
||||
|
@ -1427,6 +1427,22 @@ mjit::Compiler::jsop_setelem_typed(int atype)
|
||||
FrameEntry *slotsFe = loop->invariantArraySlots(objv);
|
||||
objReg = frame.tempRegForData(slotsFe);
|
||||
frame.pinReg(objReg);
|
||||
} else if (obj->isConstant()) {
|
||||
JSObject *array = &obj->getValue().toObject();
|
||||
int32_t length = (int32_t) TypedArray::getLength(array);
|
||||
void *data = TypedArray::getDataOffset(array);
|
||||
|
||||
objReg = frame.allocReg();
|
||||
|
||||
if (key.isConstant()) {
|
||||
if (key.index() >= length)
|
||||
stubcc.linkExit(masm.jump(), Uses(2));
|
||||
} else {
|
||||
Jump lengthGuard = masm.branch32(Assembler::AboveOrEqual, key.reg(), Imm32(length));
|
||||
stubcc.linkExit(lengthGuard, Uses(2));
|
||||
}
|
||||
|
||||
masm.move(ImmPtr(data), objReg);
|
||||
} else {
|
||||
objReg = frame.copyDataIntoReg(obj);
|
||||
|
||||
@ -1519,8 +1535,6 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
return true;
|
||||
}
|
||||
|
||||
frame.forgetMismatchedObject(obj);
|
||||
|
||||
// If the object is definitely a dense array or a typed array we can generate
|
||||
// code directly without using an inline cache.
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
@ -1546,6 +1560,8 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
#endif
|
||||
}
|
||||
|
||||
frame.forgetMismatchedObject(obj);
|
||||
|
||||
if (id->isType(JSVAL_TYPE_DOUBLE) || !globalObj) {
|
||||
jsop_setelem_slow();
|
||||
return true;
|
||||
@ -2011,6 +2027,22 @@ mjit::Compiler::jsop_getelem_typed(int atype)
|
||||
FrameEntry *slotsFe = loop->invariantArraySlots(objv);
|
||||
objReg = frame.tempRegForData(slotsFe);
|
||||
frame.pinReg(objReg);
|
||||
} else if (obj->isConstant()) {
|
||||
JSObject *array = &obj->getValue().toObject();
|
||||
int32_t length = (int32_t) TypedArray::getLength(array);
|
||||
void *data = TypedArray::getDataOffset(array);
|
||||
|
||||
objReg = frame.allocReg();
|
||||
|
||||
if (key.isConstant()) {
|
||||
if (key.index() >= length)
|
||||
stubcc.linkExit(masm.jump(), Uses(2));
|
||||
} else {
|
||||
Jump lengthGuard = masm.branch32(Assembler::AboveOrEqual, key.reg(), Imm32(length));
|
||||
stubcc.linkExit(lengthGuard, Uses(2));
|
||||
}
|
||||
|
||||
masm.move(ImmPtr(data), objReg);
|
||||
} else {
|
||||
objReg = frame.copyDataIntoReg(obj);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user