1 /*
2 * Copyright (c) 2021 Calvin Rose
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22
23 #ifndef JANET_AMALG
24 #include "features.h"
25 #include <janet.h>
26 #include "util.h"
27 #endif
28
29 #include <setjmp.h>
30
31 /* Conditionally compile this file */
32 #ifdef JANET_ASSEMBLER
33
34 /* Definition for an instruction in the assembler */
35 typedef struct JanetInstructionDef JanetInstructionDef;
36 struct JanetInstructionDef {
37 const char *name;
38 enum JanetOpCode opcode;
39 };
40
41 /* Hold all state needed during assembly */
42 typedef struct JanetAssembler JanetAssembler;
43 struct JanetAssembler {
44 JanetAssembler *parent;
45 JanetFuncDef *def;
46 jmp_buf on_error;
47 const uint8_t *errmessage;
48 int32_t errindex;
49
50 int32_t environments_capacity;
51 int32_t defs_capacity;
52 int32_t bytecode_count; /* Used for calculating labels */
53
54 Janet name;
55 JanetTable labels; /* keyword -> bytecode index */
56 JanetTable slots; /* symbol -> slot index */
57 JanetTable envs; /* symbol -> environment index */
58 JanetTable defs; /* symbol -> funcdefs index */
59 };
60
61 /* Janet opcode descriptions in lexicographic order. This
62 * allows a binary search over the elements to find the
63 * correct opcode given a name. This works in reasonable
64 * time and is easier to setup statically than a hash table or
65 * prefix tree. */
66 static const JanetInstructionDef janet_ops[] = {
67 {"add", JOP_ADD},
68 {"addim", JOP_ADD_IMMEDIATE},
69 {"band", JOP_BAND},
70 {"bnot", JOP_BNOT},
71 {"bor", JOP_BOR},
72 {"bxor", JOP_BXOR},
73 {"call", JOP_CALL},
74 {"clo", JOP_CLOSURE},
75 {"cmp", JOP_COMPARE},
76 {"cncl", JOP_CANCEL},
77 {"div", JOP_DIVIDE},
78 {"divim", JOP_DIVIDE_IMMEDIATE},
79 {"eq", JOP_EQUALS},
80 {"eqim", JOP_EQUALS_IMMEDIATE},
81 {"err", JOP_ERROR},
82 {"get", JOP_GET},
83 {"geti", JOP_GET_INDEX},
84 {"gt", JOP_GREATER_THAN},
85 {"gte", JOP_GREATER_THAN_EQUAL},
86 {"gtim", JOP_GREATER_THAN_IMMEDIATE},
87 {"in", JOP_IN},
88 {"jmp", JOP_JUMP},
89 {"jmpif", JOP_JUMP_IF},
90 {"jmpni", JOP_JUMP_IF_NIL},
91 {"jmpnn", JOP_JUMP_IF_NOT_NIL},
92 {"jmpno", JOP_JUMP_IF_NOT},
93 {"ldc", JOP_LOAD_CONSTANT},
94 {"ldf", JOP_LOAD_FALSE},
95 {"ldi", JOP_LOAD_INTEGER},
96 {"ldn", JOP_LOAD_NIL},
97 {"lds", JOP_LOAD_SELF},
98 {"ldt", JOP_LOAD_TRUE},
99 {"ldu", JOP_LOAD_UPVALUE},
100 {"len", JOP_LENGTH},
101 {"lt", JOP_LESS_THAN},
102 {"lte", JOP_LESS_THAN_EQUAL},
103 {"ltim", JOP_LESS_THAN_IMMEDIATE},
104 {"mkarr", JOP_MAKE_ARRAY},
105 {"mkbtp", JOP_MAKE_BRACKET_TUPLE},
106 {"mkbuf", JOP_MAKE_BUFFER},
107 {"mkstr", JOP_MAKE_STRING},
108 {"mkstu", JOP_MAKE_STRUCT},
109 {"mktab", JOP_MAKE_TABLE},
110 {"mktup", JOP_MAKE_TUPLE},
111 {"mod", JOP_MODULO},
112 {"movf", JOP_MOVE_FAR},
113 {"movn", JOP_MOVE_NEAR},
114 {"mul", JOP_MULTIPLY},
115 {"mulim", JOP_MULTIPLY_IMMEDIATE},
116 {"neq", JOP_NOT_EQUALS},
117 {"neqim", JOP_NOT_EQUALS_IMMEDIATE},
118 {"next", JOP_NEXT},
119 {"noop", JOP_NOOP},
120 {"prop", JOP_PROPAGATE},
121 {"push", JOP_PUSH},
122 {"push2", JOP_PUSH_2},
123 {"push3", JOP_PUSH_3},
124 {"pusha", JOP_PUSH_ARRAY},
125 {"put", JOP_PUT},
126 {"puti", JOP_PUT_INDEX},
127 {"rem", JOP_REMAINDER},
128 {"res", JOP_RESUME},
129 {"ret", JOP_RETURN},
130 {"retn", JOP_RETURN_NIL},
131 {"setu", JOP_SET_UPVALUE},
132 {"sig", JOP_SIGNAL},
133 {"sl", JOP_SHIFT_LEFT},
134 {"slim", JOP_SHIFT_LEFT_IMMEDIATE},
135 {"sr", JOP_SHIFT_RIGHT},
136 {"srim", JOP_SHIFT_RIGHT_IMMEDIATE},
137 {"sru", JOP_SHIFT_RIGHT_UNSIGNED},
138 {"sruim", JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE},
139 {"sub", JOP_SUBTRACT},
140 {"tcall", JOP_TAILCALL},
141 {"tchck", JOP_TYPECHECK}
142 };
143
144 /* Typename aliases for tchck instruction */
145 typedef struct TypeAlias {
146 const char *name;
147 int32_t mask;
148 } TypeAlias;
149
150 static const TypeAlias type_aliases[] = {
151 {"abstract", JANET_TFLAG_ABSTRACT},
152 {"array", JANET_TFLAG_ARRAY},
153 {"boolean", JANET_TFLAG_BOOLEAN},
154 {"buffer", JANET_TFLAG_BUFFER},
155 {"callable", JANET_TFLAG_CALLABLE},
156 {"cfunction", JANET_TFLAG_CFUNCTION},
157 {"dictionary", JANET_TFLAG_DICTIONARY},
158 {"fiber", JANET_TFLAG_FIBER},
159 {"function", JANET_TFLAG_FUNCTION},
160 {"indexed", JANET_TFLAG_INDEXED},
161 {"keyword", JANET_TFLAG_KEYWORD},
162 {"nil", JANET_TFLAG_NIL},
163 {"number", JANET_TFLAG_NUMBER},
164 {"pointer", JANET_TFLAG_POINTER},
165 {"string", JANET_TFLAG_STRING},
166 {"struct", JANET_TFLAG_STRUCT},
167 {"symbol", JANET_TFLAG_SYMBOL},
168 {"table", JANET_TFLAG_TABLE},
169 {"tuple", JANET_TFLAG_TUPLE}
170 };
171
172 /* Deinitialize an Assembler. Does not deinitialize the parents. */
janet_asm_deinit(JanetAssembler * a)173 static void janet_asm_deinit(JanetAssembler *a) {
174 janet_table_deinit(&a->slots);
175 janet_table_deinit(&a->labels);
176 janet_table_deinit(&a->envs);
177 janet_table_deinit(&a->defs);
178 }
179
janet_asm_longjmp(JanetAssembler * a)180 static void janet_asm_longjmp(JanetAssembler *a) {
181 #if defined(JANET_BSD) || defined(JANET_APPLE)
182 _longjmp(a->on_error, 1);
183 #else
184 longjmp(a->on_error, 1);
185 #endif
186 }
187
188 /* Throw some kind of assembly error */
janet_asm_error(JanetAssembler * a,const char * message)189 static void janet_asm_error(JanetAssembler *a, const char *message) {
190 a->errmessage = janet_formatc("%s, instruction %d", message, a->errindex);
191 janet_asm_longjmp(a);
192 }
193 #define janet_asm_assert(a, c, m) do { if (!(c)) janet_asm_error((a), (m)); } while (0)
194
195 /* Throw some kind of assembly error */
janet_asm_errorv(JanetAssembler * a,const uint8_t * m)196 static void janet_asm_errorv(JanetAssembler *a, const uint8_t *m) {
197 a->errmessage = m;
198 janet_asm_longjmp(a);
199 }
200
201 /* Add a closure environment to the assembler. Sub funcdefs may need
202 * to reference outer function environments, and may change the outer environment.
203 * Returns the index of the environment in the assembler's environments, or -1
204 * if not found. */
janet_asm_addenv(JanetAssembler * a,Janet envname)205 static int32_t janet_asm_addenv(JanetAssembler *a, Janet envname) {
206 Janet check;
207 JanetFuncDef *def = a->def;
208 int32_t envindex;
209 int32_t res;
210 if (janet_equals(a->name, envname)) {
211 return -1;
212 }
213 /* Check for memoized value */
214 check = janet_table_get(&a->envs, envname);
215 if (janet_checktype(check, JANET_NUMBER)) {
216 return (int32_t) janet_unwrap_number(check);
217 }
218 if (NULL == a->parent) return -2;
219 res = janet_asm_addenv(a->parent, envname);
220 if (res < -1) {
221 return res;
222 }
223 envindex = def->environments_length;
224 janet_table_put(&a->envs, envname, janet_wrap_number(envindex));
225 if (envindex >= a->environments_capacity) {
226 int32_t newcap = 2 * envindex;
227 def->environments = janet_realloc(def->environments, newcap * sizeof(int32_t));
228 if (NULL == def->environments) {
229 JANET_OUT_OF_MEMORY;
230 }
231 a->environments_capacity = newcap;
232 }
233 def->environments[envindex] = (int32_t) res;
234 def->environments_length = envindex + 1;
235 return envindex;
236 }
237
238 /* Parse an argument to an assembly instruction, and return the result as an
239 * integer. This integer will need to be bounds checked. */
doarg_1(JanetAssembler * a,enum JanetOpArgType argtype,Janet x)240 static int32_t doarg_1(
241 JanetAssembler *a,
242 enum JanetOpArgType argtype,
243 Janet x) {
244 int32_t ret = -1;
245 JanetTable *c;
246 switch (argtype) {
247 default:
248 c = NULL;
249 break;
250 case JANET_OAT_SLOT:
251 c = &a->slots;
252 break;
253 case JANET_OAT_ENVIRONMENT:
254 c = &a->envs;
255 break;
256 case JANET_OAT_LABEL:
257 c = &a->labels;
258 break;
259 case JANET_OAT_FUNCDEF:
260 c = &a->defs;
261 break;
262 }
263 switch (janet_type(x)) {
264 default:
265 goto error;
266 break;
267 case JANET_NUMBER: {
268 double y = janet_unwrap_number(x);
269 if (janet_checkintrange(y)) {
270 ret = (int32_t) y;
271 } else {
272 goto error;
273 }
274 break;
275 }
276 case JANET_TUPLE: {
277 const Janet *t = janet_unwrap_tuple(x);
278 if (argtype == JANET_OAT_TYPE) {
279 int32_t i = 0;
280 ret = 0;
281 for (i = 0; i < janet_tuple_length(t); i++) {
282 ret |= doarg_1(a, JANET_OAT_SIMPLETYPE, t[i]);
283 }
284 } else {
285 goto error;
286 }
287 break;
288 }
289 case JANET_KEYWORD: {
290 if (NULL != c && argtype == JANET_OAT_LABEL) {
291 Janet result = janet_table_get(c, x);
292 if (janet_checktype(result, JANET_NUMBER)) {
293 ret = janet_unwrap_integer(result) - a->bytecode_count;
294 } else {
295 goto error;
296 }
297 } else if (argtype == JANET_OAT_TYPE || argtype == JANET_OAT_SIMPLETYPE) {
298 const TypeAlias *alias = janet_strbinsearch(
299 &type_aliases,
300 sizeof(type_aliases) / sizeof(TypeAlias),
301 sizeof(TypeAlias),
302 janet_unwrap_keyword(x));
303 if (alias) {
304 ret = alias->mask;
305 } else {
306 janet_asm_errorv(a, janet_formatc("unknown type %v", x));
307 }
308 } else {
309 goto error;
310 }
311 break;
312 }
313 case JANET_SYMBOL: {
314 if (NULL != c) {
315 Janet result = janet_table_get(c, x);
316 if (janet_checktype(result, JANET_NUMBER)) {
317 ret = (int32_t) janet_unwrap_number(result);
318 } else {
319 janet_asm_errorv(a, janet_formatc("unknown name %v", x));
320 }
321 } else {
322 goto error;
323 }
324 if (argtype == JANET_OAT_ENVIRONMENT && ret == -1) {
325 /* Add a new env */
326 ret = janet_asm_addenv(a, x);
327 if (ret < -1) {
328 janet_asm_errorv(a, janet_formatc("unknown environment %v", x));
329 }
330 }
331 break;
332 }
333 }
334 if (argtype == JANET_OAT_SLOT && ret >= a->def->slotcount)
335 a->def->slotcount = (int32_t) ret + 1;
336 return ret;
337
338 error:
339 janet_asm_errorv(a, janet_formatc("error parsing instruction argument %v", x));
340 return 0;
341 }
342
343 /* Parse a single argument to an instruction. Trims it as well as
344 * try to convert arguments to bit patterns */
doarg(JanetAssembler * a,enum JanetOpArgType argtype,int nth,int nbytes,int hassign,Janet x)345 static uint32_t doarg(
346 JanetAssembler *a,
347 enum JanetOpArgType argtype,
348 int nth,
349 int nbytes,
350 int hassign,
351 Janet x) {
352 int32_t arg = doarg_1(a, argtype, x);
353 /* Calculate the min and max values that can be stored given
354 * nbytes, and whether or not the storage is signed */
355 int32_t max = (1 << ((nbytes << 3) - hassign)) - 1;
356 int32_t min = hassign ? -max - 1 : 0;
357 if (arg < min)
358 janet_asm_errorv(a, janet_formatc("instruction argument %v is too small, must be %d byte%s",
359 x, nbytes, nbytes > 1 ? "s" : ""));
360 if (arg > max)
361 janet_asm_errorv(a, janet_formatc("instruction argument %v is too large, must be %d byte%s",
362 x, nbytes, nbytes > 1 ? "s" : ""));
363 return ((uint32_t) arg) << (nth << 3);
364 }
365
366 /* Provide parsing methods for the different kinds of arguments */
read_instruction(JanetAssembler * a,const JanetInstructionDef * idef,const Janet * argt)367 static uint32_t read_instruction(
368 JanetAssembler *a,
369 const JanetInstructionDef *idef,
370 const Janet *argt) {
371 uint32_t instr = idef->opcode;
372 enum JanetInstructionType type = janet_instructions[idef->opcode];
373 switch (type) {
374 case JINT_0: {
375 if (janet_tuple_length(argt) != 1)
376 janet_asm_error(a, "expected 0 arguments: (op)");
377 break;
378 }
379 case JINT_S: {
380 if (janet_tuple_length(argt) != 2)
381 janet_asm_error(a, "expected 1 argument: (op, slot)");
382 instr |= doarg(a, JANET_OAT_SLOT, 1, 2, 0, argt[1]);
383 break;
384 }
385 case JINT_L: {
386 if (janet_tuple_length(argt) != 2)
387 janet_asm_error(a, "expected 1 argument: (op, label)");
388 instr |= doarg(a, JANET_OAT_LABEL, 1, 3, 1, argt[1]);
389 break;
390 }
391 case JINT_SS: {
392 if (janet_tuple_length(argt) != 3)
393 janet_asm_error(a, "expected 2 arguments: (op, slot, slot)");
394 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
395 instr |= doarg(a, JANET_OAT_SLOT, 2, 2, 0, argt[2]);
396 break;
397 }
398 case JINT_SL: {
399 if (janet_tuple_length(argt) != 3)
400 janet_asm_error(a, "expected 2 arguments: (op, slot, label)");
401 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
402 instr |= doarg(a, JANET_OAT_LABEL, 2, 2, 1, argt[2]);
403 break;
404 }
405 case JINT_ST: {
406 if (janet_tuple_length(argt) != 3)
407 janet_asm_error(a, "expected 2 arguments: (op, slot, type)");
408 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
409 instr |= doarg(a, JANET_OAT_TYPE, 2, 2, 0, argt[2]);
410 break;
411 }
412 case JINT_SI:
413 case JINT_SU: {
414 if (janet_tuple_length(argt) != 3)
415 janet_asm_error(a, "expected 2 arguments: (op, slot, integer)");
416 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
417 instr |= doarg(a, JANET_OAT_INTEGER, 2, 2, type == JINT_SI, argt[2]);
418 break;
419 }
420 case JINT_SD: {
421 if (janet_tuple_length(argt) != 3)
422 janet_asm_error(a, "expected 2 arguments: (op, slot, funcdef)");
423 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
424 instr |= doarg(a, JANET_OAT_FUNCDEF, 2, 2, 0, argt[2]);
425 break;
426 }
427 case JINT_SSS: {
428 if (janet_tuple_length(argt) != 4)
429 janet_asm_error(a, "expected 3 arguments: (op, slot, slot, slot)");
430 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
431 instr |= doarg(a, JANET_OAT_SLOT, 2, 1, 0, argt[2]);
432 instr |= doarg(a, JANET_OAT_SLOT, 3, 1, 0, argt[3]);
433 break;
434 }
435 case JINT_SSI:
436 case JINT_SSU: {
437 if (janet_tuple_length(argt) != 4)
438 janet_asm_error(a, "expected 3 arguments: (op, slot, slot, integer)");
439 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
440 instr |= doarg(a, JANET_OAT_SLOT, 2, 1, 0, argt[2]);
441 instr |= doarg(a, JANET_OAT_INTEGER, 3, 1, type == JINT_SSI, argt[3]);
442 break;
443 }
444 case JINT_SES: {
445 JanetAssembler *b = a;
446 uint32_t env;
447 if (janet_tuple_length(argt) != 4)
448 janet_asm_error(a, "expected 3 arguments: (op, slot, environment, envslot)");
449 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
450 env = doarg(a, JANET_OAT_ENVIRONMENT, 0, 1, 0, argt[2]);
451 instr |= env << 16;
452 for (env += 1; env > 0; env--) {
453 b = b->parent;
454 if (NULL == b)
455 janet_asm_error(a, "invalid environment index");
456 }
457 instr |= doarg(b, JANET_OAT_SLOT, 3, 1, 0, argt[3]);
458 break;
459 }
460 case JINT_SC: {
461 if (janet_tuple_length(argt) != 3)
462 janet_asm_error(a, "expected 2 arguments: (op, slot, constant)");
463 instr |= doarg(a, JANET_OAT_SLOT, 1, 1, 0, argt[1]);
464 instr |= doarg(a, JANET_OAT_CONSTANT, 2, 2, 0, argt[2]);
465 break;
466 }
467 }
468 return instr;
469 }
470
471 /* Helper to get from a structure */
janet_get1(Janet ds,Janet key)472 static Janet janet_get1(Janet ds, Janet key) {
473 switch (janet_type(ds)) {
474 default:
475 return janet_wrap_nil();
476 case JANET_TABLE:
477 return janet_table_get(janet_unwrap_table(ds), key);
478 case JANET_STRUCT:
479 return janet_struct_get(janet_unwrap_struct(ds), key);
480 }
481 }
482
483 /* Helper to assembly. Return the assembly result */
janet_asm1(JanetAssembler * parent,Janet source,int flags)484 static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int flags) {
485 JanetAssembleResult result;
486 JanetAssembler a;
487 Janet s = source;
488 JanetFuncDef *def;
489 int32_t count, i;
490 const Janet *arr;
491 Janet x;
492 (void) flags;
493
494 /* Initialize funcdef */
495 def = janet_funcdef_alloc();
496
497 /* Initialize Assembler */
498 a.def = def;
499 a.parent = parent;
500 a.errmessage = NULL;
501 a.errindex = 0;
502 a.environments_capacity = 0;
503 a.bytecode_count = 0;
504 a.defs_capacity = 0;
505 a.name = janet_wrap_nil();
506 janet_table_init(&a.labels, 0);
507 janet_table_init(&a.slots, 0);
508 janet_table_init(&a.envs, 0);
509 janet_table_init(&a.defs, 0);
510
511 /* Set error jump */
512 #if defined(JANET_BSD) || defined(JANET_APPLE)
513 if (_setjmp(a.on_error)) {
514 #else
515 if (setjmp(a.on_error)) {
516 #endif
517 if (NULL != a.parent) {
518 janet_asm_deinit(&a);
519 janet_asm_longjmp(a.parent);
520 }
521 result.funcdef = NULL;
522 result.error = a.errmessage;
523 result.status = JANET_ASSEMBLE_ERROR;
524 janet_asm_deinit(&a);
525 return result;
526 }
527
528 janet_asm_assert(&a,
529 janet_checktype(s, JANET_STRUCT) ||
530 janet_checktype(s, JANET_TABLE),
531 "expected struct or table for assembly source");
532
533 /* Check for function name */
534 a.name = janet_get1(s, janet_ckeywordv("name"));
535 if (!janet_checktype(a.name, JANET_NIL)) {
536 def->name = janet_to_string(a.name);
537 }
538
539 /* Set function arity */
540 x = janet_get1(s, janet_ckeywordv("arity"));
541 def->arity = janet_checkint(x) ? janet_unwrap_integer(x) : 0;
542 janet_asm_assert(&a, def->arity >= 0, "arity must be non-negative");
543
544 x = janet_get1(s, janet_ckeywordv("max-arity"));
545 def->max_arity = janet_checkint(x) ? janet_unwrap_integer(x) : def->arity;
546 janet_asm_assert(&a, def->max_arity >= def->arity, "max-arity must be greater than or equal to arity");
547
548 x = janet_get1(s, janet_ckeywordv("min-arity"));
549 def->min_arity = janet_checkint(x) ? janet_unwrap_integer(x) : def->arity;
550 janet_asm_assert(&a, def->min_arity <= def->arity, "min-arity must be less than or equal to arity");
551
552 /* Check vararg */
553 x = janet_get1(s, janet_ckeywordv("vararg"));
554 if (janet_truthy(x)) def->flags |= JANET_FUNCDEF_FLAG_VARARG;
555
556 /* Check source */
557 x = janet_get1(s, janet_ckeywordv("source"));
558 if (janet_checktype(x, JANET_STRING)) def->source = janet_unwrap_string(x);
559
560 /* Create slot aliases */
561 x = janet_get1(s, janet_ckeywordv("slots"));
562 if (janet_indexed_view(x, &arr, &count)) {
563 for (i = 0; i < count; i++) {
564 Janet v = arr[i];
565 if (janet_checktype(v, JANET_TUPLE)) {
566 const Janet *t = janet_unwrap_tuple(v);
567 int32_t j;
568 for (j = 0; j < janet_tuple_length(t); j++) {
569 if (!janet_checktype(t[j], JANET_SYMBOL))
570 janet_asm_error(&a, "slot names must be symbols");
571 janet_table_put(&a.slots, t[j], janet_wrap_integer(i));
572 }
573 } else if (janet_checktype(v, JANET_SYMBOL)) {
574 janet_table_put(&a.slots, v, janet_wrap_integer(i));
575 } else {
576 janet_asm_error(&a, "slot names must be symbols or tuple of symbols");
577 }
578 }
579 }
580
581 /* Parse constants */
582 x = janet_get1(s, janet_ckeywordv("constants"));
583 if (janet_indexed_view(x, &arr, &count)) {
584 def->constants_length = count;
585 def->constants = janet_malloc(sizeof(Janet) * (size_t) count);
586 if (NULL == def->constants) {
587 JANET_OUT_OF_MEMORY;
588 }
589 for (i = 0; i < count; i++) {
590 Janet ct = arr[i];
591 def->constants[i] = ct;
592 }
593 } else {
594 def->constants = NULL;
595 def->constants_length = 0;
596 }
597
598 /* Parse sub funcdefs */
599 x = janet_get1(s, janet_ckeywordv("closures"));
600 if (janet_indexed_view(x, &arr, &count)) {
601 int32_t i;
602 for (i = 0; i < count; i++) {
603 JanetAssembleResult subres;
604 Janet subname;
605 int32_t newlen;
606 subres = janet_asm1(&a, arr[i], flags);
607 if (subres.status != JANET_ASSEMBLE_OK) {
608 janet_asm_errorv(&a, subres.error);
609 }
610 subname = janet_get1(arr[i], janet_ckeywordv("name"));
611 if (!janet_checktype(subname, JANET_NIL)) {
612 janet_table_put(&a.defs, subname, janet_wrap_integer(def->defs_length));
613 }
614 newlen = def->defs_length + 1;
615 if (a.defs_capacity < newlen) {
616 int32_t newcap = newlen;
617 def->defs = janet_realloc(def->defs, newcap * sizeof(JanetFuncDef *));
618 if (NULL == def->defs) {
619 JANET_OUT_OF_MEMORY;
620 }
621 a.defs_capacity = newcap;
622 }
623 def->defs[def->defs_length] = subres.funcdef;
624 def->defs_length = newlen;
625 }
626 }
627
628 /* Parse bytecode and labels */
629 x = janet_get1(s, janet_ckeywordv("bytecode"));
630 if (janet_indexed_view(x, &arr, &count)) {
631 /* Do labels and find length */
632 int32_t blength = 0;
633 for (i = 0; i < count; ++i) {
634 Janet instr = arr[i];
635 if (janet_checktype(instr, JANET_KEYWORD)) {
636 janet_table_put(&a.labels, instr, janet_wrap_integer(blength));
637 } else if (janet_checktype(instr, JANET_TUPLE)) {
638 blength++;
639 } else {
640 a.errindex = i;
641 janet_asm_error(&a, "expected assembly instruction");
642 }
643 }
644 /* Allocate bytecode array */
645 def->bytecode_length = blength;
646 def->bytecode = janet_malloc(sizeof(uint32_t) * (size_t) blength);
647 if (NULL == def->bytecode) {
648 JANET_OUT_OF_MEMORY;
649 }
650 /* Do bytecode */
651 for (i = 0; i < count; ++i) {
652 Janet instr = arr[i];
653 if (janet_checktype(instr, JANET_KEYWORD)) {
654 continue;
655 } else {
656 uint32_t op;
657 const JanetInstructionDef *idef;
658 const Janet *t;
659 a.errindex = i;
660 janet_asm_assert(&a, janet_checktype(instr, JANET_TUPLE), "expected tuple");
661 t = janet_unwrap_tuple(instr);
662 if (janet_tuple_length(t) == 0) {
663 op = 0;
664 } else {
665 janet_asm_assert(&a, janet_checktype(t[0], JANET_SYMBOL),
666 "expected symbol in assembly instruction");
667 idef = janet_strbinsearch(
668 &janet_ops,
669 sizeof(janet_ops) / sizeof(JanetInstructionDef),
670 sizeof(JanetInstructionDef),
671 janet_unwrap_symbol(t[0]));
672 if (NULL == idef)
673 janet_asm_errorv(&a, janet_formatc("unknown instruction %v", t[0]));
674 op = read_instruction(&a, idef, t);
675 }
676 def->bytecode[a.bytecode_count++] = op;
677 }
678 }
679 } else {
680 janet_asm_error(&a, "bytecode expected");
681 }
682 a.errindex = -1;
683
684 /* Check for source mapping */
685 x = janet_get1(s, janet_ckeywordv("sourcemap"));
686 if (janet_indexed_view(x, &arr, &count)) {
687 janet_asm_assert(&a, count == def->bytecode_length, "sourcemap must have the same length as the bytecode");
688 def->sourcemap = janet_malloc(sizeof(JanetSourceMapping) * (size_t) count);
689 if (NULL == def->sourcemap) {
690 JANET_OUT_OF_MEMORY;
691 }
692 for (i = 0; i < count; i++) {
693 const Janet *tup;
694 Janet entry = arr[i];
695 JanetSourceMapping mapping;
696 if (!janet_checktype(entry, JANET_TUPLE)) {
697 janet_asm_error(&a, "expected tuple");
698 }
699 tup = janet_unwrap_tuple(entry);
700 if (!janet_checkint(tup[0])) {
701 janet_asm_error(&a, "expected integer");
702 }
703 if (!janet_checkint(tup[1])) {
704 janet_asm_error(&a, "expected integer");
705 }
706 mapping.line = janet_unwrap_integer(tup[0]);
707 mapping.column = janet_unwrap_integer(tup[1]);
708 def->sourcemap[i] = mapping;
709 }
710 }
711
712 /* Set environments */
713 def->environments =
714 janet_realloc(def->environments, def->environments_length * sizeof(int32_t));
715 if (NULL == def->environments) {
716 JANET_OUT_OF_MEMORY;
717 }
718
719 /* Verify the func def */
720 if (janet_verify(def)) {
721 janet_asm_error(&a, "invalid assembly");
722 }
723
724 /* Add final flags */
725 janet_def_addflags(def);
726
727 /* Finish everything and return funcdef */
728 janet_asm_deinit(&a);
729 result.error = NULL;
730 result.funcdef = def;
731 result.status = JANET_ASSEMBLE_OK;
732 return result;
733 }
734
735 /* Assemble a function */
736 JanetAssembleResult janet_asm(Janet source, int flags) {
737 return janet_asm1(NULL, source, flags);
738 }
739
740 /* Disassembly */
741
742 /* Find the definition of an instruction given the instruction word. Return
743 * NULL if not found. */
744 static const JanetInstructionDef *janet_asm_reverse_lookup(uint32_t instr) {
745 size_t i;
746 uint32_t opcode = instr & 0x7F;
747 for (i = 0; i < sizeof(janet_ops) / sizeof(JanetInstructionDef); i++) {
748 const JanetInstructionDef *def = janet_ops + i;
749 if (def->opcode == opcode)
750 return def;
751 }
752 return NULL;
753 }
754
755 /* Create some constant sized tuples */
756 static const Janet *tup1(Janet x) {
757 Janet *tup = janet_tuple_begin(1);
758 tup[0] = x;
759 return janet_tuple_end(tup);
760 }
761 static const Janet *tup2(Janet x, Janet y) {
762 Janet *tup = janet_tuple_begin(2);
763 tup[0] = x;
764 tup[1] = y;
765 return janet_tuple_end(tup);
766 }
767 static const Janet *tup3(Janet x, Janet y, Janet z) {
768 Janet *tup = janet_tuple_begin(3);
769 tup[0] = x;
770 tup[1] = y;
771 tup[2] = z;
772 return janet_tuple_end(tup);
773 }
774 static const Janet *tup4(Janet w, Janet x, Janet y, Janet z) {
775 Janet *tup = janet_tuple_begin(4);
776 tup[0] = w;
777 tup[1] = x;
778 tup[2] = y;
779 tup[3] = z;
780 return janet_tuple_end(tup);
781 }
782
783 /* Given an argument, convert it to the appropriate integer or symbol */
784 Janet janet_asm_decode_instruction(uint32_t instr) {
785 const JanetInstructionDef *def = janet_asm_reverse_lookup(instr);
786 Janet name;
787 if (NULL == def) {
788 return janet_wrap_integer((int32_t)instr);
789 }
790 name = janet_csymbolv(def->name);
791 const Janet *ret = NULL;
792 #define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask))
793 switch (janet_instructions[def->opcode]) {
794 case JINT_0:
795 ret = tup1(name);
796 break;
797 case JINT_S:
798 ret = tup2(name, janet_wrap_integer(oparg(1, 0xFFFFFF)));
799 break;
800 case JINT_L:
801 ret = tup2(name, janet_wrap_integer((int32_t)instr >> 8));
802 break;
803 case JINT_SS:
804 case JINT_ST:
805 case JINT_SC:
806 case JINT_SU:
807 case JINT_SD:
808 ret = tup3(name,
809 janet_wrap_integer(oparg(1, 0xFF)),
810 janet_wrap_integer(oparg(2, 0xFFFF)));
811 break;
812 case JINT_SI:
813 case JINT_SL:
814 ret = tup3(name,
815 janet_wrap_integer(oparg(1, 0xFF)),
816 janet_wrap_integer((int32_t)instr >> 16));
817 break;
818 case JINT_SSS:
819 case JINT_SES:
820 case JINT_SSU:
821 ret = tup4(name,
822 janet_wrap_integer(oparg(1, 0xFF)),
823 janet_wrap_integer(oparg(2, 0xFF)),
824 janet_wrap_integer(oparg(3, 0xFF)));
825 break;
826 case JINT_SSI:
827 ret = tup4(name,
828 janet_wrap_integer(oparg(1, 0xFF)),
829 janet_wrap_integer(oparg(2, 0xFF)),
830 janet_wrap_integer((int32_t)instr >> 24));
831 break;
832 }
833 #undef oparg
834 if (ret) {
835 /* Check if break point set */
836 if (instr & 0x80) {
837 janet_tuple_flag(ret) |= JANET_TUPLE_FLAG_BRACKETCTOR;
838 }
839 return janet_wrap_tuple(ret);
840 }
841 return janet_wrap_nil();
842 }
843
844 /*
845 * Disasm sections
846 */
847
848 static Janet janet_disasm_arity(JanetFuncDef *def) {
849 return janet_wrap_integer(def->arity);
850 }
851
852 static Janet janet_disasm_min_arity(JanetFuncDef *def) {
853 return janet_wrap_integer(def->min_arity);
854 }
855
856 static Janet janet_disasm_max_arity(JanetFuncDef *def) {
857 return janet_wrap_integer(def->max_arity);
858 }
859
860 static Janet janet_disasm_slotcount(JanetFuncDef *def) {
861 return janet_wrap_integer(def->slotcount);
862 }
863
864 static Janet janet_disasm_bytecode(JanetFuncDef *def) {
865 JanetArray *bcode = janet_array(def->bytecode_length);
866 for (int32_t i = 0; i < def->bytecode_length; i++) {
867 bcode->data[i] = janet_asm_decode_instruction(def->bytecode[i]);
868 }
869 bcode->count = def->bytecode_length;
870 return janet_wrap_array(bcode);
871 }
872
873 static Janet janet_disasm_source(JanetFuncDef *def) {
874 if (def->source != NULL) return janet_wrap_string(def->source);
875 return janet_wrap_nil();
876 }
877
878 static Janet janet_disasm_name(JanetFuncDef *def) {
879 if (def->name != NULL) return janet_wrap_string(def->name);
880 return janet_wrap_nil();
881 }
882
883 static Janet janet_disasm_vararg(JanetFuncDef *def) {
884 return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_VARARG);
885 }
886
887 static Janet janet_disasm_constants(JanetFuncDef *def) {
888 JanetArray *constants = janet_array(def->constants_length);
889 for (int32_t i = 0; i < def->constants_length; i++) {
890 constants->data[i] = def->constants[i];
891 }
892 constants->count = def->constants_length;
893 return janet_wrap_array(constants);
894 }
895
896 static Janet janet_disasm_sourcemap(JanetFuncDef *def) {
897 if (NULL == def->sourcemap) return janet_wrap_nil();
898 JanetArray *sourcemap = janet_array(def->bytecode_length);
899 for (int32_t i = 0; i < def->bytecode_length; i++) {
900 Janet *t = janet_tuple_begin(2);
901 JanetSourceMapping mapping = def->sourcemap[i];
902 t[0] = janet_wrap_integer(mapping.line);
903 t[1] = janet_wrap_integer(mapping.column);
904 sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t));
905 }
906 sourcemap->count = def->bytecode_length;
907 return janet_wrap_array(sourcemap);
908 }
909
910 static Janet janet_disasm_environments(JanetFuncDef *def) {
911 JanetArray *envs = janet_array(def->environments_length);
912 for (int32_t i = 0; i < def->environments_length; i++) {
913 envs->data[i] = janet_wrap_integer(def->environments[i]);
914 }
915 envs->count = def->environments_length;
916 return janet_wrap_array(envs);
917 }
918
919 static Janet janet_disasm_defs(JanetFuncDef *def) {
920 JanetArray *defs = janet_array(def->defs_length);
921 for (int32_t i = 0; i < def->defs_length; i++) {
922 defs->data[i] = janet_disasm(def->defs[i]);
923 }
924 defs->count = def->defs_length;
925 return janet_wrap_array(defs);
926 }
927
928 Janet janet_disasm(JanetFuncDef *def) {
929 JanetTable *ret = janet_table(10);
930 janet_table_put(ret, janet_ckeywordv("arity"), janet_disasm_arity(def));
931 janet_table_put(ret, janet_ckeywordv("min-arity"), janet_disasm_min_arity(def));
932 janet_table_put(ret, janet_ckeywordv("max-arity"), janet_disasm_max_arity(def));
933 janet_table_put(ret, janet_ckeywordv("bytecode"), janet_disasm_bytecode(def));
934 janet_table_put(ret, janet_ckeywordv("source"), janet_disasm_source(def));
935 janet_table_put(ret, janet_ckeywordv("vararg"), janet_disasm_vararg(def));
936 janet_table_put(ret, janet_ckeywordv("name"), janet_disasm_name(def));
937 janet_table_put(ret, janet_ckeywordv("slotcount"), janet_disasm_slotcount(def));
938 janet_table_put(ret, janet_ckeywordv("constants"), janet_disasm_constants(def));
939 janet_table_put(ret, janet_ckeywordv("sourcemap"), janet_disasm_sourcemap(def));
940 janet_table_put(ret, janet_ckeywordv("environments"), janet_disasm_environments(def));
941 janet_table_put(ret, janet_ckeywordv("defs"), janet_disasm_defs(def));
942 return janet_wrap_struct(janet_table_to_struct(ret));
943 }
944
945 JANET_CORE_FN(cfun_asm,
946 "(asm assembly)",
947 "Returns a new function that is the compiled result of the assembly.\n"
948 "The syntax for the assembly can be found on the Janet website, and should correspond\n"
949 "to the return value of disasm. Will throw an\n"
950 "error on invalid assembly.") {
951 janet_fixarity(argc, 1);
952 JanetAssembleResult res;
953 res = janet_asm(argv[0], 0);
954 if (res.status != JANET_ASSEMBLE_OK) {
955 janet_panics(res.error);
956 }
957 return janet_wrap_function(janet_thunk(res.funcdef));
958 }
959
960 JANET_CORE_FN(cfun_disasm,
961 "(disasm func &opt field)",
962 "Returns assembly that could be used to compile the given function. "
963 "func must be a function, not a c function. Will throw on error on a badly "
964 "typed argument. If given a field name, will only return that part of the function assembly. "
965 "Possible fields are:\n\n"
966 "* :arity - number of required and optional arguments.\n"
967 "* :min-arity - minimum number of arguments function can be called with.\n"
968 "* :max-arity - maximum number of arguments function can be called with.\n"
969 "* :vararg - true if function can take a variable number of arguments.\n"
970 "* :bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n"
971 "* :source - name of source file that this function was compiled from.\n"
972 "* :name - name of function.\n"
973 "* :slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n"
974 "* :constants - an array of constants referenced by this function.\n"
975 "* :sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n"
976 "* :environments - an internal mapping of which enclosing functions are referenced for bindings.\n"
977 "* :defs - other function definitions that this function may instantiate.\n") {
978 janet_arity(argc, 1, 2);
979 JanetFunction *f = janet_getfunction(argv, 0);
980 if (argc == 2) {
981 JanetKeyword kw = janet_getkeyword(argv, 1);
982 if (!janet_cstrcmp(kw, "arity")) return janet_disasm_arity(f->def);
983 if (!janet_cstrcmp(kw, "min-arity")) return janet_disasm_min_arity(f->def);
984 if (!janet_cstrcmp(kw, "max-arity")) return janet_disasm_max_arity(f->def);
985 if (!janet_cstrcmp(kw, "bytecode")) return janet_disasm_bytecode(f->def);
986 if (!janet_cstrcmp(kw, "source")) return janet_disasm_source(f->def);
987 if (!janet_cstrcmp(kw, "name")) return janet_disasm_name(f->def);
988 if (!janet_cstrcmp(kw, "vararg")) return janet_disasm_vararg(f->def);
989 if (!janet_cstrcmp(kw, "slotcount")) return janet_disasm_slotcount(f->def);
990 if (!janet_cstrcmp(kw, "constants")) return janet_disasm_constants(f->def);
991 if (!janet_cstrcmp(kw, "sourcemap")) return janet_disasm_sourcemap(f->def);
992 if (!janet_cstrcmp(kw, "environments")) return janet_disasm_environments(f->def);
993 if (!janet_cstrcmp(kw, "defs")) return janet_disasm_defs(f->def);
994 janet_panicf("unknown disasm key %v", argv[1]);
995 } else {
996 return janet_disasm(f->def);
997 }
998 }
999
1000 /* Load the library */
1001 void janet_lib_asm(JanetTable *env) {
1002 JanetRegExt asm_cfuns[] = {
1003 JANET_CORE_REG("asm", cfun_asm),
1004 JANET_CORE_REG("disasm", cfun_disasm),
1005 JANET_REG_END
1006 };
1007 janet_core_cfuns_ext(env, NULL, asm_cfuns);
1008 }
1009
1010 #endif
1011