History

Add new Exec module - similar to Command module but no UI context Update all current limbo modules to implement Exec instead of Command module Add new type signature building API to asm library Include the official RFC1321 (MD5) reference implementation only for use in type signature generation - NOTE: The MD5 implementation in the asm library should NOT be used for any other purpose

arr committed 10 years ago

Commit 77ee7d81 parent 8549d3410 files · +923 −28Browse files

Unified · Split

10 files
  1. limbo/Command.m +1 −1
  2. limbo/Exec.m +8 −0
  3. limbo/basic_limbo_tests.b +3 −4
  4. src/asm/asm.gyp +3 −1
  5. src/asm/rfc1321/global.h +46 −0
  6. src/asm/rfc1321/md5.h +49 −0
  7. src/asm/rfc1321/md5c.c +334 −0
  8. src/asm/type_signature.cpp +203 −0
  9. src/exec/main.cpp +20 −22
  10. src/include/vm_asm.h +256 −0
limbo/Command.m+1−1
@@ -1,5 +1,5 @@
11 #
2−# Command module definition for disvm-exec program
2+# Command module definition for the Dis VM shell
33 #
44
55 # Sys and Draw modules must be included before this file in modules.
limbo/Exec.m+8−0
@@ -0,0 +1,8 @@
1+#
2+# Exec module definition for disvm-exec program
3+#
4+
5+Exec: module
6+{
7+ init: fn(args: list of string);
8+};
limbo/basic_limbo_tests.b+3−4
@@ -1,13 +1,12 @@
1−implement Command;
1+implement Exec;
22
33 include "sys.m";
4−include "draw.m";
5−include "Command.m";
4+include "Exec.m";
65 include "external_module.m";
76
87 sys : Sys;
98
10−init(cxt: ref Draw->Context, args: list of string)
9+init(args: list of string)
1110 {
1211 a := "foobar!";
1312 sys = load Sys Sys->PATH;
src/asm/asm.gyp+3−1
@@ -5,7 +5,9 @@ · 4 unmodified lines
55 'type': 'static_library',
66 'sources': [
77 'opcode_tokens.cpp',
8− 'print_to_stream.cpp'
8+ 'print_to_stream.cpp',
9+ 'type_signature.cpp',
10+ 'rfc1321/md5c.c'
911 ],
1012 'include_dirs': [
1113 '../include'
src/asm/rfc1321/global.h+46−0
@@ -0,0 +1,46 @@
1+/* GLOBAL.H - RSAREF types and constants
2+
3+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
4+ Inc., created 1991. All rights reserved.
5+ */
6+
7+#ifndef _GLOBAL_H_
8+#define _GLOBAL_H_ 1
9+
10+/* PROTOTYPES should be set to one if and only if the compiler supports
11+ function argument prototyping.
12+ The following makes PROTOTYPES default to 1 if it has not already been
13+ defined as 0 with C compiler flags.
14+ */
15+#ifndef PROTOTYPES
16+#define PROTOTYPES 1
17+#endif
18+
19+/* POINTER defines a generic pointer type */
20+typedef unsigned char *POINTER;
21+
22+/* UINT2 defines a two byte word */
23+typedef unsigned short int UINT2;
24+
25+/* UINT4 defines a four byte word */
26+typedef unsigned long int UINT4;
27+
28+#ifndef NULL_PTR
29+#define NULL_PTR ((POINTER)0)
30+#endif
31+
32+#ifndef UNUSED_ARG
33+#define UNUSED_ARG(x) x = *(&x);
34+#endif
35+
36+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
37+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
38+ returns an empty list.
39+ */
40+#if PROTOTYPES
41+#define PROTO_LIST(list) list
42+#else
43+#define PROTO_LIST(list) ()
44+#endif
45+
46+#endif /* end _GLOBAL_H_ */
src/asm/rfc1321/md5.h+49−0
@@ -0,0 +1,49 @@
1+/* MD5.H - header file for MD5C.C
2+ */
3+
4+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
5+ rights reserved.
6+
7+ License to copy and use this software is granted provided that it
8+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
9+ Algorithm" in all material mentioning or referencing this software
10+ or this function.
11+
12+ License is also granted to make and use derivative works provided
13+ that such works are identified as "derived from the RSA Data
14+ Security, Inc. MD5 Message-Digest Algorithm" in all material
15+ mentioning or referencing the derived work.
16+
17+ RSA Data Security, Inc. makes no representations concerning either
18+ the merchantability of this software or the suitability of this
19+ software for any particular purpose. It is provided "as is"
20+ without express or implied warranty of any kind.
21+
22+ These notices must be retained in any copies of any part of this
23+ documentation and/or software.
24+ */
25+
26+#ifndef _MD5_H_
27+#define _MD5_H_ 1
28+
29+#ifdef __cplusplus
30+extern "C" {
31+#endif
32+
33+/* MD5 context. */
34+typedef struct {
35+ UINT4 state[4]; /* state (ABCD) */
36+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
37+ unsigned char buffer[64]; /* input buffer */
38+} MD5_CTX;
39+
40+void MD5Init PROTO_LIST ((MD5_CTX *));
41+void MD5Update PROTO_LIST
42+ ((MD5_CTX *, unsigned char *, unsigned int));
43+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
44+
45+#ifdef __cplusplus
46+}
47+#endif
48+
49+#endif
src/asm/rfc1321/md5c.c+334−0
@@ -0,0 +1,334 @@
1+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
2+ */
3+
4+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
5+ rights reserved.
6+
7+ License to copy and use this software is granted provided that it
8+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
9+ Algorithm" in all material mentioning or referencing this software
10+ or this function.
11+
12+ License is also granted to make and use derivative works provided
13+ that such works are identified as "derived from the RSA Data
14+ Security, Inc. MD5 Message-Digest Algorithm" in all material
15+ mentioning or referencing the derived work.
16+
17+ RSA Data Security, Inc. makes no representations concerning either
18+ the merchantability of this software or the suitability of this
19+ software for any particular purpose. It is provided "as is"
20+ without express or implied warranty of any kind.
21+
22+ These notices must be retained in any copies of any part of this
23+ documentation and/or software.
24+ */
25+
26+#include "global.h"
27+#include "md5.h"
28+
29+/* Constants for MD5Transform routine.
30+ */
31+#define S11 7
32+#define S12 12
33+#define S13 17
34+#define S14 22
35+#define S21 5
36+#define S22 9
37+#define S23 14
38+#define S24 20
39+#define S31 4
40+#define S32 11
41+#define S33 16
42+#define S34 23
43+#define S41 6
44+#define S42 10
45+#define S43 15
46+#define S44 21
47+
48+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
49+static void Encode PROTO_LIST
50+ ((unsigned char *, UINT4 *, unsigned int));
51+static void Decode PROTO_LIST
52+ ((UINT4 *, unsigned char *, unsigned int));
53+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
54+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
55+
56+static unsigned char PADDING[64] = {
57+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
60+};
61+
62+/* F, G, H and I are basic MD5 functions.
63+ */
64+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
65+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
66+#define H(x, y, z) ((x) ^ (y) ^ (z))
67+#define I(x, y, z) ((y) ^ ((x) | (~z)))
68+
69+/* ROTATE_LEFT rotates x left n bits.
70+ */
71+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
72+
73+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
74+ Rotation is separate from addition to prevent recomputation.
75+ */
76+#define FF(a, b, c, d, x, s, ac) { \
77+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
78+ (a) = ROTATE_LEFT ((a), (s)); \
79+ (a) += (b); \
80+ }
81+#define GG(a, b, c, d, x, s, ac) { \
82+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
83+ (a) = ROTATE_LEFT ((a), (s)); \
84+ (a) += (b); \
85+ }
86+#define HH(a, b, c, d, x, s, ac) { \
87+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
88+ (a) = ROTATE_LEFT ((a), (s)); \
89+ (a) += (b); \
90+ }
91+#define II(a, b, c, d, x, s, ac) { \
92+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
93+ (a) = ROTATE_LEFT ((a), (s)); \
94+ (a) += (b); \
95+ }
96+
97+/* MD5 initialization. Begins an MD5 operation, writing a new context.
98+ */
99+void MD5Init (context)
100+MD5_CTX *context; /* context */
101+{
102+ context->count[0] = context->count[1] = 0;
103+
104+ /* Load magic initialization constants.
105+ */
106+ context->state[0] = 0x67452301;
107+ context->state[1] = 0xefcdab89;
108+ context->state[2] = 0x98badcfe;
109+ context->state[3] = 0x10325476;
110+}
111+
112+/* MD5 block update operation. Continues an MD5 message-digest
113+ operation, processing another message block, and updating the
114+ context.
115+ */
116+void MD5Update (context, input, inputLen)
117+MD5_CTX *context; /* context */
118+unsigned char *input; /* input block */
119+unsigned int inputLen; /* length of input block */
120+{
121+ unsigned int i, index, partLen;
122+
123+ /* Compute number of bytes mod 64 */
124+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
125+
126+ /* Update number of bits */
127+ if ((context->count[0] += ((UINT4)inputLen << 3))
128+ < ((UINT4)inputLen << 3))
129+ context->count[1]++;
130+ context->count[1] += ((UINT4)inputLen >> 29);
131+
132+ partLen = 64 - index;
133+
134+ /* Transform as many times as possible.
135+ */
136+ if (inputLen >= partLen) {
137+ MD5_memcpy
138+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
139+ MD5Transform (context->state, context->buffer);
140+
141+ for (i = partLen; i + 63 < inputLen; i += 64)
142+ MD5Transform (context->state, &input[i]);
143+
144+ index = 0;
145+ }
146+ else
147+ i = 0;
148+
149+ /* Buffer remaining input */
150+ MD5_memcpy
151+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
152+ inputLen-i);
153+}
154+
155+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
156+ the message digest and zeroizing the context.
157+ */
158+void MD5Final (digest, context)
159+unsigned char digest[16]; /* message digest */
160+MD5_CTX *context; /* context */
161+{
162+ unsigned char bits[8];
163+ unsigned int index, padLen;
164+
165+ /* Save number of bits */
166+ Encode (bits, context->count, 8);
167+
168+ /* Pad out to 56 mod 64.
169+ */
170+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
171+ padLen = (index < 56) ? (56 - index) : (120 - index);
172+ MD5Update (context, PADDING, padLen);
173+
174+ /* Append length (before padding) */
175+ MD5Update (context, bits, 8);
176+
177+ /* Store state in digest */
178+ Encode (digest, context->state, 16);
179+
180+ /* Zeroize sensitive information.
181+ */
182+ MD5_memset ((POINTER)context, 0, sizeof (*context));
183+}
184+
185+/* MD5 basic transformation. Transforms state based on block.
186+ */
187+static void MD5Transform (state, block)
188+UINT4 state[4];
189+unsigned char block[64];
190+{
191+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
192+
193+ Decode (x, block, 64);
194+
195+ /* Round 1 */
196+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
197+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
198+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
199+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
200+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
201+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
202+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
203+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
204+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
205+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
206+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
207+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
208+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
209+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
210+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
211+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
212+
213+ /* Round 2 */
214+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
215+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
216+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
217+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
218+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
219+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
220+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
221+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
222+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
223+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
224+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
225+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
226+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
227+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
228+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
229+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
230+
231+ /* Round 3 */
232+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
233+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
234+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
235+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
236+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
237+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
238+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
239+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
240+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
241+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
242+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
243+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
244+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
245+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
246+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
247+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
248+
249+ /* Round 4 */
250+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
251+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
252+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
253+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
254+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
255+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
256+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
257+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
258+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
259+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
260+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
261+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
262+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
263+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
264+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
265+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
266+
267+ state[0] += a;
268+ state[1] += b;
269+ state[2] += c;
270+ state[3] += d;
271+
272+ /* Zeroize sensitive information.
273+ */
274+ MD5_memset ((POINTER)x, 0, sizeof (x));
275+}
276+
277+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
278+ a multiple of 4.
279+ */
280+static void Encode (output, input, len)
281+unsigned char *output;
282+UINT4 *input;
283+unsigned int len;
284+{
285+ unsigned int i, j;
286+
287+ for (i = 0, j = 0; j < len; i++, j += 4) {
288+ output[j] = (unsigned char)(input[i] & 0xff);
289+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
290+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
291+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
292+ }
293+}
294+
295+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
296+ a multiple of 4.
297+ */
298+static void Decode (output, input, len)
299+UINT4 *output;
300+unsigned char *input;
301+unsigned int len;
302+{
303+ unsigned int i, j;
304+
305+ for (i = 0, j = 0; j < len; i++, j += 4)
306+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
307+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
308+}
309+
310+/* Note: Replace "for loop" with standard memcpy if possible.
311+ */
312+static void MD5_memcpy (output, input, len)
313+POINTER output;
314+POINTER input;
315+unsigned int len;
316+{
317+ unsigned int i;
318+
319+ for (i = 0; i < len; i++)
320+ output[i] = input[i];
321+}
322+
323+/* Note: Replace "for loop" with standard memset if possible.
324+ */
325+static void MD5_memset (output, value, len)
326+POINTER output;
327+int value;
328+unsigned int len;
329+{
330+ unsigned int i;
331+
332+ for (i = 0; i < len; i++)
333+ ((char *)output)[i] = (char)value;
334+}
src/asm/type_signature.cpp+203−0
@@ -0,0 +1,203 @@
1+//
2+// Dis VM
3+// File: opcode_tokens.cpp
4+// Author: arr
5+//
6+
7+#include <vm_asm.h>
8+#include <array>
9+#include "rfc1321\global.h"
10+#include "rfc1321\md5.h"
11+
12+using namespace disvm::assembly::sigkind;
13+
14+namespace
15+{
16+ // Compute the signature of the type using the MD5 checksum.
17+ // Based on the implementation from the Limbo compiler.
18+ // Source: limbo/types.c
19+ uint32_t _compute_sig(std::string &str)
20+ {
21+ MD5_CTX context;
22+ MD5Init(&context);
23+
24+ MD5Update(&context, reinterpret_cast<unsigned char *>(const_cast<char *>(str.data())), str.length());
25+
26+ std::array<uint8_t, 16> checksum;
27+ MD5Final(checksum.data(), &context);
28+
29+ auto sig = uint32_t{ 0 };
30+ for (auto i = std::size_t{ 0 }; i < checksum.size(); i += 4)
31+ sig ^= checksum[i] | (checksum[i + 1] << 8) | (checksum[i + 2] << 16) | (checksum[i + 3] << 24);
32+
33+ return sig;
34+ }
35+}
36+
37+uint32_t sig_stream_t::compute_signature_hash(const char *sig)
38+{
39+ std::string sig_local{ sig };
40+ return _compute_sig(sig_local);
41+}
42+
43+std::string sig_stream_t::get_signature() const
44+{
45+ return _ss.str();
46+}
47+
48+uint32_t sig_stream_t::get_signature_hash() const
49+{
50+ auto sig_str = get_signature();
51+ return _compute_sig(sig_str);
52+}
53+
54+sig_stream_t &sig_stream_t::operator<<(const char c)
55+{
56+ _ss << c;
57+ return *this;
58+}
59+
60+sig_stream_t &sig_stream_t::operator<<(const char *s)
61+{
62+ _ss << s;
63+ return *this;
64+}
65+
66+sig_stream_t &sig_stream_t::operator<<(const sig_stream_t &ss)
67+{
68+ _ss << ss._ss.rdbuf();
69+ return *this;
70+}
71+
72+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const modifier_id_t &id)
73+{
74+ return os << static_cast<char>(id);
75+}
76+
77+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const type_id_t &id)
78+{
79+ assert(id != type_id_t::unknown);
80+
81+ if (id == type_id_t::function_varargs)
82+ return os << "f*";
83+
84+ return os << static_cast<char>(id);
85+}
86+
87+Tfixed::Tfixed(double scale)
88+ : _scale{ scale }
89+{ }
90+
91+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tfixed &f)
92+{
93+ char buffer[32];
94+ ::sprintf(buffer, "%g", f._scale);
95+ return os << Tfixed::id << buffer;
96+}
97+
98+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tarray &a)
99+{
100+ return os << a._s;
101+}
102+
103+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tref &r)
104+{
105+ return os << r._s;
106+}
107+
108+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tlist &l)
109+{
110+ return os << l._s;
111+}
112+
113+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tchannel &c)
114+{
115+ return os << c._s;
116+}
117+
118+Ttype_ref::Ttype_ref(uint32_t num)
119+ : _num{ num }
120+{ }
121+
122+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Ttype_ref &r)
123+{
124+ return os << '@' << r._num;
125+}
126+
127+Tm::Tm(const char *name, const type_id_t &type_id)
128+ : _name{ name }
129+ , _type_id{ type_id }
130+ , _type_id_str{ nullptr }
131+{ }
132+
133+Tm::Tm(const char *name, const char *type_id)
134+ : _name{ name }
135+ , _type_id{ type_id_t::unknown }
136+ , _type_id_str{ type_id }
137+{ }
138+
139+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tm &m)
140+{
141+ if (m._type_id_str == nullptr)
142+ {
143+ assert(m._type_id != type_id_t::unknown);
144+ return os << m._name << ':' << m._type_id;
145+ }
146+ else
147+ {
148+ assert(m._type_id == type_id_t::unknown);
149+ return os << m._name << ':' << m._type_id_str;
150+ }
151+}
152+
153+const char Ttuple::begin = '(';
154+const char Ttuple::end = ')';
155+
156+const char Tadt::begin = '(';
157+const char Tadt::end = ')';
158+
159+const char Tmodule::begin = '{';
160+const char Tmodule::end = '}';
161+
162+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Ttuple &t)
163+{
164+ return os << t._s;
165+}
166+
167+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tadt &a)
168+{
169+ return os << a._s;
170+}
171+
172+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tmodule &m)
173+{
174+ return os << m._s;
175+}
176+
177+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, Tfunction &f)
178+{
179+ if (!f._fully_defined)
180+ f.returns(Tnone::id);
181+
182+ return os << f._s;
183+}
184+
185+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tfunction &f)
186+{
187+ assert(!f._fully_defined && "Incomplete function");
188+ return os << f._s;
189+}
190+
191+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, Tfunction_varargs &f)
192+{
193+ if (!f._fully_defined)
194+ f.returns(Tnone::id);
195+
196+ return os << f._s;
197+}
198+
199+sig_stream_t &disvm::assembly::sigkind::operator<<(sig_stream_t &os, const Tfunction_varargs &f)
200+{
201+ assert(!f._fully_defined && "Incomplete function");
202+ return os << f._s;
203+}
src/exec/main.cpp+20−22
@@ -11,10 +11,12 @@ · 10 unmodified lines
1111 #include <builtin_module.h>
1212 #include <debug.h>
1313 #include <exceptions.h>
14+#include <vm_asm.h>
1415 #include "exec.h"
1516
1617 using namespace disvm;
1718 using namespace disvm::runtime;
19+using namespace disvm::assembly::sigkind;
1820
1921 namespace
2022 {
@@ -88,20 +90,16 @@ namespace · 67 unmodified lines
8890 };
8991
9092 // Initialize the module base register
91− const auto mp_type = type_descriptor_t::create(12, { 0xe0 });
93+ const auto mp_type = type_descriptor_t::create(8, { 0xc0 });
9294 e.original_mp.reset(vm_alloc_t::allocate(mp_type, vm_alloc_t::zero_memory));
9395 auto mp_base = e.original_mp->get_allocation<pointer_t>();
9496 mp_base[0] = command_module_path->get_allocation();
9597
96− // [TODO] Implement the UI context for the command
97− mp_base[1] = nullptr;
98−
9998 if (args != nullptr)
100− mp_base[2] = args->get_allocation();
99+ mp_base[1] = args->get_allocation();
101100
102101 // Define the frame offsets for the two arguments
103102 const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset;
104− const auto second_arg_offset = first_arg_offset + vm_frame_constants::register_size_in_bytes;
105103
106104 e.code_section =
107105 {
@@ -124,17 +122,9 @@ namespace · 16 unmodified lines
124122 { vm_exec_op_t
125123 {
126124 opcode_t::movp,
127− { address_mode_t::offset_indirect_mp, 4, 0 }, // UI context
128− { address_mode_middle_t::none },
129− { address_mode_t::offset_double_indirect_fp, 24, first_arg_offset } // module call frame -> UI context offset
130− }
131− },
132− { vm_exec_op_t
133− {
134− opcode_t::movp,
135− { address_mode_t::offset_indirect_mp, 8, 0 }, // Argument list
125+ { address_mode_t::offset_indirect_mp, 4, 0 }, // Argument list
136126 { address_mode_middle_t::none },
137− { address_mode_t::offset_double_indirect_fp, 24, second_arg_offset } // module call frame -> argument list offset
127+ { address_mode_t::offset_double_indirect_fp, 24, first_arg_offset } // module call frame -> argument list offset
138128 }
139129 },
140130 { vm_exec_op_t
@@ -148,13 +138,21 @@ namespace · 7 unmodified lines
148138 { vm_exec_op_t{ opcode_t::ret,{ address_mode_t::none },{ address_mode_middle_t::none },{ address_mode_t::none } } },
149139 };
150140
151− // Create import section for Command
152− // See limbo/Command.m for type details
141+ // Create import section for Exec
142+ // See limbo/Exec.m for type details
153143 {
154− import_function_t func{};
155−
156− // [TODO] Create mechanism to generated type signatures
157− func.sig = 0x4244b354;
144+ import_function_t func;
145+
146+ const auto exec_init_sig = 0x2e01144a;
147+
148+ // Validate the hard-coded type signature on debug builds.
149+#if !defined(NDEBUG)
150+ sig_stream_t m;
151+ m << Tfunction::create(Tlist::create(Tstring::id)).returns(Tnone::id);
152+ assert(exec_init_sig == m.get_signature_hash());
153+ assert(exec_init_sig == sig_stream_t::compute_signature_hash("f(Ls)n"));
154+#endif
155+ func.sig = exec_init_sig;
158156
159157 std::array<uint8_t, 5> func_name = { "init" };
160158 func.name = std::make_unique<vm_string_t>(func_name.size() - 1, func_name.data());
src/include/vm_asm.h+256−0
@@ -8,6 +8,9 @@ · 7 unmodified lines
88 #define _DISVM_SRC_INCLUDE_VM_ASM_H_
99
1010 #include <iosfwd>
11+#include <sstream>
12+#include <cassert>
13+#include <cstdint>
1114 #include "opcodes.h"
1215 #include "runtime.h"
1316
@@ -21,6 +24,259 @@ namespace disvm · 7 unmodified lines
2124 // Get the opcode from this string.
2225 // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned.
2326 disvm::opcode_t token_to_opcode(const char *);
27+
28+ // Namedspace named after enum type in Limbo compiler
29+ // Source: limbo/types.c
30+ namespace sigkind
31+ {
32+ // Signature stream
33+ class sig_stream_t
34+ {
35+ public: // static
36+ static uint32_t compute_signature_hash(const char *);
37+
38+ public:
39+ std::string get_signature() const;
40+
41+ uint32_t get_signature_hash() const;
42+
43+ sig_stream_t &operator<<(const char);
44+ sig_stream_t &operator<<(const char *);
45+ sig_stream_t &operator<<(const sig_stream_t &);
46+
47+ private:
48+ std::stringstream _ss;
49+ };
50+
51+ // Type context modifiers
52+ enum class modifier_id_t : uint8_t
53+ {
54+ self = 'S',
55+ cycle = 'y',
56+ };
57+
58+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::modifier_id_t &);
59+
60+ // Instrinsic VM types
61+ enum class type_id_t : uint8_t
62+ {
63+ unknown = 0,
64+ none = 'n',
65+ byte = 'b',
66+ integer = 'i',
67+ real = 'r',
68+ big = 'B',
69+ string = 's',
70+ poly = 'P',
71+ fixed = 'x',
72+ array = 'A',
73+ ref = 'R',
74+ list = 'L',
75+ channel = 'C',
76+ adt = 'a',
77+ //adtpick = 'p',
78+ tuple = 't',
79+ module = 'm',
80+ function = 'f',
81+ function_varargs = 0xff, // "f*"
82+ };
83+
84+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::type_id_t &);
85+
86+ template<type_id_t T>
87+ struct Tbasic_type
88+ {
89+ static const type_id_t id = T;
90+
91+ constexpr operator type_id_t() const
92+ {
93+ return Tbasic_type::id;
94+ }
95+ };
96+
97+ using Tnone = Tbasic_type<type_id_t::none>;
98+ using Tbyte = Tbasic_type<type_id_t::byte>;
99+ using Tinteger = Tbasic_type<type_id_t::integer>;
100+ using Treal = Tbasic_type<type_id_t::real>;
101+ using Tbig = Tbasic_type<type_id_t::big>;
102+ using Tstring = Tbasic_type<type_id_t::string>;
103+ using Tpoly = Tbasic_type<type_id_t::poly>;
104+
105+ class Tfixed : public Tbasic_type<type_id_t::fixed>
106+ {
107+ public:
108+ Tfixed(double scale);
109+
110+ friend sig_stream_t &operator<<(sig_stream_t &os, const Tfixed &);
111+
112+ private:
113+ const double _scale;
114+ };
115+
116+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfixed &);
117+
118+ // Type that contains/modifies another type
119+ template <type_id_t ID>
120+ class Tbasic_aggregate_type : public Tbasic_type<ID>
121+ {
122+ public:
123+ template<typename U>
124+ static Tbasic_aggregate_type create(const U &type)
125+ {
126+ sig_stream_t ss;
127+ ss << Tbasic_type::id << type;
128+
129+ return Tbasic_aggregate_type{ ss };
130+ }
131+
132+ friend sig_stream_t &operator<<(sig_stream_t &, const Tbasic_aggregate_type &);
133+
134+ private:
135+ sig_stream_t _s;
136+ Tbasic_aggregate_type(sig_stream_t &s) : _s{ std::move(s) } { }
137+ };
138+
139+ using Tarray = Tbasic_aggregate_type<type_id_t::array>;
140+ using Tref = Tbasic_aggregate_type<type_id_t::ref>;
141+ using Tlist = Tbasic_aggregate_type<type_id_t::list>;
142+ using Tchannel = Tbasic_aggregate_type<type_id_t::channel>;
143+
144+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tarray &);
145+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tref &);
146+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tlist &);
147+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tchannel &);
148+
149+ // Reference to another previously defined type in the current signature
150+ struct Ttype_ref
151+ {
152+ Ttype_ref(uint32_t num);
153+
154+ friend sig_stream_t &operator<<(sig_stream_t &os, const Ttype_ref &);
155+
156+ private:
157+ const uint32_t _num;
158+ };
159+
160+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttype_ref &);
161+
162+ // Named member type
163+ struct Tm
164+ {
165+ Tm(const char *name, const type_id_t &type_id);
166+ Tm(const char *name, const char *type_id);
167+
168+ friend sig_stream_t &operator<<(sig_stream_t &os, const Tm &);
169+
170+ private:
171+ const char *_type_id_str;
172+ const type_id_t _type_id;
173+ const char *_name;
174+ };
175+
176+ sig_stream_t & operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tm &);
177+
178+ inline void nested_type(const sig_stream_t &)
179+ {
180+ return;
181+ }
182+
183+ template<typename T, typename ...S>
184+ void nested_type(sig_stream_t &ss, const T &t, const S&...s)
185+ {
186+ ss << t;
187+ nested_type(ss, s...);
188+ }
189+
190+ template<typename T1, typename T2, typename ...S>
191+ void nested_type(sig_stream_t &ss, const T1 &t1, const T2 &t2, const S&...s)
192+ {
193+ ss << t1 << ',';
194+ nested_type(ss, t2, s...);
195+ }
196+
197+ // Type whose definition depends on contained types
198+ template <type_id_t ID>
199+ class Tnested_aggregate_type : public Tbasic_type<ID>
200+ {
201+ public:
202+ static const char begin;
203+ static const char end;
204+
205+ template<typename ...NT>
206+ static Tnested_aggregate_type create(const NT&... nestedTypes)
207+ {
208+ sig_stream_t ss;
209+ ss << Tbasic_type::id << Tnested_aggregate_type::begin;
210+
211+ nested_type(ss, nestedTypes...);
212+
213+ ss << Tnested_aggregate_type::end;
214+
215+ return Tnested_aggregate_type{ ss };
216+ }
217+
218+ friend sig_stream_t &operator<<(sig_stream_t &, const Tnested_aggregate_type &);
219+
220+ private:
221+ sig_stream_t _s;
222+ Tnested_aggregate_type(sig_stream_t &s) : _s{ std::move(s) } { }
223+ };
224+
225+ using Ttuple = Tnested_aggregate_type<type_id_t::tuple>;
226+ using Tadt = Tnested_aggregate_type<type_id_t::adt>;
227+ using Tmodule = Tnested_aggregate_type<type_id_t::module>;
228+
229+ sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttuple &);
230+ sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tadt &);
231+ sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tmodule &);
232+
233+ // Function type
234+ template<type_id_t T>
235+ class Tfunction_base_type : public Tbasic_type<T>
236+ {
237+ public:
238+ static const char begin = '(';
239+ static const char end = ')';
240+
241+ template<typename ...AT>
242+ static Tfunction_base_type create(AT... argTypes)
243+ {
244+ Tfunction_base_type a;
245+ a._s << Tfunction_base_type::id << Tfunction_base_type::begin;
246+
247+ nested_type(a._s, argTypes...);
248+
249+ a._s << Tfunction_base_type::end;
250+ return a;
251+ }
252+
253+ template<typename RT>
254+ Tfunction_base_type &returns(RT r)
255+ {
256+ assert(!_fully_defined && "Function type already complete");
257+ _s << r;
258+ _fully_defined = true;
259+
260+ return *this;
261+ }
262+
263+ friend sig_stream_t &operator<<(sig_stream_t &, Tfunction_base_type &);
264+ friend sig_stream_t &operator<<(sig_stream_t &, const Tfunction_base_type &);
265+
266+ private:
267+ bool _fully_defined;
268+ sig_stream_t _s;
269+ Tfunction_base_type() : _fully_defined{ false } { }
270+ };
271+
272+ using Tfunction = Tfunction_base_type<type_id_t::function>;
273+ using Tfunction_varargs = Tfunction_base_type<type_id_t::function_varargs>;
274+
275+ sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction &);
276+ sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction &);
277+ sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction_varargs &);
278+ sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction_varargs &);
279+ }
24280 }
25281
26282 namespace runtime