зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1233176 - Scalar Replacement: Initialize properties with the default value of the template object. r=shu
This commit is contained in:
Родитель
1b186ddd18
Коммит
9aef99a4e0
|
@ -0,0 +1,39 @@
|
|||
// This function uses UCE to test when the if branch is removed by
|
||||
// IonMonkey. Some optimization such as Scalar Replacement are able to remove
|
||||
// the scope chain, which can cause issues when the scope chain properties are
|
||||
// not initialized properly.
|
||||
var uceFault = function (i) {
|
||||
if (i % 1500 == 0) {
|
||||
uceFault = function (i) { return i % 1500 == 0; };
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function f(i) {
|
||||
if (uceFault(i) || uceFault(i))
|
||||
g();
|
||||
const x = 42;
|
||||
function g() {
|
||||
return x;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
function loop() {
|
||||
for (; i < 4000; i++)
|
||||
assertEq(f(i)(), 42);
|
||||
}
|
||||
|
||||
var caught = 0;
|
||||
var i = 1;
|
||||
while (i < 4000) {
|
||||
try {
|
||||
loop();
|
||||
} catch(e) {
|
||||
assertEq(e instanceof ReferenceError, true);
|
||||
assertEq(i == 1500 || i == 3000, true);
|
||||
caught += 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assertEq(caught, 2);
|
|
@ -3993,7 +3993,6 @@ OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
|
|||
const UnboxedLayout& layout =
|
||||
templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
|
||||
|
||||
// 0 is used as an error code.
|
||||
const UnboxedLayout::PropertyVector& properties = layout.properties();
|
||||
MOZ_ASSERT(properties.length() < 255);
|
||||
|
||||
|
@ -4068,8 +4067,54 @@ MObjectState::init(TempAllocator& alloc, MDefinition* obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal)
|
||||
{
|
||||
JSObject* templateObject = templateObjectOf(object());
|
||||
|
||||
// Initialize all the slots of the object state with the value contained in
|
||||
// the template object. This is needed to account values which are baked in
|
||||
// the template objects and not visible in IonMonkey, such as the
|
||||
// uninitialized-lexical magic value of call objects.
|
||||
if (templateObject->is<UnboxedPlainObject>()) {
|
||||
UnboxedPlainObject& unboxedObject = templateObject->as<UnboxedPlainObject>();
|
||||
const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration();
|
||||
const UnboxedLayout::PropertyVector& properties = layout.properties();
|
||||
|
||||
for (size_t i = 0; i < properties.length(); i++) {
|
||||
Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true);
|
||||
MDefinition *def = undefinedVal;
|
||||
if (!val.isUndefined()) {
|
||||
MConstant* ins = val.isObject() ?
|
||||
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
|
||||
MConstant::New(alloc, val);
|
||||
block()->insertBefore(this, ins);
|
||||
def = ins;
|
||||
}
|
||||
initSlot(i, def);
|
||||
}
|
||||
} else {
|
||||
NativeObject& nativeObject = templateObject->as<NativeObject>();
|
||||
MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
|
||||
|
||||
for (size_t i = 0; i < numSlots(); i++) {
|
||||
Value val = nativeObject.getSlot(i);
|
||||
MDefinition *def = undefinedVal;
|
||||
if (!val.isUndefined()) {
|
||||
MConstant* ins = val.isObject() ?
|
||||
MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
|
||||
MConstant::New(alloc, val);
|
||||
block()->insertBefore(this, ins);
|
||||
def = ins;
|
||||
}
|
||||
initSlot(i, def);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MObjectState*
|
||||
MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal)
|
||||
MObjectState::New(TempAllocator& alloc, MDefinition* obj)
|
||||
{
|
||||
JSObject* templateObject = templateObjectOf(obj);
|
||||
MOZ_ASSERT(templateObject, "Unexpected object creation.");
|
||||
|
@ -4084,8 +4129,6 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefined
|
|||
MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
|
||||
if (!res || !res->init(alloc, obj))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < res->numSlots(); i++)
|
||||
res->initSlot(i, undefinedVal);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -3399,9 +3399,13 @@ class MObjectState
|
|||
// on bailout.
|
||||
static JSObject* templateObjectOf(MDefinition* obj);
|
||||
|
||||
static MObjectState* New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal);
|
||||
static MObjectState* New(TempAllocator& alloc, MDefinition* obj);
|
||||
static MObjectState* Copy(TempAllocator& alloc, MObjectState* state);
|
||||
|
||||
// As we might do read of uninitialized properties, we have to copy the
|
||||
// initial values from the template object.
|
||||
bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal);
|
||||
|
||||
MDefinition* object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
|
|
@ -349,12 +349,16 @@ ObjectMemoryView::initStartingState(BlockState** pState)
|
|||
startBlock_->insertBefore(obj_, undefinedVal_);
|
||||
|
||||
// Create a new block state and insert at it at the location of the new object.
|
||||
BlockState* state = BlockState::New(alloc_, obj_, undefinedVal_);
|
||||
BlockState* state = BlockState::New(alloc_, obj_);
|
||||
if (!state)
|
||||
return false;
|
||||
|
||||
startBlock_->insertAfter(obj_, state);
|
||||
|
||||
// Initialize the properties of the object state.
|
||||
if (!state->initFromTemplateObject(alloc_, undefinedVal_))
|
||||
return false;
|
||||
|
||||
// Hold out of resume point until it is visited.
|
||||
state->setInWorklist();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче