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,
__ tst(r2, r2);
__ b(ne, &rt_call);
// Fall back to runtime if the original constructor and function differ.
__ cmp(r1, r3);
// Verify that the original constructor is a JSFunction.
__ CompareObjectType(r3, r5, r4, JS_FUNCTION_TYPE);
__ b(ne, &rt_call);
// Load the initial map and verify that it is in fact a map.
// r1: constructor function
__ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
// r3: original constructor
__ ldr(r2, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(r2, &rt_call);
__ CompareObjectType(r2, r5, r4, MAP_TYPE);
__ 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
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
......@@ -421,9 +427,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmp(r3, Operand(Map::kSlackTrackingCounterEnd));
__ b(ne, &allocate);
__ push(r1);
__ Push(r1, r2);
__ Push(r2, r1); // r1 = constructor
__ push(r2); // r2 = intial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(r2);
......
......@@ -390,18 +390,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Ldr(x2, MemOperand(x2));
__ Cbnz(x2, &rt_call);
// Fall back to runtime if the original constructor and function differ.
__ Cmp(constructor, original_constructor);
__ B(ne, &rt_call);
// Verify that the original constructor is a JSFunction.
__ JumpIfNotObjectType(original_constructor, x10, x11, JS_FUNCTION_TYPE,
&rt_call);
// Load the initial map and verify that it is in fact a map.
Register init_map = x2;
__ Ldr(init_map,
FieldMemOperand(constructor,
FieldMemOperand(original_constructor,
JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(init_map, &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
// comments in Runtime_NewObject in runtime.cc). In which case the initial
// map's instance type would be JS_FUNCTION_TYPE.
......@@ -424,9 +431,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
__ 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.
__ Push(constructor, init_map, constructor);
__ Push(constructor, init_map, init_map);
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(init_map, constructor);
__ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
......
......@@ -151,14 +151,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
__ j(not_equal, &rt_call);
// Fall back to runtime if the original constructor and function differ.
__ cmp(edx, edi);
// Verify that the original constructor is a JSFunction.
__ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx);
__ 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.
// edi: constructor
__ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
// edx: original constructor
__ mov(eax, FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi
__ JumpIfSmi(eax, &rt_call);
// edi: constructor
......@@ -166,6 +165,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpObjectType(eax, MAP_TYPE, ebx);
__ 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
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
......@@ -194,7 +198,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(edx);
__ push(edi);
__ push(edi); // constructor
__ push(eax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ pop(edi);
......
......@@ -396,16 +396,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ lw(a2, MemOperand(a2));
__ Branch(&rt_call, ne, a2, Operand(zero_reg));
// Fall back to runtime if the original constructor and function differ.
__ Branch(&rt_call, ne, a1, Operand(a3));
// Verify that the original constructor is a JSFunction.
__ 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.
// a1: constructor function
__ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
// a3: original constructor
__ lw(a2, FieldMemOperand(a3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(a2, &rt_call);
__ GetObjectType(a2, t5, t4);
__ 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
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
......@@ -427,7 +433,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Operand(Map::kSlackTrackingCounterEnd));
__ sw(t0, bit_field3); // In delay slot.
__ Push(a1, a2, a1); // a1 = Constructor.
__ Push(a1, a2, a2); // a2 = Initial map.
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a2);
......
......@@ -393,16 +393,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ ld(a2, MemOperand(a2));
__ Branch(&rt_call, ne, a2, Operand(zero_reg));
// Fall back to runtime if the original constructor and function differ.
__ Branch(&rt_call, ne, a1, Operand(a3));
// Verify that the original constructor is a JSFunction.
__ 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.
// a1: constructor function
__ ld(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
// a3: original constructor
__ ld(a2, FieldMemOperand(a3, JSFunction::kPrototypeOrInitialMapOffset));
__ JumpIfSmi(a2, &rt_call);
__ GetObjectType(a2, t1, t0);
__ 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
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
......@@ -425,7 +431,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Operand(Map::kSlackTrackingCounterEnd));
__ sw(a4, bit_field3); // In delay slot.
__ Push(a1, a2, a1); // a1 = Constructor.
__ Push(a1, a2, a2); // a2 = Initial map.
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(a1, a2);
......
......@@ -11244,16 +11244,22 @@ static void ShrinkInstanceSize(Map* map, void* data) {
void JSFunction::CompleteInobjectSlackTracking() {
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();
TransitionArray::TraverseTransitionTree(map, &GetMinInobjectSlack, &slack);
void Map::CompleteInobjectSlackTracking() {
// 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) {
// 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 {
static const int kRetainingCounterStart = kSlackTrackingCounterEnd - 1;
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
// for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype
......
......@@ -1038,8 +1038,8 @@ RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
function->CompleteInobjectSlackTracking();
CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0);
initial_map->CompleteInobjectSlackTracking();
return isolate->heap()->undefined_value();
}
......
......@@ -149,14 +149,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmpp(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &rt_call);
// Fall back to runtime if the original constructor and function differ.
__ cmpp(rdx, rdi);
// Verify that the original constructor is a JSFunction.
__ CmpObjectType(rdx, JS_FUNCTION_TYPE, rbx);
__ 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.
// rdi: constructor
__ movp(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
// rdx: original constructor
__ movp(rax, FieldOperand(rdx, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi
DCHECK(kSmiTag == 0);
__ JumpIfSmi(rax, &rt_call);
......@@ -165,6 +164,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpObjectType(rax, MAP_TYPE, rbx);
__ 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
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
......@@ -192,7 +196,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Push(rdx);
__ Push(rdi);
__ Push(rdi); // constructor
__ Push(rax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ 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