mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Track multiple types when monitoring SETPROP/SETNAME and calls, bug 641714.
This commit is contained in:
parent
57802e99bd
commit
d10d0da404
@ -2173,6 +2173,7 @@ public:
|
||||
inline bool addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
|
||||
inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
|
||||
inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
|
||||
inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::ClonedTypeSet *types);
|
||||
|
||||
/* Get the type to use for objects with no prototype. */
|
||||
inline js::types::TypeObject *getTypeEmpty();
|
||||
|
@ -364,6 +364,27 @@ struct AnalyzeState {
|
||||
// TypeSet
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
TypeSet::addTypeSet(JSContext *cx, ClonedTypeSet *types)
|
||||
{
|
||||
if (types->typeFlags & TYPE_FLAG_UNKNOWN) {
|
||||
addType(cx, TYPE_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
for (jstype type = TYPE_UNDEFINED; type <= TYPE_STRING; type++) {
|
||||
if (types->typeFlags & (1 << type))
|
||||
addType(cx, type);
|
||||
}
|
||||
|
||||
if (types->objectCount >= 2) {
|
||||
for (unsigned i = 0; i < types->objectCount; i++)
|
||||
addType(cx, (jstype) types->objectSet[i]);
|
||||
} else if (types->objectCount == 1) {
|
||||
addType(cx, (jstype) types->objectSet);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
TypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
|
||||
{
|
||||
@ -1277,14 +1298,14 @@ TypeConstraintCondensed::arrayNotPacked(JSContext *cx, bool notDense)
|
||||
}
|
||||
|
||||
/* Constraint which triggers recompilation of a script if any type is added to a type set. */
|
||||
class TypeConstraintFreezeSingleType : public TypeConstraint
|
||||
class TypeConstraintFreeze : public TypeConstraint
|
||||
{
|
||||
public:
|
||||
/* Whether a second type has already been added, triggering recompilation. */
|
||||
/* Whether a new type has already been added, triggering recompilation. */
|
||||
bool typeAdded;
|
||||
|
||||
TypeConstraintFreezeSingleType(JSScript *script)
|
||||
: TypeConstraint("freezeSingleType", script), typeAdded(false)
|
||||
TypeConstraintFreeze(JSScript *script)
|
||||
: TypeConstraint("freeze", script), typeAdded(false)
|
||||
{}
|
||||
|
||||
void newType(JSContext *cx, TypeSet *source, jstype type)
|
||||
@ -1297,44 +1318,39 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static inline jstype
|
||||
GetSingleTypeFromTypeFlags(TypeFlags flags)
|
||||
void
|
||||
TypeSet::Clone(JSContext *cx, JSScript *script, TypeSet *source, ClonedTypeSet *target)
|
||||
{
|
||||
switch (flags) {
|
||||
case TYPE_FLAG_UNDEFINED:
|
||||
return TYPE_UNDEFINED;
|
||||
case TYPE_FLAG_NULL:
|
||||
return TYPE_NULL;
|
||||
case TYPE_FLAG_BOOLEAN:
|
||||
return TYPE_BOOLEAN;
|
||||
case TYPE_FLAG_INT32:
|
||||
return TYPE_INT32;
|
||||
case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE):
|
||||
return TYPE_DOUBLE;
|
||||
case TYPE_FLAG_STRING:
|
||||
return TYPE_STRING;
|
||||
default:
|
||||
return TYPE_UNKNOWN;
|
||||
if (!source) {
|
||||
target->typeFlags = TYPE_FLAG_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
jstype
|
||||
TypeSet::getSingleType(JSContext *cx, JSScript *script)
|
||||
{
|
||||
TypeFlags flags = typeFlags & ~TYPE_FLAG_INTERMEDIATE_SET;
|
||||
jstype type;
|
||||
if (script && !source->unknown())
|
||||
source->add(cx, ArenaNew<TypeConstraintFreeze>(cx->compartment->types.pool, script), false);
|
||||
|
||||
if (objectCount >= 2)
|
||||
type = TYPE_UNKNOWN;
|
||||
else if (objectCount == 1)
|
||||
type = flags ? TYPE_UNKNOWN : (jstype) objectSet;
|
||||
else
|
||||
type = GetSingleTypeFromTypeFlags(flags);
|
||||
|
||||
if (script && type != TYPE_UNKNOWN)
|
||||
add(cx, ArenaNew<TypeConstraintFreezeSingleType>(cx->compartment->types.pool, script), false);
|
||||
|
||||
return type;
|
||||
target->typeFlags = source->typeFlags & ~TYPE_FLAG_INTERMEDIATE_SET;
|
||||
target->objectCount = source->objectCount;
|
||||
if (source->objectCount >= 2) {
|
||||
target->objectSet = (TypeObject **) ::js_malloc(sizeof(TypeObject*) * source->objectCount);
|
||||
if (!target->objectSet) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
target->objectCount = 0;
|
||||
return;
|
||||
}
|
||||
unsigned objectCapacity = HashSetCapacity(source->objectCount);
|
||||
unsigned index = 0;
|
||||
for (unsigned i = 0; i < objectCapacity; i++) {
|
||||
TypeObject *object = source->objectSet[i];
|
||||
if (object)
|
||||
target->objectSet[index++] = object;
|
||||
}
|
||||
JS_ASSERT(index == source->objectCount);
|
||||
} else if (source->objectCount == 1) {
|
||||
target->objectSet = source->objectSet;
|
||||
} else {
|
||||
target->objectSet = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -67,6 +67,7 @@ struct TypeCallsite;
|
||||
struct TypeObject;
|
||||
struct TypeFunction;
|
||||
struct TypeCompartment;
|
||||
struct ClonedTypeSet;
|
||||
|
||||
/*
|
||||
* Information about a single concrete type. This is a non-zero value whose
|
||||
@ -270,6 +271,9 @@ struct TypeSet
|
||||
*/
|
||||
inline void addType(JSContext *cx, jstype type);
|
||||
|
||||
/* Add all types in a cloned set to this set. */
|
||||
void addTypeSet(JSContext *cx, ClonedTypeSet *types);
|
||||
|
||||
/* Add specific kinds of constraints to this set. */
|
||||
inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
void addSubset(JSContext *cx, JSScript *script, TypeSet *target);
|
||||
@ -306,9 +310,6 @@ struct TypeSet
|
||||
* will be marked for recompilation.
|
||||
*/
|
||||
|
||||
/* Get the single type representing all values in this set, TYPE_UNKNOWN otherwise. */
|
||||
jstype getSingleType(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Get any type tag which all values in this set must have. */
|
||||
JSValueType getKnownTypeTag(JSContext *cx, JSScript *script);
|
||||
|
||||
@ -318,10 +319,24 @@ struct TypeSet
|
||||
/* Get whether this type set is non-empty. */
|
||||
bool knownNonEmpty(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* Clone this type set onto target; if any new types are added to this set
|
||||
* in the future, the script will be recompiled.
|
||||
*/
|
||||
static void Clone(JSContext *cx, JSScript *script, TypeSet *source, ClonedTypeSet *target);
|
||||
|
||||
private:
|
||||
inline void markUnknown(JSContext *cx);
|
||||
};
|
||||
|
||||
/* A type set captured for use by JIT compilers. */
|
||||
struct ClonedTypeSet
|
||||
{
|
||||
TypeFlags typeFlags;
|
||||
TypeObject **objectSet;
|
||||
unsigned objectCount;
|
||||
};
|
||||
|
||||
/* Type information about a property. */
|
||||
struct Property
|
||||
{
|
||||
|
@ -322,6 +322,26 @@ JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Valu
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::ClonedTypeSet *set)
|
||||
{
|
||||
if (obj->unknownProperties)
|
||||
return true;
|
||||
id = js::types::MakeTypeId(this, id);
|
||||
|
||||
js::types::AutoEnterTypeInference enter(this);
|
||||
|
||||
js::types::TypeSet *types = obj->getProperty(this, id, true);
|
||||
if (!types)
|
||||
return compartment->types.checkPendingRecompiles(this);
|
||||
|
||||
js::types::InferSpew(js::types::ISpewOps, "externalType: property %s %s",
|
||||
obj->name(), js::types::TypeIdString(id));
|
||||
types->addTypeSet(this, set);
|
||||
|
||||
return compartment->types.checkPendingRecompiles(this);
|
||||
}
|
||||
|
||||
inline js::types::TypeObject *
|
||||
JSContext::getTypeEmpty()
|
||||
{
|
||||
@ -575,6 +595,19 @@ JSScript::typeSetThis(JSContext *cx, const js::Value &value)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetThis(JSContext *cx, js::types::ClonedTypeSet *set)
|
||||
{
|
||||
if (!ensureVarTypes(cx))
|
||||
return false;
|
||||
js::types::AutoEnterTypeInference enter(cx);
|
||||
|
||||
js::types::InferSpew(js::types::ISpewOps, "externalType: setThis #%u: %s", id());
|
||||
thisTypes()->addTypeSet(cx, set);
|
||||
|
||||
return cx->compartment->types.checkPendingRecompiles(cx);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetNewCalled(JSContext *cx)
|
||||
{
|
||||
@ -628,6 +661,19 @@ JSScript::typeSetLocal(JSContext *cx, unsigned local, const js::Value &value)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *set)
|
||||
{
|
||||
if (!ensureVarTypes(cx))
|
||||
return false;
|
||||
js::types::AutoEnterTypeInference enter(cx);
|
||||
|
||||
js::types::InferSpew(js::types::ISpewOps, "externalType: setLocal #%u %u", id(), local);
|
||||
localTypes(local)->addTypeSet(cx, set);
|
||||
|
||||
return compartment->types.checkPendingRecompiles(cx);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type)
|
||||
{
|
||||
@ -657,6 +703,19 @@ JSScript::typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *set)
|
||||
{
|
||||
if (!ensureVarTypes(cx))
|
||||
return false;
|
||||
js::types::AutoEnterTypeInference enter(cx);
|
||||
|
||||
js::types::InferSpew(js::types::ISpewOps, "externalType: setArg #%u %u", id(), arg);
|
||||
argTypes(arg)->addTypeSet(cx, set);
|
||||
|
||||
return cx->compartment->types.checkPendingRecompiles(cx);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value)
|
||||
{
|
||||
@ -1167,10 +1226,28 @@ inline TypeFunction::TypeFunction(jsid name, JSObject *proto)
|
||||
}
|
||||
|
||||
inline void
|
||||
SweepType(jstype *ptype)
|
||||
SweepClonedTypes(ClonedTypeSet *types)
|
||||
{
|
||||
if (TypeIsObject(*ptype) && !((TypeObject*)*ptype)->marked)
|
||||
*ptype = TYPE_UNKNOWN;
|
||||
if (types->objectCount >= 2) {
|
||||
for (unsigned i = 0; i < types->objectCount; i++) {
|
||||
if (!types->objectSet[i]->marked)
|
||||
types->objectSet[i--] = types->objectSet[--types->objectCount];
|
||||
}
|
||||
if (types->objectCount == 1) {
|
||||
TypeObject *obj = (TypeObject *) types->objectSet;
|
||||
::js_free(types->objectSet);
|
||||
types->objectSet = (TypeObject **) obj;
|
||||
} else if (types->objectCount == 0) {
|
||||
::js_free(types->objectSet);
|
||||
types->objectSet = NULL;
|
||||
}
|
||||
} else if (types->objectCount == 1) {
|
||||
TypeObject *obj = (TypeObject *) types->objectSet;
|
||||
if (!obj->marked) {
|
||||
types->objectSet = NULL;
|
||||
types->objectCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} } /* namespace js::types */
|
||||
|
@ -527,11 +527,14 @@ struct JSScript {
|
||||
/* Add a type for a variable in this script. */
|
||||
inline bool typeSetThis(JSContext *cx, js::types::jstype type);
|
||||
inline bool typeSetThis(JSContext *cx, const js::Value &value);
|
||||
inline bool typeSetThis(JSContext *cx, js::types::ClonedTypeSet *types);
|
||||
inline bool typeSetNewCalled(JSContext *cx);
|
||||
inline bool typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type);
|
||||
inline bool typeSetLocal(JSContext *cx, unsigned local, const js::Value &value);
|
||||
inline bool typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *types);
|
||||
inline bool typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type);
|
||||
inline bool typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
|
||||
inline bool typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *types);
|
||||
inline bool typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
|
||||
|
||||
/*
|
||||
|
@ -3017,14 +3017,17 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
|
||||
callIC.typeMonitored = monitored(PC);
|
||||
if (callIC.typeMonitored && callIC.frameSize.isStatic()) {
|
||||
unsigned argc = callIC.frameSize.staticArgc();
|
||||
callIC.argTypes = (types::jstype *) js_calloc((1 + argc) * sizeof(types::jstype));
|
||||
if (!callIC.argTypes)
|
||||
callIC.argTypes = (types::ClonedTypeSet *)
|
||||
js_calloc((1 + argc) * sizeof(types::ClonedTypeSet));
|
||||
if (!callIC.argTypes) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
types::TypeSet *types = frame.getTypeSet(frame.peek(-(argc + 1)));
|
||||
callIC.argTypes[0] = types ? types->getSingleType(cx, script) : types::TYPE_UNKNOWN;
|
||||
types::TypeSet::Clone(cx, script, types, &callIC.argTypes[0]);
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
types::TypeSet *types = frame.getTypeSet(frame.peek(-(argc - i)));
|
||||
callIC.argTypes[i + 1] = types ? types->getSingleType(cx, script) : types::TYPE_UNKNOWN;
|
||||
types::TypeSet::Clone(cx, script, types, &callIC.argTypes[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3834,10 +3837,15 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
||||
if (monitored(PC)) {
|
||||
types::TypeSet *types = frame.getTypeSet(rhs);
|
||||
pic.typeMonitored = true;
|
||||
pic.knownType = types ? types->getSingleType(cx, script) : types::TYPE_UNKNOWN;
|
||||
pic.rhsTypes = (types::ClonedTypeSet *) ::js_calloc(sizeof(types::ClonedTypeSet));
|
||||
if (!pic.rhsTypes) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
types::TypeSet::Clone(cx, script, types, pic.rhsTypes);
|
||||
} else {
|
||||
pic.typeMonitored = false;
|
||||
pic.knownType = types::TYPE_UNKNOWN;
|
||||
pic.rhsTypes = NULL;
|
||||
}
|
||||
|
||||
RESERVE_IC_SPACE(masm);
|
||||
|
@ -155,7 +155,7 @@ class Compiler : public BaseCompiler
|
||||
RegisterID funPtrReg;
|
||||
FrameSize frameSize;
|
||||
bool typeMonitored;
|
||||
types::jstype *argTypes;
|
||||
types::ClonedTypeSet *argTypes;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -219,7 +219,7 @@ class Compiler : public BaseCompiler
|
||||
|
||||
struct PICGenInfo : public BaseICInfo {
|
||||
PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
|
||||
: BaseICInfo(op), kind(kind), usePropCache(usePropCache)
|
||||
: BaseICInfo(op), kind(kind), usePropCache(usePropCache), typeMonitored(false)
|
||||
{ }
|
||||
ic::PICInfo::Kind kind;
|
||||
Label typeCheck;
|
||||
@ -232,7 +232,7 @@ class Compiler : public BaseCompiler
|
||||
JSAtom *atom;
|
||||
bool hasTypeCheck;
|
||||
bool typeMonitored;
|
||||
types::jstype knownType;
|
||||
types::ClonedTypeSet *rhsTypes;
|
||||
ValueRemat vr;
|
||||
#ifdef JS_HAS_IC_LABELS
|
||||
union {
|
||||
@ -290,7 +290,7 @@ class Compiler : public BaseCompiler
|
||||
ic.u.get.hasTypeCheck = hasTypeCheck;
|
||||
}
|
||||
ic.typeMonitored = typeMonitored;
|
||||
ic.knownType = knownType;
|
||||
ic.rhsTypes = rhsTypes;
|
||||
#ifdef JS_HAS_IC_LABELS
|
||||
if (ic.isGet())
|
||||
ic.setLabels(getPropLabels());
|
||||
|
@ -343,7 +343,8 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||
}
|
||||
|
||||
static inline bool
|
||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc, types::jstype *argTypes)
|
||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc,
|
||||
types::ClonedTypeSet *argTypes)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
Value *vp = f.regs.sp - (argc + 2);
|
||||
@ -361,17 +362,20 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint
|
||||
* used without further type checking. If there is an argument count mismatch,
|
||||
* the callee's args will end up getting marked as unknown.
|
||||
*/
|
||||
types::AutoEnterTypeInference enter(cx);
|
||||
if (flags & JSFRAME_CONSTRUCTING) {
|
||||
if (!newscript->typeSetNewCalled(cx))
|
||||
return false;
|
||||
} else {
|
||||
if (!newscript->typeSetThis(cx, argTypes[0]))
|
||||
if (!newscript->typeSetThis(cx, &argTypes[0]))
|
||||
return false;
|
||||
}
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
if (!newscript->typeSetArgument(cx, i, argTypes[1 + i]))
|
||||
if (!newscript->typeSetArgument(cx, i, &argTypes[1 + i]))
|
||||
return false;
|
||||
}
|
||||
if (!cx->compartment->types.checkPendingRecompiles(cx))
|
||||
return false;
|
||||
} else {
|
||||
CallArgs args(vp + 2, argc);
|
||||
if (!cx->typeMonitorCall(args, flags & JSFRAME_CONSTRUCTING))
|
||||
@ -438,7 +442,8 @@ stubs::UncachedNew(VMFrame &f, uint32 argc)
|
||||
}
|
||||
|
||||
void
|
||||
stubs::UncachedNewHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr)
|
||||
stubs::UncachedNewHelper(VMFrame &f, uint32 argc, types::ClonedTypeSet *argTypes,
|
||||
UncachedCallResult *ucr)
|
||||
{
|
||||
ucr->init();
|
||||
|
||||
@ -481,7 +486,8 @@ stubs::Eval(VMFrame &f, uint32 argc)
|
||||
}
|
||||
|
||||
void
|
||||
stubs::UncachedCallHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr)
|
||||
stubs::UncachedCallHelper(VMFrame &f, uint32 argc, types::ClonedTypeSet *argTypes,
|
||||
UncachedCallResult *ucr)
|
||||
{
|
||||
ucr->init();
|
||||
|
||||
|
@ -1423,8 +1423,8 @@ JITScript::sweepCallICs(JSContext *cx, bool purgeAll)
|
||||
ic::CallICInfo &ic = callICs_[i];
|
||||
|
||||
if (ic.argTypes) {
|
||||
for (unsigned i = 0; i < ic.frameSize.staticArgc(); i++)
|
||||
types::SweepType(&ic.argTypes[i]);
|
||||
for (unsigned i = 0; i < ic.frameSize.staticArgc() + 1; i++)
|
||||
types::SweepClonedTypes(&ic.argTypes[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -256,7 +256,7 @@ struct CallICInfo {
|
||||
* For monitored calls with static argc, the types of 'this' and arguments.
|
||||
* For calls through Function.prototype.call, this refers to the inner this/arguments.
|
||||
*/
|
||||
types::jstype *argTypes;
|
||||
types::ClonedTypeSet *argTypes;
|
||||
|
||||
inline void reset() {
|
||||
fastGuardedObject = NULL;
|
||||
|
@ -200,7 +200,8 @@ class SetPropCompiler : public PICStubCompiler
|
||||
|
||||
static void reset(Repatcher &repatcher, ic::PICInfo &pic)
|
||||
{
|
||||
types::SweepType(&pic.knownType);
|
||||
if (pic.rhsTypes)
|
||||
types::SweepClonedTypes(pic.rhsTypes);
|
||||
|
||||
SetPropLabels &labels = pic.setPropLabels();
|
||||
repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr));
|
||||
@ -601,7 +602,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
|
||||
if (pic.typeMonitored) {
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.knownType))
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||
return error();
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
return Lookup_Uncacheable;
|
||||
@ -621,7 +622,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
return disable("invalid slot");
|
||||
if (pic.typeMonitored) {
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.knownType))
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||
return error();
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
return Lookup_Uncacheable;
|
||||
@ -640,10 +641,10 @@ class SetPropCompiler : public PICStubCompiler
|
||||
if (!script->ensureVarTypes(cx))
|
||||
return error();
|
||||
if (shape->setterOp() == SetCallArg) {
|
||||
if (!script->typeSetArgument(cx, slot, pic.knownType))
|
||||
if (!script->typeSetArgument(cx, slot, pic.rhsTypes))
|
||||
return error();
|
||||
} else {
|
||||
if (!script->typeSetLocal(cx, slot, pic.knownType))
|
||||
if (!script->typeSetLocal(cx, slot, pic.rhsTypes))
|
||||
return error();
|
||||
}
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
|
@ -453,8 +453,8 @@ struct PICInfo : public BasePolyIC {
|
||||
// Offset from start of fast path to initial shape guard.
|
||||
uint32 shapeGuard;
|
||||
|
||||
// Exact known type of the RHS, for monitored PICs.
|
||||
types::jstype knownType;
|
||||
// Possible types of the RHS, for monitored SETPROP PICs.
|
||||
types::ClonedTypeSet *rhsTypes;
|
||||
|
||||
inline bool isSet() const {
|
||||
return kind == SET || kind == SETMETHOD;
|
||||
@ -544,6 +544,11 @@ struct PICInfo : public BasePolyIC {
|
||||
inlinePathPatched = false;
|
||||
shapeRegHasBaseShape = true;
|
||||
}
|
||||
|
||||
~PICInfo() {
|
||||
if (typeMonitored)
|
||||
js_free(rhsTypes);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
|
@ -104,8 +104,8 @@ struct UncachedCallResult {
|
||||
* These functions either execute the function, return a native code
|
||||
* pointer that can be used to call the function, or throw.
|
||||
*/
|
||||
void UncachedCallHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr);
|
||||
void UncachedNewHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr);
|
||||
void UncachedCallHelper(VMFrame &f, uint32 argc, types::ClonedTypeSet *argTypes, UncachedCallResult *ucr);
|
||||
void UncachedNewHelper(VMFrame &f, uint32 argc, types::ClonedTypeSet *argTypes, UncachedCallResult *ucr);
|
||||
|
||||
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
|
||||
void JS_FASTCALL Throw(VMFrame &f);
|
||||
|
Loading…
Reference in New Issue
Block a user