Commit b9d25d86 authored by verwaest's avatar verwaest Committed by Commit bot

Support fast-path allocation for subclass constructors with correctly initialized initial maps.

BUG=v8:3330
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31913}
parent a594ff73
...@@ -388,17 +388,23 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -388,17 +388,23 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ tst(r2, r2); __ tst(r2, r2);
__ b(ne, &rt_call); __ b(ne, &rt_call);
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ cmp(r1, r3); __ CompareObjectType(r3, r5, r4, JS_FUNCTION_TYPE);
__ b(ne, &rt_call); __ b(ne, &rt_call);
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
// r1: constructor function // r3: original constructor
__ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); __ ldr(r2, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(r2, &rt_call); __ JumpIfSmi(r2, &rt_call);
__ CompareObjectType(r2, r5, r4, MAP_TYPE); __ CompareObjectType(r2, r5, r4, MAP_TYPE);
__ b(ne, &rt_call); __ b(ne, &rt_call);
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ ldr(r5, FieldMemOperand(r2, Map::kConstructorOrBackPointerOffset));
__ cmp(r1, r5);
__ b(ne, &rt_call);
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the // comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE. // initial map's instance type would be JS_FUNCTION_TYPE.
...@@ -421,9 +427,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -421,9 +427,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmp(r3, Operand(Map::kSlackTrackingCounterEnd)); __ cmp(r3, Operand(Map::kSlackTrackingCounterEnd));
__ b(ne, &allocate); __ b(ne, &allocate);
__ push(r1); __ Push(r1, r2);
__ Push(r2, r1); // r1 = constructor __ push(r2); // r2 = intial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(r2); __ pop(r2);
......
...@@ -390,18 +390,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -390,18 +390,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Ldr(x2, MemOperand(x2)); __ Ldr(x2, MemOperand(x2));
__ Cbnz(x2, &rt_call); __ Cbnz(x2, &rt_call);
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ Cmp(constructor, original_constructor); __ JumpIfNotObjectType(original_constructor, x10, x11, JS_FUNCTION_TYPE,
__ B(ne, &rt_call); &rt_call);
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
Register init_map = x2; Register init_map = x2;
__ Ldr(init_map, __ Ldr(init_map,
FieldMemOperand(constructor, FieldMemOperand(original_constructor,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(init_map, &rt_call); __ JumpIfSmi(init_map, &rt_call);
__ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call); __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ Ldr(x10,
FieldMemOperand(init_map, Map::kConstructorOrBackPointerOffset));
__ Cmp(constructor, x10);
__ B(ne, &rt_call);
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the initial // comments in Runtime_NewObject in runtime.cc). In which case the initial
// map's instance type would be JS_FUNCTION_TYPE. // map's instance type would be JS_FUNCTION_TYPE.
...@@ -424,9 +431,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -424,9 +431,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ B(ne, &allocate); __ B(ne, &allocate);
// Push the constructor and map to the stack, and the constructor again // Push the constructor and map to the stack, and the map again
// as argument to the runtime call. // as argument to the runtime call.
__ Push(constructor, init_map, constructor); __ Push(constructor, init_map, init_map);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(init_map, constructor); __ Pop(init_map, constructor);
__ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1)); __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
......
...@@ -151,14 +151,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -151,14 +151,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0)); __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ cmp(edx, edi); __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx);
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Verified that the constructor is a JSFunction.
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
// edi: constructor // edx: original constructor
__ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); __ mov(eax, FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi // Will both indicate a NULL and a Smi
__ JumpIfSmi(eax, &rt_call); __ JumpIfSmi(eax, &rt_call);
// edi: constructor // edi: constructor
...@@ -166,6 +165,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -166,6 +165,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpObjectType(eax, MAP_TYPE, ebx); __ CmpObjectType(eax, MAP_TYPE, ebx);
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ cmp(edi, FieldOperand(eax, Map::kConstructorOrBackPointerOffset));
__ j(not_equal, &rt_call);
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the // comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE. // initial map's instance type would be JS_FUNCTION_TYPE.
...@@ -194,7 +198,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -194,7 +198,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(edx); __ push(edx);
__ push(edi); __ push(edi);
__ push(edi); // constructor __ push(eax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(edi); __ pop(edi);
......
...@@ -396,16 +396,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -396,16 +396,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ lw(a2, MemOperand(a2)); __ lw(a2, MemOperand(a2));
__ Branch(&rt_call, ne, a2, Operand(zero_reg)); __ Branch(&rt_call, ne, a2, Operand(zero_reg));
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ Branch(&rt_call, ne, a1, Operand(a3)); __ GetObjectType(a3, t1, t0);
__ Branch(&rt_call, ne, t0, Operand(JS_FUNCTION_TYPE));
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
// a1: constructor function // a3: original constructor
__ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); __ lw(a2, FieldMemOperand(a3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(a2, &rt_call); __ JumpIfSmi(a2, &rt_call);
__ GetObjectType(a2, t5, t4); __ GetObjectType(a2, t5, t4);
__ Branch(&rt_call, ne, t4, Operand(MAP_TYPE)); __ Branch(&rt_call, ne, t4, Operand(MAP_TYPE));
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ lw(t1, FieldMemOperand(a2, Map::kConstructorOrBackPointerOffset));
__ Branch(&rt_call, ne, a1, Operand(t1));
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the // comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE. // initial map's instance type would be JS_FUNCTION_TYPE.
...@@ -427,7 +433,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -427,7 +433,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Operand(Map::kSlackTrackingCounterEnd)); Operand(Map::kSlackTrackingCounterEnd));
__ sw(t0, bit_field3); // In delay slot. __ sw(t0, bit_field3); // In delay slot.
__ Push(a1, a2, a1); // a1 = Constructor. __ Push(a1, a2, a2); // a2 = Initial map.
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a2); __ Pop(a1, a2);
......
...@@ -393,16 +393,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -393,16 +393,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ ld(a2, MemOperand(a2)); __ ld(a2, MemOperand(a2));
__ Branch(&rt_call, ne, a2, Operand(zero_reg)); __ Branch(&rt_call, ne, a2, Operand(zero_reg));
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ Branch(&rt_call, ne, a1, Operand(a3)); __ GetObjectType(a3, a5, a4);
__ Branch(&rt_call, ne, a4, Operand(JS_FUNCTION_TYPE));
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
// a1: constructor function // a3: original constructor
__ ld(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset)); __ ld(a2, FieldMemOperand(a3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(a2, &rt_call); __ JumpIfSmi(a2, &rt_call);
__ GetObjectType(a2, t1, t0); __ GetObjectType(a2, t1, t0);
__ Branch(&rt_call, ne, t0, Operand(MAP_TYPE)); __ Branch(&rt_call, ne, t0, Operand(MAP_TYPE));
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ ld(a5, FieldMemOperand(a2, Map::kConstructorOrBackPointerOffset));
__ Branch(&rt_call, ne, a1, Operand(a5));
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the // comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE. // initial map's instance type would be JS_FUNCTION_TYPE.
...@@ -425,7 +431,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -425,7 +431,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Operand(Map::kSlackTrackingCounterEnd)); Operand(Map::kSlackTrackingCounterEnd));
__ sw(a4, bit_field3); // In delay slot. __ sw(a4, bit_field3); // In delay slot.
__ Push(a1, a2, a1); // a1 = Constructor. __ Push(a1, a2, a2); // a2 = Initial map.
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a2); __ Pop(a1, a2);
......
...@@ -11244,16 +11244,22 @@ static void ShrinkInstanceSize(Map* map, void* data) { ...@@ -11244,16 +11244,22 @@ static void ShrinkInstanceSize(Map* map, void* data) {
void JSFunction::CompleteInobjectSlackTracking() { void JSFunction::CompleteInobjectSlackTracking() {
DCHECK(has_initial_map()); DCHECK(has_initial_map());
Map* map = initial_map(); initial_map()->CompleteInobjectSlackTracking();
}
DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
map->set_counter(Map::kRetainingCounterStart);
int slack = map->unused_property_fields(); void Map::CompleteInobjectSlackTracking() {
TransitionArray::TraverseTransitionTree(map, &GetMinInobjectSlack, &slack); // Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined());
DCHECK_GE(counter(), kSlackTrackingCounterEnd - 1);
set_counter(kRetainingCounterStart);
int slack = unused_property_fields();
TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
if (slack != 0) { if (slack != 0) {
// Resize the initial map and all maps in its transition tree. // Resize the initial map and all maps in its transition tree.
TransitionArray::TraverseTransitionTree(map, &ShrinkInstanceSize, &slack); TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
} }
} }
......
...@@ -5579,6 +5579,10 @@ class Map: public HeapObject { ...@@ -5579,6 +5579,10 @@ class Map: public HeapObject {
static const int kRetainingCounterStart = kSlackTrackingCounterEnd - 1; static const int kRetainingCounterStart = kSlackTrackingCounterEnd - 1;
static const int kRetainingCounterEnd = 0; static const int kRetainingCounterEnd = 0;
// Completes inobject slack tracking for the transition tree starting at this
// initial map.
void CompleteInobjectSlackTracking();
// Tells whether the object in the prototype property will be used // Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype // for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype // property is set to a value that is not a JSObject, the prototype
......
...@@ -1038,8 +1038,8 @@ RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) { ...@@ -1038,8 +1038,8 @@ RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0);
function->CompleteInobjectSlackTracking(); initial_map->CompleteInobjectSlackTracking();
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
...@@ -149,14 +149,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -149,14 +149,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmpp(Operand(kScratchRegister, 0), Immediate(0)); __ cmpp(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Fall back to runtime if the original constructor and function differ. // Verify that the original constructor is a JSFunction.
__ cmpp(rdx, rdi); __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rbx);
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Verified that the constructor is a JSFunction.
// Load the initial map and verify that it is in fact a map. // Load the initial map and verify that it is in fact a map.
// rdi: constructor // rdx: original constructor
__ movp(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); __ movp(rax, FieldOperand(rdx, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi // Will both indicate a NULL and a Smi
DCHECK(kSmiTag == 0); DCHECK(kSmiTag == 0);
__ JumpIfSmi(rax, &rt_call); __ JumpIfSmi(rax, &rt_call);
...@@ -165,6 +164,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -165,6 +164,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpObjectType(rax, MAP_TYPE, rbx); __ CmpObjectType(rax, MAP_TYPE, rbx);
__ j(not_equal, &rt_call); __ j(not_equal, &rt_call);
// Fall back to runtime if the expected base constructor and base
// constructor differ.
__ cmpp(rdi, FieldOperand(rax, Map::kConstructorOrBackPointerOffset));
__ j(not_equal, &rt_call);
// Check that the constructor is not constructing a JSFunction (see // Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the // comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE. // initial map's instance type would be JS_FUNCTION_TYPE.
...@@ -192,7 +196,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -192,7 +196,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Push(rdx); __ Push(rdx);
__ Push(rdi); __ Push(rdi);
__ Push(rdi); // constructor __ Push(rax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1); __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(rdi); __ Pop(rdi);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment