ffi.h.in (ffi_closure_alloc, [...]): New.

libffi/ChangeLog:
* include/ffi.h.in (ffi_closure_alloc, ffi_closure_free): New.
(ffi_prep_closure_loc): New.
(ffi_prep_raw_closure_loc): New.
(ffi_prep_java_raw_closure_loc): New.
* src/closures.c: New file.
* src/dlmalloc.c [FFI_MMAP_EXEC_WRIT] (struct malloc_segment):
Replace sflags with exec_offset.
[FFI_MMAP_EXEC_WRIT] (mmap_exec_offset, add_segment_exec_offset,
sub_segment_exec_offset): New macros.
(get_segment_flags, set_segment_flags, check_segment_merge): New
macros.
(is_mmapped_segment, is_extern_segment): Use get_segment_flags.
(add_segment, sys_alloc, create_mspace, create_mspace_with_base,
destroy_mspace): Use new macros.
(sys_alloc): Silence warning.
* Makefile.am (libffi_la_SOURCES): Add src/closures.c.
* Makefile.in: Rebuilt.
* src/prep_cif [FFI_CLOSURES] (ffi_prep_closure): Implement in
terms of ffi_prep_closure_loc.
* src/raw_api.c (ffi_prep_raw_closure_loc): Renamed and adjusted
from...
(ffi_prep_raw_closure): ... this.  Re-implement in terms of the
renamed version.
* src/java_raw_api (ffi_prep_java_raw_closure_loc): Renamed and
adjusted from...
(ffi_prep_java_raw_closure): ... this.  Re-implement in terms of
the renamed version.
* src/alpha/ffi.c (ffi_prep_closure_loc): Renamed from
(ffi_prep_closure): ... this.
* src/pa/ffi.c: Likewise.
* src/cris/ffi.c: Likewise.  Adjust.
* src/frv/ffi.c: Likewise.
* src/ia64/ffi.c: Likewise.
* src/mips/ffi.c: Likewise.
* src/powerpc/ffi_darwin.c: Likewise.
* src/s390/ffi.c: Likewise.
* src/sh/ffi.c: Likewise.
* src/sh64/ffi.c: Likewise.
* src/sparc/ffi.c: Likewise.
* src/x86/ffi64.c: Likewise.
* src/x86/ffi.c: Likewise.
(FFI_INIT_TRAMPOLINE): Adjust.
(ffi_prep_raw_closure_loc): Renamed and adjusted from...
(ffi_prep_raw_closure): ... this.
* src/powerpc/ffi.c (ffi_prep_closure_loc): Renamed from
(ffi_prep_closure): ... this.
(flush_icache): Adjust.
boehm-gc/ChangeLog:
* include/gc.h (GC_REGISTER_FINALIZER_UNREACHABLE): New.
(GC_register_finalizer_unreachable): Declare.
(GC_debug_register_finalizer_unreachable): Declare.
* finalize.c (GC_unreachable_finalize_mark_proc): New.
(GC_register_finalizer_unreachable): New.
(GC_finalize): Handle it.
* dbg_mlc.c (GC_debug_register_finalizer_unreachable): New.
(GC_debug_register_finalizer_no_order): Fix whitespace.
libjava/ChangeLog:
* include/jvm.h (_Jv_ClosureListFinalizer): New.
(_Jv_Linker::create_error_method): Adjust.
* boehm.cc (_Jv_ClosureListFinalizer): New.
* nogc.cc (_Jv_ClosureListFinalizer): New.
* java/lang/Class.h (class _Jv_ClosureList): New.
(class java::lang::Class): Declare it as friend.
* java/lang/natClass.cc (_Jv_ClosureList::releaseClosures): New.
(_Jv_ClosureList::registerClousure): New.
* include/execution.h (_Jv_ExecutionEngine): Add get_closure_list.
(_Jv_CompiledEngine::do_get_closure_list): New.
(_Jv_CompiledEngine::_Jv_CompiledEngine): Use it.
(_Jv_IndirectCompiledClass): Add closures.
(_Jv_IndirectCompiledEngine::get_aux_info): New.
(_Jv_IndirectCompiledEngine::do_allocate_field_initializers): Use
it.
(_Jv_IndirectCompiledEngine::do_get_closure_list): New.
(_Jv_IndirectCompiledEngine::_Jv_IndirectCompiledEngine): Use it.
(_Jv_InterpreterEngine::do_get_closure_list): Declare.
(_Jv_InterpreterEngine::_Jv_InterpreterEngine): Use it.
* interpret.cc (FFI_PREP_RAW_CLOSURE): Use _loc variants.
(node_closure): Add closure list.
(_Jv_InterpMethod::ncode): Add jclass argument.  Use
ffi_closure_alloc and the separate code pointer.  Register the
closure for finalization.
(_Jv_JNIMethod::ncode): Likewise.
(_Jv_InterpreterEngine::do_create_ncode): Pass klass to ncode.
(_Jv_InterpreterEngine::do_get_closure_list): New.
* include/java-interp.h (_Jv_InterpMethod::ncode): Adjust.
(_Jv_InterpClass): Add closures field.
(_Jv_JNIMethod::ncode): Adjust.
* defineclass.cc (_Jv_ClassReader::handleCodeAttribute): Adjust.
(_Jv_ClassReader::handleMethodsEnd): Likewise.
* link.cc (struct method_closure): Add closure list.
(_Jv_Linker::create_error_method): Add jclass argument.  Use
ffi_closure_alloc and the separate code pointer.  Register the
closure for finalization.
(_Jv_Linker::link_symbol_table): Remove outdated comment about
sharing of otable and atable.  Adjust.
* java/lang/reflect/natVMProxy.cc (ncode_closure): Add closure
list.
(ncode): Add jclass argument.  Use ffi_closure_alloc and the
separate code pointer.  Register the closure for finalization.
(java::lang::reflect::VMProxy::generateProxyClass): Adjust.
* testsuite/libjava.jar/TestClosureGC.java: New.
* testsuite/libjava.jar/TestClosureGC.out: New.
* testsuite/libjava.jar/TestClosureGC.xfail: New.
* testsuite/libjava.jar/TestClosureGC.jar: New.

From-SVN: r122652
This commit is contained in:
Alexandre Oliva 2007-03-07 07:27:25 +00:00 committed by Alexandre Oliva
parent dd77833100
commit 18fa3240db
43 changed files with 1325 additions and 198 deletions

View File

@ -1,3 +1,14 @@
2007-03-07 Alexandre Oliva <aoliva@redhat.com>
* include/gc.h (GC_REGISTER_FINALIZER_UNREACHABLE): New.
(GC_register_finalizer_unreachable): Declare.
(GC_debug_register_finalizer_unreachable): Declare.
* finalize.c (GC_unreachable_finalize_mark_proc): New.
(GC_register_finalizer_unreachable): New.
(GC_finalize): Handle it.
* dbg_mlc.c (GC_debug_register_finalizer_unreachable): New.
(GC_debug_register_finalizer_no_order): Fix whitespace.
2007-03-01 Brooks Moses <brooks.moses@codesourcery.com>
* Makefile.am: Add dummy install-pdf target.

View File

@ -3,6 +3,7 @@
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1997 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2007 Free Software Foundation, Inc
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -1118,8 +1119,8 @@ GC_PTR *ocd;
if (0 == base) return;
if ((ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
obj);
"GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
@ -1129,7 +1130,41 @@ GC_PTR *ocd;
&my_old_cd);
}
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
}
}
# ifdef __STDC__
void GC_debug_register_finalizer_unreachable
(GC_PTR obj, GC_finalization_proc fn,
GC_PTR cd, GC_finalization_proc *ofn,
GC_PTR *ocd)
# else
void GC_debug_register_finalizer_unreachable
(obj, fn, cd, ofn, ocd)
GC_PTR obj;
GC_finalization_proc fn;
GC_PTR cd;
GC_finalization_proc *ofn;
GC_PTR *ocd;
# endif
{
GC_finalization_proc my_old_fn;
GC_PTR my_old_cd;
ptr_t base = GC_base(obj);
if (0 == base) return;
if ((ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_debug_register_finalizer_unreachable called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
GC_register_finalizer_unreachable(base, 0, 0, &my_old_fn, &my_old_cd);
} else {
GC_register_finalizer_unreachable(base, GC_debug_invoke_finalizer,
GC_make_closure(fn,cd), &my_old_fn,
&my_old_cd);
}
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
}
# ifdef __STDC__
void GC_debug_register_finalizer_ignore_self

View File

@ -2,6 +2,7 @@
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
* Copyright (C) 2007 Free Software Foundation, Inc
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -315,6 +316,14 @@ ptr_t p;
{
}
/* Possible finalization_marker procedures. Note that mark stack */
/* overflow is handled by the caller, and is not a disaster. */
GC_API void GC_unreachable_finalize_mark_proc(p)
ptr_t p;
{
return GC_normal_finalize_mark_proc(p);
}
/* Register a finalization function. See gc.h for details. */
@ -511,6 +520,23 @@ finalization_mark_proc * mp;
ocd, GC_null_finalize_mark_proc);
}
# if defined(__STDC__)
void GC_register_finalizer_unreachable(void * obj,
GC_finalization_proc fn, void * cd,
GC_finalization_proc *ofn, void ** ocd)
# else
void GC_register_finalizer_unreachable(obj, fn, cd, ofn, ocd)
GC_PTR obj;
GC_finalization_proc fn;
GC_PTR cd;
GC_finalization_proc * ofn;
GC_PTR * ocd;
# endif
{
GC_register_finalizer_inner(obj, fn, cd, ofn,
ocd, GC_unreachable_finalize_mark_proc);
}
#ifndef NO_DEBUGGING
void GC_dump_finalization()
{
@ -638,9 +664,44 @@ void GC_finalize()
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
}
GC_set_mark_bit(real_ptr);
if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
GC_set_mark_bit(real_ptr);
}
}
}
/* now revive finalize-when-unreachable objects reachable from
other finalizable objects */
curr_fo = GC_finalize_now;
prev_fo = 0;
while (curr_fo != 0) {
next_fo = fo_next(curr_fo);
if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
if (!GC_is_marked(real_ptr)) {
GC_set_mark_bit(real_ptr);
} else {
if (prev_fo == 0)
GC_finalize_now = next_fo;
else
fo_set_next(prev_fo, next_fo);
curr_fo -> fo_hidden_base =
(word) HIDE_POINTER(curr_fo -> fo_hidden_base);
GC_words_finalized -=
ALIGNED_WORDS(curr_fo -> fo_object_size)
+ ALIGNED_WORDS(sizeof(struct finalizable_object));
i = HASH2(real_ptr, log_fo_table_size);
fo_set_next (curr_fo, fo_head[i]);
GC_fo_entries++;
fo_head[i] = curr_fo;
curr_fo = prev_fo;
}
}
prev_fo = curr_fo;
curr_fo = next_fo;
}
}
/* Remove dangling disappearing links. */

