1 #ifndef WIN32
2 # include <unistd.h>
3 #else
4 # include <io.h>
5 # include <windows.h>
6 #endif
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include "scheme.h"
13 #include "rktio.h"
14
15 #ifdef WIN32
16 # define RACKET_API_EXTERN __declspec(dllexport)
17 #else
18 # define RACKET_API_EXTERN extern
19 #endif
20 #define BOOT_EXTERN RACKET_API_EXTERN
21 #include "boot.h"
22 #include "api.h"
23
24 #define RACKET_AS_BOOT
25
26 #if defined(_MSC_VER) || defined(__MINGW32__)
27 # define BOOT_O_BINARY O_BINARY
28 #endif
29
30 #ifndef BOOT_O_BINARY
31 # define BOOT_O_BINARY 0
32 #endif
33
34 #ifdef WIN32
boot_open(const char * path,int flags)35 int boot_open(const char *path, int flags) {
36 int sz = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
37 wchar_t *w_path = malloc(sz * sizeof(wchar_t));
38
39 MultiByteToWideChar(CP_UTF8, 0, path, -1, w_path, sz);
40
41 {
42 int r = _wopen(w_path, flags);
43
44 free(w_path);
45 return r;
46 }
47 }
48 #else
49 # define boot_open open
50 #endif
51
Sbytevector(char * s)52 static ptr Sbytevector(char *s)
53 {
54 iptr len = strlen(s);
55 ptr bv;
56 bv = Smake_bytevector(len, 0);
57 memcpy(Sbytevector_data(bv), s, len);
58 return bv;
59 }
60
parse_coldirs(char * s)61 static ptr parse_coldirs(char *s)
62 {
63 iptr len = strlen(s);
64
65 if (!len || !s[len+1]) {
66 /* empty string or only one string */
67 return Sbytevector(s);
68 }
69
70 /* multiple collects paths; put into a reversed list */
71 {
72 ptr rev = Snil;
73 iptr delta = 0;
74
75 while (s[delta]) {
76 len = strlen(s + delta);
77 rev = Scons(Sbytevector(s+delta), rev);
78 delta += len + 1;
79 }
80
81 return rev;
82 }
83 }
84
run_cross_server(char ** argv)85 static void run_cross_server(char **argv)
86 {
87 ptr c, a;
88 const char *target_machine = argv[1];
89 const char *cross_server_patch_file = argv[2];
90 const char *cross_server_library_file = argv[3];
91
92 c = Stop_level_value(Sstring_to_symbol("load")); /* original `load` */
93 a = Sstring(cross_server_patch_file);
94 (void)Scall1(c, a);
95
96 c = Stop_level_value(Sstring_to_symbol("load")); /* this is the patched `load` */
97 a = Sstring(cross_server_library_file);
98 (void)Scall1(c, a);
99 c = Stop_level_value(Sstring_to_symbol("serve-cross-compile"));
100
101 a = Sstring(target_machine);
102 (void)Scall1(c, a);
103 }
104
init_foreign()105 static void init_foreign()
106 {
107 # include "rktio.inc"
108 }
109
racket_boot(racket_boot_arguments_t * ba)110 void racket_boot(racket_boot_arguments_t *ba)
111 {
112 int cross_server = 0;
113
114 #ifdef WIN32
115 if (ba->dll_dir)
116 rktio_set_dll_path((wchar_t *)ba->dll_dir);
117 if (ba->dll_open)
118 rktio_set_dll_procs(ba->dll_open, ba->dll_find_object, ba->dll_close);
119 #endif
120
121 Sscheme_register_signal_registerer(rktio_will_modify_os_signal_handler);
122
123 Sscheme_init(NULL);
124
125 if ((ba->argc == 4) && !strcmp(ba->argv[0], "--cross-server"))
126 cross_server = 1;
127
128 /* Open boot files, but reuse file descriptors when possible */
129 {
130 int fd1, fd2, close_fd1 = 0, close_fd2 = 0;
131
132 if ((ba->boot2_offset == 0)
133 || ((ba->boot1_path != ba->boot2_path)
134 && strcmp(ba->boot1_path, ba->boot2_path)))
135 close_fd1 = 1;
136 # ifdef RACKET_AS_BOOT
137 if ((ba->boot3_offset == 0)
138 || ((ba->boot2_path != ba->boot3_path)
139 && strcmp(ba->boot2_path, ba->boot3_path)))
140 close_fd2 = 1;
141 #else
142 close_fd2 = 1;
143 #endif
144
145 fd1 = boot_open(ba->boot1_path, O_RDONLY | BOOT_O_BINARY);
146 Sregister_boot_file_fd_region("petite", fd1, ba->boot1_offset, ba->boot1_len, close_fd1);
147
148 if (!close_fd1)
149 fd2 = fd1;
150 else
151 fd2 = boot_open(ba->boot2_path, O_RDONLY | BOOT_O_BINARY);
152 Sregister_boot_file_fd_region("scheme", fd2, ba->boot2_offset, ba->boot2_len, close_fd2);
153
154 # ifdef RACKET_AS_BOOT
155 if (!cross_server) {
156 int fd3;
157
158 if (!close_fd2)
159 fd3 = fd2;
160 else
161 fd3 = boot_open(ba->boot3_path, O_RDONLY | BOOT_O_BINARY);
162 Sregister_boot_file_fd_region("racket", fd3, ba->boot3_offset, ba->boot3_len, 1);
163 }
164 # endif
165 }
166
167 Sbuild_heap(NULL, init_foreign);
168
169 if (cross_server) {
170 /* Don't run Racket as usual. Instead, load the patch
171 file and run `serve-cross-compile` */
172 run_cross_server(ba->argv);
173 exit(0);
174 }
175
176 {
177 ptr l = Snil;
178 int i;
179 char segment_offset_s[32], wm_is_gracket_s[32];
180
181 if (ba->argv) {
182 for (i = ba->argc; i--; ) {
183 l = Scons(Sbytevector(ba->argv[i]), l);
184 }
185 } else {
186 l = Scons(Sbytevector("-n"), l);
187 }
188 l = Scons(Sbytevector(ba->gracket_guid_or_x11_args ? ba->gracket_guid_or_x11_args : ""), l);
189 sprintf(wm_is_gracket_s, "%d", ba->wm_is_gracket_or_x11_arg_count);
190 l = Scons(Sbytevector(wm_is_gracket_s), l);
191 l = Scons(Sbytevector(ba->is_gui ? "true" : "false"), l);
192 l = Scons(Sbytevector(ba->cs_compiled_subdir ? "true" : "false"), l);
193 sprintf(segment_offset_s, "%ld", ba->segment_offset);
194 l = Scons(Sbytevector(segment_offset_s), l);
195 l = Scons(Sbytevector(ba->k_file ? (char *)ba->k_file : (char *)ba->exec_file), l);
196 l = Scons(Sbytevector(ba->config_dir ? (char *)ba->config_dir : "etc"), l);
197 l = Scons(parse_coldirs(ba->collects_dir ? (char *)ba->collects_dir : ""), l);
198 l = Scons(Sbytevector(ba->run_file ? (char *)ba->run_file : (char *)ba->exec_file), l);
199 l = Scons(Sbytevector((char *)ba->exec_file), l);
200 l = Scons(Sbytevector(ba->exit_after ? "false" : "true"), l);
201
202 #ifdef RACKET_AS_BOOT
203 {
204 ptr c, start, apply;
205 c = Stop_level_value(Sstring_to_symbol("scheme-start"));
206 start = Scall0(c);
207 apply = Stop_level_value(Sstring_to_symbol("apply"));
208 Scall2(apply, start, l);
209 }
210 #else
211 Sset_top_level_value(Sstring_to_symbol("bytes-command-line-arguments"), l);
212 #endif
213 }
214
215 #ifndef RACKET_AS_BOOT
216 {
217 ptr c, p;
218 int f3;
219
220 fd3 = open(ba->boot3_path, O_RDONLY | BOOT_O_BINARY);
221 if (boot3_offset) lseek(fd3, ba->boot3_offset, SEEK_SET);
222 c = Stop_level_value(Sstring_to_symbol("open-fd-input-port"));
223 p = Scall1(c, Sfixnum(fd3));
224 Slock_object(p);
225 c = Stop_level_value(Sstring_to_symbol("port-file-compressed!"));
226 Scall1(c, p);
227 Sunlock_object(p);
228 c = Stop_level_value(Sstring_to_symbol("load-compiled-from-port"));
229 Scall1(c, p);
230 }
231 #endif
232 }
233
234 /* **************************************** */
235
236 enum {
237 EMBEDDED_ENTRY_APPLY,
238 EMBEDDED_ENTRY_PRIMITIVE_LOOKUP,
239 EMBEDDED_ENTRY_EVAL,
240 EMBEDDED_ENTRY_DYNAMIC_REQUIRE,
241 EMBEDDED_ENTRY_NAMESPACE_REQUIRE,
242 EMBEDDED_ENTRY_EMBEDDED_LOAD
243 };
244
get_embedded_entry(int index)245 static ptr get_embedded_entry(int index)
246 {
247 ptr vec;
248
249 vec = Stop_level_value(Sstring_to_symbol("embedded-racket-entry-info"));
250 return Svector_ref(vec, index);
251 }
252
racket_apply(ptr proc,ptr arg_list)253 ptr racket_apply(ptr proc, ptr arg_list)
254 {
255 ptr app = get_embedded_entry(EMBEDDED_ENTRY_APPLY);
256
257 return Scall2(app, proc, arg_list);
258 }
259
racket_primitive(const char * name)260 ptr racket_primitive(const char *name)
261 {
262 ptr prim_lookup = get_embedded_entry(EMBEDDED_ENTRY_PRIMITIVE_LOOKUP);
263
264 return Scall1(prim_lookup, Sstring_to_symbol(name));
265 }
266
racket_eval(ptr s_expr)267 ptr racket_eval(ptr s_expr)
268 {
269 ptr eval = get_embedded_entry(EMBEDDED_ENTRY_EVAL);
270
271 return racket_apply(eval, Scons(s_expr, Snil));
272 }
273
racket_dynamic_require(ptr module_path,ptr sym_or_false)274 ptr racket_dynamic_require(ptr module_path, ptr sym_or_false)
275 {
276 ptr dy_req = get_embedded_entry(EMBEDDED_ENTRY_DYNAMIC_REQUIRE);
277
278 return racket_apply(dy_req, Scons(module_path, Scons(sym_or_false, Snil)));
279 }
280
racket_namespace_require(ptr module_path)281 void racket_namespace_require(ptr module_path)
282 {
283 ptr ns_req = get_embedded_entry(EMBEDDED_ENTRY_NAMESPACE_REQUIRE);
284
285 (void)racket_apply(ns_req, Scons(module_path, Snil));
286 }
287
embedded_load(ptr path,ptr start,ptr end,ptr bstr,int as_predefined)288 static void embedded_load(ptr path, ptr start, ptr end, ptr bstr, int as_predefined)
289 {
290 ptr load = get_embedded_entry(EMBEDDED_ENTRY_EMBEDDED_LOAD);
291 ptr pre = (as_predefined ? Strue : Sfalse);
292
293 (void)racket_apply(load, Scons(path, Scons(start, Scons(end, Scons(bstr, Scons(pre, Snil))))));
294 }
295
racket_embedded_load_bytes(const char * code,uptr len,int as_predefined)296 void racket_embedded_load_bytes(const char *code, uptr len, int as_predefined)
297 {
298 ptr bstr = Smake_bytevector(len, 0);
299 memcpy(Sbytevector_data(bstr), code, len);
300
301 embedded_load(Sfalse, Sfalse, Sfalse, bstr, as_predefined);
302 }
303
racket_embedded_load_file(const char * path,int as_predefined)304 void racket_embedded_load_file(const char *path, int as_predefined)
305 {
306 embedded_load(Sbytevector((char *)path), Sfixnum(0), Sfalse, Sfalse, as_predefined);
307 }
308
racket_embedded_load_file_region(const char * path,uptr start,uptr end,int as_predefined)309 void racket_embedded_load_file_region(const char *path, uptr start, uptr end, int as_predefined)
310 {
311 embedded_load(Sbytevector((char *)path), Sfixnum(start), Sfixnum(end), Sfalse, as_predefined);
312 }
313
racket_cpointer_address(ptr cptr)314 void *racket_cpointer_address(ptr cptr) {
315 void *p;
316 iptr offset;
317 p = racket_cpointer_base_address(cptr);
318 offset = racket_cpointer_offset(cptr);
319 return (char *)p + offset;
320 }
321
racket_cpointer_base_address(ptr cptr)322 void *racket_cpointer_base_address(ptr cptr) {
323 if (Srecordp(cptr)) {
324 cptr = Srecord_uniform_ref(cptr, 0);
325
326 if (Sbytevectorp(cptr))
327 return &Sbytevector_u8_ref(cptr, 0);
328 else if (Svectorp(cptr))
329 return &Svector_ref(cptr, 0);
330 else if (Sfixnump(cptr) || Sbignump(cptr))
331 return TO_VOIDP(Sinteger_value(cptr));
332 }
333
334 return NULL;
335 }
336
racket_cpointer_offset(ptr cptr)337 iptr racket_cpointer_offset(ptr cptr) {
338 if (Srecordp(cptr)) {
339 if (Srecord_type_parent(Srecord_type(cptr)) != Sfalse) {
340 /* assume that it's a cpointer+offset */
341 return Sinteger_value(Srecord_uniform_ref(cptr, 2));
342 }
343 }
344
345 return 0;
346 }
347