Skip to content
This repository
Browse code

Merge pull request #91 from macrotis/struct-use-block-attr-accessors

Use blocks for attribute accessors in Struct to facilitate proper aliasing behavior
  • Loading branch information...
commit b7c9b70f1b85c3e6643071c0408ea0f88b71f462 2 parents f814013 + 3c06b54
Mark Rada ferrous26 authored
2  .gitignore
@@ -44,6 +44,8 @@ mspec/upstream_patches
44 44 mspec_upstream
45 45 node_name.inc
46 46 parse.c
  47 +plblockimp/blockimp_ARM*
  48 +plblockimp/blockimp_x86*
47 49 prelude.c
48 50 rbconfig.rb
49 51 revision.h
28 LEGAL
@@ -316,3 +316,31 @@ icu-*/**/*.h:
2  lib/mkmf.rb
@@ -1932,7 +1932,7 @@ def init_mkmf(config = CONFIG)
1932 1932 $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup
1933 1933 $INCFLAGS = "-I$(arch_hdrdir)"
1934 1934 $INCFLAGS << " -I$(hdrdir)/ruby/backward" unless $extmk
1935   - $INCFLAGS << " -I$(hdrdir) -I$(srcdir)"
  1935 + $INCFLAGS << " -I$(hdrdir) -I$(srcdir) -I$(top_srcdir)/plblockimp"