View File

@ -3,6 +3,7 @@
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright 1996-1999 by Silicon Graphics. All rights reserved.
* Copyright 1999 by Hewlett-Packard Company. All rights reserved.
* Copyright (C) 2007 Free Software Foundation, Inc
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -602,6 +603,8 @@ GC_API GC_PTR GC_debug_realloc_replacement
GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
GC_debug_register_finalizer_no_order(p, f, d, of, od)
# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
GC_debug_register_finalizer_unreachable(p, f, d, of, od)
# define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS);
# define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
@ -624,6 +627,8 @@ GC_API GC_PTR GC_debug_realloc_replacement
GC_register_finalizer_ignore_self(p, f, d, of, od)
# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
GC_register_finalizer_no_order(p, f, d, of, od)
# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
GC_register_finalizer_unreachable(p, f, d, of, od)
# define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
# define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
@ -716,6 +721,19 @@ GC_API void GC_debug_register_finalizer_no_order
GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
GC_finalization_proc *ofn, GC_PTR *ocd));
/* This is a special finalizer that is useful when an object's */
/* finalizer must be run when the object is known to be no */
/* longer reachable, not even from other finalizable objects. */
/* This can be used in combination with finalizer_no_order so */
/* as to release resources that must not be released while an */
/* object can still be brought back to life by other */
/* finalizers. */
GC_API void GC_register_finalizer_unreachable
GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
GC_finalization_proc *ofn, GC_PTR *ocd));
GC_API void GC_debug_register_finalizer_unreachable
GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
GC_finalization_proc *ofn, GC_PTR *ocd));
/* The following routine may be used to break cycles between */
/* finalizable objects, thus causing cyclic finalizable */

View File

@ -1,3 +1,53 @@
2007-03-07 Alexandre Oliva <aoliva@redhat.com>
* include/ffi.h.in (ffi_closure_alloc, ffi_closure_free): New.
(ffi_prep_closure_loc): New.
(ffi_prep_raw_closure_loc): New.
(ffi_prep_java_raw_closure_loc): New.
* src/closures.c: New file.
* src/dlmalloc.c [FFI_MMAP_EXEC_WRIT] (struct malloc_segment):
Replace sflags with exec_offset.
[FFI_MMAP_EXEC_WRIT] (mmap_exec_offset, add_segment_exec_offset,
sub_segment_exec_offset): New macros.
(get_segment_flags, set_segment_flags, check_segment_merge): New
macros.
(is_mmapped_segment, is_extern_segment): Use get_segment_flags.
(add_segment, sys_alloc, create_mspace, create_mspace_with_base,
destroy_mspace): Use new macros.
(sys_alloc): Silence warning.
* Makefile.am (libffi_la_SOURCES): Add src/closures.c.
* Makefile.in: Rebuilt.
* src/prep_cif [FFI_CLOSURES] (ffi_prep_closure): Implement in
terms of ffi_prep_closure_loc.
* src/raw_api.c (ffi_prep_raw_closure_loc): Renamed and adjusted
from...
(ffi_prep_raw_closure): ... this. Re-implement in terms of the
renamed version.
* src/java_raw_api (ffi_prep_java_raw_closure_loc): Renamed and
adjusted from...
(ffi_prep_java_raw_closure): ... this. Re-implement in terms of
the renamed version.
* src/alpha/ffi.c (ffi_prep_closure_loc): Renamed from
(ffi_prep_closure): ... this.
* src/pa/ffi.c: Likewise.
* src/cris/ffi.c: Likewise. Adjust.
* src/frv/ffi.c: Likewise.
* src/ia64/ffi.c: Likewise.
* src/mips/ffi.c: Likewise.
* src/powerpc/ffi_darwin.c: Likewise.
* src/s390/ffi.c: Likewise.
* src/sh/ffi.c: Likewise.
* src/sh64/ffi.c: Likewise.
* src/sparc/ffi.c: Likewise.
* src/x86/ffi64.c: Likewise.
* src/x86/ffi.c: Likewise.
(FFI_INIT_TRAMPOLINE): Adjust.
(ffi_prep_raw_closure_loc): Renamed and adjusted from...
(ffi_prep_raw_closure): ... this.
* src/powerpc/ffi.c (ffi_prep_closure_loc): Renamed from
(ffi_prep_closure): ... this.
(flush_icache): Adjust.
2007-03-07 Alexandre Oliva <aoliva@redhat.com>
* src/dlmalloc.c: New file, imported version 2.8.3 of Doug

View File

@ -78,7 +78,7 @@ toolexeclib_LTLIBRARIES = libffi.la
noinst_LTLIBRARIES = libffi_convenience.la
libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c \
src/raw_api.c src/java_raw_api.c
src/raw_api.c src/java_raw_api.c src/closures.c
nodist_libffi_la_SOURCES =

View File

