| Index: src/builtins/ppc/builtins-ppc.cc
|
| diff --git a/src/builtins/ppc/builtins-ppc.cc b/src/builtins/ppc/builtins-ppc.cc
|
| index 35713097dd00cd0eafd8a4a6e0e86e666bf1f539..f805818c8186d4d901b0b774c958f5a6ba50c7ac 100644
|
| --- a/src/builtins/ppc/builtins-ppc.cc
|
| +++ b/src/builtins/ppc/builtins-ppc.cc
|
| @@ -427,23 +427,6 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
|
| __ JumpToJSEntry(ip);
|
| }
|
|
|
| -void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
|
| - // Checking whether the queued function is ready for install is optional,
|
| - // since we come across interrupts and stack checks elsewhere. However,
|
| - // not checking may delay installing ready functions, and always checking
|
| - // would be quite expensive. A good compromise is to first check against
|
| - // stack limit as a cue for an interrupt signal.
|
| - Label ok;
|
| - __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| - __ cmpl(sp, ip);
|
| - __ bge(&ok);
|
| -
|
| - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
|
| -
|
| - __ bind(&ok);
|
| - GenerateTailCallToSharedCode(masm);
|
| -}
|
| -
|
| namespace {
|
|
|
| void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
|
| @@ -1033,6 +1016,120 @@ static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) {
|
| __ add(sp, sp, args_count);
|
| }
|
|
|
| +// Tail-call |function_id| if |smi_entry| == |marker|
|
| +static void TailCallRuntimeIfMarkerEquals(MacroAssembler* masm,
|
| + Register smi_entry,
|
| + OptimizationMarker marker,
|
| + Runtime::FunctionId function_id) {
|
| + Label no_match;
|
| + __ CmpSmiLiteral(smi_entry, Smi::FromEnum(marker), r0);
|
| + __ bne(&no_match);
|
| + GenerateTailCallToReturnedCode(masm, function_id);
|
| + __ bind(&no_match);
|
| +}
|
| +
|
| +static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
|
| + Register feedback_vector,
|
| + Register scratch1, Register scratch2,
|
| + Register scratch3) {
|
| + // ----------- S t a t e -------------
|
| + // -- r0 : argument count (preserved for callee if needed, and caller)
|
| + // -- r3 : new target (preserved for callee if needed, and caller)
|
| + // -- r1 : target function (preserved for callee if needed, and caller)
|
| + // -- feedback vector (preserved for caller if needed)
|
| + // -----------------------------------
|
| + DCHECK(
|
| + !AreAliased(feedback_vector, r3, r4, r6, scratch1, scratch2, scratch3));
|
| +
|
| + Label optimized_code_slot_is_cell, fallthrough;
|
| +
|
| + Register closure = r4;
|
| + Register optimized_code_entry = scratch1;
|
| +
|
| + const int kOptimizedCodeCellOffset =
|
| + FeedbackVector::kOptimizedCodeIndex * kPointerSize +
|
| + FeedbackVector::kHeaderSize;
|
| + __ LoadP(optimized_code_entry,
|
| + FieldMemOperand(feedback_vector, kOptimizedCodeCellOffset));
|
| +
|
| + // Check if the code entry is a Smi. If yes, we interpret it as an
|
| + // optimisation marker. Otherwise, interpret is as a weak cell to a code
|
| + // object.
|
| + __ JumpIfNotSmi(optimized_code_entry, &optimized_code_slot_is_cell);
|
| +
|
| + {
|
| + // Optimized code slot is a Smi optimization marker.
|
| +
|
| + // Fall through if no optimization trigger.
|
| + __ CmpSmiLiteral(optimized_code_entry,
|
| + Smi::FromEnum(OptimizationMarker::kNone), r0);
|
| + __ beq(&fallthrough);
|
| +
|
| + TailCallRuntimeIfMarkerEquals(masm, optimized_code_entry,
|
| + OptimizationMarker::kCompileOptimized,
|
| + Runtime::kCompileOptimized_NotConcurrent);
|
| + TailCallRuntimeIfMarkerEquals(
|
| + masm, optimized_code_entry,
|
| + OptimizationMarker::kCompileOptimizedConcurrent,
|
| + Runtime::kCompileOptimized_Concurrent);
|
| +
|
| + {
|
| + // Otherwise, the marker is InOptimizationQueue.
|
| + if (FLAG_debug_code) {
|
| + __ CmpSmiLiteral(
|
| + optimized_code_entry,
|
| + Smi::FromEnum(OptimizationMarker::kInOptimizationQueue), r0);
|
| + __ Assert(eq, kExpectedOptimizationSentinel);
|
| + }
|
| +
|
| + // Checking whether the queued function is ready for install is optional,
|
| + // since we come across interrupts and stack checks elsewhere. However,
|
| + // not checking may delay installing ready functions, and always checking
|
| + // would be quite expensive. A good compromise is to first check against
|
| + // stack limit as a cue for an interrupt signal.
|
| + __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| + __ cmpl(sp, ip);
|
| + __ bge(&fallthrough);
|
| + GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
|
| + }
|
| + }
|
| +
|
| + {
|
| + // Optimized code slot is a WeakCell.
|
| + __ bind(&optimized_code_slot_is_cell);
|
| +
|
| + __ LoadP(optimized_code_entry,
|
| + FieldMemOperand(optimized_code_entry, WeakCell::kValueOffset));
|
| + __ JumpIfSmi(optimized_code_entry, &fallthrough);
|
| +
|
| + // Check if the optimized code is marked for deopt. If it is, call the
|
| + // runtime to clear it.
|
| + Label found_deoptimized_code;
|
| + __ LoadP(scratch2, FieldMemOperand(optimized_code_entry,
|
| + Code::kKindSpecificFlags1Offset));
|
| + __ TestBit(scratch2, Code::kMarkedForDeoptimizationBit, r0);
|
| + __ bne(&found_deoptimized_code, 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.
|
| + // The feedback vector is no longer used, so re-use it as a scratch
|
| + // register.
|
| + ReplaceClosureEntryWithOptimizedCode(masm, optimized_code_entry, closure,
|
| + scratch2, scratch3, feedback_vector);
|
| + __ mr(ip, optimized_code_entry);
|
| + __ Jump(optimized_code_entry);
|
| +
|
| + // Optimized code slot contains deoptimized code, evict it and re-enter the
|
| + // closure's code.
|
| + __ bind(&found_deoptimized_code);
|
| + GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot);
|
| + }
|
| +
|
| + // Fall-through if the optimized code cell is clear and there is no
|
| + // optimization marker.
|
| + __ bind(&fallthrough);
|
| +}
|
| +
|
| // Generate code for entering a JS function with the interpreter.
|
| // On entry to the function the receiver and arguments have been pushed on the
|
| // stack left to right. The actual argument count matches the formal parameter
|
| @@ -1052,36 +1149,33 @@ static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) {
|
| void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
| ProfileEntryHookStub::MaybeCallEntryHook(masm);
|
|
|
| + Register closure = r4;
|
| + Register feedback_vector = r5;
|
| +
|
| + // Load the feedback vector from the closure.
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(closure, JSFunction::kFeedbackVectorOffset));
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(feedback_vector, Cell::kValueOffset));
|
| + // Read off the optimized code slot in the feedback vector, and if there
|
| + // is optimized code or an optimization marker, call that instead.
|
| + MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, r7, r9, r8);
|
| +
|
| // Open a frame scope to indicate that there is a frame on the stack. The
|
| // MANUAL indicates that the scope shouldn't actually generate code to set up
|
| // the frame (that is done below).
|
| 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);
|
| + __ PushStandardFrame(closure);
|
|
|
| // Get the bytecode array from the function object (or from the DebugInfo if
|
| // it is present) and load it into kInterpreterBytecodeArrayRegister.
|
| Label maybe_load_debug_bytecode_array, bytecode_array_loaded;
|
| - __ LoadP(r3, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
| + __ LoadP(r3, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
| // Load original bytecode array or the debug copy.
|
| __ LoadP(kInterpreterBytecodeArrayRegister,
|
| FieldMemOperand(r3, SharedFunctionInfo::kFunctionDataOffset));
|
| - __ LoadP(r5, FieldMemOperand(r3, SharedFunctionInfo::kDebugInfoOffset));
|
| - __ TestIfSmi(r5, r0);
|
| + __ LoadP(r7, FieldMemOperand(r3, SharedFunctionInfo::kDebugInfoOffset));
|
| + __ TestIfSmi(r7, r0);
|
| __ bne(&maybe_load_debug_bytecode_array, cr0);
|
| __ bind(&bytecode_array_loaded);
|
|
|
| @@ -1095,16 +1189,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
| __ bne(&switch_to_different_code_kind);
|
|
|
| // Increment invocation count for the function.
|
| - __ LoadP(r7, FieldMemOperand(r4, JSFunction::kFeedbackVectorOffset));
|
| - __ LoadP(r7, FieldMemOperand(r7, Cell::kValueOffset));
|
| - __ LoadP(r8, FieldMemOperand(
|
| - r7, FeedbackVector::kInvocationCountIndex * kPointerSize +
|
| - FeedbackVector::kHeaderSize));
|
| + __ LoadP(
|
| + r8, FieldMemOperand(feedback_vector,
|
| + FeedbackVector::kInvocationCountIndex * kPointerSize +
|
| + FeedbackVector::kHeaderSize));
|
| __ AddSmiLiteral(r8, r8, Smi::FromInt(1), r0);
|
| - __ StoreP(r8, FieldMemOperand(
|
| - r7, FeedbackVector::kInvocationCountIndex * kPointerSize +
|
| - FeedbackVector::kHeaderSize),
|
| - r0);
|
| + __ StoreP(
|
| + r8,
|
| + FieldMemOperand(feedback_vector,
|
| + FeedbackVector::kInvocationCountIndex * kPointerSize +
|
| + FeedbackVector::kHeaderSize),
|
| + r0);
|
|
|
| // Check function data field is actually a BytecodeArray object.
|
|
|
| @@ -1182,12 +1277,12 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
| // SharedFunctionInfo::kFunctionDataOffset.
|
| Label done;
|
| __ bind(&maybe_load_debug_bytecode_array);
|
| - __ LoadP(ip, FieldMemOperand(r5, DebugInfo::kFlagsOffset));
|
| + __ LoadP(ip, FieldMemOperand(r7, DebugInfo::kFlagsOffset));
|
| __ SmiUntag(ip);
|
| __ andi(r0, ip, Operand(DebugInfo::kHasBreakInfo));
|
| __ beq(&done, cr0);
|
| __ LoadP(kInterpreterBytecodeArrayRegister,
|
| - FieldMemOperand(r5, DebugInfo::kDebugBytecodeArrayOffset));
|
| + FieldMemOperand(r7, DebugInfo::kDebugBytecodeArrayOffset));
|
| __ bind(&done);
|
| __ b(&bytecode_array_loaded);
|
|
|
| @@ -1196,35 +1291,12 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
| // closure by switching the code entry field over to the new code as well.
|
| __ bind(&switch_to_different_code_kind);
|
| __ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
| - __ LoadP(r7, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
| + __ LoadP(r7, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
| __ LoadP(r7, FieldMemOperand(r7, SharedFunctionInfo::kCodeOffset));
|
| __ addi(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
|
| - __ StoreP(r7, FieldMemOperand(r4, JSFunction::kCodeEntryOffset), r0);
|
| - __ RecordWriteCodeEntryField(r4, r7, r8);
|
| + __ StoreP(r7, FieldMemOperand(closure, JSFunction::kCodeEntryOffset), r0);
|
| + __ RecordWriteCodeEntryField(closure, 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.
|
| - __ lwz(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,
|
| @@ -1459,6 +1531,34 @@ void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
|
| Generate_InterpreterEnterBytecode(masm);
|
| }
|
|
|
| +void Builtins::Generate_CheckOptimizationMarker(MacroAssembler* masm) {
|
| + // ----------- S t a t e -------------
|
| + // -- r3 : argument count (preserved for callee)
|
| + // -- r6 : new target (preserved for callee)
|
| + // -- r4 : target function (preserved for callee)
|
| + // -----------------------------------
|
| + Register closure = r4;
|
| +
|
| + // Get the feedback vector.
|
| + Register feedback_vector = r5;
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(closure, JSFunction::kFeedbackVectorOffset));
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(feedback_vector, Cell::kValueOffset));
|
| +
|
| + // The feedback vector must be defined.
|
| + if (FLAG_debug_code) {
|
| + __ CompareRoot(feedback_vector, Heap::kUndefinedValueRootIndex);
|
| + __ Assert(ne, BailoutReason::kExpectedFeedbackVector);
|
| + }
|
| +
|
| + // Is there an optimization marker or optimized code in the feedback vector?
|
| + MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, r7, r9, r8);
|
| +
|
| + // Otherwise, tail call the SFI code.
|
| + GenerateTailCallToSharedCode(masm);
|
| +}
|
| +
|
| void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
| // ----------- S t a t e -------------
|
| // -- r3 : argument count (preserved for callee)
|
| @@ -1467,42 +1567,25 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
| // -----------------------------------
|
| // First lookup code, maybe we don't need to compile!
|
| Label gotta_call_runtime;
|
| - Label try_shared;
|
|
|
| Register closure = r4;
|
| - Register index = r5;
|
| + Register feedback_vector = r5;
|
|
|
| // Do we have a valid feedback vector?
|
| - __ LoadP(index, FieldMemOperand(closure, JSFunction::kFeedbackVectorOffset));
|
| - __ LoadP(index, FieldMemOperand(index, Cell::kValueOffset));
|
| - __ JumpIfRoot(index, Heap::kUndefinedValueRootIndex, &gotta_call_runtime);
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(closure, JSFunction::kFeedbackVectorOffset));
|
| + __ LoadP(feedback_vector,
|
| + FieldMemOperand(feedback_vector, Cell::kValueOffset));
|
| + __ JumpIfRoot(feedback_vector, Heap::kUndefinedValueRootIndex,
|
| + &gotta_call_runtime);
|
|
|
| - // Is optimized code available in the feedback vector?
|
| - Register entry = r7;
|
| - __ LoadP(entry, FieldMemOperand(index, FeedbackVector::kOptimizedCodeIndex *
|
| - kPointerSize +
|
| - FeedbackVector::kHeaderSize));
|
| - __ LoadP(entry, FieldMemOperand(entry, WeakCell::kValueOffset));
|
| - __ JumpIfSmi(entry, &try_shared);
|
| -
|
| - // Found code, check if it is marked for deopt, if so call into runtime to
|
| - // clear the optimized code slot.
|
| - __ lwz(r8, FieldMemOperand(entry, Code::kKindSpecificFlags1Offset));
|
| - __ TestBit(r8, Code::kMarkedForDeoptimizationBit, r0);
|
| - __ bne(&gotta_call_runtime, cr0);
|
| -
|
| - // Code is good, get it into the closure and tail call.
|
| - ReplaceClosureEntryWithOptimizedCode(masm, entry, closure, r9, r8, r5);
|
| - __ JumpToJSEntry(entry);
|
| + // Is there an optimization marker or optimized code in the feedback vector?
|
| + MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, r7, r9, r8);
|
|
|
| // We found no optimized code.
|
| - __ bind(&try_shared);
|
| + Register entry = r7;
|
| __ LoadP(entry,
|
| FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset));
|
| - // Is the shared function marked for tier up?
|
| - __ lwz(r8, FieldMemOperand(entry, SharedFunctionInfo::kCompilerHintsOffset));
|
| - __ TestBit(r8, SharedFunctionInfo::MarkedForTierUpBit::kShift, r0);
|
| - __ bne(&gotta_call_runtime, cr0);
|
|
|
| // If SFI points to anything other than CompileLazy, install that.
|
| __ LoadP(entry, FieldMemOperand(entry, SharedFunctionInfo::kCodeOffset));
|
| @@ -1520,15 +1603,6 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
|
| GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
|
| }
|
|
|
| -void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
|
| - GenerateTailCallToReturnedCode(masm,
|
| - Runtime::kCompileOptimized_NotConcurrent);
|
| -}
|
| -
|
| -void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
|
| - GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent);
|
| -}
|
| -
|
| void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
| // ----------- S t a t e -------------
|
| // -- r3 : argument count (preserved for callee)
|
|
|