Skip to content

Commit

Permalink
Merge bc0162c into ec969cf
Browse files Browse the repository at this point in the history
  • Loading branch information
timfel committed Mar 23, 2017
2 parents ec969cf + bc0162c commit f1e8608
Show file tree
Hide file tree
Showing 37 changed files with 1,813 additions and 967 deletions.
1 change: 1 addition & 0 deletions .codeclimate.yml
Expand Up @@ -27,3 +27,4 @@ exclude_paths:
- "repository/*"
- "scripts/**/*"
- "scripts/*"

56 changes: 28 additions & 28 deletions rsqueakvm/constants.py
Expand Up @@ -127,42 +127,42 @@
SO_JIT_HOOK_RCVR = 59 # really selectorTrap

constant_objects_in_special_object_table = {
"nil": (SO_NIL, "POINTERS"),
"true": (SO_TRUE, "POINTERS"),
"false": (SO_FALSE, "POINTERS"),
"nil": (SO_NIL, "FIXED"),
"true": (SO_TRUE, "FIXED"),
"false": (SO_FALSE, "FIXED"),
"charactertable": (SO_CHARACTER_TABLE_ARRAY, "POINTERS"),
"schedulerassociationpointer": (SO_SCHEDULERASSOCIATIONPOINTER, "POINTERS"),
"schedulerassociationpointer": (SO_SCHEDULERASSOCIATIONPOINTER, "FIXED"),
"special_selectors": (SO_SPECIAL_SELECTORS_ARRAY, "POINTERS"),
"smalltalkdict": (SO_SMALLTALK, "POINTERS"),
"smalltalkdict": (SO_SMALLTALK, "FIXED"),
"doesNotUnderstand": (SO_DOES_NOT_UNDERSTAND, "BYTES"),
"mustBeBoolean": (SO_MUST_BE_BOOLEAN, "BYTES"),
"runWithIn": (SO_RUN_WITH_IN, "BYTES"),
"cannotReturn": (SO_CANNOT_RETURN, "BYTES"),
# classes
"Bitmap": (SO_BITMAP_CLASS, "POINTERS"),
"SmallInteger": (SO_SMALLINTEGER_CLASS, "POINTERS"),
"String": (SO_STRING_CLASS, "POINTERS"),
"Array": (SO_ARRAY_CLASS, "POINTERS"),
"Float": (SO_FLOAT_CLASS, "POINTERS"),
"MethodContext": (SO_METHODCONTEXT_CLASS, "POINTERS"),
"BlockContext": (SO_BLOCKCONTEXT_CLASS, "POINTERS"),
"BlockClosure": (SO_BLOCKCLOSURE_CLASS, "POINTERS"),
"Point": (SO_POINT_CLASS, "POINTERS"),
"LargePositiveInteger": (SO_LARGEPOSITIVEINTEGER_CLASS, "POINTERS"),
"Message": (SO_MESSAGE_CLASS, "POINTERS"),
"CompiledMethod": (SO_COMPILEDMETHOD_CLASS, "POINTERS"),
"Semaphore": (SO_SEMAPHORE_CLASS, "POINTERS"),
"Character": (SO_CHARACTER_CLASS, "POINTERS"),
"ByteArray": (SO_BYTEARRAY_CLASS, "POINTERS"),
"Process": (SO_PROCESS_CLASS, "POINTERS"),
# "PseudoContext" : (SO_PSEUDOCONTEXT_CLASS, "POINTERS"),
# "TranslatedMethod" : (SO_TRANSLATEDMETHOD_CLASS, "POINTERS"),
"LargeNegativeInteger" : (SO_LARGENEGATIVEINTEGER_CLASS, "POINTERS"),
"Bitmap": (SO_BITMAP_CLASS, "FIXED"),
"SmallInteger": (SO_SMALLINTEGER_CLASS, "FIXED"),
"String": (SO_STRING_CLASS, "FIXED"),
"Array": (SO_ARRAY_CLASS, "FIXED"),
"Float": (SO_FLOAT_CLASS, "FIXED"),
"MethodContext": (SO_METHODCONTEXT_CLASS, "FIXED"),
"BlockContext": (SO_BLOCKCONTEXT_CLASS, "FIXED"),
"BlockClosure": (SO_BLOCKCLOSURE_CLASS, "FIXED"),
"Point": (SO_POINT_CLASS, "FIXED"),
"LargePositiveInteger": (SO_LARGEPOSITIVEINTEGER_CLASS, "FIXED"),
"Message": (SO_MESSAGE_CLASS, "FIXED"),
"CompiledMethod": (SO_COMPILEDMETHOD_CLASS, "FIXED"),
"Semaphore": (SO_SEMAPHORE_CLASS, "FIXED"),
"Character": (SO_CHARACTER_CLASS, "FIXED"),
"ByteArray": (SO_BYTEARRAY_CLASS, "FIXED"),
"Process": (SO_PROCESS_CLASS, "FIXED"),
# "PseudoContext" : (SO_PSEUDOCONTEXT_CLASS, "FIXED"),
# "TranslatedMethod" : (SO_TRANSLATEDMETHOD_CLASS, "FIXED"),
"LargeNegativeInteger" : (SO_LARGENEGATIVEINTEGER_CLASS, "FIXED"),
# ours, not in the table, but we'd like it to
"ClassBinding": (SPECIAL_OBJECTS_SIZE + 30, "POINTERS"),
"Metaclass": (SPECIAL_OBJECTS_SIZE + 31, "POINTERS"),
"Processor": (SPECIAL_OBJECTS_SIZE + 32, "POINTERS"),
"ByteSymbol": (SPECIAL_OBJECTS_SIZE + 33, "POINTERS")
"ClassBinding": (SPECIAL_OBJECTS_SIZE + 30, "FIXED"),
"Metaclass": (SPECIAL_OBJECTS_SIZE + 31, "FIXED"),
"Processor": (SPECIAL_OBJECTS_SIZE + 32, "FIXED"),
"ByteSymbol": (SPECIAL_OBJECTS_SIZE + 33, "FIXED")
}

