Fix crashes during GC caused by partially initialized objects. The
inline allocation code used the expected number of properties to calculate the number of inobject properties for an object instead of getting the actual number from the initial map. It is safer to use the inobject property count from the initial map in any case because that is the amount the instances will get. I think this disconnect got introduced when adding shrinking of objects. Unfortuntely I haven't been able to create a simple reproduction for a test case but this fixes the webpage that exhibits the crash. I'll see if I can create a reproduction tomorrow. Review URL: http://codereview.chromium.org/5278003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5879 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
3dda6c496f
commit
4c6f79ecec
@ -2902,8 +2902,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
||||||
SharedFunctionInfo* shared) {
|
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r0 : argc
|
// -- r0 : argc
|
||||||
// -- r1 : constructor
|
// -- r1 : constructor
|
||||||
@ -2987,6 +2986,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
// r7: undefined
|
// r7: undefined
|
||||||
// Fill the initialized properties with a constant value or a passed argument
|
// Fill the initialized properties with a constant value or a passed argument
|
||||||
// depending on the this.x = ...; assignment in the function.
|
// depending on the this.x = ...; assignment in the function.
|
||||||
|
SharedFunctionInfo* shared = function->shared();
|
||||||
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
||||||
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
||||||
Label not_passed, next;
|
Label not_passed, next;
|
||||||
@ -3011,8 +3011,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill the unused in-object property fields with undefined.
|
// Fill the unused in-object property fields with undefined.
|
||||||
|
ASSERT(function->has_initial_map());
|
||||||
for (int i = shared->this_property_assignments_count();
|
for (int i = shared->this_property_assignments_count();
|
||||||
i < shared->CalculateInObjectProperties();
|
i < function->initial_map()->inobject_properties();
|
||||||
i++) {
|
i++) {
|
||||||
__ str(r7, MemOperand(r5, kPointerSize, PostIndex));
|
__ str(r7, MemOperand(r5, kPointerSize, PostIndex));
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
|
|||||||
|
|
||||||
void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
|
void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
|
||||||
// If objects constructed from this function exist then changing
|
// If objects constructed from this function exist then changing
|
||||||
// 'estimated_nof_properties' is dangerous since the previois value might
|
// 'estimated_nof_properties' is dangerous since the previous value might
|
||||||
// have been compiled into the fast construct stub. More over, the inobject
|
// have been compiled into the fast construct stub. More over, the inobject
|
||||||
// slack tracking logic might have adjusted the previous value, so even
|
// slack tracking logic might have adjusted the previous value, so even
|
||||||
// passing the same value is risky.
|
// passing the same value is risky.
|
||||||
|
@ -537,7 +537,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::LoadAllocationTopHelper(Register result,
|
void MacroAssembler::LoadAllocationTopHelper(Register result,
|
||||||
Register result_end,
|
|
||||||
Register scratch,
|
Register scratch,
|
||||||
AllocationFlags flags) {
|
AllocationFlags flags) {
|
||||||
ExternalReference new_space_allocation_top =
|
ExternalReference new_space_allocation_top =
|
||||||
@ -559,7 +558,6 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
|
|||||||
if (scratch.is(no_reg)) {
|
if (scratch.is(no_reg)) {
|
||||||
mov(result, Operand::StaticVariable(new_space_allocation_top));
|
mov(result, Operand::StaticVariable(new_space_allocation_top));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(!scratch.is(result_end));
|
|
||||||
mov(Operand(scratch), Immediate(new_space_allocation_top));
|
mov(Operand(scratch), Immediate(new_space_allocation_top));
|
||||||
mov(result, Operand(scratch, 0));
|
mov(result, Operand(scratch, 0));
|
||||||
}
|
}
|
||||||
@ -608,7 +606,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
Register top_reg = result_end.is_valid() ? result_end : result;
|
Register top_reg = result_end.is_valid() ? result_end : result;
|
||||||
|
|
||||||
@ -664,7 +662,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
// Calculate new top and bail out if new space is exhausted.
|
// Calculate new top and bail out if new space is exhausted.
|
||||||
ExternalReference new_space_allocation_limit =
|
ExternalReference new_space_allocation_limit =
|
||||||
@ -705,7 +703,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
// Calculate new top and bail out if new space is exhausted.
|
// Calculate new top and bail out if new space is exhausted.
|
||||||
ExternalReference new_space_allocation_limit =
|
ExternalReference new_space_allocation_limit =
|
||||||
|
@ -631,7 +631,6 @@ class MacroAssembler: public Assembler {
|
|||||||
|
|
||||||
// Allocation support helpers.
|
// Allocation support helpers.
|
||||||
void LoadAllocationTopHelper(Register result,
|
void LoadAllocationTopHelper(Register result,
|
||||||
Register result_end,
|
|
||||||
Register scratch,
|
Register scratch,
|
||||||
AllocationFlags flags);
|
AllocationFlags flags);
|
||||||
void UpdateAllocationTopHelper(Register result_end, Register scratch);
|
void UpdateAllocationTopHelper(Register result_end, Register scratch);
|
||||||
|
@ -3021,8 +3021,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
|
|||||||
|
|
||||||
// Specialized stub for constructing objects from functions which only have only
|
// Specialized stub for constructing objects from functions which only have only
|
||||||
// simple assignments of the form this.x = ...; in their body.
|
// simple assignments of the form this.x = ...; in their body.
|
||||||
MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
||||||
SharedFunctionInfo* shared) {
|
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- eax : argc
|
// -- eax : argc
|
||||||
// -- edi : constructor
|
// -- edi : constructor
|
||||||
@ -3098,6 +3097,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
// edi: undefined
|
// edi: undefined
|
||||||
// Fill the initialized properties with a constant value or a passed argument
|
// Fill the initialized properties with a constant value or a passed argument
|
||||||
// depending on the this.x = ...; assignment in the function.
|
// depending on the this.x = ...; assignment in the function.
|
||||||
|
SharedFunctionInfo* shared = function->shared();
|
||||||
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
||||||
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
||||||
// Check if the argument assigned to the property is actually passed.
|
// Check if the argument assigned to the property is actually passed.
|
||||||
@ -3125,8 +3125,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill the unused in-object property fields with undefined.
|
// Fill the unused in-object property fields with undefined.
|
||||||
|
ASSERT(function->has_initial_map());
|
||||||
for (int i = shared->this_property_assignments_count();
|
for (int i = shared->this_property_assignments_count();
|
||||||
i < shared->CalculateInObjectProperties();
|
i < function->initial_map()->inobject_properties();
|
||||||
i++) {
|
i++) {
|
||||||
__ mov(Operand(edx, i * kPointerSize), edi);
|
__ mov(Operand(edx, i * kPointerSize), edi);
|
||||||
}
|
}
|
||||||
|
@ -6392,7 +6392,7 @@ static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
|
|||||||
}
|
}
|
||||||
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
|
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
|
||||||
ConstructStubCompiler compiler;
|
ConstructStubCompiler compiler;
|
||||||
MaybeObject* code = compiler.CompileConstructStub(function->shared());
|
MaybeObject* code = compiler.CompileConstructStub(*function);
|
||||||
if (!code->IsFailure()) {
|
if (!code->IsFailure()) {
|
||||||
function->shared()->set_construct_stub(
|
function->shared()->set_construct_stub(
|
||||||
Code::cast(code->ToObjectUnchecked()));
|
Code::cast(code->ToObjectUnchecked()));
|
||||||
@ -6460,7 +6460,6 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
|
|||||||
// track one initial_map at a time, so we force the completion before the
|
// track one initial_map at a time, so we force the completion before the
|
||||||
// function is called as a constructor for the first time.
|
// function is called as a constructor for the first time.
|
||||||
shared->CompleteInobjectSlackTracking();
|
shared->CompleteInobjectSlackTracking();
|
||||||
TrySettingInlineConstructStub(function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool first_allocation = !shared->live_objects_may_exist();
|
bool first_allocation = !shared->live_objects_may_exist();
|
||||||
|
@ -740,7 +740,7 @@ class ConstructStubCompiler: public StubCompiler {
|
|||||||
public:
|
public:
|
||||||
explicit ConstructStubCompiler() {}
|
explicit ConstructStubCompiler() {}
|
||||||
|
|
||||||
MUST_USE_RESULT MaybeObject* CompileConstructStub(SharedFunctionInfo* shared);
|
MUST_USE_RESULT MaybeObject* CompileConstructStub(JSFunction* function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MaybeObject* GetCode();
|
MaybeObject* GetCode();
|
||||||
|
@ -1889,7 +1889,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::LoadAllocationTopHelper(Register result,
|
void MacroAssembler::LoadAllocationTopHelper(Register result,
|
||||||
Register result_end,
|
|
||||||
Register scratch,
|
Register scratch,
|
||||||
AllocationFlags flags) {
|
AllocationFlags flags) {
|
||||||
ExternalReference new_space_allocation_top =
|
ExternalReference new_space_allocation_top =
|
||||||
@ -1911,7 +1910,6 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
|
|||||||
// Move address of new object to result. Use scratch register if available,
|
// Move address of new object to result. Use scratch register if available,
|
||||||
// and keep address in scratch until call to UpdateAllocationTopHelper.
|
// and keep address in scratch until call to UpdateAllocationTopHelper.
|
||||||
if (scratch.is_valid()) {
|
if (scratch.is_valid()) {
|
||||||
ASSERT(!scratch.is(result_end));
|
|
||||||
movq(scratch, new_space_allocation_top);
|
movq(scratch, new_space_allocation_top);
|
||||||
movq(result, Operand(scratch, 0));
|
movq(result, Operand(scratch, 0));
|
||||||
} else if (result.is(rax)) {
|
} else if (result.is(rax)) {
|
||||||
@ -1972,7 +1970,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
// Calculate new top and bail out if new space is exhausted.
|
// Calculate new top and bail out if new space is exhausted.
|
||||||
ExternalReference new_space_allocation_limit =
|
ExternalReference new_space_allocation_limit =
|
||||||
@ -2029,7 +2027,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
// Calculate new top and bail out if new space is exhausted.
|
// Calculate new top and bail out if new space is exhausted.
|
||||||
ExternalReference new_space_allocation_limit =
|
ExternalReference new_space_allocation_limit =
|
||||||
@ -2071,7 +2069,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
|
|||||||
ASSERT(!result.is(result_end));
|
ASSERT(!result.is(result_end));
|
||||||
|
|
||||||
// Load address of new object into result.
|
// Load address of new object into result.
|
||||||
LoadAllocationTopHelper(result, result_end, scratch, flags);
|
LoadAllocationTopHelper(result, scratch, flags);
|
||||||
|
|
||||||
// Calculate new top and bail out if new space is exhausted.
|
// Calculate new top and bail out if new space is exhausted.
|
||||||
ExternalReference new_space_allocation_limit =
|
ExternalReference new_space_allocation_limit =
|
||||||
|
@ -950,12 +950,9 @@ class MacroAssembler: public Assembler {
|
|||||||
|
|
||||||
// Allocation support helpers.
|
// Allocation support helpers.
|
||||||
// Loads the top of new-space into the result register.
|
// Loads the top of new-space into the result register.
|
||||||
// If flags contains RESULT_CONTAINS_TOP then result_end is valid and
|
|
||||||
// already contains the top of new-space, and scratch is invalid.
|
|
||||||
// Otherwise the address of the new-space top is loaded into scratch (if
|
// Otherwise the address of the new-space top is loaded into scratch (if
|
||||||
// scratch is valid), and the new-space top is loaded into result.
|
// scratch is valid), and the new-space top is loaded into result.
|
||||||
void LoadAllocationTopHelper(Register result,
|
void LoadAllocationTopHelper(Register result,
|
||||||
Register result_end,
|
|
||||||
Register scratch,
|
Register scratch,
|
||||||
AllocationFlags flags);
|
AllocationFlags flags);
|
||||||
// Update allocation top with value in result_end register.
|
// Update allocation top with value in result_end register.
|
||||||
|
@ -2890,8 +2890,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
|
|||||||
|
|
||||||
// Specialized stub for constructing objects from functions which only have only
|
// Specialized stub for constructing objects from functions which only have only
|
||||||
// simple assignments of the form this.x = ...; in their body.
|
// simple assignments of the form this.x = ...; in their body.
|
||||||
MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
||||||
SharedFunctionInfo* shared) {
|
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- rax : argc
|
// -- rax : argc
|
||||||
// -- rdi : constructor
|
// -- rdi : constructor
|
||||||
@ -2964,6 +2963,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
// r9: first in-object property of the JSObject
|
// r9: first in-object property of the JSObject
|
||||||
// Fill the initialized properties with a constant value or a passed argument
|
// Fill the initialized properties with a constant value or a passed argument
|
||||||
// depending on the this.x = ...; assignment in the function.
|
// depending on the this.x = ...; assignment in the function.
|
||||||
|
SharedFunctionInfo* shared = function->shared();
|
||||||
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
|
||||||
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
if (shared->IsThisPropertyAssignmentArgument(i)) {
|
||||||
// Check if the argument assigned to the property is actually passed.
|
// Check if the argument assigned to the property is actually passed.
|
||||||
@ -2983,8 +2983,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill the unused in-object property fields with undefined.
|
// Fill the unused in-object property fields with undefined.
|
||||||
|
ASSERT(function->has_initial_map());
|
||||||
for (int i = shared->this_property_assignments_count();
|
for (int i = shared->this_property_assignments_count();
|
||||||
i < shared->CalculateInObjectProperties();
|
i < function->initial_map()->inobject_properties();
|
||||||
i++) {
|
i++) {
|
||||||
__ movq(Operand(r9, i * kPointerSize), r8);
|
__ movq(Operand(r9, i * kPointerSize), r8);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user