Created
August 14, 2021 12:43
-
-
Save elct9620/6d54a301728010fe11681e27c619b110 to your computer and use it in GitHub Desktop.
RubyKaigi 2021 Takeout - mruby VM demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdio.h> | |
#include <string.h> | |
static inline uint32_t | |
bin_to_uint32(const uint8_t *bin) | |
{ | |
return (uint32_t)bin[0] << 24 | | |
(uint32_t)bin[1] << 16 | | |
(uint32_t)bin[2] << 8 | | |
(uint32_t)bin[3]; | |
} | |
static inline uint16_t | |
bin_to_uint16(const uint8_t *bin) | |
{ | |
return (uint16_t)bin[0] << 8 | | |
(uint16_t)bin[1]; | |
} | |
static size_t skip_padding(const uint8_t* buf) { | |
const size_t align = sizeof(uint32_t); | |
return -(intptr_t)buf & (align - 1); | |
} | |
const uint8_t* irep_get_symbol(const uint8_t* p, int n) { | |
// SKIP IREP HEADER / ISEQ | |
p += 10; | |
uint32_t length = bin_to_uint32(p); | |
p += 4; | |
p += skip_padding(p); | |
p += length; | |
// SKIP POOL | |
{ | |
uint32_t npool = bin_to_uint32(p); | |
p += 4; | |
for(int i = 0; i < npool; i++) { | |
uint8_t vtype = *p; | |
p++; | |
uint16_t len = bin_to_uint16(p); | |
p += 2; | |
p += len + 1; // End with null byte | |
} | |
} | |
// Find in SYM | |
{ | |
uint32_t nsym = n; | |
p += 4; | |
for (int i = 0; i < nsym; i++) { | |
uint16_t len = bin_to_uint16(p); | |
p += len + 1; // End with null byte | |
} | |
return p + 2; // Skip length | |
} | |
return p; | |
} | |
enum { | |
OP_NOP, | |
OP_LOADI__1 = 5, | |
OP_LOADI_0, | |
OP_LOADI_1, | |
OP_LOADI_2, | |
OP_LOADI_3, | |
OP_LOADI_4, | |
OP_LOADI_5, | |
OP_LOADI_6, | |
OP_LOADI_7, | |
OP_LOADSELF = 16, | |
OP_SEND = 46, | |
OP_RETURN = 55, | |
OP_ADD = 59, | |
OP_ADDI, | |
}; | |
int main(int argc, char** argv) { | |
printf("Read: %s\n", argv[1]); | |
FILE *fp = fopen(argv[1], "r"); | |
fseek(fp, 0, SEEK_END); | |
size_t size = ftell(fp); | |
fseek(fp, 0, SEEK_SET); | |
uint8_t binary[size]; | |
fread(binary, sizeof(uint8_t), size, fp); | |
const uint8_t* bin = binary; | |
const uint8_t* data = binary; | |
// RITE | |
bin += 34; | |
data += 34; | |
// Record Size | |
bin += 4; | |
// Local Variables | |
uint16_t nlocals = bin_to_uint16(bin); | |
bin += 2; | |
uint16_t nregs = bin_to_uint16(bin); | |
bin += 2; | |
uint16_t nirep = bin_to_uint16(bin); | |
bin += 2; | |
uint32_t niseq = bin_to_uint32(bin); | |
bin += 4; | |
bin += skip_padding(bin); | |
printf("nregs=%d nlocals=%d iseq=%d\n", nregs, nlocals, niseq); | |
// Create Register | |
intptr_t reg[nregs - 1]; | |
// Temp Variable | |
int32_t a = 0; | |
int32_t b = 0; | |
int32_t c = 0; | |
for(;;) { | |
uint8_t opcode = *bin++; | |
switch(opcode) { | |
case OP_NOP: | |
break; | |
case OP_LOADI_0: | |
case OP_LOADI_1: | |
case OP_LOADI_2: | |
case OP_LOADI_3: | |
case OP_LOADI_4: | |
case OP_LOADI_5: | |
case OP_LOADI_6: | |
case OP_LOADI_7: | |
a = *bin++; | |
reg[a] = opcode - OP_LOADI_0; | |
break; | |
case OP_ADDI: | |
a = *bin++; b = *bin++; | |
reg[a] += b; | |
break; | |
case OP_LOADSELF: | |
// Create Call Stack | |
a = *bin++; | |
break; | |
case OP_SEND: | |
a = *bin++; | |
b = *bin++; | |
c = *bin++; | |
const char* fn = (const char*)irep_get_symbol(data, b); | |
if(strcmp(fn, "c_add") == 0) { | |
int sum = 0; | |
// Sum Arguments | |
for(int i = 1; i <= c; i++) { | |
sum += reg[a + i]; | |
} | |
// Save to return value | |
reg[a] = sum; | |
} else { | |
// Undefiend Method | |
printf("Undefined Method\n"); | |
return 1; | |
} | |
break; | |
case OP_RETURN: | |
a = *bin++; | |
printf("Result: %ld\n", reg[a]); | |
return 0; | |
default: | |
printf("Unsuport OPCODE = %d\n", opcode); | |
return 1; | |
} | |
} | |
fclose(fp); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment