blob: 42afefde7044d156ba1d15fe4a20ea85f5c457be [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.
*/
/*
* Trace the java heap
*/
#include "cxxlog.h"
#include "open/gc.h"
#include "open/vm_field_access.h"
#include "open/vm_class_manipulation.h"
#include "slot.h"
// VM internal headers
#include "vm_arrays.h"
// private module headers
#include "jvmti_heap.h"
#include "jvmti_roots.h"
#include "jvmti_tags.h"
#include "jvmti_trace.h"
static void ti_trace_reference(TIEnv *ti_env,
ManagedObject* referrer,
ManagedObject* obj,
jvmtiObjectReferenceKind reference_kind,
jint referrer_index)
{
TIIterationState *state = ti_env->iteration_state;
// do nothing if the user requested abort termination
if (state->abort) return;
jlong class_tag = ti_get_object_class_tag(ti_env, obj);
jlong size = ti_get_object_size(ti_env, obj);
tag_pair** tp = ti_get_object_tptr(obj);
jlong tag = (*tp != NULL ? (*tp)->tag : 0);
jlong referrer_tag = ti_get_object_tag(ti_env, referrer);
void *user_data = state->user_data;
assert(state->object_ref_callback);
jvmtiIterationControl r = state->object_ref_callback(reference_kind,
class_tag, size, &tag, referrer_tag,
referrer_index, user_data);
ti_env->tags->update(obj, tag, tp);
if (JVMTI_ITERATION_ABORT == r) {
state->abort = true;
}
if (r != JVMTI_ITERATION_CONTINUE) return;
if (ti_mark_object(obj, state)) {
TRACE2("ti.trace", "marked " << (void*)obj
<< " from " << (void*)referrer);
state->markstack->push(obj);
}
}
static void ti_trace_object(TIEnv *ti_env, ManagedObject* referrer)
{
TIIterationState* state = ti_env->iteration_state;
state->objects += 1;
state->bytes += ti_get_object_size(ti_env, referrer);
TRACE2("ti.trace", "tracing object " << (void*)referrer);
Class* ch = ((ManagedObject*)referrer)->vt()->clss;
if (ch->is_array()) {
if (class_is_non_ref_array(ch)) return;
// trace reference array
int len = get_vector_length(referrer);
int i;
for (i = 0; i < len; i++) {
Slot slot(get_vector_element_address_ref(referrer, i));
if (slot.is_null()) continue;
ti_trace_reference(
ti_env, referrer,
(ManagedObject*) slot.dereference(),
JVMTI_REFERENCE_ARRAY_ELEMENT, i);
}
} else {
// trace object fields
unsigned num_fields = class_num_instance_fields_recursive(ch);
unsigned i;
for (i = 0; i < num_fields; i++) {
Field_Handle fh = class_get_instance_field_recursive(ch, i);
if(field_is_enumerable_reference(fh)){
int offset = field_get_offset(fh);
Slot slot((void*)((UDATA)referrer + offset));
if (slot.is_null()) continue;
ti_trace_reference(
ti_env, referrer,
(ManagedObject*) slot.dereference(),
JVMTI_REFERENCE_FIELD, i);
}
}
}
}
void ti_trace_heap(TIEnv* ti_env)
{
TIIterationState *state = ti_env->iteration_state;
state->objects = 0;
state->bytes = 0;
while (!state->markstack->empty() && !state->abort) {
ManagedObject *obj = state->markstack->top();
state->markstack->pop();
ti_trace_object(ti_env, obj);
}
INFO2("ti.trace", "traced " << state->objects << " live objects, "
<< state->bytes << " live bytes");
}
bool ti_mark_object(Managed_Object_Handle obj, TIIterationState *state)
{
assert((UDATA)obj < (UDATA)VM_Global_State::loader_env->heap_end);
assert((UDATA)obj >= (UDATA)VM_Global_State::loader_env->heap_base);
UDATA offset = (UDATA)obj - (UDATA)VM_Global_State::loader_env->heap_base;
UDATA bitnum = offset / GC_OBJECT_ALIGNMENT;
UDATA index = bitnum / 8;
unsigned mask = 1 << (bitnum % 8);
assert(index < state->markbits_size);
bool unmarked = ((state->markbits[index] & mask) == 0);
state->markbits[index] = (state->markbits[index] | mask);
return unmarked;
}