Fix inobject slack tracking for both subclassing and non-subclassing cases.

It didn't support subclassing case at all and in non-subclassing case the runtime
allocation didn't do the slack tracking step.

BUG=chromium:563339
LOG=Y

Review URL: https://codereview.chromium.org/1488023002

Cr-Commit-Position: refs/heads/master@{#32547}
This commit is contained in:
ishell 2015-12-03 02:02:46 -08:00 committed by Commit bot
parent 5cdb107f88
commit 5d38d6819c
18 changed files with 1409 additions and 327 deletions

View File

@ -379,38 +379,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CompareInstanceType(r2, r5, JS_FUNCTION_TYPE);
__ b(eq, &rt_call);
if (!is_api_function) {
Label allocate;
MemOperand bit_field3 = FieldMemOperand(r2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ ldr(r4, bit_field3);
__ DecodeField<Map::Counter>(r0, r4);
__ cmp(r0, Operand(Map::kSlackTrackingCounterEnd));
__ b(lt, &allocate);
// Decrease generous allocation count.
__ sub(r4, r4, Operand(1 << Map::Counter::kShift));
__ str(r4, bit_field3);
__ cmp(r0, Operand(Map::kSlackTrackingCounterEnd));
__ b(ne, &allocate);
// Push the constructor, new_target and map to the stack, and
// the map again as an argument to the runtime call.
__ Push(r1, r3, r2);
__ push(r2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(r1, r3, r2);
__ mov(r0, Operand(Map::kSlackTrackingCounterEnd - 1));
__ bind(&allocate);
}
// Now allocate the JSObject on the heap.
// r1: constructor function
// r2: initial map
// r3: new target
// r0: slack tracking counter (non-API function case)
__ ldrb(r9, FieldMemOperand(r2, Map::kInstanceSizeOffset));
__ Allocate(r9, r4, r9, r6, &rt_call, SIZE_IN_WORDS);
@ -420,9 +392,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// r1: constructor function
// r2: initial map
// r3: new target
// r4: JSObject (not tagged)
// r4: JSObject (not HeapObject tagged - the actual address).
// r9: start of next object
// r0: slack tracking counter (non-API function case)
__ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
__ mov(r5, r4);
STATIC_ASSERT(0 * kPointerSize == JSObject::kMapOffset);
@ -433,7 +404,12 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ str(r6, MemOperand(r5, kPointerSize, PostIndex));
STATIC_ASSERT(3 * kPointerSize == JSObject::kHeaderSize);
// 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.
__ add(r4, r4, Operand(kHeapObjectTag));
// Fill all the in-object properties with the appropriate filler.
// r4: JSObject (tagged)
// r5: First in-object property of JSObject (not tagged)
__ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
@ -441,14 +417,23 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Label no_inobject_slack_tracking;
// Check if slack tracking is enabled.
__ cmp(r0, Operand(Map::kSlackTrackingCounterEnd));
MemOperand bit_field3 = FieldMemOperand(r2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ ldr(r0, bit_field3);
__ DecodeField<Map::Counter>(ip, r0);
// ip: slack tracking counter
__ cmp(ip, Operand(Map::kSlackTrackingCounterEnd));
__ b(lt, &no_inobject_slack_tracking);
__ push(ip); // Save allocation count value.
// Decrease generous allocation count.
__ sub(r0, r0, Operand(1 << Map::Counter::kShift));
__ str(r0, bit_field3);
// Allocate object with a slack.
__ ldr(r2, FieldMemOperand(r2, Map::kInstanceAttributesOffset));
__ Ubfx(r2, r2, Map::kUnusedPropertyFieldsByte * kBitsPerByte,
__ ldr(r0, FieldMemOperand(r2, Map::kInstanceAttributesOffset));
__ Ubfx(r0, r0, Map::kUnusedPropertyFieldsByte * kBitsPerByte,
kBitsPerByte);
__ sub(r0, r9, Operand(r2, LSL, kPointerSizeLog2));
__ sub(r0, r9, Operand(r0, LSL, kPointerSizeLog2));
// r0: offset of first field after pre-allocated fields
if (FLAG_debug_code) {
__ cmp(r5, r0);
@ -459,16 +444,29 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// To allow truncation fill the remaining fields with one pointer
// filler map.
__ LoadRoot(r6, Heap::kOnePointerFillerMapRootIndex);
__ InitializeFieldsWithFiller(r5, r9, r6);
__ pop(r0); // Restore allocation count value before decreasing.
__ cmp(r0, Operand(Map::kSlackTrackingCounterEnd));
__ b(ne, &allocated);
// Push the constructor, new_target and the object to the stack,
// and then the initial map as an argument to the runtime call.
__ Push(r1, r3, r4, r2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(r1, r3, r4);
// Continue with JSObject being successfully allocated
// r1: constructor function
// r3: new target
// r4: JSObject
__ jmp(&allocated);
__ bind(&no_inobject_slack_tracking);
}
__ InitializeFieldsWithFiller(r5, r9, r6);
// 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.
__ add(r4, r4, Operand(kHeapObjectTag));
// Continue with JSObject being successfully allocated
// r1: constructor function
// r3: new target

View File

@ -389,31 +389,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
__ B(eq, &rt_call);
Register constructon_count = x14;
if (!is_api_function) {
Label allocate;
MemOperand bit_field3 =
FieldMemOperand(init_map, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ Ldr(x4, bit_field3);
__ DecodeField<Map::Counter>(constructon_count, x4);
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ B(lt, &allocate);
// Decrease generous allocation count.
__ Subs(x4, x4, Operand(1 << Map::Counter::kShift));
__ Str(x4, bit_field3);
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ B(ne, &allocate);
// Push the constructor, new_target and map to the stack, and
// the map again as an argument to the runtime call.
__ Push(constructor, new_target, init_map, init_map);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(init_map, new_target, constructor);
__ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
__ Bind(&allocate);
}
// Now allocate the JSObject on the heap.
Register obj_size = x10;
Register new_obj = x4;
@ -436,6 +411,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
MemOperand(write_address, 2 * kPointerSize, PostIndex));
STATIC_ASSERT(3 * kPointerSize == JSObject::kHeaderSize);
// 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.
__ Add(new_obj, new_obj, kHeapObjectTag);
// Fill all of the in-object properties with the appropriate filler.
Register filler = x7;
__ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
@ -443,10 +422,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
if (!is_api_function) {
Label no_inobject_slack_tracking;
Register constructon_count = x14;
MemOperand bit_field3 =
FieldMemOperand(init_map, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ Ldr(x11, bit_field3);
__ DecodeField<Map::Counter>(constructon_count, x11);
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ B(lt, &no_inobject_slack_tracking);
constructon_count = NoReg;
// Decrease generous allocation count.
__ Subs(x11, x11, Operand(1 << Map::Counter::kShift));
__ Str(x11, bit_field3);
// Allocate object with a slack.
Register unused_props = x11;
@ -471,17 +457,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Fill the remaining fields with one pointer filler map.
__ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
__ InitializeFieldsWithFiller(write_address, next_obj, filler);
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ B(ne, &allocated);
// Push the constructor, new_target and the object to the stack,
// and then the initial map as an argument to the runtime call.
__ Push(constructor, new_target, new_obj, init_map);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(new_obj, new_target, constructor);
// Continue with JSObject being successfully allocated.
__ B(&allocated);
__ bind(&no_inobject_slack_tracking);
}
// Fill all of the property fields with undef.
__ InitializeFieldsWithFiller(write_address, next_obj, filler);
// 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.
__ Add(new_obj, new_obj, kHeapObjectTag);
// Continue with JSObject being successfully allocated.
__ B(&allocated);
}

View File

@ -2356,6 +2356,7 @@ class ScriptContextFieldStub : public HandlerStub {
const ScriptContextTable::LookupResult* lookup_result)
: HandlerStub(isolate) {
DCHECK(Accepted(lookup_result));
STATIC_ASSERT(kContextIndexBits + kSlotIndexBits <= kSubMinorKeyBits);
set_sub_minor_key(ContextIndexBits::encode(lookup_result->context_index) |
SlotIndexBits::encode(lookup_result->slot_index));
}
@ -2372,7 +2373,7 @@ class ScriptContextFieldStub : public HandlerStub {
}
private:
static const int kContextIndexBits = 13;
static const int kContextIndexBits = 9;
static const int kSlotIndexBits = 13;
class ContextIndexBits : public BitField<int, 0, kContextIndexBits> {};
class SlotIndexBits

View File

@ -1386,9 +1386,7 @@ Reduction JSTypedLowering::ReduceJSCreate(Node* node) {
DCHECK(constructor->IsConstructor());
// Force completion of inobject slack tracking before
// generating code to finalize the instance size.
if (constructor->IsInobjectSlackTrackingInProgress()) {
constructor->CompleteInobjectSlackTracking();
}
constructor->CompleteInobjectSlackTrackingIfActive();
// TODO(bmeurer): We fall back to the runtime in case we cannot inline
// the allocation here, which is sort of expensive. We should think about

View File

@ -9923,9 +9923,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
// Force completion of inobject slack tracking before generating
// allocation code to finalize instance size.
if (constructor->IsInobjectSlackTrackingInProgress()) {
constructor->CompleteInobjectSlackTracking();
}
constructor->CompleteInobjectSlackTrackingIfActive();
// Calculate instance size from initial map of constructor.
DCHECK(constructor->has_initial_map());

View File

@ -1653,7 +1653,7 @@ Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
DCHECK(function->shared()->is_generator());
JSFunction::EnsureHasInitialMap(function);
Handle<Map> map(function->initial_map());
DCHECK(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
DCHECK_EQ(JS_GENERATOR_OBJECT_TYPE, map->instance_type());
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObjectFromMap(*map),

View File

@ -3373,16 +3373,18 @@ void Heap::InitializeJSObjectBody(JSObject* obj, Map* map, int start_offset) {
// 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.
Object* constructor = map->GetConstructor();
if (constructor->IsJSFunction() &&
JSFunction::cast(constructor)->IsInobjectSlackTrackingInProgress()) {
// In case of Array subclassing the |map| could already be transitioned
// to different elements kind from the initial map on which we track slack.
Map* initial_map = map->FindRootMap();
if (initial_map->IsInobjectSlackTrackingInProgress()) {
// We might want to shrink the object later.
DCHECK_EQ(0, obj->GetInternalFieldCount());
filler = Heap::one_pointer_filler_map();
} else {
filler = Heap::undefined_value();
}
obj->InitializeBody(map, start_offset, Heap::undefined_value(), filler);
initial_map->InobjectSlackTrackingStep();
}

View File

@ -166,37 +166,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpInstanceType(eax, JS_FUNCTION_TYPE);
__ j(equal, &rt_call);
if (!is_api_function) {
Label allocate;
// The code below relies on these assumptions.
STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
// Check if slack tracking is enabled.
__ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
__ shr(esi, Map::Counter::kShift);
__ cmp(esi, Map::kSlackTrackingCounterEnd);
__ j(less, &allocate);
// Decrease generous allocation count.
__ sub(FieldOperand(eax, Map::kBitField3Offset),
Immediate(1 << Map::Counter::kShift));
__ cmp(esi, Map::kSlackTrackingCounterEnd);
__ j(not_equal, &allocate);
__ push(eax);
__ push(edx);
__ push(edi);
__ push(eax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(edi);
__ pop(edx);
__ pop(eax);
__ mov(esi, Map::kSlackTrackingCounterEnd - 1);
__ bind(&allocate);
}
// Now allocate the JSObject on the heap.
// edi: constructor
// eax: initial map
@ -209,25 +178,37 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Allocated the JSObject, now initialize the fields.
// eax: initial map
// ebx: JSObject
// ebx: JSObject (not HeapObject tagged - the actual address).
// edi: start of next object
__ mov(Operand(ebx, JSObject::kMapOffset), eax);
__ mov(ecx, factory->empty_fixed_array());
__ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
__ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
// Set extra fields in the newly allocated object.
// eax: initial map
// ebx: JSObject
// edi: start of next object
// esi: slack tracking counter (non-API function case)
__ mov(edx, factory->undefined_value());
__ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
// 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.
__ or_(ebx, Immediate(kHeapObjectTag));
// Fill all the in-object properties with the appropriate filler.
// ebx: JSObject (tagged)
// ecx: First in-object property of JSObject (not tagged)
__ mov(edx, factory->undefined_value());
if (!is_api_function) {
Label no_inobject_slack_tracking;
// The code below relies on these assumptions.
STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
// Check if slack tracking is enabled.
__ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
__ shr(esi, Map::Counter::kShift);
__ cmp(esi, Map::kSlackTrackingCounterEnd);
__ j(less, &no_inobject_slack_tracking);
__ push(esi); // Save allocation count value.
// Decrease generous allocation count.
__ sub(FieldOperand(eax, Map::kBitField3Offset),
Immediate(1 << Map::Counter::kShift));
// Allocate object with a slack.
__ movzx_b(esi, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
@ -244,17 +225,28 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// To allow truncation fill the remaining fields with one pointer
// filler map.
__ mov(edx, factory->one_pointer_filler_map());
__ InitializeFieldsWithFiller(ecx, edi, edx);
__ pop(esi); // Restore allocation count value before decreasing.
__ cmp(esi, Map::kSlackTrackingCounterEnd);
__ j(not_equal, &allocated);
// Push the object to the stack, and then the initial map as
// an argument to the runtime call.
__ push(ebx);
__ push(eax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(ebx);
// Continue with JSObject being successfully allocated
// ebx: JSObject (tagged)
__ jmp(&allocated);
__ bind(&no_inobject_slack_tracking);
}
__ 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.
// ebx: JSObject (untagged)
__ or_(ebx, Immediate(kHeapObjectTag));
// Continue with JSObject being successfully allocated
// ebx: JSObject (tagged)
__ jmp(&allocated);

View File

@ -382,35 +382,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ lbu(t5, FieldMemOperand(a2, Map::kInstanceTypeOffset));
__ Branch(&rt_call, eq, t5, Operand(JS_FUNCTION_TYPE));
if (!is_api_function) {
Label allocate;
MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ lw(t0, bit_field3);
__ DecodeField<Map::Counter>(t2, t0);
__ Branch(&allocate, lt, t2, Operand(Map::kSlackTrackingCounterEnd));
// Decrease generous allocation count.
__ Subu(t0, t0, Operand(1 << Map::Counter::kShift));
__ Branch(USE_DELAY_SLOT, &allocate, ne, t2,
Operand(Map::kSlackTrackingCounterEnd));
__ sw(t0, bit_field3); // In delay slot.
// Push the constructor, new_target and map to the stack, and
// the map again as an argument to the runtime call.
__ Push(a1, a3, a2, a2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a3, a2);
__ li(t2, Operand(Map::kSlackTrackingCounterEnd - 1));
__ bind(&allocate);
}
// Now allocate the JSObject on the heap.
// a1: constructor function
// a2: initial map
// a3: new target
// t2: slack tracking counter (non-API function case)
__ lbu(t3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
__ Allocate(t3, t4, t3, t6, &rt_call, SIZE_IN_WORDS);
@ -420,9 +395,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// a1: constructor function
// a2: initial map
// a3: new target
// t4: JSObject (not tagged)
// t4: JSObject (not HeapObject tagged - the actual address).
// t3: start of next object
// t2: slack tracking counter (non-API function case)
__ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
__ mov(t5, t4);
STATIC_ASSERT(0 * kPointerSize == JSObject::kMapOffset);
@ -434,18 +408,28 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
STATIC_ASSERT(3 * kPointerSize == JSObject::kHeaderSize);
__ Addu(t5, t5, Operand(3 * kPointerSize));
// Fill all the in-object properties with appropriate filler.
// t5: First in-object property of JSObject (not tagged)
// 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.
__ Addu(t4, t4, Operand(kHeapObjectTag));
// Use t7 to hold undefined, which is used in several places below.
// Fill all the in-object properties with appropriate filler.
// t4: JSObject (tagged)
// t5: First in-object property of JSObject (not tagged)
__ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
if (!is_api_function) {
Label no_inobject_slack_tracking;
MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ lw(t0, bit_field3);
__ DecodeField<Map::Counter>(t2, t0);
// t2: slack tracking counter
__ Branch(&no_inobject_slack_tracking, lt, t2,
Operand(Map::kSlackTrackingCounterEnd));
// Decrease generous allocation count.
__ Subu(t0, t0, Operand(1 << Map::Counter::kShift));
__ sw(t0, bit_field3);
// Allocate object with a slack.
__ lbu(a0, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset));
@ -461,16 +445,28 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// To allow truncation fill the remaining fields with one pointer
// filler map.
__ LoadRoot(t7, Heap::kOnePointerFillerMapRootIndex);
__ InitializeFieldsWithFiller(t5, t3, t7);
// t2: slack tracking counter value before decreasing.
__ Branch(&allocated, ne, t2, Operand(Map::kSlackTrackingCounterEnd));
// Push the constructor, new_target and the object to the stack,
// and then the initial map as an argument to the runtime call.
__ Push(a1, a3, t4, a2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a3, t4);
// Continue with JSObject being successfully allocated.
// a1: constructor function
// a3: new target
// t4: JSObject
__ jmp(&allocated);
__ bind(&no_inobject_slack_tracking);
}
__ InitializeFieldsWithFiller(t5, t3, t7);
// 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.
__ Addu(t4, t4, Operand(kHeapObjectTag));
// Continue with JSObject being successfully allocated.
// a1: constructor function
// a3: new target

View File

@ -380,36 +380,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ lbu(t1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
__ Branch(&rt_call, eq, t1, Operand(JS_FUNCTION_TYPE));
if (!is_api_function) {
Label allocate;
MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ lwu(a4, bit_field3);
__ DecodeField<Map::Counter>(a6, a4);
__ Branch(
&allocate, lt, a6,
Operand(static_cast<int64_t>(Map::kSlackTrackingCounterEnd)));
// Decrease generous allocation count.
__ Dsubu(a4, a4, Operand(1 << Map::Counter::kShift));
__ Branch(USE_DELAY_SLOT, &allocate, ne, a6,
Operand(Map::kSlackTrackingCounterEnd));
__ sw(a4, bit_field3); // In delay slot.
// Push the constructor, new_target and map to the stack, and
// the map again as an argument to the runtime call.
__ Push(a1, a3, a2, a2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a3, a2);
__ li(a6, Operand(Map::kSlackTrackingCounterEnd - 1));
__ bind(&allocate);
}
// Now allocate the JSObject on the heap.
// a1: constructor function
// a2: initial map
// a6: slack tracking counter (non-API function case)
__ lbu(a4, FieldMemOperand(a2, Map::kInstanceSizeOffset));
__ Allocate(a4, t0, a4, t2, &rt_call, SIZE_IN_WORDS);
@ -418,9 +391,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// a1: constructor function
// a2: initial map
// a3: object size
// t0: JSObject (not tagged)
// t0: JSObject (not HeapObject tagged - the actual address).
// a4: start of next object
// a6: slack tracking counter (non-API function case)
__ LoadRoot(t2, Heap::kEmptyFixedArrayRootIndex);
__ mov(t1, t0);
STATIC_ASSERT(0 * kPointerSize == JSObject::kMapOffset);
@ -432,19 +404,28 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
STATIC_ASSERT(3 * kPointerSize == JSObject::kHeaderSize);
__ Daddu(t1, t1, Operand(3 * kPointerSize));
// Fill all the in-object properties with appropriate filler.
// t1: First in-object property of JSObject (not tagged)
// 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.
__ Daddu(t0, t0, Operand(kHeapObjectTag));
// Use t3 to hold undefined, which is used in several places below.
// Fill all the in-object properties with appropriate filler.
// t0: JSObject (tagged)
// t1: First in-object property of JSObject (not tagged)
__ LoadRoot(t3, Heap::kUndefinedValueRootIndex);
if (!is_api_function) {
Label no_inobject_slack_tracking;
MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
// Check if slack tracking is enabled.
__ Branch(
&no_inobject_slack_tracking, lt, a6,
Operand(static_cast<int64_t>(Map::kSlackTrackingCounterEnd)));
__ lwu(t2, bit_field3);
__ DecodeField<Map::Counter>(a6, t2);
// a6: slack tracking counter
__ Branch(&no_inobject_slack_tracking, lt, a6,
Operand(Map::kSlackTrackingCounterEnd));
// Decrease generous allocation count.
__ Dsubu(t2, t2, Operand(1 << Map::Counter::kShift));
__ sw(t2, bit_field3);
// Allocate object with a slack.
__ lbu(a0, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset));
@ -460,20 +441,32 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// To allow truncation fill the remaining fields with one pointer
// filler map.
__ LoadRoot(t3, Heap::kOnePointerFillerMapRootIndex);
__ InitializeFieldsWithFiller(t1, a4, t3);
// a6: slack tracking counter value before decreasing.
__ Branch(&allocated, ne, a6, Operand(Map::kSlackTrackingCounterEnd));
// Push the constructor, new_target and the object to the stack,
// and then the initial map as an argument to the runtime call.
__ Push(a1, a3, t0, a2);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a3, t0);
// Continue with JSObject being successfully allocated.
// a1: constructor function
// a3: new target
// t0: JSObject
__ jmp(&allocated);
__ bind(&no_inobject_slack_tracking);
}
__ InitializeFieldsWithFiller(t1, a4, t3);
// 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.
__ Daddu(t0, t0, Operand(kHeapObjectTag));
// Continue with JSObject being successfully allocated.
// a1: constructor function
// a3: new target
// a4: JSObject
// t0: JSObject
__ jmp(&allocated);
}

View File

@ -6154,9 +6154,25 @@ bool JSFunction::IsInOptimizationQueue() {
}
bool JSFunction::IsInobjectSlackTrackingInProgress() {
return has_initial_map() &&
initial_map()->counter() >= Map::kSlackTrackingCounterEnd;
void JSFunction::CompleteInobjectSlackTrackingIfActive() {
if (has_initial_map() && initial_map()->IsInobjectSlackTrackingInProgress()) {
initial_map()->CompleteInobjectSlackTracking();
}
}
bool Map::IsInobjectSlackTrackingInProgress() {
return counter() >= Map::kSlackTrackingCounterEnd;
}
void Map::InobjectSlackTrackingStep() {
if (!IsInobjectSlackTrackingInProgress()) return;
int counter = this->counter();
set_counter(counter - 1);
if (counter == kSlackTrackingCounterEnd) {
CompleteInobjectSlackTracking();
}
}

View File

@ -428,17 +428,6 @@ void JSModule::JSModulePrint(std::ostream& os) { // NOLINT
}
static const char* TypeToString(InstanceType type) {
switch (type) {
#define TYPE_TO_STRING(TYPE) case TYPE: return #TYPE;
INSTANCE_TYPE_LIST(TYPE_TO_STRING)
#undef TYPE_TO_STRING
}
UNREACHABLE();
return "UNKNOWN"; // Keep the compiler happy.
}
void Symbol::SymbolPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Symbol");
os << " - hash: " << Hash();
@ -453,7 +442,7 @@ void Symbol::SymbolPrint(std::ostream& os) { // NOLINT
void Map::MapPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Map");
os << " - type: " << TypeToString(instance_type()) << "\n";
os << " - type: " << instance_type() << "\n";
os << " - instance size: " << instance_size() << "\n";
if (IsJSObjectMap()) {
os << " - inobject properties: " << GetInObjectProperties() << "\n";
@ -495,6 +484,7 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
os << "\n - constructor: " << Brief(GetConstructor());
os << "\n - code cache: " << Brief(code_cache());
os << "\n - dependent code: " << Brief(dependent_code());
os << "\n - counter: " << counter();
os << "\n";
}

View File

@ -57,6 +57,19 @@
namespace v8 {
namespace internal {
std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
switch (instance_type) {
#define WRITE_TYPE(TYPE) \
case TYPE: \
return os << #TYPE;
INSTANCE_TYPE_LIST(WRITE_TYPE)
#undef WRITE_TYPE
}
UNREACHABLE();
return os << "UNKNOWN"; // Keep the compiler happy.
}
Handle<HeapType> Object::OptimalType(Isolate* isolate,
Representation representation) {
if (representation.IsNone()) return HeapType::None(isolate);
@ -11994,12 +12007,6 @@ static void ShrinkInstanceSize(Map* map, void* data) {
}
void JSFunction::CompleteInobjectSlackTracking() {
DCHECK(has_initial_map());
initial_map()->CompleteInobjectSlackTracking();
}
void Map::CompleteInobjectSlackTracking() {
// Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined());
@ -12318,9 +12325,7 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
// copy containing the new prototype. Also complete any in-object
// slack tracking that is in progress at this point because it is
// still tracking the old copy.
if (function->IsInobjectSlackTrackingInProgress()) {
function->CompleteInobjectSlackTracking();
}
function->CompleteInobjectSlackTrackingIfActive();
Handle<Map> initial_map(function->initial_map(), isolate);
@ -12551,10 +12556,7 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
// Finally link initial map and constructor function.
DCHECK(prototype->IsJSReceiver());
JSFunction::SetInitialMap(function, map, prototype);
if (!function->shared()->is_generator()) {
function->StartInobjectSlackTracking();
}
map->StartInobjectSlackTracking();
}
@ -12629,7 +12631,7 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
JSFunction::SetInitialMap(new_target_function, map, prototype);
map->SetConstructor(*constructor);
new_target_function->StartInobjectSlackTracking();
map->StartInobjectSlackTracking();
return map;
}
@ -13181,18 +13183,16 @@ bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
}
void JSFunction::StartInobjectSlackTracking() {
DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
Map* map = initial_map();
void Map::StartInobjectSlackTracking() {
DCHECK(!IsInobjectSlackTrackingInProgress());
// No tracking during the snapshot construction phase.
Isolate* isolate = GetIsolate();
if (isolate->serializer_enabled()) return;
if (map->unused_property_fields() == 0) return;
if (unused_property_fields() == 0) return;
map->set_counter(Map::kSlackTrackingCounterStart);
set_counter(Map::kSlackTrackingCounterStart);
}

View File

@ -777,6 +777,9 @@ STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType);
STATIC_ASSERT(FOREIGN_TYPE == Internals::kForeignType);
std::ostream& operator<<(std::ostream& os, InstanceType instance_type);
#define FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(V) \
V(FAST_ELEMENTS_SUB_TYPE) \
V(DICTIONARY_ELEMENTS_SUB_TYPE) \
@ -5498,6 +5501,49 @@ class Map: public HeapObject {
static const int kRetainingCounterStart = kSlackTrackingCounterEnd - 1;
static const int kRetainingCounterEnd = 0;
// Inobject slack tracking is the way to reclaim unused inobject space.
//
// The instance size is initially determined by adding some slack to
// expected_nof_properties (to allow for a few extra properties added
// after the constructor). There is no guarantee that the extra space
// will not be wasted.
//
// Here is the algorithm to reclaim the unused inobject space:
// - Detect the first constructor call for this JSFunction.
// When it happens enter the "in progress" state: initialize construction
// counter in the initial_map.
// - While the tracking is in progress initialize unused properties of a new
// object with one_pointer_filler_map instead of undefined_value (the "used"
// part is initialized with undefined_value as usual). This way they can
// be resized quickly and safely.
// - Once enough objects have been created compute the 'slack'
// (traverse the map transition tree starting from the
// initial_map and find the lowest value of unused_property_fields).
// - Traverse the transition tree again and decrease the instance size
// of every map. Existing objects will resize automatically (they are
// filled with one_pointer_filler_map). All further allocations will
// use the adjusted instance size.
// - SharedFunctionInfo's expected_nof_properties left unmodified since
// allocations made using different closures could actually create different
// kind of objects (see prototype inheritance pattern).
//
// Important: inobject slack tracking is not attempted during the snapshot
// creation.
static const int kGenerousAllocationCount =
kSlackTrackingCounterStart - kSlackTrackingCounterEnd + 1;
// Starts the tracking by initializing object constructions countdown counter.
void StartInobjectSlackTracking();
// True if the object constructions countdown counter is a range
// [kSlackTrackingCounterEnd, kSlackTrackingCounterStart].
inline bool IsInobjectSlackTrackingInProgress();
// Does the tracking step.
inline void InobjectSlackTrackingStep();
// Completes inobject slack tracking for the transition tree starting at this
// initial map.
void CompleteInobjectSlackTracking();
@ -7216,46 +7262,8 @@ class JSFunction: public JSObject {
// Tells whether or not the function is on the concurrent recompilation queue.
inline bool IsInOptimizationQueue();
// Inobject slack tracking is the way to reclaim unused inobject space.
//
// The instance size is initially determined by adding some slack to
// expected_nof_properties (to allow for a few extra properties added
// after the constructor). There is no guarantee that the extra space
// will not be wasted.
//
// Here is the algorithm to reclaim the unused inobject space:
// - Detect the first constructor call for this JSFunction.
// When it happens enter the "in progress" state: initialize construction
// counter in the initial_map.
// - While the tracking is in progress create objects filled with
// one_pointer_filler_map instead of undefined_value. This way they can be
// resized quickly and safely.
// - Once enough objects have been created compute the 'slack'
// (traverse the map transition tree starting from the
// initial_map and find the lowest value of unused_property_fields).
// - Traverse the transition tree again and decrease the instance size
// of every map. Existing objects will resize automatically (they are
// filled with one_pointer_filler_map). All further allocations will
// use the adjusted instance size.
// - SharedFunctionInfo's expected_nof_properties left unmodified since
// allocations made using different closures could actually create different
// kind of objects (see prototype inheritance pattern).
//
// Important: inobject slack tracking is not attempted during the snapshot
// creation.
// True if the initial_map is set and the object constructions countdown
// counter is not zero.
static const int kGenerousAllocationCount =
Map::kSlackTrackingCounterStart - Map::kSlackTrackingCounterEnd + 1;
inline bool IsInobjectSlackTrackingInProgress();
// Starts the tracking.
// Initializes object constructions countdown counter in the initial map.
void StartInobjectSlackTracking();
// Completes the tracking.
void CompleteInobjectSlackTracking();
// Completes inobject slack tracking on initial map if it is active.
inline void CompleteInobjectSlackTrackingIfActive();
// [literals_or_bindings]: Fixed array holding either
// the materialized literals or the bindings of a bound function.

View File

@ -1033,6 +1033,16 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate,
Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
Handle<AllocationSite> site) {
DCHECK(constructor->IsConstructor());
// If called through new, new.target can be:
// - a subclass of constructor,
// - a proxy wrapper around constructor, or
// - the constructor itself.
// If called through Reflect.construct, it's guaranteed to be a constructor by
// REFLECT_CONSTRUCT_PREPARE.
DCHECK(new_target->IsConstructor());
DCHECK(!constructor->has_initial_map() ||
constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
@ -1057,16 +1067,6 @@ RUNTIME_FUNCTION(Runtime_NewObject) {
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1);
DCHECK(constructor->IsConstructor());
// If called through new, new.target can be:
// - a subclass of constructor,
// - a proxy wrapper around constructor, or
// - the constructor itself.
// If called through Reflect.construct, it's guaranteed to be a constructor by
// REFLECT_CONSTRUCT_PREPARE.
DCHECK(new_target->IsConstructor());
return Runtime_NewObjectHelper(isolate, constructor, new_target,
Handle<AllocationSite>::null());
}

View File

@ -155,39 +155,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmpp(rdi, FieldOperand(rax, Map::kConstructorOrBackPointerOffset));
__ j(not_equal, &rt_call);
if (!is_api_function) {
Label allocate;
// The code below relies on these assumptions.
STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
// Check if slack tracking is enabled.
__ movl(rsi, FieldOperand(rax, Map::kBitField3Offset));
__ shrl(rsi, Immediate(Map::Counter::kShift));
__ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
__ j(less, &allocate);
// Decrease generous allocation count.
__ subl(FieldOperand(rax, Map::kBitField3Offset),
Immediate(1 << Map::Counter::kShift));
__ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
__ j(not_equal, &allocate);
// Push the constructor, new_target and map to the stack, and
// the map again as an argument to the runtime call.
__ Push(rax);
__ Push(rdx);
__ Push(rdi);
__ Push(rax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(rdi);
__ Pop(rdx);
__ Pop(rax);
__ movl(rsi, Immediate(Map::kSlackTrackingCounterEnd - 1));
__ bind(&allocate);
}
// Now allocate the JSObject on the heap.
__ movzxbp(r9, FieldOperand(rax, Map::kInstanceSizeOffset));
__ shlp(r9, Immediate(kPointerSizeLog2));
@ -203,20 +170,31 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
__ movp(Operand(rbx, JSObject::kPropertiesOffset), rcx);
__ movp(Operand(rbx, JSObject::kElementsOffset), rcx);
// Set extra fields in the newly allocated object.
// rax: initial map
// rdx: new target
// rbx: JSObject
// r9: start of next object
// rsi: slack tracking counter (non-API function case)
__ leap(rcx, Operand(rbx, JSObject::kHeaderSize));
// 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.
__ orp(rbx, Immediate(kHeapObjectTag));
// Fill all the in-object properties with the appropriate filler.
// rbx: JSObject (tagged)
// rcx: First in-object property of JSObject (not tagged)
__ LoadRoot(r11, Heap::kUndefinedValueRootIndex);
if (!is_api_function) {
Label no_inobject_slack_tracking;
// The code below relies on these assumptions.
STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
// Check if slack tracking is enabled.
__ movl(rsi, FieldOperand(rax, Map::kBitField3Offset));
__ shrl(rsi, Immediate(Map::Counter::kShift));
__ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
__ j(less, &no_inobject_slack_tracking);
__ Push(rsi); // Save allocation count value.
// Decrease generous allocation count.
__ subl(FieldOperand(rax, Map::kBitField3Offset),
Immediate(1 << Map::Counter::kShift));
// Allocate object with a slack.
__ movzxbp(rsi, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
@ -233,17 +211,36 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// To allow truncation fill the remaining fields with one pointer
// filler map.
__ LoadRoot(r11, Heap::kOnePointerFillerMapRootIndex);
__ InitializeFieldsWithFiller(rcx, r9, r11);
__ Pop(rsi); // Restore allocation count value before decreasing.
__ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
__ j(not_equal, &allocated);
// Push the constructor, new_target and the object to the stack,
// and then the initial map as an argument to the runtime call.
__ Push(rdi);
__ Push(rdx);
__ Push(rbx);
__ Push(rax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(rbx);
__ Pop(rdx);
__ Pop(rdi);
// Continue with JSObject being successfully allocated.
// rdi: constructor
// rdx: new target
// rbx: JSObject (tagged)
__ jmp(&allocated);
__ bind(&no_inobject_slack_tracking);
}
__ InitializeFieldsWithFiller(rcx, r9, r11);
// 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.
// rbx: JSObject (untagged)
__ orp(rbx, Immediate(kHeapObjectTag));
// Continue with JSObject being successfully allocated
// rdi: constructor
// rdx: new target

View File

@ -143,6 +143,7 @@
'test-hydrogen-types.cc',
'test-identity-map.cc',
'test-incremental-marking.cc',
'test-inobject-slack-tracking.cc',
'test-list.cc',
'test-liveedit.cc',
'test-lockers.cc',

File diff suppressed because it is too large Load Diff