variables_in_special_object_table = {
Expand Down
2 changes: 1 addition & 1 deletion rsqueakvm/display.py
Expand Up @@ -726,7 +726,7 @@ def cursor_words_to_bytes(self, bytenum, words):
separate_module_sources=["""
int InterruptEventFilter(void* userdata, SDL_Event *event) {
int interrupt_key = 15 << 8;
if (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP) {
if (event->type == SDL_KEYUP) {
if (((SDL_KeyboardEvent*)event)->keysym.sym == SDLK_PERIOD) {
if ((((SDL_KeyboardEvent*)event)->keysym.mod & (KMOD_ALT|KMOD_GUI)) != 0) {
if (event->type == SDL_KEYUP) { // only keyup generates the interrupt
Expand Down
91 changes: 74 additions & 17 deletions rsqueakvm/interpreter.py
Expand Up @@ -126,9 +126,27 @@ def __init__(self, s_new_context, forced=False):
ContextSwitchException.__init__(self, s_new_context)
self.forced = forced

class Optargs(object):
_attrs_ = ["max_squeak_unroll_count", "squeak_unroll_trace_limit"]
_immutable_fields_ = ["max_squeak_unroll_count", "squeak_unroll_trace_limit"]
def __init__(self):
"""
- max_squeak_unroll_count: How many times to unroll a loop before
JIT'ing. The default (2) was chosen because it "felt right".
- squeak_unroll_trace_limit: After how many operations we should never
unroll. This tries to avoid trace_too_long aborts, and should kind of
be synchronized with the default trace_limit. Imagine you have a long
loop, and you unroll it twice, then we're at 86k ops with the default
of 32k ops. This is alreay quite a long trace, we don't want to blow
it up too much.
"""
self.max_squeak_unroll_count = 2
self.squeak_unroll_trace_limit = 32000


UNROLLING_BYTECODE_RANGES = unroll.unrolling_iterable(interpreter_bytecodes.BYTECODE_RANGES)

def get_printable_location(pc, self, method, w_class, blockmethod):
def get_printable_location(pc, jump_back_pc, unrollings, frame_size, self, method, w_class, blockmethod):
bc = ord(method.bytes[pc])
name = method.safe_identifier_string()
classname = "???"
Expand All @@ -143,8 +161,8 @@ def get_printable_location(pc, self, method, w_class, blockmethod):
blockname = blockmethod.safe_identifier_string()
return '%s(%s): (%s) [%d]: <%s>%s' % (classname, name, blockname, pc, hex(bc), interpreter_bytecodes.BYTECODE_NAMES[bc])

def resume_get_printable_location(pc, self, method, w_class):
return "resume: %s" % get_printable_location(pc, self, method, w_class, None)
def resume_get_printable_location(pc, frame_size, self, method, w_class):
return "resume: %s" % get_printable_location(pc, 0, 0, frame_size, self, method, w_class, None)

# def confirm_enter_jit(pc, self, method, w_class, s_context):
# print get_printable_location(pc, self, method, w_class)
Expand All @@ -161,11 +179,13 @@ class Interpreter(object):
"evented",
"interrupts",
"trace_important",
"trace"]
"trace",
"optargs"]

jit_driver = jit.JitDriver(
name=jit_driver_name,
greens=['pc', 'self', 'method', 'w_class', 'blockmethod'],
greens=['pc', 'jump_back_pc', 'unrollings', 'frame_size', 'self',
'method', 'w_class', 'blockmethod'],
reds=['s_context'],
virtualizables=['s_context'],
get_printable_location=get_printable_location,
Expand All @@ -174,15 +194,15 @@ class Interpreter(object):

resume_driver = jit.JitDriver(
name=jit_driver_name + "_resume",
greens=['pc', 'self', 'method', 'w_class'],
greens=['pc', 'frame_size', 'self', 'method', 'w_class'],
reds=['s_context'],
# virtualizables=['s_context'],
get_printable_location=resume_get_printable_location,
is_recursive=True
)

def __init__(self, space, image=None, trace_important=False,
trace=False, evented=True, interrupts=True):
trace=False, evented=True, interrupts=True, optargs=None):
# === Initialize immutable variables
self.space = space
self.image = image
Expand All @@ -199,6 +219,7 @@ def __init__(self, space, image=None, trace_important=False,
self.interrupt_counter_size = constants.INTERRUPT_COUNTER_SIZE
self.last_check = self.time_now()
self.trace = trace
self.optargs = optargs or Optargs()

# === Initialize mutable variables
self.interrupt_check_counter = self.interrupt_counter_size
Expand All @@ -217,9 +238,11 @@ def loop(self, w_active_context):
s_context = w_active_context.as_context_get_shadow(self.space)
while True:
method = s_context.w_method()
frame_size = method.frame_size()
pc = s_context.pc()
self.resume_driver.jit_merge_point(
pc=pc,
frame_size=frame_size,
self=self,
method=method,
w_class=self.getreceiverclass(s_context),
Expand All @@ -239,6 +262,7 @@ def loop(self, w_active_context):
self.resume_driver.can_enter_jit(
pc=pc,
self=self,
frame_size=frame_size,
method=method,
w_class=self.getreceiverclass(s_context),
s_context=s_context)
Expand Down Expand Up @@ -304,27 +328,60 @@ def getreceiverclass(self, s_context):
return s_context.w_receiver().safe_getclass(self.space)

def getblockmethod(self, s_context):
return s_context.blockmethod
return s_context.blockmethod()

def loop_bytecodes(self, s_context, may_context_switch=True):
old_pc = 0
jump_back_pc = 0
unrollings = 0
if not jit.we_are_jitted() and may_context_switch:
self.quick_check_for_interrupt(s_context)
method = s_context.w_method()
frame_size = method.frame_size()
while True:
pc = s_context.pc()
if pc < old_pc:
if jit.we_are_jitted():
# Do the interrupt-check at the end of a loop, don't interrupt loops midway.
self.jitted_check_for_interrupt(s_context)
self.jit_driver.can_enter_jit(
pc=pc, self=self, method=method,
w_class=self.getreceiverclass(s_context),
blockmethod=self.getblockmethod(s_context),
s_context=s_context)
if jump_back_pc == old_pc:
if (unrollings < self.optargs.max_squeak_unroll_count and
jit.current_trace_length() < self.optargs.squeak_unroll_trace_limit):
unrollings += 1
else:
if jit.we_are_jitted():
# Do the interrupt-check at the end of a loop, don't
# interrupt loops midway.
self.jitted_check_for_interrupt(s_context)
if not s_context.has_overflow_stack():
self.jit_driver.can_enter_jit(
pc=pc,
jump_back_pc=jump_back_pc,
unrollings=unrollings,
frame_size=frame_size,
self=self, method=method,
w_class=self.getreceiverclass(s_context),
blockmethod=self.getblockmethod(s_context),
s_context=s_context)
else:
jump_back_pc = old_pc
unrollings = 1
# we jumped back from the end of a loop. Instead of allowing
# to enter the JIT here, we instead wait for the second time
# this loop runs and call can_enter_jit only then
# (effectively unrolling at least two iterations). This is
# because the way the Squeak compiler generates loop
# bytecodes: we get the branch condition in the header and a
# conditional jump forward in case it is false. Then the
# loop body and an unconditional jump back. In the case of 1
# to: 1 do: or other loops that run for exactly one
# iteration, we will still generate a call_assembler in that
# case, which we work around with this. There are indeed a
# few examples of loops that run exactly one iteration
old_pc = pc
self.jit_driver.jit_merge_point(
pc=pc, self=self, method=method,
pc=pc,
jump_back_pc=jump_back_pc,
unrollings=unrollings,
frame_size=frame_size,
self=self, method=method,
w_class=self.getreceiverclass(s_context),
blockmethod=self.getblockmethod(s_context),
s_context=s_context)
Expand Down
2 changes: 1 addition & 1 deletion rsqueakvm/interpreter_bytecodes.py
Expand Up @@ -365,7 +365,7 @@ def _sendSelfSelectorSpecial(self, selector, numargs, interp):

@objectmodel.specialize.arg(3)
def _sendSpecialSelector(self, interp, receiver, special_selector, w_args=[]):
space = jit.promote(self.space)
space = self.space
w_special_selector = getattr(space, "w_" + special_selector)
s_class = receiver.class_shadow(space)

Expand Down

0 comments on commit f1e8608

Please sign in to comment.