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
|
||||
{
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
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 ion {
|
||||
class IonScript;
|
||||
struct IonScript;
|
||||
}
|
||||
|
||||
# define ION_DISABLED_SCRIPT ((js::ion::IonScript *)0x1)
|
||||
|
Loading…
Reference in New Issue
Block a user