mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Progress on porting x86 assembler for MicroJIT
This commit is contained in:
parent
07dd5f22a5
commit
0a5dcc056e
5 changed files with 294 additions and 0 deletions
|
@ -150,6 +150,8 @@ COMMONOBJS = array.$(OBJEXT) \
|
||||||
vm_dump.$(OBJEXT) \
|
vm_dump.$(OBJEXT) \
|
||||||
vm_sync.$(OBJEXT) \
|
vm_sync.$(OBJEXT) \
|
||||||
vm_trace.$(OBJEXT) \
|
vm_trace.$(OBJEXT) \
|
||||||
|
ujit_asm.$(OBJEXT) \
|
||||||
|
ujit_asm_tests.$(OBJEXT) \
|
||||||
$(COROUTINE_OBJ) \
|
$(COROUTINE_OBJ) \
|
||||||
$(DTRACE_OBJ) \
|
$(DTRACE_OBJ) \
|
||||||
$(BUILTIN_ENCOBJS) \
|
$(BUILTIN_ENCOBJS) \
|
||||||
|
|
6
test_asm.sh
Executable file
6
test_asm.sh
Executable file
|
@ -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
|
183
ujit_asm.c
Normal file
183
ujit_asm.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
72
ujit_asm.h
Normal file
72
ujit_asm.h
Normal file
|
@ -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
|
31
ujit_asm_tests.c
Normal file
31
ujit_asm_tests.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue