aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2006-10-13 12:53:36 +0000
committerAndrew Haley <aph@redhat.com>2006-10-13 12:53:36 +0000
commit81d174387ba4c17194f7e45bba6d5522dfddf481 (patch)
tree29c8b84d1d10ec914eb6fb0512dddbc6effe929f
parent53cad73923f715fea760022380abb07c6c9cc816 (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/ChangeLog8
-rw-r--r--gcc/java/class.c107
-rw-r--r--gcc/java/java-gimplify.c72
-rw-r--r--gcc/java/java-tree.h3
-rw-r--r--gcc/java/jcf-parse.c1
-rw-r--r--gcc/java/parse.y2
-rw-r--r--libjava/ChangeLog8
-rw-r--r--libjava/java/lang/ThreadLocal.java23
-rw-r--r--libjava/java/lang/natThreadLocal.cc148
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