Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inlining #to:do: #35

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/rtruffle/abstract_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ def _adapt_after_inlining(node, mgenc):
n.adapt_after_inlining(mgenc)
else:
current = getattr(node, child_slot)
current.adapt_after_inlining(mgenc)
if current is not None:
current.adapt_after_inlining(mgenc)
node.handle_inlining(mgenc)

cls.adapt_after_inlining = _adapt_after_inlining
Expand All @@ -83,7 +84,10 @@ def _adapt_after_outer_inlined(node, removed_ctx_level, mgenc_with_inlined):
)
else:
current = getattr(node, child_slot)
current.adapt_after_outer_inlined(removed_ctx_level, mgenc_with_inlined)
if current is not None:
current.adapt_after_outer_inlined(
removed_ctx_level, mgenc_with_inlined
)
node.handle_outer_inlined(removed_ctx_level, mgenc_with_inlined)

cls.adapt_after_outer_inlined = _adapt_after_outer_inlined
Expand Down
24 changes: 21 additions & 3 deletions src/som/compiler/ast/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
IfInlinedNode,
IfElseInlinedNode,
)
from som.interpreter.ast.nodes.specialized.literal_to_do import ToDoInlined
from som.interpreter.ast.nodes.specialized.literal_while import WhileInlinedNode
from som.vm.symbols import symbol_for

Expand Down Expand Up @@ -72,7 +73,7 @@ def _create_sequence_node(self, coordinate, expressions):
if not expressions:
from som.vm.globals import nilObject

return LiteralNode(nilObject)
return LiteralNode(nilObject, self._get_source_section(coordinate))
if len(expressions) == 1:
return expressions[0]

Expand Down Expand Up @@ -291,6 +292,18 @@ def _try_inlining_or(receiver, arg_expr, source, mgenc):
arg_body = arg_expr.get_method().inline(mgenc)
return OrInlinedNode(receiver, arg_body, source)

@staticmethod
def _try_inlining_to_do(receiver, arguments, source, mgenc):
if not isinstance(arguments[1], BlockNode):
return None

block_method = arguments[1].get_method()
do_expr = block_method.inline(mgenc)
idx_arg = block_method.get_argument(1, 0)
return ToDoInlined(
receiver, arguments[0], do_expr, mgenc.get_inlined_local(idx_arg, 0), source
)

def _keyword_message(self, mgenc, receiver):
is_super_send = self._super_send

Expand Down Expand Up @@ -358,6 +371,12 @@ def _keyword_message(self, mgenc, receiver):
)
if inlined is not None:
return inlined
elif keyword == "to:do:":
inlined = self._try_inlining_to_do(
receiver, arguments, source, mgenc
)
if inlined is not None:
return inlined

selector = symbol_for(keyword)

Expand Down Expand Up @@ -400,8 +419,7 @@ def _literal(self):
coord = self._lexer.get_source_coordinate()
val = self._get_object_for_current_literal()

lit = LiteralNode(val)
self._assign_source(lit, coord)
lit = LiteralNode(val, self._get_source_section(coord))
return lit

def _get_object_for_current_literal(self):
Expand Down
3 changes: 2 additions & 1 deletion src/som/compiler/ast/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ def get_initialized_read_node(self, context_level, source_section):
def copy_for_inlining(self, idx):
if self._name == "$blockSelf":
return None
return Argument(self._name, idx, self.source)
assert self._name != "self"
return Local(self._name, idx, self.source)

def __str__(self):
return "Argument(" + self._name + " idx: " + str(self.idx) + ")"
Expand Down
15 changes: 15 additions & 0 deletions src/som/compiler/bc/bytecode_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def emit_push_argument(mgenc, idx, ctx):
emit3(mgenc, BC.push_argument, idx, ctx, 1)


def emit_nil_local(mgenc, idx):
emit2(mgenc, BC.nil_local, idx, 0)


def emit_return_self(mgenc):
mgenc.optimize_dup_pop_pop_sequence()
emit1(mgenc, BC.return_self, 0)
Expand Down Expand Up @@ -57,6 +61,10 @@ def emit_dup(mgenc):
emit1(mgenc, BC.dup, 1)


