10c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen/*
20c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * Copyright (C) 2012 The Android Open Source Project
30c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen *
40c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * Licensed under the Apache License, Version 2.0 (the "License");
50c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * you may not use this file except in compliance with the License.
60c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * You may obtain a copy of the License at
70c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen *
80c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen *      http://www.apache.org/licenses/LICENSE-2.0
90c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen *
100c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * Unless required by applicable law or agreed to in writing, software
110c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * distributed under the License is distributed on an "AS IS" BASIS,
120c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * See the License for the specific language governing permissions and
140c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen * limitations under the License.
150c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen */
160c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
170c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
180c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen/*! \file LowerReturn.cpp
190c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    \brief This file lowers the following bytecodes: RETURN
200c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
210c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen*/
220c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "libdex/DexOpcodes.h"
230c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "libdex/DexFile.h"
240c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "mterp/Mterp.h"
250c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "Lower.h"
260c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "enc_wrapper.h"
270c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#include "NcgHelper.h"
280c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
290c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//4 GPRs and scratch registers used in get_self_pointer, set_glue_method and set_glue_dvmdex
300c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//will jump to "gotoBail" if caller method is NULL or if debugger is active
310c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//what is %edx for each case? for the latter case, it is 1
320c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#define P_GPR_1 PhysicalReg_ECX //must be ecx
330c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#define P_GPR_2 PhysicalReg_EBX
340c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#define P_SCRATCH_1 PhysicalReg_EDX
350c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#define P_OLD_FP PhysicalReg_EAX
360c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen/*!
370c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen\brief common section to return from a method
380c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
390c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan ChenIf the helper switch is on, this will generate a helper function
400c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen*/
410c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chenint common_returnFromMethod() {
420c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
430c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    insertMapWorklist(offsetPC, mapFromBCtoNCG[offsetPC], 1); //check when helper switch is on
440c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#endif
450c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
460c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[0] = PhysicalReg_SCRATCH_7;
470c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    get_self_pointer(2, false);
480c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
490c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //update rFP to caller stack frame
500c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_reg(OpndSize_32, PhysicalReg_FP, true, 10, false);
510c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_prevFrame, PhysicalReg_FP, true, PhysicalReg_FP, true); //update rFP
520c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //get caller method by accessing the stack save area
530c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_method, PhysicalReg_FP, true, 6, false);
540c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    compare_imm_reg(OpndSize_32, 0, 6, false);
550c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    conditional_jump(Condition_E, "common_gotoBail_0", false);
560c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    get_self_pointer(3, false);
570c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //update glue->method
580c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_mem(OpndSize_32, 6, false, offsetof(Thread, interpSave.method), 2, false);
590c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //get clazz of caller method
600c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, offMethod_clazz, 6, false, 14, false);
610c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //update self->frame
620c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, 3, false);
630c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //get method->clazz->pDvmDex
640c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, 14, false, 7, false);
650c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_mem(OpndSize_32, 7, false, offsetof(Thread, interpSave.methodClassDex), 2, false);
660c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
670c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    compare_imm_mem(OpndSize_32, 0, offsetof(Thread, suspendCount), 2, false); /* suspendCount */
680c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_returnAddr, 10, false, PhysicalReg_EBX, true);
690c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_imm_to_reg(OpndSize_32, 0, 17, false);
700c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    /* if suspendCount is not zero, clear the chaining cell address */
710c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 17, false/*src*/, PhysicalReg_EBX, true/*dst*/);
720c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_savedPc, 10, false, PhysicalReg_EAX, true);
730c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //if returnAddr is not NULL, the thread is still in code cache
740c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_mem(OpndSize_32, PhysicalReg_EBX, true, offThread_inJitCodeCache, 3, false);
750c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
760c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    insertLabel(".LreturnToInterp", true); //local label
770c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //move rPC by 6 (3 bytecode units for INVOKE)
780c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EAX, true);
790c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
800c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    //returnAddr in %ebx, if not zero, jump to returnAddr
810c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    compare_imm_reg(OpndSize_32, 0, PhysicalReg_EBX, true);
820c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    conditional_jump(Condition_E, ".LcontinueToInterp", true);
830c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#ifdef DEBUG_CALL_STACK3
840c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_reg(OpndSize_32, PhysicalReg_EBX, true, PhysicalReg_ESI, true);
850c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_imm_to_reg(OpndSize_32, 0xaabb, PhysicalReg_EBX, true);
860c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[0] = PhysicalReg_EAX;
870c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    call_debug_dumpSwitch(); //%ebx, %eax, %edx
880c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
890c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    call_debug_dumpSwitch();
900c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
910c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#endif
920c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    unconditional_jump_reg(PhysicalReg_EBX, true);
930c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    insertLabel(".LcontinueToInterp", true);
940c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[0] = PhysicalReg_SCRATCH_4;
950c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    typedef void (*vmHelper)(int);
960c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    vmHelper funcPtr = dvmJitToInterpNoChainNoProfile; //%eax is the input
970c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
9819eb287ac848f10e03ca2614bf53bd9d1ddd3724Udayan Banerji#if defined(WITH_JIT_TUNING)
9919eb287ac848f10e03ca2614bf53bd9d1ddd3724Udayan Banerji    /* Return address not in code cache. Indicate that continuing with interpreter.
10019eb287ac848f10e03ca2614bf53bd9d1ddd3724Udayan Banerji     */
10119eb287ac848f10e03ca2614bf53bd9d1ddd3724Udayan Banerji    move_imm_to_mem(OpndSize_32, kCallsiteInterpreted, 0, PhysicalReg_ESP, true);
10219eb287ac848f10e03ca2614bf53bd9d1ddd3724Udayan Banerji#endif
1030c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
1040c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    touchEax();
1050c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    return 0;
1060c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen}
1070c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#undef P_GPR_1
1080c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#undef P_GPR_2
1090c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen#undef P_SCRATCH_1
1100c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1110c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! lower bytecode RETURN_VOID
1120c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1130c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! It seems that shared code cache does not support helper switch
1140c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chenint op_return_void() {
1150c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    int retval;
1160c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    retval = common_returnFromMethod();
1170c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    rPC += 1;
1180c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    return retval;
1190c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen}
1200c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1210c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! lower bytecode RETURN
1220c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1230c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! It seems that shared code cache does not support helper switch
1240c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! The return value is stored to glue->retval first
1250c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chenint op_return() {
1260c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    u2 vA = INST_AA(inst);
1270c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1280c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    get_virtual_reg(vA, OpndSize_32, 22, false);
1290c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[0] = PhysicalReg_SCRATCH_1;
1300c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    set_return_value(OpndSize_32, 22, false);
1310c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1320c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    common_returnFromMethod();
1330c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    rPC += 1;
1340c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    return 0;
1350c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen}
1360c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1370c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! lower bytecode RETURN_WIDE
1380c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1390c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! It seems that shared code cache does not support helper switch
1400c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen//! The return value is stored to glue->retval first
1410c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chenint op_return_wide() {
1420c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    u2 vA = INST_AA(inst);
1430c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    get_virtual_reg(vA, OpndSize_64, 1, false);
1440c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[0] = PhysicalReg_SCRATCH_10; scratchRegs[1] = PhysicalReg_Null;
1450c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
1460c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    set_return_value(OpndSize_64, 1, false);
1470c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen
1480c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    common_returnFromMethod();
1490c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    rPC += 1;
1500c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen    return 0;
1510c2dc522d0e120f346cf0a40c8cf0c93346131c2Dong-Yuan Chen}
152