Bug 771130 part 2 - Inline monomorphic GETPROP and SETPROP. r=dvander

This commit is contained in:
Jan de Mooij 2012-07-19 10:02:36 +02:00
parent 1b6c312684
commit 1d6e90b1ae
8 changed files with 169 additions and 13 deletions

View File

@ -54,8 +54,8 @@ CountArgSlots(JSFunction *fun)
class CompileInfo
{
public:
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc)
: script_(script), fun_(fun), osrPc_(osrPc)
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
: script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing)
{
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
nslots_ = script->nslots + CountArgSlots(fun);
@ -67,7 +67,9 @@ class CompileInfo
JSFunction *fun() const {
return fun_;
}
bool constructing() const {
return constructing_;
}
jsbytecode *osrPc() {
return osrPc_;
}
@ -169,6 +171,7 @@ class CompileInfo
JSFunction *fun_;
unsigned nslots_;
jsbytecode *osrPc_;
bool constructing_;
};
} // namespace ion

View File

@ -866,7 +866,7 @@ IonCompile(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode *osrPc)
MIRGraph graph(temp);
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)
return false;

View File

@ -75,14 +75,26 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator &temp, MIRGraph &graph, Type
bool
IonBuilder::abort(const char *message, ...)
{
// Don't call PCToLineNumber in release builds.
#ifdef DEBUG
va_list ap;
va_start(ap, message);
abortFmt(message, ap);
va_end(ap);
IonSpew(IonSpew_Abort, "aborted @ %s:%d", script->filename, PCToLineNumber(script, pc));
#endif
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
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
// lifetime.
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(
callee->script(), callee, (jsbytecode *)NULL);
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(callee->script(), callee,
(jsbytecode *)NULL, constructing);
if (!info)
return false;
@ -5039,6 +5051,62 @@ IonBuilder::invalidatedIdempotentCache()
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
IonBuilder::jsop_getprop(HandlePropertyName name)
{
@ -5118,14 +5186,28 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
}
if (unary.ival == MIRType_Object) {
MGetPropertyCache *load = MGetPropertyCache::New(obj, name);
if (!barrier) {
// Use the default type (Value) when the output type is undefined or null.
// Because specializing to those types isn't possible.
if (unary.rval != MIRType_Undefined && unary.rval != MIRType_Null)
load->setResultType(unary.rval);
MIRType rvalType = MIRType_Value;
if (!barrier && !IsNullOrUndefined(unary.rval))
rvalType = unary.rval;
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);
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
// (its ICs are used to mark property reads as likely non-idempotent) or
// if we are compiling eagerly (to improve test coverage).
@ -5201,6 +5283,24 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
if (monitored) {
ins = MCallSetProperty::New(obj, value, name, script->strictModeCode);
} 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);
if (!binaryTypes.lhsTypes || binaryTypes.lhsTypes->propertyNeedsBarrier(cx, id))

View File

@ -209,6 +209,7 @@ class IonBuilder : public MIRGenerator
uint32 readIndex(jsbytecode *pc);
JSAtom *readAtom(jsbytecode *pc);
bool abort(const char *message, ...);
void spew(const char *message);
static bool inliningEnabled() {
return js_IonOptions.inlining;
@ -314,6 +315,9 @@ class IonBuilder : public MIRGenerator
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_bitnot();
bool jsop_bitop(JSOp op);

View File

@ -515,6 +515,13 @@ TypeInferenceOracle::propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc
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
TypeInferenceOracle::elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc)
{

View File

@ -160,6 +160,9 @@ class TypeOracle
virtual bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc) {
return true;
}
virtual bool propertyWriteNeedsBarrier(JSScript *script, jsbytecode *pc, jsid id) {
return true;
}
virtual bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc) {
return true;
}
@ -281,6 +284,7 @@ class TypeInferenceOracle : public TypeOracle
bool elementWriteIsPacked(JSScript *script, jsbytecode *pc);
bool setElementHasWrittenHoles(JSScript *script, jsbytecode *pc);
bool propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc);
bool propertyWriteNeedsBarrier(JSScript *script, jsbytecode *pc, jsid id);
bool elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc);
MIRType elementWrite(JSScript *script, jsbytecode *pc);
bool arrayPrototypeHasIndexedProperty();

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

View File

@ -23,7 +23,7 @@
namespace js {
namespace ion {
class IonScript;
struct IonScript;
}
# define ION_DISABLED_SCRIPT ((js::ion::IonScript *)0x1)