def emit_dup_second(mgenc):
emit1(mgenc, BC.dup_second, 1)


def emit_push_block(mgenc, block_method, with_ctx):
idx = mgenc.add_literal_if_absent(block_method)
emit2(mgenc, BC.push_block if with_ctx else BC.push_block_no_ctx, idx, 1)
Expand Down Expand Up @@ -211,6 +219,13 @@ def emit_jump_with_dummy_offset(mgenc):
return idx


def emit_jump_if_greater_with_dummy_offset(mgenc):
emit1(mgenc, BC.jump_if_greater, 0)
idx = mgenc.add_bytecode_argument_and_get_index(0)
mgenc.add_bytecode_argument(0)
return idx


def emit_jump_backward_with_offset(mgenc, offset):
emit3(
mgenc,
Expand Down
8 changes: 7 additions & 1 deletion src/som/compiler/bc/disassembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ def dump_bytecode(m, b, indent=""):
+ ", context "
+ str(m.get_bytecode(b + 2))
)
elif bytecode == Bytecodes.push_frame or bytecode == Bytecodes.pop_frame:
elif (
bytecode == Bytecodes.push_frame
or bytecode == Bytecodes.pop_frame
or bytecode == Bytecodes.nil_inner
or bytecode == Bytecodes.nil_frame
or bytecode == Bytecodes.nil_local
):
error_println("idx: " + str(m.get_bytecode(b + 1)))
elif bytecode == Bytecodes.push_inner or bytecode == Bytecodes.pop_inner:
error_println(
Expand Down
74 changes: 65 additions & 9 deletions src/som/compiler/bc/method_generation_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
emit_pop,
emit_push_constant,
emit_jump_backward_with_offset,
emit_dup,
emit_inc,
emit_dup_second,
emit_jump_if_greater_with_dummy_offset,
emit_pop_local,
emit_nil_local,
emit_inc_field_push,
emit_return_field,
)
Expand Down Expand Up @@ -96,8 +102,8 @@ def add_local(self, local_name, source, parser):
self._local_list.append(local)
return local

def inline_locals(self, local_vars):
fresh_copies = MethodGenerationContextBase.inline_locals(self, local_vars)
def inline_as_locals(self, variables):
fresh_copies = MethodGenerationContextBase.inline_as_locals(self, variables)
if fresh_copies:
self._local_list.extend(fresh_copies)
return fresh_copies
Expand Down Expand Up @@ -476,16 +482,18 @@ def _assemble_literal_return(self, return_candidate, push_candidate):
):
return None

source_section = self.lexical_scope.arguments[0].source

if len(self._literals) == 1:
return LiteralReturn(self.signature, self._literals[0])
return LiteralReturn(self.signature, self._literals[0], source_section)
if self._bytecode[0] == Bytecodes.push_0:
return LiteralReturn(self.signature, int_0)
return LiteralReturn(self.signature, int_0, source_section)
if self._bytecode[0] == Bytecodes.push_1:
return LiteralReturn(self.signature, int_1)
return LiteralReturn(self.signature, int_1, source_section)
if self._bytecode[0] == Bytecodes.push_nil:
from som.vm.globals import nilObject

return LiteralReturn(self.signature, nilObject)
return LiteralReturn(self.signature, nilObject, source_section)
raise NotImplementedError(
"Not sure what's going on. Perhaps some new bytecode or unexpected literal?"
)
Expand All @@ -502,14 +510,16 @@ def _assemble_global_return(self, return_candidate, push_candidate):
global_name = self._literals[0]
assert isinstance(global_name, Symbol)

source_section = self.lexical_scope.arguments[0].source

if global_name is sym_true:
return LiteralReturn(self.signature, trueObject)
return LiteralReturn(self.signature, trueObject, source_section)
if global_name is sym_false:
return LiteralReturn(self.signature, falseObject)
return LiteralReturn(self.signature, falseObject, source_section)
if global_name is sym_nil:
from som.vm.globals import nilObject