1936 1936 $DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup
1937 1937 $LIBEXT = config['LIBEXT'].dup
1938 1938 $OBJEXT = config["OBJEXT"].dup
1  macruby_internal.h
@@ -13,6 +13,7 @@ extern "C" {
13 13 #endif
14 14
15 15 #include "ruby.h"
  16 +#include "PLBlockIMP.h"
16 17
17 18 #include <objc/objc.h>
18 19 #include <objc/runtime.h>
66 plblockimp/ARM/blockimp_arm.tramp
... ... @@ -0,0 +1,66 @@
  1 +#!/bin/sh
  2 +
  3 +# -----------------------------------------------------------------------
  4 +# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
  5 +# All Rights Reserved.
  6 +#
  7 +# Permission is hereby granted, free of charge, to any person obtaining
  8 +# a copy of this software and associated documentation files (the
  9 +# ``Software''), to deal in the Software without restriction, including
  10 +# without limitation the rights to use, copy, modify, merge, publish,
  11 +# distribute, sublicense, and/or sell copies of the Software, and to
  12 +# permit persons to whom the Software is furnished to do so, subject to
  13 +# the following conditions:
  14 +#
  15 +# The above copyright notice and this permission notice shall be included
  16 +# in all copies or substantial portions of the Software.
  17 +#
  18 +# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
  19 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21 +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22 +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23 +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25 +# DEALINGS IN THE SOFTWARE.
  26 +# -----------------------------------------------------------------------
  27 +
  28 +# Architecture definitions. We support either armv6 or armv7
  29 +if [ "${CURRENT_ARCH}" = "armv6" ] || [ "${CURRENT_ARCH}" = "armv7" ]; then
  30 + ARCH="${CURRENT_ARCH}"
  31 +else
  32 + ARCH=""
  33 +fi
  34 +
  35 +PAGE_SIZE="4096"
  36 +
  37 +# The name of this page
  38 +PAGE_NAME=pl_blockimp_table_page
  39 +
  40 +# Prefix to be placed at the start of the trampoline page
  41 +trampoline_prefix () {
  42 +asm << 'EOF'
  43 + _block_tramp_dispatch:
  44 + # trampoline address+8 is in r12 -- calculate our config page address
  45 + sub r12, #0x8
  46 + sub r12, #0x1000
  47 +
  48 + # Set the 'self' argument as the second argument
  49 + mov r1, r0
  50 +
  51 + # Load the block pointer as the first argument
  52 + ldr r0, [r12]
  53 +
  54 + # Jump to the block pointer
  55 + ldr pc, [r0, #0xc]
  56 +EOF
  57 +}
  58 +
  59 +# Generate a single trampoline
  60 +trampoline () {
  61 +asm << 'EOF'
  62 + # Save pc+8, then jump to the shared prefix implementation
  63 + mov r12, pc
  64 + b _block_tramp_dispatch;
  65 +EOF
  66 +}
61 plblockimp/ARM/blockimp_arm_stret.tramp
... ... @@ -0,0 +1,61 @@
  1 +#!/bin/sh
  2 +
  3 +# -----------------------------------------------------------------------
  4 +# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
  5 +# All Rights Reserved.
  6 +#
  7 +# Permission is hereby granted, free of charge, to any person obtaining
  8 +# a copy of this software and associated documentation files (the
  9 +# ``Software''), to deal in the Software without restriction, including
  10 +# without limitation the rights to use, copy, modify, merge, publish,
  11 +# distribute, sublicense, and/or sell copies of the Software, and to
  12 +# permit persons to whom the Software is furnished to do so, subject to
  13 +# the following conditions:
  14 +#
  15 +# The above copyright notice and this permission notice shall be included
  16 +# in all copies or substantial portions of the Software.
  17 +#
  18 +# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
  19 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21 +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22 +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23 +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25 +# DEALINGS IN THE SOFTWARE.
  26 +# -----------------------------------------------------------------------
  27 +
  28 +# Architecture definitions
  29 +ARCH="${CURRENT_ARCH}"
  30 +PAGE_SIZE="4096"
  31 +
  32 +# The name of this page
  33 +PAGE_NAME=pl_blockimp_table_stret_page
  34 +
  35 +# Prefix to be placed at the start of the trampoline page
  36 +trampoline_prefix () {
  37 +asm << 'EOF'
  38 + _block_tramp_dispatch:
  39 + # trampoline address+8 is in r12 -- calculate our config page address
  40 + sub r12, #0x8
  41 + sub r12, #0x1000
  42 +
  43 + # Set the 'self' argument as the third argument
  44 + mov r2, r1
  45 +
  46 + # Load the block pointer as the second argument
  47 + ldr r1, [r12]
  48 +
  49 + # Jump to the block pointer
  50 + ldr pc, [r1, #0xc]
  51 +EOF
  52 +}
  53 +
  54 +# Generate a single trampoline
  55 +trampoline () {
  56 +asm << 'EOF'
  57 + # Save pc+8, then jump to the shared prefix implementation
  58 + mov r12, pc
  59 + b _block_tramp_dispatch;
  60 +EOF
  61 +}
28 plblockimp/PLBlockIMP.h
... ... @@ -0,0 +1,28 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +#pragma once
  28 +#include "blockimp.h"
117 plblockimp/blockimp.c
... ... @@ -0,0 +1,117 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +#include "blockimp.h"
  28 +#include "blockimp_private.h"
  29 +
  30 +#include "trampoline_table.h"
  31 +
  32 +#include <stdio.h>
  33 +#include <Block.h>
  34 +
  35 +#pragma mark Trampolines
  36 +
  37 +/* Global lock for our mutable state. Must be held when accessing the trampoline tables. */
  38 +static pthread_mutex_t blockimp_lock = PTHREAD_MUTEX_INITIALIZER;
  39 +
  40 +/* Trampoline tables for objc_msgSend_stret() dispatch. */
  41 +static pl_trampoline_table *blockimp_table_stret = NULL;
  42 +
  43 +/* Trampoline tables for objc_msgSend() dispatch. */
  44 +static pl_trampoline_table *blockimp_table = NULL;
  45 +
  46 +/**
  47 + *
  48 + */
  49 +IMP pl_imp_implementationWithBlock (void *block) {
  50 +#if SUPPORT_APPLE_FALLBACK
  51 + /* Prefer Apple's implementation */
  52 + if (&imp_implementationWithBlock != NULL)
  53 + return imp_implementationWithBlock(block);
  54 +#endif
  55 +
  56 + /* Allocate the appropriate trampoline type. */
  57 + pl_trampoline *tramp;
  58 + struct Block_layout *bl = block;
  59 + if (bl->flags & BLOCK_USE_STRET) {
  60 + tramp = pl_trampoline_alloc(&pl_blockimp_table_stret_page_config, &blockimp_lock, &blockimp_table_stret);
  61 + } else {
  62 + tramp = pl_trampoline_alloc(&pl_blockimp_table_page_config, &blockimp_lock, &blockimp_table);
  63 + }
  64 +
  65 + /* Configure the trampoline */
  66 + void **config = pl_trampoline_data_ptr(tramp->trampoline);
  67 + config[0] = Block_copy(block);
  68 + config[1] = tramp;
  69 +
  70 + /* Return the function pointer. */
  71 + return (IMP) tramp->trampoline;
  72 +}
  73 +
  74 +/**
  75 + *
  76 + */
  77 +void *pl_imp_getBlock(IMP anImp) {
  78 +#if SUPPORT_APPLE_FALLBACK
  79 + /* Prefer Apple's implementation */
  80 + if (&imp_getBlock != NULL) {
  81 + return imp_getBlock(anImp);
  82 + }
  83 +#endif
  84 +
  85 + /* Fetch the config data and return the block reference. */
  86 + void **config = pl_trampoline_data_ptr(anImp);
  87 + return config[0];
  88 +}
  89 +
  90 +/**
  91 + *
  92 + */
  93 +BOOL pl_imp_removeBlock(IMP anImp) {
  94 +#if SUPPORT_APPLE_FALLBACK
  95 + /* Prefer Apple's implementation */
  96 + if (&imp_removeBlock != NULL)
  97 + return imp_removeBlock(anImp);
  98 +#endif
  99 +
  100 + /* Fetch the config data */
  101 + void **config = pl_trampoline_data_ptr(anImp);
  102 + struct Block_layout *bl = config[0];
  103 + pl_trampoline *tramp = config[1];
  104 +
  105 + /* Drop the trampoline allocation */
  106 + if (bl->flags & BLOCK_USE_STRET) {
  107 + pl_trampoline_free(&blockimp_lock, &blockimp_table_stret, tramp);
  108 + } else {
  109 + pl_trampoline_free(&blockimp_lock, &blockimp_table, tramp);
  110 + }
  111 +
  112 + /* Release the block */
  113 + Block_release(config[0]);
  114 +
  115 + // TODO - what does this return value mean?
  116 + return YES;
  117 +}
31 plblockimp/blockimp.h
... ... @@ -0,0 +1,31 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +#include <objc/runtime.h>
  28 +
  29 +extern IMP pl_imp_implementationWithBlock(void *block);
  30 +extern void *pl_imp_getBlock(IMP anImp);
  31 +extern BOOL pl_imp_removeBlock(IMP anImp);
135 plblockimp/blockimp_private.h
... ... @@ -0,0 +1,135 @@
  1 +/*
  2 + * Private Block ABI Structures
  3 + * Originally acquired frm PLBlocks and compiler_rt
  4 + *
  5 + * Copyright 2008 - 2009 Apple, Inc.
  6 + * Copyright 2009 - 2011 Plausible Labs Cooperative, Inc.
  7 + *
  8 + * Permission is hereby granted, free of charge,
  9 + * to any person obtaining a copy of this software and associated documentation
  10 + * files (the "Software"), to deal in the Software without restriction,
  11 + * including without limitation the rights to use, copy, modify, merge, publish,
  12 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  13 + * persons to whom the Software is furnished to do so, subject to the following
  14 + * conditions:
  15 + *
  16 + * The above copyright notice and this permission notice shall be included in
  17 + * all copies or substantial portions of the Software.
  18 + *
  19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  25 + * SOFTWARE.
  26 + *
  27 + */
  28 +
  29 +#pragma once
  30 +
  31 +#if defined(__i386__)
  32 +# include "blockimp_x86_32.h"
  33 +# include "blockimp_x86_32_stret.h"
  34 +#elif defined(__x86_64__)
  35 +# include "blockimp_x86_64.h"
  36 +# include "blockimp_x86_64_stret.h"
  37 +#elif defined(__arm__)
  38 +# include "blockimp_arm.h"
  39 +# include "blockimp_arm_stret.h"
  40 +#else
  41 +# error Unknown Architecture
  42 +#endif
  43 +
  44 +#pragma mark Fallback Support
  45 +
  46 +// if 1, we attempt to use Apple's official implementations
  47 +#define SUPPORT_APPLE_FALLBACK 0
  48 +#if SUPPORT_APPLE_FALLBACK
  49 +extern IMP imp_implementationWithBlock(void *block) WEAK_IMPORT_ATTRIBUTE;
  50 +extern void *imp_getBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
  51 +extern BOOL imp_removeBlock(IMP anImp) WEAK_IMPORT_ATTRIBUTE;
  52 +#endif
  53 +
  54 +/*
  55 + * Block Flags
  56 + */
  57 +typedef enum {
  58 + /** 16-bit block reference count. */
  59 + BLOCK_REFCOUNT_MASK = (0xffff),
  60 +
  61 + BLOCK_NEEDS_FREE = (1 << 24),
  62 + BLOCK_HAS_COPY_DISPOSE = (1 << 25),
  63 +
  64 + /** Helpers have C++ code. */
  65 + BLOCK_HAS_CTOR = (1 << 26),
  66 +
  67 + BLOCK_IS_GC = (1 << 27),
  68 + BLOCK_IS_GLOBAL = (1 << 28),
  69 +
  70 + /** Block returns its aggregate value in memory (ie, the block has a structure return type). */
  71 + BLOCK_USE_STRET = (1 << 29),
  72 +} block_flags_t;
  73 +
  74 +
  75 +/*
  76 + * Block field flags.
  77 + */
  78 +typedef enum {
  79 + // see function implementation for a more complete description of these fields and combinations
  80 + BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
  81 + BLOCK_FIELD_IS_BLOCK = 7, // a block variable
  82 + BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
  83 + BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers
  84 + BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines.
  85 +} block_field_flags_t;
  86 +
  87 +/*
  88 + * Block description.
  89 + *
  90 + * Block descriptions are shared across all instances of a block, and
  91 + * provide basic information on the block size, as well as pointers
  92 + * to any helper functions necessary to copy or dispose of the block.
  93 + */
  94 +struct Block_descriptor {
  95 + /** Reserved value */
  96 + unsigned long int reserved;
  97 +
  98 + /** Total size of the described block, including imported variables. */
  99 + unsigned long int size;
  100 +
  101 + /** Optional block copy helper. May be NULL. */
  102 + void (*copy)(void *dst, void *src);
  103 +
  104 + /** Optional block dispose helper. May be NULL. */
  105 + void (*dispose)(void *);
  106 +};
  107 +
  108 +
  109 +/*
  110 + * Block instance.
  111 + *
  112 + * The block layout defines the per-block instance state, which includes
  113 + * a reference to the shared block descriptor.
  114 + *
  115 + * The block's imported variables are allocated following the block
  116 + * descriptor member.
  117 + */
  118 +struct Block_layout {
  119 + /** Pointer to the block's Objective-C class. */
  120 + void *isa;
  121 +
  122 + /** Block flags. */
  123 + int flags;
  124 +
  125 + /** Reserved value. */
  126 + int reserved;
  127 +
  128 + /** Block invocation function. */
  129 + void (*invoke)(void *, ...);
  130 +
  131 + /** Shared block descriptor. */
  132 + struct Block_descriptor *descriptor;
  133 +
  134 + // imported variables
  135 +};
148 plblockimp/blockimp_tests.m
... ... @@ -0,0 +1,148 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +#import "GTMSenTestCase.h"
  28 +#import "blockimp.h"
  29 +
  30 +@interface BlockIMPTests : SenTestCase @end
  31 +
  32 +/**
  33 + * BlockIMP Tests
  34 + */
  35 +@implementation BlockIMPTests
  36 +
  37 +/**
  38 + * Test basic IMP allocation and execution.
  39 + */
  40 +- (void) testAllocateIMP {
  41 + /* A test block */
  42 + __block BOOL didRun = NO;
  43 + void (^Block)(id self) = ^(id blockself) {
  44 + didRun = YES;
  45 +
  46 + STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
  47 + };
  48 +
  49 + /* Create the IMP */
  50 + IMP imp = pl_imp_implementationWithBlock(Block);
  51 + STAssertTrue(imp != NULL, @"Returned NULL IMP");
  52 +
  53 + /* Verify the IMP is valid. */
  54 + void (*ptr)(id self, SEL _cmd) = (void *) imp;
  55 + ptr(self, @selector(testAllocateIMP));
  56 + STAssertTrue(didRun, @"Block was not run");
  57 +
  58 + /* Clean up */
  59 + pl_imp_removeBlock(imp);
  60 +}
  61 +
  62 +/**
  63 + * Test basic stret IMP allocation and execution.
  64 + */
  65 +- (void) testAllocateStretIMP {
  66 + /* A test block */
  67 + __block BOOL didRun = NO;
  68 + NSRange (^Block)(id self) = ^NSRange (id blockself) {
  69 + didRun = YES;
  70 +
  71 + STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
  72 + return NSMakeRange(42, 1);
  73 + };
  74 +
  75 + /* Create the IMP */
  76 + IMP imp = pl_imp_implementationWithBlock(Block);
  77 + STAssertTrue(imp != NULL, @"Returned NULL IMP");
  78 +
  79 + /* Verify the IMP is valid. */
  80 + NSRange (*ptr)(id self, SEL _cmd) = (void *) imp;
  81 + NSRange result = ptr(self, @selector(testAllocateStretIMP));
  82 +
  83 + STAssertTrue(didRun, @"Block was not run");
  84 + STAssertEquals(result.location, (NSUInteger)42, @"Incorrect location");
  85 + STAssertEquals(result.length, (NSUInteger)1, @"Incorrect length");
  86 +
  87 + /* Clean up */
  88 + pl_imp_removeBlock(imp);
  89 +}
  90 +
  91 +/**
  92 + * Test fetching of the Block ptr from the IMP pointer.
  93 + */
  94 +- (void) testGetBlock {
  95 + /* A test block */
  96 + void (^Block)(id self) = [[^(id blockself) {
  97 + STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
  98 + } copy] autorelease];
  99 +
  100 + /* Create the IMP */
  101 + IMP imp = pl_imp_implementationWithBlock(Block);
  102 + STAssertTrue(imp != NULL, @"Returned NULL IMP");
  103 +
  104 + /* Try to fetch the underlying block */
  105 + void *b = pl_imp_getBlock(imp);
  106 + STAssertEquals(b, (void *) Block, @"Did not fetch block");
  107 +
  108 + /* Clean up */
  109 + pl_imp_removeBlock(imp);
  110 +}
  111 +
  112 +/**
  113 + * Exercise block allocation
  114 + */
  115 +- (void) testAllocationExcercise {
  116 + /* A test block */
  117 + __block int callCount = 0;
  118 + void (^Block)(id self) = [[^(id blockself) {
  119 + callCount++;
  120 + STAssertEqualObjects(blockself, self, @"Incorrect 'self' pointer");
  121 + } copy] autorelease];
  122 +
  123 + /* Use a count larger than what a single page (on any architecture) can likely hold */
  124 + int count=PAGE_SIZE*2;
  125 +
  126 + /* Generate the IMPs */
  127 + IMP *imps = malloc(sizeof(IMP) * count);
  128 + for (int i = 0; i < count; i++) {
  129 + imps[i] = pl_imp_implementationWithBlock(Block);
  130 + }
  131 +
  132 + /* Call the IMPs */
  133 + for (int i = 0; i < count; i++) {
  134 + void (*ptr)(id self, SEL _cmd) = (void *) imps[i];
  135 + ptr(self, @selector(testAllocationExcercise));
  136 + }
  137 +
  138 + /* Clean up the IMPs. We do this in reverse to exercise table reordering. */
  139 + for (int i = count-1; i+1 >= 1; i--) {
  140 + pl_imp_removeBlock(imps[i]);
  141 + }
  142 + free(imps);
  143 +
  144 + /* Verify the result */
  145 + STAssertEquals(callCount, count, @"Call count does not match expected count; not all IMPs were called");
  146 +}
  147 +
  148 +@end
207 plblockimp/gentramp.sh
... ... @@ -0,0 +1,207 @@
  1 +#!/bin/sh
  2 +
  3 +# -----------------------------------------------------------------------
  4 +# gentramp.sh - Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
  5 +#
  6 +# Trampoline Page Generator
  7 +# Author: Landon Fuller <landonf@plausible.coop>
  8 +#
  9 +# Permission is hereby granted, free of charge, to any person obtaining
  10 +# a copy of this software and associated documentation files (the
  11 +# ``Software''), to deal in the Software without restriction, including
  12 +# without limitation the rights to use, copy, modify, merge, publish,
  13 +# distribute, sublicense, and/or sell copies of the Software, and to
  14 +# permit persons to whom the Software is furnished to do so, subject to
  15 +# the following conditions:
  16 +#
  17 +# The above copyright notice and this permission notice shall be included
  18 +# in all copies or substantial portions of the Software.
  19 +#
  20 +# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
  21 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23 +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  24 +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  25 +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  27 +# DEALINGS IN THE SOFTWARE.
  28 +# -----------------------------------------------------------------------
  29 +
  30 +PROGNAME=$0
  31 +
  32 +INPUT_FILE_PATH="$1"
  33 +INPUT_FILE_BASE="`basename -a $(sed s/\.[^.]*$// <<< $INPUT_FILE_PATH)`"
  34 +CURRENT_ARCH="$2"
  35 +OUTPUT_DIR="$3"
  36 +SRC_C_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}_config.c"
  37 +SRC_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.s"
  38 +HEADER_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.h"
  39 +
  40 +# Default implementation
  41 +trampoline_prefix () {
  42 + return 0
  43 +}
  44 +
  45 +# Import the trampoline definition
  46 +. ${INPUT_FILE_PATH}
  47 +
  48 +check_required () {
  49 + local name=$1
  50 + eval "local var=\${$1}"
  51 +
  52 + if [ -z "${var}" ]; then
  53 + echo "Required variable ${name} not defined."
  54 + exit 1
  55 + fi
  56 +}
  57 +
  58 +check_required ARCH
  59 +check_required PAGE_SIZE
  60 +check_required PAGE_NAME
  61 +
  62 +# Write a header line
  63 +header () {
  64 + echo "$1" >> "${HEADER_OUTPUT}"
  65 +}
  66 +
  67 +# Write a C source line
  68 +src () {
  69 + echo "$1" >> "${SRC_C_OUTPUT}"
  70 +}
  71 +
  72 +# Flush the assembler output buffer to disk
  73 +ASM_BUFFER=""
  74 +asm_flush () {
  75 + echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
  76 + asm_discard
  77 +}
  78 +
  79 +# Write the assembler buffer to disk, but don't discard the contents
  80 +asm_write () {
  81 + echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
  82 +}
  83 +
  84 +# Discard the current assembler output buffer
  85 +asm_discard () {
  86 + ASM_BUFFER=''
  87 + return 0;
  88 +}
  89 +
  90 +# Append data to the assembler output buffer
  91 +asm () {
  92 + local line=""
  93 + while read -r line; do
  94 + ASM_BUFFER+=$line
  95 + ASM_BUFFER+="\n"
  96 + done
  97 +}
  98 +
  99 +# Compute the assembled size of the current assembler buffer
  100 +compute_asm_size () {
  101 + # Create the temporary assembler file
  102 + local output=".globl _byte_count_start\n"
  103 + output+="_byte_count_start:\n"
  104 + output+="${ASM_BUFFER}"
  105 + output+=".globl _byte_count_end\n"
  106 + output+="_byte_count_end:\n"
  107 +
  108 + local tempfile=`mktemp /tmp/as_bytecount.XXXXXXXX`
  109 + echo "${output}" | as -arch "${CURRENT_ARCH}" -o "${tempfile}" -
  110 + if [ $? != 0 ]; then
  111 + echo "Assembling the trampoline failed"
  112 + exit 1
  113 + fi
  114 +
  115 + local byte_size=`nm -t d -P "${tempfile}" | grep ^_byte_count_end | awk '{print $3}'`
  116 + rm -f "${tempfile}"
  117 +
  118 + echo $byte_size
  119 +}
  120 +
  121 +
  122 +# Write out the page header
  123 +write_page_decl () {
  124 + # Calculate the required alignment
  125 + local align=`perl -l -e "print log(${PAGE_SIZE})/log(2)"`
  126 + asm << EOF
  127 + # GENERATED CODE - DO NOT EDIT"
  128 + # This file was generated by $PROGNAME on `date`
  129 +
  130 + # Write out the trampoline table, aligned to the page boundary
  131 + .text
  132 + .align ${align}
  133 + .globl _${PAGE_NAME}
  134 + _${PAGE_NAME}:
  135 +EOF
  136 +}
  137 +
  138 +main () {
  139 + echo '' > "${SRC_OUTPUT}"
  140 + echo '' > "${SRC_C_OUTPUT}"
  141 + echo '' > "${HEADER_OUTPUT}"
  142 +
  143 + # Write out the trampoline header file
  144 + header "extern void *${PAGE_NAME};"
  145 + header "extern struct pl_trampoline_table_config ${PAGE_NAME}_config;"
  146 +
  147 + # Don't generate the sources for the incorrect arch
  148 + if [ "${ARCH}" != "${CURRENT_ARCH}" ]; then
  149 + return
  150 + fi
  151 +
  152 + # Determine the trampoline prefix size
  153 + trampoline_prefix
  154 + local prefix_size=$(compute_asm_size)
  155 + asm_discard
  156 +
  157 + # Compute the size of the remaining code page.
  158 + local page_avail=`expr $PAGE_SIZE - $prefix_size`
  159 +
  160 + # Determine the trampoline size
  161 + trampoline
  162 + local tramp_size=$(compute_asm_size)
  163 + asm_discard
  164 + if [ "${tramp_size}" = 0 ]; then
  165 + echo "Error occured calculating trampoline size; received size of 0"
  166 + exit 1
  167 + fi
  168 +
  169 + # Compute the number of of available trampolines.
  170 + local trampoline_count=`expr $page_avail / $tramp_size`
  171 + echo "Prefix size: ${prefix_size}"
  172 + echo "Trampoline size: ${tramp_size}"
  173 + echo "Trampolines per page: ${trampoline_count}"
  174 +
  175 + # Write out the page declaration
  176 + write_page_decl
  177 + asm_flush
  178 +
  179 + # Write out the prefix
  180 + trampoline_prefix
  181 + asm_flush
  182 +
  183 + # Write out the trampolines
  184 + trampoline
  185 + local i=0
  186 + while [ $i -lt ${trampoline_count} ]; do
  187 + asm_write
  188 + local i=`expr $i + 1`
  189 + done
  190 + asm_discard
  191 +
  192 + # Write out the table configuration
  193 + local config_src=`cat << EOF
  194 + #include "trampoline_table.h"
  195 +
  196 + extern void *${PAGE_NAME};
  197 + pl_trampoline_table_config ${PAGE_NAME}_config = {
  198 + .trampoline_size = ${tramp_size},
  199 + .page_offset = ${prefix_size},
  200 + .trampoline_count = ${trampoline_count},
  201 + .template_page = &${PAGE_NAME}
  202 + };
  203 +EOF`
  204 + src "${config_src}"
  205 +}
  206 +
  207 +main
202 plblockimp/trampoline_table.c
... ... @@ -0,0 +1,202 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +
  28 +#include "trampoline_table.h"
  29 +
  30 +#include <pthread.h>
  31 +#include <stdio.h>
  32 +#include <stdlib.h>
  33 +
  34 +
  35 +/*
  36 + * Allocate, register, and return a new trampoline table. The trampoline lock must be held by the caller.
  37 + *
  38 + * @param source_page The source page that will be remapped.
  39 + */
  40 +static pl_trampoline_table *pl_trampoline_table_alloc (pl_trampoline_table_config *config) {
  41 + pl_trampoline_table *table = NULL;
  42 +
  43 + /* Loop until we can allocate two contigious pages */
  44 + while (table == NULL) {
  45 + vm_address_t data_page = 0x0;
  46 + kern_return_t kt;
  47 +
  48 + /* Try to allocate two pages */
  49 + kt = vm_allocate (mach_task_self(), &data_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE);
  50 + if (kt != KERN_SUCCESS) {
  51 + fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
  52 + break;
  53 + }
  54 +
  55 + /* Now drop the second half of the allocation to make room for the trampoline table */
  56 + vm_address_t trampoline_page = data_page+PAGE_SIZE;
  57 + kt = vm_deallocate (mach_task_self(), trampoline_page, PAGE_SIZE);
  58 + if (kt != KERN_SUCCESS) {
  59 + fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
  60 + break;
  61 + }
  62 +
  63 + /* Remap the trampoline table to directly follow the config page */
  64 + vm_prot_t cur_prot;
  65 + vm_prot_t max_prot;
  66 +
  67 + 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);
  68 +
  69 + /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */
  70 + if (kt != KERN_SUCCESS) {
  71 + /* Log unexpected failures */
  72 + if (kt != KERN_NO_SPACE) {
  73 + fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
  74 + }
  75 +
  76 + vm_deallocate (mach_task_self(), data_page, PAGE_SIZE);
  77 + continue;
  78 + }
  79 +
  80 + /* We have valid trampoline and config pages */
  81 + table = calloc (1, sizeof(pl_trampoline_table));
  82 + table->free_count = config->trampoline_count;
  83 + table->data_page = data_page;
  84 + table->trampoline_page = trampoline_page;
  85 + table->config = config;
  86 +
  87 + /* Create and initialize the free list */
  88 + table->free_list_pool = calloc(config->trampoline_count, sizeof(pl_trampoline));
  89 +
  90 + uint16_t i;
  91 + for (i = 0; i < table->free_count; i++) {
  92 + pl_trampoline *entry = &table->free_list_pool[i];
  93 + entry->table = table;
  94 + entry->trampoline = (void *) (table->trampoline_page + (i * config->trampoline_size) + config->page_offset);
  95 +
  96 + if (i < table->free_count - 1)
  97 + entry->next = &table->free_list_pool[i+1];
  98 + }
  99 +
  100 + table->free_list = table->free_list_pool;
  101 + }
  102 +
  103 + return table;
  104 +}
  105 +
  106 +/**
  107 + * Allocate a new trampoline. Returns NULL on error.
  108 + *
  109 + * @param config The table configuration. This value is owned by the caller, and must survive for the lifetime of the table.
  110 + * @param lock The lock to acquire when modifying shared mutable state.
  111 + * @param root_table The table from which the entry should be allocated.
  112 + */
  113 +pl_trampoline *pl_trampoline_alloc (pl_trampoline_table_config *config, pthread_mutex_t *lock, pl_trampoline_table **table_head) {
  114 + pthread_mutex_lock(lock);
  115 +
  116 + /* Check for an active trampoline table with available entries. */
  117 + pl_trampoline_table *table = *table_head;
  118 + if (table == NULL || table->free_list == NULL) {
  119 + table = pl_trampoline_table_alloc (config);
  120 + if (table == NULL) {
  121 + return NULL;
  122 + }
  123 +
  124 + /* Insert the new table at the top of the list */
  125 + table->next = *table_head;
  126 + if (table->next != NULL)
  127 + table->next->prev = table;
  128 +
  129 + *table_head = table;
  130 + }
  131 +
  132 + /* Claim the free entry */
  133 + pl_trampoline *entry = (*table_head)->free_list;
  134 + (*table_head)->free_list = entry->next;
  135 + (*table_head)->free_count--;
  136 + entry->next = NULL;
  137 +
  138 + pthread_mutex_unlock(lock);
  139 +
  140 + return entry;
  141 +}
  142 +
  143 +/**
  144 + * Given a trampoline's code pointer, return its associated data pointer.
  145 + */
  146 +void *pl_trampoline_data_ptr (void *code_ptr) {
  147 + return (uint8_t *) code_ptr - PAGE_SIZE;
  148 +}
  149 +
  150 +/**
  151 + * Deallocate a trampoline and return it to the free list.
  152 + *
  153 + * @param lock The lock to acquire when modifying shared mutable state.
  154 + * @param root_table The root table from which the entry should be deallocated.
  155 + * @param tramp The trampoline to deallocate.
  156 + */
  157 +void pl_trampoline_free (pthread_mutex_t *lock, pl_trampoline_table **table_head, pl_trampoline *tramp) {
  158 + pthread_mutex_lock(lock);
  159 +
  160 + /* Fetch the table references */
  161 + pl_trampoline_table *table = tramp->table;
  162 +
  163 + /* Return the entry to the free list */
  164 + tramp->next = table->free_list;
  165 + table->free_list = tramp;
  166 + table->free_count++;
  167 +
  168 + /* If all trampolines within this table are free, and at least one other table exists, deallocate
  169 + * the table */
  170 + if (table->free_count == table->config->trampoline_count && *table_head != table) {
  171 + /* Remove from the list */
  172 + if (table->prev != NULL)
  173 + table->prev->next = table->next;
  174 +
  175 + if (table->next != NULL)
  176 + table->next->prev = table->prev;
  177 +
  178 + /* Deallocate pages */
  179 + kern_return_t kt;
  180 + kt = vm_deallocate (mach_task_self(), table->data_page, PAGE_SIZE);
  181 + if (kt != KERN_SUCCESS)
  182 + fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
  183 +
  184 + kt = vm_deallocate (mach_task_self(), table->trampoline_page, PAGE_SIZE);
  185 + if (kt != KERN_SUCCESS)
  186 + fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__);
  187 +
  188 + /* Deallocate free list */
  189 + free (table->free_list_pool);
  190 + free (table);
  191 + } else if (*table_head != table) {
  192 + /* Otherwise, bump this table to the top of the list */
  193 + table->prev = NULL;
  194 + table->next = *table_head;
  195 + if (*table_head != NULL)
  196 + (*table_head)->prev = table;
  197 +
  198 + *table_head = table;
  199 + }
  200 +
  201 + pthread_mutex_unlock (lock);
  202 +}
