示例#1
0
void
objc_registerClassPair(Class cls)
{
  Class metaClass;
  Class	existing;

  if (Nil == cls)
    {
      fprintf(stderr, "*** ERROR *** function objc_registerClassPair() called "
	"on Nil class pair '%s'\n", class_getName(cls));
    }
  existing = (Class)objc_lookUpClass (class_getName (cls));
  if (existing == cls)
    {
      return;	// Already registered
    }
  else if (Nil != existing)
    {
      fprintf(stderr, "*** ERROR *** function objc_registerClassPair() called "
	"for class pair with name ('%s') of existing class.\n",
	class_getName(cls));
      return;
    }

  // Initialize the dispatch table for the class and metaclass.
  metaClass = cls->class_pointer;
  __objc_update_dispatch_table_for_class(metaClass);
  __objc_update_dispatch_table_for_class(cls);
  __objc_add_class_to_hash(cls);
  // Add pointer from super class
  __objc_resolve_class_links();
}
示例#2
0
static void
_objc_unload_classes_in_branch(Class branch, void *kernel_module)
{
	if (branch == Nil){
		return;
	}
	
	/* It is important to save the next pointer before calling ourselves
	 * recursively since it is possible the class will be already deallocated
	 * when we return back to this function.
	 */
	Class c = branch->subclass_list;
	while (c != Nil){
		Class next_class = c->sibling_list;
		_objc_unload_classes_in_branch(c, kernel_module);
		
		c = next_class;
	}
	
	objc_debug_log("\t Checking class %s - module %p, sibling %p (%s)\n",
				   class_getName(branch), branch->kernel_module,
				   branch->sibling_list, branch->sibling_list == Nil ? "(null)" :
				   class_getName(branch->sibling_list));
	if (branch->kernel_module == kernel_module){
		/* Remove this node. */
		objc_class_unload(branch);
	}
}
示例#3
0
文件: class.cpp 项目: crwulff/darling
std::vector<const char*> ProcessClassesNew(const struct mach_header* mh, intptr_t slide, const char* segment, const char* section, uint32_t image_index)
{
	class_t **classes, **classes_end;
	unsigned long size;
	std::vector<const char*> classNames;

	classes = reinterpret_cast<class_t**>(
		getsectdata(mh, segment, section, &size)
	);

	if (nullptr != classes)
	{
		classes_end = classes + size / sizeof(class_t*);

		while (classes < classes_end)
		{
			Class c = RegisterClass(*classes, slide, image_index);
			classNames.push_back(class_getName(c));
			LOG << "Fixup @" << classes << " " << *classes << " -> " << c <<std::endl;
			*classes = (class_t*)c;

			classes++;
		}
	}

	return classNames;
}
示例#4
0
void __darwin_objc_exception_throw(objc_object* object)
{
	TRACE1(object);

	if (!object)
	{
		std::cerr << "NULL Objective-C exception thrown!\n";
		abort();
	}

	if (!m_lastBlock)
	{
		std::cerr << "Unhandled Objective-C exception: " << class_getName(object_getClass(object)) << '(' << object << ")\n";
		abort();
	}
	else
	{
		TryBlock* currentBlock = m_lastBlock;
		
		currentBlock->exceptionObject = object;
		m_lastBlock = m_lastBlock->previousBlock;

		longjmp(currentBlock->buffer, true);
	}
}
示例#5
0
文件: variable.c 项目: kyab/MacRuby
static VALUE
find_class_path(VALUE klass)
{
    struct fc_result arg;

    arg.name = 0;
    arg.path = 0;
    arg.klass = klass;
    arg.track = rb_cObject;
    arg.prev = 0;

    CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(rb_cObject);
    if (iv_dict != NULL) {
	ivar_dict_foreach(iv_dict, fc_i, (VALUE)&arg);
    }
    if (arg.path == 0) {
	st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg);
    }
    if (arg.path) {
	iv_dict = rb_class_ivar_dict_or_create(klass);
	CFDictionarySetValue(iv_dict, (const void *)id_classpath,
		(const void *)arg.path);
	CFDictionaryRemoveValue(iv_dict, (const void *)id_tmp_classpath);
	return arg.path;
    }
    if (!RCLASS_RUBY(klass)) {
	VALUE name = rb_str_new2(class_getName((Class)klass));
	iv_dict = rb_class_ivar_dict_or_create(klass);
	CFDictionarySetValue(iv_dict, (const void *)id_classpath,
		(const void *)name);
	CFDictionaryRemoveValue(iv_dict, (const void *)id_tmp_classpath);
	return name;
    }
    return Qnil;
}
示例#6
0
extern "C" __declspec(dllexport) void objc_exception_throw(void *exception)
{
    int typeCount = 0;

    //  Get count of all types in exception
    Class curType = object_getClass((id) exception);
    while (curType != nil) {
        typeCount++;

        curType = class_getSuperclass(curType);
    }

    typeCount++; //  For id

    __ObjC_CatchableTypeArray *exceptTypes = (__ObjC_CatchableTypeArray *)_alloca(sizeof(__ObjC_CatchableTypeArray) + sizeof(__ObjC_CatchableType *) * typeCount);

	//  Add exception type and all base types to throw information
    typeCount = 0;
    curType = object_getClass((id)exception);
    while (curType != nil) {
        exceptTypes->types[typeCount] = (__ObjC_CatchableType *)_alloca(sizeof(__ObjC_CatchableType));
        memset(exceptTypes->types[typeCount], 0, sizeof(__ObjC_CatchableType));
        exceptTypes->types[typeCount]->flags = 1;
        exceptTypes->types[typeCount]->mdisp = 0;
        exceptTypes->types[typeCount]->pdisp = -1;
        exceptTypes->types[typeCount]->vdisp = 0;
        exceptTypes->types[typeCount]->type = (const char *) alloca(32);
        memset((void *) exceptTypes->types[typeCount]->type, 0, 32);
        memcpy((char *)exceptTypes->types[typeCount]->type, class_getName(curType), strlen(class_getName(curType)));
        exceptTypes->types[typeCount]->size = 4;
        typeCount++;

        curType = class_getSuperclass(curType);
    }

    //  Add id
    exceptTypes->types[typeCount] = (__ObjC_CatchableType *)_alloca(sizeof(__ObjC_CatchableType));
    memset(exceptTypes->types[typeCount], 0, sizeof(__ObjC_CatchableType));
    exceptTypes->types[typeCount]->flags = 1;
    exceptTypes->types[typeCount]->mdisp = 0;
    exceptTypes->types[typeCount]->pdisp = -1;
    exceptTypes->types[typeCount]->vdisp = 0;
    exceptTypes->types[typeCount]->type = (const char *)alloca(32);
    memset((void *)exceptTypes->types[typeCount]->type, 0, 32);
    exceptTypes->types[typeCount]->size = 4;
    typeCount++;

    exceptTypes->count = typeCount;

    _ThrowInfo ti = 
    {
     0,
     NULL,
     NULL,
     (_CatchableTypeArray *) exceptTypes
    };

    _CxxThrowException(&exception, &ti);
}
示例#7
0
PRIVATE BOOL
_objc_unload_modules(struct objc_loader_module **begin,
					 struct objc_loader_module **end,
					 void *kernel_module)
{
	OBJC_LOCK_RUNTIME_FOR_SCOPE();
	
	struct objc_loader_module **module_ptr;
	for (module_ptr = begin; module_ptr < end; module_ptr++) {
		objc_debug_log("Checking module dependencies for %s\n",
					   (*module_ptr)->name);
		if (!_objc_module_check_dependencies_for_unloading(*module_ptr,
														   kernel_module)){
			objc_debug_log("Failed checking module dependencies for %s\n",
						   (*module_ptr)->name);
			return NO;
		}
	}
	
	objc_debug_log("No dependencies, unloading classes...\n");
	
	/*
	 * At this point, we can be certain that it is safe to unload all the
	 * classes and protocols.
	 */
	_objc_unload_classes_in_kernel_module(kernel_module);
	
	objc_debug_log("Unloading protocols...\n");
	
	for (module_ptr = begin; module_ptr < end; module_ptr++) {
		struct objc_loader_module *module = *module_ptr;
		for (int i = 0; i < module->symbol_table->protocol_count; ++i){
			objc_protocol_unload(module->symbol_table->protocols[i]);
		}
	}
	
	
	objc_debug_log("Unloading IMPs...\n");
	
	/*
	 * Now for the fun part. Go through all the IMPs...
	 */
	_objc_unload_IMPs_from_kernel_module(kernel_module);
	
	objc_debug_log("All done unloading module %s.\n", module_getname(kernel_module));
	
	objc_debug_log("SlowInit2: %p\n", objc_getClass("SlowInit2"));
	objc_log("Remaining classes:\n");
	unsigned int count;
	Class *classes = objc_copyClassList(&count);
	for (int i = 0; i < count; ++i){
		objc_log("\t [%02i] %s [%p]\n", i, class_getName(classes[i]), classes[i]);
	}
	objc_dealloc(classes, M_CLASS_TYPE);
	
	return YES;
}
示例#8
0
void
objc_disposeClassPair(Class cls)
{
  Class meta;

  if (cls == 0)
    {
      return;
    }
  meta = ((id) cls)->isa;

  if (objc_lookUpClass (class_getName (cls)) == (id)cls)
    {
      fprintf(stderr, "*** ERROR *** function objc_disposeClassPair() called "
	"on registered class pair '%s'\n", class_getName(cls));
      return;
    /*
       The runtime provides no mechanism to remove a class.
       The following code essentially frees the memory used by a class without
       fully removing it ... which obviously tends to cause random crashes
       later on if anything tries to use the class or to traverse data
       structures containing the class.
       Indeed, it's hard to see how this function could ever be made to work
       (what if there are subclasses of the class being removed, or if
       there are instances of the class?) even with changes to the runtime.
      
      // Remove from the runtime system so nothing tries updating the dtable
      // while we are freeing the class.
      objc_mutex_lock(__objc_runtime_mutex);
      safe_remove_from_subclass_list(meta);
      safe_remove_from_subclass_list(cls);
      objc_mutex_unlock(__objc_runtime_mutex);
    */
    }

  // Free the method and ivar lists.
  freeMethodLists(cls);
  freeMethodLists(meta);
  freeIvarLists(cls);

  // Free the class and metaclass
  free(meta);
  free(cls);
}
示例#9
0
static BOOL
_objc_can_unload_protocol(Protocol *p, Class root_class, void *kernel_module)
{
	for (Class c = root_class; c != Nil; c = c->sibling_list){
		if (c->kernel_module == kernel_module){
			/*
			 * We can safely assume that if the class is from this module,
			 * it doesn't matter if the protocol is adopted on this class
			 * or its subclasses since we've already run the class check.
			 */
			continue;
		}
		
		objc_debug_log("Checking protocol %p for class %s\n", p,
					   class_getName(c));
		objc_protocol_list *protocol_list = c->protocols;
		if (protocol_list != NULL){
			while (protocol_list != NULL) {
				for (int i = 0; i < protocol_list->size; ++i){
					if (protocol_list->list[i] == p){
						objc_log("Cannot unload protocol %s since it is used in"
								 " class %s and this class is declared in module"
								 " %s which is still loaded.\n",
								 p->name,
								 class_getName(c),
								 c->kernel_module == NULL ? "(null)" :
								 module_getname(c->kernel_module));
						return NO;
					}
				}
				protocol_list = protocol_list->next;
			}
		}
		
		if (c->subclass_list != Nil){
			if (!_objc_can_unload_protocol(p, c->subclass_list, kernel_module)){
				return NO;
			}
		}
	}
	
	return YES;
}
示例#10
0
// BAF:  This seems to be some garbage collection magic.  Not for us mortals to look at!
__private_extern__ Boolean __CFRuntimeIsFreedObject(id anObject) {
    if (!anObject) return false;
    static Class freedClass = Nil;
    if (!freedClass) freedClass = _objc_getFreedObjectClass();
    Class cls = object_getClass(anObject);
    if (cls == freedClass) return true;
    // in 64-bit, a future class has nil isa, and calling class_getName() on
    // such will crash so we do this test; zombie classes are not future classes
    if (objc_getClass((id)cls) == nil) return false;
    const char *cname = class_getName(cls);
    if (cname && 0 == strncmp(cname, "_NSZombie_", 10)) return true;
    return false;
}
示例#11
0
void printMethodsForClass(Class cls)
{
  unsigned int totalCount;
  Method *methods __attribute__((cleanup(free_methods))) = class_copyMethodList(cls, &totalCount);
  
  printf("=> List Methods For Class: %s (%u)\n", class_getName(cls), totalCount);
  for (unsigned int i = 0; i<totalCount; i++) {
    Method method = methods[i];
    SEL sel = method_getName(method);
    IMP imp = method_getImplementation(method);
    printf("    method<%p>: %s \n", imp, sel_getName(sel));
  }
  printf("\n");
  
}
示例#12
0
static void
_objc_unload_classes_in_kernel_module(void *kernel_module)
{
	Class root = objc_class_get_root_class_list();
	
	objc_debug_log("\t Unloading classes in module %p, root class %s\n",
				   kernel_module, root == Nil ? "(null)" : class_getName(root));
	
	Class c = root;
	while (c != Nil){
		Class next_class = c->sibling_list;
		_objc_unload_classes_in_branch(c, kernel_module);
		
		c = next_class;
	}
}
示例#13
0
文件: gc.c 项目: 1nueve/MacRuby
static int
rb_objc_yield_classes(VALUE of)
{
    const int count = objc_getClassList(NULL, 0);
    assert(count > 0);

    Class *buf = (Class *)alloca(sizeof(Class) * count);
    objc_getClassList(buf, count);
    const bool only_modules = of == rb_cModule;

    int rcount = 0;
    for (int i = 0; i < count; i++) {
	Class k = buf[i];
	if (class_getName(k)[0] == '_') {
	    continue;
	}

	if (only_modules) {
	    if (!RCLASS_MODULE(k)) {
		continue;
	    }
	}
	else {
	    bool nsobject_based = false;
	    Class sk = k;
	    do {
		sk = (Class)RCLASS_SUPER(sk);
		if (sk == (Class)rb_cNSObject) {
		    nsobject_based = true;
		    break;
		}
	    }
	    while (sk != NULL);
	    if (!nsobject_based) {
		continue;
	    }
	}

	rb_yield((VALUE)k);
	RETURN_IF_BROKEN();
	rcount++;
    }

    return rcount;
}
示例#14
0
static BOOL
_objc_can_unload_class(Class cl, void *kernel_module)
{
	for (Class c = cl; c != Nil; c = c->sibling_list){
		if (c->kernel_module != kernel_module){
			objc_log("Cannot unload class %s since it is declared in module %s"
					 " and is a subclass of a class declared in this module.\n",
					 class_getName(c), module_getname(kernel_module));
			return NO;
		}
		
		if (c->subclass_list != Nil
			&& !_objc_can_unload_class(c->subclass_list, kernel_module)){
			return NO;
		}
	}
	return YES;
}
示例#15
0
 void
 SortByTotalCount (const ObjCClasses &objc_classes, bool print)
 {
     if (m_sort_type != eSortTypeCount && m_size > 0)
     {
         ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_count);            
         m_sort_type = eSortTypeCount;
     }
     if (print && m_size > 0)
     {
         puts("Objective C objects by total count:");
         puts("Count    Class Name");
         puts("-------- -----------------------------------------------------------------");
         for (uint32_t i=0; i<m_size && m_entries[i].count > 0; ++i)
         {
             printf ("%8u %s\n", m_entries[i].count, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx)));
         }            
     }
 }
