+ struct sarray *dtable;
+ struct sarray *super_dtable;
+
+ /* This table could be initialized in init.c. We cannot use the
+ class name since the class maintains the instance methods and the
+ meta class maintains the the class methods yet both share the
+ same name. Classes should be unique in any program. */
+ if (! prepared_dtable_table)
+ prepared_dtable_table
+ = objc_hash_new (32,
+ (hash_func_type) objc_hash_ptr,
+ (compare_func_type) objc_compare_ptrs);
+
+ /* If the class has not yet had its class links resolved, we must
+ re-compute all class links. */
+ if (! CLS_ISRESOLV (cls))
+ __objc_resolve_class_links ();
+
+ assert (cls);
+ assert (cls->dtable == __objc_uninstalled_dtable);
+
+ /* If there is already a prepared dtable for this class, we must
+ replace it with a new version (since there must have been methods
+ added to or otherwise modified in the class while executing
+ +initialize, and the table needs to be recomputed. */
+ dtable = __objc_prepared_dtable_for_class (cls);
+ if (dtable != 0)
+ {
+ objc_hash_remove (prepared_dtable_table, cls);
+ sarray_free (dtable);
+ }
+
+ /* Now prepare the dtable for population. */
+ assert (cls != cls->super_class);
+ if (cls->super_class)
+ {
+ /* Inherit the method list from the super class. Yet the super
+ class may still be initializing in the case when a class
+ cluster sub class initializes its super classes. */
+ if (cls->super_class->dtable == __objc_uninstalled_dtable)
+ __objc_install_dtable_for_class (cls->super_class);
+
+ super_dtable = cls->super_class->dtable;
+ /* If the dispatch table is not yet installed, we are still in
+ the process of executing +initialize. Yet the dispatch table
+ should be available. */
+ if (super_dtable == __objc_uninstalled_dtable)
+ super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
+
+ assert (super_dtable);
+ dtable = sarray_lazy_copy (super_dtable);
+ }
+ else
+ dtable = sarray_new (__objc_selector_max_index, 0);
+
+ __objc_install_methods_in_dtable (dtable, cls->methods);
+
+ objc_hash_add (&prepared_dtable_table,
+ cls,
+ dtable);
+}
+
+/* This wrapper only exists to allow an easy replacement of the lookup
+ implementation and it is expected that the compiler will optimize
+ it away. */
+static struct sarray *
+__objc_prepared_dtable_for_class (Class cls)
+{
+ struct sarray *dtable = 0;
+ assert (cls);
+ if (prepared_dtable_table)
+ dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
+ /* dtable my be nil, since we call this to check whether we are
+ currently preparing before we start preparing. */
+ return dtable;
+}
+
+/* Helper function for messages sent to CLS or implementation pointers
+ retrieved from CLS during +initialize before the dtable is
+ installed. When a class implicitly initializes another class which
+ in turn implicitly invokes methods in this class, before the
+ implementation of +initialize of CLS completes, this returns the
+ expected implementation. Forwarding remains the responsibility of
+ objc_msg_lookup. This function should only be called under the
+ global lock. */
+static IMP
+__objc_get_prepared_imp (Class cls,SEL sel)
+{
+ struct sarray *dtable;
+ IMP imp;
+
+ assert (cls);
+ assert (sel);
+ assert (cls->dtable == __objc_uninstalled_dtable);
+ dtable = __objc_prepared_dtable_for_class (cls);
+
+ assert (dtable);
+ assert (dtable != __objc_uninstalled_dtable);
+ imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
+
+ /* imp may be Nil if the method does not exist and we may fallback
+ to the forwarding implementation later. */
+ return imp;
+}
+
+/* When this function is called +initialize should be completed. So
+ now we are safe to install the dispatch table for the class so that
+ they become available for other threads that may be waiting in the
+ lock. */
+static void
+__objc_install_prepared_dtable_for_class (Class cls)
+{
+ assert (cls);
+ assert (cls->dtable == __objc_uninstalled_dtable);
+ cls->dtable = __objc_prepared_dtable_for_class (cls);
+
+ assert (cls->dtable);
+ assert (cls->dtable != __objc_uninstalled_dtable);
+ objc_hash_remove (prepared_dtable_table, cls);