diff options
Diffstat (limited to 'deps/v8/src/builtins/arm64/builtins-arm64.cc')
-rw-r--r-- | deps/v8/src/builtins/arm64/builtins-arm64.cc | 246 |
1 files changed, 117 insertions, 129 deletions
diff --git a/deps/v8/src/builtins/arm64/builtins-arm64.cc b/deps/v8/src/builtins/arm64/builtins-arm64.cc index 4e159a69b7..9edd074e3d 100644 --- a/deps/v8/src/builtins/arm64/builtins-arm64.cc +++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc @@ -1001,108 +1001,78 @@ static void TailCallRuntimeIfMarkerEquals(MacroAssembler* masm, OptimizationMarker marker, Runtime::FunctionId function_id) { Label no_match; - __ CompareAndBranch(smi_entry, Operand(Smi::FromEnum(marker)), ne, &no_match); + __ CompareTaggedAndBranch(smi_entry, Operand(Smi::FromEnum(marker)), ne, + &no_match); GenerateTailCallToReturnedCode(masm, function_id); __ bind(&no_match); } -static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, - Register feedback_vector, - Register scratch1, - Register scratch2) { +static void TailCallOptimizedCodeSlot(MacroAssembler* masm, + Register optimized_code_entry, + Register scratch) { // ----------- S t a t e ------------- // -- x3 : new target (preserved for callee if needed, and caller) // -- x1 : target function (preserved for callee if needed, and caller) - // -- feedback vector (preserved for caller if needed) // ----------------------------------- - DCHECK(!AreAliased(feedback_vector, x1, x3, scratch1, scratch2)); - - Label optimized_code_slot_is_weak_ref, fallthrough; + DCHECK(!AreAliased(x1, x3, optimized_code_entry, scratch)); Register closure = x1; - Register optimized_code_entry = scratch1; - - __ LoadAnyTaggedField( - optimized_code_entry, - FieldMemOperand(feedback_vector, - FeedbackVector::kOptimizedCodeWeakOrSmiOffset)); - - // Check if the code entry is a Smi. If yes, we interpret it as an - // optimisation marker. Otherwise, interpret is at a weak reference to a code - // object. - __ JumpIfNotSmi(optimized_code_entry, &optimized_code_slot_is_weak_ref); - - { - // Optimized code slot is a Smi optimization marker. - - // Fall through if no optimization trigger. - __ CompareAndBranch(optimized_code_entry, - Operand(Smi::FromEnum(OptimizationMarker::kNone)), eq, - &fallthrough); - - // TODO(v8:8394): The logging of first execution will break if - // feedback vectors are not allocated. We need to find a different way of - // logging these events if required. - TailCallRuntimeIfMarkerEquals(masm, optimized_code_entry, - OptimizationMarker::kLogFirstExecution, - Runtime::kFunctionFirstExecution); - 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, so fall through hoping - // that an interrupt will eventually update the slot with optimized code. - if (FLAG_debug_code) { - __ Cmp( - optimized_code_entry, - Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); - __ Assert(eq, AbortReason::kExpectedOptimizationSentinel); - } - __ B(&fallthrough); - } - } - { - // Optimized code slot is a weak reference. - __ bind(&optimized_code_slot_is_weak_ref); - - __ LoadWeakValue(optimized_code_entry, 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; + __ LoadTaggedPointerField( + scratch, + FieldMemOperand(optimized_code_entry, Code::kCodeDataContainerOffset)); + __ Ldr(scratch.W(), + FieldMemOperand(scratch, CodeDataContainer::kKindSpecificFlagsOffset)); + __ Tbnz(scratch.W(), Code::kMarkedForDeoptimizationBit, + &found_deoptimized_code); + + // Optimized code is good, get it into the closure and link the closure into + // the optimized functions list, then tail call the optimized code. + ReplaceClosureCodeWithOptimizedCode(masm, optimized_code_entry, closure); + static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch"); + __ LoadCodeObjectEntry(x2, optimized_code_entry); + __ Jump(x2); - // Check if the optimized code is marked for deopt. If it is, call the - // runtime to clear it. - Label found_deoptimized_code; - __ LoadTaggedPointerField( - scratch2, - FieldMemOperand(optimized_code_entry, Code::kCodeDataContainerOffset)); - __ Ldr( - scratch2.W(), - FieldMemOperand(scratch2, CodeDataContainer::kKindSpecificFlagsOffset)); - __ Tbnz(scratch2.W(), Code::kMarkedForDeoptimizationBit, - &found_deoptimized_code); - - // 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. - ReplaceClosureCodeWithOptimizedCode(masm, optimized_code_entry, closure); - static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch"); - __ LoadCodeObjectEntry(x2, optimized_code_entry); - __ Jump(x2); + // Optimized code slot contains deoptimized code, evict it and re-enter the + // closure's code. + __ bind(&found_deoptimized_code); + GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); +} - // Optimized code slot contains deoptimized code, evict it and re-enter the - // closure's code. - __ bind(&found_deoptimized_code); - GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); +static void MaybeOptimizeCode(MacroAssembler* masm, Register feedback_vector, + Register optimization_marker) { + // ----------- S t a t e ------------- + // -- x3 : new target (preserved for callee if needed, and caller) + // -- x1 : target function (preserved for callee if needed, and caller) + // -- feedback vector (preserved for caller if needed) + // -- optimization_marker : a Smi containing a non-zero optimization marker. + // ----------------------------------- + DCHECK(!AreAliased(feedback_vector, x1, x3, optimization_marker)); + + // TODO(v8:8394): The logging of first execution will break if + // feedback vectors are not allocated. We need to find a different way of + // logging these events if required. + TailCallRuntimeIfMarkerEquals(masm, optimization_marker, + OptimizationMarker::kLogFirstExecution, + Runtime::kFunctionFirstExecution); + TailCallRuntimeIfMarkerEquals(masm, optimization_marker, + OptimizationMarker::kCompileOptimized, + Runtime::kCompileOptimized_NotConcurrent); + TailCallRuntimeIfMarkerEquals(masm, optimization_marker, + OptimizationMarker::kCompileOptimizedConcurrent, + Runtime::kCompileOptimized_Concurrent); + + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. + if (FLAG_debug_code) { + __ CmpTagged( + optimization_marker, + Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); + __ Assert(eq, AbortReason::kExpectedOptimizationSentinel); } - - // Fall-through if the optimized code cell is clear and there is no - // optimization marker. - __ bind(&fallthrough); } // Advance the current bytecode offset. This simulates what all bytecode @@ -1129,19 +1099,19 @@ static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, __ Cmp(bytecode, Operand(0x3)); __ B(hi, &process_bytecode); __ Tst(bytecode, Operand(0x1)); - __ B(ne, &extra_wide); - - // Load the next bytecode and update table to the wide scaled table. + // The code to load the next bytecode is common to both wide and extra wide. + // We can hoist them up here since they do not modify the flags after Tst. __ Add(bytecode_offset, bytecode_offset, Operand(1)); __ Ldrb(bytecode, MemOperand(bytecode_array, bytecode_offset)); + __ B(ne, &extra_wide); + + // Update table to the wide scaled table. __ Add(bytecode_size_table, bytecode_size_table, Operand(kIntSize * interpreter::Bytecodes::kBytecodeCount)); __ B(&process_bytecode); __ Bind(&extra_wide); - // Load the next bytecode and update table to the extra wide scaled table. - __ Add(bytecode_offset, bytecode_offset, Operand(1)); - __ Ldrb(bytecode, MemOperand(bytecode_array, bytecode_offset)); + // Update table to the extra wide scaled table. __ Add(bytecode_size_table, bytecode_size_table, Operand(2 * kIntSize * interpreter::Bytecodes::kBytecodeCount)); @@ -1211,7 +1181,20 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // 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, x7, x4); + Register optimized_code_entry = x7; + __ LoadAnyTaggedField( + optimized_code_entry, + FieldMemOperand(feedback_vector, + FeedbackVector::kOptimizedCodeWeakOrSmiOffset)); + + // Check if the optimized code slot is not empty. + Label optimized_code_slot_not_empty; + __ CompareTaggedAndBranch(optimized_code_entry, + Operand(Smi::FromEnum(OptimizationMarker::kNone)), + ne, &optimized_code_slot_not_empty); + + Label not_optimized; + __ bind(¬_optimized); // Increment invocation count for the function. // MaybeTailCallOptimizedCodeSlot preserves feedback_vector, so safe to reuse @@ -1248,13 +1231,13 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ Push(kInterpreterBytecodeArrayRegister, x0); // Allocate the local and temporary register file on the stack. + Label stack_overflow; { // Load frame size from the BytecodeArray object. __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister, BytecodeArray::kFrameSizeOffset)); // Do a stack check to ensure we don't go over the limit. - Label ok; __ Sub(x10, sp, Operand(x11)); { UseScratchRegisterScope temps(masm); @@ -1262,21 +1245,19 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { LoadRealStackLimit(masm, scratch); __ Cmp(x10, scratch); } - __ B(hs, &ok); - __ CallRuntime(Runtime::kThrowStackOverflow); - __ Bind(&ok); + __ B(lo, &stack_overflow); // If ok, push undefined as the initial value for all register file entries. // Note: there should always be at least one stack slot for the return // register in the register file. Label loop_header; - __ LoadRoot(x10, RootIndex::kUndefinedValue); + __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); __ Lsr(x11, x11, kSystemPointerSizeLog2); // Round up the number of registers to a multiple of 2, to align the stack // to 16 bytes. __ Add(x11, x11, 1); __ Bic(x11, x11, 1); - __ PushMultipleTimes(x10, x11); + __ PushMultipleTimes(kInterpreterAccumulatorRegister, x11); __ Bind(&loop_header); } @@ -1291,8 +1272,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { __ Str(x3, MemOperand(fp, x10, LSL, kSystemPointerSizeLog2)); __ Bind(&no_incoming_new_target_or_generator_register); - // Load accumulator with undefined. - __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); + // The accumulator is already loaded with undefined. // Load the dispatch table into a register and dispatch to the bytecode // handler at the current bytecode offset. @@ -1315,9 +1295,8 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // Get bytecode array and bytecode offset from the stack frame. __ Ldr(kInterpreterBytecodeArrayRegister, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); - __ Ldr(kInterpreterBytecodeOffsetRegister, - MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); - __ SmiUntag(kInterpreterBytecodeOffsetRegister); + __ SmiUntag(kInterpreterBytecodeOffsetRegister, + MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); // Either return, or advance to the next bytecode and dispatch. Label do_return; @@ -1333,9 +1312,28 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { LeaveInterpreterFrame(masm, x2); __ Ret(); + __ bind(&optimized_code_slot_not_empty); + Label maybe_has_optimized_code; + // Check if optimized code marker is actually a weak reference to the + // optimized code as opposed to an optimization marker. + __ JumpIfNotSmi(optimized_code_entry, &maybe_has_optimized_code); + MaybeOptimizeCode(masm, feedback_vector, optimized_code_entry); + // Fall through if there's no runnable optimized code. + __ jmp(¬_optimized); + + __ bind(&maybe_has_optimized_code); + // Load code entry from the weak reference, if it was cleared, resume + // execution of unoptimized code. + __ LoadWeakValue(optimized_code_entry, optimized_code_entry, ¬_optimized); + TailCallOptimizedCodeSlot(masm, optimized_code_entry, x4); + __ bind(&compile_lazy); GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy); __ Unreachable(); // Should not return. + + __ bind(&stack_overflow); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Unreachable(); // Should not return. } static void Generate_InterpreterPushArgs(MacroAssembler* masm, @@ -1543,9 +1541,8 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { } // Get the target bytecode offset from the frame. - __ Ldr(kInterpreterBytecodeOffsetRegister, - MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); - __ SmiUntag(kInterpreterBytecodeOffsetRegister); + __ SmiUntag(kInterpreterBytecodeOffsetRegister, + MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); // Dispatch to the target bytecode. __ Ldrb(x23, MemOperand(kInterpreterBytecodeArrayRegister, @@ -1560,9 +1557,8 @@ void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { // Get bytecode array and bytecode offset from the stack frame. __ ldr(kInterpreterBytecodeArrayRegister, MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); - __ ldr(kInterpreterBytecodeOffsetRegister, - MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); - __ SmiUntag(kInterpreterBytecodeOffsetRegister); + __ SmiUntag(kInterpreterBytecodeOffsetRegister, + MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); // Load the current bytecode. __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister, @@ -1633,7 +1629,7 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) { // Set flags for determining the value of smi-tagged argc. // lt => 1, eq => 2, gt => 3. - __ Cmp(argc, Smi::FromInt(2)); + __ CmpTagged(argc, Smi::FromInt(2)); __ B(gt, &three_args); // One or two arguments. @@ -1769,20 +1765,14 @@ void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { } void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { - // Lookup the function in the JavaScript frame. - __ Ldr(x0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); - __ Ldr(x0, MemOperand(x0, JavaScriptFrameConstants::kFunctionOffset)); - { FrameScope scope(masm, StackFrame::INTERNAL); - // Pass function as argument. - __ PushArgument(x0); __ CallRuntime(Runtime::kCompileForOnStackReplacement); } // If the code object is null, just return to the caller. Label skip; - __ CompareAndBranch(x0, Smi::zero(), ne, &skip); + __ CompareTaggedAndBranch(x0, Smi::zero(), ne, &skip); __ Ret(); __ Bind(&skip); @@ -1878,8 +1868,8 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { // 3. Tail call with no arguments if argArray is null or undefined. Label no_arguments; - __ Cmp(arg_array, null_value); - __ Ccmp(arg_array, undefined_value, ZFlag, ne); + __ CmpTagged(arg_array, null_value); + __ CcmpTagged(arg_array, undefined_value, ZFlag, ne); __ B(eq, &no_arguments); // 4a. Apply the receiver to the given argArray. @@ -2261,7 +2251,7 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, __ Bind(&loop); __ Sub(len, len, 1); __ LoadAnyTaggedField(scratch, MemOperand(src, kTaggedSize, PostIndex)); - __ Cmp(scratch, the_hole_value); + __ CmpTagged(scratch, the_hole_value); __ Csel(scratch, scratch, undefined_value, ne); __ Poke(scratch, Operand(len, LSL, kSystemPointerSizeLog2)); __ Cbnz(len, &loop); @@ -2319,7 +2309,7 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, __ Ldr(args_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ Ldr(x4, MemOperand(args_fp, CommonFrameConstants::kContextOrFrameTypeOffset)); - __ Cmp(x4, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)); + __ CmpTagged(x4, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)); __ B(eq, &arguments_adaptor); { __ Ldr(scratch, @@ -2626,7 +2616,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // -- x1 : the target to call (can be any Object). // ----------------------------------- - Label non_callable, non_function, non_smi; + Label non_callable, non_smi; __ JumpIfSmi(x1, &non_callable); __ Bind(&non_smi); __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE); @@ -2642,12 +2632,10 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // Check if target is a proxy and call CallProxy external builtin __ Cmp(x5, JS_PROXY_TYPE); - __ B(ne, &non_function); - __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET); + __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq); // 2. Call to something else, which might have a [[Call]] internal method (if // not we raise an exception). - __ Bind(&non_function); // Overwrite the original receiver with the (original) target. __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2)); // Let the "call_as_function_delegate" take care of the rest. @@ -2712,7 +2700,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { // Patch new.target to [[BoundTargetFunction]] if new.target equals target. { Label done; - __ Cmp(x1, x3); + __ CmpTagged(x1, x3); __ B(ne, &done); __ LoadTaggedPointerField( x3, FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset)); |