return LiteralReturn(self.signature, nilObject)
return LiteralReturn(self.signature, nilObject, source_section)

return GlobalRead(
self.signature,
Expand Down Expand Up @@ -752,6 +762,52 @@ def inline_andor(self, parser, is_or):

return True

def inline_to_do(self, parser):
# HACK: We do assume that the receiver on the stack is a integer,
# HACK: similar to the other inlined messages.
# HACK: We don't support anything but integer at the moment.
push_block_candidate = self._last_bytecode_is_one_of(0, PUSH_BLOCK_BYTECODES)
if push_block_candidate == Bytecodes.invalid:
return False

assert bytecode_length(push_block_candidate) == 2
block_literal_idx = self._bytecode[-1]

to_be_inlined = self._literals[block_literal_idx]
to_be_inlined.merge_scope_into(self)

block_arg = to_be_inlined.get_argument(1, 0)
i_var_idx = self.get_inlined_local_idx(block_arg, 0)

self._remove_last_bytecodes(1) # remove push_block*

self._is_currently_inlining_a_block = True
emit_dup_second(self)

emit_nil_local(self, i_var_idx)

loop_begin_idx = self.offset_of_next_instruction()
jump_offset_idx_to_end = emit_jump_if_greater_with_dummy_offset(self)

emit_dup(self)

emit_pop_local(self, i_var_idx, 0)

to_be_inlined.inline(self, False)

emit_pop(self)
emit_inc(self)

emit_nil_local(self, i_var_idx)
self.emit_backwards_jump_offset_to_target(loop_begin_idx, parser)

self.patch_jump_offset_to_point_to_next_instruction(
jump_offset_idx_to_end, parser
)

self._is_currently_inlining_a_block = False
return True

def _complete_jumps_and_emit_returning_nil(
self, parser, loop_begin_idx, jump_offset_idx_to_skip_loop_body
):
Expand Down
1 change: 1 addition & 0 deletions src/som/compiler/bc/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def _keyword_message(self, mgenc):
keyword == "ifFalse:ifTrue:"
and mgenc.inline_if_true_false(self, False)
)
or (keyword == "to:do:" and mgenc.inline_to_do(self))
):
return

Expand Down
15 changes: 9 additions & 6 deletions src/som/compiler/method_generation_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ def add_local(self, local_name, source, parser):
self._locals[local_name] = result
return result

def inline_locals(self, local_vars):
def inline_as_locals(self, variables):
fresh_copies = []
for local in local_vars:
fresh_copy = local.copy_for_inlining(len(self._locals))
for var in variables:
fresh_copy = var.copy_for_inlining(len(self._locals))
if fresh_copy:
# fresh_copy can be None, because we don't need the $blockSelf
name = local.get_qualified_name()
name = var.get_qualified_name()
assert name not in self._locals
self._locals[name] = fresh_copy
fresh_copies.append(fresh_copy)
Expand Down Expand Up @@ -212,10 +212,13 @@ def set_block_signature(self, line, column):
self.signature = symbol_for(block_sig)

def merge_into_scope(self, scope_to_be_inlined):
assert len(scope_to_be_inlined.arguments) == 1
arg_vars = scope_to_be_inlined.arguments
if len(arg_vars) > 1:
self.inline_as_locals(arg_vars)

local_vars = scope_to_be_inlined.locals
if local_vars:
self.inline_locals(local_vars)
self.inline_as_locals(local_vars)


def _strip_colons_and_source_location(method_name):
Expand Down
4 changes: 2 additions & 2 deletions src/som/interpreter/ast/nodes/literal_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class LiteralNode(ExpressionNode):
_immutable_fields_ = ["_value"]

def __init__(self, value, source_section=None):
def __init__(self, value, source_section):
ExpressionNode.__init__(self, source_section)
self._value = value

Expand All @@ -14,4 +14,4 @@ def execute(self, _frame):
def create_trivial_method(self, signature):
from som.vmobjects.method_trivial import LiteralReturn

return LiteralReturn(signature, self._value)
return LiteralReturn(signature, self._value, self.source_section)
Loading