blob: 7d0cc6914aa9c676defcb71fe5def77efe1bdca6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Alexander Astapchuk
*/
#include "compiler.h"
#include "trace.h"
#ifdef WIN32
#include <malloc.h>
#endif
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
#include <open/vm_class_info.h>
#include <jit_import.h>
/**
* @file
* @brief CodeGen routines for PUSH/POP, LDC and LD/ST.
*/
namespace Jitrino {
namespace Jet {
void CodeGen::gen_ldc(void)
{
jtype jtyp = to_jtype(class_cp_get_const_type(
m_klass, (unsigned short)m_curr_inst->op0));
if (jtyp != jobj) { // if not loading String
const void * p = class_cp_get_const_addr(m_klass, m_curr_inst->op0);
assert(p);
if (jtyp == dbl64 || jtyp == flt32) {
gen_push(jtyp, p);
}
else if(jtyp == i64) {
gen_push(*(jlong*)p);
}
else if(jtyp == i32) {
gen_push(*(int*)p);
}
else if(jtyp == u16) {
gen_push(*(unsigned short*)p);
}
else if(jtyp == i16) {
gen_push(*(short*)p);
}
else {
assert(jtyp == i8);
gen_push(*(char*)p);
}
return;
}
assert(m_curr_inst->opcode != OPCODE_LDC2_W);
gen_call_vm(ci_helper_oi, rt_helper_ldc_string, 0, m_klass, m_curr_inst->op0);
gen_save_ret(ci_helper_oi);
vstack(0).set(VA_NZ);
m_bbstate->seen_gcpt = true;
}
void CodeGen::gen_push(int ival)
{
vpush(Val(ival));
}
void CodeGen::gen_push(jlong lval)
{
if (is_big(i64)) {
vpush2(Val((jlong)lo32(lval)), Val((jlong)hi32(lval)));
}
else {
vpush(Val(lval));
}
}
void CodeGen::gen_push(jtype jt, const void *p)
{
if (jt == dbl64) {
vpush(Val(*(double*)p, p));
}
else if (jt == flt32) {
vpush(Val(*(float*)p, p));
}
else {
assert(jt==jobj);
// This is for brand new 1.5's 'LDC object'.
// The object loaded is marked as constant which can cross a call
// site, however must check with VM/GC guys whether this is indeed
// true.
// XXX: So, are the 'LDC object'-s pinned ?
// For now, using conservative approach.
vpush(Val(jobj, p)); // vpush(Val(jobj, p).long_live());
}
}
void CodeGen::gen_pop(jtype jt)
{
vpop();
}
void CodeGen::gen_pop2(void)
{
jtype jt = m_jframe->top();
if (is_wide(jt)) {
vpop();
}
else {
vpop();
assert(!is_wide(m_jframe->top()));
vpop();
}
}
void CodeGen::gen_dup(JavaByteCodes opc)
{
jtype jtop = m_jframe->top();
// Only need to take a special action if 's' is a stack item resides in
// the stack memory area. If it points to
// local/static/const/field/register/whatever then can simply duplicate it.
#define COPY_SLOT(dst, src) \
{ \
const Val& ssrc = vstack(src); \
if (vis_stack(ssrc) && !ssrc.is_dummy()) { \
vstack(src, true); \
} \
Val& sdst = vstack(dst); \
rfree(sdst); \
sdst = ssrc; \
rref(sdst); \
}
if (opc == OPCODE_SWAP) {
// stack: .. val1, val2 => val2, val1
Val& val2 = vstack(0, vis_stack(0));
rlock(val2);
Val& val1 = vstack(1, vis_stack(1));
runlock(val2);
Val tmp = val1;
val1 = val2;
val2 = tmp;
return;
}
if (opc == OPCODE_DUP) {
// [.. val] => [.. val, val]
vpush(jtop);
COPY_SLOT(0, 1);
return;
}
if (opc==OPCODE_DUP2) {
// [.. val64] => [.. val64, val64]
vpush(jtop);
if (!is_wide(jtop)) {
vpush(jtop);
}
COPY_SLOT(0, 2);
COPY_SLOT(1, 3);
return;
}
if (opc == OPCODE_DUP_X1) {
// [..., value2, value1] => [.. value1, value2, value1]
// 1. push(jtop)
// result: val2, val1, typeof(val1)
// 2. depth(0) = depth(1)
// result: val2, val1, val1
// 3. depth(1) = depth(2)
// result: val2, val2, val1
// 4. depth(2) = depth(0)
// result: val1, val2, val1
vpush(jtop);
COPY_SLOT(0, 1);
COPY_SLOT(1, 2);
COPY_SLOT(2, 0);
return;
}
// DUP_X2
if (opc == OPCODE_DUP_X2) {
// Form 1: .. val3, val2, val1 => val1, val3, val2, val1
// Form 2: .. val2.hi, val2.lo, val1.32 =>
// ..val1, val2.hi, val2.lo, val1
// form1:
// 1. push(typeof(depth(0)))
// result: val3, val2, val1, typeof(val1)
// 2. depth(0) = depth(1)
// result: val3, val2, val1, val1
// 3. depth(1) = depth(2)
// result: val3, val2, val2, val1
// 4. depth(2) = depth(3)
// result: val3, val3, val2, val1
// 5. depth(3) = depth(0)
// result: val1, val3, val2, val1
vpush(jtop);
COPY_SLOT(0, 1);
COPY_SLOT(1, 2);
COPY_SLOT(2, 3);
COPY_SLOT(3, 0);
return;
}
if (opc == OPCODE_DUP2_X1) {
// Form 1: val3, val2, val1 => val2, val1, val3, val2, val1
// Form 2: [..., val2.32, val1.64] => [.. val1, val2, val1]
// A strategy:
// 1. push(typeof(v1))
// result: .. val2, val1.64, val1.64(unknown location)
// 2. depth(0) = depth(2) ; depth(1) = depth(3)
// result: .. val2, val1.64, val1.64
// 3. depth(2) = depth(4) ;
// result: .. val2, zzz, val2, val1.64
// zzz is former high part of val1
// 4. depth(3) = depth(0)
// result: .. val2, val1.lo, val2, val1.64
// 5. depth(4) = depth(1)
// result: .. val1.hi, val1.lo, val2, val1.64
vpush(jtop);
if (!is_wide(jtop)) {
vpush(jtop);
}
COPY_SLOT(0, 2); COPY_SLOT(1, 3);
COPY_SLOT(2, 4);
COPY_SLOT(3, 0);
COPY_SLOT(4, 1);
return;
}
if (opc == OPCODE_DUP2_X2) {
// [.. val2.64, val1.64] => [.. val1.64, val2.64, val1.64]
//f1 .., val4, val3, val2, val1 => val2, val1, val4, val3, val2, val1
//f2 .., val3, val2, val1 ..., val1, val3, val2, val1
//f3 .., val3, val2, val1 ..., val2, val1, val3, val2, val1
//f4 .., val2, val1 ..., val1, val2, val1
//
// A strategy:
// 1. push(any-wide-type)
// result: val4, val3, val2, val1, xx, xx
// 2. depth(0) = depth(2)
// 3. depth(1) = depth(3)
// result: val4, val3, val2, val1, val2, val1
// 4. depth(2) = depth(4)
// 5. depth(3) = depth(5)
// result: val4, val3, val4, val3, val2, val1
// 6. depth(4) = depth(0)
// 7. depth(5) = depth(1)
// result: val2, val1, val2, val1, val2, val1
vpush(i64); // the type does not really matter
// 2, 3
COPY_SLOT(0, 2);
COPY_SLOT(1, 3);
// 4, 5
COPY_SLOT(2, 4);
COPY_SLOT(3, 5);
// 6, 7
COPY_SLOT(4, 0);
COPY_SLOT(5, 1);
return;
}
assert(false);
}
void CodeGen::gen_ld(jtype jt, unsigned idx)
{
if (is_big(jt)) {
Val vlo = vlocal(jt, idx, false);
rlock(vlo);
Val vhi = vlocal(jt, idx+1, false);
vpush2(vlo, vhi);
runlock(vlo);
}
else {
Val& v = vlocal(jt, idx, false);
vpush(v);
}
}
void CodeGen::gen_st(jtype jt, unsigned idx)
{
vvar_def(jt, idx);
gen_gc_mark_local(jt, idx);
//
// v|s
// -|-|-------------------------
// r|m| move
// r|i| move
// r|r| move
// m|m| allocate reg, then move
// m|r| move
// m|i| move
//
Val s0 = vstack(0);
rlock(s0);
Val& var = vlocal(jt, idx, true);
runlock(s0);
vunref(jt, var);
if (var.is_mem() && s0.is_reg() && rrefs(s0.reg()) == 1) {
// The local is on memory, though the stack item is on register
vunref(jt, s0, 0);
vassign(jt, idx, s0);
}
else {
do_mov(var, s0);
}
var.attrs(s0.attrs());
if (is_big(jt)) {
//
++idx;
//
Val s0 = vstack(1);
rlock(s0);
Val& var = vlocal(jt, idx, true);
runlock(s0);
vunref(jt, var);
if (var.is_mem() && s0.is_reg() && rrefs(s0.reg()) == 1) {
// The local is on memory, though the stack item is on register
vunref(jt, s0, 1);
vassign(jt, idx, s0);
}
else {
do_mov(var, s0);
}
var.attrs(s0.attrs());
}
vpop();
}
}}; // ~namespace Jitrino::Jet