示例#16
0
 void
 SortByTotalBytes (const ObjCClasses &objc_classes, bool print)
 {
     if (m_sort_type != eSortTypeBytes && m_size > 0)
     {
         ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_bytes);            
         m_sort_type = eSortTypeBytes;
     }
     if (print && m_size > 0)
     {
         puts("Objective C objects by total bytes:");
         puts("Total Bytes Class Name");
         puts("----------- -----------------------------------------------------------------");
         for (uint32_t i=0; i<m_size && m_entries[i].bytes > 0; ++i)
         {
             printf ("%11llu %s\n", m_entries[i].bytes, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx)));
         }            
     }
 }
示例#17
0
文件: gc.c 项目: prototype/MacRuby
static int
rb_objc_yield_classes(VALUE of)
{
    int i, count, rcount;
    Class *buf;

    count = objc_getClassList(NULL, 0);
    assert(count > 0);

    buf = (Class *)alloca(sizeof(Class) * count);
    objc_getClassList(buf, count);

    for (i = rcount = 0; i < count; i++) {
	Class sk, k = buf[i];
	bool nsobject_based;

	if (class_getName(k)[0] == '_')
	    continue;

	if (of == rb_cModule && !RCLASS_MODULE(k))
	    continue;

	nsobject_based = false;
	sk = k;
	do {
	    sk = (Class)RCLASS_SUPER(sk);
	    if (sk == (Class)rb_cNSObject) {
		nsobject_based = true;
		break;
	    }
	}
	while (sk != NULL);	

	if (nsobject_based) {
	    rb_yield((VALUE)k);
	    RETURN_IF_BROKEN();
	    rcount++;
	}
    }

    return rcount;
}
示例#18
0
static void
_objc_unload_IMPs_in_class(Class cl, void *kernel_module){
	if (cl->methods == NULL){
		return;
	}
	
	objc_debug_log("Unloading IMPs in class %s\n", class_getName(cl));
	
	for (objc_method_list *list = cl->methods; list != NULL; list = list->next){
		objc_debug_log("\t [%p]\n", list);
		for (int i = 0; i < list->size; ++i){
			Method m = &list->list[i];
			if (module_contains_IMP(kernel_module, m->implementation)){
				objc_debug_log("\t\t [%02i] - %s\n", i, sel_getName(m->selector));
				IMP old_imp = m->implementation;
				m->implementation = objc_unloaded_module_method;
				
				/* Since the selector name and types can actually be also
				 * allocated in the module, we better update the strings
				 * as well.
				 */
				m->selector_name = "__objc_unloaded_method";
				m->selector_types = sizeof(void*) == 4 ? "v8@0:4" : "v16@0:8";
				
				/* Update the dtable! */
				SparseArray *arr = (SparseArray*)cl->dtable;
				if (arr != NULL && arr != uninstalled_dtable){
					struct objc_slot *slot = SparseArrayLookup(arr, m->selector);
					if (slot != NULL && slot->implementation == old_imp){
						slot->implementation = m->implementation;
						
						slot->types = m->selector_types;
						
						++slot->version;
					}
				}
			}
		}
	}
}
示例#19
0
static void
fill_ocache(struct mcache *cache, VALUE self, Class klass, IMP imp, SEL sel,
	    Method method, int argc)
{
    cache->flag = MCACHE_OCALL;
    cache->sel = sel;
    cache->klass = klass;
    cache->as.ocall.imp = imp;
    cache->as.ocall.argc = argc;
    cache->as.ocall.bs_method = GET_CORE()->find_bs_method(klass, sel);

    char types[200];
    if (!rb_objc_get_types(self, klass, sel, method, cache->as.ocall.bs_method,
		types, sizeof types)) {
	printf("cannot get encoding types for %c[%s %s]\n",
		class_isMetaClass(klass) ? '+' : '-',
		class_getName(klass),
		sel_getName(sel));
	abort();
    }
    bool variadic = false;
    if (cache->as.ocall.bs_method != NULL
	    && cache->as.ocall.bs_method->variadic && method != NULL) {
	// TODO honor printf_format
	const int real_argc = rb_method_getNumberOfArguments(method) - 2;
	if (real_argc < argc) {
	    const size_t s = strlen(types);
	    assert(s + argc - real_argc < sizeof types);
	    for (int i = real_argc; i < argc; i++) {
		strlcat(types, "@", sizeof types);
	    }
	    argc = real_argc;
	}
	variadic = true;
    }
    cache->as.ocall.stub = (rb_vm_objc_stub_t *)GET_CORE()->gen_stub(types,
	    variadic, argc, true);
}
示例#20
0
文件: gc.c 项目: 1nueve/MacRuby
static void 
print_memory_object(task_t task, void *context, unsigned type_mask,
	vm_range_t *ranges, unsigned range_count)
{
    const size_t min_size = *(size_t *)context;
    for (vm_range_t *r = ranges, *end = ranges + range_count; r < end; r++) {
	const size_t size = auto_zone_size(__auto_zone, (void *)r->address);
	if (size >= min_size) {
	    printf("address %p size %ld rc %d layout type ",
		    (void *)r->address, size,
		    auto_zone_retain_count(__auto_zone, (void *)r->address));
	    switch (auto_zone_get_layout_type(__auto_zone,
			(void *)r->address)) {
		case AUTO_OBJECT:
		    printf("object (class %s)\n",
			    class_getName(object_getClass((void *)r->address)));
		    break;
		default:
		    printf("memory\n");
		    break;
	    }
	}
    }
}
示例#21
0
id UndefinedClassInitialize(id obj, SEL sel)
{
	fprintf(stderr, "Undefined class %s used\n", class_getName(object_getClass(obj)));
	return obj;
}
示例#22
0
const char *createAspectMethodPrefix(Class patchClass)
{
  return xace_concat(2, class_getName(patchClass), metamacro_stringify(_XAAspectMethodBodyJoiner));
}
示例#23
0
VALUE
rb_vm_dispatch(void *_vm, struct mcache *cache, VALUE top, VALUE self,
	Class klass, SEL sel, rb_vm_block_t *block, unsigned char opt,
	int argc, const VALUE *argv)
{
    RoxorVM *vm = (RoxorVM *)_vm;

#if ROXOR_VM_DEBUG
    bool cached = true;
#endif
    bool cache_method = true;

    Class current_super_class = vm->get_current_super_class();
    SEL current_super_sel = vm->get_current_super_sel();

    if (opt & DISPATCH_SUPER) {
	// TODO
	goto recache;
    }

    if (cache->sel != sel || cache->klass != klass || cache->flag == 0) {
recache:
#if ROXOR_VM_DEBUG
	cached = false;
#endif

	Method method;
	if (opt & DISPATCH_SUPER) {
	    if (!sel_equal(klass, current_super_sel, sel)) {
		current_super_sel = sel;
		current_super_class = klass;
	    }
	    else {
		// Let's make sure the current_super_class is valid before
		// using it; we check this by verifying that it's a real
		// super class of the current class, as we may be calling
		// a super method of the same name but on a totally different
		// class hierarchy.
		Class k = klass;
		bool current_super_class_ok = false;
		while (k != NULL) {
		    if (k == current_super_class) {
			current_super_class_ok = true;
			break;
		    }
		    k = class_getSuperclass(k);
		}
		if (!current_super_class_ok) {
		    current_super_class = klass;
		}
	    }
	    method = rb_vm_super_lookup(current_super_class, sel,
		    &current_super_class);
	}
	else {
	    current_super_sel = 0;
	    method = class_getInstanceMethod(klass, sel);
	}

	if (method != NULL) {
recache2:
	    IMP imp = method_getImplementation(method);

	    if (UNAVAILABLE_IMP(imp)) {
		// Method was undefined.
		goto call_method_missing;
	    }

	    rb_vm_method_node_t *node = GET_CORE()->method_node_get(method);

	    if (node != NULL) {
		// ruby call
		fill_rcache(cache, klass, sel, node);
	    }
	    else {
		// objc call
		fill_ocache(cache, self, klass, imp, sel, method, argc);
	    }

	    if (opt & DISPATCH_SUPER) {
		cache->flag |= MCACHE_SUPER;
	    }
	}
	else {
	    // Method is not found...

#if !defined(MACRUBY_STATIC)
	    // Force a method resolving, because the objc cache might be
	    // wrong.
	    if (rb_vm_resolve_method(klass, sel)) {
		goto recache;
	    }
#endif

	    // Does the receiver implements -forwardInvocation:?
	    if ((opt & DISPATCH_SUPER) == 0
		    && rb_objc_supports_forwarding(self, sel)) {

//#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
		// In earlier versions of the Objective-C runtime, there seems
		// to be a bug where class_getInstanceMethod isn't atomic,
		// and might return NULL while at the exact same time another
		// thread registers the related method.
		// As a work-around, we double-check if the method still does
		// not exist here. If he does, we can dispatch it properly.

		// note: OS X 10.7 also, this workaround is required. see #1476
		method = class_getInstanceMethod(klass, sel);
		if (method != NULL) {
		    goto recache2;
		}
//#endif
		fill_ocache(cache, self, klass, (IMP)objc_msgSend, sel, NULL,
			argc);
		goto dispatch;
	    }

	    // Let's see if are not trying to call a Ruby method that accepts
	    // a regular argument then an optional Hash argument, to be
	    // compatible with the Ruby specification.
	    const char *selname = (const char *)sel;
	    size_t selname_len = strlen(selname);
	    if (argc > 1) {
		const char *p = strchr(selname, ':');
		if (p != NULL && p + 1 != '\0') {
		    char *tmp = (char *)malloc(selname_len + 1);
		    assert(tmp != NULL);
		    strncpy(tmp, selname, p - selname + 1);
		    tmp[p - selname + 1] = '\0';
		    sel = sel_registerName(tmp);
		    VALUE h = rb_hash_new();
		    bool ok = true;
		    p += 1;
		    for (int i = 1; i < argc; i++) {
			const char *p2 = strchr(p, ':');
			if (p2 == NULL) {
			    ok = false;
			    break;
			}
			strlcpy(tmp, p, selname_len);
			tmp[p2 - p] = '\0';
			p = p2 + 1; 
			rb_hash_aset(h, ID2SYM(rb_intern(tmp)), argv[i]);
		    }
		    free(tmp);
		    tmp = NULL;
		    if (ok) {
			argc = 2;
			((VALUE *)argv)[1] = h; // bad, I know...
			Method m = class_getInstanceMethod(klass, sel);
			if (m != NULL) {	
			    method = m;
			    cache_method = false;
			    goto recache2;
			}
		    }
		}
	    }

	    // Enable helpers for classes which are not RubyObject based.
	    if ((RCLASS_VERSION(klass) & RCLASS_IS_OBJECT_SUBCLASS)
		    != RCLASS_IS_OBJECT_SUBCLASS) {
		// Let's try to see if we are not given a helper selector.
		SEL new_sel = helper_sel(selname, selname_len);
		if (new_sel != NULL) {
		    Method m = class_getInstanceMethod(klass, new_sel);
		    if (m != NULL) {
		    	sel = new_sel;
		    	method = m;
		    	// We need to invert arguments because
		    	// #[]= and setObject:forKey: take arguments
		    	// in a reverse order
		    	if (new_sel == selSetObjectForKey && argc == 2) {
		    	    VALUE swap = argv[0];
		    	    ((VALUE *)argv)[0] = argv[1];
		    	    ((VALUE *)argv)[1] = swap;
		    	    cache_method = false;
		    	}
		    	goto recache2;
		    }
		}
	    }

	    // Let's see if we are not trying to call a BridgeSupport function.
	    if (selname[selname_len - 1] == ':') {
		selname_len--;
	    }
	    std::string name(selname, selname_len);
	    bs_element_function_t *bs_func = GET_CORE()->find_bs_function(name);
	    if (bs_func != NULL) {
		if ((unsigned)argc < bs_func->args_count
			|| ((unsigned)argc > bs_func->args_count
				&& bs_func->variadic == false)) {
		    rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
			argc, bs_func->args_count);
		}
		std::string types;
		vm_gen_bs_func_types(argc, argv, bs_func, types);

		cache->flag = MCACHE_FCALL;
		cache->sel = sel;
		cache->klass = klass;
		cache->as.fcall.bs_function = bs_func;
		cache->as.fcall.imp = (IMP)dlsym(RTLD_DEFAULT, bs_func->name);
		assert(cache->as.fcall.imp != NULL);
		cache->as.fcall.stub = (rb_vm_c_stub_t *)GET_CORE()->gen_stub(
			types, bs_func->variadic, bs_func->args_count, false);
	    }
	    else {
		// Still nothing, then let's call #method_missing.
		goto call_method_missing;
	    }
	}
    }

