Revert [TypeFeedbackVector] Root literal arrays in function literal slots
GC performance issues need to be addressed first.
TBR=bmeurer@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:5456
Review-Url: https://codereview.chromium.org/2642743002
Cr-Original-Commit-Position: refs/heads/master@{#42495}
Committed: 7803aa1ffb
Review-Url: https://codereview.chromium.org/2642743002
Cr-Commit-Position: refs/heads/master@{#42517}
This commit is contained in:
parent
f604724448
commit
55feaaea4c
@ -1339,19 +1339,12 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register argument_count = r0;
|
||||
Register closure = r1;
|
||||
Register new_target = r3;
|
||||
Register map = argument_count;
|
||||
Register index = r2;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ ldr(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ ldr(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex,
|
||||
&gotta_call_runtime_no_stack);
|
||||
|
||||
__ push(argument_count);
|
||||
__ push(new_target);
|
||||
__ push(closure);
|
||||
|
||||
Register map = argument_count;
|
||||
Register index = r2;
|
||||
__ ldr(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ldr(map,
|
||||
FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
|
||||
@ -1359,6 +1352,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Operand(Smi::FromInt(2)));
|
||||
__ b(lt, &gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// r3 : native context
|
||||
// r2 : length / index
|
||||
// r0 : optimized code map
|
||||
@ -1378,6 +1372,20 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ cmp(temp, native_context);
|
||||
__ b(ne, &loop_bottom);
|
||||
// Literals available?
|
||||
__ ldr(temp, FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ ldr(r4, MemOperand(sp, 0));
|
||||
__ str(temp, FieldMemOperand(r4, JSFunction::kLiteralsOffset));
|
||||
__ push(index);
|
||||
__ RecordWriteField(r4, JSFunction::kLiteralsOffset, temp, index,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ pop(index);
|
||||
|
||||
// Code available?
|
||||
Register entry = r4;
|
||||
@ -1387,7 +1395,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ pop(closure);
|
||||
// Store code entry in the closure.
|
||||
__ add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
@ -1422,7 +1430,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Operand(Smi::FromInt(1)));
|
||||
__ b(gt, &loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1350,12 +1350,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register closure = x1;
|
||||
Register map = x13;
|
||||
Register index = x2;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ Ldr(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ Ldr(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex, &gotta_call_runtime);
|
||||
|
||||
__ Ldr(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ Ldr(map,
|
||||
FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
|
||||
@ -1363,6 +1357,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ Cmp(index, Operand(2));
|
||||
__ B(lt, &gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// x3 : native context
|
||||
// x2 : length / index
|
||||
// x13 : optimized code map
|
||||
@ -1382,6 +1377,17 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ Cmp(temp, native_context);
|
||||
__ B(ne, &loop_bottom);
|
||||
// Literals available?
|
||||
__ Ldr(temp, FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ Ldr(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ Str(temp, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, x7,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
|
||||
// Code available?
|
||||
Register entry = x7;
|
||||
@ -1391,7 +1397,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ Ldr(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ Add(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ Str(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset));
|
||||
__ RecordWriteCodeEntryField(closure, entry, x5);
|
||||
@ -1420,7 +1426,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ Cmp(index, Operand(1));
|
||||
__ B(gt, &loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ B(&gotta_call_runtime);
|
||||
|
||||
__ Bind(&try_shared);
|
||||
|
@ -120,14 +120,13 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
|
||||
|
||||
// Initialize the rest of the function.
|
||||
Node* empty_fixed_array = HeapConstant(factory->empty_fixed_array());
|
||||
Node* empty_literals_array = HeapConstant(factory->empty_literals_array());
|
||||
StoreObjectFieldNoWriteBarrier(result, JSObject::kPropertiesOffset,
|
||||
empty_fixed_array);
|
||||
StoreObjectFieldNoWriteBarrier(result, JSObject::kElementsOffset,
|
||||
empty_fixed_array);
|
||||
Node* literals_array = LoadFixedArrayElement(
|
||||
feedback_vector, slot, 0, CodeStubAssembler::SMI_PARAMETERS);
|
||||
StoreObjectFieldNoWriteBarrier(result, JSFunction::kLiteralsOffset,
|
||||
literals_array);
|
||||
empty_literals_array);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result, JSFunction::kPrototypeOrInitialMapOffset, TheHoleConstant());
|
||||
StoreObjectFieldNoWriteBarrier(result, JSFunction::kSharedFunctionInfoOffset,
|
||||
|
@ -1027,12 +1027,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register new_target = edx;
|
||||
Register argument_count = eax;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ mov(ebx, FieldOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ cmp(ebx, masm->isolate()->factory()->undefined_value());
|
||||
__ j(equal, &gotta_call_runtime_no_stack);
|
||||
|
||||
__ push(argument_count);
|
||||
__ push(new_target);
|
||||
__ push(closure);
|
||||
@ -1045,6 +1039,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Immediate(Smi::FromInt(2)));
|
||||
__ j(less, &gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// edx : native context
|
||||
// ebx : length / index
|
||||
// eax : optimized code map
|
||||
@ -1062,6 +1057,20 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ cmp(temp, native_context);
|
||||
__ j(not_equal, &loop_bottom);
|
||||
// Literals available?
|
||||
__ mov(temp, FieldOperand(map, index, times_half_pointer_size,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ mov(ecx, Operand(esp, 0));
|
||||
__ mov(FieldOperand(ecx, JSFunction::kLiteralsOffset), temp);
|
||||
__ push(index);
|
||||
__ RecordWriteField(ecx, JSFunction::kLiteralsOffset, temp, index,
|
||||
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
__ pop(index);
|
||||
|
||||
// Code available?
|
||||
Register entry = ecx;
|
||||
__ mov(entry, FieldOperand(map, index, times_half_pointer_size,
|
||||
@ -1069,7 +1078,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ pop(closure);
|
||||
// Store code entry in the closure.
|
||||
__ lea(entry, FieldOperand(entry, Code::kHeaderSize));
|
||||
@ -1103,7 +1112,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Immediate(Smi::FromInt(1)));
|
||||
__ j(greater, &loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1352,24 +1352,18 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register argument_count = a0;
|
||||
Register closure = a1;
|
||||
Register new_target = a3;
|
||||
Register map = a0;
|
||||
Register index = a2;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ lw(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ lw(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex,
|
||||
&gotta_call_runtime_no_stack);
|
||||
|
||||
__ push(argument_count);
|
||||
__ push(new_target);
|
||||
__ push(closure);
|
||||
|
||||
Register map = a0;
|
||||
Register index = a2;
|
||||
__ lw(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ lw(map, FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
|
||||
__ lw(index, FieldMemOperand(map, FixedArray::kLengthOffset));
|
||||
__ Branch(&gotta_call_runtime, lt, index, Operand(Smi::FromInt(2)));
|
||||
|
||||
// Find literals.
|
||||
// a3 : native context
|
||||
// a2 : length / index
|
||||
// a0 : optimized code map
|
||||
@ -1389,6 +1383,20 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
SharedFunctionInfo::kOffsetToPreviousContext));
|
||||
__ lw(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ Branch(&loop_bottom, ne, temp, Operand(native_context));
|
||||
// Literals available?
|
||||
__ lw(temp, FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ lw(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ lw(t0, MemOperand(sp, 0));
|
||||
__ sw(temp, FieldMemOperand(t0, JSFunction::kLiteralsOffset));
|
||||
__ push(index);
|
||||
__ RecordWriteField(t0, JSFunction::kLiteralsOffset, temp, index,
|
||||
kRAHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ pop(index);
|
||||
|
||||
// Code available?
|
||||
Register entry = t0;
|
||||
@ -1398,7 +1406,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ lw(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ pop(closure);
|
||||
// Store code entry in the closure.
|
||||
__ Addu(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
@ -1433,7 +1441,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
|
||||
__ Branch(&loop_top, gt, index, Operand(Smi::FromInt(1)));
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1343,24 +1343,18 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register argument_count = a0;
|
||||
Register closure = a1;
|
||||
Register new_target = a3;
|
||||
Register map = a0;
|
||||
Register index = a2;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ ld(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ ld(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex,
|
||||
&gotta_call_runtime_no_stack);
|
||||
|
||||
__ push(argument_count);
|
||||
__ push(new_target);
|
||||
__ push(closure);
|
||||
|
||||
Register map = a0;
|
||||
Register index = a2;
|
||||
__ ld(map, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ ld(map, FieldMemOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
|
||||
__ ld(index, FieldMemOperand(map, FixedArray::kLengthOffset));
|
||||
__ Branch(&gotta_call_runtime, lt, index, Operand(Smi::FromInt(2)));
|
||||
|
||||
// Find literals.
|
||||
// a3 : native context
|
||||
// a2 : length / index
|
||||
// a0 : optimized code map
|
||||
@ -1380,6 +1374,20 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
SharedFunctionInfo::kOffsetToPreviousContext));
|
||||
__ ld(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ Branch(&loop_bottom, ne, temp, Operand(native_context));
|
||||
// Literals available?
|
||||
__ ld(temp, FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ ld(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ ld(a4, MemOperand(sp, 0));
|
||||
__ sd(temp, FieldMemOperand(a4, JSFunction::kLiteralsOffset));
|
||||
__ push(index);
|
||||
__ RecordWriteField(a4, JSFunction::kLiteralsOffset, temp, index,
|
||||
kRAHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ pop(index);
|
||||
|
||||
// Code available?
|
||||
Register entry = a4;
|
||||
@ -1389,7 +1397,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ ld(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ pop(closure);
|
||||
// Store code entry in the closure.
|
||||
__ Daddu(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
@ -1424,7 +1432,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength)));
|
||||
__ Branch(&loop_top, gt, index, Operand(Smi::FromInt(1)));
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1363,12 +1363,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register closure = r4;
|
||||
Register map = r9;
|
||||
Register index = r5;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ LoadP(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ LoadP(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex, &gotta_call_runtime);
|
||||
|
||||
__ LoadP(map,
|
||||
FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ LoadP(map,
|
||||
@ -1377,6 +1371,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ CmpSmiLiteral(index, Smi::FromInt(2), r0);
|
||||
__ blt(&gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// r10 : native context
|
||||
// r5 : length / index
|
||||
// r9 : optimized code map
|
||||
@ -1397,6 +1392,18 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ LoadP(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ cmp(temp, native_context);
|
||||
__ bne(&loop_bottom);
|
||||
// Literals available?
|
||||
__ LoadP(temp,
|
||||
FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ LoadP(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ StoreP(temp, FieldMemOperand(closure, JSFunction::kLiteralsOffset), r0);
|
||||
__ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, r7,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
|
||||
// Code available?
|
||||
Register entry = r7;
|
||||
@ -1406,7 +1413,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ LoadP(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
// Store code entry in the closure.
|
||||
__ addi(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ StoreP(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0);
|
||||
@ -1440,7 +1447,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ CmpSmiLiteral(index, Smi::FromInt(1), r0);
|
||||
__ bgt(&loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ b(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1368,12 +1368,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register closure = r3;
|
||||
Register map = r8;
|
||||
Register index = r4;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ LoadP(index, FieldMemOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ LoadP(index, FieldMemOperand(index, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(index, Heap::kUndefinedValueRootIndex, &gotta_call_runtime);
|
||||
|
||||
__ LoadP(map,
|
||||
FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ LoadP(map,
|
||||
@ -1403,6 +1397,18 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ LoadP(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ CmpP(temp, native_context);
|
||||
__ bne(&loop_bottom, Label::kNear);
|
||||
// Literals available?
|
||||
__ LoadP(temp,
|
||||
FieldMemOperand(array_pointer,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ LoadP(temp, FieldMemOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ StoreP(temp, FieldMemOperand(closure, JSFunction::kLiteralsOffset), r0);
|
||||
__ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, r6,
|
||||
kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
|
||||
// Code available?
|
||||
Register entry = r6;
|
||||
@ -1412,7 +1418,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ LoadP(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
// Store code entry in the closure.
|
||||
__ AddP(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ StoreP(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0);
|
||||
@ -1446,7 +1452,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ CmpSmiLiteral(index, Smi::FromInt(1), r0);
|
||||
__ bgt(&loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ b(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -998,18 +998,13 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register closure = rdi;
|
||||
Register map = r8;
|
||||
Register index = r9;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ movp(rbx, FieldOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ movp(rbx, FieldOperand(rbx, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ JumpIfRoot(rbx, Heap::kUndefinedValueRootIndex, &gotta_call_runtime);
|
||||
|
||||
__ movp(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ movp(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset));
|
||||
__ SmiToInteger32(index, FieldOperand(map, FixedArray::kLengthOffset));
|
||||
__ cmpl(index, Immediate(2));
|
||||
__ j(less, &gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// r14 : native context
|
||||
// r9 : length / index
|
||||
// r8 : optimized code map
|
||||
@ -1026,6 +1021,17 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ movp(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ cmpp(temp, native_context);
|
||||
__ j(not_equal, &loop_bottom);
|
||||
// Literals available?
|
||||
__ movp(temp, FieldOperand(map, index, times_pointer_size,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ movp(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ movp(FieldOperand(closure, JSFunction::kLiteralsOffset), temp);
|
||||
__ movp(r15, index);
|
||||
__ RecordWriteField(closure, JSFunction::kLiteralsOffset, temp, r15,
|
||||
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
|
||||
// Code available?
|
||||
Register entry = rcx;
|
||||
@ -1034,7 +1040,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ movp(entry, FieldOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ leap(entry, FieldOperand(entry, Code::kHeaderSize));
|
||||
__ movp(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry);
|
||||
__ RecordWriteCodeEntryField(closure, entry, r15);
|
||||
@ -1065,7 +1071,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmpl(index, Immediate(1));
|
||||
__ j(greater, &loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -1028,12 +1028,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
Register new_target = edx;
|
||||
Register argument_count = eax;
|
||||
|
||||
// Do we have a valid feedback vector?
|
||||
__ mov(ebx, FieldOperand(closure, JSFunction::kLiteralsOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, LiteralsArray::kFeedbackVectorOffset));
|
||||
__ cmp(ebx, masm->isolate()->factory()->undefined_value());
|
||||
__ j(equal, &gotta_call_runtime_no_stack);
|
||||
|
||||
__ push(argument_count);
|
||||
__ push(new_target);
|
||||
__ push(closure);
|
||||
@ -1046,6 +1040,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Immediate(Smi::FromInt(2)));
|
||||
__ j(less, &gotta_call_runtime);
|
||||
|
||||
// Find literals.
|
||||
// edx : native context
|
||||
// ebx : length / index
|
||||
// eax : optimized code map
|
||||
@ -1063,6 +1058,20 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ cmp(temp, native_context);
|
||||
__ j(not_equal, &loop_bottom);
|
||||
// Literals available?
|
||||
__ mov(temp, FieldOperand(map, index, times_half_pointer_size,
|
||||
SharedFunctionInfo::kOffsetToPreviousLiterals));
|
||||
__ mov(temp, FieldOperand(temp, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(temp, &gotta_call_runtime);
|
||||
|
||||
// Save the literals in the closure.
|
||||
__ mov(ecx, Operand(esp, 0));
|
||||
__ mov(FieldOperand(ecx, JSFunction::kLiteralsOffset), temp);
|
||||
__ push(index);
|
||||
__ RecordWriteField(ecx, JSFunction::kLiteralsOffset, temp, index,
|
||||
kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
__ pop(index);
|
||||
|
||||
// Code available?
|
||||
Register entry = ecx;
|
||||
__ mov(entry, FieldOperand(map, index, times_half_pointer_size,
|
||||
@ -1070,7 +1079,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ mov(entry, FieldOperand(entry, WeakCell::kValueOffset));
|
||||
__ JumpIfSmi(entry, &try_shared);
|
||||
|
||||
// Found code. Get it into the closure and return.
|
||||
// Found literals and code. Get them into the closure and return.
|
||||
__ pop(closure);
|
||||
// Store code entry in the closure.
|
||||
__ lea(entry, FieldOperand(entry, Code::kHeaderSize));
|
||||
@ -1104,7 +1113,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
||||
__ cmp(index, Immediate(Smi::FromInt(1)));
|
||||
__ j(greater, &loop_top);
|
||||
|
||||
// We found no code.
|
||||
// We found neither literals nor code.
|
||||
__ jmp(&gotta_call_runtime);
|
||||
|
||||
__ bind(&try_shared);
|
||||
|
@ -598,13 +598,14 @@ MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap(
|
||||
&RuntimeCallStats::CompileGetFromOptimizedCodeMap);
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
DisallowHeapAllocation no_gc;
|
||||
Code* code = shared->SearchOptimizedCodeMap(
|
||||
CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
|
||||
function->context()->native_context(), osr_ast_id);
|
||||
if (code != nullptr) {
|
||||
if (cached.code != nullptr) {
|
||||
// Caching of optimized code enabled and optimized code found.
|
||||
DCHECK(!code->marked_for_deoptimization());
|
||||
if (cached.literals != nullptr) function->set_literals(cached.literals);
|
||||
DCHECK(!cached.code->marked_for_deoptimization());
|
||||
DCHECK(function->shared()->is_compiled());
|
||||
return Handle<Code>(code);
|
||||
return Handle<Code>(cached.code);
|
||||
}
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
@ -626,9 +627,10 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
|
||||
// Cache optimized context-specific code.
|
||||
Handle<JSFunction> function = info->closure();
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
Handle<LiteralsArray> literals(function->literals());
|
||||
Handle<Context> native_context(function->context()->native_context());
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code,
|
||||
info->osr_ast_id());
|
||||
literals, info->osr_ast_id());
|
||||
}
|
||||
|
||||
bool GetOptimizedCodeNow(CompilationJob* job) {
|
||||
@ -864,8 +866,10 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) {
|
||||
} else if (job->FinalizeJob() == CompilationJob::SUCCEEDED) {
|
||||
job->RecordOptimizedCompilationStats();
|
||||
RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info);
|
||||
if (shared->SearchOptimizedCodeMap(info->context()->native_context(),
|
||||
info->osr_ast_id()) == nullptr) {
|
||||
if (shared
|
||||
->SearchOptimizedCodeMap(info->context()->native_context(),
|
||||
info->osr_ast_id())
|
||||
.code == nullptr) {
|
||||
InsertCodeIntoOptimizedCodeMap(info);
|
||||
}
|
||||
if (FLAG_trace_opt) {
|
||||
@ -1752,16 +1756,19 @@ void Compiler::PostInstantiation(Handle<JSFunction> function,
|
||||
function->MarkForOptimization();
|
||||
}
|
||||
|
||||
Code* code = shared->SearchOptimizedCodeMap(
|
||||
CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
|
||||
function->context()->native_context(), BailoutId::None());
|
||||
if (code != nullptr) {
|
||||
if (cached.code != nullptr) {
|
||||
// Caching of optimized code enabled and optimized code found.
|
||||
DCHECK(!code->marked_for_deoptimization());
|
||||
DCHECK(!cached.code->marked_for_deoptimization());
|
||||
DCHECK(function->shared()->is_compiled());
|
||||
function->ReplaceCode(code);
|
||||
function->ReplaceCode(cached.code);
|
||||
}
|
||||
|
||||
if (shared->is_compiled()) {
|
||||
if (cached.literals != nullptr) {
|
||||
DCHECK(shared->is_compiled());
|
||||
function->set_literals(cached.literals);
|
||||
} else if (shared->is_compiled()) {
|
||||
// TODO(mvstanton): pass pretenure flag to EnsureLiterals.
|
||||
JSFunction::EnsureLiterals(function);
|
||||
}
|
||||
|
@ -764,15 +764,12 @@ Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
|
||||
Node* function_map = jsgraph()->HeapConstant(
|
||||
handle(Map::cast(native_context()->get(function_map_index)), isolate()));
|
||||
|
||||
FeedbackVectorSlot slot = p.feedback().slot();
|
||||
Node* literals = jsgraph()->HeapConstant(
|
||||
handle(LiteralsArray::cast(p.feedback().vector()->Get(slot)), isolate()));
|
||||
|
||||
// Note that it is only safe to embed the raw entry point of the compile
|
||||
// lazy stub into the code, because that stub is immortal and immovable.
|
||||
Node* compile_entry = jsgraph()->PointerConstant(
|
||||
jsgraph()->isolate()->builtins()->CompileLazy()->entry());
|
||||
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
|
||||
Node* empty_literals_array = jsgraph()->EmptyLiteralsArrayConstant();
|
||||
Node* the_hole = jsgraph()->TheHoleConstant();
|
||||
Node* undefined = jsgraph()->UndefinedConstant();
|
||||
AllocationBuilder a(jsgraph(), effect, control);
|
||||
@ -781,7 +778,7 @@ Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
|
||||
a.Store(AccessBuilder::ForMap(), function_map);
|
||||
a.Store(AccessBuilder::ForJSObjectProperties(), empty_fixed_array);
|
||||
a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
|
||||
a.Store(AccessBuilder::ForJSFunctionLiterals(), literals);
|
||||
a.Store(AccessBuilder::ForJSFunctionLiterals(), empty_literals_array);
|
||||
a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(), the_hole);
|
||||
a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
|
||||
a.Store(AccessBuilder::ForJSFunctionContext(), context);
|
||||
|
@ -66,6 +66,11 @@ Node* JSGraph::EmptyFixedArrayConstant() {
|
||||
HeapConstant(factory()->empty_fixed_array()));
|
||||
}
|
||||
|
||||
Node* JSGraph::EmptyLiteralsArrayConstant() {
|
||||
return CACHED(kEmptyLiteralsArrayConstant,
|
||||
HeapConstant(factory()->empty_literals_array()));
|
||||
}
|
||||
|
||||
Node* JSGraph::EmptyStringConstant() {
|
||||
return CACHED(kEmptyStringConstant, HeapConstant(factory()->empty_string()));
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
ArgvMode argv_mode = kArgvOnStack,
|
||||
bool builtin_exit_frame = false);
|
||||
Node* EmptyFixedArrayConstant();
|
||||
Node* EmptyLiteralsArrayConstant();
|
||||
Node* EmptyStringConstant();
|
||||
Node* FixedArrayMapConstant();
|
||||
Node* FixedDoubleArrayMapConstant();
|
||||
@ -166,6 +167,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
kCEntryStub3Constant,
|
||||
kCEntryStub1WithBuiltinExitFrameConstant,
|
||||
kEmptyFixedArrayConstant,
|
||||
kEmptyLiteralsArrayConstant,
|
||||
kEmptyStringConstant,
|
||||
kFixedArrayMapConstant,
|
||||
kFixedDoubleArrayMapConstant,
|
||||
|
@ -1282,13 +1282,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
|
||||
|
||||
DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
|
||||
|
||||
Map* map = nexus.FindFirstMap();
|
||||
if (map == nullptr) {
|
||||
// Maps are weakly held in the type feedback vector, we may not have one.
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Handle<Map> receiver_map(map, isolate());
|
||||
Handle<Map> receiver_map(nexus.FindFirstMap(), isolate());
|
||||
Handle<Name> cached_name =
|
||||
handle(Name::cast(nexus.GetFeedbackExtra()), isolate());
|
||||
|
||||
|
@ -412,8 +412,9 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
|
||||
|
||||
static const int kSharedOffset = 0;
|
||||
static const int kCachedCodeOffset = 1;
|
||||
static const int kOsrAstIdOffset = 2;
|
||||
static const int kEntryLength = 3;
|
||||
static const int kLiteralsOffset = 2;
|
||||
static const int kOsrAstIdOffset = 3;
|
||||
static const int kEntryLength = 4;
|
||||
static const int kInitialLength = kEntryLength;
|
||||
|
||||
int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
|
||||
@ -435,29 +436,38 @@ int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
|
||||
return -1;
|
||||
}
|
||||
|
||||
Code* Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared,
|
||||
BailoutId osr_ast_id) {
|
||||
void Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared,
|
||||
BailoutId osr_ast_id, Code** pcode,
|
||||
LiteralsArray** pliterals) {
|
||||
DCHECK(this->IsNativeContext());
|
||||
int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id);
|
||||
if (entry != -1) {
|
||||
FixedArray* code_map = osr_code_table();
|
||||
DCHECK_LE(entry + kEntryLength, code_map->length());
|
||||
WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
|
||||
WeakCell* literals_cell =
|
||||
WeakCell::cast(code_map->get(entry + kLiteralsOffset));
|
||||
|
||||
return cell->cleared() ? nullptr : Code::cast(cell->value());
|
||||
*pcode = cell->cleared() ? nullptr : Code::cast(cell->value());
|
||||
*pliterals = literals_cell->cleared()
|
||||
? nullptr
|
||||
: LiteralsArray::cast(literals_cell->value());
|
||||
} else {
|
||||
*pcode = nullptr;
|
||||
*pliterals = nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Context::AddToOptimizedCodeMap(Handle<Context> native_context,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
Handle<Code> code,
|
||||
Handle<LiteralsArray> literals,
|
||||
BailoutId osr_ast_id) {
|
||||
DCHECK(native_context->IsNativeContext());
|
||||
Isolate* isolate = native_context->GetIsolate();
|
||||
if (isolate->serializer_enabled()) return;
|
||||
|
||||
STATIC_ASSERT(kEntryLength == 3);
|
||||
STATIC_ASSERT(kEntryLength == 4);
|
||||
Handle<FixedArray> new_code_map;
|
||||
int entry;
|
||||
|
||||
@ -468,9 +478,12 @@ void Context::AddToOptimizedCodeMap(Handle<Context> native_context,
|
||||
Handle<FixedArray> old_code_map(native_context->osr_code_table(), isolate);
|
||||
entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id);
|
||||
if (entry >= 0) {
|
||||
// Just set the code of the entry.
|
||||
// Just set the code and literals of the entry.
|
||||
Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
|
||||
old_code_map->set(entry + kCachedCodeOffset, *code_cell);
|
||||
Handle<WeakCell> literals_cell =
|
||||
isolate->factory()->NewWeakCell(literals);
|
||||
old_code_map->set(entry + kLiteralsOffset, *literals_cell);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -494,10 +507,12 @@ void Context::AddToOptimizedCodeMap(Handle<Context> native_context,
|
||||
}
|
||||
|
||||
Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
|
||||
Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
|
||||
Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared);
|
||||
|
||||
new_code_map->set(entry + kSharedOffset, *shared_cell);
|
||||
new_code_map->set(entry + kCachedCodeOffset, *code_cell);
|
||||
new_code_map->set(entry + kLiteralsOffset, *literals_cell);
|
||||
new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -508,6 +523,8 @@ void Context::AddToOptimizedCodeMap(Handle<Context> native_context,
|
||||
DCHECK(cell->cleared() ||
|
||||
(cell->value()->IsCode() &&
|
||||
Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
|
||||
cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
|
||||
DCHECK(cell->cleared() || cell->value()->IsFixedArray());
|
||||
DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
|
||||
}
|
||||
#endif
|
||||
@ -548,6 +565,8 @@ void Context::EvictFromOptimizedCodeMap(Code* optimized_code,
|
||||
code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset));
|
||||
code_map->set(dst + kCachedCodeOffset,
|
||||
code_map->get(src + kCachedCodeOffset));
|
||||
code_map->set(dst + kLiteralsOffset,
|
||||
code_map->get(src + kLiteralsOffset));
|
||||
code_map->set(dst + kOsrAstIdOffset,
|
||||
code_map->get(src + kOsrAstIdOffset));
|
||||
}
|
||||
|
@ -571,14 +571,15 @@ class Context: public FixedArray {
|
||||
|
||||
// A native context keeps track of all osrd optimized functions.
|
||||
inline bool OptimizedCodeMapIsCleared();
|
||||
Code* SearchOptimizedCodeMap(SharedFunctionInfo* shared,
|
||||
BailoutId osr_ast_id);
|
||||
void SearchOptimizedCodeMap(SharedFunctionInfo* shared, BailoutId osr_ast_id,
|
||||
Code** pcode, LiteralsArray** pliterals);
|
||||
int SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
|
||||
BailoutId osr_ast_id);
|
||||
|
||||
static void AddToOptimizedCodeMap(Handle<Context> native_context,
|
||||
Handle<SharedFunctionInfo> shared,
|
||||
Handle<Code> code,
|
||||
Handle<LiteralsArray> literals,
|
||||
BailoutId osr_ast_id);
|
||||
|
||||
// A native context holds a list of all functions with optimized code.
|
||||
|
@ -823,33 +823,35 @@ class LiteralFixer {
|
||||
public:
|
||||
static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
Isolate* isolate) {
|
||||
bool feedback_metadata_changed, Isolate* isolate) {
|
||||
int new_literal_count = compile_info_wrapper->GetLiteralCount();
|
||||
int old_literal_count = shared_info->num_literals();
|
||||
|
||||
// Recreate the literal array and type feedback vector.
|
||||
// Since the feedback vector roots literal arrays for nested functions,
|
||||
// we can't simply leave it in place because those nested literal
|
||||
// array and feedback vectors may have changed structure.
|
||||
Handle<FixedArray> function_instances =
|
||||
CollectJSFunctions(shared_info, isolate);
|
||||
Handle<TypeFeedbackMetadata> feedback_metadata(
|
||||
shared_info->feedback_metadata());
|
||||
if (old_literal_count == new_literal_count && !feedback_metadata_changed) {
|
||||
// If literal count didn't change, simply go over all functions
|
||||
// and clear literal arrays.
|
||||
ClearValuesVisitor visitor;
|
||||
IterateJSFunctions(shared_info, &visitor);
|
||||
} else {
|
||||
// When literal count changes, we have to create new array instances.
|
||||
// Since we cannot create instances when iterating heap, we should first
|
||||
// collect all functions and fix their literal arrays.
|
||||
Handle<FixedArray> function_instances =
|
||||
CollectJSFunctions(shared_info, isolate);
|
||||
Handle<TypeFeedbackMetadata> feedback_metadata(
|
||||
shared_info->feedback_metadata());
|
||||
|
||||
for (int i = 0; i < function_instances->length(); i++) {
|
||||
Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
|
||||
Handle<TypeFeedbackVector> vector =
|
||||
TypeFeedbackVector::New(isolate, feedback_metadata);
|
||||
Handle<LiteralsArray> new_literals =
|
||||
LiteralsArray::New(isolate, vector, new_literal_count);
|
||||
Handle<LiteralsArray> old_literals(fun->literals(), isolate);
|
||||
fun->set_literals(*new_literals);
|
||||
for (int i = 0; i < function_instances->length(); i++) {
|
||||
Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
|
||||
Handle<TypeFeedbackVector> vector =
|
||||
TypeFeedbackVector::New(isolate, feedback_metadata);
|
||||
Handle<LiteralsArray> new_literals =
|
||||
LiteralsArray::New(isolate, vector, new_literal_count);
|
||||
fun->set_literals(*new_literals);
|
||||
}
|
||||
|
||||
// The literals are rooted in a containing feedback vector.
|
||||
// Replace them there, so new closures have the correct literals.
|
||||
ReplaceRoots(old_literals, new_literals);
|
||||
shared_info->set_num_literals(new_literal_count);
|
||||
}
|
||||
|
||||
shared_info->set_num_literals(new_literal_count);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -870,56 +872,6 @@ class LiteralFixer {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
static void IterateAllJSFunctions(Heap* heap, Visitor* visitor) {
|
||||
HeapIterator iterator(heap);
|
||||
for (HeapObject* obj = iterator.next(); obj != NULL;
|
||||
obj = iterator.next()) {
|
||||
if (obj->IsJSFunction()) {
|
||||
JSFunction* function = JSFunction::cast(obj);
|
||||
visitor->visit(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReplaceRootsVisitor {
|
||||
public:
|
||||
ReplaceRootsVisitor(Handle<LiteralsArray> old_literals,
|
||||
Handle<LiteralsArray> new_literals)
|
||||
: old_literals_(old_literals), new_literals_(new_literals) {}
|
||||
|
||||
void visit(JSFunction* fun) {
|
||||
if (!fun->shared()->is_compiled()) return;
|
||||
|
||||
// Look in the type feedback vector for a copy of literals.
|
||||
TypeFeedbackVector* vector = fun->feedback_vector();
|
||||
// Note: it's important to get the feedback metadata from the
|
||||
// type feedback vector, because there may be a new metadata
|
||||
// object in the SharedFunctionInfo (with a different slot
|
||||
// configuration).
|
||||
TypeFeedbackMetadataIterator iter(vector->metadata());
|
||||
while (iter.HasNext()) {
|
||||
FeedbackVectorSlot slot = iter.Next();
|
||||
FeedbackVectorSlotKind kind = iter.kind();
|
||||
if (kind == FeedbackVectorSlotKind::CREATE_CLOSURE) {
|
||||
Object* obj = vector->Get(slot);
|
||||
if (obj == *old_literals_) {
|
||||
vector->Set(slot, *new_literals_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Handle<LiteralsArray> old_literals_;
|
||||
Handle<LiteralsArray> new_literals_;
|
||||
};
|
||||
|
||||
static void ReplaceRoots(Handle<LiteralsArray> old_literals,
|
||||
Handle<LiteralsArray> new_literals) {
|
||||
ReplaceRootsVisitor replace_visitor(old_literals, new_literals);
|
||||
IterateAllJSFunctions(old_literals->GetHeap(), &replace_visitor);
|
||||
}
|
||||
|
||||
// Finds all instances of JSFunction that refers to the provided shared_info
|
||||
// and returns array with them.
|
||||
static Handle<FixedArray> CollectJSFunctions(
|
||||
@ -1020,6 +972,7 @@ void LiveEdit::ReplaceFunctionCode(
|
||||
Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
|
||||
Handle<SharedFunctionInfo> new_shared_info =
|
||||
compile_info_wrapper.GetSharedFunctionInfo();
|
||||
bool feedback_metadata_changed = false;
|
||||
|
||||
if (shared_info->is_compiled()) {
|
||||
// Take whatever code we can get from the new shared function info. We
|
||||
@ -1066,6 +1019,8 @@ void LiveEdit::ReplaceFunctionCode(
|
||||
// Update the type feedback vector, if needed.
|
||||
Handle<TypeFeedbackMetadata> new_feedback_metadata(
|
||||
new_shared_info->feedback_metadata());
|
||||
feedback_metadata_changed =
|
||||
new_feedback_metadata->DiffersFrom(shared_info->feedback_metadata());
|
||||
shared_info->set_feedback_metadata(*new_feedback_metadata);
|
||||
}
|
||||
|
||||
@ -1074,7 +1029,8 @@ void LiveEdit::ReplaceFunctionCode(
|
||||
shared_info->set_start_position(start_position);
|
||||
shared_info->set_end_position(end_position);
|
||||
|
||||
LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
|
||||
LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info,
|
||||
feedback_metadata_changed, isolate);
|
||||
|
||||
DeoptimizeDependentFunctions(*shared_info);
|
||||
isolate->compilation_cache()->Remove(shared_info);
|
||||
|
@ -551,6 +551,26 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails(
|
||||
RecordFixedArrayHelper(sfi, optimized_code_map, OPTIMIZED_CODE_MAP_SUB_TYPE,
|
||||
0);
|
||||
// Optimized code map should be small, so skip accounting.
|
||||
int len = optimized_code_map->length();
|
||||
for (int i = SharedFunctionInfo::kEntriesStart; i < len;
|
||||
i += SharedFunctionInfo::kEntryLength) {
|
||||
Object* slot =
|
||||
optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset);
|
||||
LiteralsArray* literals = nullptr;
|
||||
if (slot->IsWeakCell()) {
|
||||
WeakCell* cell = WeakCell::cast(slot);
|
||||
if (!cell->cleared()) {
|
||||
literals = LiteralsArray::cast(cell->value());
|
||||
}
|
||||
} else {
|
||||
literals = LiteralsArray::cast(slot);
|
||||
}
|
||||
if (literals != nullptr) {
|
||||
RecordFixedArrayHelper(sfi, literals, LITERALS_ARRAY_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(sfi, literals->feedback_vector(),
|
||||
TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3463,16 +3463,12 @@ LiteralsArray* LiteralsArray::cast(Object* object) {
|
||||
return reinterpret_cast<LiteralsArray*>(object);
|
||||
}
|
||||
|
||||
bool LiteralsArray::has_feedback_vector() const {
|
||||
return !get(kVectorIndex)->IsUndefined(this->GetIsolate());
|
||||
}
|
||||
|
||||
TypeFeedbackVector* LiteralsArray::feedback_vector() const {
|
||||
if (length() == 0 || !has_feedback_vector()) {
|
||||
if (length() == 0) {
|
||||
return TypeFeedbackVector::cast(
|
||||
this->GetIsolate()->heap()->empty_type_feedback_vector());
|
||||
const_cast<FixedArray*>(FixedArray::cast(this)));
|
||||
}
|
||||
|
||||
return TypeFeedbackVector::cast(get(kVectorIndex));
|
||||
}
|
||||
|
||||
@ -6627,13 +6623,6 @@ void JSFunction::ReplaceCode(Code* code) {
|
||||
}
|
||||
}
|
||||
|
||||
bool JSFunction::has_literals_array() const {
|
||||
SharedFunctionInfo* shared = this->shared();
|
||||
|
||||
return (literals() != shared->GetIsolate()->heap()->empty_literals_array() ||
|
||||
(shared->feedback_metadata()->slot_count() == 0 &&
|
||||
shared->num_literals() == 0));
|
||||
}
|
||||
|
||||
Context* JSFunction::context() {
|
||||
return Context::cast(READ_FIELD(this, kContextOffset));
|
||||
|
119
src/objects.cc
119
src/objects.cc
@ -12007,20 +12007,48 @@ void JSFunction::AttemptConcurrentOptimization() {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals(
|
||||
Handle<SharedFunctionInfo> shared, Handle<Context> native_context) {
|
||||
Isolate* isolate = shared->GetIsolate();
|
||||
CodeAndLiterals result =
|
||||
shared->SearchOptimizedCodeMap(*native_context, BailoutId::None());
|
||||
if (result.literals != nullptr) {
|
||||
DCHECK(shared->feedback_metadata()->is_empty() ||
|
||||
!result.literals->feedback_vector()->is_empty());
|
||||
return handle(result.literals, isolate);
|
||||
}
|
||||
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
|
||||
Handle<LiteralsArray> literals =
|
||||
LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
|
||||
Handle<Code> code;
|
||||
if (result.code != nullptr) {
|
||||
code = Handle<Code>(result.code, isolate);
|
||||
}
|
||||
AddToOptimizedCodeMap(shared, native_context, code, literals,
|
||||
BailoutId::None());
|
||||
return literals;
|
||||
}
|
||||
|
||||
// static
|
||||
void SharedFunctionInfo::AddToOptimizedCodeMap(
|
||||
Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
|
||||
Handle<Code> code, BailoutId osr_ast_id) {
|
||||
MaybeHandle<Code> code, Handle<LiteralsArray> literals,
|
||||
BailoutId osr_ast_id) {
|
||||
Isolate* isolate = shared->GetIsolate();
|
||||
if (isolate->serializer_enabled()) return;
|
||||
DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
|
||||
DCHECK(code.is_null() ||
|
||||
code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION);
|
||||
DCHECK(native_context->IsNativeContext());
|
||||
STATIC_ASSERT(kEntryLength == 2);
|
||||
STATIC_ASSERT(kEntryLength == 3);
|
||||
Handle<FixedArray> new_code_map;
|
||||
int entry;
|
||||
|
||||
if (!osr_ast_id.IsNone()) {
|
||||
Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
|
||||
Context::AddToOptimizedCodeMap(
|
||||
native_context, shared, code.ToHandleChecked(), literals, osr_ast_id);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -12032,9 +12060,15 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
|
||||
Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
|
||||
entry = shared->SearchOptimizedCodeMapEntry(*native_context);
|
||||
if (entry >= kEntriesStart) {
|
||||
// Just set the code of the entry.
|
||||
Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
|
||||
old_code_map->set(entry + kCachedCodeOffset, *code_cell);
|
||||
// Just set the code and literals of the entry.
|
||||
if (!code.is_null()) {
|
||||
Handle<WeakCell> code_cell =
|
||||
isolate->factory()->NewWeakCell(code.ToHandleChecked());
|
||||
old_code_map->set(entry + kCachedCodeOffset, *code_cell);
|
||||
}
|
||||
Handle<WeakCell> literals_cell =
|
||||
isolate->factory()->NewWeakCell(literals);
|
||||
old_code_map->set(entry + kLiteralsOffset, *literals_cell);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -12062,11 +12096,15 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
|
||||
}
|
||||
}
|
||||
|
||||
Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
|
||||
Handle<WeakCell> code_cell =
|
||||
code.is_null() ? isolate->factory()->empty_weak_cell()
|
||||
: isolate->factory()->NewWeakCell(code.ToHandleChecked());
|
||||
Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
|
||||
WeakCell* context_cell = native_context->self_weak_cell();
|
||||
|
||||
new_code_map->set(entry + kContextOffset, context_cell);
|
||||
new_code_map->set(entry + kCachedCodeOffset, *code_cell);
|
||||
new_code_map->set(entry + kLiteralsOffset, *literals_cell);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
|
||||
@ -12076,6 +12114,8 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
|
||||
DCHECK(cell->cleared() ||
|
||||
(cell->value()->IsCode() &&
|
||||
Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
|
||||
cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
|
||||
DCHECK(cell->cleared() || cell->value()->IsFixedArray());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -12113,7 +12153,7 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
|
||||
ShortPrint();
|
||||
PrintF("]\n");
|
||||
}
|
||||
// Just clear the code.
|
||||
// Just clear the code in order to continue sharing literals.
|
||||
code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
|
||||
SKIP_WRITE_BARRIER);
|
||||
}
|
||||
@ -12130,45 +12170,12 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
|
||||
void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
Handle<Context> native_context(function->context()->native_context());
|
||||
Isolate* isolate = shared->GetIsolate();
|
||||
|
||||
if (!function->has_literals_array()) {
|
||||
if (FLAG_trace_strong_rooted_literals) {
|
||||
PrintF("EnsureLiterals: Installing literals array in %s %p\n",
|
||||
shared->DebugName()->ToCString().get(),
|
||||
reinterpret_cast<void*>(*function));
|
||||
}
|
||||
// Top level code didn't get it's literals installed.
|
||||
Handle<TypeFeedbackVector> feedback_vector =
|
||||
TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
|
||||
Handle<LiteralsArray> new_literals =
|
||||
LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
|
||||
function->set_literals(*new_literals);
|
||||
} else if (!function->literals()->has_feedback_vector()) {
|
||||
if (FLAG_trace_strong_rooted_literals) {
|
||||
PrintF("EnsureLiterals: Installing feedback vector in %s %p\n",
|
||||
shared->DebugName()->ToCString().get(),
|
||||
reinterpret_cast<void*>(*function));
|
||||
}
|
||||
// If the feedback vector hasn't been installed, do that.
|
||||
Handle<TypeFeedbackVector> feedback_vector = TypeFeedbackVector::New(
|
||||
shared->GetIsolate(), handle(shared->feedback_metadata()));
|
||||
function->literals()->set_feedback_vector(*feedback_vector);
|
||||
} else {
|
||||
if (FLAG_trace_strong_rooted_literals) {
|
||||
PrintF("EnsureLiterals: did nothing for %s %p\n",
|
||||
shared->DebugName()->ToCString().get(),
|
||||
reinterpret_cast<void*>(*function));
|
||||
}
|
||||
if (function->literals() ==
|
||||
function->GetIsolate()->heap()->empty_literals_array()) {
|
||||
Handle<LiteralsArray> literals =
|
||||
SharedFunctionInfo::FindOrCreateLiterals(shared, native_context);
|
||||
function->set_literals(*literals);
|
||||
}
|
||||
|
||||
// No matter what, ensure some post-conditions.
|
||||
DCHECK(shared->feedback_metadata()->slot_count() != 0 ||
|
||||
function->feedback_vector() ==
|
||||
shared->GetIsolate()->heap()->empty_type_feedback_vector());
|
||||
DCHECK(shared->num_literals() == 0 ||
|
||||
function->literals() !=
|
||||
shared->GetIsolate()->heap()->empty_literals_array());
|
||||
}
|
||||
|
||||
static void GetMinInobjectSlack(Map* map, void* data) {
|
||||
@ -13747,11 +13754,15 @@ void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
|
||||
}
|
||||
}
|
||||
|
||||
Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
|
||||
BailoutId osr_ast_id) {
|
||||
Code* result = nullptr;
|
||||
CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
|
||||
Context* native_context, BailoutId osr_ast_id) {
|
||||
CodeAndLiterals result = {nullptr, nullptr};
|
||||
if (!osr_ast_id.IsNone()) {
|
||||
return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
|
||||
Code* code;
|
||||
LiteralsArray* literals;
|
||||
native_context->SearchOptimizedCodeMap(this, osr_ast_id, &code, &literals);
|
||||
result = {code, literals};
|
||||
return result;
|
||||
}
|
||||
|
||||
DCHECK(osr_ast_id.IsNone());
|
||||
@ -13760,8 +13771,12 @@ Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
|
||||
FixedArray* code_map = optimized_code_map();
|
||||
DCHECK_LE(entry + kEntryLength, code_map->length());
|
||||
WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
|
||||
WeakCell* literals_cell =
|
||||
WeakCell::cast(code_map->get(entry + kLiteralsOffset));
|
||||
|
||||
result = cell->cleared() ? nullptr : Code::cast(cell->value());
|
||||
result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
|
||||
literals_cell->cleared() ? nullptr : LiteralsArray::cast(
|
||||
literals_cell->value())};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -4997,10 +4997,8 @@ class LiteralsArray : public FixedArray {
|
||||
return OffsetOfElementAt(index + kFirstLiteralIndex);
|
||||
}
|
||||
|
||||
inline bool has_feedback_vector() const;
|
||||
inline TypeFeedbackVector* feedback_vector() const;
|
||||
inline void set_feedback_vector(TypeFeedbackVector* vector);
|
||||
|
||||
inline Object* literal(int literal_index) const;
|
||||
inline void set_literal(int literal_index, Object* literal);
|
||||
inline void set_literal_undefined(int literal_index);
|
||||
@ -7137,6 +7135,12 @@ enum BuiltinFunctionId {
|
||||
kStringIteratorNext,
|
||||
};
|
||||
|
||||
// Result of searching in an optimized code map of a SharedFunctionInfo. Note
|
||||
// that both {code} and {literals} can be NULL to pass search result status.
|
||||
struct CodeAndLiterals {
|
||||
Code* code; // Cached optimized code.
|
||||
LiteralsArray* literals; // Cached literals array.
|
||||
};
|
||||
|
||||
// SharedFunctionInfo describes the JSFunction information that can be
|
||||
// shared by multiple instances of the function.
|
||||
@ -7168,7 +7172,11 @@ class SharedFunctionInfo: public HeapObject {
|
||||
DECL_ACCESSORS(optimized_code_map, FixedArray)
|
||||
|
||||
// Returns entry from optimized code map for specified context and OSR entry.
|
||||
Code* SearchOptimizedCodeMap(Context* native_context, BailoutId osr_ast_id);
|
||||
// Note that {code == nullptr, literals == nullptr} indicates no matching
|
||||
// entry has been found, whereas {code, literals == nullptr} indicates that
|
||||
// code is context-independent.
|
||||
CodeAndLiterals SearchOptimizedCodeMap(Context* native_context,
|
||||
BailoutId osr_ast_id);
|
||||
|
||||
// Clear optimized code map.
|
||||
void ClearOptimizedCodeMap();
|
||||
@ -7190,9 +7198,12 @@ class SharedFunctionInfo: public HeapObject {
|
||||
Handle<SharedFunctionInfo> shared, Handle<Context> native_context);
|
||||
|
||||
// Add or update entry in the optimized code map for context-dependent code.
|
||||
// If {code} is not given, then an existing entry's code won't be overwritten.
|
||||
static void AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,
|
||||
Handle<Context> native_context,
|
||||
Handle<Code> code, BailoutId osr_ast_id);
|
||||
MaybeHandle<Code> code,
|
||||
Handle<LiteralsArray> literals,
|
||||
BailoutId osr_ast_id);
|
||||
|
||||
// Set up the link between shared function info and the script. The shared
|
||||
// function info is added to the list on the script.
|
||||
@ -7203,7 +7214,8 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kEntriesStart = 0;
|
||||
static const int kContextOffset = 0;
|
||||
static const int kCachedCodeOffset = 1;
|
||||
static const int kEntryLength = 2;
|
||||
static const int kLiteralsOffset = 2;
|
||||
static const int kEntryLength = 3;
|
||||
static const int kInitialLength = kEntriesStart + kEntryLength;
|
||||
|
||||
static const int kNotFound = -1;
|
||||
@ -7215,6 +7227,8 @@ class SharedFunctionInfo: public HeapObject {
|
||||
static const int kOffsetToPreviousCachedCode =
|
||||
FixedArray::kHeaderSize +
|
||||
kPointerSize * (kCachedCodeOffset - kEntryLength);
|
||||
static const int kOffsetToPreviousLiterals =
|
||||
FixedArray::kHeaderSize + kPointerSize * (kLiteralsOffset - kEntryLength);
|
||||
|
||||
// [scope_info]: Scope info.
|
||||
DECL_ACCESSORS(scope_info, ScopeInfo)
|
||||
@ -8164,7 +8178,6 @@ class JSFunction: public JSObject {
|
||||
// access to. For API objects we store the boilerplate in the literal array.
|
||||
DECL_ACCESSORS(literals, LiteralsArray)
|
||||
|
||||
inline bool has_literals_array() const;
|
||||
static void EnsureLiterals(Handle<JSFunction> function);
|
||||
inline TypeFeedbackVector* feedback_vector();
|
||||
|
||||
|
@ -23,15 +23,10 @@ RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(4, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(index, 2);
|
||||
CONVERT_SMI_ARG_CHECKED(pretenured_flag, 3);
|
||||
Handle<Context> context(isolate->context(), isolate);
|
||||
FeedbackVectorSlot slot = TypeFeedbackVector::ToSlot(index);
|
||||
Handle<LiteralsArray> literals(LiteralsArray::cast(vector->Get(slot)),
|
||||
isolate);
|
||||
return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared, context, literals, static_cast<PretenureFlag>(pretenured_flag));
|
||||
shared, context, static_cast<PretenureFlag>(pretenured_flag));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -613,15 +613,10 @@ RUNTIME_FUNCTION(Runtime_NewClosure) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(index, 2);
|
||||
Handle<Context> context(isolate->context(), isolate);
|
||||
FeedbackVectorSlot slot = TypeFeedbackVector::ToSlot(index);
|
||||
Handle<LiteralsArray> literals(LiteralsArray::cast(vector->Get(slot)),
|
||||
isolate);
|
||||
Handle<JSFunction> function =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared, context, literals, NOT_TENURED);
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
||||
NOT_TENURED);
|
||||
return *function;
|
||||
}
|
||||
|
||||
@ -630,17 +625,12 @@ RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(index, 2);
|
||||
Handle<Context> context(isolate->context(), isolate);
|
||||
FeedbackVectorSlot slot = TypeFeedbackVector::ToSlot(index);
|
||||
Handle<LiteralsArray> literals(LiteralsArray::cast(vector->Get(slot)),
|
||||
isolate);
|
||||
// The caller ensures that we pretenure closures that are assigned
|
||||
// directly to properties.
|
||||
Handle<JSFunction> function =
|
||||
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
||||
literals, TENURED);
|
||||
TENURED);
|
||||
return *function;
|
||||
}
|
||||
|
||||
|
@ -251,8 +251,10 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::New(
|
||||
// the empty literals array here.
|
||||
array->set(index, *factory->empty_literals_array(), SKIP_WRITE_BARRIER);
|
||||
} else {
|
||||
Handle<FixedArray> value = factory->NewFixedArray(length);
|
||||
array->set(index, *value);
|
||||
// TODO(mvstanton): Create the array.
|
||||
// Handle<FixedArray> value = factory->NewFixedArray(length);
|
||||
// array->set(index, *value);
|
||||
array->set(index, *factory->empty_literals_array(), SKIP_WRITE_BARRIER);
|
||||
}
|
||||
}
|
||||
i += entry_size;
|
||||
@ -373,10 +375,10 @@ void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
|
||||
break;
|
||||
}
|
||||
case FeedbackVectorSlotKind::CREATE_CLOSURE: {
|
||||
// Clear the literals in the embedded LiteralsArray.
|
||||
LiteralsArray* literals = LiteralsArray::cast(Get(slot));
|
||||
for (int i = 0; i < literals->literals_count(); i++) {
|
||||
literals->set_literal_undefined(i);
|
||||
// Fill the array with undefined.
|
||||
FixedArray* array = FixedArray::cast(Get(slot));
|
||||
for (int i = 1; i < array->length(); i++) {
|
||||
array->set_undefined(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4297,6 +4297,10 @@ TEST(Regress513507) {
|
||||
if (!code->is_optimized_code()) return;
|
||||
}
|
||||
|
||||
Handle<TypeFeedbackVector> vector =
|
||||
TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
|
||||
Handle<LiteralsArray> lit =
|
||||
LiteralsArray::New(isolate, vector, shared->num_literals());
|
||||
Handle<Context> context(isolate->context());
|
||||
|
||||
// Add the new code several times to the optimized code map and also set an
|
||||
@ -4305,11 +4309,211 @@ TEST(Regress513507) {
|
||||
FLAG_gc_interval = 1000;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
BailoutId id = BailoutId(i);
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, id);
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
TEST(Regress514122) {
|
||||
if (!i::FLAG_incremental_marking) return;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
LocalContext env;
|
||||
Heap* heap = isolate->heap();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Perfrom one initial GC to enable code flushing.
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// Prepare function whose optimized code map we can use.
|
||||
Handle<SharedFunctionInfo> shared;
|
||||
{
|
||||
HandleScope inner_scope(isolate);
|
||||
CompileRun(
|
||||
"function f() { return 1 }"
|
||||
"f(); %OptimizeFunctionOnNextCall(f); f();");
|
||||
|
||||
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
||||
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
|
||||
CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
|
||||
shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
|
||||
CompileRun("f = null");
|
||||
}
|
||||
|
||||
// Prepare optimized code that we can use.
|
||||
Handle<Code> code;
|
||||
{
|
||||
HandleScope inner_scope(isolate);
|
||||
CompileRun(
|
||||
"function g() { return 2 }"
|
||||
"g(); %OptimizeFunctionOnNextCall(g); g();");
|
||||
|
||||
Handle<JSFunction> g = Handle<JSFunction>::cast(
|
||||
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
|
||||
CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
|
||||
code = inner_scope.CloseAndEscape(handle(g->code(), isolate));
|
||||
if (!code->is_optimized_code()) return;
|
||||
}
|
||||
|
||||
Handle<TypeFeedbackVector> vector =
|
||||
TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
|
||||
Handle<LiteralsArray> lit =
|
||||
LiteralsArray::New(isolate, vector, shared->num_literals(), TENURED);
|
||||
Handle<Context> context(isolate->context());
|
||||
|
||||
// Add the code several times to the optimized code map.
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
HandleScope inner_scope(isolate);
|
||||
BailoutId id = BailoutId(i);
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
|
||||
}
|
||||
shared->optimized_code_map()->Print();
|
||||
|
||||
// Add the code with a literals array to be evacuated.
|
||||
Page* evac_page;
|
||||
{
|
||||
HandleScope inner_scope(isolate);
|
||||
AlwaysAllocateScope always_allocate(isolate);
|
||||
// Make sure literal is placed on an old-space evacuation candidate.
|
||||
heap::SimulateFullSpace(heap->old_space());
|
||||
|
||||
// Make sure there the number of literals is > 0.
|
||||
Handle<LiteralsArray> lit = LiteralsArray::New(isolate, vector, 23);
|
||||
|
||||
evac_page = Page::FromAddress(lit->address());
|
||||
BailoutId id = BailoutId(100);
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
|
||||
}
|
||||
|
||||
// Heap is ready, force {lit_page} to become an evacuation candidate and
|
||||
// simulate incremental marking to enqueue optimized code map.
|
||||
FLAG_manual_evacuation_candidates_selection = true;
|
||||
heap::ForceEvacuationCandidate(evac_page);
|
||||
heap::SimulateIncrementalMarking(heap);
|
||||
|
||||
// No matter whether reachable or not, {boomer} is doomed.
|
||||
Handle<Object> boomer(shared->optimized_code_map(), isolate);
|
||||
|
||||
// Add the code several times to the optimized code map. This will leave old
|
||||
// copies of the optimized code map unreachable but still marked.
|
||||
for (int i = 3; i < 6; ++i) {
|
||||
HandleScope inner_scope(isolate);
|
||||
BailoutId id = BailoutId(i);
|
||||
SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id);
|
||||
}
|
||||
|
||||
// Trigger a GC to flush out the bug.
|
||||
CcTest::CollectGarbage(i::OLD_SPACE);
|
||||
boomer->Print();
|
||||
}
|
||||
|
||||
TEST(OptimizedCodeMapReuseEntries) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
// BUG(v8:4598): Since TurboFan doesn't treat maps in code weakly, we can't
|
||||
// run this test.
|
||||
if (i::FLAG_turbo) return;
|
||||
CcTest::InitializeVM();
|
||||
v8::Isolate* v8_isolate = CcTest::isolate();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Create 3 contexts, allow the 2nd one to be disposed, and verify that
|
||||
// a 4th context will re-use the weak slots in the optimized code map
|
||||
// to hold data, rather than expanding the map.
|
||||
v8::Local<v8::Context> c1 = v8::Context::New(v8_isolate);
|
||||
const char* source = "function foo(x) { var l = [1]; return x+l[0]; }";
|
||||
v8::ScriptCompiler::Source script_source(
|
||||
v8::String::NewFromUtf8(v8_isolate, source, v8::NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
v8::Local<v8::UnboundScript> indep =
|
||||
v8::ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source)
|
||||
.ToLocalChecked();
|
||||
const char* toplevel = "foo(3); %OptimizeFunctionOnNextCall(foo); foo(3);";
|
||||
// Perfrom one initial GC to enable code flushing.
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
c1->Enter();
|
||||
indep->BindToCurrentContext()->Run(c1).ToLocalChecked();
|
||||
CompileRun(toplevel);
|
||||
|
||||
Handle<SharedFunctionInfo> shared;
|
||||
Handle<JSFunction> foo = Handle<JSFunction>::cast(
|
||||
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
|
||||
CcTest::global()->Get(c1, v8_str("foo")).ToLocalChecked())));
|
||||
CHECK(foo->shared()->is_compiled());
|
||||
shared = handle(foo->shared());
|
||||
c1->Exit();
|
||||
|
||||
{
|
||||
HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> c2 = v8::Context::New(v8_isolate);
|
||||
c2->Enter();
|
||||
indep->BindToCurrentContext()->Run(c2).ToLocalChecked();
|
||||
CompileRun(toplevel);
|
||||
c2->Exit();
|
||||
}
|
||||
|
||||
{
|
||||
HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> c3 = v8::Context::New(v8_isolate);
|
||||
c3->Enter();
|
||||
indep->BindToCurrentContext()->Run(c3).ToLocalChecked();
|
||||
CompileRun(toplevel);
|
||||
c3->Exit();
|
||||
|
||||
// Now, collect garbage. Context c2 should have no roots to it, and it's
|
||||
// entry in the optimized code map should be free for a new context.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
}
|
||||
|
||||
Handle<FixedArray> optimized_code_map =
|
||||
handle(shared->optimized_code_map());
|
||||
// There should be 3 entries in the map.
|
||||
CHECK_EQ(
|
||||
3, ((optimized_code_map->length() - SharedFunctionInfo::kEntriesStart) /
|
||||
SharedFunctionInfo::kEntryLength));
|
||||
// But one of them (formerly for c2) should be cleared.
|
||||
int cleared_count = 0;
|
||||
for (int i = SharedFunctionInfo::kEntriesStart;
|
||||
i < optimized_code_map->length();
|
||||
i += SharedFunctionInfo::kEntryLength) {
|
||||
cleared_count +=
|
||||
WeakCell::cast(
|
||||
optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
|
||||
->cleared()
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
CHECK_EQ(1, cleared_count);
|
||||
|
||||
// Verify that a new context uses the cleared entry rather than creating a
|
||||
// new
|
||||
// optimized code map array.
|
||||
v8::Local<v8::Context> c4 = v8::Context::New(v8_isolate);
|
||||
c4->Enter();
|
||||
indep->BindToCurrentContext()->Run(c4).ToLocalChecked();
|
||||
CompileRun(toplevel);
|
||||
c4->Exit();
|
||||
CHECK_EQ(*optimized_code_map, shared->optimized_code_map());
|
||||
|
||||
// Now each entry is in use.
|
||||
cleared_count = 0;
|
||||
for (int i = SharedFunctionInfo::kEntriesStart;
|
||||
i < optimized_code_map->length();
|
||||
i += SharedFunctionInfo::kEntryLength) {
|
||||
cleared_count +=
|
||||
WeakCell::cast(
|
||||
optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
|
||||
->cleared()
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
CHECK_EQ(0, cleared_count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Regress513496) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
CcTest::InitializeVM();
|
||||
@ -4355,9 +4559,9 @@ TEST(Regress513496) {
|
||||
}
|
||||
|
||||
// Lookup the optimized code and keep it alive.
|
||||
Code* result = shared->SearchOptimizedCodeMap(
|
||||
CodeAndLiterals result = shared->SearchOptimizedCodeMap(
|
||||
isolate->context()->native_context(), BailoutId::None());
|
||||
Handle<Code> optimized_code(result, isolate);
|
||||
Handle<Code> optimized_code(result.code, isolate);
|
||||
|
||||
// Finish a full GC cycle so that the unoptimized code of 'g' is flushed even
|
||||
// though the optimized code for 'f' is reachable via the optimized code map.
|
||||
|
@ -7500,7 +7500,8 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) {
|
||||
}
|
||||
// A single GC should be enough to reclaim the memory, since we are using
|
||||
// phantom handles.
|
||||
CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 20000);
|
||||
// BUG(5865): --expose-wasm with no snapshot builds requires a limit change.
|
||||
CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 19000);
|
||||
CHECK(object_a.flag);
|
||||
CHECK(object_b.flag);
|
||||
}
|
||||
|
@ -107,9 +107,7 @@ TEST(VectorStructure) {
|
||||
FeedbackVectorSlotKind::CREATE_CLOSURE));
|
||||
FeedbackVectorSlot slot = helper.slot(1);
|
||||
FixedArray* array = FixedArray::cast(vector->Get(slot));
|
||||
CHECK_EQ(5, array->length());
|
||||
CHECK_EQ(5, vector->GetParameter(slot));
|
||||
CHECK_EQ(array->get(0), *factory->undefined_value());
|
||||
CHECK_EQ(array, *factory->empty_literals_array());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,56 +0,0 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --expose-gc
|
||||
|
||||
// Make sure literals are strongly rooted and safe from weak-code deopts.
|
||||
|
||||
(function() {
|
||||
function foo() {
|
||||
var a = { y: 0 };
|
||||
a.y = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
foo();
|
||||
foo();
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo();
|
||||
gc();
|
||||
assertOptimized(foo);
|
||||
})();
|
||||
|
||||
|
||||
(function() {
|
||||
function hot(o) {
|
||||
return o.x + o.y;
|
||||
}
|
||||
function mapPlus(a, y) {
|
||||
return a.map(x => hot({x, y}));
|
||||
}
|
||||
|
||||
var a = [1, 2, 3];
|
||||
print(mapPlus(a, 1));
|
||||
print(mapPlus(a, 2));
|
||||
%OptimizeFunctionOnNextCall(hot);
|
||||
print(mapPlus(a, 3));
|
||||
gc(); // BOOOM!
|
||||
assertOptimized(hot);
|
||||
print(mapPlus(a, 4));
|
||||
})();
|
||||
|
||||
// Verify that we can handle the creation of a new script, where the
|
||||
// code is cached and the feedback vector has to be re-created.
|
||||
(function() {
|
||||
var sopen = "function wrapper() { ";
|
||||
var s1 = "function foo() { return bar(5); } ";
|
||||
var s2 = "foo(); foo(); %OptimizeFunctionOnNextCall(foo); foo(); ";
|
||||
var sclose = "} wrapper(); ";
|
||||
var s = sopen + s1 + s2 + sclose;
|
||||
function bar(i) { return i + 3 };
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
eval(s);
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user