/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*! \file LowerConst.cpp
    \brief This file lowers the following bytecodes: CONST_XXX

    Functions are called from the lowered native sequence:
    1> const_string_resolve
       INPUT: const pool index in %eax
       OUTPUT: resolved string in %eax
       The only register that is still live after this function is ebx
    2> class_resolve
       INPUT: const pool index in %eax
       OUTPUT: resolved class in %eax
       The only register that is still live after this function is ebx
*/
#include "libdex/DexOpcodes.h"
#include "libdex/DexFile.h"
#include "Lower.h"
#include "NcgAot.h"
#include "enc_wrapper.h"

#define P_GPR_1 PhysicalReg_EBX
#define P_GPR_2 PhysicalReg_ECX

//! LOWER bytecode CONST_STRING without usage of helper function

//! It calls const_string_resolve (%ebx is live across the call)
//! Since the register allocator does not handle control flow within the lowered native sequence,
//!   we define an interface between the lowering module and register allocator:
//!     rememberState, gotoState, transferToState
//!   to make sure at the control flow merge point the state of registers is the same
int const_string_common_nohelper(u4 tmp, u2 vA) {
    /* for trace-based JIT, the string is already resolved since this code has been executed */
    void *strPtr = (void*)
              (currentMethod->clazz->pDvmDex->pResStrings[tmp]);
    assert(strPtr != NULL);
    set_VR_to_imm(vA, OpndSize_32, (int) strPtr );
    return 0;
}
//! dispatcher to select either const_string_common_helper or const_string_common_nohelper

//!
int const_string_common(u4 tmp, u2 vA) {
    return const_string_common_nohelper(tmp, vA);
}
#undef P_GPR_1
#undef P_GPR_2

//! lower bytecode CONST_4

//!
int op_const_4() {
    u2 vA = INST_A(inst);
    s4 tmp = (s4) (INST_B(inst) << 28) >> 28;
    set_VR_to_imm(vA, OpndSize_32, tmp);
    rPC += 1;
    return 1;
}
//! lower bytecode CONST_16

//!
int op_const_16() {
    u2 BBBB = FETCH(1);
    u2 vA = INST_AA(inst);
    set_VR_to_imm(vA, OpndSize_32, (s2)BBBB);
    rPC += 2;
    return 1;
}
//! lower bytecode CONST

//!
int op_const() {
    u2 vA = INST_AA(inst);
    u4 tmp = FETCH(1);
    tmp |= (u4)FETCH(2) << 16;
    set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
    rPC += 3;
    return 1;
}
//! lower bytecode CONST_HIGH16

//!
int op_const_high16() {
    u2 vA = INST_AA(inst);
    u2 tmp = FETCH(1);
    set_VR_to_imm(vA, OpndSize_32, (s4)tmp<<16); //??
    rPC += 2;
    return 1;
}
//! lower bytecode CONST_WIDE_16

//!
int op_const_wide_16() {
    u2 vA = INST_AA(inst);
    u2 tmp = FETCH(1);
    set_VR_to_imm(vA, OpndSize_32, (s2)tmp);
    set_VR_to_imm(vA+1, OpndSize_32, (s2)tmp>>31);
    rPC += 2;
    return 2;
}
//! lower bytecode CONST_WIDE_32

//!
int op_const_wide_32() {
    u2 vA = INST_AA(inst);
    u4 tmp = FETCH(1);
    tmp |= (u4)FETCH(2) << 16;
    set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
    set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp>>31);
    rPC += 3;
    return 2;
}
//! lower bytecode CONST_WIDE

//!
int op_const_wide() {
    u2 vA = INST_AA(inst);
    u4 tmp = FETCH(1);
    tmp |= (u8)FETCH(2) << 16;
    set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
    tmp = (u8)FETCH(3);
    tmp |= (u8)FETCH(4) << 16;
    set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp);
    rPC += 5;
    return 2;
}
//! lower bytecode CONST_WIDE_HIGH16

//!
int op_const_wide_high16() {
    u2 vA = INST_AA(inst);
    u2 tmp = FETCH(1);
    set_VR_to_imm(vA, OpndSize_32, 0);
    set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp<<16);
    rPC += 2;
    return 2;
}
//! lower bytecode CONST_STRING

//!
int op_const_string() {
    u2 vB = FETCH(1);
    u2 vA = INST_AA(inst);
    u4 tmp = vB;
    int retval = const_string_common(tmp, vA);
    rPC += 2;
    return retval;
}
//! lower bytecode CONST_STRING_JUMBO

//!
int op_const_string_jumbo() {
    u2 vA = INST_AA(inst);
    u4 tmp = FETCH(1);
    tmp |= (u4)FETCH(2) << 16;
    int retval = const_string_common(tmp, vA);
    rPC += 3;
    return retval;
}

#define P_GPR_1 PhysicalReg_EBX
//! LOWER bytecode CONST_CLASS

//! It calls class_resolve (%ebx is live across the call)
//! Since the register allocator does not handle control flow within the lowered native sequence,
//!   we define an interface between the lowering module and register allocator:
//!     rememberState, gotoState, transferToState
//!   to make sure at the control flow merge point the state of registers is the same
int op_const_class() {
    u2 vA = INST_AA(inst);
    u4 tmp = (u4)FETCH(1);
    /* for trace-based JIT, the class is already resolved since this code has been executed */
    void *classPtr = (void*)
       (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
    assert(classPtr != NULL);
    set_VR_to_imm(vA, OpndSize_32, (int) classPtr );
    rPC += 2;
    return 0;
}

#undef P_GPR_1