diff options
author | Andrew Haley <aph@redhat.com> | 2006-10-13 12:53:36 +0000 |
---|---|---|
committer | Andrew Haley <aph@redhat.com> | 2006-10-13 12:53:36 +0000 |
commit | 81d174387ba4c17194f7e45bba6d5522dfddf481 (patch) | |
tree | 29c8b84d1d10ec914eb6fb0512dddbc6effe929f | |
parent | 53cad73923f715fea760022380abb07c6c9cc816 (diff) |
2006-10-13 Andrew Haley <aph@redhat.com>gcj/gcj-tls-experimental-branch
* java-gimplify.c: Revert last changes.
* java-tree.h: Likewise.
* jcf-parse.c: Likewise.
* parse.y: Likewise.
* class.c: Likewise.
2006-10-12 Andrew Haley <aph@redhat.com>
* java/lang/natThreadLocal.cc: New file.
* java/lang/ThreadLocal.java: Rewrite to use native TLS.
* Makefile.am: Add java/lang/natThreadLocal.cc.
* sources.am: Move classpath/java/lang/ThreadLocal.java to
java/lang/ThreadLocal.java.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcj/gcj-tls-experimental-branch@117693 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/java/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/java/class.c | 107 | ||||
-rw-r--r-- | gcc/java/java-gimplify.c | 72 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 3 | ||||
-rw-r--r-- | gcc/java/jcf-parse.c | 1 | ||||
-rw-r--r-- | gcc/java/parse.y | 2 | ||||
-rw-r--r-- | libjava/ChangeLog | 8 | ||||
-rw-r--r-- | libjava/java/lang/ThreadLocal.java | 23 | ||||
-rw-r--r-- | libjava/java/lang/natThreadLocal.cc | 148 |
9 files changed, 104 insertions, 268 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 51043db398e..dccb08e6ae5 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,11 @@ +2006-10-13 Andrew Haley <aph@redhat.com> + + * java-gimplify.c: Revert last changes. + * java-tree.h: Likewise. + * jcf-parse.c: Likewise. + * parse.y: Likewise. + * class.c: Likewise. + 2006-09-01 Andrew Haley <aph@redhat.com> * class.c (find_tls_thunk): New function. diff --git a/gcc/java/class.c b/gcc/java/class.c index ea9bf719822..cdb298e77a1 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -65,7 +65,6 @@ static int assume_compiled (const char *); static tree build_symbol_entry (tree, tree); static tree emit_assertion_table (tree); static void register_class (void); -static void build_tls_thunk (tree decl); struct obstack temporary_obstack; @@ -1617,96 +1616,6 @@ supers_all_compiled (tree type) return 1; } -tree -find_tls_thunk (tree decl) -{ - char *buf = alloca (4096); - tree id; - - sprintf (buf, "_Jv_thread_local_thunk_%s_%s", - IDENTIFIER_POINTER (DECL_NAME (decl)), - IDENTIFIER_POINTER (mangled_classname ("", DECL_CONTEXT (decl)))); - id = get_identifier (buf); - return id ? IDENTIFIER_GLOBAL_VALUE (id) : NULL_TREE; -} - -void -build_tls_thunks (tree class) -{ - tree field; - - if (targetm.have_tls) - for (field = TYPE_FIELDS (class); field != NULL_TREE; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) == VAR_DECL - && TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE - && FIELD_STATIC (field) - && ((DECL_NAME (TYPE_NAME (TREE_TYPE (TREE_TYPE (field))))) - == get_identifier ("java.lang.ThreadLocal"))) - build_tls_thunk (field); - } -} - -static void -build_tls_thunk (tree decl) -{ - tree fdecl, vdecl; - char *buf = alloca (4096); - tree stmts; - tree_stmt_iterator it; - tree ret_stmt; - tree result_decl; - tree function_identifier; - tree buf_type = make_node (RECORD_TYPE); - - { - tree id_field = build_decl (FIELD_DECL, NULL_TREE, long_type_node); - tree ptr_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); - TYPE_FIELDS (buf_type) = id_field; - TREE_CHAIN (id_field) = ptr_field; - layout_type (buf_type); - } - - sprintf (buf, "_Jv_thread_local_%s_%s", - IDENTIFIER_POINTER (DECL_NAME (decl)), - IDENTIFIER_POINTER (mangled_classname ("", DECL_CONTEXT (decl)))); - vdecl = build_decl (VAR_DECL, get_identifier (buf), buf_type); - DECL_TLS_MODEL (vdecl) = decl_default_tls_model (vdecl); - TREE_STATIC (vdecl) = 1; - DECL_IGNORED_P (vdecl) = 1; - DECL_ARTIFICIAL (vdecl) = 1; - rest_of_decl_compilation (vdecl, 1, 0); - - sprintf (buf, "_Jv_thread_local_thunk_%s_%s", - IDENTIFIER_POINTER (DECL_NAME (decl)), - IDENTIFIER_POINTER (mangled_classname ("", DECL_CONTEXT (decl)))); - function_identifier = get_identifier (buf); - fdecl = build_decl (FUNCTION_DECL, function_identifier, - build_function_type_list (ptr_type_node, - void_type_node, - NULL_TREE)); - IDENTIFIER_GLOBAL_VALUE (function_identifier) = fdecl; - result_decl = build_result_decl (fdecl); - - ret_stmt - = build1 (RETURN_EXPR, ptr_type_node, - (build2 (MODIFY_EXPR, ptr_type_node, - result_decl, - fold_convert (ptr_type_node, - build_address_of (vdecl))))); - - stmts = make_node (STATEMENT_LIST); - it = tsi_last (stmts); - tsi_link_after (&it, ret_stmt, TSI_CONTINUE_LINKING); - TREE_TYPE (stmts) = void_type_node; - - DECL_SAVED_TREE (fdecl) = stmts; - DECL_INITIAL (fdecl) = make_node (BLOCK); - - java_genericize (fdecl); - cgraph_finalize_function (fdecl, false); -} - void make_class_data (tree type) { @@ -1737,7 +1646,6 @@ make_class_data (tree type) to where objects actually point at, following new g++ ABI. */ tree dtable_start_offset = build_int_cst (NULL_TREE, 2 * POINTER_SIZE / BITS_PER_UNIT); - tree first_field; this_class_addr = build_static_class_ref (type); decl = TREE_OPERAND (this_class_addr, 0); @@ -1759,16 +1667,13 @@ make_class_data (tree type) class_dtable_decl = dtable_decl; } - /* Find the first real field. */ - first_field = TYPE_FIELDS (type); - while (first_field && DECL_ARTIFICIAL (first_field)) - first_field = TREE_CHAIN (first_field); /* Skip dummy fields. */ - if (first_field && DECL_NAME (first_field) == NULL_TREE) - first_field = TREE_CHAIN (first_field); /* Skip dummy field - for inherited data. */ - /* Build Field array. */ - for (field = first_field; field != NULL_TREE; field = TREE_CHAIN (field)) + field = TYPE_FIELDS (type); + while (field && DECL_ARTIFICIAL (field)) + field = TREE_CHAIN (field); /* Skip dummy fields. */ + if (field && DECL_NAME (field) == NULL_TREE) + field = TREE_CHAIN (field); /* Skip dummy field for inherited data. */ + for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (! DECL_ARTIFICIAL (field)) { diff --git a/gcc/java/java-gimplify.c b/gcc/java/java-gimplify.c index 3d3171653ff..54900d3f9ab 100644 --- a/gcc/java/java-gimplify.c +++ b/gcc/java/java-gimplify.c @@ -26,14 +26,11 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "system.h" #include "coretypes.h" #include "tm.h" -#include "target.h" #include "tree.h" #include "java-tree.h" #include "tree-dump.h" #include "tree-gimple.h" #include "toplev.h" -#include "rtl.h" /* For decl_default_tls_model. */ -#include "jcf.h" static tree java_gimplify_labeled_block_expr (tree); static tree java_gimplify_exit_block_expr (tree); @@ -269,77 +266,14 @@ java_gimplify_component_ref (tree *expr_p, tree *pre_p, tree *post_p) return GS_UNHANDLED; } -static enum gimplify_status -java_maybe_replace_init_expr (tree *modify_expr_p, - tree *pre_p ATTRIBUTE_UNUSED, - tree *post_p ATTRIBUTE_UNUSED) -{ - tree modify_expr = *modify_expr_p; - tree lhs = TREE_OPERAND (modify_expr, 0); - tree lhs_type = TREE_TYPE (lhs); - tree name = NULL_TREE; - tree fdecl, arg_list; - - if (targetm.have_tls - && TREE_CODE (lhs) == VAR_DECL - && TREE_CODE (lhs_type) == POINTER_TYPE - && FIELD_STATIC (lhs) - && ((name = DECL_NAME (TYPE_NAME (TREE_TYPE (lhs_type)))) - == get_identifier ("java.lang.ThreadLocal")) - && (fdecl = find_tls_thunk (lhs)) != NULL_TREE) - { - tree call_expr; - tree rhs = TREE_OPERAND (modify_expr, 1); - enum gimplify_status stat; - tree maybe_method - = lookup_java_method (TREE_TYPE (lhs_type), - get_identifier ("setTLS"), - get_identifier ("(Lgnu/gcj/RawData;)V")); - if (! maybe_method /* && ! flag_verify_invocations */) - { - maybe_method - = add_method (TREE_TYPE (lhs_type), ACC_FINAL|ACC_PRIVATE, - get_identifier ("setTLS"), - get_identifier ("(Lgnu/gcj/RawData;)V")); - DECL_EXTERNAL (maybe_method) = 1; - } -/* IDENTIFIER_GLOBAL_VALUE (name) = NULL_TREE; */ - stat = gimplify_expr (&rhs, pre_p, post_p, - is_gimple_formal_tmp_var, fb_rvalue); - if (stat == GS_ERROR) - return stat; - - arg_list = tree_cons (NULL_TREE, rhs, build_tree_list (NULL_TREE, - build_address_of (fdecl))); - - call_expr = build3 (CALL_EXPR, void_type_node, - build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (maybe_method)), -/* build_invokevirtual (invoke_build_dtable (0, arg_list), */ -/* maybe_method, */ -/* integer_one_node) */ - build_known_method_ref (maybe_method, TREE_TYPE (maybe_method), - DECL_CONTEXT (maybe_method), - get_identifier ("(Lgnu/gcj/RawData;)V"), - arg_list, integer_one_node)), - arg_list, - NULL_TREE); - TREE_OPERAND (modify_expr, 1) = build2 (COMPOUND_EXPR, TREE_TYPE (rhs), call_expr, rhs); - } - - return GS_UNHANDLED; -} static enum gimplify_status java_gimplify_modify_expr (tree *modify_expr_p, tree *pre_p, tree *post_p) { tree modify_expr = *modify_expr_p; - tree lhs, lhs_type, rhs; - - java_maybe_replace_init_expr (&modify_expr, pre_p, post_p); - - lhs = TREE_OPERAND (modify_expr, 0); - rhs = TREE_OPERAND (modify_expr, 1); - lhs_type = TREE_TYPE (lhs); + tree lhs = TREE_OPERAND (modify_expr, 0); + tree rhs = TREE_OPERAND (modify_expr, 1); + tree lhs_type = TREE_TYPE (lhs); if (CLASS_FROM_SOURCE_P (output_class) && TREE_CODE (lhs) == COMPONENT_REF diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 452eaa23f2e..f3478692d70 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -1405,9 +1405,6 @@ extern int in_same_package (tree, tree); extern tree builtin_function (const char *, tree, int, enum built_in_class, const char *, tree); -tree find_tls_thunk (tree decl); -void build_tls_thunks (tree class); - #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) /* Access flags etc for a method (a FUNCTION_DECL): */ diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 8d576b2526b..b9d52b61f8c 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -856,7 +856,6 @@ parse_class_file (void) (*debug_hooks->start_source_file) (input_line, input_filename); gen_indirect_dispatch_tables (current_class); - build_tls_thunks (current_class); java_mark_class_local (current_class); diff --git a/gcc/java/parse.y b/gcc/java/parse.y index b7c3de119b1..39a5ac94997 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -8272,8 +8272,6 @@ java_expand_method_bodies (tree class) { tree decl; - build_tls_thunks (class); - for (decl = TYPE_METHODS (class); decl; decl = TREE_CHAIN (decl)) { tree block; diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 3b98a204d65..0dccbe7e806 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,11 @@ +2006-10-12 Andrew Haley <aph@redhat.com> + + * java/lang/natThreadLocal.cc: New file. + * java/lang/ThreadLocal.java: Rewrite to use native TLS. + * Makefile.am: Add java/lang/natThreadLocal.cc. + * sources.am: Move classpath/java/lang/ThreadLocal.java to + java/lang/ThreadLocal.java. + 2006-09-01 Andrew Haley <aph@redhat.com> * Makefile.in: Rebuild. diff --git a/libjava/java/lang/ThreadLocal.java b/libjava/java/lang/ThreadLocal.java index cd6276f5d7d..644c93b67e4 100644 --- a/libjava/java/lang/ThreadLocal.java +++ b/libjava/java/lang/ThreadLocal.java @@ -100,6 +100,7 @@ public class ThreadLocal */ public ThreadLocal() { + constructNative(); } /** @@ -125,7 +126,7 @@ public class ThreadLocal */ public native Object get(); - private final Object slowGet() + private final Object internalGet() { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will @@ -149,7 +150,7 @@ public class ThreadLocal */ public native void set(Object value); - private final void slowSet(Object value) + private final void internalSet(Object value) { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will @@ -164,27 +165,15 @@ public class ThreadLocal */ public native void remove(); - private final void slowRemove() + private final void internalRemove() { Map map = Thread.getThreadLocals(); map.remove(this); } - private final void setTLS(gnu.gcj.RawData p) - { - synchronized (sentinel) - { - if (counter == 0) - // We've run out of unique TLS IDs. Fall back to using slow - // TLS. - return; - id = counter++; - TLSPointer = p; - } - } + protected native void finalize () throws Throwable; - static private long counter = 1; + private native void constructNative(); private gnu.gcj.RawData TLSPointer; - private long id; } diff --git a/libjava/java/lang/natThreadLocal.cc b/libjava/java/lang/natThreadLocal.cc index 3bced24541a..1b81aab63f0 100644 --- a/libjava/java/lang/natThreadLocal.cc +++ b/libjava/java/lang/natThreadLocal.cc @@ -52,55 +52,10 @@ details. */ So, we can't simply replace get() and set() with accesses of a __thread variable. - This is how our soloution works: - - Whenever we create a static field of Class ThreadLocal, we also - create a variable with __thread attribute, but it is only used as a - cache of a ThreadLocal entry. Whenever we set() a static - ThreadLocal, we must update a map of ThreadLocals and the __thread - variable we're using to cache the entry. However, when we get() a - static ThreadLocal, we only need to read the cache. - - - In detail: - - When gcj allocates a static field that is an instance of - ThreadLocal, it also allocates a thread-local cache variable. This - is is a static structure of type tls_t: - - typedef struct - { - jlong id; - void *val; - } tls_t; - - When gcj generates a store that sets a ThreadLocal static field, it - also generates a call to setTLS(ptr). ptr is a pointer to a - function that returns the address of the cache variable in thread - local memory. ThreadLocal.setTLS(ptr) saves that function pointer - and also generates a unique ID that will be used to identify this - instance of ThreadLocal. So, the ThreadLocal instance is now - "tied" to that cache variable. - - The first time that ThreadLocal.set() is called in a particular - thread, we check the ID in the cache variable to see if it is the - same as the ID of this ThreadLocal instance. We see that it is - not, because all __thread variables are initialized to zero, so we - write the ID of this ThreadLocal and the value into the cache - variable. We also update the map of ThreadLocals on the heap; we - must do this for the benefit of the garbage collector. - - When get() is called, we look in the cache variable, check the ID, - see that it is the same as the ID of this ThreadLocal instance, and - return the value immediately. - - Whenever we need to invalidate the cache, we can do so by setting - ID to 0. - - This is safe even in degenerate cases such as assigning the same - ThreadLocal instance to multiple static fields or repeatedly - re-assigning a static field in multiple threads. If the cached - value doesn't belong to this ThreadLocal, we simply ignore it. + So, we create a pthread_key in each ThreadLocal object and use that + as a kind of "look-aside cache". When a ThreadLocal is set, we + also set the corresponding thread-specific value. When the + ThreadLocal is collected, we delete the key. This scheme is biased towards efficiency when get() is called much more frequently than set(). It is slightly slower than the @@ -110,19 +65,22 @@ details. */ */ -typedef struct -{ - jlong id; - void *val; -} tls_t; +#ifdef _POSIX_PTHREAD_SEMANTICS -static inline tls_t* -get_tls_addr (void *p) +class tls_t { - typedef tls_t* func (void); - func *fptr = (func*)p; +public: + pthread_key_t key; +}; - return fptr (); +void +java::lang::ThreadLocal::constructNative (void) +{ + tls_t *tls = (tls_t *)_Jv_Malloc (sizeof (tls_t)); + if (pthread_key_create (&tls->key, NULL) == 0) + TLSPointer = (::gnu::gcj::RawData *)tls; + else + _Jv_Free (tls); } void @@ -130,28 +88,27 @@ java::lang::ThreadLocal::set (::java::lang::Object *value) { if (TLSPointer != NULL) { - tls_t* tls_var_p = get_tls_addr (TLSPointer); - tls_var_p->val = value; - tls_var_p->id = id; - } + tls_t* tls = (tls_t*)TLSPointer; + pthread_setspecific (tls->key, value); + } - slowSet (value); + internalSet (value); } ::java::lang::Object * java::lang::ThreadLocal::get (void) { if (TLSPointer == NULL) - return slowGet (); + return internalGet (); - tls_t* tls_var_p = get_tls_addr (TLSPointer); + tls_t* tls = (tls_t*)TLSPointer; + void *obj = pthread_getspecific(tls->key); - if (tls_var_p->id == this->id) - return (::java::lang::Object *)tls_var_p->val; + if (obj) + return (::java::lang::Object *)obj; - ::java::lang::Object *value = slowGet (); - tls_var_p->val = value; - tls_var_p->id = this->id; + ::java::lang::Object *value = internalGet (); + pthread_setspecific (tls->key, value); return value; } @@ -161,11 +118,52 @@ java::lang::ThreadLocal::remove (void) { if (TLSPointer != NULL) { - tls_t* tls_var_p = get_tls_addr (TLSPointer); - tls_var_p->val = NULL; - tls_var_p->id = 0; + tls_t* tls = (tls_t*)TLSPointer; + pthread_setspecific (tls->key, NULL); + } + + internalRemove (); +} + +void +java::lang::ThreadLocal::finalize (void) +{ + if (TLSPointer != NULL) + { + tls_t* tls = (tls_t*)TLSPointer; + pthread_key_delete (tls->key); + _Jv_Free (tls); } +} + +#else + +void +java::lang::ThreadLocal::constructNative (void) +{ +} - slowRemove (); +void +java::lang::ThreadLocal::set (::java::lang::Object *value) +{ + internalSet (value); +} + +::java::lang::Object * +java::lang::ThreadLocal::get (void) +{ + return internalGet (); +} + +void +java::lang::ThreadLocal::remove (void) +{ + internalRemove (); +} + +void +java::lang::ThreadLocal::finalize (void) +{ } +#endif |