@ -92,7 +92,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
libffi_la_LIBADD =
am__dirstamp = $(am__leading_dot)dirstamp
am_libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \
src/raw_api.lo src/java_raw_api.lo
src/raw_api.lo src/java_raw_api.lo src/closures.lo
@MIPS_IRIX_TRUE@am__objects_1 = src/mips/ffi.lo src/mips/o32.lo \
@MIPS_IRIX_TRUE@ src/mips/n32.lo
@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo
@ -141,7 +141,7 @@ libffi_la_OBJECTS = $(am_libffi_la_OBJECTS) \
$(nodist_libffi_la_OBJECTS)
libffi_convenience_la_LIBADD =
am__objects_24 = src/debug.lo src/prep_cif.lo src/types.lo \
src/raw_api.lo src/java_raw_api.lo
src/raw_api.lo src/java_raw_api.lo src/closures.lo
am_libffi_convenience_la_OBJECTS = $(am__objects_24)
am__objects_25 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
@ -416,7 +416,7 @@ MAKEOVERRIDES =
toolexeclib_LTLIBRARIES = libffi.la
noinst_LTLIBRARIES = libffi_convenience.la
libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c \
src/raw_api.c src/java_raw_api.c
src/raw_api.c src/java_raw_api.c src/closures.c
nodist_libffi_la_SOURCES = $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_4) $(am__append_5) \
@ -534,6 +534,7 @@ src/prep_cif.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/types.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/java_raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/closures.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/mips/$(am__dirstamp):
@$(mkdir_p) src/mips
@: > src/mips/$(am__dirstamp)
@ -729,6 +730,8 @@ mostlyclean-compile:
-rm -f src/arm/ffi.lo
-rm -f src/arm/sysv.$(OBJEXT)
-rm -f src/arm/sysv.lo
-rm -f src/closures.$(OBJEXT)
-rm -f src/closures.lo
-rm -f src/cris/ffi.$(OBJEXT)
-rm -f src/cris/ffi.lo
-rm -f src/cris/sysv.$(OBJEXT)
@ -827,6 +830,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/closures.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/debug.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/java_raw_api.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/prep_cif.Plo@am__quote@

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------*-C-*-
libffi @VERSION@ - Copyright (c) 1996-2003 Red Hat, Inc.
libffi @VERSION@ - Copyright (c) 1996-2003, 2007 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -228,12 +228,22 @@ typedef struct {
void *user_data;
} ffi_closure __attribute__((aligned (8)));
void *ffi_closure_alloc (size_t size, void **code);
void ffi_closure_free (void *);
ffi_status
ffi_prep_closure (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data);
ffi_status
ffi_prep_closure_loc (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void*codeloc);
typedef struct {
char tramp[FFI_TRAMPOLINE_SIZE];
@ -261,12 +271,26 @@ ffi_prep_raw_closure (ffi_raw_closure*,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data);
ffi_status
ffi_prep_raw_closure_loc (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc);
ffi_status
ffi_prep_java_raw_closure (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data);
ffi_status
ffi_prep_java_raw_closure_loc (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc);
#endif /* FFI_CLOSURES */
/* ---- Public interface definition -------------------------------------- */

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc.
ffi.c - Copyright (c) 1998, 2001, 2007 Red Hat, Inc.
Alpha Foreign Function Interface
@ -146,10 +146,11 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp;

513
libffi/src/closures.c Normal file
View File

@ -0,0 +1,513 @@
/* -----------------------------------------------------------------------
closures.c - Copyright (c) 2007 Red Hat, Inc.
Code to allocate and deallocate memory for closures.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#ifndef FFI_MMAP_EXEC_WRIT
# if __gnu_linux__
/* This macro indicates it may be forbidden to map anonymous memory
with both write and execute permission. Code compiled when this
option is defined will attempt to map such pages once, but if it
fails, it falls back to creating a temporary file in a writable and
executable filesystem and mapping pages from it into separate
locations in the virtual memory space, one location writable and
another executable. */
# define FFI_MMAP_EXEC_WRIT 1
# endif
#endif
#if FFI_CLOSURES
# if FFI_MMAP_EXEC_WRIT
#define USE_LOCKS 1
#define USE_DL_PREFIX 1
#define USE_BUILTIN_FFS 1
/* We need to use mmap, not sbrk. */
#define HAVE_MORECORE 0
/* We could, in theory, support mremap, but it wouldn't buy us anything. */
#define HAVE_MREMAP 0
/* We have no use for this, so save some code and data. */
#define NO_MALLINFO 1
/* We need all allocations to be in regular segments, otherwise we
lose track of the corresponding code address. */
#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
/* Don't allocate more than a page unless needed. */
#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
#if FFI_CLOSURE_TEST
/* Don't release single pages, to avoid a worst-case scenario of
continuously allocating and releasing single pages, but release
pairs of pages, which should do just as well given that allocations
are likely to be small. */
#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <mntent.h>
#include <sys/param.h>
#include <pthread.h>
/* We don't want sys/mman.h to be included after we redefine mmap and
dlmunmap. */
#include <sys/mman.h>
#define LACKS_SYS_MMAN_H 1
#define MAYBE_UNUSED __attribute__((__unused__))
/* Declare all functions defined in dlmalloc.c as static. */
static void *dlmalloc(size_t);
static void dlfree(void*);
static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
static void *dlvalloc(size_t) MAYBE_UNUSED;
static int dlmallopt(int, int) MAYBE_UNUSED;
static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
static void *dlpvalloc(size_t) MAYBE_UNUSED;
static int dlmalloc_trim(size_t) MAYBE_UNUSED;
static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
static void dlmalloc_stats(void) MAYBE_UNUSED;
/* Use these for mmap and munmap within dlmalloc.c. */
static void *dlmmap(void *, size_t, int, int, int, off_t);
static int dlmunmap(void *, size_t);
#define mmap dlmmap
#define munmap dlmunmap
#include "dlmalloc.c"
#undef mmap
#undef munmap
/* A mutex used to synchronize access to *exec* variables in this file. */
static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
/* A file descriptor of a temporary file from which we'll map
executable pages. */
static int execfd = -1;
/* The amount of space already allocated from the temporary file. */
static size_t execsize = 0;
/* Open a temporary file name, and immediately unlink it. */
static int
open_temp_exec_file_name (char *name)
{
int fd = mkstemp (name);
if (fd != -1)
unlink (name);
return fd;
}
/* Open a temporary file in the named directory. */
static int
open_temp_exec_file_dir (const char *dir)
{
static const char suffix[] = "/ffiXXXXXX";
int lendir = strlen (dir);
char *tempname = __builtin_alloca (lendir + sizeof (suffix));
if (!tempname)
return -1;
memcpy (tempname, dir, lendir);
memcpy (tempname + lendir, suffix, sizeof (suffix));
return open_temp_exec_file_name (tempname);
}
/* Open a temporary file in the directory in the named environment
variable. */
static int
open_temp_exec_file_env (const char *envvar)
{
const char *value = getenv (envvar);
if (!value)
return -1;
return open_temp_exec_file_dir (value);
}
/* Open a temporary file in an executable and writable mount point
listed in the mounts file. Subsequent calls with the same mounts
keep searching for mount points in the same file. Providing NULL
as the mounts file closes the file. */
static int
open_temp_exec_file_mnt (const char *mounts)
{
static const char *last_mounts;
static FILE *last_mntent;
if (mounts != last_mounts)
{
if (last_mntent)
endmntent (last_mntent);
last_mounts = mounts;
if (mounts)
last_mntent = setmntent (mounts, "r");
else
last_mntent = NULL;
}
if (!last_mntent)
return -1;
for (;;)
{
int fd;
struct mntent mnt;
char buf[MAXPATHLEN * 3];
if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
return -1;
if (hasmntopt (&mnt, "ro")
|| hasmntopt (&mnt, "noexec")
|| access (mnt.mnt_dir, W_OK))
continue;
fd = open_temp_exec_file_dir (mnt.mnt_dir);
if (fd != -1)
return fd;
}
}
/* Instructions to look for a location to hold a temporary file that
can be mapped in for execution. */
static struct
{
int (*func)(const char *);
const char *arg;
int repeat;
} open_temp_exec_file_opts[] = {
{ open_temp_exec_file_env, "TMPDIR", 0 },
{ open_temp_exec_file_dir, "/tmp", 0 },
{ open_temp_exec_file_dir, "/var/tmp", 0 },
{ open_temp_exec_file_dir, "/dev/shm", 0 },
{ open_temp_exec_file_env, "HOME", 0 },
{ open_temp_exec_file_mnt, "/etc/mtab", 1 },
{ open_temp_exec_file_mnt, "/proc/mounts", 1 },
};
/* Current index into open_temp_exec_file_opts. */
static int open_temp_exec_file_opts_idx = 0;
/* Reset a current multi-call func, then advances to the next entry.
If we're at the last, go back to the first and return nonzero,
otherwise return zero. */
static int
open_temp_exec_file_opts_next (void)
{
if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
open_temp_exec_file_opts_idx++;
if (open_temp_exec_file_opts_idx
== (sizeof (open_temp_exec_file_opts)
/ sizeof (*open_temp_exec_file_opts)))
{
open_temp_exec_file_opts_idx = 0;
return 1;
}
return 0;
}
/* Return a file descriptor of a temporary zero-sized file in a
writable and exexutable filesystem. */
static int
open_temp_exec_file (void)
{
int fd;
do
{
fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
(open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
|| fd == -1)
{
if (open_temp_exec_file_opts_next ())
break;
}
}
while (fd == -1);
return fd;
}
/* Map in a chunk of memory from the temporary exec file into separate
locations in the virtual memory address space, one writable and one
executable. Returns the address of the writable portion, after
storing an offset to the corresponding executable portion at the
last word of the requested chunk. */
static void *
dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
{
void *ptr;
if (execfd == -1)
{
open_temp_exec_file_opts_idx = 0;
retry_open:
execfd = open_temp_exec_file ();
if (execfd == -1)
return MFAIL;
}
offset = execsize;
if (ftruncate (execfd, offset + length))
return MFAIL;
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
flags |= MAP_SHARED;
ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
flags, execfd, offset);
if (ptr == MFAIL)
{
if (!offset)
{
close (execfd);
goto retry_open;
}
ftruncate (execfd, offset);
return MFAIL;
}
else if (!offset
&& open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
open_temp_exec_file_opts_next ();
start = mmap (start, length, prot, flags, execfd, offset);
if (start == MFAIL)
{
munmap (ptr, length);
ftruncate (execfd, offset);
return start;
}
mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
execsize += length;
return start;
}
/* Map in a writable and executable chunk of memory if possible.
Failing that, fall back to dlmmap_locked. */
static void *
dlmmap (void *start, size_t length, int prot,
int flags, int fd, off_t offset)
{
void *ptr;
assert (start == NULL && length % malloc_getpagesize == 0
&& prot == (PROT_READ | PROT_WRITE)
&& flags == (MAP_PRIVATE | MAP_ANONYMOUS)
&& fd == -1 && offset == 0);
#if FFI_CLOSURE_TEST
printf ("mapping in %zi\n", length);
#endif
if (execfd == -1)
{
ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
/* Cool, no need to mess with separate segments. */
return ptr;
/* If MREMAP_DUP is ever introduced and implemented, try mmap
with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
MREMAP_DUP and prot at this point. */
}
if (execsize == 0 || execfd == -1)
{
pthread_mutex_lock (&open_temp_exec_file_mutex);
ptr = dlmmap_locked (start, length, prot, flags, offset);
pthread_mutex_unlock (&open_temp_exec_file_mutex);
return ptr;
}
return dlmmap_locked (start, length, prot, flags, offset);
}
/* Release memory at the given address, as well as the corresponding
executable page if it's separate. */
static int
dlmunmap (void *start, size_t length)
{
/* We don't bother decreasing execsize or truncating the file, since
we can't quite tell whether we're unmapping the end of the file.
We don't expect frequent deallocation anyway. If we did, we
could locate pages in the file by writing to the pages being
deallocated and checking that the file contents change.
Yuck. */
msegmentptr seg = segment_holding (gm, start);
void *code;
#if FFI_CLOSURE_TEST
printf ("unmapping %zi\n", length);
#endif
if (seg && (code = add_segment_exec_offset (start, seg)) != start)
{
int ret = munmap (code, length);
if (ret)
return ret;
}
return munmap (start, length);
}
#if FFI_CLOSURE_FREE_CODE
/* Return segment holding given code address. */
static msegmentptr
segment_holding_code (mstate m, char* addr)
{
msegmentptr sp = &m->seg;
for (;;) {
if (addr >= add_segment_exec_offset (sp->base, sp)
&& addr < add_segment_exec_offset (sp->base, sp) + sp->size)
return sp;
if ((sp = sp->next) == 0)
return 0;
}
}
#endif
/* Allocate a chunk of memory with the given size. Returns a pointer
to the writable address, and sets *CODE to the executable
corresponding virtual address. */
void *
ffi_closure_alloc (size_t size, void **code)
{
void *ptr;
if (!code)
return NULL;
ptr = dlmalloc (size);
if (ptr)
{
msegmentptr seg = segment_holding (gm, ptr);
*code = add_segment_exec_offset (ptr, seg);
}
return ptr;
}
/* Release a chunk of memory allocated with ffi_closure_alloc. If
FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
writable or the executable address given. Otherwise, only the
writable address can be provided here. */
void
ffi_closure_free (void *ptr)
{
#if FFI_CLOSURE_FREE_CODE
msegmentptr seg = segment_holding_code (gm, ptr);
if (seg)
ptr = sub_segment_exec_offset (ptr, seg);
#endif
dlfree (ptr);
}
#if FFI_CLOSURE_TEST
/* Do some internal sanity testing to make sure allocation and
deallocation of pages are working as intended. */
int main ()
{
void *p[3];
#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
GET (0, malloc_getpagesize / 2);
GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
PUT (1);
GET (1, 2 * malloc_getpagesize);
GET (2, malloc_getpagesize / 2);
PUT (1);
PUT (0);
PUT (2);
return 0;
}
#endif /* FFI_CLOSURE_TEST */
# else /* ! FFI_MMAP_EXEC_WRIT */
/* On many systems, memory returned by malloc is writable and
executable, so just use it. */
#include <stdlib.h>
void *
ffi_closure_alloc (size_t size, void **code)
{
if (!code)
return NULL;
return *code = malloc (size);
}
void
ffi_closure_free (void *ptr)
{
free (ptr);
}
# endif /* ! FFI_MMAP_EXEC_WRIT */
#endif /* FFI_CLOSURES */

View File

@ -2,6 +2,7 @@
ffi.c - Copyright (c) 1998 Cygnus Solutions
Copyright (c) 2004 Simon Posnjak
Copyright (c) 2005 Axis Communications AB
Copyright (C) 2007 Free Software Foundation, Inc.
CRIS Foreign Function Interface
@ -360,10 +361,11 @@ ffi_prep_closure_inner (void **params, ffi_closure* closure)
/* API function: Prepare the trampoline. */
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif *, void *, void **, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif *, void *, void **, void*),
void *user_data,
void *codeloc)
{
void *innerfn = ffi_prep_closure_inner;
FFI_ASSERT (cif->abi == FFI_SYSV);
@ -375,7 +377,7 @@ ffi_prep_closure (ffi_closure* closure,
memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
&innerfn, sizeof (void *));
memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
&closure, sizeof (void *));
&codeloc, sizeof (void *));
return FFI_OK;
}

