@@ -916,7 +916,7 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
916916 __ mov (CSP, SP);
917917
918918 // Update information in the thread object and enter a safepoint.
919- __ TransitionGeneratedToNative (branch, temp);
919+ __ TransitionGeneratedToNative (branch, FPREG, temp);
920920
921921 __ blr (branch);
922922
@@ -944,6 +944,177 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
944944 __ set_constant_pool_allowed (true );
945945}
946946
947+ void NativeReturnInstr::EmitNativeCode (FlowGraphCompiler* compiler) {
948+ __ LeaveDartFrame ();
949+
950+ // The dummy return address is in LR, no need to pop it as on Intel.
951+
952+ // These can be anything besides the return register (R0).
953+ const Register vm_tag_reg = R1, old_exit_frame_reg = R2, tmp = R3;
954+
955+ __ Pop (old_exit_frame_reg);
956+
957+ // Restore top_resource.
958+ __ Pop (tmp);
959+ __ StoreToOffset (tmp, THR, compiler::target::Thread::top_resource_offset ());
960+
961+ __ Pop (vm_tag_reg);
962+
963+ // Reset the exit frame info to
964+ // old_exit_frame_reg *before* entering the safepoint.
965+ __ TransitionGeneratedToNative (vm_tag_reg, old_exit_frame_reg, tmp);
966+
967+ __ PopNativeCalleeSavedRegisters ();
968+
969+ // Leave the entry frame.
970+ __ LeaveFrame ();
971+
972+ // Leave the dummy frame holding the pushed arguments.
973+ __ LeaveFrame ();
974+
975+ // Restore the actual stack pointer from SPREG.
976+ __ RestoreCSP ();
977+
978+ __ Ret ();
979+
980+ // For following blocks.
981+ __ set_constant_pool_allowed (true );
982+ }
983+
984+ void NativeEntryInstr::SaveArgument (FlowGraphCompiler* compiler,
985+ Location loc) const {
986+ ASSERT (!loc.IsPairLocation ());
987+
988+ if (loc.HasStackIndex ()) return ;
989+
990+ if (loc.IsRegister ()) {
991+ __ Push (loc.reg ());
992+ } else if (loc.IsFpuRegister ()) {
993+ __ PushDouble (loc.fpu_reg ());
994+ } else {
995+ UNREACHABLE ();
996+ }
997+ }
998+
999+ void NativeEntryInstr::EmitNativeCode (FlowGraphCompiler* compiler) {
1000+ if (FLAG_precompiled_mode) {
1001+ UNREACHABLE ();
1002+ }
1003+
1004+ // Constant pool cannot be used until we enter the actual Dart frame.
1005+ __ set_constant_pool_allowed (false );
1006+
1007+ __ Bind (compiler->GetJumpLabel (this ));
1008+
1009+ // We don't use the regular stack pointer in ARM64, so we have to copy the
1010+ // native stack pointer into the Dart stack pointer.
1011+ __ SetupDartSP ();
1012+
1013+ // Create a dummy frame holding the pushed arguments. This simplifies
1014+ // NativeReturnInstr::EmitNativeCode.
1015+ __ EnterFrame (0 );
1016+
1017+ // Save the argument registers, in reverse order.
1018+ for (intptr_t i = argument_locations_->length (); i-- > 0 ;) {
1019+ SaveArgument (compiler, argument_locations_->At (i));
1020+ }
1021+
1022+ // Enter the entry frame.
1023+ __ EnterFrame (0 );
1024+
1025+ // Save a space for the code object.
1026+ __ PushImmediate (0 );
1027+
1028+ __ PushNativeCalleeSavedRegisters ();
1029+
1030+ // Load the thread object.
1031+ // TODO(35765): Fix linking issue on AOT.
1032+ // TOOD(35934): Exclude native callbacks from snapshots.
1033+ //
1034+ // Create another frame to align the frame before continuing in "native" code.
1035+ {
1036+ __ EnterFrame (0 );
1037+ __ ReserveAlignedFrameSpace (0 );
1038+
1039+ __ LoadImmediate (
1040+ R0, reinterpret_cast <int64_t >(DLRT_GetThreadForNativeCallback));
1041+ __ blr (R0);
1042+ __ mov (THR, R0);
1043+
1044+ __ LeaveFrame ();
1045+ }
1046+
1047+ // Refresh write barrier mask.
1048+ __ ldr (BARRIER_MASK,
1049+ Address (THR, compiler::target::Thread::write_barrier_mask_offset ()));
1050+
1051+ // Save the current VMTag on the stack.
1052+ __ LoadFromOffset (R0, THR, compiler::target::Thread::vm_tag_offset ());
1053+ __ Push (R0);
1054+
1055+ // Save the top resource.
1056+ __ LoadFromOffset (R0, THR, compiler::target::Thread::top_resource_offset ());
1057+ __ Push (R0);
1058+ __ StoreToOffset (ZR, THR, compiler::target::Thread::top_resource_offset ());
1059+
1060+ // Save the top exit frame info. We don't set it to 0 yet in Thread because we
1061+ // need to leave the safepoint first.
1062+ __ LoadFromOffset (R0, THR,
1063+ compiler::target::Thread::top_exit_frame_info_offset ());
1064+ __ Push (R0);
1065+
1066+ // In debug mode, verify that we've pushed the top exit frame info at the
1067+ // correct offset from FP.
1068+ __ EmitEntryFrameVerification ();
1069+
1070+ // TransitionNativeToGenerated will reset top exit frame info to 0 *after*
1071+ // leaving the safepoint.
1072+ __ TransitionNativeToGenerated (R0);
1073+
1074+ // Now that the safepoint has ended, we can touch Dart objects without
1075+ // handles.
1076+
1077+ // Otherwise we'll clobber the argument sent from the caller.
1078+ ASSERT (CallingConventions::ArgumentRegisters[0 ] != TMP &&
1079+ CallingConventions::ArgumentRegisters[0 ] != TMP2 &&
1080+ CallingConventions::ArgumentRegisters[0 ] != R1);
1081+ __ LoadImmediate (CallingConventions::ArgumentRegisters[0 ], callback_id_);
1082+ __ LoadFromOffset (
1083+ R1, THR,
1084+ compiler::target::Thread::verify_callback_isolate_entry_point_offset ());
1085+ __ blr (R1);
1086+
1087+ // Load the code object.
1088+ __ LoadFromOffset (R0, THR, compiler::target::Thread::callback_code_offset ());
1089+ __ LoadFieldFromOffset (R0, R0,
1090+ compiler::target::GrowableObjectArray::data_offset ());
1091+ __ LoadFieldFromOffset (CODE_REG, R0,
1092+ compiler::target::Array::data_offset () +
1093+ callback_id_ * compiler::target::kWordSize );
1094+
1095+ // Put the code object in the reserved slot.
1096+ __ StoreToOffset (CODE_REG, FPREG,
1097+ kPcMarkerSlotFromFp * compiler::target::kWordSize );
1098+ if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
1099+ __ ldr (PP,
1100+ Address (THR, compiler::target::Thread::global_object_pool_offset ()));
1101+ __ sub (PP, PP, Operand (kHeapObjectTag )); // Pool in PP is untagged!
1102+ } else {
1103+ // We now load the pool pointer (PP) with a GC safe value as we are about to
1104+ // invoke dart code. We don't need a real object pool here.
1105+ // Smi zero does not work because ARM64 assumes PP to be untagged.
1106+ __ LoadObject (PP, compiler::NullObject ());
1107+ }
1108+
1109+ // Load a dummy return address which suggests that we are inside of
1110+ // InvokeDartCodeStub. This is how the stack walker detects an entry frame.
1111+ __ LoadFromOffset (LR, THR,
1112+ compiler::target::Thread::invoke_dart_code_stub_offset ());
1113+ __ LoadFieldFromOffset (LR, LR, compiler::target::Code::entry_point_offset ());
1114+
1115+ FunctionEntryInstr::EmitNativeCode (compiler);
1116+ }
1117+
9471118LocationSummary* OneByteStringFromCharCodeInstr::MakeLocationSummary (
9481119 Zone* zone,
9491120 bool opt) const {
0 commit comments