dispatch:
    if (cache->flag & MCACHE_RCALL) {
	if (!cache_method) {
	    cache->flag = 0;
	}

#if ROXOR_VM_DEBUG
	printf("ruby dispatch %c[<%s %p> %s] (imp %p block %p argc %d opt %d cache %p cached %s)\n",
		class_isMetaClass(klass) ? '+' : '-',
		class_getName(klass),
		(void *)self,
		sel_getName(sel),
		cache->as.rcall.node->ruby_imp,
		block,
		argc,
		opt,
		cache,
		cached ? "true" : "false");
#endif

	bool block_already_current = vm->is_block_current(block);
	Class current_klass = vm->get_current_class();
	if (!block_already_current) {
	    vm->add_current_block(block);
	}
	vm->set_current_class(NULL);

	Class old_current_super_class = vm->get_current_super_class();
	vm->set_current_super_class(current_super_class);
	SEL old_current_super_sel = vm->get_current_super_sel();
	vm->set_current_super_sel(current_super_sel);

	const bool should_pop_broken_with =
	    sel != selInitialize && sel != selInitialize2;

	struct Finally {
	    bool block_already_current;
	    Class current_class;
	    Class current_super_class;
	    SEL current_super_sel;
	    bool should_pop_broken_with;
	    RoxorVM *vm;
	    Finally(bool _block_already_current, Class _current_class,
		    Class _current_super_class, SEL _current_super_sel,
		    bool _should_pop_broken_with, RoxorVM *_vm) {
		block_already_current = _block_already_current;
		current_class = _current_class;
		current_super_class = _current_super_class;
		current_super_sel = _current_super_sel;
		should_pop_broken_with = _should_pop_broken_with;
		vm = _vm;
	    }
	    ~Finally() {
		if (!block_already_current) {
		    vm->pop_current_block();
		}
		vm->set_current_class(current_class);
		if (should_pop_broken_with) {
		    vm->pop_broken_with();
		}
		vm->set_current_super_class(current_super_class);
		vm->set_current_super_sel(current_super_sel);
		vm->pop_current_binding();
	    }
	} finalizer(block_already_current, current_klass,
		old_current_super_class, old_current_super_sel,
		should_pop_broken_with, vm);

	// DTrace probe: method__entry
	if (MACRUBY_METHOD_ENTRY_ENABLED()) {
	    char *class_name = (char *)rb_class2name((VALUE)klass);
	    char *method_name = (char *)sel_getName(sel);
	    char file[PATH_MAX];
	    unsigned long line = 0;
	    GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line,
		    NULL, 0);
	    MACRUBY_METHOD_ENTRY(class_name, method_name, file, line);
	}

	VALUE v = ruby_dispatch(top, self, sel, cache->as.rcall.node,
		opt, argc, argv);

	// DTrace probe: method__return
	if (MACRUBY_METHOD_RETURN_ENABLED()) {
	    char *class_name = (char *)rb_class2name((VALUE)klass);
	    char *method_name = (char *)sel_getName(sel);
	    char file[PATH_MAX];
	    unsigned long line = 0;
	    GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line,
		    NULL, 0);
	    MACRUBY_METHOD_RETURN(class_name, method_name, file, line);
	}

	return v;
    }
    else if (cache->flag & MCACHE_OCALL) {
	if (cache->as.ocall.argc != argc) {
	    goto recache;
	}
	if (!cache_method) {
	    cache->flag = 0;
	}

	if (block != NULL) {
	    rb_warn("passing a block to an Objective-C method - " \
		    "will be ignored");
	}
	else if (sel == selNew) {
	    if (self == rb_cNSMutableArray) {
		self = rb_cRubyArray;
	    }
	}
	else if (sel == selClass) {
	    // Because +[NSObject class] returns self.
	    if (RCLASS_META(klass)) {
		return RCLASS_MODULE(self) ? rb_cModule : rb_cClass;
	    }
	    // Because the CF classes should be hidden, for Ruby compat.
	    if (self == Qnil) {
		return rb_cNilClass;
	    }
	    if (self == Qtrue) {
		return rb_cTrueClass;
	    }
	    if (self == Qfalse) {
		return rb_cFalseClass;
	    }
	    return rb_class_real((VALUE)klass, true);
	}

#if ROXOR_VM_DEBUG
	printf("objc dispatch %c[<%s %p> %s] imp=%p cache=%p argc=%d (cached=%s)\n",
		class_isMetaClass(klass) ? '+' : '-',
		class_getName(klass),
		(void *)self,
		sel_getName(sel),
		cache->as.ocall.imp,
		cache,
		argc,
		cached ? "true" : "false");
#endif

	id ocrcv = RB2OC(self);

 	if (cache->as.ocall.bs_method != NULL) {
	    Class ocklass = object_getClass(ocrcv);
	    for (int i = 0; i < (int)cache->as.ocall.bs_method->args_count;
		    i++) {
		bs_element_arg_t *arg = &cache->as.ocall.bs_method->args[i];
		if (arg->sel_of_type != NULL) {
		    // BridgeSupport tells us that this argument contains a
		    // selector of the given type, but we don't have any
		    // information regarding the target. RubyCocoa and the
		    // other ObjC bridges do not really require it since they
		    // use the NSObject message forwarding mechanism, but
		    // MacRuby registers all methods in the runtime.
		    //
		    // Therefore, we apply here a naive heuristic by assuming
		    // that either the receiver or one of the arguments of this
		    // call is the future target.
		    const int arg_i = arg->index;
		    assert(arg_i >= 0 && arg_i < argc);
		    if (argv[arg_i] != Qnil) {
			ID arg_selid = rb_to_id(argv[arg_i]);
			SEL arg_sel = sel_registerName(rb_id2name(arg_selid));

			if (reinstall_method_maybe(ocklass, arg_sel,
				    arg->sel_of_type)) {
			    goto sel_target_found;
			}
			for (int j = 0; j < argc; j++) {
			    if (j != arg_i && !SPECIAL_CONST_P(argv[j])) {
				if (reinstall_method_maybe(*(Class *)argv[j],
					    arg_sel, arg->sel_of_type)) {
				    goto sel_target_found;
				}
			    }
			}
		    }

sel_target_found:
		    // There can only be one sel_of_type argument.
		    break; 
		}
	    }
	}

	return __rb_vm_objc_dispatch(cache->as.ocall.stub, cache->as.ocall.imp,
		ocrcv, sel, argc, argv);
    }
    else if (cache->flag & MCACHE_FCALL) {
#if ROXOR_VM_DEBUG
	printf("C dispatch %s() imp=%p argc=%d (cached=%s)\n",
		cache->as.fcall.bs_function->name,
		cache->as.fcall.imp,
		argc,
		cached ? "true" : "false");
#endif
	return (*cache->as.fcall.stub)(cache->as.fcall.imp, argc, argv);
    }

    printf("method dispatch is b0rked\n");
    abort();

