blob: 708f4e5691cb10ca122c82f3aaf061ccdd3381b7 [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.
*/
#define LOG_DOMAIN "vm.helpers"
#include "cxxlog.h"
#include <stdlib.h>
#include "lock_manager.h"
#include "open/types.h"
#include "open/vm_type_access.h"
#include "open/vm_method_access.h"
#include "Class.h"
#include "type.h"
#include "environment.h"
#include "stack_iterator.h"
#include "m2n.h"
#include "m2n_internal.h"
#include "exceptions.h"
#include "exceptions_jit.h"
#include "jit_intf.h"
#include "jit_intf_cpp.h"
#include "jit_runtime_support.h"
#include "type.h"
#include "encoder.h"
#include "object_layout.h"
#include "nogc.h"
#include "open/gc.h"
#include "open/vm_util.h"
#include "vm_threads.h"
#include "ini.h"
#include "type.h"
#include "compile.h"
#include "lil.h"
#include "lil_code_generator.h"
#include "vm_stats.h"
#include "dump.h"
void compile_flush_generated_code_block(U_8*, size_t) {
// Nothing to do on IA32
}
void compile_flush_generated_code() {
// Nothing to do on IA32
}
static U_32* get_arg_word(unsigned num_arg_words, unsigned word) {
return m2n_get_args(m2n_get_last_frame())+num_arg_words-word-1;
}
void compile_protect_arguments(Method_Handle method, GcFrame* gc) {
assert(!hythread_is_suspend_enabled());
Method_Signature_Handle msh = method_get_signature(method);
if (msh == NULL) {
return;
}
assert(msh);
unsigned num_args = method_args_get_number(msh);
unsigned num_arg_words = ((Method*)method)->get_num_arg_slots();
unsigned cur_word = 0;
for(unsigned i=0; i<num_args; i++) {
Type_Info_Handle tih = method_args_get_type_info(msh, i);
bool is_magic = false; //wjw, MMTk support
const String *str = tih->get_type_name();
switch (type_info_get_type(tih)) {
case VM_DATA_TYPE_INT64:
case VM_DATA_TYPE_UINT64:
case VM_DATA_TYPE_F8:
cur_word += 2;
break;
case VM_DATA_TYPE_INT8:
case VM_DATA_TYPE_UINT8:
case VM_DATA_TYPE_INT16:
case VM_DATA_TYPE_UINT16:
case VM_DATA_TYPE_INT32:
case VM_DATA_TYPE_UINT32:
case VM_DATA_TYPE_INTPTR:
case VM_DATA_TYPE_UINTPTR:
case VM_DATA_TYPE_F4:
case VM_DATA_TYPE_BOOLEAN:
case VM_DATA_TYPE_CHAR:
case VM_DATA_TYPE_UP:
cur_word++;
break;
case VM_DATA_TYPE_CLASS:
case VM_DATA_TYPE_ARRAY:
if (str) { //wjw MMTk support
if (strncmp(str->bytes, "org/vmmagic/unboxed/Address", str->len) == 0 )
is_magic = true;
if (strncmp(str->bytes, "org/vmmagic/unboxed/Extent", str->len) == 0 )
is_magic = true;
if (strncmp(str->bytes, "org/vmmagic/unboxed/Offset", str->len) == 0 )
is_magic = true;
if (strncmp(str->bytes, "org/vmmagic/unboxed/Word", str->len) == 0 )
is_magic = true;
if (strncmp(str->bytes, "org/vmmagic/unboxed/ObjectReference", str->len) == 0 )
is_magic = true;
}
if (is_magic == false)
gc->add_object((ManagedObject**)get_arg_word(num_arg_words, cur_word));
cur_word++;
break;
case VM_DATA_TYPE_MP:
gc->add_managed_pointer((ManagedPointer*)get_arg_word(num_arg_words, cur_word));
break;
case VM_DATA_TYPE_VALUE:
{
// This should never cause loading
Class_Handle UNUSED c = type_info_get_class(tih);
assert(c);
LDIE(30, "This functionality is not currently supported");
break;
}
default:
DIE(("Unexpected data type: %d", type_info_get_type(tih)));
}
}
}
void patch_code_with_threads_suspended(U_8* UNREF code_block, U_8* UNREF new_code, size_t UNREF size) {
LDIE(46, "Not supported on IA32 currently");
}
// Convert a reference on the stack, if null, from a managed null
// (represented by heap_base) to an unmanaged one (NULL/0). Uses %eax.
char * gen_convert_managed_to_unmanaged_null_ia32(char * ss,
unsigned stack_pointer_offset) {
#ifdef REFS_RUNTIME_OR_COMPRESSED
REFS_RUNTIME_SWITCH_IF
ss = mov(ss, eax_opnd, M_Base_Opnd(esp_reg, stack_pointer_offset));
ss = alu(ss, cmp_opc, eax_opnd, Imm_Opnd((I_32)VM_Global_State::loader_env->heap_base) );
ss = branch8(ss, Condition_NE, Imm_Opnd(size_8, 0)); // not null, branch around the mov 0
char *backpatch_address__not_managed_null = ((char *)ss) - 1;
ss = mov(ss, M_Base_Opnd(esp_reg, stack_pointer_offset), Imm_Opnd(0));
signed offset = (signed)ss - (signed)backpatch_address__not_managed_null - 1;
*backpatch_address__not_managed_null = (char)offset;
REFS_RUNTIME_SWITCH_ENDIF
#endif // REFS_RUNTIME_OR_COMPRESSED
return ss;
}
/* BEGIN COMPILE-ME STUBS */
static NativeCodePtr compile_get_compile_me_generic() {
static NativeCodePtr addr = NULL;
if (addr) {
return addr;
}
const int STUB_SIZE = 15 + m2n_push_m2n_size(false, 0) +
m2n_pop_m2n_size(false, 0, 0, 1);
char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE,
DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate);
addr = stub;
#ifndef NDEBUG
memset(stub, 0xcc /*int 3*/, STUB_SIZE);
#endif
// push m2n to the stack
stub = m2n_gen_push_m2n(stub, NULL, FRAME_COMPILATION, false, 0);
// ecx register should contain correct Mehod_Handle
stub = push(stub, ecx_opnd);
// compile the method
stub = call(stub, (char *)&compile_me);
// remove ecx from the stack
stub = pop(stub, ecx_opnd);
// pop m2n from the stack
stub = m2n_gen_pop_m2n(stub, false, 0, 0, 1);
// transfer control to the compiled code
stub = jump(stub, eax_opnd);
assert(stub - (char *)addr <= STUB_SIZE);
compile_add_dynamic_generated_code_chunk("compile_me_generic", false, addr, STUB_SIZE);
if (jvmti_should_report_event(JVMTI_EVENT_DYNAMIC_CODE_GENERATED)) {
jvmti_send_dynamic_code_generated_event("compile_me_generic", addr, STUB_SIZE);
}
DUMP_STUB(addr, "compileme_generic", stub - (char *)addr);
return addr;
}
NativeCodePtr compile_gen_compile_me(Method_Handle method) {
const int STUB_SIZE = 16;
#ifdef VM_STATS
++VM_Statistics::get_vm_stats().num_compileme_generated;
#endif
char * stub = (char *) method_get_class(method)->code_alloc(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CAA_Allocate);
NativeCodePtr addr = stub;
#ifndef NDEBUG
memset(stub, 0xcc /*int 3*/, STUB_SIZE);
#endif
#ifdef VM_STATS
stub = inc(stub, M_Base_Opnd(n_reg, (I_32)&VM_Statistics::get_vm_stats().num_compileme_used));
#endif
stub = mov(stub, ecx_opnd, Imm_Opnd((I_32)method));
stub = jump(stub, (char *)compile_get_compile_me_generic());
assert(stub - (char *)addr <= STUB_SIZE);
char* name;
const char * c = method->get_class()->get_name()->bytes;
const char * m = method->get_name()->bytes;
const char * d = method->get_descriptor()->bytes;
size_t sz = strlen(c) + strlen(m) + strlen(d) + 12;
name = (char*)STD_MALLOC(sz);
sprintf(name, "compileme.%s.%s%s", c, m, d);
compile_add_dynamic_generated_code_chunk(name, true, addr, STUB_SIZE);
if (jvmti_should_report_event(JVMTI_EVENT_DYNAMIC_CODE_GENERATED)) {
jvmti_send_dynamic_code_generated_event(name, addr, STUB_SIZE);
}
#ifndef NDEBUG
static unsigned done = 0;
// dump first 10 compileme stubs
if (dump_stubs && ++done <= 10) {
char * buf;
const char * c = method->get_class()->get_name()->bytes;
const char * m = method->get_name()->bytes;
const char * d = method->get_descriptor()->bytes;
size_t sz = strlen(c)+strlen(m)+strlen(d)+12;
buf = (char *)STD_MALLOC(sz);
sprintf(buf, "compileme.%s.%s%s", c, m, d);
assert(strlen(buf) < sz);
DUMP_STUB(addr, buf, stub - (char *)addr);
STD_FREE(buf);
}
#endif
return addr;
} //compile_gen_compile_me
/* END COMPILE-ME STUBS */
void gen_native_hashcode(Emitter_Handle h, Method *m);
unsigned native_hashcode_fastpath_size(Method *m);
void gen_native_system_currenttimemillis(Emitter_Handle h, Method *m);
unsigned native_getccurrenttime_fastpath_size(Method *m);
void gen_native_readinternal(Emitter_Handle h, Method *m);
unsigned native_readinternal_fastpath_size(Method *m);
void gen_native_newinstance(Emitter_Handle h, Method *m);
unsigned native_newinstance_fastpath_size(Method *m);
// ****** 20031009 above are additions to bring original on par with LIL
void gen_native_getclass_fastpath(Emitter_Handle h, Method *m);
unsigned native_getclass_fastpath_size(Method *m);
void gen_native_arraycopy_fastpath(Emitter_Handle h, Method *m);
unsigned native_arraycopy_fastpath_size(Method *m);
static Stub_Override_Entry _stub_override_entries_base[] = {
{"java/lang/VMSystem", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", gen_native_arraycopy_fastpath, native_arraycopy_fastpath_size},
{"java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", gen_native_arraycopy_fastpath, native_arraycopy_fastpath_size},
{"java/lang/Object", "getClass", "()Ljava/lang/Class;", gen_native_getclass_fastpath, native_getclass_fastpath_size},
// ****** 20031009 below are additions to bring baseline on par with LIL
{"java/lang/System", "currentTimeMillis", "()J", gen_native_system_currenttimemillis, native_getccurrenttime_fastpath_size},
{"java/io/FileInputStream", "readInternal", "(I[BII)I", gen_native_readinternal, native_readinternal_fastpath_size},
#ifndef PLATFORM_POSIX
// because of threading, this override will not work on Linux!
{"java/lang/Class", "newInstance", "()Ljava/lang/Object;", gen_native_newinstance, native_newinstance_fastpath_size},
#endif
{"java/lang/VMSystem", "identityHashCode", "(Ljava/lang/Object;)I", gen_native_hashcode, native_hashcode_fastpath_size}
};
Stub_Override_Entry *stub_override_entries = &(_stub_override_entries_base[0]);
int sizeof_stub_override_entries = sizeof(_stub_override_entries_base) / sizeof(_stub_override_entries_base[0]);