public
Description: The Nu programming language.
Homepage: http://programming.nu
Clone URL: git://github.com/timburks/nu.git
Search Repo:
Preliminary support for precompiled method handlers.

Up to now, method handlers have been constructed dynamically
with libffi. This involved generating machine-level code at
runtime, which on some platforms, also required setting
memory permissions for the new code to allow execution.

On platforms where this is not possible, we can alternately
dynamically assign handlers from a precompiled pool of
configurable method handlers. While this imposes resource
limits, in practice as many method handlers as needed can
be easily added by applications and loadable bundles
using the NuHandlerWarehouse api.

Currently handlers are implemented entirely in C, which
forces us to associate different pools of handers with
different return types. But this can be resolved at
the assembly language level.
timburks (author)
Thu May 15 12:25:54 -0700 2008
commit  738822c78d5b91857f44af345be4ad21ab46ab6b
tree    9234e77f1834933c71fe402fe65123174e211d86
parent  52fb3c2199c8b9534a840aacbc0cb42776e1cb74
...
35
36
37
 
38
39
40
...
1095
1096
1097
1098
 
1099
1100
1101
1102
1103
1104
1105
 
1106
1107
1108
...
1110
1111
1112
1113
1114
1115
1116
...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1136
1137
1138
...
35
36
37
38
39
40
41
...
1096
1097
1098
 
1099
1100
1101
1102
 
1103
 
 
1104
1105
1106
1107
...
1109
1110
1111
 
1112
1113
1114
...
1122
1123
1124
 
1125
1126
1127
1128
1129
1130
 
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
0
@@ -35,6 +35,7 @@ limitations under the License.
0
 #import "st.h"
0
 #import "reference.h"
0
 #import "pointer.h"
0
+#import "handler.h"
0
 #import <sys/mman.h>
0
 