View File

@ -1879,11 +1879,47 @@ struct malloc_segment {
char* base; /* base address */
size_t size; /* allocated size */
struct malloc_segment* next; /* ptr to next segment */
#if FFI_MMAP_EXEC_WRIT
/* The mmap magic is supposed to store the address of the executable
segment at the very end of the requested block. */
# define mmap_exec_offset(b,s) (*(ptrdiff_t*)((b)+(s)-sizeof(ptrdiff_t)))
/* We can only merge segments if their corresponding executable
segments are at identical offsets. */
# define check_segment_merge(S,b,s) \
(mmap_exec_offset((b),(s)) == (S)->exec_offset)
# define add_segment_exec_offset(p,S) ((char*)(p) + (S)->exec_offset)
# define sub_segment_exec_offset(p,S) ((char*)(p) - (S)->exec_offset)
/* The removal of sflags only works with HAVE_MORECORE == 0. */
# define get_segment_flags(S) (IS_MMAPPED_BIT)
# define set_segment_flags(S,v) \
(((v) != IS_MMAPPED_BIT) ? (ABORT, (v)) : \
(((S)->exec_offset = \
mmap_exec_offset((S)->base, (S)->size)), \
(mmap_exec_offset((S)->base + (S)->exec_offset, (S)->size) != \
(S)->exec_offset) ? (ABORT, (v)) : \
(mmap_exec_offset((S)->base, (S)->size) = 0), (v)))
/* We use an offset here, instead of a pointer, because then, when
base changes, we don't have to modify this. On architectures
with segmented addresses, this might not work. */
ptrdiff_t exec_offset;
#else
# define get_segment_flags(S) ((S)->sflags)
# define set_segment_flags(S,v) ((S)->sflags = (v))
# define check_segment_merge(S,b,s) (1)
flag_t sflags; /* mmap and extern flag */
#endif
};
#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT)
#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
#define is_mmapped_segment(S) (get_segment_flags(S) & IS_MMAPPED_BIT)
#define is_extern_segment(S) (get_segment_flags(S) & EXTERN_BIT)
typedef struct malloc_segment msegment;
typedef struct malloc_segment* msegmentptr;
@ -3290,7 +3326,7 @@ static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
*ss = m->seg; /* Push current record */
m->seg.base = tbase;
m->seg.size = tsize;
m->seg.sflags = mmapped;
set_segment_flags(&m->seg, mmapped);
m->seg.next = ss;
/* Insert trailing fenceposts */
@ -3393,7 +3429,7 @@ static void* sys_alloc(mstate m, size_t nb) {
if (end != CMFAIL)
asize += esize;
else { /* Can't use; try to release */
CALL_MORECORE(-asize);
(void)CALL_MORECORE(-asize);
br = CMFAIL;
}
}
@ -3450,7 +3486,7 @@ static void* sys_alloc(mstate m, size_t nb) {
if (!is_initialized(m)) { /* first-time initialization */
m->seg.base = m->least_addr = tbase;
m->seg.size = tsize;
m->seg.sflags = mmap_flag;
set_segment_flags(&m->seg, mmap_flag);
m->magic = mparams.magic;
init_bins(m);
if (is_global(m))
@ -3469,7 +3505,8 @@ static void* sys_alloc(mstate m, size_t nb) {
sp = sp->next;
if (sp != 0 &&
!is_extern_segment(sp) &&
(sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&
check_segment_merge(sp, tbase, tsize) &&
(get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag &&
segment_holds(sp, m->top)) { /* append */
sp->size += tsize;
init_top(m, m->top, m->topsize + tsize);
@ -3482,7 +3519,8 @@ static void* sys_alloc(mstate m, size_t nb) {
sp = sp->next;
if (sp != 0 &&
!is_extern_segment(sp) &&
(sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
check_segment_merge(sp, tbase, tsize) &&
(get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag) {
char* oldbase = sp->base;
sp->base = tbase;
sp->size += tsize;
@ -4397,7 +4435,7 @@ mspace create_mspace(size_t capacity, int locked) {
char* tbase = (char*)(CALL_MMAP(tsize));
if (tbase != CMFAIL) {
m = init_user_mstate(tbase, tsize);
m->seg.sflags = IS_MMAPPED_BIT;
set_segment_flags(&m->seg, IS_MMAPPED_BIT);
set_lock(m, locked);
}
}
@ -4412,7 +4450,7 @@ mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
if (capacity > msize + TOP_FOOT_SIZE &&
capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
m = init_user_mstate((char*)base, capacity);
m->seg.sflags = EXTERN_BIT;
set_segment_flags(&m->seg, EXTERN_BIT);
set_lock(m, locked);
}
return (mspace)m;
@ -4426,7 +4464,7 @@ size_t destroy_mspace(mspace msp) {
while (sp != 0) {
char* base = sp->base;
size_t size = sp->size;
flag_t flag = sp->sflags;
flag_t flag = get_segment_flags(sp);
sp = sp->next;
if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&
CALL_MUNMAP(base, size) == 0)

View File

@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2004 Anthony Green
Copyright (C) 2007 Free Software Foundation, Inc.
FR-V Foreign Function Interface
@ -243,14 +244,15 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
}
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned long fn = (long) ffi_closure_eabi;
unsigned long cls = (long) closure;
unsigned long cls = (long) codeloc;
#ifdef __FRV_FDPIC__
register void *got __asm__("gr15");
#endif
@ -259,7 +261,7 @@ ffi_prep_closure (ffi_closure* closure,
fn = (unsigned long) ffi_closure_eabi;
#ifdef __FRV_FDPIC__
tramp[0] = &tramp[2];
tramp[0] = &((unsigned int *)codeloc)[2];
tramp[1] = got;
tramp[2] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */
tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */
@ -281,7 +283,8 @@ ffi_prep_closure (ffi_closure* closure,
/* Cache flushing. */
for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
__asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i));
__asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
"r" (codeloc));
return FFI_OK;
}

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Red Hat, Inc.
ffi.c - Copyright (c) 1998, 2007 Red Hat, Inc.
Copyright (c) 2000 Hewlett Packard Company
IA64 Foreign Function Interface
@ -400,10 +400,11 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
extern void ffi_closure_unix ();
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
/* The layout of a function descriptor. A C function pointer really
points to one of these. */
@ -430,7 +431,7 @@ ffi_prep_closure (ffi_closure* closure,
tramp->code_pointer = fd->code_pointer;
tramp->real_gp = fd->gp;
tramp->fake_gp = (UINT64)(PTR64)closure;
tramp->fake_gp = (UINT64)(PTR64)codeloc;
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
java_raw_api.c - Copyright (c) 1999 Red Hat, Inc.
java_raw_api.c - Copyright (c) 1999, 2007 Red Hat, Inc.
Cloned from raw_api.c
@ -307,22 +307,20 @@ ffi_java_translate_args (ffi_cif *cif, void *rvalue,
ffi_java_raw_to_rvalue (cif, rvalue);
}
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_java_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
ffi_prep_java_raw_closure_loc (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
ffi_status status;
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
&ffi_java_translate_args,
(void*)cl);
status = ffi_prep_closure_loc ((ffi_closure*) cl,
cif,
&ffi_java_translate_args,
codeloc,
codeloc);
if (status == FFI_OK)
{
cl->fun = fun;
@ -332,6 +330,19 @@ ffi_prep_java_raw_closure (ffi_raw_closure* cl,
return status;
}
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_java_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
return ffi_prep_java_raw_closure_loc (cl, cif, fun, user_data, cl);
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NATIVE_RAW_API */
#endif /* !FFI_NO_RAW_API */

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996 Red Hat, Inc.
ffi.c - Copyright (c) 1996, 2007 Red Hat, Inc.
MIPS Foreign Function Interface
@ -497,14 +497,15 @@ extern void ffi_closure_O32(void);
#endif /* FFI_MIPS_O32 */
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned int fn;
unsigned int ctx = (unsigned int) closure;
unsigned int ctx = (unsigned int) codeloc;
#if defined(FFI_MIPS_O32)
FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
@ -525,7 +526,7 @@ ffi_prep_closure (ffi_closure *closure,
closure->user_data = user_data;
/* XXX this is available on Linux, but anything else? */
cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, ICACHE);
return FFI_OK;
}

View File

@ -613,10 +613,11 @@ ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
extern void ffi_closure_pa32(void);
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
UINT32 *tramp = (UINT32 *)(closure->tramp);
#ifdef PA_HPUX

View File

@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1998 Geoffrey Keating
Copyright (C) 2007 Free Software Foundation, Inc
PowerPC Foreign Function Interface
@ -834,27 +835,27 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
#define MIN_CACHE_LINE_SIZE 8
static void
flush_icache (char *addr1, int size)
flush_icache (char *wraddr, char *xaddr, int size)
{
int i;
char * addr;
for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
{
addr = addr1 + i;
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;"
: : "r" (addr) : "memory");
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
: : "r" (xaddr + i), "r" (wraddr + i) : "memory");
}
addr = addr1 + size - 1;
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;"
: : "r"(addr) : "memory");
__asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
: : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
: "memory");
}
#endif
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
void *user_data)
ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
void *user_data,
void *codeloc)
{
#ifdef POWERPC64
void **tramp = (void **) &closure->tramp[0];
@ -862,7 +863,7 @@ ffi_prep_closure (ffi_closure *closure,
FFI_ASSERT (cif->abi == FFI_LINUX64);
/* Copy function address and TOC from ffi_closure_LINUX64. */
memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
tramp[2] = (void *) closure;
tramp[2] = (void *) codeloc;
#else
unsigned int *tramp;
@ -878,10 +879,10 @@ ffi_prep_closure (ffi_closure *closure,
tramp[8] = 0x7c0903a6; /* mtctr r0 */
tramp[9] = 0x4e800420; /* bctr */
*(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */
*(void **) &tramp[3] = (void *) closure; /* context */
*(void **) &tramp[3] = (void *) codeloc; /* context */
/* Flush the icache. */
flush_icache (&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
flush_icache (tramp, codeloc, FFI_TRAMPOLINE_SIZE);
#endif
closure->cif = cif;

View File

@ -3,7 +3,7 @@
Copyright (C) 1998 Geoffrey Keating
Copyright (C) 2001 John Hornkvist
Copyright (C) 2002, 2006 Free Software Foundation, Inc.
Copyright (C) 2002, 2006, 2007 Free Software Foundation, Inc.
FFI support for Darwin and AIX.
@ -528,10 +528,11 @@ SP current --> +---------------------------------------+ 176 <- parent frame
*/
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp;
struct ffi_aix_trampoline_struct *tramp_aix;
@ -553,14 +554,14 @@ ffi_prep_closure (ffi_closure* closure,
tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */
tramp[9] = 0x4e800420; /* bctr */
tramp[2] = (unsigned long) ffi_closure_ASM; /* function */
tramp[3] = (unsigned long) closure; /* context */
tramp[3] = (unsigned long) codeloc; /* context */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
/* Flush the icache. Only necessary on Darwin. */
flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);
flush_range(codeloc, FFI_TRAMPOLINE_SIZE);
break;
@ -573,7 +574,7 @@ ffi_prep_closure (ffi_closure* closure,
tramp_aix->code_pointer = fd->code_pointer;
tramp_aix->toc = fd->toc;
tramp_aix->static_chain = closure;
tramp_aix->static_chain = codeloc;
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc.
prep_cif.c - Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -158,3 +158,16 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */
#if FFI_CLOSURES
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
}
#endif

View File

@ -209,22 +209,20 @@ ffi_translate_args (ffi_cif *cif, void *rvalue,
(*cl->fun) (cif, rvalue, raw, cl->user_data);
}
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
ffi_prep_raw_closure_loc (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
ffi_status status;
status = ffi_prep_closure ((ffi_closure*) cl,
cif,
&ffi_translate_args,
(void*)cl);
status = ffi_prep_closure_loc ((ffi_closure*) cl,
cif,
&ffi_translate_args,
codeloc,
codeloc);
if (status == FFI_OK)
{
cl->fun = fun;
@ -236,4 +234,22 @@ ffi_prep_raw_closure (ffi_raw_closure* cl,
#endif /* FFI_CLOSURES */
#endif /* !FFI_NATIVE_RAW_API */
#if FFI_CLOSURES
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl);
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NO_RAW_API */

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2000 Software AG
ffi.c - Copyright (c) 2000, 2007 Software AG
S390 Foreign Function Interface
@ -736,17 +736,18 @@ ffi_closure_helper_SYSV (ffi_closure *closure,
/*====================================================================*/
/* */
/* Name - ffi_prep_closure. */
/* Name - ffi_prep_closure_loc. */
/* */
/* Function - Prepare a FFI closure. */
/* */
/*====================================================================*/
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
void *user_data)
ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif *cif,
void (*fun) (ffi_cif *, void *, void **, void *),
void *user_data,
void *codeloc)
{
FFI_ASSERT (cif->abi == FFI_SYSV);
@ -755,7 +756,7 @@ ffi_prep_closure (ffi_closure *closure,
*(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
*(short *)&closure->tramp [4] = 0x1006;
*(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
*(long *)&closure->tramp [8] = (long)closure;
*(long *)&closure->tramp [8] = (long)codeloc;
*(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
#else
*(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
@ -763,7 +764,7 @@ ffi_prep_closure (ffi_closure *closure,
*(short *)&closure->tramp [4] = 0x100e;
*(short *)&closure->tramp [6] = 0x0004;
*(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
*(long *)&closure->tramp[16] = (long)closure;
*(long *)&closure->tramp[16] = (long)codeloc;
*(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
#endif

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006 Kaz Kojima
ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Kaz Kojima
SuperH Foreign Function Interface
@ -452,10 +452,11 @@ extern void __ic_invalidate (void *line);
#endif
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp;
unsigned short insn;
@ -475,7 +476,7 @@ ffi_prep_closure (ffi_closure* closure,
tramp[0] = 0xd102d301;
tramp[1] = 0x412b0000 | insn;
#endif
*(void **) &tramp[2] = (void *)closure; /* ctx */
*(void **) &tramp[2] = (void *)codeloc; /* ctx */
*(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
closure->cif = cif;
@ -484,7 +485,7 @@ ffi_prep_closure (ffi_closure* closure,
#if defined(__SH4__)
/* Flush the icache. */
__ic_invalidate(&closure->tramp[0]);
__ic_invalidate(codeloc);
#endif
return FFI_OK;

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2003, 2004, 2006 Kaz Kojima
ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
SuperH SHmedia Foreign Function Interface
@ -283,10 +283,11 @@ extern void ffi_closure_SYSV (void);
extern void __ic_invalidate (void *line);
ffi_status
ffi_prep_closure (ffi_closure *closure,
ffi_cif *cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure *closure,
ffi_cif *cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp;
@ -310,8 +311,8 @@ ffi_prep_closure (ffi_closure *closure,
tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
tramp[4] = 0x6bf10600;
tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
tramp[7] = 0x4401fff0;
closure->cif = cif;
@ -319,7 +320,8 @@ ffi_prep_closure (ffi_closure *closure,
closure->user_data = user_data;
/* Flush the icache. */
asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
"r"(codeloc));
return FFI_OK;
}

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
ffi.c - Copyright (c) 1996, 2003, 2004, 2007 Red Hat, Inc.
SPARC Foreign Function Interface
@ -425,10 +425,11 @@ extern void ffi_closure_v8(void);
#endif
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
unsigned int *tramp = (unsigned int *) &closure->tramp[0];
unsigned long fn;
@ -443,7 +444,7 @@ ffi_prep_closure (ffi_closure* closure,
tramp[3] = 0x01000000; /* nop */
*((unsigned long *) &tramp[4]) = fn;
#else
unsigned long ctx = (unsigned long) closure;
unsigned long ctx = (unsigned long) codeloc;
FFI_ASSERT (cif->abi == FFI_V8);
fn = (unsigned long) ffi_closure_v8;
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
@ -302,7 +302,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
unsigned int __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[5] = 0xe9; \
@ -313,16 +313,17 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
/* the cif must already be prep'ed */
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
FFI_ASSERT (cif->abi == FFI_SYSV);
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
&ffi_closure_SYSV, \
(void*)closure);
codeloc);
closure->cif = cif;
closure->user_data = user_data;
@ -336,10 +337,11 @@ ffi_prep_closure (ffi_closure* closure,
#if !FFI_NO_RAW_API
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
int i;
@ -358,7 +360,7 @@ ffi_prep_raw_closure (ffi_raw_closure* closure,
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
(void*)closure);
codeloc);
closure->cif = cif;
closure->user_data = user_data;

View File

@ -1,5 +1,5 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
ffi.c - Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
x86-64 Foreign Function Interface
@ -433,10 +433,11 @@ ffi_call (ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
extern void ffi_closure_unix64(void);
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data)
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
volatile unsigned short *tramp;
@ -445,7 +446,7 @@ ffi_prep_closure (ffi_closure* closure,
tramp[0] = 0xbb49; /* mov <code>, %r11 */
*(void * volatile *) &tramp[1] = ffi_closure_unix64;
tramp[5] = 0xba49; /* mov <data>, %r10 */
*(void * volatile *) &tramp[6] = closure;
*(void * volatile *) &tramp[6] = codeloc;
/* Set the carry bit iff the function uses any sse registers.
This is clc or stc, together with the first byte of the jmp. */

View File

@ -1,3 +1,53 @@
2007-03-07 Alexandre Oliva <aoliva@redhat.com>
* include/jvm.h (_Jv_ClosureListFinalizer): New.
(_Jv_Linker::create_error_method): Adjust.
* boehm.cc (_Jv_ClosureListFinalizer): New.
* nogc.cc (_Jv_ClosureListFinalizer): New.
* java/lang/Class.h (class _Jv_ClosureList): New.
(class java::lang::Class): Declare it as friend.
* java/lang/natClass.cc (_Jv_ClosureList::releaseClosures): New.
(_Jv_ClosureList::registerClousure): New.
* include/execution.h (_Jv_ExecutionEngine): Add get_closure_list.
(_Jv_CompiledEngine::do_get_closure_list): New.
(_Jv_CompiledEngine::_Jv_CompiledEngine): Use it.
(_Jv_IndirectCompiledClass): Add closures.
(_Jv_IndirectCompiledEngine::get_aux_info): New.
(_Jv_IndirectCompiledEngine::do_allocate_field_initializers): Use
it.
(_Jv_IndirectCompiledEngine::do_get_closure_list): New.
(_Jv_IndirectCompiledEngine::_Jv_IndirectCompiledEngine): Use it.
(_Jv_InterpreterEngine::do_get_closure_list): Declare.
(_Jv_InterpreterEngine::_Jv_InterpreterEngine): Use it.
* interpret.cc (FFI_PREP_RAW_CLOSURE): Use _loc variants.
(node_closure): Add closure list.
(_Jv_InterpMethod::ncode): Add jclass argument. Use
ffi_closure_alloc and the separate code pointer. Register the
closure for finalization.
(_Jv_JNIMethod::ncode): Likewise.
(_Jv_InterpreterEngine::do_create_ncode): Pass klass to ncode.
(_Jv_InterpreterEngine::do_get_closure_list): New.
* include/java-interp.h (_Jv_InterpMethod::ncode): Adjust.
(_Jv_InterpClass): Add closures field.
(_Jv_JNIMethod::ncode): Adjust.
* defineclass.cc (_Jv_ClassReader::handleCodeAttribute): Adjust.
(_Jv_ClassReader::handleMethodsEnd): Likewise.
* link.cc (struct method_closure): Add closure list.
(_Jv_Linker::create_error_method): Add jclass argument. Use
ffi_closure_alloc and the separate code pointer. Register the
closure for finalization.
(_Jv_Linker::link_symbol_table): Remove outdated comment about
sharing of otable and atable. Adjust.
* java/lang/reflect/natVMProxy.cc (ncode_closure): Add closure
list.
(ncode): Add jclass argument. Use ffi_closure_alloc and the
separate code pointer. Register the closure for finalization.
(java::lang::reflect::VMProxy::generateProxyClass): Adjust.
* testsuite/libjava.jar/TestClosureGC.java: New.
* testsuite/libjava.jar/TestClosureGC.out: New.
* testsuite/libjava.jar/TestClosureGC.xfail: New.
* testsuite/libjava.jar/TestClosureGC.jar: New.
2007-03-06 Kyle Galloway <kgallowa@redhat.com>
* classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java: New file.

View File

@ -1,6 +1,6 @@
// boehm.cc - interface between libjava and Boehm GC.
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation
This file is part of libgcj.
@ -380,6 +380,29 @@ _Jv_AllocRawObj (jsize size)
return (void *) GC_MALLOC (size ? size : 1);
}
typedef _Jv_ClosureList *closure_list_pointer;
/* Release closures in a _Jv_ClosureList. */
static void
finalize_closure_list (GC_PTR obj, GC_PTR)
{
_Jv_ClosureList **clpp = (_Jv_ClosureList **)obj;
_Jv_ClosureList::releaseClosures (clpp);
}
/* Allocate a double-indirect pointer to a _Jv_ClosureList that will
get garbage-collected after this double-indirect pointer becomes
unreachable by any other objects, including finalizable ones. */
_Jv_ClosureList **
_Jv_ClosureListFinalizer ()
{
_Jv_ClosureList **clpp;
clpp = (_Jv_ClosureList **)_Jv_AllocBytes (sizeof (*clpp));
GC_REGISTER_FINALIZER_UNREACHABLE (clpp, finalize_closure_list,
NULL, NULL, NULL);
return clpp;
}
static void
call_finalizer (GC_PTR obj, GC_PTR client_data)
{

View File

@ -1,6 +1,7 @@
// defineclass.cc - defining a class from .class format.
/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation
This file is part of libgcj.
@ -1695,7 +1696,7 @@ void _Jv_ClassReader::handleCodeAttribute
// call a static method of an interpreted class from precompiled
// code without first resolving the class (that will happen
// during class initialization instead).
method->self->ncode = method->ncode ();
method->self->ncode = method->ncode (def);
}
}
@ -1740,7 +1741,7 @@ void _Jv_ClassReader::handleMethodsEnd ()
// interpreted class from precompiled code without
// first resolving the class (that will happen
// during class initialization instead).
method->ncode = m->ncode ();
method->ncode = m->ncode (def);
}
}
}

View File

@ -1,6 +1,6 @@
// execution.h - Execution engines. -*- c++ -*-
/* Copyright (C) 2004, 2006 Free Software Foundation
/* Copyright (C) 2004, 2006, 2007 Free Software Foundation
This file is part of libgcj.
@ -29,6 +29,7 @@ struct _Jv_ExecutionEngine
_Jv_ResolvedMethod *(*resolve_method) (_Jv_Method *, jclass,
jboolean);
void (*post_miranda_hook) (jclass);
_Jv_ClosureList **(*get_closure_list) (jclass);
};
// This handles gcj-compiled code except that compiled with
@ -77,6 +78,11 @@ struct _Jv_CompiledEngine : public _Jv_ExecutionEngine
// Not needed.
}
static _Jv_ClosureList **do_get_closure_list (jclass)
{
return NULL;
}
_Jv_CompiledEngine ()
{
unregister = do_unregister;
@ -87,6 +93,7 @@ struct _Jv_CompiledEngine : public _Jv_ExecutionEngine
create_ncode = do_create_ncode;
resolve_method = do_resolve_method;
post_miranda_hook = do_post_miranda_hook;
get_closure_list = do_get_closure_list;
}
// These operators make it so we don't have to link in libstdc++.
@ -105,6 +112,7 @@ class _Jv_IndirectCompiledClass
{
public:
void **field_initializers;
_Jv_ClosureList **closures;
};
// This handles gcj-compiled code compiled with -findirect-classes.
@ -114,14 +122,32 @@ struct _Jv_IndirectCompiledEngine : public _Jv_CompiledEngine
{
allocate_static_fields = do_allocate_static_fields;
allocate_field_initializers = do_allocate_field_initializers;
get_closure_list = do_get_closure_list;
}
static _Jv_IndirectCompiledClass *get_aux_info (jclass klass)
{
_Jv_IndirectCompiledClass *aux =
(_Jv_IndirectCompiledClass*)klass->aux_info;
if (!aux)
{
aux = (_Jv_IndirectCompiledClass*)
_Jv_AllocRawObj (sizeof (_Jv_IndirectCompiledClass));
klass->aux_info = aux;
}
return aux;
}
static void do_allocate_field_initializers (jclass klass)
{
_Jv_IndirectCompiledClass *aux
= (_Jv_IndirectCompiledClass*)
_Jv_AllocRawObj (sizeof (_Jv_IndirectCompiledClass));
klass->aux_info = aux;
_Jv_IndirectCompiledClass *aux = get_aux_info (klass);
if (!aux)
{
aux = (_Jv_IndirectCompiledClass*)
_Jv_AllocRawObj (sizeof (_Jv_IndirectCompiledClass));
klass->aux_info = aux;
}
aux->field_initializers = (void **)_Jv_Malloc (klass->field_count
* sizeof (void*));
@ -172,6 +198,16 @@ struct _Jv_IndirectCompiledEngine : public _Jv_CompiledEngine
}
_Jv_Free (aux->field_initializers);
}
static _Jv_ClosureList **do_get_closure_list (jclass klass)
{
_Jv_IndirectCompiledClass *aux = get_aux_info (klass);
if (!aux->closures)
aux->closures = _Jv_ClosureListFinalizer ();
return aux->closures;
}
};
@ -203,6 +239,8 @@ class _Jv_InterpreterEngine : public _Jv_ExecutionEngine
static void do_post_miranda_hook (jclass);
static _Jv_ClosureList **do_get_closure_list (jclass klass);
_Jv_InterpreterEngine ()
{
unregister = do_unregister;
@ -213,6 +251,7 @@ class _Jv_InterpreterEngine : public _Jv_ExecutionEngine
create_ncode = do_create_ncode;
resolve_method = do_resolve_method;
post_miranda_hook = do_post_miranda_hook;
get_closure_list = do_get_closure_list;
}
// These operators make it so we don't have to link in libstdc++.

View File

@ -202,7 +202,7 @@ class _Jv_InterpMethod : public _Jv_MethodBase
}
// return the method's invocation pointer (a stub).
void *ncode ();
void *ncode (jclass);
void compile (const void * const *);
static void run_normal (ffi_cif*, void*, ffi_raw*, void*);
@ -293,6 +293,7 @@ class _Jv_InterpClass
_Jv_MethodBase **interpreted_methods;
_Jv_ushort *field_initializers;
jstring source_file_name;
_Jv_ClosureList **closures;
friend class _Jv_ClassReader;
friend class _Jv_InterpMethod;
@ -341,7 +342,7 @@ class _Jv_JNIMethod : public _Jv_MethodBase
// This function is used when making a JNI call from the interpreter.
static void call (ffi_cif *, void *, ffi_raw *, void *);
void *ncode ();
void *ncode (jclass);
friend class _Jv_ClassReader;
friend class _Jv_InterpreterEngine;

View File

@ -288,7 +288,7 @@ private:
_Jv_Utf8Const *method_signature,
jclass *found_class,
bool check_perms = true);
static void *create_error_method(_Jv_Utf8Const *);
static void *create_error_method(_Jv_Utf8Const *, jclass);
/* The least significant bit of the signature pointer in a symbol
table is set to 1 by the compiler if the reference is "special",
@ -341,6 +341,10 @@ void *_Jv_AllocBytes (jsize size) __attribute__((__malloc__));
/* Allocate space for a new non-Java object, which does not have the usual
Java object header but may contain pointers to other GC'ed objects. */
void *_Jv_AllocRawObj (jsize size) __attribute__((__malloc__));
/* Allocate a double-indirect pointer to a _Jv_ClosureList such that
the _Jv_ClosureList gets automatically finalized when it is no
longer reachable, not even by other finalizable objects. */
_Jv_ClosureList **_Jv_ClosureListFinalizer (void) __attribute__((__malloc__));
/* Explicitly throw an out-of-memory exception. */
void _Jv_ThrowNoMemory() __attribute__((__noreturn__));
/* Allocate an object with a single pointer. The first word is reserved

View File

@ -1255,10 +1255,10 @@ _Jv_init_cif (_Jv_Utf8Const* signature,
}
#if FFI_NATIVE_RAW_API
# define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure
# define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure_loc
# define FFI_RAW_SIZE ffi_raw_size
#else
# define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure
# define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure_loc
# define FFI_RAW_SIZE ffi_java_raw_size
#endif
@ -1269,6 +1269,7 @@ _Jv_init_cif (_Jv_Utf8Const* signature,
typedef struct {
ffi_raw_closure closure;
_Jv_ClosureList list;
ffi_cif cif;
ffi_type *arg_types[0];
} ncode_closure;
@ -1276,7 +1277,7 @@ typedef struct {
typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*);
void *
_Jv_InterpMethod::ncode ()
_Jv_InterpMethod::ncode (jclass klass)
{
using namespace java::lang::reflect;
@ -1286,9 +1287,12 @@ _Jv_InterpMethod::ncode ()
jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
int arg_count = _Jv_count_arguments (self->signature, staticp);
void *code;
ncode_closure *closure =
(ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*));
(ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*),
&code);
closure->list.registerClosure (klass, closure);
_Jv_init_cif (self->signature,
arg_count,
@ -1341,9 +1345,11 @@ _Jv_InterpMethod::ncode ()
FFI_PREP_RAW_CLOSURE (&closure->closure,
&closure->cif,
fun,
(void*)this);
(void*)this,
code);
self->ncode = code;
self->ncode = (void*)closure;
return self->ncode;
}
@ -1540,7 +1546,7 @@ _Jv_InterpMethod::set_insn (jlong index, pc_t insn)
}
void *
_Jv_JNIMethod::ncode ()
_Jv_JNIMethod::ncode (jclass klass)
{
using namespace java::lang::reflect;
@ -1550,9 +1556,12 @@ _Jv_JNIMethod::ncode ()
jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
int arg_count = _Jv_count_arguments (self->signature, staticp);
void *code;
ncode_closure *closure =
(ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*));
(ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*),
&code);
closure->list.registerClosure (klass, closure);
ffi_type *rtype;
_Jv_init_cif (self->signature,
@ -1594,9 +1603,10 @@ _Jv_JNIMethod::ncode ()
FFI_PREP_RAW_CLOSURE (&closure->closure,
&closure->cif,
fun,
(void*) this);
(void*) this,
code);
self->ncode = (void *) closure;
self->ncode = code;
return self->ncode;
}
@ -1657,16 +1667,27 @@ _Jv_InterpreterEngine::do_create_ncode (jclass klass)
// cases. Well, we can't, because we don't allocate these
// objects using `new', and thus they don't get a vtable.
_Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth);
klass->methods[i].ncode = jnim->ncode ();
klass->methods[i].ncode = jnim->ncode (klass);
}
else if (imeth != 0) // it could be abstract
{
_Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
klass->methods[i].ncode = im->ncode ();
klass->methods[i].ncode = im->ncode (klass);
}
}
}
_Jv_ClosureList **
_Jv_InterpreterEngine::do_get_closure_list (jclass klass)
{
_Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info;
if (!iclass->closures)
iclass->closures = _Jv_ClosureListFinalizer ();
return iclass->closures;
}
void
_Jv_InterpreterEngine::do_allocate_static_fields (jclass klass,
int pointer_size,

View File

@ -105,6 +105,15 @@ class _Jv_InterpClass;
class _Jv_InterpMethod;
#endif
class _Jv_ClosureList
{
_Jv_ClosureList *next;
void *ptr;
public:
void registerClosure (jclass klass, void *ptr);
static void releaseClosures (_Jv_ClosureList **closures);
};
struct _Jv_Constants
{
jint size;
@ -632,6 +641,7 @@ private:
friend class ::_Jv_CompiledEngine;
friend class ::_Jv_IndirectCompiledEngine;
friend class ::_Jv_InterpreterEngine;
friend class ::_Jv_ClosureList;
friend void ::_Jv_sharedlib_register_hook (jclass klass);

View File

@ -670,6 +670,28 @@ java::lang::Class::finalize (void)
engine->unregister(this);
}
void
_Jv_ClosureList::releaseClosures (_Jv_ClosureList **closures)
{
if (!closures)
return;
while (_Jv_ClosureList *current = *closures)
{
*closures = current->next;
ffi_closure_free (current->ptr);
}
}
void
_Jv_ClosureList::registerClosure (jclass klass, void *ptr)
{
_Jv_ClosureList **closures = klass->engine->get_closure_list (klass);
this->ptr = ptr;
this->next = *closures;
*closures = this;
}
// This implements the initialization process for a class. From Spec
// section 12.4.2.
void

View File

@ -1,6 +1,6 @@
// natVMProxy.cc -- Implementation of VMProxy methods.
/* Copyright (C) 2006
/* Copyright (C) 2006, 2007
Free Software Foundation
This file is part of libgcj.
@ -66,7 +66,7 @@ using namespace java::lang::reflect;
using namespace java::lang;
typedef void (*closure_fun) (ffi_cif*, void*, void**, void*);
static void *ncode (_Jv_Method *self, closure_fun fun);
static void *ncode (jclass klass, _Jv_Method *self, closure_fun fun);
static void run_proxy (ffi_cif*, void*, void**, void*);
typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);
@ -165,7 +165,7 @@ java::lang::reflect::VMProxy::generateProxyClass
// the interfaces of which it is a proxy will also be reachable,
// so this is safe.
method = imethod;
method.ncode = ncode (&method, run_proxy);
method.ncode = ncode (klass, &method, run_proxy);
method.accflags &= ~Modifier::ABSTRACT;
}
@ -289,6 +289,7 @@ unbox (jobject o, jclass klass, void *rvalue, FFI_TYPE type)
typedef struct {
ffi_closure closure;
_Jv_ClosureList list;
ffi_cif cif;
_Jv_Method *self;
ffi_type *arg_types[0];
@ -366,16 +367,19 @@ run_proxy (ffi_cif *cif,
// the address of its closure.
static void *
ncode (_Jv_Method *self, closure_fun fun)
ncode (jclass klass, _Jv_Method *self, closure_fun fun)
{
using namespace java::lang::reflect;
jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
int arg_count = _Jv_count_arguments (self->signature, staticp);
void *code;
ncode_closure *closure =
(ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*));
(ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*),
&code);
closure->list.registerClosure (klass, closure);
_Jv_init_cif (self->signature,
arg_count,
@ -387,11 +391,12 @@ ncode (_Jv_Method *self, closure_fun fun)
JvAssert ((self->accflags & Modifier::NATIVE) == 0);
ffi_prep_closure (&closure->closure,
&closure->cif,
fun,
(void*)closure);
ffi_prep_closure_loc (&closure->closure,
&closure->cif,
fun,
code,
code);
self->ncode = (void*)closure;
self->ncode = code;
return self->ncode;
}

View File

@ -1022,15 +1022,17 @@ struct method_closure
// be the same as the address of the overall structure. This is due
// to disabling interior pointers in the GC.
ffi_closure closure;
_Jv_ClosureList list;
ffi_cif cif;
ffi_type *arg_types[1];
};
void *
_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name, jclass klass)
{
void *code;
method_closure *closure
= (method_closure *) _Jv_AllocBytes(sizeof (method_closure));
= (method_closure *)ffi_closure_alloc (sizeof (method_closure), &code);
closure->arg_types[0] = &ffi_type_void;
@ -1042,13 +1044,18 @@ _Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
1,
&ffi_type_void,
closure->arg_types) == FFI_OK
&& ffi_prep_closure (&closure->closure,
&closure->cif,
_Jv_ThrowNoClassDefFoundErrorTrampoline,
class_name) == FFI_OK)
return &closure->closure;
&& ffi_prep_closure_loc (&closure->closure,
&closure->cif,
_Jv_ThrowNoClassDefFoundErrorTrampoline,
class_name,
code) == FFI_OK)
{
closure->list.registerClosure (klass, closure);
return code;
}
else
{
ffi_closure_free (closure);
java::lang::StringBuffer *buffer = new java::lang::StringBuffer();
buffer->append(JvNewStringLatin1("Error setting up FFI closure"
" for static method of"
@ -1059,7 +1066,7 @@ _Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
}
#else
void *
_Jv_Linker::create_error_method (_Jv_Utf8Const *)
_Jv_Linker::create_error_method (_Jv_Utf8Const *, jclass)
{
// Codepath for platforms which do not support (or want) libffi.
// You have to accept that it is impossible to provide the name
@ -1090,8 +1097,6 @@ static bool debug_link = false;
// at the corresponding position in the virtual method offset table
// (klass->otable).
// The same otable and atable may be shared by many classes.
// This must be called while holding the class lock.
void
@ -1242,13 +1247,15 @@ _Jv_Linker::link_symbol_table (jclass klass)
// NullPointerException
klass->atable->addresses[index] = NULL;
bool use_error_method = false;
// If the target class is missing we prepare a function call
// that throws a NoClassDefFoundError and store the address of
// that newly prepared method in the atable. The user can run
// code in classes where the missing class is part of the
// execution environment as long as it is never referenced.
if (target_class == NULL)
klass->atable->addresses[index] = create_error_method(sym.class_name);
use_error_method = true;
// We're looking for a static field or a static method, and we
// can tell which is needed by looking at the signature.
else if (signature->first() == '(' && signature->len() >= 2)
@ -1296,12 +1303,16 @@ _Jv_Linker::link_symbol_table (jclass klass)
}
}
else
use_error_method = true;
if (use_error_method)
klass->atable->addresses[index]
= create_error_method(sym.class_name);
= create_error_method(sym.class_name, klass);
continue;
}
// Try fields only if the target class exists.
if (target_class != NULL)
{

View File

@ -1,6 +1,7 @@
// nogc.cc - Implement null garbage collector.
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2007
Free Software Foundation
This file is part of libgcj.
@ -71,6 +72,14 @@ _Jv_AllocRawObj (jsize size)
return calloc (size, 1);
}
_Jv_ClosureList **
_Jv_ClosureListFinalizer ()
{
_Jv_ClosureList **clpp;
clpp = (_Jv_ClosureList **)_Jv_AllocBytes (sizeof (*clpp));
return clpp;
}
void
_Jv_RegisterFinalizer (void *, _Jv_FinalizerFunc *)
{

Binary file not shown.

View File

@ -0,0 +1,116 @@
/* Verify that libffi closures aren't deallocated too early.
Copyright (C) 2007 Free Software Foundation, Inc
Contributed by Alexandre Oliva <aoliva@redhat.com>
If libffi closures are released too early, we lose.
*/
import java.util.HashSet;
public class TestClosureGC {
public static String objId (Object obj) {
return obj + "/"
+ Integer.toHexString(obj.getClass().getClassLoader().hashCode());
}
public static class cld extends java.net.URLClassLoader {
static final Object obj = new cl0();
public cld () throws Exception {
super(new java.net.URL[] { });
/* System.out.println (objId (this) + " created"); */
}
public void finalize () {
/* System.out.println (objId (this) + " finalized"); */
}
public String toString () {
return this.getClass().getName() + "@"
+ Integer.toHexString (hashCode ());
}
public Class loadClass (String name) throws ClassNotFoundException {
try {
java.io.InputStream IS = getSystemResourceAsStream
(name + ".class");
int maxsz = 1024, readsz = 0;
byte buf[] = new byte[maxsz];
for(;;) {
int readnow = IS.read (buf, readsz, maxsz - readsz);
if (readnow <= 0)
break;
readsz += readnow;
if (readsz == maxsz) {
byte newbuf[] = new byte[maxsz *= 2];
System.arraycopy (buf, 0, newbuf, 0, readsz);
buf = newbuf;
}
}
return defineClass (name, buf, 0, readsz);
} catch (Exception e) {
return super.loadClass (name);
}
}
}
public static class cl0 {
public cl0 () {
/* System.out.println (objId (this) + " created"); */
}
public void finalize () {
/* System.out.println (objId (this) + " finalized"); */
}
}
public static class cl1 {
final HashSet hs;
static final Object obj = new cl0();
public cl1 (final HashSet hs) {
this.hs = hs;
/* System.out.println (objId (this) + " created"); */
}
public void finalize () {
/* System.out.println (objId (this) + " finalized"); */
}
}
public static class cl2 {
final HashSet hs;
static final Object obj = new cl0();
public cl2 (final HashSet hs) {
this.hs = hs;
/* System.out.println (objId (this) + " created"); */
}
public void finalize () {
/* System.out.println (objId (this) + " finalized"); */
hs.add(this);
hs.add(new cl0());
}
}
static final HashSet hs = new HashSet();
static final Object obj = new cl0();
public static void main(String[] argv) throws Exception {
{
Class[] hscs = { HashSet.class };
Object[] hsos = { hs };
new cld().loadClass ("TestClosureGC$cl1").
getConstructor (hscs).newInstance (hsos);
new cld().loadClass ("TestClosureGC$cl2").
getConstructor (hscs).newInstance (hsos);
new cld().loadClass ("TestClosureGC$cl1").
getConstructor (hscs).newInstance (hsos);
new cld().loadClass ("TestClosureGC$cl1").
getConstructor (hscs).newInstance (hsos);
}
for (int i = 1; i <= 5; i++) {
/* System.out.println ("Will run GC and finalization " + i); */
System.gc ();
Thread.sleep (100);
System.runFinalization ();
Thread.sleep (100);
if (hs.isEmpty ())
continue;
java.util.Iterator it = hs.iterator ();
while (it.hasNext ()) {
Object obj = it.next();
/* System.out.println (objId (obj) + " in ht, removing"); */
it.remove ();
}
}
System.out.println ("ok");
}
}

View File

@ -0,0 +1 @@
ok

View File

@ -0,0 +1 @@
main=TestClosureGC