blob: f8d9fb1b7b258cf3e9f020a6f8cc1c4906130c11 [file]
/*
* 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 "open/vm_class_loading.h"
#include "open/vm_ee.h"
#include "open/vm.h"
/**
* @file
* @brief Object creation, monitors and cast checks.
*/
namespace Jitrino {
namespace Jet {
void CodeGen::gen_new_array(Class_Handle enclClass, unsigned cpIndex)
{
bool lazy = m_lazy_resolution;
bool resolve = !lazy || class_cp_is_entry_resolved(enclClass, cpIndex);
if (resolve) {
Allocation_Handle ah = 0;
Class_Handle klass = resolve_class(m_compileHandle, enclClass, cpIndex);
if (klass != NULL) {
klass = class_get_array_of_class(klass);
}
if (klass != NULL) {
ah = class_get_allocation_handle(klass);
}
gen_new_array(ah);
return;
}
assert(lazy);
vpark();
SYNC_FIRST(static const CallSig cs_newarray_withresolve(CCONV_HELPERS, jobj, iplatf, i32, i32));
rlock(cs_newarray_withresolve);
Val sizeVal = vstack(0);
// setup constant parameters first,
Val vclass(iplatf, enclClass);
Val vcpIdx((int)cpIndex);
gen_args(cs_newarray_withresolve, 0, &vclass, &vcpIdx, &sizeVal);
gen_call_vm(cs_newarray_withresolve, rt_helper_new_array_withresolve, 3);
runlock(cs_newarray_withresolve);
vpop();// pop array size
gen_save_ret(cs_newarray_withresolve);
// the returned can not be null, marking as such.
vstack(0).set(VA_NZ);
// allocation assumes GC invocation
m_bbstate->seen_gcpt = true;
}
void CodeGen::gen_new_array(Allocation_Handle ah) {
const JInst& jinst = *m_curr_inst;
assert(jinst.opcode == OPCODE_NEWARRAY || jinst.opcode == OPCODE_ANEWARRAY);
if (ah == 0) {
assert(!m_lazy_resolution);
// it's unexpected that that something failed for a primitive type
assert(jinst.opcode != OPCODE_NEWARRAY);
gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0,
m_klass, jinst.op0, jinst.opcode);
}
SYNC_FIRST(static const CallSig cs_new_arr(CCONV_HELPERS, jobj, i32, jobj));
unsigned stackFix = gen_stack_to_args(true, cs_new_arr, 0, 1);
gen_call_vm(cs_new_arr, rt_helper_new_array, 1, ah);
runlock(cs_new_arr);
if (stackFix != 0) {
alu(alu_sub, sp, stackFix);
}
gen_save_ret(cs_new_arr);
// the returned can not be null, marking as such.
vstack(0).set(VA_NZ);
// allocation assumes GC invocation
m_bbstate->seen_gcpt = true;
}
void CodeGen::gen_multianewarray(Class_Handle enclClass, unsigned short cpIndex, unsigned num_dims)
{
// stack: [..., count1, [...count N] ]
// args: (klassHandle, num_dims, count_n, ... count_1)
// native stack to be established (ia32):
// .., count_1, .. count_n, num_dims, klassHandle
vector<jtype> args;
for (unsigned i = 0; i<num_dims; i++) {
args.push_back(i32);
}
args.push_back(i32);
args.push_back(jobj);
Class_Handle klass = NULL;
Val klassVal;
bool lazy = m_lazy_resolution;
bool resolve = !lazy || class_cp_is_entry_resolved(enclClass, cpIndex);
if(!resolve) {
assert(lazy);
SYNC_FIRST(static const CallSig ci_get_class_withresolve(CCONV_HELPERS, jobj, iplatf, i32));
gen_call_vm(ci_get_class_withresolve, rt_helper_get_class_withresolve, 0, enclClass, cpIndex);
AR gr_ret = ci_get_class_withresolve.ret_reg(0);
klassVal = Val(jobj, gr_ret);
} else {
klass = resolve_class(m_compileHandle, enclClass, cpIndex);
klassVal = Val(jobj, klass);
}
rlock(klassVal); // to protect gr_ret while setting up helper args
// note: need to restore the stack - the cdecl-like function
CallSig ci(CCONV_CDECL|CCONV_MEM|CCONV_L2R|CCONV_RETURN_FP_THROUGH_FPU, jobj, args);
unsigned stackFix = gen_stack_to_args(true, ci, 0, num_dims);
runlock(klassVal);
if (klass == NULL && !lazy) {
gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0,
m_klass, cpIndex, OPCODE_MULTIANEWARRAY);
}
Val vnum_dims = Opnd(num_dims);
gen_args(ci, num_dims, &vnum_dims, &klassVal);
gen_call_vm(ci, rt_helper_multinewarray, 2+num_dims);
runlock(ci);
if (stackFix != 0) {
alu(alu_sub, sp, stackFix);
}
gen_save_ret(ci);
// the returned can not be null, marking as such.
vstack(0).set(VA_NZ);
// allocation assumes GC invocation
m_bbstate->seen_gcpt = true;
}
void CodeGen::gen_new(Class_Handle enclClass, unsigned short cpIndex)
{
bool lazy = m_lazy_resolution;
bool resolve = !lazy || class_cp_is_entry_resolved(enclClass, cpIndex);
const CallSig* ci = NULL;
if (resolve) {
SYNC_FIRST(static const CallSig ci_new(CCONV_HELPERS, jobj, i32, jobj));
ci = &ci_new;
Class_Handle klass = resolve_class_new(m_compileHandle, enclClass, cpIndex);
if (klass == NULL) {
gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, enclClass, cpIndex, OPCODE_NEW);
} else {
if ( klass!=enclClass && !class_is_initialized(klass)) {
gen_call_vm(ci_helper_o, rt_helper_init_class, 0, klass);
}
unsigned size = class_get_object_size(klass);
Allocation_Handle ah = class_get_allocation_handle(klass);
gen_call_vm(ci_new, rt_helper_new, 0, size, ah);
}
} else {
assert(lazy);
SYNC_FIRST(static const CallSig ci_new_with_resolve(CCONV_HELPERS, jobj, iplatf, i32));
ci = &ci_new_with_resolve;
gen_call_vm(ci_new_with_resolve, rt_helper_new_withresolve, 0, enclClass, cpIndex);
}
gen_save_ret(*ci);
vstack(0).set(VA_NZ);// the returned can not be null, marking as such.
m_bbstate->seen_gcpt = true;// allocation assumes GC invocation
}
void CodeGen::gen_instanceof_cast(JavaByteCodes opcode, Class_Handle enclClass, unsigned short cpIdx)
{
assert (opcode == OPCODE_INSTANCEOF || opcode == OPCODE_CHECKCAST);
bool lazy = m_lazy_resolution;
bool resolve = !lazy || class_cp_is_entry_resolved(enclClass, cpIdx);
if (resolve) {
Class_Handle klass = resolve_class(m_compileHandle, enclClass, cpIdx);
if (klass == NULL) {
// resolution has failed
gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, enclClass, cpIdx, opcode);
}
SYNC_FIRST(static const CallSig cs_checkcast(CCONV_HELPERS, jobj, jobj, jobj));
SYNC_FIRST(static const CallSig cs_instanceof(CCONV_HELPERS, i32, jobj, jobj));
const CallSig& cs = (opcode == OPCODE_CHECKCAST) ? cs_checkcast : cs_instanceof;
char * helper = (opcode == OPCODE_CHECKCAST) ? rt_helper_checkcast : rt_helper_instanceof;
unsigned stackFix = gen_stack_to_args(true, cs, 0, 1);
gen_call_vm(cs, helper, 1, klass);
if (stackFix != 0) {
alu(alu_sub, sp, stackFix);
}
runlock(cs);
gen_save_ret(cs);
} else {
assert(lazy);
vpark();
SYNC_FIRST(static const CallSig cs_checkcast_with_resolve(CCONV_HELPERS, jobj, iplatf, i32, jobj));
SYNC_FIRST(static const CallSig cs_instanceof_with_resolve(CCONV_HELPERS, i32, iplatf, i32, jobj));
const CallSig& cs_with_resolve = (opcode == OPCODE_CHECKCAST) ? cs_checkcast_with_resolve : cs_instanceof_with_resolve;
rlock(cs_with_resolve);
char * helper = (opcode == OPCODE_CHECKCAST) ? rt_helper_checkcast_withresolve : rt_helper_instanceof_withresolve;
Val tos = vstack(0);
// setup constant parameters first,
Val vclass(iplatf, enclClass);
Val vcpIdx(cpIdx);
gen_args(cs_with_resolve, 0, &vclass, &vcpIdx, &tos);
gen_call_vm(cs_with_resolve, helper, 3);
runlock(cs_with_resolve);
vpop();//pop obj
gen_save_ret(cs_with_resolve);
}
}
void CodeGen::gen_monitor_ee(void)
{
const JInst& jinst = *m_curr_inst;
gen_check_null(0);
SYNC_FIRST(static const CallSig cs_mon(CCONV_HELPERS, jvoid, jobj));
unsigned stackFix = gen_stack_to_args(true, cs_mon, 0);
gen_call_vm(cs_mon,
jinst.opcode == OPCODE_MONITORENTER ?
rt_helper_monitor_enter : rt_helper_monitor_exit, 1);
runlock(cs_mon);
if (stackFix != 0) {
alu(alu_sub, sp, stackFix);
}
}
void CodeGen::gen_athrow(void)
{
SYNC_FIRST(static const CallSig cs_throw(CCONV_HELPERS, jvoid, jobj));
unsigned stackFix = gen_stack_to_args(true, cs_throw, 0);
gen_call_vm(cs_throw, rt_helper_throw, 1);
runlock(cs_throw);
if (stackFix != 0) {
alu(alu_sub, sp, stackFix);
}
}
}}; // ~namespace Jitrino::Jet