Skip to content
Browse files

fix for #48, support for passing pointers to boxed types, support for…

… the already_retained retval attribute and resourceful CF objectx

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@240 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 5d36df8 commit 36b9ead6bf23fcc5d85d6a19c40547b21ce310b6 Laurent Sansonetti committed Jun 2, 2008
Showing with 598 additions and 61 deletions.
  1. +15 −1 bs.c
  2. +5 −2 bs.h
  3. +14 −0 instruby.rb
  4. +451 −0 markgc.c
  5. +97 −57 objc.m
  6. +15 −0 sample-macruby/Scripts/circle.rb
  7. +1 −1 sample-macruby/Scripts/hello_world.rb
View
16 bs.c
@@ -1096,7 +1096,21 @@ _bs_parse(const char *path, char **loaded_paths,
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;
}
View
7 bs.h
@@ -202,7 +202,10 @@ typedef void (*bs_parse_callback_t)
(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 @@ typedef enum {
* 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.
View
14 instruby.rb
@@ -489,6 +489,20 @@ def install_stuff(what, from, to, mode)
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:
View
451 markgc.c
@@ -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@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();
+ }
+
View
154 objc.m
@@ -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)
-{
- bs_element_boxed_t *bs_boxed;
- bool ok = true;
-
- octype = rb_objc_skip_octype_modifiers(octype);
+static void rb_objc_rval_to_ocval(VALUE, const char *, void **);
- if (*octype == _C_VOID)
- return;
+static void *
+rb_objc_rval_to_boxed_data(VALUE rval, bs_element_boxed_t *bs_boxed, bool *ok)
+{
+ void *data;
- if (st_lookup(bs_boxeds, (st_data_t)octype, (st_data_t *)&bs_boxed)) {
- void *data;
+ if (TYPE(rval) == T_ARRAY && bs_boxed->type == BS_ELEMENT_STRUCT) {
+ bs_element_struct_t *bs_struct;
+ long i, n;
+ size_t pos;
- 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;
- bs_struct = (bs_element_struct_t *)bs_boxed->value;
+ rb_bs_boxed_assert_ffitype_ok(bs_boxed);
- 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;
- }
- }
- else {
- data = bs_element_boxed_get_data(bs_boxed, rval, &ok);
+ 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;
}
+
+ *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
}
}
View
15 sample-macruby/Scripts/circle.rb
@@ -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)
View
2 sample-macruby/Scripts/hello_world.rb
@@ -11,7 +11,7 @@ def sayHello(sender)
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,

0 comments on commit 36b9ead

Please sign in to comment.
Something went wrong with that request. Please try again.