Bug 854400 - Rebase Shu's patch, and combine inlined code with jsop_setelem_dense r=jandem

This commit is contained in:
Nicholas D. Matsakis 2013-05-07 17:37:42 -04:00
parent acfd12a00f
commit 36df22ee4c
4 changed files with 58 additions and 40 deletions

View File

@ -6518,7 +6518,8 @@ IonBuilder::jsop_setelem()
types::StackTypeSet::DoubleConversion conversion =
object->resultTypeSet()->convertDoubleElements(cx);
if (conversion != types::StackTypeSet::AmbiguousDoubleConversion)
return jsop_setelem_dense(conversion, object, index, value);
return jsop_setelem_dense(conversion, SetElem_Normal,
object, index, value);
}
}
@ -6537,6 +6538,7 @@ IonBuilder::jsop_setelem()
bool
IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition *obj, MDefinition *id, MDefinition *value)
{
MIRType elementType = DenseNativeElementType(cx, obj);
@ -6565,15 +6567,22 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
MElements *elements = MElements::New(obj);
current->add(elements);
bool writeHole = script()->analysis()->getCode(pc).arrayWriteHole;
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
writeHole |= icInspect.sawOOBDenseWrite();
bool writeHole;
if (safety == SetElem_Normal) {
writeHole = script()->analysis()->getCode(pc).arrayWriteHole;
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
writeHole |= icInspect.sawOOBDenseWrite();
} else {
writeHole = false;
}
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
// the initialized length and bounds check.
MStoreElementCommon *store;
if (writeHole && writeOutOfBounds) {
JS_ASSERT(safety == SetElem_Normal);
MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, newValue);
store = ins;
@ -6586,15 +6595,24 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
MInitializedLength *initLength = MInitializedLength::New(elements);
current->add(initLength);
id = addBoundsCheck(id, initLength);
bool needsHoleCheck = !packed && !writeOutOfBounds;
bool needsHoleCheck;
if (safety == SetElem_Normal) {
id = addBoundsCheck(id, initLength);
needsHoleCheck = !packed && !writeOutOfBounds;
} else {
needsHoleCheck = false;
}
MStoreElement *ins = MStoreElement::New(elements, id, newValue, needsHoleCheck);
store = ins;
if (safety == SetElem_Unsafe)
ins->setRacy();
current->add(ins);
current->push(value);
if (safety == SetElem_Normal)
current->push(value);
if (!resumeAfter(ins))
return false;

View File

@ -31,6 +31,16 @@ class IonBuilder : public MIRGenerator
ControlStatus_None // No control flow.
};
enum SetElemSafety {
// Normal write like a[b] = c.
SetElem_Normal,
// Write due to UnsafeSetElement:
// - assumed to be in bounds,
// - not checked for data races
SetElem_Unsafe,
};
struct DeferredEdge : public TempObject
{
MBasicBlock *block;
@ -383,6 +393,7 @@ class IonBuilder : public MIRGenerator
bool jsop_getelem_string();
bool jsop_setelem();
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_setelem_typed(int arrayType,
SetElemSafety safety,

View File

@ -942,12 +942,6 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo)
{
return InliningStatus_NotInlined;
}
if (obj->resultTypeSet()->convertDoubleElements(cx) !=
types::StackTypeSet::DontConvertToDoubles)
{
return InliningStatus_NotInlined;
}
}
callInfo.unwrapArgs();
@ -985,7 +979,8 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo)
}
bool
IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
IonBuilder::inlineUnsafeSetDenseArrayElement(
CallInfo &callInfo, uint32_t base)
{
// Note: we do not check the conditions that are asserted as true
// in intrinsic_UnsafeSetElement():
@ -994,33 +989,14 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
// Furthermore, note that inlineUnsafeSetElement ensures the type of the
// value is reflected in the JSID_VOID property of the array.
uint32_t arri = base + 0;
uint32_t idxi = base + 1;
uint32_t elemi = base + 2;
MDefinition *obj = callInfo.getArg(base + 0);
MDefinition *id = callInfo.getArg(base + 1);
MDefinition *elem = callInfo.getArg(base + 2);
MElements *elements = MElements::New(callInfo.getArg(arri));
current->add(elements);
MToInt32 *id = MToInt32::New(callInfo.getArg(idxi));
current->add(id);
// We disable the hole check for this store. This implies that if
// there were setters on the prototype, they would not be invoked.
// But this is actually the desired behavior.
MStoreElement *store = MStoreElement::New(elements, id,
callInfo.getArg(elemi),
/* needsHoleCheck = */ false);
store->setRacy();
if (callInfo.getArg(arri)->resultTypeSet()->propertyNeedsBarrier(cx, JSID_VOID))
store->setNeedsBarrier();
current->add(store);
if (!resumeAfter(store))
types::StackTypeSet::DoubleConversion conversion =
obj->resultTypeSet()->convertDoubleElements(cx);
if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
return false;
return true;
}

View File

@ -12,6 +12,19 @@ function testPushConvert() {
}
testPushConvert();
var UnsafeSetElement = getSelfHostedValue("UnsafeSetElement");
function testUnsafeSetConvert() {
var x = [0.5, 1.5, 2.1];
for (var i = 0; i < 2000; i++)
// try to ensure we JIT and hence inline
UnsafeSetElement(x, 1, i);
var res = 0;
for (var i = 0; i < x.length; i++)
res += x[i];
assertEq(res, 2001.6);
}
testUnsafeSetConvert();
function testArrayInitializer() {
var x = [.5,1.5,2.5,3];
var res = 0;