-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpreter.py
143 lines (121 loc) · 5.4 KB
/
interpreter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
from __future__ import with_statement
from rpython.rlib import jit
from type_wrapper import NoValue, NumericValue, BasicBlock
from rpython.rtyper.lltypesystem import rffi, lltype
from state import InterpreterState, Frame
from llvm_objects import W_Module
import llvm_wrapper as llwrap
import sys
def target(*args):
return main, None
def jitpolicy(driver):
from rpython.jit.codewriter.policy import JitPolicy
return JitPolicy()
def get_printable_location(interpreter, block, function):
return "%s: %s" % (function.name, interpreter.current_instruction.name)
jit_driver = jit.JitDriver(greens=["self", "block", "function"],
reds=[],
get_printable_location=get_printable_location)
class InvalidFileException(Exception):
pass
class UnparsableBitcodeException(Exception):
pass
def exit_not_implemented(name):
print "[ERROR]: Found unimplemented operation. Exiting."
raise NotImplementedError(name)
def puts(string, args=[]):
''' Prints (on separate lines) the given string and the arguments
specified. '''
print string
if args:
for arg in args:
assert isinstance(arg, NumericValue)
print arg.value
print "\n\n"
# the print function to use - can be changed to some other function
# for testing purposes (to supress and save the output)
print_function = puts
class Interpreter(object):
interp_state = InterpreterState()
def __init__(self, module, global_frame, frame):
self.module = module
self.global_frame = global_frame
self.current_instruction = None
self.frame = frame
Interpreter.interp_state.update(module=self.module,\
global_frame=self.global_frame,
frame=self.frame)
@jit.unroll_safe
def _get_args(self, args):
''' Returns a list of Values representing each Variable
in args. '''
arg_vals = []
for arg in args:
arg_vals.append(self.interp_state.lookup_var(arg, ignore_err=True))
return arg_vals
def run(self, function):
''' Runs each instruction of the given function and creates
a new stack frame for the local variables. '''
# call instructions set up the next stack frame for the interpreter
# initially, each stack frame contains the function arguments
block = function.get_first_block()
Interpreter.interp_state.update(frame=self.frame, last_block=block)
while block:
jit_driver.jit_merge_point(function=function, block=block, self=self)
instruction = block.get_first_instruction()
next_block = block.w_next_block
while instruction:
self.current_instruction = instruction
result = instruction.execute(self._get_args(instruction.operands))
Interpreter.interp_state.update(frame=self.frame)
if isinstance(result, BasicBlock):
next_block = result.value
break
elif not isinstance(result, NoValue):
self.frame.set_variable(instruction.addr, result)
instruction = instruction.w_next_instr
# last instruction should be ret
if not instruction:
return result
self.interp_state.update(last_block=block)
block = next_block
def create_module(filename):
''' Returns the W_Module representing an LLVM module created with the
contents of the given file. '''
module = llwrap.LLVMModuleCreateWithName("module")
with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as out_message:
with lltype.scoped_alloc(rffi.VOIDP.TO, 1) as mem_buff:
with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as mem_buff_ptr:
mem_buff_ptr[0] = mem_buff
rc = llwrap.LLVMCreateMemoryBufferWithContentsOfFile(filename,
mem_buff_ptr,
out_message)
if rc != 0:
print "[ERROR]: Cannot create memory buffer with contents of"\
" %s: %s.\n" % (filename, rffi.charp2str(out_message[0]))
raise InvalidFileException(filename)
mem_buff = mem_buff_ptr[0]
with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as module_ptr:
module_ptr[0] = module
rc = llwrap.LLVMParseBitcode(mem_buff, module_ptr, out_message)
if rc != 0:
print "[ERROR]: Cannot parse %s: %s.\n" % (filename,
rffi.charp2str(out_message[0]))
raise UnparsableBitcodeException(filename)
module = module_ptr[0]
return W_Module(module)
def main(args):
if len(args) < 2:
print"[ERROR]: Need an argument:\nUsage: ./interpreter-c name.bc [C args]\n"
return 1
module = create_module(args[1])
main_argc = len(args) - 1
main_argv = args[1:]
global_frame = Frame()
module.load_globals(global_frame)
module.load_main(main_argc, main_argv)
interp = Interpreter(module, global_frame, InterpreterState.main_frame)
interp.run(module.w_main_fun)
return 0
if __name__ == '__main__':
main(sys.argv)