[macruby-changes] [240] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun Jun 1 17:20:35 PDT 2008


Revision: 240
          http://trac.macosforge.org/projects/ruby/changeset/240
Author:   lsansonetti at apple.com
Date:     2008-06-01 17:20:34 -0700 (Sun, 01 Jun 2008)

Log Message:
-----------
fix for #48, support for passing pointers to boxed types, support for the already_retained retval attribute and resourceful CF objectx

Modified Paths:
--------------
    MacRuby/trunk/bs.c
    MacRuby/trunk/bs.h
    MacRuby/trunk/instruby.rb
    MacRuby/trunk/objc.m
    MacRuby/trunk/sample-macruby/Scripts/hello_world.rb

Added Paths:
-----------
    MacRuby/trunk/markgc.c
    MacRuby/trunk/sample-macruby/Scripts/circle.rb

Modified: MacRuby/trunk/bs.c
===================================================================
--- MacRuby/trunk/bs.c	2008-05-30 22:45:25 UTC (rev 239)
+++ MacRuby/trunk/bs.c	2008-06-02 00:20:34 UTC (rev 240)
@@ -1096,7 +1096,21 @@
     free(protocol_name);
 
   xmlFreeTextReader(reader);
-  
+
+  if (success && options == BS_PARSE_OPTIONS_LOAD_DYLIBS) {
+    char *p, buf[PATH_MAX];
+    strncpy(buf, path, sizeof buf);
+    p = strrchr(buf, '.');
+    assert(p != NULL);
+    strlcpy(p, ".dylib", p - path - 1);
+    if (access(buf, R_OK) == 0) {
+      if (dlopen(buf, RTLD_LAZY) == NULL) {
+        *error = dlerror();
+        success = false;
+      }
+    }
+  }
+
   return success;
 }
 

