@@ -1382,18 +1382,17 @@ LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
13821382 zone, is_optimizing,
13831383 (R (CallingConventions::kSecondNonArgumentRegister ) |
13841384 R (CallingConventions::kFfiAnyNonAbiRegister ) | R (CALLEE_SAVED_TEMP2)));
1385- // A3/A4/A5 are blocked during Dart register allocation because they are
1385+
1386+ // A3/A4/A5 are unavailable in normal register allocation because they are
13861387 // assigned to TMP/TMP2/PP. This assignment is important for reducing code
1387- // size. To work around this for FFI calls, the FFI argument definitions are
1388- // allocated to other registers and moved to the correct register at the last
1389- // moment (so there are no conflicting uses of TMP/TMP2/PP) .
1390- // FfiCallInstr itself sometimes also clobbers A2/CODE_REG.
1391- // See also FfiCallInstr::EmitCall .
1388+ // size. We can't just override the normal blockage of these registers because
1389+ // they may be used by other instructions between the argument's definition
1390+ // and its use in FfiCallInstr .
1391+ // Note that A3/A4/A5 might be not be the 3rd/4th/5th input because of mixed
1392+ // integer and floating-point arguments .
13921393 for (intptr_t i = 0 ; i < summary->input_count (); i++) {
13931394 if (!summary->in (i).IsRegister ()) continue ;
1394- if (summary->in (i).reg () == A2) {
1395- summary->set_in (i, Location::RegisterLocation (T2));
1396- } else if (summary->in (i).reg () == A3) {
1395+ if (summary->in (i).reg () == A3) {
13971396 summary->set_in (i, Location::RegisterLocation (T3));
13981397 } else if (summary->in (i).reg () == A4) {
13991398 summary->set_in (i, Location::RegisterLocation (T4));
@@ -1407,6 +1406,20 @@ LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
14071406#undef R
14081407
14091408void FfiCallInstr::EmitNativeCode (FlowGraphCompiler* compiler) {
1409+ // Beware! Do not use CODE_REG/TMP/TMP2/PP within FfiCallInstr as they are
1410+ // assigned to A2/A3/A4/A5, which may be in use as argument registers.
1411+ __ set_constant_pool_allowed (false );
1412+ for (intptr_t i = 0 ; i < locs ()->input_count (); i++) {
1413+ if (!locs ()->in (i).IsRegister ()) continue ;
1414+ if (locs ()->in (i).reg () == T3) {
1415+ __ mv (A3, T3);
1416+ } else if (locs ()->in (i).reg () == T4) {
1417+ __ mv (A4, T4);
1418+ } else if (locs ()->in (i).reg () == T5) {
1419+ __ mv (A5, T5);
1420+ }
1421+ }
1422+
14101423 const Register target = locs ()->in (TargetAddressIndex ()).reg ();
14111424
14121425 // The temps are indexed according to their register number.
@@ -1431,17 +1444,27 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
14311444 __ mv (saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
14321445
14331446 if (!is_leaf_) {
1434- // We need to create a dummy "exit frame". It will share the same pool
1435- // pointer but have a null code object.
1436- __ LoadObject (CODE_REG, Object::null_object ());
1437- __ set_constant_pool_allowed (false );
1438- __ EnterDartFrame (0 , PP);
1447+ // We need to create a dummy "exit frame".
1448+ // This is EnterDartFrame without accessing A2=CODE_REG or A5=PP.
1449+ if (FLAG_precompiled_mode) {
1450+ __ subi (SP, SP, 2 * compiler::target::kWordSize );
1451+ __ sx (RA, compiler::Address (SP, 1 * compiler::target::kWordSize ));
1452+ __ sx (FP, compiler::Address (SP, 0 * compiler::target::kWordSize ));
1453+ __ addi (FP, SP, 2 * compiler::target::kWordSize );
1454+ } else {
1455+ __ subi (SP, SP, 4 * compiler::target::kWordSize );
1456+ __ sx (RA, compiler::Address (SP, 3 * compiler::target::kWordSize ));
1457+ __ sx (FP, compiler::Address (SP, 2 * compiler::target::kWordSize ));
1458+ __ sx (NULL_REG, compiler::Address (SP, 1 * compiler::target::kWordSize ));
1459+ __ sx (NULL_REG, compiler::Address (SP, 0 * compiler::target::kWordSize ));
1460+ __ addi (FP, SP, 4 * compiler::target::kWordSize );
1461+ }
14391462 }
14401463
14411464 // Reserve space for the arguments that go on the stack (if any), then align.
14421465 __ ReserveAlignedFrameSpace (marshaller_.RequiredStackSpaceInBytes ());
14431466
1444- EmitParamMoves (compiler, is_leaf_ ? FPREG : saved_fp_or_sp, temp1);
1467+ EmitParamMoves (compiler, is_leaf_ ? FPREG : saved_fp_or_sp, temp1, temp2 );
14451468
14461469 if (compiler::Assembler::EmittingComments ()) {
14471470 __ Comment (is_leaf_ ? " Leaf Call" : " Call" );
@@ -1456,10 +1479,7 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
14561479 __ StoreToOffset (target, THR, compiler::target::Thread::vm_tag_offset ());
14571480#endif
14581481
1459- EmitCall (compiler, target);
1460-
1461- ASSERT (!IsCalleeSavedRegister (PP));
1462- __ RestorePoolPointer ();
1482+ __ jalr (target);
14631483
14641484#if !defined(PRODUCT)
14651485 __ LoadImmediate (temp1, compiler::target::Thread::vm_tag_dart_id ());
@@ -1484,7 +1504,7 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
14841504 __ TransitionGeneratedToNative (target, FPREG, temp1,
14851505 /* enter_safepoint=*/ true );
14861506
1487- EmitCall (compiler, target);
1507+ __ jalr ( target);
14881508
14891509 // Update information in the thread object and leave the safepoint.
14901510 __ TransitionNativeToGenerated (temp1, /* leave_safepoint=*/ true );
@@ -1500,7 +1520,7 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
15001520
15011521 // Calls T0 and clobbers R19 (along with volatile registers).
15021522 ASSERT (target == T0);
1503- EmitCall (compiler, temp1);
1523+ __ jalr ( temp1);
15041524 }
15051525
15061526 // Refresh pinned registers values (inc. write barrier mask and null
@@ -1514,27 +1534,18 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
15141534 // Restore the pre-aligned SP.
15151535 __ mv (SPREG, saved_fp_or_sp);
15161536 } else {
1517- // Although PP is a callee-saved register, it may have been moved by the GC.
1518- __ LeaveDartFrame (compiler::kRestoreCallerPP );
1537+ __ LeaveDartFrame ();
15191538
15201539 // Restore the global object pool after returning from runtime (old space is
15211540 // moving, so the GOP could have been relocated).
15221541 if (FLAG_precompiled_mode) {
15231542 __ SetupGlobalPoolAndDispatchTable ();
15241543 }
1525-
1526- __ set_constant_pool_allowed (true );
15271544 }
1528- }
15291545
1530- void FfiCallInstr::EmitCall (FlowGraphCompiler* compiler, Register target) {
1531- // Marshall certain argument registers at the last possible moment.
1532- // See FfiCallInstr::MakeLocationSummary for the details.
1533- if (InputCount () > 2 ) __ mv (A2, T2); // A2=CODE_REG
1534- if (InputCount () > 3 ) __ mv (A3, T3); // A3=TMP
1535- if (InputCount () > 4 ) __ mv (A4, T4); // A4=TMP2
1536- if (InputCount () > 5 ) __ mv (A5, T5); // A5=PP
1537- __ jalr (target);
1546+ // PP is a volatile register, so it must be restored even for leaf FFI calls.
1547+ __ RestorePoolPointer ();
1548+ __ set_constant_pool_allowed (true );
15381549}
15391550
15401551// Keep in sync with NativeEntryInstr::EmitNativeCode.
0 commit comments