зеркало из https://github.com/github/ruby.git
Progress on porting x86 assembler for MicroJIT
This commit is contained in:
Родитель
07dd5f22a5
Коммит
0a5dcc056e
|
@ -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) \
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
Загрузка…
Ссылка в новой задаче