blob: 2513d6a3fd4684042c625c1c50d3ca485dfdff5c [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.core"
#include "cxxlog.h"
#ifndef USE_GC_STATIC
#include <apr_dso.h>
#include <apr_errno.h>
#include "dll_gc.h"
#include "open/gc.h"
#include "open/vm_util.h"
#include "environment.h"
#include "properties.h"
/* $$$ GMJ #include "object_generic.h" */
#include "object.h"
static void default_gc_write_barrier(Managed_Object_Handle);
static void default_gc_pin_object(Managed_Object_Handle*);
static void default_gc_unpin_object(Managed_Object_Handle*);
static I_32 default_gc_get_hashcode(Managed_Object_Handle);
static Managed_Object_Handle default_gc_get_next_live_object(void*);
static void default_gc_iterate_heap();
static void default_gc_finalize_on_exit();
static void default_gc_set_mutator_block_flag();
static Boolean default_gc_clear_mutator_block_flag();
static int64 default_gc_max_memory();
static void default_gc_wrapup();
static Boolean default_gc_requires_barriers();
static Boolean default_gc_supports_compressed_references();
static void default_gc_heap_slot_write_ref(Managed_Object_Handle p_base_of_object_with_slot,
Managed_Object_Handle *p_slot,
Managed_Object_Handle value);
static void default_gc_heap_slot_write_ref_compressed(Managed_Object_Handle p_base_of_object_with_slot,
U_32 *p_slot,
Managed_Object_Handle value);
static void default_gc_heap_write_global_slot(Managed_Object_Handle *p_slot,
Managed_Object_Handle value);
static void default_gc_heap_write_global_slot_compressed(U_32 *p_slot,
Managed_Object_Handle value);
static void default_gc_heap_wrote_object(Managed_Object_Handle p_base_of_object_just_written);
static void default_gc_add_compressed_root_set_entry(U_32 *ref);
static void default_gc_add_root_set_entry_managed_pointer(void **slot,
Boolean is_pinned);
static void *default_gc_heap_base_address();
static void *default_gc_heap_ceiling_address();
static void default_gc_test_safepoint();
/* $$$ GMJ static I_32 default_gc_get_hashcode(Managed_Object_Handle); */
static Boolean default_gc_supports_frontier_allocation(unsigned *offset_of_current, unsigned *offset_of_limit);
static void default_gc_add_weak_root_set_entry(
Managed_Object_Handle*, Boolean, Boolean);
static Boolean default_gc_supports_class_unloading();
Boolean (*gc_supports_compressed_references)() = 0;
void (*gc_add_root_set_entry)(Managed_Object_Handle *ref, Boolean is_pinned) = 0;
void (*gc_add_weak_root_set_entry)(Managed_Object_Handle *ref, Boolean is_pinned,Boolean is_short_weak) = 0;
void (*gc_add_compressed_root_set_entry)(U_32 *ref, Boolean is_pinned) = 0;
void (*gc_add_root_set_entry_interior_pointer)(void **slot, int offset, Boolean is_pinned) = 0;
void (*gc_add_root_set_entry_managed_pointer)(void **slot, Boolean is_pinned) = 0;
void (*gc_class_prepared)(Class_Handle ch, VTable_Handle vth) = 0;
int64 (*gc_get_collection_count)() = 0;
int64 (*gc_get_collection_time)() = 0;
void (*gc_force_gc)() = 0;
int64 (*gc_free_memory)() = 0;
void (*gc_heap_slot_write_ref)(Managed_Object_Handle p_base_of_object_with_slot,
Managed_Object_Handle *p_slot,
Managed_Object_Handle value) = 0;
void (*gc_heap_slot_write_ref_compressed)(Managed_Object_Handle p_base_of_object_with_slot,
U_32 *p_slot,
Managed_Object_Handle value) = 0;
void (*gc_heap_write_global_slot)(Managed_Object_Handle *p_slot,
Managed_Object_Handle value) = 0;
void (*gc_heap_write_global_slot_compressed)(U_32 *p_slot,
Managed_Object_Handle value) = 0;
void (*gc_heap_write_ref)(Managed_Object_Handle p_base_of_object_with_slot,
unsigned offset,
Managed_Object_Handle value) = 0;
Boolean (*gc_heap_copy_object_array)(Managed_Object_Handle src_array, unsigned int src_start, Managed_Object_Handle dst_array, unsigned int dst_start, unsigned int length)=0;
void (*gc_heap_wrote_object)(Managed_Object_Handle p_base_of_object_just_written) = 0;
int (*gc_init)() = 0;
Boolean (*gc_is_object_pinned)(Managed_Object_Handle obj) = 0;
Managed_Object_Handle (*gc_alloc)(unsigned size,
Allocation_Handle p_vtable,
void *thread_pointer) = 0;
Managed_Object_Handle (*gc_alloc_fast)(unsigned size,
Allocation_Handle p_vtable,
void *thread_pointer) = 0;
void (*gc_vm_initialized)() = 0;
Boolean (*gc_requires_barriers)() = default_gc_requires_barriers;
void (*gc_thread_init)(void *gc_information) = 0;
void (*gc_thread_kill)(void *gc_information) = 0;
unsigned int (*gc_time_since_last_gc)() = 0;
int64 (*gc_total_memory)() = 0;
int64 (*gc_max_memory)() = 0;
void * (*gc_heap_base_address)() = 0;
void * (*gc_heap_ceiling_address)() = 0;
void (*gc_test_safepoint)() = 0;
void (*gc_wrapup)() = default_gc_wrapup;
void (*gc_write_barrier)(Managed_Object_Handle p_base_of_obj_with_slot) = 0;
Boolean (*gc_supports_frontier_allocation)(unsigned *offset_of_current, unsigned *offset_of_limit) = 0;
void (*gc_pin_object)(Managed_Object_Handle* p_object) = 0;
void (*gc_unpin_object)(Managed_Object_Handle* p_object) = 0;
I_32 (*gc_get_hashcode)(Managed_Object_Handle obj) = 0;
Managed_Object_Handle (*gc_get_next_live_object)(void *iterator) = 0;
I_32 (*gc_get_hashcode0) (Managed_Object_Handle p_object) = 0;
void (*gc_iterate_heap)() = 0;
void (*gc_finalize_on_exit)() = 0;
void (*gc_set_mutator_block_flag)() = 0;
Boolean (*gc_clear_mutator_block_flag)() = 0;
Boolean (*gc_supports_class_unloading)() = 0;
static apr_dso_handle_sym_t getFunction(apr_dso_handle_t *handle, const char *name, const char *dllName)
{
apr_dso_handle_sym_t fn;
if (apr_dso_sym(&fn, handle, name) != APR_SUCCESS) {
LWARN(6, "Couldn't load GC dll {0}: missing entry point {1}" << dllName << name);
return 0;
}
return fn;
}
static apr_dso_handle_sym_t getFunctionOptional(apr_dso_handle_t *handle,
const char *name,
const char * UNREF dllName,
apr_dso_handle_sym_t default_func)
{
apr_dso_handle_sym_t fn;
if (apr_dso_sym(&fn, handle, name) != APR_SUCCESS) {
return default_func;
} else {
return fn;
}
} //getFunctionOptional
static apr_pool_t *pool;
void vm_add_gc(const char *dllName)
{
if(!pool) {
apr_pool_create(&pool, 0);
}
apr_dso_handle_t *handle;
if (apr_dso_load(&handle, dllName, pool) != APR_SUCCESS)
{
LWARN(7, "Failure to open GC dll {0}" << dllName);
return;
}
gc_supports_compressed_references = (Boolean (*)())
getFunctionOptional(handle,
"gc_supports_compressed_references",
dllName,
(apr_dso_handle_sym_t)default_gc_supports_compressed_references);
gc_add_root_set_entry = (void (*)(Managed_Object_Handle *ref, Boolean is_pinned))
getFunction(handle, "gc_add_root_set_entry", dllName);
gc_add_weak_root_set_entry = (void (*)(Managed_Object_Handle *, Boolean, Boolean))
getFunctionOptional(handle, "gc_add_weak_root_set_entry", dllName,
(apr_dso_handle_sym_t) default_gc_add_weak_root_set_entry);
gc_add_compressed_root_set_entry = (void (*)(U_32 *ref, Boolean is_pinned))
getFunctionOptional(handle,
"gc_add_compressed_root_set_entry",
dllName,
(apr_dso_handle_sym_t)default_gc_add_compressed_root_set_entry);
gc_add_root_set_entry_interior_pointer = (void (*)(void **slot, int offset, Boolean is_pinned)) getFunction(handle, "gc_add_root_set_entry_interior_pointer", dllName);
gc_add_root_set_entry_managed_pointer = (void (*)(void **slot, Boolean is_pinned))
getFunctionOptional(handle,
"gc_add_root_set_entry_managed_pointer",
dllName,
(apr_dso_handle_sym_t)default_gc_add_root_set_entry_managed_pointer);
gc_class_prepared = (void (*)(Class_Handle ch, VTable_Handle vth)) getFunction(handle, "gc_class_prepared", dllName);
gc_get_collection_count = (int64 (*)()) getFunction(handle, "gc_get_collection_count", dllName);
gc_get_collection_time = (int64 (*)()) getFunction(handle, "gc_get_collection_time", dllName);
gc_force_gc = (void (*)()) getFunction(handle, "gc_force_gc", dllName);
gc_free_memory = (int64 (*)()) getFunction(handle, "gc_free_memory", dllName);
gc_heap_slot_write_ref = (void (*)(Managed_Object_Handle p_base_of_object_with_slot,
Managed_Object_Handle *p_slot,
Managed_Object_Handle value))
getFunctionOptional(handle,
"gc_heap_slot_write_ref",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_slot_write_ref);
gc_heap_slot_write_ref_compressed = (void (*)(Managed_Object_Handle p_base_of_object_with_slot,
U_32 *p_slot,
Managed_Object_Handle value))
getFunctionOptional(handle,
"gc_heap_slot_write_ref_compressed",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_slot_write_ref_compressed); ;
gc_heap_write_global_slot = (void (*)(Managed_Object_Handle *p_slot,
Managed_Object_Handle value))
getFunctionOptional(handle,
"gc_heap_write_global_slot",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_write_global_slot);
gc_heap_write_global_slot_compressed = (void (*)(U_32 *p_slot,
Managed_Object_Handle value))
getFunctionOptional(handle,
"gc_heap_write_global_slot_compressed",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_write_global_slot_compressed);
gc_heap_copy_object_array = (Boolean (*)(Managed_Object_Handle src_array, unsigned int src_start, Managed_Object_Handle dst_array, unsigned int dst_start, unsigned int length))
getFunctionOptional(handle,
"gc_heap_copy_object_array",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_wrote_object);
gc_heap_wrote_object = (void (*)(Managed_Object_Handle p_base_of_object_just_written))
getFunctionOptional(handle,
"gc_heap_wrote_object",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_wrote_object);
gc_init = (int (*)()) getFunction(handle, "gc_init", dllName);
gc_is_object_pinned = (Boolean (*)(Managed_Object_Handle obj)) getFunction(handle, "gc_is_object_pinned", dllName);
gc_alloc = (Managed_Object_Handle (*)(unsigned size,
Allocation_Handle type,
void *thread_pointer))
getFunctionOptional(handle, "gc_alloc", dllName, NULL);
gc_alloc_fast = (Managed_Object_Handle (*)(unsigned size,
Allocation_Handle type,
void *thread_pointer))
getFunctionOptional(handle, "gc_alloc_fast", dllName, NULL);
gc_pin_object = (void (*)(Managed_Object_Handle*))
getFunctionOptional(handle, "gc_pin_object", dllName,
(apr_dso_handle_sym_t)default_gc_pin_object);
gc_unpin_object = (void (*)(Managed_Object_Handle*))
getFunctionOptional(handle, "gc_unpin_object", dllName,
(apr_dso_handle_sym_t)default_gc_unpin_object);
gc_get_hashcode = (I_32 (*)(Managed_Object_Handle))
getFunctionOptional(handle, "gc_get_hashcode", dllName,
(apr_dso_handle_sym_t)default_gc_get_hashcode);
gc_get_next_live_object = (Managed_Object_Handle (*)(void*))
getFunctionOptional(handle, "gc_get_next_live_object", dllName,
(apr_dso_handle_sym_t)default_gc_get_next_live_object);
gc_iterate_heap = (void (*)())
getFunctionOptional(handle, "gc_iterate_heap", dllName,
(apr_dso_handle_sym_t)default_gc_iterate_heap);
gc_finalize_on_exit = (void (*)())
getFunctionOptional(handle, "gc_finalize_on_exit", dllName,
(apr_dso_handle_sym_t)default_gc_finalize_on_exit);
gc_set_mutator_block_flag = (void (*)())
getFunctionOptional(handle, "gc_set_mutator_block_flag", dllName,
(apr_dso_handle_sym_t)default_gc_set_mutator_block_flag);
gc_clear_mutator_block_flag = (Boolean (*)())
getFunctionOptional(handle, "gc_clear_mutator_block_flag", dllName,
(apr_dso_handle_sym_t)default_gc_clear_mutator_block_flag);
gc_get_hashcode0 = (I_32 (*)(Managed_Object_Handle))
getFunctionOptional(handle, "gc_get_hashcode", dllName, (apr_dso_handle_sym_t) default_gc_get_hashcode);
gc_vm_initialized = (void (*)()) getFunction(handle, "gc_vm_initialized", dllName);
gc_requires_barriers = (Boolean (*)())
getFunctionOptional(handle, "gc_requires_barriers", dllName,
(apr_dso_handle_sym_t)default_gc_requires_barriers);
gc_thread_init = (void (*)(void *gc_information)) getFunction(handle, "gc_thread_init", dllName);
gc_thread_kill = (void (*)(void *gc_information)) getFunction(handle, "gc_thread_kill", dllName);
gc_time_since_last_gc = (unsigned int (*)()) getFunction(handle, "gc_time_since_last_gc", dllName);
gc_total_memory = (int64 (*)()) getFunction(handle, "gc_total_memory", dllName);
gc_max_memory = (int64 (*)())
getFunctionOptional(handle, "gc_max_memory", dllName,
(apr_dso_handle_sym_t)default_gc_max_memory);
gc_heap_base_address = (void * (*)())
getFunctionOptional(handle,
"gc_heap_base_address",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_base_address);
gc_heap_ceiling_address = (void * (*)())
getFunctionOptional(handle,
"gc_heap_ceiling_address",
dllName,
(apr_dso_handle_sym_t)default_gc_heap_ceiling_address);
gc_supports_frontier_allocation = (Boolean (*)(unsigned *offset_of_current, unsigned *offset_of_limit))
getFunctionOptional(handle,
"gc_supports_frontier_allocation",
dllName,
(apr_dso_handle_sym_t)default_gc_supports_frontier_allocation);
gc_wrapup = (void (*)()) getFunction(handle, "gc_wrapup", dllName);
gc_write_barrier = (void (*)(Managed_Object_Handle p_base_of_obj_with_slot))
getFunctionOptional(handle, "gc_write_barrier", dllName,
(apr_dso_handle_sym_t)default_gc_write_barrier);
gc_test_safepoint = (void (*)()) getFunctionOptional(handle, "gc_test_safepoint", dllName, (apr_dso_handle_sym_t)default_gc_test_safepoint);
gc_supports_class_unloading = (Boolean (*)())
getFunctionOptional(handle,
"gc_supports_class_unloading",
dllName,
(apr_dso_handle_sym_t)default_gc_supports_class_unloading);
} //vm_add_gc
bool vm_is_a_gc_dll(const char *dll_filename)
{
if (!pool) {
apr_pool_create(&pool, 0);
}
apr_dso_handle_t *handle;
bool result = false;
apr_status_t stat;
if ((stat = apr_dso_load(&handle, dll_filename, pool)) == APR_SUCCESS)
{
apr_dso_handle_sym_t tmp;
if (apr_dso_sym(&tmp, handle, "gc_init") == APR_SUCCESS) {
result = true;
}
apr_dso_unload(handle);
} else {
char buf[1024];
apr_dso_error(handle, buf, 1024);
LWARN(8, "Loading error {0}" << buf);
//apr_strerror(stat, buf, 1024);
//printf("error %s, is %d, expected %d\n", buf, stat, APR_SUCCESS);
}
return result;
} //vm_is_a_gc_dll
static Boolean default_gc_requires_barriers()
{
return FALSE;
} //default_gc_requires_barriers
static void default_gc_wrapup()
{
} //default_gc_wrapup
static Boolean default_gc_supports_compressed_references()
{
return FALSE;
} //default_gc_supports_compressed_references
// This is the default implementation of the GC interface gc_heap_slot_write_ref() function for use by the VM
// when no other implementation is provided by a GC.
static void default_gc_heap_slot_write_ref(Managed_Object_Handle UNREF p_base_of_object_with_slot,
Managed_Object_Handle *p_slot,
Managed_Object_Handle value)
{
assert(!REFS_IS_COMPRESSED_MODE);
assert(p_slot != NULL);
*p_slot = value;
} //default_gc_heap_slot_write_ref
static void default_gc_heap_slot_write_ref_compressed(Managed_Object_Handle UNREF p_base_of_object_with_slot,
U_32 *p_slot,
Managed_Object_Handle value)
{
// p_slot is the address of a 32 bit slot holding the offset of a referenced object in the heap.
// That slot is being updated, so store the heap offset of value's object. If value is NULL, store a 0 offset.
assert(REFS_IS_COMPRESSED_MODE);
#ifndef REFS_USE_UNCOMPRESSED
assert(p_slot != NULL);
if (value != NULL) {
COMPRESSED_REFERENCE value_offset = compress_reference((ManagedObject *)value);
*p_slot = value_offset;
} else {
*p_slot = 0;
}
#endif // REFS_USE_UNCOMPRESSED
} //default_gc_heap_slot_write_ref_compressed
static void default_gc_heap_write_global_slot(Managed_Object_Handle *p_slot,
Managed_Object_Handle value)
{
assert(p_slot != NULL);
*p_slot = value;
} //default_gc_heap_write_global_slot
static void default_gc_heap_write_global_slot_compressed(U_32 *p_slot,
Managed_Object_Handle value)
{
// p_slot is the address of a 32 bit global variable holding the offset of a referenced object in the heap.
// That slot is being updated, so store the heap offset of value's object. If value is NULL, store a 0 offset.
assert(REFS_IS_COMPRESSED_MODE);
#ifndef REFS_USE_UNCOMPRESSED
assert(p_slot != NULL);
if (value != NULL) {
COMPRESSED_REFERENCE value_offset = compress_reference((ManagedObject *)value);
*p_slot = value_offset;
} else {
*p_slot = 0;
}
#endif // REFS_USE_UNCOMPRESSED
} //default_gc_heap_write_global_slot_compressed
static void default_gc_heap_wrote_object(Managed_Object_Handle UNREF p_base_of_object_just_written)
{
} //default_gc_heap_wrote_object
static void default_gc_add_compressed_root_set_entry(U_32 * UNREF ref)
{
LDIE(7, "Fatal GC error: compressed references are not supported.");
} //default_gc_add_compressed_root_set_entry
static void default_gc_add_root_set_entry_managed_pointer(void ** UNREF slot,
Boolean UNREF is_pinned)
{
LDIE(8,"Fatal GC error: managed pointers are not supported.");
} //default_gc_add_root_set_entry_managed_pointer
static void *default_gc_heap_base_address()
{
return (void *)0;
} //default_gc_heap_base_address
static Boolean default_gc_supports_frontier_allocation(unsigned * UNREF offset_of_current, unsigned * UNREF offset_of_limit)
{
return FALSE;
}
static I_32 default_gc_get_hashcode(Managed_Object_Handle obj) {
return default_hashcode(obj);
}
static void *default_gc_heap_ceiling_address()
{
#ifdef POINTER64
return (void *)0xffffFFFFffffFFFF;
#else // !POINTER64
return (void *)0xffffFFFF;
#endif // !POINTER64
} //default_gc_heap_ceiling_address
static void default_gc_test_safepoint()
{
// Do nothing.
} // default_gc_test_safepoint
#define WARN_ONCE(message_number, messagedef_and_params) \
{ \
static bool warning = true; \
if (warning) { \
LWARN(message_number, messagedef_and_params);\
warning = false; \
} \
}
static void default_gc_pin_object(Managed_Object_Handle*)
{
WARN_ONCE(9, "The GC did not provide {0}" << "gc_pin_object()");
}
static void default_gc_unpin_object(Managed_Object_Handle*)
{
WARN_ONCE(9, "The GC did not provide {0}" << "gc_unpin_object()");
}
/* $$$ GMJ
static I_32 default_gc_get_hashcode(Managed_Object_Handle obj)
{
return default_hashcode((ManagedObject*) obj);
}
*/
static Managed_Object_Handle default_gc_get_next_live_object(void*)
{
WARN_ONCE(10, "The GC did not provide live object iterator");
return NULL;
}
static void default_gc_iterate_heap()
{
WARN_ONCE(11, "The GC did not provide heap iteration");
}
static void default_gc_finalize_on_exit()
{
WARN_ONCE(12, "The GC did not provide finalization on exit");
}
static void default_gc_set_mutator_block_flag()
{
WARN_ONCE(43, "The GC did not provide set mutator block flag");
}
static Boolean default_gc_clear_mutator_block_flag()
{
WARN_ONCE(44, "The GC did not provide clear mutator block flag");
return FALSE;
}
static int64 default_gc_max_memory()
{
WARN_ONCE(9, "The GC did not provide {0}" << "gc_max_memory()");
return 0x7fffFFFFl;
}
static void default_gc_write_barrier(Managed_Object_Handle)
{
}
static void default_gc_add_weak_root_set_entry(
Managed_Object_Handle* root, Boolean pinned, Boolean is_short)
{
WARN_ONCE(9, "The GC did not provide {0}" << "gc_add_weak_root_set_entry()");
// default to strong reference semantics
gc_add_root_set_entry(root, pinned);
}
static Boolean default_gc_supports_class_unloading()
{
return TRUE;
} //default_gc_supports_class_unloading
#endif // !USE_GC_STATIC