mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 771130 part 2 - Inline monomorphic GETPROP and SETPROP. r=dvander
This commit is contained in:
parent
1b6c312684
commit
1d6e90b1ae
@ -54,8 +54,8 @@ CountArgSlots(JSFunction *fun)
|
|||||||
class CompileInfo
|
class CompileInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc)
|
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
|
||||||
: script_(script), fun_(fun), osrPc_(osrPc)
|
: script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
|
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
|
||||||
nslots_ = script->nslots + CountArgSlots(fun);
|
nslots_ = script->nslots + CountArgSlots(fun);
|
||||||
@ -67,7 +67,9 @@ class CompileInfo
|
|||||||
JSFunction *fun() const {
|
JSFunction *fun() const {
|
||||||
return fun_;
|
return fun_;
|
||||||
}
|
}
|
||||||
|
bool constructing() const {
|
||||||
|
return constructing_;
|
||||||
|
}
|
||||||
jsbytecode *osrPc() {
|
jsbytecode *osrPc() {
|
||||||
return osrPc_;
|
return osrPc_;
|
||||||
}
|
}
|
||||||
@ -169,6 +171,7 @@ class CompileInfo
|
|||||||
JSFunction *fun_;
|
JSFunction *fun_;
|
||||||
unsigned nslots_;
|
unsigned nslots_;
|
||||||
jsbytecode *osrPc_;
|
jsbytecode *osrPc_;
|
||||||
|
bool constructing_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ion
|
} // namespace ion
|
||||||
|
@ -866,7 +866,7 @@ IonCompile(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode *osrPc)
|
|||||||
|
|
||||||
MIRGraph graph(temp);
|
MIRGraph graph(temp);
|
||||||
JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
|
JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
|
||||||
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(script, fun, osrPc);
|
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(script, fun, osrPc, fp->isConstructing());
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -75,14 +75,26 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator &temp, MIRGraph &graph, Type
|
|||||||
bool
|
bool
|
||||||
IonBuilder::abort(const char *message, ...)
|
IonBuilder::abort(const char *message, ...)
|
||||||
{
|
{
|
||||||
|
// Don't call PCToLineNumber in release builds.
|
||||||
|
#ifdef DEBUG
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
abortFmt(message, ap);
|
abortFmt(message, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
IonSpew(IonSpew_Abort, "aborted @ %s:%d", script->filename, PCToLineNumber(script, pc));
|
IonSpew(IonSpew_Abort, "aborted @ %s:%d", script->filename, PCToLineNumber(script, pc));
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IonBuilder::spew(const char *message)
|
||||||
|
{
|
||||||
|
// Don't call PCToLineNumber in release builds.
|
||||||
|
#ifdef DEBUG
|
||||||
|
IonSpew(IonSpew_MIR, "%s @ %s:%d", message, script->filename, PCToLineNumber(script, pc));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline int32
|
static inline int32
|
||||||
GetJumpOffset(jsbytecode *pc)
|
GetJumpOffset(jsbytecode *pc)
|
||||||
{
|
{
|
||||||
@ -2812,8 +2824,8 @@ IonBuilder::jsop_call_inline(HandleFunction callee, uint32 argc, bool constructi
|
|||||||
|
|
||||||
// Compilation information is allocated for the duration of the current tempLifoAlloc
|
// Compilation information is allocated for the duration of the current tempLifoAlloc
|
||||||
// lifetime.
|
// lifetime.
|
||||||
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(
|
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(callee->script(), callee,
|
||||||
callee->script(), callee, (jsbytecode *)NULL);
|
(jsbytecode *)NULL, constructing);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -5039,6 +5051,62 @@ IonBuilder::invalidatedIdempotentCache()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType)
|
||||||
|
{
|
||||||
|
JS_ASSERT(shape->hasDefaultGetter());
|
||||||
|
JS_ASSERT(shape->hasSlot());
|
||||||
|
|
||||||
|
types::TypeSet *barrier = oracle->propertyReadBarrier(script, pc);
|
||||||
|
types::TypeSet *types = oracle->propertyRead(script, pc);
|
||||||
|
|
||||||
|
if (shape->slot() < shape->numFixedSlots()) {
|
||||||
|
MLoadFixedSlot *load = MLoadFixedSlot::New(obj, shape->slot());
|
||||||
|
current->add(load);
|
||||||
|
current->push(load);
|
||||||
|
|
||||||
|
load->setResultType(rvalType);
|
||||||
|
return pushTypeBarrier(load, types, barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
MSlots *slots = MSlots::New(obj);
|
||||||
|
current->add(slots);
|
||||||
|
|
||||||
|
MLoadSlot *load = MLoadSlot::New(slots, shape->slot() - shape->numFixedSlots());
|
||||||
|
current->add(load);
|
||||||
|
current->push(load);
|
||||||
|
|
||||||
|
load->setResultType(rvalType);
|
||||||
|
return pushTypeBarrier(load, types, barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier)
|
||||||
|
{
|
||||||
|
JS_ASSERT(shape->hasDefaultSetter());
|
||||||
|
JS_ASSERT(shape->writable());
|
||||||
|
JS_ASSERT(shape->hasSlot());
|
||||||
|
|
||||||
|
if (shape->slot() < shape->numFixedSlots()) {
|
||||||
|
MStoreFixedSlot *store = MStoreFixedSlot::New(obj, shape->slot(), value);
|
||||||
|
current->add(store);
|
||||||
|
current->push(value);
|
||||||
|
if (needsBarrier)
|
||||||
|
store->setNeedsBarrier();
|
||||||
|
return resumeAfter(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
MSlots *slots = MSlots::New(obj);
|
||||||
|
current->add(slots);
|
||||||
|
|
||||||
|
MStoreSlot *store = MStoreSlot::New(slots, shape->slot() - shape->numFixedSlots(), value);
|
||||||
|
current->add(store);
|
||||||
|
current->push(value);
|
||||||
|
if (needsBarrier)
|
||||||
|
store->setNeedsBarrier();
|
||||||
|
return resumeAfter(store);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_getprop(HandlePropertyName name)
|
IonBuilder::jsop_getprop(HandlePropertyName name)
|
||||||
{
|
{
|
||||||
@ -5118,14 +5186,28 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unary.ival == MIRType_Object) {
|
if (unary.ival == MIRType_Object) {
|
||||||
MGetPropertyCache *load = MGetPropertyCache::New(obj, name);
|
MIRType rvalType = MIRType_Value;
|
||||||
if (!barrier) {
|
if (!barrier && !IsNullOrUndefined(unary.rval))
|
||||||
// Use the default type (Value) when the output type is undefined or null.
|
rvalType = unary.rval;
|
||||||
// Because specializing to those types isn't possible.
|
|
||||||
if (unary.rval != MIRType_Undefined && unary.rval != MIRType_Null)
|
if (Shape *objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) {
|
||||||
load->setResultType(unary.rval);
|
// The JM IC was monomorphic, so we inline the property access.
|
||||||
|
MGuardShape *guard = MGuardShape::New(obj, objShape);
|
||||||
|
current->add(guard);
|
||||||
|
|
||||||
|
spew("Inlining monomorphic GETPROP");
|
||||||
|
|
||||||
|
Shape *shape = objShape->search(cx, NameToId(name));
|
||||||
|
JS_ASSERT(shape);
|
||||||
|
|
||||||
|
return loadSlot(obj, shape, rvalType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spew("GETPROP not monomorphic");
|
||||||
|
|
||||||
|
MGetPropertyCache *load = MGetPropertyCache::New(obj, name);
|
||||||
|
load->setResultType(rvalType);
|
||||||
|
|
||||||
// Try to mark the cache as idempotent. We only do this if JM is enabled
|
// Try to mark the cache as idempotent. We only do this if JM is enabled
|
||||||
// (its ICs are used to mark property reads as likely non-idempotent) or
|
// (its ICs are used to mark property reads as likely non-idempotent) or
|
||||||
// if we are compiling eagerly (to improve test coverage).
|
// if we are compiling eagerly (to improve test coverage).
|
||||||
@ -5201,6 +5283,24 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
|
|||||||
if (monitored) {
|
if (monitored) {
|
||||||
ins = MCallSetProperty::New(obj, value, name, script->strictModeCode);
|
ins = MCallSetProperty::New(obj, value, name, script->strictModeCode);
|
||||||
} else {
|
} else {
|
||||||
|
if (Shape *objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) {
|
||||||
|
// The JM IC was monomorphic, so we inline the property access.
|
||||||
|
MGuardShape *guard = MGuardShape::New(obj, objShape);
|
||||||
|
current->add(guard);
|
||||||
|
|
||||||
|
Shape *shape = objShape->search(cx, NameToId(name));
|
||||||
|
JS_ASSERT(shape);
|
||||||
|
|
||||||
|
spew("Inlining monomorphic SETPROP");
|
||||||
|
|
||||||
|
jsid typeId = types::MakeTypeId(cx, id);
|
||||||
|
bool needsBarrier = oracle->propertyWriteNeedsBarrier(script, pc, typeId);
|
||||||
|
|
||||||
|
return storeSlot(obj, shape, value, needsBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
spew("SETPROP not monomorphic");
|
||||||
|
|
||||||
ins = MSetPropertyCache::New(obj, value, name, script->strictModeCode);
|
ins = MSetPropertyCache::New(obj, value, name, script->strictModeCode);
|
||||||
|
|
||||||
if (!binaryTypes.lhsTypes || binaryTypes.lhsTypes->propertyNeedsBarrier(cx, id))
|
if (!binaryTypes.lhsTypes || binaryTypes.lhsTypes->propertyNeedsBarrier(cx, id))
|
||||||
|
@ -209,6 +209,7 @@ class IonBuilder : public MIRGenerator
|
|||||||
uint32 readIndex(jsbytecode *pc);
|
uint32 readIndex(jsbytecode *pc);
|
||||||
JSAtom *readAtom(jsbytecode *pc);
|
JSAtom *readAtom(jsbytecode *pc);
|
||||||
bool abort(const char *message, ...);
|
bool abort(const char *message, ...);
|
||||||
|
void spew(const char *message);
|
||||||
|
|
||||||
static bool inliningEnabled() {
|
static bool inliningEnabled() {
|
||||||
return js_IonOptions.inlining;
|
return js_IonOptions.inlining;
|
||||||
@ -314,6 +315,9 @@ class IonBuilder : public MIRGenerator
|
|||||||
|
|
||||||
bool invalidatedIdempotentCache();
|
bool invalidatedIdempotentCache();
|
||||||
|
|
||||||
|
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType);
|
||||||
|
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier);
|
||||||
|
|
||||||
bool jsop_add(MDefinition *left, MDefinition *right);
|
bool jsop_add(MDefinition *left, MDefinition *right);
|
||||||
bool jsop_bitnot();
|
bool jsop_bitnot();
|
||||||
bool jsop_bitop(JSOp op);
|
bool jsop_bitop(JSOp op);
|
||||||
|
@ -515,6 +515,13 @@ TypeInferenceOracle::propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc
|
|||||||
return !script->analysis()->getCode(pc).monitoredTypes;
|
return !script->analysis()->getCode(pc).monitoredTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypeInferenceOracle::propertyWriteNeedsBarrier(JSScript *script, jsbytecode *pc, jsid id)
|
||||||
|
{
|
||||||
|
types::TypeSet *types = script->analysis()->poppedTypes(pc, 1);
|
||||||
|
return types->propertyNeedsBarrier(cx, id);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TypeInferenceOracle::elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc)
|
TypeInferenceOracle::elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc)
|
||||||
{
|
{
|
||||||
|
@ -160,6 +160,9 @@ class TypeOracle
|
|||||||
virtual bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc) {
|
virtual bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
virtual bool propertyWriteNeedsBarrier(JSScript *script, jsbytecode *pc, jsid id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
virtual bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc) {
|
virtual bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -281,6 +284,7 @@ class TypeInferenceOracle : public TypeOracle
|
|||||||
bool elementWriteIsPacked(JSScript *script, jsbytecode *pc);
|
bool elementWriteIsPacked(JSScript *script, jsbytecode *pc);
|
||||||
bool setElementHasWrittenHoles(JSScript *script, jsbytecode *pc);
|
bool setElementHasWrittenHoles(JSScript *script, jsbytecode *pc);
|
||||||
bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc);
|
bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc);
|
||||||
|
bool propertyWriteNeedsBarrier(JSScript *script, jsbytecode *pc, jsid id);
|
||||||
bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc);
|
bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc);
|
||||||
MIRType elementWrite(JSScript *script, jsbytecode *pc);
|
MIRType elementWrite(JSScript *script, jsbytecode *pc);
|
||||||
bool arrayPrototypeHasIndexedProperty();
|
bool arrayPrototypeHasIndexedProperty();
|
||||||
|
38
js/src/jit-test/tests/ion/monomorphic-property-access.js
Normal file
38
js/src/jit-test/tests/ion/monomorphic-property-access.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
function Foo() {
|
||||||
|
for (var i=0; i<10; i++) {
|
||||||
|
this["p" + i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test1(foo) {
|
||||||
|
for (var i=0; i<10400; i++) {
|
||||||
|
foo.p1 = i;
|
||||||
|
foo.p9 = i;
|
||||||
|
var x = foo.p0 + foo.p1 + foo.p2 + foo.p8 + foo.p4 +
|
||||||
|
foo.p5 + foo.p6 + foo.p7 + foo.p3 + foo.p9;
|
||||||
|
assertEq(x, i + i + 35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test1(new Foo);
|
||||||
|
|
||||||
|
function Bar(arg) {
|
||||||
|
if (arg) { // Thwart definite-property analysis.
|
||||||
|
this.x = 1;
|
||||||
|
this.y = 2;
|
||||||
|
this.z = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test2(bar) {
|
||||||
|
for (var i=0; i<10400; i++) {
|
||||||
|
bar.x++;
|
||||||
|
bar.y++;
|
||||||
|
bar.z++;
|
||||||
|
}
|
||||||
|
assertEq(bar.x, 10401);
|
||||||
|
assertEq(bar.y, 10402);
|
||||||
|
assertEq(bar.z, 10403);
|
||||||
|
}
|
||||||
|
|
||||||
|
test2(new Bar(true));
|
@ -23,7 +23,7 @@
|
|||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
namespace ion {
|
namespace ion {
|
||||||
class IonScript;
|
struct IonScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
# define ION_DISABLED_SCRIPT ((js::ion::IonScript *)0x1)
|
# define ION_DISABLED_SCRIPT ((js::ion::IonScript *)0x1)
|
||||||
|
Loading…
Reference in New Issue
Block a user