Index: src/builtins/ppc/builtins-ppc.cc |
diff --git a/src/builtins/ppc/builtins-ppc.cc b/src/builtins/ppc/builtins-ppc.cc |
index f84b6a0c03180811f6dcaad77464972f2622252e..fa97eb56b931cc91d08095b53e2011df9b591f21 100644 |
--- a/src/builtins/ppc/builtins-ppc.cc |
+++ b/src/builtins/ppc/builtins-ppc.cc |
@@ -994,6 +994,41 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
Generate_JSEntryTrampolineHelper(masm, true); |
} |
+static void ReplaceClosureEntryWithOptimizedCode( |
+ MacroAssembler* masm, Register optimized_code_entry, Register closure, |
+ Register scratch1, Register scratch2, Register scratch3) { |
+ Register native_context = scratch1; |
+ // Store code entry in the closure. |
+ __ addi(optimized_code_entry, optimized_code_entry, |
+ Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ __ StoreP(optimized_code_entry, |
+ FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0); |
+ __ RecordWriteCodeEntryField(closure, optimized_code_entry, scratch2); |
+ |
+ // Link the closure into the optimized function list. |
+ // r7 : code entry |
+ // r10: native context |
+ // r4 : closure |
+ __ LoadP(native_context, NativeContextMemOperand()); |
+ __ LoadP(scratch2, ContextMemOperand(native_context, |
+ Context::OPTIMIZED_FUNCTIONS_LIST)); |
+ __ StoreP(scratch2, |
+ FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset), r0); |
+ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, scratch2, |
+ scratch3, kLRHasNotBeenSaved, kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
+ const int function_list_offset = |
+ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST); |
+ __ StoreP( |
+ closure, |
+ ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST), r0); |
+ // Save closure before the write barrier. |
+ __ mr(scratch2, closure); |
+ __ RecordWriteContextSlot(native_context, function_list_offset, closure, |
+ scratch3, kLRHasNotBeenSaved, kDontSaveFPRegs); |
+ __ mr(closure, scratch2); |
+} |
+ |
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) { |
Register args_count = scratch; |
@@ -1034,6 +1069,21 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
FrameScope frame_scope(masm, StackFrame::MANUAL); |
__ PushStandardFrame(r4); |
+ // First check if there is optimized code in the feedback vector which we |
+ // could call instead. |
+ Label switch_to_optimized_code; |
+ |
+ Register optimized_code_entry = r7; |
+ __ LoadP(r3, FieldMemOperand(r4, JSFunction::kFeedbackVectorOffset)); |
+ __ LoadP(r3, FieldMemOperand(r3, Cell::kValueOffset)); |
+ __ LoadP( |
+ optimized_code_entry, |
+ FieldMemOperand(r3, FeedbackVector::kOptimizedCodeIndex * kPointerSize + |
+ FeedbackVector::kHeaderSize)); |
+ __ LoadP(optimized_code_entry, |
+ FieldMemOperand(optimized_code_entry, WeakCell::kValueOffset)); |
+ __ JumpIfNotSmi(optimized_code_entry, &switch_to_optimized_code); |
+ |
// Get the bytecode array from the function object (or from the DebugInfo if |
// it is present) and load it into kInterpreterBytecodeArrayRegister. |
__ LoadP(r3, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); |
@@ -1154,6 +1204,29 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
__ StoreP(r7, FieldMemOperand(r4, JSFunction::kCodeEntryOffset), r0); |
__ RecordWriteCodeEntryField(r4, r7, r8); |
__ JumpToJSEntry(r7); |
+ |
+ // If there is optimized code on the type feedback vector, check if it is good |
+ // to run, and if so, self heal the closure and call the optimized code. |
+ __ bind(&switch_to_optimized_code); |
+ __ LeaveFrame(StackFrame::JAVA_SCRIPT); |
+ Label gotta_call_runtime; |
+ |
+ // Check if the optimized code is marked for deopt. |
+ __ lbz(r8, FieldMemOperand(optimized_code_entry, |
+ Code::kKindSpecificFlags1Offset)); |
+ __ TestBit(r8, Code::kMarkedForDeoptimizationBit, r0); |
+ __ bne(&gotta_call_runtime, cr0); |
+ |
+ // Optimized code is good, get it into the closure and link the closure into |
+ // the optimized functions list, then tail call the optimized code. |
+ ReplaceClosureEntryWithOptimizedCode(masm, optimized_code_entry, r4, r9, r8, |
+ r5); |
+ __ JumpToJSEntry(optimized_code_entry); |
+ |
+ // Optimized code is marked for deopt, bailout to the CompileLazy runtime |
+ // function which will clear the feedback vector's optimized code slot. |
+ __ bind(&gotta_call_runtime); |
+ GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); |
} |
static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, |
@@ -1421,31 +1494,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) { |
__ bne(&gotta_call_runtime, cr0); |
// Code is good, get it into the closure and tail call. |
- __ addi(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag)); |
- __ StoreP(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0); |
- __ RecordWriteCodeEntryField(closure, entry, r8); |
- |
- // Load native context into r9. |
- Register native_context = r9; |
- __ LoadP(native_context, NativeContextMemOperand()); |
- |
- // Link the closure into the optimized function list. |
- __ LoadP( |
- r8, ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST)); |
- __ StoreP(r8, FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset), |
- r0); |
- __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, r8, r5, |
- kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, |
- OMIT_SMI_CHECK); |
- const int function_list_offset = |
- Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST); |
- __ StoreP( |
- closure, |
- ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST), r0); |
- // Save closure before the write barrier. |
- __ mr(r8, closure); |
- __ RecordWriteContextSlot(native_context, function_list_offset, r8, r5, |
- kLRHasNotBeenSaved, kDontSaveFPRegs); |
+ ReplaceClosureEntryWithOptimizedCode(masm, entry, closure, r9, r8, r5); |
__ JumpToJSEntry(entry); |
// We found no optimized code. |