Fix for V8 issue 2795: Check fails with deopt for mjsunit/array-store-and-grow
(https://code.google.com/p/v8/issues/detail?id=2795) The reason is when allocating and building arrays in hydrogen we need to ensure we do any int32-to-smi conversions BEFORE the allocation. These conversions can at least theoretically deoptimize. If this happens before all the fields of the newly allocated object are filled in, we will have a corrupted heap. BUG= R=verwaest@chromium.org Review URL: https://codereview.chromium.org/20726002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15929 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
41a4831fd9
commit
e9cc78af7e
@ -5562,9 +5562,11 @@ class HObjectAccess {
|
||||
|
||||
static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
|
||||
return HObjectAccess(
|
||||
kArrayLengths, JSArray::kLengthOffset,
|
||||
IsFastElementsKind(elements_kind) && FLAG_track_fields ?
|
||||
Representation::Smi() : Representation::Tagged());
|
||||
kArrayLengths,
|
||||
JSArray::kLengthOffset,
|
||||
IsFastElementsKind(elements_kind) &&
|
||||
FLAG_track_fields
|
||||
? Representation::Smi() : Representation::Tagged());
|
||||
}
|
||||
|
||||
static HObjectAccess ForAllocationSiteTransitionInfo() {
|
||||
@ -5577,9 +5579,9 @@ class HObjectAccess {
|
||||
|
||||
static HObjectAccess ForFixedArrayLength() {
|
||||
return HObjectAccess(
|
||||
kArrayLengths, FixedArray::kLengthOffset,
|
||||
FLAG_track_fields ?
|
||||
Representation::Smi() : Representation::Tagged());
|
||||
kArrayLengths,
|
||||
FixedArray::kLengthOffset,
|
||||
FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
|
||||
}
|
||||
|
||||
static HObjectAccess ForPropertiesPointer() {
|
||||
|
@ -1078,8 +1078,16 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
|
||||
|
||||
HValue* context = environment()->LookupContext();
|
||||
|
||||
HValue* new_capacity = BuildNewElementsCapacity(context, key);
|
||||
HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
|
||||
HValue* max_capacity = AddInstruction(
|
||||
HAdd::New(zone, context, current_capacity, max_gap));
|
||||
IfBuilder key_checker(this);
|
||||
key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
|
||||
key_checker.Then();
|
||||
key_checker.ElseDeopt();
|
||||
key_checker.End();
|
||||
|
||||
HValue* new_capacity = BuildNewElementsCapacity(context, key);
|
||||
HValue* new_elements = BuildGrowElementsCapacity(object, elements,
|
||||
kind, kind, length,
|
||||
new_capacity);
|
||||
@ -1337,6 +1345,9 @@ HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
|
||||
HValue* context,
|
||||
ElementsKind kind,
|
||||
HValue* capacity) {
|
||||
// The HForceRepresentation is to prevent possible deopt on int-smi
|
||||
// conversion after allocation but before the new object fields are set.
|
||||
capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
|
||||
HValue* new_elements = BuildAllocateElements(context, kind, capacity);
|
||||
BuildInitializeElementsHeader(new_elements, kind, capacity);
|
||||
return new_elements;
|
||||
@ -1474,7 +1485,6 @@ HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context,
|
||||
HValue* half_old_capacity =
|
||||
AddInstruction(HShr::New(zone, context, old_capacity,
|
||||
graph_->GetConstant1()));
|
||||
half_old_capacity->ClearFlag(HValue::kCanOverflow);
|
||||
|
||||
HValue* new_capacity = AddInstruction(
|
||||
HAdd::New(zone, context, half_old_capacity, old_capacity));
|
||||
@ -1497,8 +1507,6 @@ void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) {
|
||||
int max_size = heap->MaxRegularSpaceAllocationSize() / element_size;
|
||||
max_size -= JSArray::kSize / element_size;
|
||||
HConstant* max_size_constant = Add<HConstant>(max_size);
|
||||
// Since we're forcing Integer32 representation for this HBoundsCheck,
|
||||
// there's no need to Smi-check the index.
|
||||
Add<HBoundsCheck>(length, max_size_constant);
|
||||
}
|
||||
|
||||
@ -1927,6 +1935,14 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
|
||||
bool fill_with_hole) {
|
||||
HValue* context = builder()->environment()->LookupContext();
|
||||
|
||||
// These HForceRepresentations are because we store these as fields in the
|
||||
// objects we construct, and an int32-to-smi HChange could deopt. Accept
|
||||
// the deopt possibility now, before allocation occurs.
|
||||
capacity = builder()->Add<HForceRepresentation>(capacity,
|
||||
Representation::Smi());
|
||||
length_field = builder()->Add<HForceRepresentation>(length_field,
|
||||
Representation::Smi());
|
||||
|
||||
// Allocate (dealing with failure appropriately)
|
||||
HAllocate::Flags flags = HAllocate::DefaultFlags(kind_);
|
||||
HAllocate* new_object = builder()->Add<HAllocate>(context, size_in_bytes,
|
||||
|
@ -25,6 +25,8 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
// Verifies that the KeyedStoreIC correctly handles out-of-bounds stores
|
||||
// to an array that grow it by a single element. Test functions are
|
||||
// called twice to make sure that the IC is used, first call is handled
|
||||
@ -184,3 +186,23 @@ a = [];
|
||||
array_store_1(a, 0, 0.5);
|
||||
assertEquals(0.5, a[0]);
|
||||
assertEquals(0.5, array_store_1([], 0, 0.5));
|
||||
|
||||
// Verify that a grow store will deoptimize if the max gap (difference between
|
||||
// the end of an array capacity and a new index) is passed. The wrapper is to
|
||||
// make sure array_store_10 isn't inlined.
|
||||
|
||||
(function() {
|
||||
function grow_store(a,b,c) {
|
||||
a[b] = c;
|
||||
}
|
||||
|
||||
a = new Array(1);
|
||||
grow_store(a,1,1);
|
||||
grow_store(a,2,1);
|
||||
%OptimizeFunctionOnNextCall(grow_store);
|
||||
grow_store(a,10,1);
|
||||
assertOptimized(grow_store);
|
||||
grow_store(a,2048,1);
|
||||
assertUnoptimized(grow_store);
|
||||
})();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user