Revision: 9335
Author: [email protected]
Date: Tue Sep 20 03:06:23 2011
Log: Initialize pre-allocated fields of JSObject with undefined.
BUG=94873
Review URL: http://codereview.chromium.org/7929001
http://code.google.com/p/v8/source/detail?r=9335
Added:
/branches/bleeding_edge/test/mjsunit/regress/regress-94873.js
Modified:
/branches/bleeding_edge/src/arm/builtins-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/ia32/builtins-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/x64/builtins-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.h
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-94873.js Tue Sep
20 03:06:23 2011
@@ -0,0 +1,78 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug;
+
+function sendCommand(state, cmd) {
+ // Get the debug command processor in paused state.
+ var dcp = state.debugCommandProcessor(false);
+ var request = JSON.stringify(cmd);
+ var response = dcp.processDebugJSONRequest(request);
+ return JSON.parse(response);
+}
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ var line = event_data.sourceLineText();
+ print('break: ' + line);
+
+ var frame = sendCommand(exec_state, {
+ seq: 0,
+ type: "request",
+ command: "frame"
+ });
+
+ sendCommand(exec_state, {
+ seq: 0,
+ type: "request",
+ command: "evaluate",
+ arguments: {
+ expression: "obj.x.toString()",
+ additional_context: [{
+ name: "obj",
+ handle: frame.body.receiver.ref
+ }]
+ }
+ });
+ }
+ } catch (e) {
+ print(e);
+ }
+}
+
+Debug.setListener(listener);
+
+function a(x, y) {
+ this.x = x;
+ this.y = y;
+}
+
+Debug.setBreakPoint(a, 0, 0);
+new a(1, 2);
=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc Fri Sep 16 05:26:29 2011
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc Tue Sep 20 03:06:23 2011
@@ -750,20 +750,22 @@
// r5: First in-object property of JSObject (not tagged)
__ add(r6, r4, Operand(r3, LSL, kPointerSizeLog2)); // End of
object.
ASSERT_EQ(3 * kPointerSize, JSObject::kHeaderSize);
- { Label loop, entry;
- if (count_constructions) {
- // To allow for truncation.
- __ LoadRoot(r7, Heap::kOnePointerFillerMapRootIndex);
- } else {
- __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
- }
- __ b(&entry);
- __ bind(&loop);
- __ str(r7, MemOperand(r5, kPointerSize, PostIndex));
- __ bind(&entry);
- __ cmp(r5, r6);
- __ b(lt, &loop);
- }
+ __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
+ if (count_constructions) {
+ __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
+ __ Ubfx(r0, r0, Map::kPreAllocatedPropertyFieldsByte *
kBitsPerByte,
+ kBitsPerByte);
+ __ add(r0, r5, Operand(r0, LSL, kPointerSizeLog2));
+ // r0: offset of first field after pre-allocated fields
+ if (FLAG_debug_code) {
+ __ cmp(r0, r6);
+ __ Assert(le, "Unexpected number of pre-allocated property
fields.");
+ }
+ __ InitializeFieldsWithFiller(r5, r0, r7);
+ // To allow for truncation.
+ __ LoadRoot(r7, Heap::kOnePointerFillerMapRootIndex);
+ }
+ __ InitializeFieldsWithFiller(r5, r6, r7);
// Add the object tag to make the JSObject real, so that we can
continue
// and jump into the continuation code at any time from now on. Any
@@ -780,9 +782,11 @@
// The field instance sizes contains both pre-allocated property
fields
// and in-object properties.
__ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
- __ Ubfx(r6, r0, Map::kPreAllocatedPropertyFieldsByte * 8, 8);
+ __ Ubfx(r6, r0, Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
+ kBitsPerByte);
__ add(r3, r3, Operand(r6));
- __ Ubfx(r6, r0, Map::kInObjectPropertiesByte * 8, 8);
+ __ Ubfx(r6, r0, Map::kInObjectPropertiesByte * kBitsPerByte,
+ kBitsPerByte);
__ sub(r3, r3, Operand(r6), SetCC);
// Done if no extra properties are to be allocated.
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Sep 20
03:06:23 2011
@@ -3000,6 +3000,19 @@
b(ne, &byte_loop_1);
bind(&done);
}
+
+
+void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler) {
+ Label loop, entry;
+ b(&entry);
+ bind(&loop);
+ str(filler, MemOperand(start_offset, kPointerSize, PostIndex));
+ bind(&entry);
+ cmp(start_offset, end_offset);
+ b(lt, &loop);
+}
void MacroAssembler::CountLeadingZeros(Register zeros, // Answer.
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Sep 20
03:06:23 2011
@@ -653,6 +653,13 @@
Register length,
Register scratch);
+ // Initialize fields with filler values. Fields starting at |
start_offset|
+ // not including end_offset are overwritten with the value in |filler|.
At
+ // the end the loop, |start_offset| takes the value of |end_offset|.
+ void InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler);
+
//
---------------------------------------------------------------------------
// Support functions.
=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Sep 20 01:32:48 2011
+++ /branches/bleeding_edge/src/heap.cc Tue Sep 20 03:06:23 2011
@@ -3443,6 +3443,9 @@
// We cannot always fill with one_pointer_filler_map because objects
// created from API functions expect their internal fields to be
initialized
// with undefined_value.
+ // Pre-allocated fields need to be initialized with undefined_value as
well
+ // so that object accesses before the constructor completes (e.g. in the
+ // debugger) will not cause a crash.
if (map->constructor()->IsJSFunction() &&
JSFunction::cast(map->constructor())->shared()->
IsInobjectSlackTrackingInProgress()) {
@@ -3452,7 +3455,7 @@
} else {
filler = Heap::undefined_value();
}
- obj->InitializeBody(map->instance_size(), filler);
+ obj->InitializeBody(map, Heap::undefined_value(), filler);
}
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Fri Sep 16 05:26:29
2011
+++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Tue Sep 20 03:06:23
2011
@@ -204,22 +204,23 @@
// eax: initial map
// ebx: JSObject
// edi: start of next object
- { Label loop, entry;
- // To allow for truncation.
- if (count_constructions) {
- __ mov(edx, factory->one_pointer_filler_map());
- } else {
- __ mov(edx, factory->undefined_value());
- }
- __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
- __ jmp(&entry);
- __ bind(&loop);
- __ mov(Operand(ecx, 0), edx);
- __ add(Operand(ecx), Immediate(kPointerSize));
- __ bind(&entry);
- __ cmp(ecx, Operand(edi));
- __ j(less, &loop);
- }
+ __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
+ __ mov(edx, factory->undefined_value());
+ if (count_constructions) {
+ __ movzx_b(esi,
+ FieldOperand(eax,
Map::kPreAllocatedPropertyFieldsOffset));
+ __ lea(esi,
+ Operand(ebx, esi, times_pointer_size,
JSObject::kHeaderSize));
+ // esi: offset of first field after pre-allocated fields
+ if (FLAG_debug_code) {
+ __ cmp(esi, Operand(edi));
+ __ Assert(less_equal,
+ "Unexpected number of pre-allocated property fields.");
+ }
+ __ InitializeFieldsWithFiller(ecx, esi, edx);
+ __ mov(edx, factory->one_pointer_filler_map());
+ }
+ __ InitializeFieldsWithFiller(ecx, edi, edx);
// Add the object tag to make the JSObject real, so that we can
continue
// and jump into the continuation code at any time from now on. Any
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Sep 20
03:06:23 2011
@@ -1377,6 +1377,20 @@
bind(&done);
}
+
+
+void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler) {
+ Label loop, entry;
+ jmp(&entry);
+ bind(&loop);
+ mov(Operand(start_offset, 0), filler);
+ add(Operand(start_offset), Immediate(kPointerSize));
+ bind(&entry);
+ cmp(start_offset, Operand(end_offset));
+ j(less, &loop);
+}
void MacroAssembler::NegativeZeroTest(Register result,
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Sep 20
03:06:23 2011
@@ -551,6 +551,13 @@
Register length,
Register scratch);
+ // Initialize fields with filler values. Fields starting at |
start_offset|
+ // not including end_offset are overwritten with the value in |filler|.
At
+ // the end the loop, |start_offset| takes the value of |end_offset|.
+ void InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler);
+
//
---------------------------------------------------------------------------
// Support functions.
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Sep 19 11:36:47 2011
+++ /branches/bleeding_edge/src/objects-inl.h Tue Sep 20 03:06:23 2011
@@ -1493,10 +1493,26 @@
-void JSObject::InitializeBody(int object_size, Object* value) {
- ASSERT(!value->IsHeapObject() || !GetHeap()->InNewSpace(value));
- for (int offset = kHeaderSize; offset < object_size; offset +=
kPointerSize) {
- WRITE_FIELD(this, offset, value);
+void JSObject::InitializeBody(Map* map,
+ Object* pre_allocated_value,
+ Object* filler_value) {
+ ASSERT(!filler_value->IsHeapObject() ||
+ !GetHeap()->InNewSpace(filler_value));
+ ASSERT(!pre_allocated_value->IsHeapObject() ||
+ !GetHeap()->InNewSpace(pre_allocated_value));
+ int size = map->instance_size();
+ int offset = kHeaderSize;
+ if (filler_value != pre_allocated_value) {
+ int pre_allocated = map->pre_allocated_property_fields();
+ ASSERT(pre_allocated * kPointerSize + kHeaderSize <= size);
+ for (int i = 0; i < pre_allocated; i++) {
+ WRITE_FIELD(this, offset, pre_allocated_value);
+ offset += kPointerSize;
+ }
+ }
+ while (offset < size) {
+ WRITE_FIELD(this, offset, filler_value);
+ offset += kPointerSize;
}
}
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Sep 19 11:36:47 2011
+++ /branches/bleeding_edge/src/objects.h Tue Sep 20 03:06:23 2011
@@ -1815,11 +1815,14 @@
WriteBarrierMode mode
= UPDATE_WRITE_BARRIER);
- // initializes the body after properties slot, properties slot is
- // initialized by set_properties
- // Note: this call does not update write barrier, it is caller's
- // reponsibility to ensure that *v* can be collected without WB here.
- inline void InitializeBody(int object_size, Object* value);
+ // Initializes the body after properties slot, properties slot is
+ // initialized by set_properties. Fill the pre-allocated fields with
+ // pre_allocated_value and the rest with filler_value.
+ // Note: this call does not update write barrier, the caller is
responsible
+ // to ensure that |filler_value| can be collected without WB here.
+ inline void InitializeBody(Map* map,
+ Object* pre_allocated_value,
+ Object* filler_value);
// Check whether this object references another object
bool ReferencesObject(Object* obj);
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc Fri Sep 16 05:26:29 2011
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc Tue Sep 20 03:06:23 2011
@@ -207,22 +207,23 @@
// rax: initial map
// rbx: JSObject
// rdi: start of next object
- { Label loop, entry;
- // To allow for truncation.
- if (count_constructions) {
- __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex);
- } else {
- __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
- }
- __ lea(rcx, Operand(rbx, JSObject::kHeaderSize));
- __ jmp(&entry);
- __ bind(&loop);
- __ movq(Operand(rcx, 0), rdx);
- __ addq(rcx, Immediate(kPointerSize));
- __ bind(&entry);
- __ cmpq(rcx, rdi);
- __ j(less, &loop);
- }
+ __ lea(rcx, Operand(rbx, JSObject::kHeaderSize));
+ __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+ if (count_constructions) {
+ __ movzxbq(rsi,
+ FieldOperand(rax,
Map::kPreAllocatedPropertyFieldsOffset));
+ __ lea(rsi,
+ Operand(rbx, rsi, times_pointer_size,
JSObject::kHeaderSize));
+ // rsi: offset of first field after pre-allocated fields
+ if (FLAG_debug_code) {
+ __ cmpq(rsi, rdi);
+ __ Assert(less_equal,
+ "Unexpected number of pre-allocated property fields.");
+ }
+ __ InitializeFieldsWithFiller(rcx, rsi, rdx);
+ __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex);
+ }
+ __ InitializeFieldsWithFiller(rcx, rdi, rdx);
// Add the object tag to make the JSObject real, so that we can
continue
// and jump into the continuation code at any time from now on. Any
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Sep 20
03:06:23 2011
@@ -3849,6 +3849,20 @@
bind(&done);
}
}
+
+
+void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler) {
+ Label loop, entry;
+ jmp(&entry);
+ bind(&loop);
+ movq(Operand(start_offset, 0), filler);
+ addq(start_offset, Immediate(kPointerSize));
+ bind(&entry);
+ cmpq(start_offset, end_offset);
+ j(less, &loop);
+}
void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Mon Sep 19
11:36:47 2011
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Sep 20
03:06:23 2011
@@ -1205,6 +1205,13 @@
int min_length = 0,
Register scratch = kScratchRegister);
+ // Initialize fields with filler values. Fields starting at |
start_offset|
+ // not including end_offset are overwritten with the value in |filler|.
At
+ // the end the loop, |start_offset| takes the value of |end_offset|.
+ void InitializeFieldsWithFiller(Register start_offset,
+ Register end_offset,
+ Register filler);
+
//
---------------------------------------------------------------------------
// StatsCounter support
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev