提交 b39c2e53 编写于 作者: S stefank

8003720: NPG: Method in interpreter stack frame can be deallocated

Summary: Pass down a closure during root scanning to keep the class of the method alive.
Reviewed-by: coleenp, jcoomes
上级 b66e5f23
......@@ -52,14 +52,22 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) {
PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
CLDToOopClosure mark_and_push_from_clds(&mark_and_push_closure, true);
CodeBlobToOopClosure mark_and_push_in_blobs(&mark_and_push_closure, /*do_marking=*/ true);
if (_java_thread != NULL)
_java_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
_java_thread->oops_do(
&mark_and_push_closure,
&mark_and_push_from_clds,
&mark_and_push_in_blobs);
if (_vm_thread != NULL)
_vm_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
_vm_thread->oops_do(
&mark_and_push_closure,
&mark_and_push_from_clds,
&mark_and_push_in_blobs);
// Do the real work
cm->follow_marking_stacks();
......@@ -89,7 +97,8 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
{
ResourceMark rm;
CodeBlobToOopClosure each_active_code_blob(&mark_and_push_closure, /*do_marking=*/ true);
Threads::oops_do(&mark_and_push_closure, &each_active_code_blob);
CLDToOopClosure mark_and_push_from_cld(&mark_and_push_closure);
Threads::oops_do(&mark_and_push_closure, &mark_and_push_from_cld, &each_active_code_blob);
}
break;
......
......@@ -495,8 +495,9 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
ParallelScavengeHeap::ParStrongRootsScope psrs;
Universe::oops_do(mark_and_push_closure());
JNIHandles::oops_do(mark_and_push_closure()); // Global (strong) JNI handles
CLDToOopClosure mark_and_push_from_cld(mark_and_push_closure());
CodeBlobToOopClosure each_active_code_blob(mark_and_push_closure(), /*do_marking=*/ true);
Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
Threads::oops_do(mark_and_push_closure(), &mark_and_push_from_cld, &each_active_code_blob);
ObjectSynchronizer::oops_do(mark_and_push_closure());
FlatProfiler::oops_do(mark_and_push_closure());
Management::oops_do(mark_and_push_closure());
......@@ -584,7 +585,8 @@ void PSMarkSweep::mark_sweep_phase3() {
// General strong roots.
Universe::oops_do(adjust_root_pointer_closure());
JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_root_pointer_closure(), NULL);
CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
FlatProfiler::oops_do(adjust_root_pointer_closure());
Management::oops_do(adjust_root_pointer_closure());
......
......@@ -2436,7 +2436,8 @@ void PSParallelCompact::adjust_roots() {
// General strong roots.
Universe::oops_do(adjust_root_pointer_closure());
JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_root_pointer_closure(), NULL);
CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
FlatProfiler::oops_do(adjust_root_pointer_closure());
Management::oops_do(adjust_root_pointer_closure());
......
......@@ -65,7 +65,8 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
case threads:
{
ResourceMark rm;
Threads::oops_do(&roots_closure, NULL);
CLDToOopClosure* cld_closure = NULL; // Not needed. All CLDs are already visited.
Threads::oops_do(&roots_closure, cld_closure, NULL);
}
break;
......@@ -120,13 +121,14 @@ void ThreadRootsTask::do_it(GCTaskManager* manager, uint which) {
PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which);
PSScavengeRootsClosure roots_closure(pm);
CLDToOopClosure* roots_from_clds = NULL; // Not needed. All CLDs are already visited.
CodeBlobToOopClosure roots_in_blobs(&roots_closure, /*do_marking=*/ true);
if (_java_thread != NULL)
_java_thread->oops_do(&roots_closure, &roots_in_blobs);
_java_thread->oops_do(&roots_closure, roots_from_clds, &roots_in_blobs);
if (_vm_thread != NULL)
_vm_thread->oops_do(&roots_closure, &roots_in_blobs);
_vm_thread->oops_do(&roots_closure, roots_from_clds, &roots_in_blobs);
// Do the real work
pm->drain_stacks(false);
......
......@@ -30,6 +30,10 @@ void KlassToOopClosure::do_klass(Klass* k) {
k->oops_do(_oop_closure);
}
void CLDToOopClosure::do_cld(ClassLoaderData* cld) {
cld->oops_do(_oop_closure, &_klass_closure, _must_claim_cld);
}
void ObjectToOopClosure::do_object(oop obj) {
obj->oop_iterate(_cl);
}
......
......@@ -135,6 +135,20 @@ class KlassToOopClosure : public KlassClosure {
virtual void do_klass(Klass* k);
};
class CLDToOopClosure {
OopClosure* _oop_closure;
KlassToOopClosure _klass_closure;
bool _must_claim_cld;
public:
CLDToOopClosure(OopClosure* oop_closure, bool must_claim_cld = true) :
_oop_closure(oop_closure),
_klass_closure(oop_closure),
_must_claim_cld(must_claim_cld) {}
void do_cld(ClassLoaderData* cld);
};
// ObjectClosure is used for iterating through an object space
class ObjectClosure : public Closure {
......
......@@ -154,10 +154,12 @@ void SharedHeap::process_strong_roots(bool activate_scope,
if (!_process_strong_tasks->is_task_claimed(SH_PS_JNIHandles_oops_do))
JNIHandles::oops_do(roots);
// All threads execute this; the individual threads are task groups.
CLDToOopClosure roots_from_clds(roots);
CLDToOopClosure* roots_from_clds_p = (is_scavenging ? NULL : &roots_from_clds);
if (ParallelGCThreads > 0) {
Threads::possibly_parallel_oops_do(roots, code_roots);
Threads::possibly_parallel_oops_do(roots, roots_from_clds_p ,code_roots);
} else {
Threads::oops_do(roots, code_roots);
Threads::oops_do(roots, roots_from_clds_p, code_roots);
}
if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do))
ObjectSynchronizer::oops_do(roots);
......
......@@ -721,7 +721,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
guarantee(false, "wrong number of expression stack elements during deopt");
}
VerifyOopClosure verify;
iframe->oops_interpreted_do(&verify, &rm, false);
iframe->oops_interpreted_do(&verify, NULL, &rm, false);
callee_size_of_parameters = mh->size_of_parameters();
callee_max_locals = mh->max_locals();
is_top_frame = false;
......
......@@ -879,7 +879,8 @@ oop* frame::interpreter_callee_receiver_addr(Symbol* signature) {
}
void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache) {
void frame::oops_interpreted_do(OopClosure* f, CLDToOopClosure* cld_f,
const RegisterMap* map, bool query_oop_map_cache) {
assert(is_interpreted_frame(), "Not an interpreted frame");
assert(map != NULL, "map must be set");
Thread *thread = Thread::current();
......@@ -906,6 +907,16 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
}
// process fixed part
if (cld_f != NULL) {
// The method pointer in the frame might be the only path to the method's
// klass, and the klass needs to be kept alive while executing. The GCs
// don't trace through method pointers, so typically in similar situations
// the mirror or the class loader of the klass are installed as a GC root.
// To minimze the overhead of doing that here, we ask the GC to pass down a
// closure that knows how to keep klasses alive given a ClassLoaderData.
cld_f->do_cld(m->method_holder()->class_loader_data());
}
#if !defined(PPC) || defined(ZERO)
if (m->is_native()) {
#ifdef CC_INTERP
......@@ -1108,7 +1119,7 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) {
}
void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
void frame::oops_do_internal(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
#ifndef PRODUCT
// simulate GC crash here to dump java thread in error report
if (CrashGCForDumpingJavaThread) {
......@@ -1117,7 +1128,7 @@ void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* ma
}
#endif
if (is_interpreted_frame()) {
oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
oops_interpreted_do(f, cld_f, map, use_interpreter_oop_map_cache);
} else if (is_entry_frame()) {
oops_entry_do(f, map);
} else if (CodeCache::contains(pc())) {
......@@ -1278,7 +1289,7 @@ void frame::verify(const RegisterMap* map) {
}
}
COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");)
oops_do_internal(&VerifyOopClosure::verify_oop, NULL, (RegisterMap*)map, false);
oops_do_internal(&VerifyOopClosure::verify_oop, NULL, NULL, (RegisterMap*)map, false);
}
......
......@@ -413,19 +413,19 @@ class frame VALUE_OBJ_CLASS_SPEC {
// Oops-do's
void oops_compiled_arguments_do(Symbol* signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f);
void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true);
void oops_interpreted_do(OopClosure* f, CLDToOopClosure* cld_f, const RegisterMap* map, bool query_oop_map_cache = true);
private:
void oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, OopClosure* f);
// Iteration of oops
void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache);
void oops_do_internal(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache);
void oops_entry_do(OopClosure* f, const RegisterMap* map);
void oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map);
int adjust_offset(Method* method, int index); // helper for above fn
public:
// Memory management
void oops_do(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cf, map, true); }
void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cld_f, cf, map, true); }
void nmethods_do(CodeBlobClosure* cf);
// RedefineClasses support for finding live interpreted methods on the stack
......
......@@ -826,7 +826,7 @@ bool Thread::claim_oops_do_par_case(int strong_roots_parity) {
return false;
}
void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
void Thread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
active_handles()->oops_do(f);
// Do oop for ThreadShadow
f->do_oop((oop*)&_pending_exception);
......@@ -2705,7 +2705,7 @@ public:
}
};
void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
void JavaThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
// Verify that the deferred card marks have been flushed.
assert(deferred_card_mark().is_empty(), "Should be empty during GC");
......@@ -2713,7 +2713,7 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// since there may be more than one thread using each ThreadProfiler.
// Traverse the GCHandles
Thread::oops_do(f, cf);
Thread::oops_do(f, cld_f, cf);
assert( (!has_last_Java_frame() && java_call_counter() == 0) ||
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
......@@ -2741,7 +2741,7 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// Traverse the execution stack
for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
fst.current()->oops_do(f, cf, fst.register_map());
fst.current()->oops_do(f, cld_f, cf, fst.register_map());
}
}
......@@ -2875,7 +2875,7 @@ static void frame_verify(frame* f, const RegisterMap *map) { f->verify(map); }
void JavaThread::verify() {
// Verify oops in the thread.
oops_do(&VerifyOopClosure::verify_oop, NULL);
oops_do(&VerifyOopClosure::verify_oop, NULL, NULL);
// Verify the stack frames.
frames_do(frame_verify);
......@@ -3125,7 +3125,7 @@ class PrintAndVerifyOopClosure: public OopClosure {
static void oops_print(frame* f, const RegisterMap *map) {
PrintAndVerifyOopClosure print;
f->print_value();
f->oops_do(&print, NULL, (RegisterMap*)map);
f->oops_do(&print, NULL, NULL, (RegisterMap*)map);
}
// Print our all the locations that contain oops and whether they are
......@@ -3227,8 +3227,8 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters)
#endif
}
void CompilerThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
JavaThread::oops_do(f, cf);
void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
JavaThread::oops_do(f, cld_f, cf);
if (_scanned_nmethod != NULL && cf != NULL) {
// Safepoints can occur when the sweeper is scanning an nmethod so
// process it here to make sure it isn't unloaded in the middle of
......@@ -4201,14 +4201,14 @@ bool Threads::includes(JavaThread* p) {
// uses the Threads_lock to gurantee this property. It also makes sure that
// all threads gets blocked when exiting or starting).
void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) {
void Threads::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
ALL_JAVA_THREADS(p) {
p->oops_do(f, cf);
p->oops_do(f, cld_f, cf);
}
VMThread::vm_thread()->oops_do(f, cf);
VMThread::vm_thread()->oops_do(f, cld_f, cf);
}
void Threads::possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf) {
void Threads::possibly_parallel_oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
// Introduce a mechanism allowing parallel threads to claim threads as
// root groups. Overhead should be small enough to use all the time,
// even in sequential code.
......@@ -4225,12 +4225,12 @@ void Threads::possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf) {
int cp = SharedHeap::heap()->strong_roots_parity();
ALL_JAVA_THREADS(p) {
if (p->claim_oops_do(is_par, cp)) {
p->oops_do(f, cf);
p->oops_do(f, cld_f, cf);
}
}
VMThread* vmt = VMThread::vm_thread();
if (vmt->claim_oops_do(is_par, cp)) {
vmt->oops_do(f, cf);
vmt->oops_do(f, cld_f, cf);
}
}
......
......@@ -480,8 +480,10 @@ class Thread: public ThreadShadow {
// GC support
// Apply "f->do_oop" to all root oops in "this".
// Apply "cld_f->do_cld" to CLDs that are otherwise not kept alive.
// Used by JavaThread::oops_do.
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
virtual void oops_do(OopClosure* f, CodeBlobClosure* cf);
virtual void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
// Handles the parallel case for the method below.
private:
......@@ -1405,7 +1407,7 @@ class JavaThread: public Thread {
void frames_do(void f(frame*, const RegisterMap*));
// Memory operations
void oops_do(OopClosure* f, CodeBlobClosure* cf);
void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
// Sweeper operations
void nmethods_do(CodeBlobClosure* cf);
......@@ -1825,7 +1827,7 @@ class CompilerThread : public JavaThread {
// GC support
// Apply "f->do_oop" to all root oops in "this".
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
void oops_do(OopClosure* f, CodeBlobClosure* cf);
void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
#ifndef PRODUCT
private:
......@@ -1892,9 +1894,9 @@ class Threads: AllStatic {
// Apply "f->do_oop" to all root oops in all threads.
// This version may only be called by sequential code.
static void oops_do(OopClosure* f, CodeBlobClosure* cf);
static void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
// This version may be called by sequential or parallel code.
static void possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf);
static void possibly_parallel_oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
// This creates a list of GCTasks, one per thread.
static void create_thread_roots_tasks(GCTaskQueue* q);
// This creates a list of GCTasks, one per thread, for marking objects.
......
......@@ -668,8 +668,8 @@ void VMThread::execute(VM_Operation* op) {
}
void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
Thread::oops_do(f, cf);
void VMThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
Thread::oops_do(f, cld_f, cf);
_vm_queue->oops_do(f);
}
......@@ -701,5 +701,5 @@ void VMOperationQueue::verify_queue(int prio) {
#endif
void VMThread::verify() {
oops_do(&VerifyOopClosure::verify_oop, NULL);
oops_do(&VerifyOopClosure::verify_oop, NULL, NULL);
}
......@@ -137,7 +137,7 @@ class VMThread: public NamedThread {
static VMThread* vm_thread() { return _vm_thread; }
// GC support
void oops_do(OopClosure* f, CodeBlobClosure* cf);
void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf);
// Debugging
void print_on(outputStream* st) const;
......
import com.sun.xml.internal.ws.org.objectweb.asm.*;
class Asmator {
static byte[] fixup(byte[] buf) throws java.io.IOException {
ClassReader cr = new ClassReader(buf);
ClassWriter cw = new ClassWriter(0) {
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
MethodVisitor mv = super.visitMethod(access,
name,
desc,
signature,
exceptions);
if (mv == null) return null;
if (name.equals("callme")) {
// make receiver go dead!
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, 0);
}
return mv;
}
};
cr.accept(cw, 0);
return cw.toByteArray();
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @bug 8003720
* @summary Method in interpreter stack frame can be deallocated
* @compile -XDignore.symbol.file Victim.java
* @run main/othervm -Xverify:all -Xint Test8003720
*/
// Attempts to make the JVM unload a class while still executing one of its methods.
public class Test8003720 {
final static String VICTIM_CLASS_NAME = "Victim";
final static boolean QUIET = true;
final static long DURATION = 30000;
public interface CallMe { void callme(); }
public static void main(String... av) throws Throwable {
newVictimClassLoader();
System.gc();
newVictimClass();
System.gc();
newVictimInstance();
System.gc();
((CallMe)newVictimInstance()).callme();
}
public static Object newVictimInstance() throws Throwable {
return newVictimClass().newInstance();
}
public static Class<?> newVictimClass() throws Throwable {
return Class.forName(VICTIM_CLASS_NAME, true, new VictimClassLoader());
}
public static ClassLoader newVictimClassLoader() throws Throwable {
return new VictimClassLoader();
}
public static void println(String line) {
if (!QUIET) {
System.out.println(line);
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
public class Victim implements Test8003720.CallMe {
public void callme() {
// note: Victim.this is dead here
Test8003720.println("executing in loader=" + Victim.class.getClassLoader());
long now = System.currentTimeMillis();
while ((System.currentTimeMillis() - now) < Test8003720.DURATION) {
long count = VictimClassLoader.counter++;
if (count % 1000000 == 0) System.gc();
if (count % 16180000 == 0) blurb();
new Object[1].clone();
}
}
static void blurb() {
Test8003720.println("count=" + VictimClassLoader.counter);
}
static {
blather();
}
static void blather() {
new java.util.ArrayList<Object>(1000000);
Class<Victim> c = Victim.class;
Test8003720.println("initializing " + c + "#" + System.identityHashCode(c) + " in " + c.getClassLoader());
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
public class VictimClassLoader extends ClassLoader {
public static long counter = 0;
private int which = (int) ++counter;
protected VictimClassLoader() {
super(VictimClassLoader.class.getClassLoader());
}
protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class c;
if (!name.endsWith("Victim")) {
c = super.loadClass(name, resolve);
return c;
}
c = findLoadedClass(name);
if (c != null) {
return c;
}
byte[] buf = readClassFile(name);
c = defineClass(name, buf, 0, buf.length);
resolveClass(c);
if (c.getClassLoader() != this) {
throw new AssertionError();
}
Test8003720.println("loaded " + c + "#" + System.identityHashCode(c) + " in " + c.getClassLoader());
return c;
}
static byte[] readClassFile(String name) {
try {
String rname = name.substring(name.lastIndexOf('.') + 1) + ".class";
java.net.URL url = VictimClassLoader.class.getResource(rname);
Test8003720.println("found " + rname + " = " + url);
java.net.URLConnection connection = url.openConnection();
int contentLength = connection.getContentLength();
byte[] buf = readFully(connection.getInputStream(), contentLength);
return Asmator.fixup(buf);
} catch (java.io.IOException ex) {
throw new Error(ex);
}
}
static byte[] readFully(java.io.InputStream in, int len) throws java.io.IOException {
// Warning here:
return sun.misc.IOUtils.readFully(in, len, true);
}
public void finalize() {
Test8003720.println("Goodbye from " + this);
}
public String toString() {
return "VictimClassLoader#" + which;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册