Index: src/builtins/s390/builtins-s390.cc |
diff --git a/src/builtins/s390/builtins-s390.cc b/src/builtins/s390/builtins-s390.cc |
index 0340ea6eb74c46bb76533c591bdaea530029ca78..e002abca80f97c49fbbe9ba10e8c33f975e2d6d3 100644 |
--- a/src/builtins/s390/builtins-s390.cc |
+++ b/src/builtins/s390/builtins-s390.cc |
@@ -988,6 +988,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. |
+ __ AddP(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. |
+ // r6 : code entry |
+ // r9: native context |
+ // r3 : 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. |
+ __ LoadRR(scratch2, closure); |
+ __ RecordWriteContextSlot(native_context, function_list_offset, closure, |
+ scratch3, kLRHasNotBeenSaved, kDontSaveFPRegs); |
+ __ LoadRR(closure, scratch2); |
+} |
+ |
static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) { |
Register args_count = scratch; |
@@ -1028,6 +1063,21 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
FrameScope frame_scope(masm, StackFrame::MANUAL); |
__ PushStandardFrame(r3); |
+ // 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 = r6; |
+ __ LoadP(r2, FieldMemOperand(r3, JSFunction::kFeedbackVectorOffset)); |
+ __ LoadP(r2, FieldMemOperand(r2, Cell::kValueOffset)); |
+ __ LoadP( |
+ optimized_code_entry, |
+ FieldMemOperand(r2, 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(r2, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
@@ -1147,6 +1197,29 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
__ StoreP(r6, FieldMemOperand(r3, JSFunction::kCodeEntryOffset), r0); |
__ RecordWriteCodeEntryField(r3, r6, r7); |
__ JumpToJSEntry(r6); |
+ |
+ // 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. |
+ __ LoadlB(r7, FieldMemOperand(optimized_code_entry, |
+ Code::kKindSpecificFlags1Offset)); |
+ __ tmll(r7, Operand(Code::kMarkedForDeoptimizationBit)); |
+ __ bne(&gotta_call_runtime); |
+ |
+ // 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, r3, r8, r7, |
+ r4); |
+ __ 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, |
@@ -1413,31 +1486,7 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) { |
__ bne(&gotta_call_runtime); |
// Code is good, get it into the closure and tail call. |
- __ AddP(entry, entry, Operand(Code::kHeaderSize - kHeapObjectTag)); |
- __ StoreP(entry, FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0); |
- __ RecordWriteCodeEntryField(closure, entry, r7); |
- |
- // Load native context into r8. |
- Register native_context = r8; |
- __ LoadP(native_context, NativeContextMemOperand()); |
- |
- // Link the closure into the optimized function list. |
- __ LoadP( |
- r7, ContextMemOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST)); |
- __ StoreP(r7, FieldMemOperand(closure, JSFunction::kNextFunctionLinkOffset), |
- r0); |
- __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, r7, r4, |
- 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. |
- __ LoadRR(r7, closure); |
- __ RecordWriteContextSlot(native_context, function_list_offset, r7, r4, |
- kLRHasNotBeenSaved, kDontSaveFPRegs); |
+ ReplaceClosureEntryWithOptimizedCode(masm, entry, closure, r8, r7, r4); |
__ JumpToJSEntry(entry); |
// We found no optimized code. |