call_method_missing:
    // Before calling method_missing, let's check if we are not in the following
    // cases:
    //
    //    def foo; end; foo(42)
    //    def foo(x); end; foo
    //
    // If yes, we need to raise an ArgumentError exception instead.
    const char *selname = sel_getName(sel);
    const size_t selname_len = strlen(selname);
    SEL new_sel = 0;

    if (argc > 0 && selname[selname_len - 1] == ':') {
	char buf[100];
	assert(sizeof buf > selname_len - 1);
	strlcpy(buf, selname, sizeof buf);
	buf[selname_len - 1] = '\0';
	new_sel = sel_registerName(buf);
    }
    else if (argc == 0) {
	char buf[100];
	snprintf(buf, sizeof buf, "%s:", selname);
	new_sel = sel_registerName(buf);
    }
    if (new_sel != 0) {
	Method m = class_getInstanceMethod(klass, new_sel);
	if (m != NULL) {
	    IMP mimp = method_getImplementation(m);
	    if (!UNAVAILABLE_IMP(mimp)) {
		unsigned expected_argc;
		rb_vm_method_node_t *node = GET_CORE()->method_node_get(m);
		if (node != NULL) {
		    expected_argc = node->arity.min;
		}
		else {
		    expected_argc = rb_method_getNumberOfArguments(m);
		    expected_argc -= 2; // removing receiver and selector
		}
		rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
			argc, expected_argc);
	    }
	}
    }

    rb_vm_method_missing_reason_t status;
    if (opt & DISPATCH_VCALL) {
	status = METHOD_MISSING_VCALL;
    }
    else if (opt & DISPATCH_SUPER) {
	status = METHOD_MISSING_SUPER;
    }
    else {
	status = METHOD_MISSING_DEFAULT;
    }
    return method_missing((VALUE)self, sel, block, argc, argv, status);
}
示例#24
0
const char *createSupercallerMethodPrefix(Class targetClass)
{
  return xace_concat(2, class_getName(targetClass), metamacro_stringify(_XACallSuperKeyword));
}
示例#25
0
const char *object_getClassName(id obj)
{
	CHECK_ARG(obj);
	return class_getName(object_getClass(obj));
}
示例#26
0
文件: class.c 项目: Strongc/WinObjC
const char* object_getClassName(id obj) {
    return class_getName(object_getClass(obj));
}
示例#27
0
文件: class.cpp 项目: crwulff/darling
Class RegisterClass(const class_t* cls, intptr_t slide, uint32_t image_index)
{
	if (nullptr == cls)
	{
		return nullptr;
	}

	auto & g_classPointers = getClassPointers();
	auto itClass = g_classPointers.find(cls);
	if (itClass != g_classPointers.end())
	{
		LOG << "Found existing class @" << itClass->second << std::endl;
		return itClass->second;
	}

	Class super = RegisterClass(cls->superclass, slide, image_index);

	LOG << "...superclass is @" << super << std::endl;
	if (nullptr != super)
	{
		LOG << "...superclass name " << (((uintptr_t)super != (uintptr_t)cls->superclass) ? cls->superclass->data()->className : class_getName(super)) << std::endl;
		LOG << "...super name " << class_getName(super) << std::endl;
	}

	if (nullptr == cls->data())
	{
		// TODO: Is this a bad pointer filled in, or are we supposed to do something different with this?
		// This is from when we call RegisterClass recursively sometimes...
		std::cerr << "Error - Null class data at class @" << cls << std::endl;
		return nullptr;
	}

	if (nullptr == cls->data()->className)
	{
		// TODO: Is this a bad pointer filled in, or are we supposed to do something different with this?
		// This is from when we call RegisterClass recursively sometimes...
		std::cerr << "Error - Null class name at class @" << cls << std::endl;
		return nullptr;
	}

	LOG << "Processing ObjC class " << cls->data()->className << std::endl;

	Class sameClass = (Class)objc_getClass(cls->data()->className);
	if (nullptr != sameClass)
	{
		LOG << "Found a class with the same name @" << sameClass << std::endl;
		return sameClass;
	}

	LOG << "obj_allocateClassPair(" << super << ", " << cls->data()->className << ")" << std::endl;

	Class conv = objc_allocateClassPair(super, cls->data()->className, 0);

	if (nullptr == conv)
	{
		std::cerr << "Failed to allocate class " << cls->data()->className << std::endl;
		return nullptr;
	}

	Class meta = object_getClass(id(conv));

	const class_ro_t* ro = cls->data();

	if (ro->baseMethods)
		ConvertMethodListGen(conv, ro->baseMethods, image_index);
	if (g_classPointers.find(cls->isa) == g_classPointers.end())
	{
		const class_ro_t* roMeta = cls->isa->data();
		if (roMeta->baseMethods)
			ConvertMethodListGen(meta, roMeta->baseMethods, image_index);
	}
	if (ro->ivars)
		ConvertIvarList(conv, ro->ivars);
	if (ro->baseProtocols)
		AddClassProtocols(conv, ro->baseProtocols, slide);
	if (ro->baseProperties)
	{
		ConvertProperties(ro->baseProperties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); bug_gnustepFixPropertyCount(conv); });
	}

	// conv->instance_size = ro->instSize;

	objc_registerClassPair(conv);
	
	LOG << "ObjC class " << cls->data()->className << " now @" << conv << std::endl;
	g_classPointers[cls] = conv;
	g_classPointers[conv] = conv;
	g_classPointers[meta] = meta;

	return conv;
}
示例#28
0
void* UndefMgr::generateNew(const char* name)
{
	bool isClass = (strncmp(name, "OBJC_CLASS", 10) == 0);
	bool isMetaClass = (strncmp(name, "OBJC_METACLASS", 14) == 0);

	if (isClass || isMetaClass)
	{
		// Strip the OBJC_CLASS_$_ or OBJC_METACLASS_$_
		name =  &name[(isMetaClass) ? 17 : 13];

		// Objective-C class or metaclass info
		static std::map<std::string, Class> undefClasses;
		Class classStub = nullptr;
		auto classIter = undefClasses.find(name);
		if (classIter != undefClasses.end())
		{
			classStub = classIter->second;
		}
		else if (NULL == (classStub = (Class)objc_getClass(name)))
		{
			classStub = objc_allocateClassPair(nullptr, name, 0);
			if (isMetaClass)
			{
				// Put in a dummy initialize method that lets us know the class got used
				IMP imp = reinterpret_cast<IMP>(&UndefinedClassInitialize);
				SEL sel = sel_registerTypedName_np("initialize", NULL);
				class_addMethod(object_getClass(reinterpret_cast<id>(classStub)), sel, imp, NULL);
			}
			objc_registerClassPair(classStub);
			Darling::MachOMgr::instance()->registerNativeClass(object_getClass(reinterpret_cast<id>(classStub)));
			Darling::MachOMgr::instance()->registerNativeClass(classStub);
			fprintf(stderr, "Undef class for class %s at %p\n", class_getName(classStub), classStub);
			undefClasses[name] = classStub;
		}

		return (isClass) ? classStub : object_getClass(reinterpret_cast<id>(classStub));
	}
	else if (strncmp(name, "OBJC_IVAR", 9) == 0)
	{
		// Objective-C ivar
		typedef struct 
		{
			const char *name;
			const char *type;
			int         offset;
		} objc_ivar;

		objc_ivar *ivarStub = new objc_ivar;
		ivarStub->name = &name[12];
		ivarStub->type = "";
		ivarStub->offset = 0;
		return ivarStub;
	}
	else
	{
		// Generate a function stub
		UndefinedFunction * uf = new UndefinedFunction();
		uf->init(name);
		return uf->getPointer();
	}
}