Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use plblockimp to provide imp_implementationWithBlock() for OS X 10.6…

… compatiblility
  • Loading branch information...
commit 5bf56cf3f7a453c109dc17349a227de317da98bc 1 parent 0625753
@macrotis macrotis authored
View
2  .gitignore
@@ -44,6 +44,8 @@ mspec/upstream_patches
mspec_upstream
node_name.inc
parse.c
+plblockimp/blockimp_ARM*
+plblockimp/blockimp_x86*
prelude.c
rbconfig.rb
revision.h
View
2  lib/mkmf.rb
@@ -1932,7 +1932,7 @@ def init_mkmf(config = CONFIG)
$LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup
$INCFLAGS = "-I$(arch_hdrdir)"
$INCFLAGS << " -I$(hdrdir)/ruby/backward" unless $extmk
- $INCFLAGS << " -I$(hdrdir) -I$(srcdir)"
+ $INCFLAGS << " -I$(hdrdir) -I$(srcdir) -I$(top_srcdir)/plblockimp"
$DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup
$LIBEXT = config['LIBEXT'].dup
$OBJEXT = config["OBJEXT"].dup
View
1  macruby_internal.h
@@ -13,6 +13,7 @@ extern "C" {
#endif
#include "ruby.h"
+#include "PLBlockIMP.h"
#include <objc/objc.h>
#include <objc/runtime.h>
View
66 plblockimp/ARM/blockimp_arm.tramp
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions. We support either armv6 or armv7
+if [ "${CURRENT_ARCH}" = "armv6" ] || [ "${CURRENT_ARCH}" = "armv7" ]; then
+ ARCH="${CURRENT_ARCH}"
+else
+ ARCH=""
+fi
+
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ # trampoline address+8 is in r12 -- calculate our config page address
+ sub r12, #0x8
+ sub r12, #0x1000
+
+ # Set the 'self' argument as the second argument
+ mov r1, r0
+
+ # Load the block pointer as the first argument
+ ldr r0, [r12]
+
+ # Jump to the block pointer
+ ldr pc, [r0, #0xc]
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+ # Save pc+8, then jump to the shared prefix implementation
+ mov r12, pc
+ b _block_tramp_dispatch;
+EOF
+}
View
61 plblockimp/ARM/blockimp_arm_stret.tramp
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions
+ARCH="${CURRENT_ARCH}"
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_stret_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ # trampoline address+8 is in r12 -- calculate our config page address
+ sub r12, #0x8
+ sub r12, #0x1000
+
+ # Set the 'self' argument as the third argument
+ mov r2, r1
+
+ # Load the block pointer as the second argument
+ ldr r1, [r12]
+
+ # Jump to the block pointer
+ ldr pc, [r1, #0xc]
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+ # Save pc+8, then jump to the shared prefix implementation
+ mov r12, pc
+ b _block_tramp_dispatch;
+EOF
+}
View
23 plblockimp/LICENSE
@@ -0,0 +1,23 @@
+Author: Landon Fuller <landonf@plausible.coop>
+
+Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+All rights reserved.
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
View
28 plblockimp/PLBlockIMP.h
@@ -0,0 +1,28 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+#include "blockimp.h"
View
117 plblockimp/blockimp.c
@@ -0,0 +1,117 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "blockimp.h"
+#include "blockimp_private.h"
+
+#include "trampoline_table.h"
+
+#include <stdio.h>
+#include <Block.h>
+
+#pragma mark Trampolines
+
+/* Global lock for our mutable state. Must be held when accessing the trampoline tables. */
+static pthread_mutex_t blockimp_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Trampoline tables for objc_msgSend_stret() dispatch. */
+static pl_trampoline_table *blockimp_table_stret = NULL;
+
+/* Trampoline tables for objc_msgSend() dispatch. */
+static pl_trampoline_table *blockimp_table = NULL;
+
+/**
+ *
+ */
+IMP pl_imp_implementationWithBlock (void *block) {
+#if SUPPORT_APPLE_FALLBACK
+ /* Prefer Apple's implementation */
+ if (&imp_implementationWithBlock != NULL)
+ return imp_implementationWithBlock(block);
+#endif
+
+ /* Allocate the appropriate trampoline type. */
+ pl_trampoline *tramp;
+ struct Block_layout *bl = block;
+ if (bl->flags & BLOCK_USE_STRET) {
+ tramp = pl_trampoline_alloc(&pl_blockimp_table_stret_page_config, &blockimp_lock, &blockimp_table_stret);
+ } else {
+ tramp = pl_trampoline_alloc(&pl_blockimp_table_page_config, &blockimp_lock, &blockimp_table);
+ }
+
+ /* Configure the trampoline */
+ void **config = pl_trampoline_data_ptr(tramp->trampoline);
+ config[0] = Block_copy(block);
+ config[1] = tramp;
+
+ /* Return the function pointer. */
+ return (IMP) tramp->trampoline;
+}
+
+/**
+ *
+ */
+void *pl_imp_getBlock(IMP anImp) {
+#if SUPPORT_APPLE_FALLBACK
+ /* Prefer Apple's implementation */
+ if (&imp_getBlock != NULL) {
+ return imp_getBlock(anImp);
+ }
+#endif
+
+ /* Fetch the config data and return the block reference. */
+ void **config = pl_trampoline_data_ptr(anImp);
+ return config[0];
+}
+
+/**
+ *
+ */
+BOOL pl_imp_removeBlock(IMP anImp) {
+#if SUPPORT_APPLE_FALLBACK
+ /* Prefer Apple's implementation */
+ if (&imp_removeBlock != NULL)
+ return imp_removeBlock(anImp);
+#endif
+
+ /* Fetch the config data */
+ void **config = pl_trampoline_data_ptr(anImp);
+ struct Block_layout *bl = config[0];
+ pl_trampoline *tramp = config[1];
+
+ /* Drop the trampoline allocation */
+ if (bl->flags & BLOCK_USE_STRET) {
+ pl_trampoline_free(&blockimp_lock, &blockimp_table_stret, tramp);
+ } else {
+ pl_trampoline_free(&blockimp_lock, &blockimp_table, tramp);
+ }
+
+ /* Release the block */
+ Block_release(config[0]);
+
+ // TODO - what does this return value mean?
+ return YES;
+}
View
31 plblockimp/blockimp.h
@@ -0,0 +1,31 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <objc/runtime.h>
+
+extern IMP pl_imp_implementationWithBlock(void *block);
+extern void *pl_imp_getBlock(IMP anImp);
+extern BOOL pl_imp_removeBlock(IMP anImp);
View
135 plblockimp/blockimp_private.h
@@ -0,0 +1,135 @@
+/*
+ * Private Block ABI Structures
+ * Originally acquired frm PLBlocks and compiler_rt
+ *
+ * Copyright 2008 - 2009 Apple, Inc.
+ * Copyright 2009 - 2011 Plausible Labs Cooperative, Inc.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#if defined(__i386__)
+# include "blockimp_x86_32.h"
+# include "blockimp_x86_32_stret.h"
+#elif defined(__x86_64__)
+# include "blockimp_x86_64.h"
+# include "blockimp_x86_64_stret.h"
+#elif defined(__arm__)
+# include "blockimp_arm.h"
+# include "blockimp_arm_stret.h"
+#else
+# error Unknown Architecture
+#endif
+
+#pragma mark Fallback Support
+
+// if 1, we attempt to use Apple's official implementations
+#define SUPPORT_APPLE_FALLBACK 0
+#if SUPPORT_APPLE_FALLBACK
+extern IMP imp_implementationWithBlock(void *block) WEAK_IMPORT_ATTRIBUTE;
+extern void *imp_getBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
+extern BOOL imp_removeBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
+#endif
+
+/*
+ * Block Flags
+ */
+typedef enum {
+ /** 16-bit block reference count. */
+ BLOCK_REFCOUNT_MASK = (0xffff),
+
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+
+ /** Helpers have C++ code. */
+ BLOCK_HAS_CTOR = (1 << 26),
+
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+
+ /** Block returns its aggregate value in memory (ie, the block has a structure return type). */
+ BLOCK_USE_STRET = (1 << 29),
+} block_flags_t;
+
+
+/*
+ * Block field flags.
+ */
+typedef enum {
+ // see function implementation for a more complete description of these fields and combinations
+ BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
+ BLOCK_FIELD_IS_BLOCK = 7, // a block variable
+ BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
+ BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers
+ BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines.
+} block_field_flags_t;
+
+/*
+ * Block description.
+ *
+ * Block descriptions are shared across all instances of a block, and
+ * provide basic information on the block size, as well as pointers
+ * to any helper functions necessary to copy or dispose of the block.
+ */
+struct Block_descriptor {
+ /** Reserved value */
+ unsigned long int reserved;
+
+ /** Total size of the described block, including imported variables. */
+ unsigned long int size;
+
+ /** Optional block copy helper. May be NULL. */
+ void (*copy)(void *dst, void *src);
+
+ /** Optional block dispose helper. May be NULL. */
+ void (*dispose)(void *);
+};
+
+
+/*
+ * Block instance.
+ *
+ * The block layout defines the per-block instance state, which includes
+ * a reference to the shared block descriptor.
+ *
+ * The block's imported variables are allocated following the block
+ * descriptor member.
+ */
+struct Block_layout {
+ /** Pointer to the block's Objective-C class. */
+ void *isa;
+
+ /** Block flags. */
+ int flags;
+
+ /** Reserved value. */
+ int reserved;
+
+ /** Block invocation function. */
+ void (*invoke)(void *, ...);
+
+ /** Shared block descriptor. */
+ struct Block_descriptor *descriptor;
+
+ // imported variables
+};
View
148 plblockimp/blockimp_tests.m
@@ -0,0 +1,148 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#import "GTMSenTestCase.h"
+#import "blockimp.h"
+
+@interface BlockIMPTests : SenTestCase @end
+
+/**
+ * BlockIMP Tests
+ */
+@implementation BlockIMPTests
+
+/**
+ * Test basic IMP allocation and execution.
+ */
+- (void) testAllocateIMP {
+ /* A test block */
+ __block BOOL didRun = NO;
+ void (^Block)(id self) = ^(id blockself) {
+ didRun = YES;
+
+ STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
+ };
+
+ /* Create the IMP */
+ IMP imp = pl_imp_implementationWithBlock(Block);
+ STAssertTrue(imp != NULL, @"Returned NULL IMP");
+
+ /* Verify the IMP is valid. */
+ void (*ptr)(id self, SEL _cmd) = (void *) imp;
+ ptr(self, @selector(testAllocateIMP));
+ STAssertTrue(didRun, @"Block was not run");
+
+ /* Clean up */
+ pl_imp_removeBlock(imp);
+}
+
+/**
+ * Test basic stret IMP allocation and execution.
+ */
+- (void) testAllocateStretIMP {
+ /* A test block */
+ __block BOOL didRun = NO;
+ NSRange (^Block)(id self) = ^NSRange (id blockself) {
+ didRun = YES;
+
+ STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
+ return NSMakeRange(42, 1);
+ };
+
+ /* Create the IMP */
+ IMP imp = pl_imp_implementationWithBlock(Block);
+ STAssertTrue(imp != NULL, @"Returned NULL IMP");
+
+ /* Verify the IMP is valid. */
+ NSRange (*ptr)(id self, SEL _cmd) = (void *) imp;
+ NSRange result = ptr(self, @selector(testAllocateStretIMP));
+
+ STAssertTrue(didRun, @"Block was not run");
+ STAssertEquals(result.location, (NSUInteger)42, @"Incorrect location");
+ STAssertEquals(result.length, (NSUInteger)1, @"Incorrect length");
+
+ /* Clean up */
+ pl_imp_removeBlock(imp);
+}
+
+/**
+ * Test fetching of the Block ptr from the IMP pointer.
+ */
+- (void) testGetBlock {
+ /* A test block */
+ void (^Block)(id self) = [[^(id blockself) {
+ STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
+ } copy] autorelease];
+
+ /* Create the IMP */
+ IMP imp = pl_imp_implementationWithBlock(Block);
+ STAssertTrue(imp != NULL, @"Returned NULL IMP");
+
+ /* Try to fetch the underlying block */
+ void *b = pl_imp_getBlock(imp);
+ STAssertEquals(b, (void *) Block, @"Did not fetch block");
+
+ /* Clean up */
+ pl_imp_removeBlock(imp);
+}
+
+/**
+ * Exercise block allocation
+ */
+- (void) testAllocationExcercise {
+ /* A test block */
+ __block int callCount = 0;
+ void (^Block)(id self) = [[^(id blockself) {
+ callCount++;
+ STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
+ } copy] autorelease];
+
+ /* Use a count larger than what a single page (on any architecture) can likely hold */
+ int count=PAGE_SIZE*2;
+
+ /* Generate the IMPs */
+ IMP *imps = malloc(sizeof(IMP) * count);
+ for (int i = 0; i < count; i++) {
+ imps[i] = pl_imp_implementationWithBlock(Block);
+ }
+
+ /* Call the IMPs */
+ for (int i = 0; i < count; i++) {
+ void (*ptr)(id self, SEL _cmd) = (void *) imps[i];
+ ptr(self, @selector(testAllocationExcercise));
+ }
+
+ /* Clean up the IMPs. We do this in reverse to exercise table reordering. */
+ for (int i = count-1; i+1 >= 1; i--) {
+ pl_imp_removeBlock(imps[i]);
+ }
+ free(imps);
+
+ /* Verify the result */
+ STAssertEquals(callCount, count, @"Call count does not match expected count; not all IMPs were called");
+}
+
+@end
View
207 plblockimp/gentramp.sh
@@ -0,0 +1,207 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# gentramp.sh - Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+#
+# Trampoline Page Generator
+# Author: Landon Fuller <landonf@plausible.coop>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+PROGNAME=$0
+
+INPUT_FILE_PATH="$1"
+INPUT_FILE_BASE="`basename -a $(sed s/\.[^.]*$// <<< $INPUT_FILE_PATH)`"
+CURRENT_ARCH="$2"
+OUTPUT_DIR="$3"
+SRC_C_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}_config.c"
+SRC_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.s"
+HEADER_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.h"
+
+# Default implementation
+trampoline_prefix () {
+ return 0
+}
+
+# Import the trampoline definition
+. ${INPUT_FILE_PATH}
+
+check_required () {
+ local name=$1
+ eval "local var=\${$1}"
+
+ if [ -z "${var}" ]; then
+ echo "Required variable ${name} not defined."
+ exit 1
+ fi
+}
+
+check_required ARCH
+check_required PAGE_SIZE
+check_required PAGE_NAME
+
+# Write a header line
+header () {
+ echo "$1" >> "${HEADER_OUTPUT}"
+}
+
+# Write a C source line
+src () {
+ echo "$1" >> "${SRC_C_OUTPUT}"
+}
+
+# Flush the assembler output buffer to disk
+ASM_BUFFER=""
+asm_flush () {
+ echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
+ asm_discard
+}
+
+# Write the assembler buffer to disk, but don't discard the contents
+asm_write () {
+ echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
+}
+
+# Discard the current assembler output buffer
+asm_discard () {
+ ASM_BUFFER=''
+ return 0;
+}
+
+# Append data to the assembler output buffer
+asm () {
+ local line=""
+ while read -r line; do
+ ASM_BUFFER+=$line
+ ASM_BUFFER+="\n"
+ done
+}
+
+# Compute the assembled size of the current assembler buffer
+compute_asm_size () {
+ # Create the temporary assembler file
+ local output=".globl _byte_count_start\n"
+ output+="_byte_count_start:\n"
+ output+="${ASM_BUFFER}"
+ output+=".globl _byte_count_end\n"
+ output+="_byte_count_end:\n"
+
+ local tempfile=`mktemp /tmp/as_bytecount.XXXXXXXX`
+ echo "${output}" | as -arch "${CURRENT_ARCH}" -o "${tempfile}" -
+ if [ $? != 0 ]; then
+ echo "Assembling the trampoline failed"
+ exit 1
+ fi
+
+ local byte_size=`nm -t d -P "${tempfile}" | grep ^_byte_count_end | awk '{print $3}'`
+ rm -f "${tempfile}"
+
+ echo $byte_size
+}
+
+
+# Write out the page header
+write_page_decl () {
+ # Calculate the required alignment
+ local align=`perl -l -e "print log(${PAGE_SIZE})/log(2)"`
+ asm << EOF
+ # GENERATED CODE - DO NOT EDIT"
+ # This file was generated by $PROGNAME on `date`
+
+ # Write out the trampoline table, aligned to the page boundary
+ .text
+ .align ${align}
+ .globl _${PAGE_NAME}
+ _${PAGE_NAME}:
+EOF
+}
+
+main () {
+ echo '' > "${SRC_OUTPUT}"
+ echo '' > "${SRC_C_OUTPUT}"
+ echo '' > "${HEADER_OUTPUT}"
+
+ # Write out the trampoline header file
+ header "extern void *${PAGE_NAME};"
+ header "extern struct pl_trampoline_table_config ${PAGE_NAME}_config;"
+
+ # Don't generate the sources for the incorrect arch
+ if [ "${ARCH}" != "${CURRENT_ARCH}" ]; then
+ return
+ fi
+
+ # Determine the trampoline prefix size
+ trampoline_prefix
+ local prefix_size=$(compute_asm_size)
+ asm_discard
+
+ # Compute the size of the remaining code page.
+ local page_avail=`expr $PAGE_SIZE - $prefix_size`
+
+ # Determine the trampoline size
+ trampoline
+ local tramp_size=$(compute_asm_size)
+ asm_discard
+ if [ "${tramp_size}" = 0 ]; then
+ echo "Error occured calculating trampoline size; received size of 0"
+ exit 1
+ fi
+
+ # Compute the number of of available trampolines.
+ local trampoline_count=`expr $page_avail / $tramp_size`
+ echo "Prefix size: ${prefix_size}"
+ echo "Trampoline size: ${tramp_size}"
+ echo "Trampolines per page: ${trampoline_count}"
+
+ # Write out the page declaration
+ write_page_decl
+ asm_flush
+
+ # Write out the prefix
+ trampoline_prefix
+ asm_flush
+
+ # Write out the trampolines
+ trampoline
+ local i=0
+ while [ $i -lt ${trampoline_count} ]; do
+ asm_write
+ local i=`expr $i + 1`
+ done
+ asm_discard
+
+ # Write out the table configuration
+ local config_src=`cat << EOF
+ #include "trampoline_table.h"
+
+ extern void *${PAGE_NAME};
+ pl_trampoline_table_config ${PAGE_NAME}_config = {
+ .trampoline_size = ${tramp_size},
+ .page_offset = ${prefix_size},
+ .trampoline_count = ${trampoline_count},
+ .template_page = &${PAGE_NAME}
+ };
+EOF`
+ src "${config_src}"
+}
+
+main
View
202 plblockimp/trampoline_table.c
@@ -0,0 +1,202 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include "trampoline_table.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*
+ * Allocate, register, and return a new trampoline table. The trampoline lock must be held by the caller.
+ *
+ * @param source_page The source page that will be remapped.
+ */
+static pl_trampoline_table *pl_trampoline_table_alloc (pl_trampoline_table_config *config) {
+ pl_trampoline_table *table = NULL;
+
+ /* Loop until we can allocate two contigious pages */
+ while (table == NULL) {
+ vm_address_t data_page = 0x0;
+ kern_return_t kt;
+
+ /* Try to allocate two pages */
+ kt = vm_allocate (mach_task_self(), &data_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
+ if (kt != KERN_SUCCESS) {
+ fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
+ break;
+ }
+
+ /* Now drop the second half of the allocation to make room for the trampoline table */
+ vm_address_t trampoline_page = data_page+PAGE_SIZE;
+ kt = vm_deallocate (mach_task_self(), trampoline_page, PAGE_SIZE);
+ if (kt != KERN_SUCCESS) {
+ fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
+ break;
+ }
+
+ /* Remap the trampoline table to directly follow the config page */
+ vm_prot_t cur_prot;
+ vm_prot_t max_prot;
+
+ kt = vm_remap (mach_task_self(), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self(), (vm_address_t) config->template_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
+
+ /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
+ if (kt != KERN_SUCCESS) {
+ /* Log unexpected failures */
+ if (kt != KERN_NO_SPACE) {
+ fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
+ }
+
+ vm_deallocate (mach_task_self(), data_page, PAGE_SIZE);
+ continue;
+ }
+
+ /* We have valid trampoline and config pages */
+ table = calloc (1, sizeof(pl_trampoline_table));
+ table->free_count = config->trampoline_count;
+ table->data_page = data_page;
+ table->trampoline_page = trampoline_page;
+ table->config = config;
+
+ /* Create and initialize the free list */
+ table->free_list_pool = calloc(config->trampoline_count, sizeof(pl_trampoline));
+
+ uint16_t i;
+ for (i = 0; i < table->free_count; i++) {
+ pl_trampoline *entry = &table->free_list_pool[i];
+ entry->table = table;
+ entry->trampoline = (void *) (table->trampoline_page + (i * config->trampoline_size) + config->page_offset);
+
+ if (i < table->free_count - 1)
+ entry->next = &table->free_list_pool[i+1];
+ }
+
+ table->free_list = table->free_list_pool;
+ }
+
+ return table;
+}
+
+/**
+ * Allocate a new trampoline. Returns NULL on error.
+ *
+ * @param config The table configuration. This value is owned by the caller, and must survive for the lifetime of the table.
+ * @param lock The lock to acquire when modifying shared mutable state.
+ * @param root_table The table from which the entry should be allocated.
+ */
+pl_trampoline *pl_trampoline_alloc (pl_trampoline_table_config *config, pthread_mutex_t *lock, pl_trampoline_table **table_head) {
+ pthread_mutex_lock(lock);
+
+ /* Check for an active trampoline table with available entries. */
+ pl_trampoline_table *table = *table_head;
+ if (table == NULL || table->free_list == NULL) {
+ table = pl_trampoline_table_alloc (config);
+ if (table == NULL) {
+ return NULL;
+ }
+
+ /* Insert the new table at the top of the list */
+ table->next = *table_head;
+ if (table->next != NULL)
+ table->next->prev = table;
+
+ *table_head = table;
+ }
+
+ /* Claim the free entry */
+ pl_trampoline *entry = (*table_head)->free_list;
+ (*table_head)->free_list = entry->next;
+ (*table_head)->free_count--;
+ entry->next = NULL;
+
+ pthread_mutex_unlock(lock);
+
+ return entry;
+}
+
+/**
+ * Given a trampoline's code pointer, return its associated data pointer.
+ */
+void *pl_trampoline_data_ptr (void *code_ptr) {
+ return (uint8_t *) code_ptr - PAGE_SIZE;
+}
+
+/**
+ * Deallocate a trampoline and return it to the free list.
+ *
+ * @param lock The lock to acquire when modifying shared mutable state.
+ * @param root_table The root table from which the entry should be deallocated.
+ * @param tramp The trampoline to deallocate.
+ */
+void pl_trampoline_free (pthread_mutex_t *lock, pl_trampoline_table **table_head, pl_trampoline *tramp) {
+ pthread_mutex_lock(lock);
+
+ /* Fetch the table references */
+ pl_trampoline_table *table = tramp->table;
+
+ /* Return the entry to the free list */
+ tramp->next = table->free_list;
+ table->free_list = tramp;
+ table->free_count++;
+
+ /* If all trampolines within this table are free, and at least one other table exists, deallocate
+ * the table */
+ if (table->free_count == table->config->trampoline_count && *table_head != table) {
+ /* Remove from the list */
+ if (table->prev != NULL)
+ table->prev->next = table->next;
+
+ if (table->next != NULL)
+ table->next->prev = table->prev;
+
+ /* Deallocate pages */
+ kern_return_t kt;
+ kt = vm_deallocate (mach_task_self(), table->data_page, PAGE_SIZE);
+ if (kt != KERN_SUCCESS)
+ fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
+
+ kt = vm_deallocate (mach_task_self(), table->trampoline_page, PAGE_SIZE);
+ if (kt != KERN_SUCCESS)
+ fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
+
+ /* Deallocate free list */
+ free (table->free_list_pool);
+ free (table);
+ } else if (*table_head != table) {
+ /* Otherwise, bump this table to the top of the list */
+ table->prev = NULL;
+ table->next = *table_head;
+ if (*table_head != NULL)
+ (*table_head)->prev = table;
+
+ *table_head = table;
+ }
+
+ pthread_mutex_unlock (lock);
+}
View
92 plblockimp/trampoline_table.h
@@ -0,0 +1,92 @@
+/*
+ * Author: Landon Fuller <landonf@plausible.coop>
+ *
+ * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#ifdef PL_BLOCKIMP_PRIVATE
+
+#include <mach/mach.h>
+#include <pthread.h>
+
+typedef struct pl_trampoline_table pl_trampoline_table;
+typedef struct pl_trampoline pl_trampoline;
+
+/*
+ * Trampoline table configuration
+ */
+typedef struct pl_trampoline_table_config {
+ /* The trampoline size */
+ uint32_t trampoline_size;
+
+ /* The page offset at which the trampolines are located. */
+ uint32_t page_offset;
+
+ /* The number of trampolines allocated per page. */
+ uint32_t trampoline_count;
+
+ /** The template code page. */
+ void *template_page;
+} pl_trampoline_table_config;
+
+/*
+ * A double-linked list of trampoline table entries.
+ */
+struct pl_trampoline_table {
+ /* Table configuration */
+ pl_trampoline_table_config *config;
+
+ /* Contigious writable and executable pages */
+ vm_address_t data_page;
+ vm_address_t trampoline_page;
+
+ /* free list tracking */
+ uint16_t free_count;
+ pl_trampoline *free_list;
+ pl_trampoline *free_list_pool;
+
+ pl_trampoline_table *prev;
+ pl_trampoline_table *next;
+};
+
+/*
+ * A linked list of trampoline table entries.
+ */
+struct pl_trampoline {
+ /* The actual trampoline. */
+ void *(*trampoline)();
+
+ /** The table in which the entry is allocated. */
+ pl_trampoline_table *table;
+
+ /* Next entry in the trampoline list. */
+ pl_trampoline *next;
+};
+
+pl_trampoline *pl_trampoline_alloc (pl_trampoline_table_config *config, pthread_mutex_t *lock, pl_trampoline_table **table_head);
+void pl_trampoline_free (pthread_mutex_t *lock, pl_trampoline_table **table_head, pl_trampoline *tramp);
+void *pl_trampoline_data_ptr (void *code_ptr);
+
+#endif /* PL_BLOCKIMP_PRIVATE */
View
67 plblockimp/x86_32/blockimp_x86_32.tramp
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions
+ARCH="i386"
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ pop %eax
+ andl $0xfffffff8, %eax // truncate to the trampoline start (each is 8 bytes)
+ subl $0x1000, %eax // load the config location
+
+ // Move 'self' to the second parameter, overwriting IMP
+ movl 0x4(%esp), %ecx
+ movl %ecx, 0x8(%esp)
+
+ // Load the block reference from the config page, insert as the first parameter
+ movl (%eax), %eax
+ movl %eax, 0x4(%esp)
+
+ // Jump to the block fptr
+ jmp *0xc(%eax)
+
+ .align 3 // align the trampolines at 8 bytes
+
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+
+ # Call into the dispatcher, placing our return address on the stack.
+ calll _block_tramp_dispatch # 5 bytes
+ .align 3 // align the trampolines at 8 bytes
+EOF
+}
View
67 plblockimp/x86_32/blockimp_x86_32_stret.tramp
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions
+ARCH="i386"
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_stret_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ pop %eax
+ andl $0xfffffff8, %eax // truncate to the trampoline start (each is 8 bytes)
+ subl $0x1000, %eax // load the config location
+
+ // Move 'self' to the third parameter, overwriting IMP
+ movl 0x8(%esp), %ecx
+ movl %ecx, 0xc(%esp)
+
+ // Load the block reference from the config page, insert as the second parameter
+ movl (%eax), %eax
+ movl %eax, 0x8(%esp)
+
+ // Jump to the block fptr
+ jmp *0xc(%eax)
+
+ .align 3 // align the trampolines at 8 bytes
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+
+ # Call into the dispatcher, placing our return address on the stack.
+ calll _block_tramp_dispatch # 5 bytes
+ .align 3 // align the trampolines at 8 bytes
+
+EOF
+}
View
62 plblockimp/x86_64/blockimp_x86_64.tramp
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions
+ARCH="x86_64"
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ pop %r11
+ and $0xfffffffffffffff8, %r11 // truncate to the trampoline start (each is 8 bytes)
+ sub $0x1000, %r11 // load the config location
+
+ // Move 'self' to the second parameter, overwriting IMP
+ movq %rdi, %rsi
+
+ // Load the block reference from the config page, and move to the first parameter
+ movq (%r11), %rdi
+
+ // Jump to the block fptr
+ jmp *0x10(%rdi)
+ .align 4 // align the trampolines at 16 bytes (required for config page lookup and sizing)
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+ // Call into the dispatcher, placing our return address on the stack.
+ call _block_tramp_dispatch # 5 bytes
+ .align 4 // align the trampolines at 16 bytes (required for config page lookup and sizing)
+EOF
+}
View
62 plblockimp/x86_64/blockimp_x86_64_stret.tramp
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------
+# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# ``Software''), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+# -----------------------------------------------------------------------
+
+# Architecture definitions
+ARCH="x86_64"
+PAGE_SIZE="4096"
+
+# The name of this page
+PAGE_NAME=pl_blockimp_table_stret_page
+
+# Prefix to be placed at the start of the trampoline page
+trampoline_prefix () {
+asm << 'EOF'
+ _block_tramp_dispatch:
+ pop %r11
+ and $0xfffffffffffffff8, %r11 // truncate to the trampoline start (each is 8 bytes)
+ sub $0x1000, %r11 // load the config location
+
+ // Move 'self' to the third parameter, overwriting IMP
+ movq %rsi, %rdx
+
+ // Load the block reference from the config page, and move to the second parameter
+ movq (%r11), %rsi
+
+ // Jump to the block fptr
+ jmp *0x10(%rsi)
+ .align 4 // align the trampolines at 16 bytes (required for config page lookup and sizing)
+EOF
+}
+
+# Generate a single trampoline
+trampoline () {
+asm << 'EOF'
+ // Call into the dispatcher, placing our return address on the stack.
+ call _block_tramp_dispatch # 5 bytes
+ .align 4 // align the trampolines at 16 bytes (required for config page lookup and sizing)
+EOF
+}
View
62 rakelib/builder.rake
@@ -7,7 +7,58 @@ task :mark_gc do
end
end
-task :files => [:config_h, :dtrace_h, :revision_h, :mark_gc] do
+desc "Build the plblockimp library for imp_implementationWithBlock() support."
+task :plblockimp do
+ # Prepare assembly trampolines for plblockimp
+ plblockimp_sources = []
+ plblockimp_targets = []
+ ARCHS.each do |a|
+ tramp_sources = ["", "_stret"].map { |s|
+ "plblockimp/#{a}/blockimp_#{a}#{s}.tramp"
+ }
+ tramp_sources.each do |s|
+ unless sh "plblockimp/gentramp.sh #{s} #{a} plblockimp/"
+ $stderr.puts "Failed to generate trampolines for plblockimp"
+ exit 1
+ end
+ end
+ plblockimp_sources.concat( ["", "_stret"].map { |s|
+ "plblockimp/blockimp_#{a}#{s}_config.c"
+ } )
+ as_sources = ["", "_stret"].map { |s|
+ "plblockimp/blockimp_#{a}#{s}.s"
+ }
+ as_sources.each do |s|
+ t = s.sub(%r{\.s$}, ".o")
+ unless sh "as -arch #{a} -o #{t} #{s}"
+ $stderr.puts "Failed to assemble trampolines for plblockimp"
+ exit 1
+ end
+ plblockimp_targets << t
+ end
+ end
+
+ # Build plblockimp as an object file for later linking
+ plblockimp_sources.concat( ["blockimp.c", "trampoline_table.c"].map { |s|
+ "plblockimp/#{s}"
+ } )
+ cflags = $builder.cflags.scan(%r{-[^D][^\s]*}).join(' ').sub(%r{-arch},'')
+ plblockimp_sources.each do |s|
+ t = s.sub(%r{.c$}, ".o")
+ a = ARCHS.map { |x| "-arch #{x}" }.join(' ')
+ unless sh "#{CC} #{a} -c #{cflags} -DPL_BLOCKIMP_PRIVATE -o #{t} #{s}"
+ exit 1
+ end
+ plblockimp_targets << t
+ end
+ plbi_o = plblockimp_targets.join(' ')
+ unless sh "ld #{plbi_o} -r -o #{$builder.objsdir}/plblockimp.o"
+ $stderr.puts "Failed to link plblockimp components"
+ exit 1
+ end
+end
+
+task :files => [:config_h, :dtrace_h, :revision_h, :mark_gc, :plblockimp] do
end
def build_objects
@@ -58,6 +109,9 @@ def build_objects
mv "#{output}.old", output
end
end
+
+
+
dispatcher_o = File.join($builder.objsdir, 'dispatcher.o')
t = File.exist?(dispatcher_o) ? File.mtime(dispatcher_o) : nil
vm_o = File.join($builder.objsdir, 'vm.o')
@@ -75,7 +129,7 @@ desc "Create miniruby"
task :miniruby => :files do
$builder.config = FULL_CONFIG
build_objects
- $builder.link_executable('miniruby', OBJS)
+ $builder.link_executable('miniruby', OBJS + ['plblockimp'])
end
desc "Create config file"
@@ -90,7 +144,7 @@ namespace :macruby do
$builder.config = FULL_CONFIG
build_objects
dylib = "lib#{RUBY_SO_NAME}.#{NEW_RUBY_VERSION}.dylib"
- $builder.link_dylib(dylib, $builder.objs - ['main', 'gc-stub'])
+ $builder.link_dylib(dylib, $builder.objs - ['main', 'gc-stub'] + ['plblockimp'])
major, minor, teeny = NEW_RUBY_VERSION.scan(/\d+/)
["lib#{RUBY_SO_NAME}.#{major}.#{minor}.dylib", "lib#{RUBY_SO_NAME}.dylib"].each do |dylib_alias|
if !File.exist?(dylib_alias) or File.readlink(dylib_alias) != dylib
@@ -105,7 +159,7 @@ namespace :macruby do
if ENABLE_STATIC_LIBRARY
$builder.config = STATIC_CONFIG
build_objects
- $builder.link_archive("lib#{RUBY_SO_NAME}-static.a", $builder.objs - ['main', 'gc-stub'])
+ $builder.link_archive("lib#{RUBY_SO_NAME}-static.a", $builder.objs - ['main', 'gc-stub'] + ['plblockimp'])
end
end
View
4 rakelib/builder/options.rb
@@ -180,8 +180,8 @@ def initialize(opt)
end
@cxxflags << " -fno-rtti" unless @cxxflags.index("-fno-rtti")
@dldflags = "-dynamiclib -undefined suppress -flat_namespace -install_name #{INSTALL_NAME} -current_version #{MACRUBY_VERSION} -compatibility_version #{MACRUBY_VERSION} -exported_symbols_list #{EXPORTED_SYMBOLS_LIST}"
- @cflags << ' -I./icu-1060'
- @cxxflags << ' -I./icu-1060'
+ @cflags << ' -I./icu-1060 -I./plblockimp'
+ @cxxflags << ' -I./icu-1060 -I./plblockimp'
if sdk
sdk_flags = "--sysroot=#{sdk}"
@cflags << " #{sdk_flags}"
View
4 struct.c
@@ -182,9 +182,9 @@ make_struct(VALUE name, VALUE members, VALUE klass)
return val;
};
rb_objc_define_method(nstr, rb_id2name(id),
- imp_implementationWithBlock(Block_copy(struct_ref)), 0);
+ pl_imp_implementationWithBlock(Block_copy(struct_ref)), 0);
rb_objc_define_method(nstr, rb_id2name(rb_id_attrset(id)),
- imp_implementationWithBlock(Block_copy(struct_set)), 1);
+ pl_imp_implementationWithBlock(Block_copy(struct_set)), 1);
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.