92 plblockimp/trampoline_table.h
... ... @@ -0,0 +1,92 @@
  1 +/*
  2 + * Author: Landon Fuller <landonf@plausible.coop>
  3 + *
  4 + * Copyright 2010-2011 Plausible Labs Cooperative, Inc.
  5 + * All rights reserved.
  6 + *
  7 + * Permission is hereby granted, free of charge,
  8 + * to any person obtaining a copy of this software and associated documentation
  9 + * files (the "Software"), to deal in the Software without restriction,
  10 + * including without limitation the rights to use, copy, modify, merge, publish,
  11 + * distribute, sublicense, and/or sell copies of the Software, and to permit
  12 + * persons to whom the Software is furnished to do so, subject to the following
  13 + * conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 + * SOFTWARE.
  25 + */
  26 +
  27 +#pragma once
  28 +
  29 +#ifdef PL_BLOCKIMP_PRIVATE
  30 +
  31 +#include <mach/mach.h>
  32 +#include <pthread.h>
  33 +
  34 +typedef struct pl_trampoline_table pl_trampoline_table;
  35 +typedef struct pl_trampoline pl_trampoline;
  36 +
  37 +/*
  38 + * Trampoline table configuration
  39 + */
  40 +typedef struct pl_trampoline_table_config {
  41 + /* The trampoline size */
  42 + uint32_t trampoline_size;
  43 +
  44 + /* The page offset at which the trampolines are located. */
  45 + uint32_t page_offset;
  46 +
  47 + /* The number of trampolines allocated per page. */
  48 + uint32_t trampoline_count;
  49 +
  50 + /** The template code page. */
  51 + void *template_page;
  52 +} pl_trampoline_table_config;
  53 +
  54 +/*
  55 + * A double-linked list of trampoline table entries.
  56 + */
  57 +struct pl_trampoline_table {
  58 + /* Table configuration */
  59 + pl_trampoline_table_config *config;
  60 +
  61 + /* Contigious writable and executable pages */
  62 + vm_address_t data_page;
  63 + vm_address_t trampoline_page;
  64 +
  65 + /* free list tracking */
  66 + uint16_t free_count;
  67 + pl_trampoline *free_list;
  68 + pl_trampoline *free_list_pool;
  69 +
  70 + pl_trampoline_table *prev;
  71 + pl_trampoline_table *next;
  72 +};
  73 +
  74 +/*
  75 + * A linked list of trampoline table entries.
  76 + */
  77 +struct pl_trampoline {
  78 + /* The actual trampoline. */
  79 + void *(*trampoline)();
  80 +
  81 + /** The table in which the entry is allocated. */
  82 + pl_trampoline_table *table;
  83 +
  84 + /* Next entry in the trampoline list. */
  85 + pl_trampoline *next;
  86 +};
  87 +
  88 +pl_trampoline *pl_trampoline_alloc (pl_trampoline_table_config *config, pthread_mutex_t *lock, pl_trampoline_table **table_head);
  89 +void pl_trampoline_free (pthread_mutex_t *lock, pl_trampoline_table **table_head, pl_trampoline *tramp);
  90 +void *pl_trampoline_data_ptr (void *code_ptr);
  91 +
  92 +#endif /* PL_BLOCKIMP_PRIVATE */
67 plblockimp/x86_32/blockimp_x86_32.tramp
... ... @@ -0,0 +1,67 @@
  1 +#!/bin/sh
  2 +
  3 +# -----------------------------------------------------------------------
  4 +# Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
  5 +# All Rights Reserved.
  6 +#
  7 +# Permission is hereby granted, free of charge, to any person obtaining
  8 +# a copy of this software and associated documentation files (the
  9 +# ``Software''), to deal in the Software without restriction, including
  10 +# without limitation the rights to use, copy, modify, merge, publish,
  11 +# distribute, sublicense, and/or sell copies of the Software, and to
  12 +# permit persons to whom the Software is furnished to do so, subject to
  13 +# the following conditions: