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:
parent
5cdb107f88
commit
5d38d6819c
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
1098
test/cctest/test-inobject-slack-tracking.cc
Normal file
1098
test/cctest/test-inobject-slack-tracking.cc
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user