summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2020-09-04 15:56:00 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2021-10-20 18:19:22 -0400
commit0a5dcc056e22bab849d8d7877928d300201af823 (patch)
treeb633cb97d8bacda6f8b5a5df533404c260a2e565
parent07dd5f22a5d3127981eea7602bd3d6c221f5d12e (diff)
downloadruby-0a5dcc056e22bab849d8d7877928d300201af823.tar.gz
Progress on porting x86 assembler for MicroJIT
-rw-r--r--common.mk2
-rwxr-xr-xtest_asm.sh6
-rw-r--r--ujit_asm.c183
-rw-r--r--ujit_asm.h72
-rw-r--r--ujit_asm_tests.c31
5 files changed, 294 insertions, 0 deletions
diff --git a/common.mk b/common.mk
index 45ebaab86a..59d5dcea5d 100644
--- a/common.mk
+++ b/common.mk
@@ -150,6 +150,8 @@ COMMONOBJS = array.$(OBJEXT) \
vm_dump.$(OBJEXT) \
vm_sync.$(OBJEXT) \
vm_trace.$(OBJEXT) \
+ ujit_asm.$(OBJEXT) \
+ ujit_asm_tests.$(OBJEXT) \
$(COROUTINE_OBJ) \
$(DTRACE_OBJ) \
$(BUILTIN_ENCOBJS) \
diff --git a/test_asm.sh b/test_asm.sh
new file mode 100755
index 0000000000..446dd36d65
--- /dev/null
+++ b/test_asm.sh
@@ -0,0 +1,6 @@
+# NOTE: I did not know what would be the sensible way to compile
+# and run these tests from the Ruby makefile
+
+clang -std=c99 -Wall ujit_asm.c ujit_asm_tests.c -o asm_test
+
+./asm_test
diff --git a/ujit_asm.c b/ujit_asm.c
new file mode 100644
index 0000000000..7ff8792059
--- /dev/null
+++ b/ujit_asm.c
@@ -0,0 +1,183 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+// For mmapp()
+#include <sys/mman.h>
+
+#include "ujit_asm.h"
+
+// TODO: give ujit_examples.h some more meaningful file name
+#include "ujit_examples.h"
+
+void cb_init(codeblock_t* cb, size_t mem_size)
+{
+ // Map the memory as executable
+ cb->mem_block = (uint8_t*)mmap(
+ NULL,
+ mem_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANON,
+ -1,
+ 0
+ );
+
+ // Check that the memory mapping was successful
+ if (cb->mem_block == MAP_FAILED)
+ {
+ fprintf(stderr, "mmap call failed\n");
+ exit(-1);
+ }
+
+ cb->mem_size = mem_size;
+ cb->write_pos = 0;
+ cb->num_labels = 0;
+ cb->num_refs = 0;
+}
+
+// Get a direct pointer into the executable memory block
+uint8_t* cb_get_ptr(codeblock_t* cb, size_t index)
+{
+ assert (index < cb->mem_size);
+ return &cb->mem_block[index];
+}
+
+// Write a byte at the current position
+void cb_write_byte(codeblock_t* cb, uint8_t byte)
+{
+ assert (cb->mem_block);
+ assert (cb->write_pos + 1 <= cb->mem_size);
+ cb->mem_block[cb->write_pos++] = byte;
+}
+
+// Write multiple bytes starting from the current position
+void cb_write_bytes(codeblock_t* cb, size_t num_bytes, ...)
+{
+ va_list va;
+ va_start(va, num_bytes);
+
+ for (size_t i = 0; i < num_bytes; ++i)
+ {
+ uint8_t byte = va_arg(va, int);
+ cb_write_byte(cb, byte);
+ }
+
+ va_end(va);
+}
+
+// Write a signed integer over a given number of bits at the current position
+void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits)
+{
+ assert (num_bits > 0);
+ assert (num_bits % 8 == 0);
+
+ // Switch on the number of bits
+ switch (num_bits)
+ {
+ case 8:
+ cb_write_byte(cb, (uint8_t)val);
+ break;
+
+ case 16:
+ cb_write_bytes(
+ cb,
+ 2,
+ (uint8_t)((val >> 0) & 0xFF),
+ (uint8_t)((val >> 8) & 0xFF)
+ );
+ break;
+
+ case 32:
+ cb_write_bytes(
+ cb,
+ 4,
+ (uint8_t)((val >> 0) & 0xFF),
+ (uint8_t)((val >> 8) & 0xFF),
+ (uint8_t)((val >> 16) & 0xFF),
+ (uint8_t)((val >> 24) & 0xFF)
+ );
+ break;
+
+ default:
+ {
+ // Compute the size in bytes
+ size_t num_bytes = num_bits / 8;
+
+ // Write out the bytes
+ for (size_t i = 0; i < num_bytes; ++i)
+ {
+ uint8_t byte_val = (uint8_t)(val & 0xFF);
+ cb_write_byte(cb, byte_val);
+ val >>= 8;
+ }
+ }
+ }
+}
+
+// nop - Noop, one or multiple bytes long
+void nop(codeblock_t* cb, size_t length)
+{
+ switch (length)
+ {
+ case 0:
+ break;
+
+ case 1:
+ //cb.writeASM("nop1");
+ cb_write_byte(cb, 0x90);
+ break;
+
+ case 2:
+ //cb.writeASM("nop2");
+ cb_write_bytes(cb, 2, 0x66,0x90);
+ break;
+
+ case 3:
+ //cb.writeASM("nop3");
+ cb_write_bytes(cb, 3, 0x0F,0x1F,0x00);
+ break;
+
+ case 4:
+ //cb.writeASM("nop4");
+ cb_write_bytes(cb, 4, 0x0F,0x1F,0x40,0x00);
+ break;
+
+ case 5:
+ //cb.writeASM("nop5");
+ cb_write_bytes(cb, 5, 0x0F,0x1F,0x44,0x00,0x00);
+ break;
+
+ case 6:
+ //cb.writeASM("nop6");
+ cb_write_bytes(cb, 6, 0x66,0x0F,0x1F,0x44,0x00,0x00);
+ break;
+
+ case 7:
+ //cb.writeASM("nop7");
+ cb_write_bytes(cb, 7, 0x0F,0x1F,0x80,0x00,0x00,0x00,0x00);
+ break;
+
+ case 8:
+ //cb.writeASM("nop8");
+ cb_write_bytes(cb, 8, 0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00);
+ break;
+
+ case 9:
+ //cb.writeASM("nop9");
+ cb_write_bytes(cb, 9, 0x66,0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00);
+ break;
+
+ default:
+ {
+ size_t written = 0;
+ while (written + 9 <= length)
+ {
+ nop(cb, 9);
+ written += 9;
+ }
+ nop(cb, length - written);
+ }
+ break;
+ }
+}
diff --git a/ujit_asm.h b/ujit_asm.h
new file mode 100644
index 0000000000..998c171d5d
--- /dev/null
+++ b/ujit_asm.h
@@ -0,0 +1,72 @@
+#ifndef UJIT_ASM_H
+#define UJIT_ASM_H 1
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+// Maximum number of labels to link
+#define MAX_LABELS 32
+
+// Maximum number of label references
+#define MAX_LABEL_REFS 32
+
+typedef struct LabelRef
+{
+ // Position where the label reference is in the code block
+ size_t pos;
+
+ // Label which this refers to
+ size_t label_idx;
+
+} labelref_t;
+
+typedef struct CodeBlock
+{
+ // Memory block
+ uint8_t* mem_block;
+
+ // Memory block size
+ size_t mem_size;
+
+ /// Current writing position
+ size_t write_pos;
+
+ // Table of registered label addresses
+ size_t label_addrs[MAX_LABELS];
+
+ // References to labels
+ labelref_t label_refs[MAX_LABEL_REFS];
+
+ // Number of labels registeered
+ size_t num_labels;
+
+ // Number of references to labels
+ size_t num_refs;
+
+ // TODO: system for disassembly/comment strings, indexed by position
+
+ // Flag to enable or disable comments
+ bool has_asm;
+
+} codeblock_t;
+
+void cb_init(codeblock_t* cb, size_t mem_size);
+uint8_t* cb_get_ptr(codeblock_t* cb, size_t index);
+void cb_write_byte(codeblock_t* cb, uint8_t byte);
+void cb_write_bytes(codeblock_t* cb, size_t num_bytes, ...);
+void cb_write_int(codeblock_t* cb, uint64_t val, size_t num_bits);
+
+// TODO:
+// prologue and epilogue functions
+// cb_write_prologue()
+// cb_write_epilogue
+// Test those out
+
+void nop(codeblock_t* cb, size_t length);
+
+
+
+
+
+#endif
diff --git a/ujit_asm_tests.c b/ujit_asm_tests.c
new file mode 100644
index 0000000000..0c94fb8b04
--- /dev/null
+++ b/ujit_asm_tests.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "ujit_asm.h"
+
+//fprintf(stderr, format);
+//exit(-1)
+
+void run_tests()
+{
+ printf("Running assembler tests\n");
+
+ codeblock_t cb;
+ cb_init(&cb, 4096);
+
+
+
+
+
+
+
+
+
+ printf("Assembler tests done\n");
+}
+
+int main(int argc, char** argv)
+{
+ run_tests();
+
+ return 0;
+}