Modified: MacRuby/trunk/bs.h
===================================================================
--- MacRuby/trunk/bs.h	2008-05-30 22:45:25 UTC (rev 239)
+++ MacRuby/trunk/bs.h	2008-06-02 00:20:34 UTC (rev 240)
@@ -202,7 +202,10 @@
   (const char *path, bs_element_type_t type, void *value, void *context);
 
 typedef enum {
-  BS_PARSE_DEFAULT = 0
+  /* Default option: parse bridge support files. */
+  BS_PARSE_OPTIONS_DEFAULT = 0,
+  /* Parse bridge support files and dlopen(3) the dylib files, if any. */
+  BS_PARSE_OPTIONS_LOAD_DYLIBS
 } bs_parse_options_t;
 
 /* bs_parse() 
@@ -213,7 +216,7 @@
  * Returns true on success, otherwise false.
  *
  * path: the full path of the bridge support file to parse.
- * options: parsing options, reserved for future use. You can pass 0 for now.
+ * options: parsing options.
  * callback: a callback function pointer.
  * context: a contextual data pointer that will be passed to the callback 
  * function.

Modified: MacRuby/trunk/instruby.rb
===================================================================
--- MacRuby/trunk/instruby.rb	2008-05-30 22:45:25 UTC (rev 239)
+++ MacRuby/trunk/instruby.rb	2008-06-02 00:20:34 UTC (rev 240)
@@ -489,6 +489,20 @@
   end
 end
 
+puts "fixing bridge support dylibs"
+unless File.exist?('markgc')
+  unless system("gcc markgc.c -std=gnu99 -o markgc")
+    $stderr.puts "cannot build the markgc tool"
+    exit 1
+  end
+end
+Dir.glob('/System/Library/Frameworks/**/BridgeSupport/*.dylib').each do |p|
+  unless system("markgc '#{p}' >& /dev/null")
+    $stderr.puts "cannot markgc #{p}"
+    exit 1
+  end
+end
+
 end # unless $installing_rdoc
 
 # vi:set sw=2:

Added: MacRuby/trunk/markgc.c
===================================================================
--- MacRuby/trunk/markgc.c	                        (rev 0)
+++ MacRuby/trunk/markgc.c	2008-06-02 00:20:34 UTC (rev 240)
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2007 Apple Inc.  All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#import <stdio.h>
+#include <fcntl.h>
+#import <sys/stat.h>
+#import <mach-o/fat.h>
+#import <mach-o/arch.h>
+#import <mach-o/loader.h>
+
+typedef char bool;
+#define true 1
+#define false 0
+
+bool debug;
+bool verbose;
+bool quiet;
+bool rrOnly;
+bool patch = true;
+
+struct gcinfo {
+        bool hasObjC;
+        bool hasInfo;
+        uint32_t flags;
+        char *arch;
+} GCInfo[4];
+
+void dumpinfo(char *filename);
+
+int Errors = 0;
+char *FileBase;
+size_t FileSize;
+const char *FileName;
+
+int main(int argc, char *argv[]) {
+    //NSAutoreleasePool *pool = [NSAutoreleasePool new];
+    int i;
+    //dumpinfo("/System/Library/Frameworks/AppKit.framework/AppKit");
+    if (argc == 1) {
+        printf("Usage: gcinfo [-v] [-r] [--] library_or_executable_image [image2 ...]\n");
+        printf(" prints Garbage Collection readiness of named images, ignoring those without ObjC segments\n");
+        printf("  'GC'      - compiled with write-barriers, presumably otherwise aware\n");
+        printf("  'RR'      - retain/release (presumed) aware for non-GC\n");
+        printf("  'GC-only' - compiled with write-barriers and marked at compile time as not being retain/release savvy\n");
+        printf("  -v        - provide archtectural details\n");
+        printf("  -r        - only show libraries that are non-GC, e.g. RR only\n");
+        printf("  --        - read files & directories from stdin, e.g. find /Plug-ins | gcinfo --\n");
+        printf("\nAuthor: blaine at apple.com\n");
+        exit(0);
+    }
+    for (i = 1; i < argc; ++i) {
+        if (!strcmp(argv[i], "-v")) {
+            verbose = true;
+            continue;
+        }
+        if (!strcmp(argv[i], "-d")) {
+            debug = true;
+            continue;
+        }
+        if (!strcmp(argv[i], "-q")) {
+            quiet = true;
+            continue;
+        }
+        if (!strcmp(argv[i], "-r")) {
+            quiet = true;
+            rrOnly = true;
+            continue;
+        }
+        if (!strcmp(argv[i], "-p")) {
+            patch = true;
+            continue;
+        }
+        if (!strcmp(argv[i], "--")) {
+            char buf[1024];
+            while (fgets(buf, 1024, stdin)) {
+                int len = strlen(buf);
+                buf[len-1] = 0;
+                dumpinfo(buf);
+            }
+            continue;
+        }
+        dumpinfo(argv[i]);
+    }
+    return Errors;
+}
+
+struct imageInfo {
+    uint32_t version;
+    uint32_t flags;
+};
+
+void patchFile(uint32_t value, size_t offset) {
+    int fd = open(FileName, 1);
+    off_t lresult = lseek(fd, offset, SEEK_SET);
+    if (lresult == -1) {
+        printf("couldn't seek to %x position on fd %d\n", offset, fd);
+        ++Errors;
+        return;
+    }
+    int wresult = write(fd, &value, 4);
+    if (wresult != 4) {
+        ++Errors;
+        printf("didn't write new value\n");
+    }
+    else {
+        printf("patched %s at offset %p\n", FileName, offset);
+    }
+    close(fd);
+}
+
+uint32_t iiflags(struct imageInfo *ii, uint32_t size, bool needsFlip) {
+    if (needsFlip) {
+        ii->flags = OSSwapInt32(ii->flags);
+    }
+    if (debug) printf("flags->%x, nitems %d\n", ii->flags, size/sizeof(struct imageInfo));
+    uint32_t flags = ii->flags;
+    if (patch && (flags&0x2)==0) {
+        //printf("will patch %s at offset %p\n", FileName, (char*)(&ii->flags) - FileBase);
+        uint32_t newvalue = flags | 0x2;
+        if (needsFlip) newvalue = OSSwapInt32(newvalue);
+        patchFile(newvalue, (char*)(&ii->flags) - FileBase);
+    }
+    for(int niis = 1; niis < size/sizeof(struct imageInfo); ++niis) {
+        if (needsFlip) ii[niis].flags = OSSwapInt32(ii[niis].flags);
+        if (ii[niis].flags != flags) {
+            // uh, oh.
+            printf("XXX ii[%d].flags %x != ii[0].flags %x\n", niis, ii[niis].flags, flags);
+            ++Errors;
+        }
+    }
+    return flags;
+}
+
+void printflags(uint32_t flags) {
+    if (flags & 0x1) printf(" F&C");
+    if (flags & 0x2) printf(" GC");
+    if (flags & 0x4) printf(" GC-only");
+    else printf(" RR");
+}
+
+/*
+void doimageinfo(struct imageInfo *ii, uint32_t size, bool needsFlip) {
+    uint32_t flags = iiflags(ii, size, needsFlip);
+    printflags(flags);
+}
+*/
+
+
+void dosect32(void *start, struct section *sect, bool needsFlip, struct gcinfo *gcip) {
+    if (debug) printf("section %s from segment %s\n", sect->sectname, sect->segname);
+    if (strcmp(sect->segname, "__OBJC")) return;
+    gcip->hasObjC = true;
+    if (strcmp(sect->sectname, "__image_info")) return;
+    gcip->hasInfo = true;
+    if (needsFlip) {
+        sect->offset = OSSwapInt32(sect->offset);
+        sect->size = OSSwapInt32(sect->size);
+    }
+    // these guys aren't inline - they point elsewhere
+    gcip->flags = iiflags(start + sect->offset, sect->size, needsFlip);
+}
+
+void dosect64(void *start, struct section_64 *sect, bool needsFlip, struct gcinfo *gcip) {
+    if (debug) printf("section %s from segment %s\n", sect->sectname, sect->segname);
+    if (strcmp(sect->segname, "__OBJC") && strcmp(sect->segname, "__DATA")) return;
+    if (strcmp(sect->sectname, "__image_info") && strncmp(sect->sectname, "__objc_imageinfo", 16)) return;
+    gcip->hasObjC = true;
+    gcip->hasInfo = true;
+    if (needsFlip) {
+        sect->offset = OSSwapInt32(sect->offset);
+        sect->size = OSSwapInt64(sect->size);
+    }
+    // these guys aren't inline - they point elsewhere
+    gcip->flags = iiflags(start + sect->offset, sect->size, needsFlip);
+}
+
+void doseg32(void *start, struct segment_command *seg, bool needsFlip, struct gcinfo *gcip) {
+    // lets do sections
+    if (needsFlip) {
+        seg->fileoff = OSSwapInt32(seg->fileoff);
+        seg->nsects = OSSwapInt32(seg->nsects);
+    }
+    if (debug) printf("segment name: %s, nsects %d\n", seg->segname, seg->nsects);
+    if (seg->segname[0]) {
+        if (strcmp("__OBJC", seg->segname)) return;
+    }
+    int nsects;
+    struct section *sect = (struct section *)(seg + 1);
+    for (int nsects = 0; nsects < seg->nsects; ++nsects) {
+        // sections directly follow
+        
+        dosect32(start, sect + nsects, needsFlip, gcip);
+    }
+}
+void doseg64(void *start, struct segment_command_64 *seg, bool needsFlip, struct gcinfo *gcip) {
+    if (debug) printf("segment name: %s\n", seg->segname);
+    if (seg->segname[0] && strcmp("__OBJC", seg->segname) && strcmp("__DATA", seg->segname)) return;
+    gcip->hasObjC = true;
+    // lets do sections
+    if (needsFlip) {
+        seg->fileoff = OSSwapInt64(seg->fileoff);
+        seg->nsects = OSSwapInt32(seg->nsects);
+    }
+    int nsects;
+    struct section_64 *sect = (struct section_64 *)(seg + 1);
+    for (int nsects = 0; nsects < seg->nsects; ++nsects) {
+        // sections directly follow
+        
+        dosect64(start, sect + nsects, needsFlip, gcip);
+    }
+}
+
+#if 0
+/*
+ * A variable length string in a load command is represented by an lc_str
+ * union.  The strings are stored just after the load command structure and
+ * the offset is from the start of the load command structure.  The size
+ * of the string is reflected in the cmdsize field of the load command.
+ * Once again any padded bytes to bring the cmdsize field to a multiple
+ * of 4 bytes must be zero.
+ */
+union lc_str {
+	uint32_t	offset;	/* offset to the string */
+#ifndef __LP64__
+	char		*ptr;	/* pointer to the string */
+#endif 
+};
+
+struct dylib {
+    union lc_str  name;			/* library's path name */
+    uint32_t timestamp;			/* library's build time stamp */
+    uint32_t current_version;		/* library's current version number */
+    uint32_t compatibility_version;	/* library's compatibility vers number*/
+};
+
+ * A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
+ * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
+ * An object that uses a dynamically linked shared library also contains a
+ * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
+ * LC_REEXPORT_DYLIB) for each library it uses.
+
+struct dylib_command {
+	uint32_t	cmd;		/* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
+					   LC_REEXPORT_DYLIB */
+	uint32_t	cmdsize;	/* includes pathname string */
+	struct dylib	dylib;		/* the library identification */
+};
+#endif
+
+void dodylib(void *start, struct dylib_command *dylibCmd, bool needsFlip) {
+    if (!verbose) return;
+    if (needsFlip) {
+    }
+    int count = dylibCmd->cmdsize - sizeof(struct dylib_command);
+    //printf("offset is %d, count is %d\n", dylibCmd->dylib.name.offset, count);
+    if (dylibCmd->dylib.name.offset > count) return;
+    //printf("-->%.*s<---", count, ((void *)dylibCmd)+dylibCmd->dylib.name.offset);
+    if (verbose) printf("load %s\n", ((void *)dylibCmd)+dylibCmd->dylib.name.offset);
+}
+
+struct load_command *doloadcommand(void *start, struct load_command *lc, bool needsFlip, bool is32, struct gcinfo *gcip) {
+    if (needsFlip) {
+        lc->cmd = OSSwapInt32(lc->cmd);
+        lc->cmdsize = OSSwapInt32(lc->cmdsize);
+    }
+
+    switch(lc->cmd) {
+    case LC_SEGMENT_64:
+	if (debug) printf("...segment64\n");
+        if (is32) printf("XXX we have a 64-bit segment in a 32-bit mach-o\n");
+        doseg64(start, (struct segment_command_64 *)lc, needsFlip, gcip);
+        break;
+    case LC_SEGMENT:
+	if (debug) printf("...segment32\n");
+        doseg32(start, (struct segment_command *)lc, needsFlip, gcip);
+        break;
+    case LC_SYMTAB: if (debug) printf("...dynamic symtab\n"); break;
+    case LC_DYSYMTAB: if (debug) printf("...symtab\n"); break;
+    case LC_LOAD_DYLIB:
+        dodylib(start, (struct dylib_command *)lc, needsFlip);
+        break;
+    case LC_SUB_UMBRELLA: if (debug) printf("...load subumbrella\n"); break;
+    default:    if (debug) printf("cmd is %x\n", lc->cmd); break;
+    }
+    
+    return (struct load_command *)((void *)lc + lc->cmdsize);
+}
+
+void doofile(void *start, uint32_t size, struct gcinfo *gcip) {
+    struct mach_header *mh = (struct mach_header *)start;
+    bool isFlipped = false;
+    if (mh->magic == MH_CIGAM || mh->magic == MH_CIGAM_64) {
+        if (debug) printf("(flipping)\n");
+        mh->magic = OSSwapInt32(mh->magic);
+        mh->cputype = OSSwapInt32(mh->cputype);
+        mh->cpusubtype = OSSwapInt32(mh->cpusubtype);
+        mh->filetype = OSSwapInt32(mh->filetype);
+        mh->ncmds = OSSwapInt32(mh->ncmds);
+        mh->sizeofcmds = OSSwapInt32(mh->sizeofcmds);
+        mh->flags = OSSwapInt32(mh->flags);
+        isFlipped = true;
+    }
+    if (rrOnly && mh->filetype != 6) return; // ignore executables
+    NXArchInfo *info = (NXArchInfo *)NXGetArchInfoFromCpuType(mh->cputype, mh->cpusubtype);
+    //printf("%s:", info->description);
+    gcip->arch = (char *)info->description;
+    //if (debug) printf("...description is %s\n", info->description);
+    bool is32 = (mh->cputype == 18 || mh->cputype == 7);
+    if (debug) printf("is 32? %d\n", is32);
+    if (debug) printf("filetype -> %d\n", mh->filetype);
+    if (debug) printf("ncmds -> %d\n", mh->ncmds);
+    struct load_command *lc = (is32 ? (struct load_command *)(mh + 1) : (struct load_command *)((struct mach_header_64 *)start + 1));
+    int ncmds;
+    for (ncmds = 0; ncmds < mh->ncmds; ++ncmds) {
+        lc = doloadcommand(start, lc, isFlipped, is32, gcip);
+    }
+    //printf("\n");
+}
+
+void initGCInfo() {
+    bzero((void *)GCInfo, sizeof(GCInfo));
+}
+
+void printGCInfo(char *filename) {
+    if (!GCInfo[0].hasObjC) return; // don't bother
+    // verify that flags are all the same
+    uint32_t flags = GCInfo[0].flags;
+    bool allSame = true;
+    for (int i = 1; i < 4 && GCInfo[i].arch; ++i) {
+        if (flags != GCInfo[i].flags) {
+            allSame = false;
+        }
+    }
+    if (rrOnly) {
+        if (allSame && (flags & 0x2))
+            return;
+        printf("*** not all GC in %s:\n", filename);
+    }
+    if (allSame && !verbose) {
+        printf("%s:", filename);
+        printflags(flags);
+        printf("\n");
+    }
+    else {
+        printf("%s:\n", filename);
+        for (int i = 0; i < 4 && GCInfo[i].arch; ++i) {
+            printf("%s:", GCInfo[i].arch);
+            printflags(GCInfo[i].flags);
+            printf("\n");
+        }
+        printf("\n");
+    }
+}
+
+void dofat(void *start) {
+    struct fat_header *fh = start;
+    bool needsFlip = false;
+    if (fh->magic == FAT_CIGAM) {
+        fh->nfat_arch = OSSwapInt32(fh->nfat_arch);
+        needsFlip = true;
+    }
+    if (debug) printf("%d architectures\n", fh->nfat_arch);
+    int narchs;
+    struct fat_arch *arch_ptr = (struct fat_arch *)(fh + 1);
+    for (narchs = 0; narchs < fh->nfat_arch; ++narchs) {
+        if (needsFlip) {
+            arch_ptr->offset = OSSwapInt32(arch_ptr->offset);
+            arch_ptr->size = OSSwapInt32(arch_ptr->size);
+        }
+        doofile(start+arch_ptr->offset, arch_ptr->size, &GCInfo[narchs]);
+        arch_ptr++;
+    }
+}
+
+bool openFile(const char *filename) {
+    FileName = filename;
+    // get size
+    struct stat statb;
+    int fd = open(filename, 0);
+    if (fd < 0) {
+        printf("couldn't open %s for reading\n", filename);
+        return false;
+    }
+    int osresult = fstat(fd, &statb);
+    if (osresult != 0) {
+        printf("couldn't get size of %s\n", filename);
+        close(fd);
+        return false;
+    }
+    FileSize = statb.st_size;
+    FileBase = malloc(FileSize);
+    if (!FileBase) {
+        printf("couldn't malloc %d bytes\n", FileSize);
+        close(fd);
+        return false;
+    }
+    off_t readsize = read(fd, FileBase, FileSize);
+    if (readsize != FileSize) {
+        printf("read %d bytes, wanted %d\n", readsize, FileSize);
+        close(fd);
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
+void closeFile() {
+    free(FileBase);
+}
+
+void dumpinfo(char *filename) {
+    initGCInfo();
+    openFile(filename);
+    struct fat_header *fh = (struct fat_header *)FileBase;
+    if (fh->magic == FAT_MAGIC || fh->magic == FAT_CIGAM) {
+        dofat((void *)FileBase);
+        //printGCInfo(filename);
+    }
+    else if (fh->magic == MH_MAGIC || fh->magic == MH_CIGAM || fh->magic == MH_MAGIC_64 || fh->magic == MH_CIGAM_64) {
+        doofile((void *)FileBase, FileSize, &GCInfo[0]);
+        //printGCInfo(filename);
+    }
+    else if (!quiet) {
+        printf("don't understand %s!\n", filename);
+    }
+    closeFile();
+ }
+


Property changes on: MacRuby/trunk/markgc.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2008-05-30 22:45:25 UTC (rev 239)
+++ MacRuby/trunk/objc.m	2008-06-02 00:20:34 UTC (rev 240)
@@ -593,8 +593,11 @@
     long n = 0;
     while ((*elements) != NULL) {
 	if ((*elements)->type == FFI_TYPE_STRUCT) {
-	    long i, n2 = rebuild_new_struct_ary((*elements)->elements, orig, new);
-	    VALUE tmp = rb_ary_new();
+	    long i, n2;
+	    VALUE tmp;
+
+	    n2 = rebuild_new_struct_ary((*elements)->elements, orig, new);
+	    tmp = rb_ary_new();
 	    for (i = 0; i < n2; i++) {
 		if (RARRAY_LEN(orig) == 0)
 		    return 0;
@@ -608,70 +611,88 @@
     return n;
 }
 
-static void
-rb_objc_rval_to_ocval(VALUE rval, const char *octype, void **ocval)
+static void rb_objc_rval_to_ocval(VALUE, const char *, void **);
+
+static void *
+rb_objc_rval_to_boxed_data(VALUE rval, bs_element_boxed_t *bs_boxed, bool *ok)
 {
-    bs_element_boxed_t *bs_boxed;
-    bool ok = true;
+    void *data;
 
-    octype = rb_objc_skip_octype_modifiers(octype);
+    if (TYPE(rval) == T_ARRAY && bs_boxed->type == BS_ELEMENT_STRUCT) {
+	bs_element_struct_t *bs_struct;
+	long i, n;
+	size_t pos;
 
-    if (*octype == _C_VOID)
-	return;
+	bs_struct = (bs_element_struct_t *)bs_boxed->value;
 
-    if (st_lookup(bs_boxeds, (st_data_t)octype, (st_data_t *)&bs_boxed)) {
-	void *data;
+	rb_bs_boxed_assert_ffitype_ok(bs_boxed);
 
-	if (TYPE(rval) == T_ARRAY && bs_boxed->type == BS_ELEMENT_STRUCT) {
-	    bs_element_struct_t *bs_struct;
-	    long i, n;
-	    size_t pos;
-
-	    bs_struct = (bs_element_struct_t *)bs_boxed->value;
-
-	    n = RARRAY_LEN(rval);
-	    if (n < bs_struct->fields_count)
-		rb_raise(rb_eArgError, 
+	n = RARRAY_LEN(rval);
+	if (n < bs_struct->fields_count)
+	    rb_raise(rb_eArgError, 
 		    "not enough elements in array `%s' to create " \
 		    "structure `%s' (%d for %d)", 
 		    RSTRING_CPTR(rb_inspect(rval)), bs_struct->name, n, 
 		    bs_struct->fields_count);
-	    
-	    if (n > bs_struct->fields_count) {
-		VALUE new_rval = rb_ary_new();
-		VALUE orig = rval;
-		rval = rb_ary_dup(rval);
-		rebuild_new_struct_ary(bs_boxed->ffi_type->elements, rval, 
-				       new_rval);
-		n = RARRAY_LEN(new_rval);
-		if (RARRAY_LEN(rval) != 0 || n != bs_struct->fields_count) {
-		    rb_raise(rb_eArgError, 
+
+	if (n > bs_struct->fields_count) {
+	    VALUE new_rval = rb_ary_new();
+	    VALUE orig = rval;
+	    rval = rb_ary_dup(rval);
+	    rebuild_new_struct_ary(bs_boxed->ffi_type->elements, rval, 
+		    new_rval);
+	    n = RARRAY_LEN(new_rval);
+	    if (RARRAY_LEN(rval) != 0 || n != bs_struct->fields_count) {
+		rb_raise(rb_eArgError, 
 			"too much elements in array `%s' to create " \
 			"structure `%s' (%d for %d)", 
 			RSTRING_CPTR(rb_inspect(orig)), 
 			bs_struct->name, RARRAY_LEN(orig), 
 			bs_struct->fields_count);
-		}
-		rval = new_rval;
 	    }
+	    rval = new_rval;
+	}
 
-	    data = alloca(bs_boxed->ffi_type->size);
+	data = xmalloc(bs_boxed->ffi_type->size);
 
-	    for (i = 0, pos = 0; i < bs_struct->fields_count; i++) {
-		VALUE o = RARRAY_AT(rval, i);
-		char *field_type = bs_struct->fields[i].type;
-		rb_objc_rval_to_ocval(o, field_type, data + pos);
-		pos += rb_objc_octype_to_ffitype(field_type)->size;
-	    }
+	for (i = 0, pos = 0; i < bs_struct->fields_count; i++) {
+	    VALUE o = RARRAY_AT(rval, i);
+	    char *field_type = bs_struct->fields[i].type;
+	    rb_objc_rval_to_ocval(o, field_type, data + pos);
+	    pos += rb_objc_octype_to_ffitype(field_type)->size;
 	}
-	else {
-	    data = bs_element_boxed_get_data(bs_boxed, rval, &ok);
-	}
+
+	*ok = true;
+    }
+    else {
+	data = bs_element_boxed_get_data(bs_boxed, rval, ok);
+    }
+
+    return data;
+}
+
+static void
+rb_objc_rval_to_ocval(VALUE rval, const char *octype, void **ocval)
+{
+    bs_element_boxed_t *bs_boxed;
+    bool ok = true;
+
+    octype = rb_objc_skip_octype_modifiers(octype);
+
+    if (*octype == _C_VOID)
+	return;
+
+    if (st_lookup(bs_boxeds, (st_data_t)octype, (st_data_t *)&bs_boxed)) {
+	void *data;
+
+	data = rb_objc_rval_to_boxed_data(rval, bs_boxed, &ok);
 	if (ok) {
 	    if (data == NULL)
 		*(void **)ocval = NULL;
-	    else
+	    else {
 		memcpy(ocval, data, bs_boxed->ffi_type->size);
+		xfree(data);
+	    }
 	}
 	goto bails; 
     }
@@ -703,6 +724,14 @@
 	    else if (TYPE(rval) == T_STRING) {
 		*(char **)ocval = StringValuePtr(rval);
 	    }	
+	    else if (st_lookup(bs_boxeds, (st_data_t)octype + 1, 
+		     (st_data_t *)&bs_boxed)) {
+		void *data;
+
+		data = rb_objc_rval_to_boxed_data(rval, bs_boxed, &ok);
+		if (ok)
+		    *(void **)ocval = data;
+	    }
 	    else {
 		ok = false;
 	    }
@@ -1521,6 +1550,24 @@
     rb_funcall(ary, rb_intern("uniq!"), 0);
 }
 
+static bool
+rb_objc_resourceful(VALUE obj)
+{
+    /* TODO we should export this function in the runtime 
+     * Object#__resourceful__? perhaps? 
+     */
+    extern CFTypeID __CFGenericTypeID(void *);
+    CFTypeID t = __CFGenericTypeID((void *)obj);
+    if (t > 0) {
+	extern void *_CFRuntimeGetClassWithTypeID(CFTypeID);
+	long *d = (long *)_CFRuntimeGetClassWithTypeID(t);
+	/* first long is version, 4 means resourceful */
+	if (d != NULL && *d & 4)
+	    return true;	
+    }
+    return false;
+}
+
 static VALUE
 bs_function_dispatch(int argc, VALUE *argv, VALUE recv)
 {
@@ -1588,9 +1635,11 @@
     }
 
     resp = Qnil;
-    if (ffi_rettype != &ffi_type_void)
+    if (ffi_rettype != &ffi_type_void) {
 	rb_objc_ocval_to_rbval(ffi_ret, bs_func->retval->type, &resp);
-
+    	if (bs_func->retval->already_retained && !rb_objc_resourceful(resp))
+	    CFMakeCollectable((void *)resp);
+    }
     return resp;
 }
 
@@ -2199,18 +2248,9 @@
     char *p;
 
     if (bs_find_path(framework_path, path, sizeof path)) {
-	if (!bs_parse(path, 0, bs_parse_cb, NULL, &error))
+	if (!bs_parse(path, BS_PARSE_OPTIONS_LOAD_DYLIBS, bs_parse_cb, NULL, 
+		      &error))
 	    rb_raise(rb_eRuntimeError, error);
-#if 0
-	/* FIXME 'GC capability mismatch' with .dylib files */
-	p = strrchr(path, '.');
-	assert(p != NULL);
-	strlcpy(p, ".dylib", p - path - 1);
-	if (access(path, R_OK) == 0) {
-	    if (dlopen(path, RTLD_LAZY) == NULL)
-		rb_raise(rb_eRuntimeError, dlerror());
-	}
-#endif
     }
 }
 

Added: MacRuby/trunk/sample-macruby/Scripts/circle.rb
===================================================================
--- MacRuby/trunk/sample-macruby/Scripts/circle.rb	                        (rev 0)
+++ MacRuby/trunk/sample-macruby/Scripts/circle.rb	2008-06-02 00:20:34 UTC (rev 240)
@@ -0,0 +1,15 @@
+# Create a new PDF file and draw a red circle in it, using Core Graphics.
+framework 'Cocoa'
+
+url = NSURL.fileURLWithPath('circle.pdf')
+pdf = CGPDFContextCreateWithURL(url, [[0, 0], [617, 792]], nil)
+
+CGPDFContextBeginPage(pdf, nil)
+CGContextSetRGBFillColor(pdf, 1.0, 0.0, 0.0, 1.0)
+CGContextAddArc(pdf, 300, 300, 100, 0, 2 * Math::PI, 1)
+CGContextFillPath(pdf)
+CGPDFContextEndPage(pdf)
+CGContextFlush(pdf)
+
+# CGContextRef is a resourceful object, so it must be released manually.
+CFRelease(pdf)

Modified: MacRuby/trunk/sample-macruby/Scripts/hello_world.rb
===================================================================
--- MacRuby/trunk/sample-macruby/Scripts/hello_world.rb	2008-05-30 22:45:25 UTC (rev 239)
+++ MacRuby/trunk/sample-macruby/Scripts/hello_world.rb	2008-06-02 00:20:34 UTC (rev 240)
@@ -11,7 +11,7 @@
 end
 
 app = NSApplication.sharedApplication
-app.delegate = AppDelegate.alloc.init
+app.delegate = AppDelegate.new
 
 win = NSWindow.alloc.initWithContentRect([200, 300, 250, 100],
     styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask, 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080601/e912fe79/attachment-0001.htm 


More information about the macruby-changes mailing list