0
 /*
0
@@ -1095,14 +1096,12 @@ static void objc_calling_nu_method_handler(ffi_cif* cif, void* returnvalue, void
0
     [pool release];
0
 }
0
 
0
-IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature)
0
+char **generate_userdata(SEL sel, NuBlock *block, const char *signature)
0
 {
0
     NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature];
0
     const char *return_type_string = [methodSignature methodReturnType];
0
- ffi_type *result_type = ffi_type_for_objc_type(return_type_string);
0
     int argument_count = [methodSignature numberOfArguments];
0
- char **userdata = (char **) malloc ((argument_count+2) * sizeof(char*));
0
- ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *));
0
+ char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*));
0
     userdata[0] = (char *) malloc (2 + strlen(return_type_string));
0
     #ifdef DARWIN
0
     const char *methodName = sel_getName(sel);
0
@@ -1110,7 +1109,6 @@ IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature)
0
     const char *methodName = sel_get_name(sel);
0
     #endif
0
     BOOL returnsRetainedResult = NO;
0
-
0
     if ((!strcmp(methodName, "alloc")) ||
0
         (!strcmp(methodName, "allocWithZone:")) ||
0
         (!strcmp(methodName, "copy")) ||
0
@@ -1124,15 +1122,38 @@ IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature)
0
     else
0
         sprintf(userdata[0], " %s", return_type_string);
0
     //NSLog(@"constructing handler for method %s with %d arguments and returnType %s", methodName, argument_count, userdata[0]);
0
-
0
     userdata[1] = (char *) block;
0
     [block retain];
0
     int i;
0
     for (i = 0; i < argument_count; i++) {
0
         const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i];
0
         if (i > 1) userdata[i] = strdup(argument_type_string);
0
- argument_types[i] = ffi_type_for_objc_type(argument_type_string);
0
     }
0
+ userdata[argument_count] = NULL;
0
+ return userdata;
0
+}
0
+
0
+IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature)
0
+{
0
+ char **userdata = generate_userdata(sel, block, signature);
0
+ IMP imp = [NuHandlerWarehouse handlerWithSelector:sel block:block signature:signature userdata:userdata];
0
+ if (imp) {
0
+ return imp;
0
+ }
0
+ int argument_count = 0;
0
+ while (userdata[argument_count] != 0) argument_count++;
0
+ #ifdef DARWIN
0
+ const char *methodName = sel_getName(sel);
0
+ #else
0
+ const char *methodName = sel_get_name(sel);
0
+ #endif
0
+ //NSLog(@"using libffi to construct handler for method %s with %d arguments and signature %s", methodName, argument_count, signature);
0
+ ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *));
0
+ ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1);
0
+ argument_types[0] = ffi_type_for_objc_type("@");
0
+ argument_types[1] = ffi_type_for_objc_type(":");
0
+ for (int i = 2; i < argument_count; i++)
0
+ argument_types[i] = ffi_type_for_objc_type(userdata[i]);
0
     argument_types[argument_count] = NULL;
0
     ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif));
0
     if (cif == NULL) {
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
0
@@ -0,0 +1,37 @@
0
+/*!
0
+@header handler.h
0
+@discussion Nu support for precompiled method handlers.
0
+@copyright Copyright (c) 2008 Neon Design Technology, Inc.
0
+
0
+Licensed under the Apache License, Version 2.0 (the "License");
0
+you may not use this file except in compliance with the License.
0
+You may obtain a copy of the License at
0
+
0
+http://www.apache.org/licenses/LICENSE-2.0
0
+
0
+Unless required by applicable law or agreed to in writing, software
0
+distributed under the License is distributed on an "AS IS" BASIS,
0
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0
+See the License for the specific language governing permissions and
0
+limitations under the License.
0
+*/
0
+
0
+#import <Foundation/Foundation.h>
0
+#import "block.h"
0
+
0
+struct handler_description
0
+{
0
+ IMP handler;
0
+ char **description;
0
+};
0
+
0
+@interface NuHandlerWarehouse : NSObject
0
+{
0
+}
0
+
0
++ (void) registerHandlers:(struct handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType;
0
++ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata;
0
+
0
+@end
0
+
0
+void nu_handler(void *return_value, struct handler_description *description, id receiver, va_list ap);
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
0
@@ -0,0 +1,141 @@
0
+/*!
0
+@file handler.m
0
+@description Nu support for precompiled method handlers.
0
+@copyright Copyright (c) 2008 Neon Design Technology, Inc.
0
+
0
+Licensed under the Apache License, Version 2.0 (the "License");
0
+you may not use this file except in compliance with the License.
0
+You may obtain a copy of the License at
0
+
0
+http://www.apache.org/licenses/LICENSE-2.0
0
+
0
+Unless required by applicable law or agreed to in writing, software
0
+distributed under the License is distributed on an "AS IS" BASIS,
0
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0
+See the License for the specific language governing permissions and
0
+limitations under the License.
0
+*/
0
+
0
+#import "handler.h"
0
+#import "cell.h"
0
+
0
+static id collect_arguments(struct handler_description *description, va_list ap)
0
+{
0
+ int i = 0;
0
+ char *type;
0
+ id arguments = [[NuCell alloc] init];
0
+ id cursor = arguments;
0
+ while((type = description->description[2+i])) {
0
+ [cursor setCdr:[[[NuCell alloc] init] autorelease]];
0
+ cursor = [cursor cdr];
0
+ //NSLog(@"argument type %d: %s", i, type);
0
+ if (!strcmp(type, "@")) {
0
+ [cursor setCar:va_arg(ap, id)];
0
+ }
0
+ else if (!strcmp(type, "i")) {
0
+ int x = va_arg(ap, int);
0
+ [cursor setCar:get_nu_value_from_objc_value(&x, type)];
0
+ }
0
+ else if (!strcmp(type, "f")) {
0
+ // calling this w/ float crashes on intel
0
+ double x = (double) va_arg(ap, double);
0
+ //NSLog(@"argument is %f", *((float *) &x));
0
+ ap = ap - sizeof(float); // messy, messy...
0
+ [cursor setCar:get_nu_value_from_objc_value(&x, type)];
0
+ }
0
+ else if (!strcmp(type, "d")) {
0
+ double x = va_arg(ap, double);
0
+ //NSLog(@"argument is %lf", x);
0
+ [cursor setCar:get_nu_value_from_objc_value(&x, type)];
0
+ }
0
+ else if (!strcmp(type, "^@")) {
0
+ void *x = va_arg(ap, void *);
0
+ //NSLog(@"argument is %lf", x);
0
+ [cursor setCar:get_nu_value_from_objc_value(&x, type)];
0
+ }
0
+ else {
0
+ NSLog(@"unsupported argument type %s, see objc/handler.m to add support for it", type);
0
+ }
0
+ i++;
0
+ }
0
+ return arguments;
0
+}
0
+
0
+// helper function called by method handlers
0
+void nu_handler(void *return_value, struct handler_description *description, id receiver, va_list ap)
0
+{
0
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
0
+ id arguments = collect_arguments(description, ap);
0
+ NuBlock *block = (NuBlock *) description->description[1];
0
+ id result = [block evalWithArguments:[arguments cdr] context:nil self:receiver];
0
+ if (description->description[0][1] == '@') {
0
+ [result retain];
0
+ if (description->description[0][0] == '!') {
0
+ [result retain];
0
+ }
0
+ }
0
+ if (return_value) {
0
+ set_objc_value_from_nu_value(return_value, result, description->description[0]+1);
0
+ }
0
+ [arguments release];
0
+ [pool release];
0
+ if (description->description[0][1] == '@') {
0
+ [result autorelease];
0
+ }
0
+}
0
+
0
+@interface NuHandlers : NSObject
0
+{
0
+ @public
0
+ struct handler_description *handlers;
0
+ int handler_count;
0
+ int next_free_handler;
0
+}
0
+
0
+@end
0
+
0
+@implementation NuHandlers
0
+- (id) initWithHandlers:(struct handler_description *) h count:(int) count
0
+{
0
+ [super init];
0
+ handlers = h;
0
+ handler_count = count;
0
+ next_free_handler = 0;
0
+ return self;
0
+}
0
+
0
+@end
0
+
0
+static NSMutableDictionary *handlerWarehouse = nil;
0
+
0
+@implementation NuHandlerWarehouse
0
+
0
++ (void) registerHandlers:(struct handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType
0
+{
0
+ if (!handlerWarehouse) {
0
+ handlerWarehouse = [[NSMutableDictionary alloc] init];
0
+ }
0
+ NuHandlers *handlers = [[NuHandlers alloc] initWithHandlers:description count:count];
0
+ [handlerWarehouse setObject:handlers forKey:returnType];
0
+ [handlers release];
0
+}
0
+
0
++ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata
0
+{
0
+ if (!handlerWarehouse) {
0
+ return NULL;
0
+ }
0
+ NuHandlers *handlers =
0
+ [handlerWarehouse objectForKey:[NSString stringWithCString:userdata[0]+1 encoding:NSUTF8StringEncoding]];
0
+ if (handlers) {
0
+ if (handlers->next_free_handler < handlers->handler_count) {
0
+ handlers->handlers[handlers->next_free_handler].description = userdata;
0
+ IMP handler = handlers->handlers[handlers->next_free_handler].handler;
0
+ handlers->next_free_handler++;
0
+ return handler;
0
+ }
0
+ }
0
+ return NULL;
0
+}
0
+
0
+@end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
0
@@ -0,0 +1,60 @@
0
+;; Use this script to generate precompiled configurable method handlers.
0
+;; Copyright 2008, Tim Burks, Neon Design Technology, Inc.
0
+;; Released under the Apache License, 2.0.
0
+
0
+(load "template")
0
+
0
+(function generate-handlers-for-type (type count)
0
+ (set lower (type lowercaseString))
0
+ (eval (NuTemplate codeForString:<<-END
0
+struct handler_description nu_handlers_returning_<%= lower %>[<%= count %>];
0
+<% (count times:(do (i) %>
0
+static <%= type %> nu_handler_returning_<%= lower %>_<%= i %> (id receiver, SEL selector, ...)
0
+{
0
+ va_list ap;
0
+ va_start(ap, selector);
0
+ <% (if (!= type "void") %><%= type %> result;<% ) %>
0
+ nu_handler(<% (if (!= type "void") then %>&result<% else %>0<% ) %>, &nu_handlers_returning_<%= lower %>[<%= i %>], receiver, ap);
0
+ <% (if (!= type "void") %>return result;<% ) %>
0
+}
0
+<% )) %>
0
+void nu_init_handlers_returning_<%= lower %>() {<% (count times:(do (i) %>
0
+ nu_handlers_returning_<%= lower %>[<%= i %>].handler = (IMP) nu_handler_returning_<%= lower %>_<%= i %>;<% )) %>
0
+}
0
+END)))
0
+
0
+(function generate-handlers (class-name handlers)
0
+ (eval (NuTemplate codeForString:<<-END
0
+#import "handler.h"
0
+
0
+<% (handlers each:(do (group) %>
0
+<%= (generate-handlers-for-type (group 0) (group 2)) %>
0
+<% )) %>
0
+
0
+@interface <%= class-name %> : NSObject { }
0
+@end
0
+@implementation <%= class-name %>
0
++ (void) load {
0
+<% (handlers each:(do (group) %>
0
+ nu_init_handlers_returning_<%= ((group 0) lowercaseString) %> ();
0
+ [NuHandlerWarehouse registerHandlers:nu_handlers_returning_<%= ((group 0) lowercaseString) %> withCount:<%= (group 2) %> forReturnType:@"<%= (group 1) %>"];
0
+<% )) %>
0
+}
0
+@end
0
+END)))
0
+
0
+(set source
0
+ (generate-handlers "NuHandlerWarehouseLoader"
0
+ '(("void" "v" 400)
0
+ ("id" "@" 400)
0
+ ("int" "i" 400)
0
+ ("float" "f" 100)
0
+ ("double" "d" 100)
0
+ ("CGRect" "{_CGRect={_CGPoint=ff}{_CGSize=ff}}" 20)
0
+ ("CGPoint" "{_CGPoint=ff}" 20)
0
+ ("CGSize" "{_CGSize=ff}" 20)
0
+ ("NSRange" "{_NSRange=II}" 20))))
0
+
0
+(source writeToFile:"handlers.m" atomically:NO)
0
+
0
+

Comments

    No one has commented yet.