Revision: 18769
Author:   [email protected]
Date:     Thu Jan 23 10:16:42 2014 UTC
Log:      Experimental parser: perform inlining in python

[email protected]

BUG=

Review URL: https://codereview.chromium.org/145583002
http://code.google.com/p/v8/source/detail?r=18769

Modified:
 /branches/experimental/parser/tools/lexer_generator/code_generator.jinja
 /branches/experimental/parser/tools/lexer_generator/code_generator.py

=======================================
--- /branches/experimental/parser/tools/lexer_generator/code_generator.jinja Wed Jan 22 14:19:09 2014 UTC +++ /branches/experimental/parser/tools/lexer_generator/code_generator.jinja Thu Jan 23 10:16:42 2014 UTC
@@ -196,11 +196,10 @@
 {%- endmacro -%}


-{%- macro write_label(label_name, node_number_chain) %}
-  {%- set node_number = node_number_chain|first -%}
+{%- macro write_label(label_name, node_number) %}
   {%- set state = dfa_states[node_number] -%}
   {%- set used = state['entry_points'][label_name] -%}
-  {%- set long_label = label_name + '_' + node_number_chain|join('_') -%}
+  {%- set long_label = label_name ~ '_' ~ node_number -%}
   {% if used -%}
     {{long_label}}:
   {%- else -%}
@@ -209,12 +208,11 @@
 {% endmacro -%}


-{%- macro do_dfa_state(node_number_chain) -%}
+{%- macro do_dfa_state(node_number) -%}

-  {%- set node_number = node_number_chain|first -%}
   {%- set state = dfa_states[node_number] -%}

-  {{ write_label('state_entry', node_number_chain) }}
+  {{ write_label('state_entry', node_number) }}

   {% if not state['can_elide_read'] -%}
     READ_CURSOR();
@@ -232,7 +230,7 @@
     {{ dispatch_entry_action(entry_action[0], entry_action[1]) }}
   {%- endif %}

-  {{ write_label('after_entry_code', node_number_chain) }}
+  {{ write_label('after_entry_code', node_number) }}

   {%- if debug_print %}
fprintf(stderr, "char at hand is %c (%d)\n", primary_char, primary_char);
@@ -240,10 +238,10 @@

   {%- macro do_transition(jump_id) -%}
     {%- set transition_state_id = jump_table[jump_id][0] -%}
- {%- set inline_transition = dfa_states[transition_state_id]['inline'] %}
+    {%- set inline_transition = jump_table[jump_id][1] == 'inline' %}
     FORWARD();
     {%- if inline_transition %}
-      {{ do_dfa_state([transition_state_id] + node_number_chain) }}
+      {{ do_dfa_state(transition_state_id) }}
     {% else %}
       {{ jump(jump_id) }}
     {% endif %}
@@ -344,7 +342,7 @@
 {# first node is start node #}
 {% for dfa_state in dfa_states -%}
   {%- if not dfa_state['inline'] %}
-    {{ do_dfa_state([dfa_state['node_number']]) }}
+    {{ do_dfa_state(dfa_state['node_number']) }}
   {%- endif -%}
 {%- endfor %}

=======================================
--- /branches/experimental/parser/tools/lexer_generator/code_generator.py Wed Jan 22 14:19:09 2014 UTC +++ /branches/experimental/parser/tools/lexer_generator/code_generator.py Thu Jan 23 10:16:42 2014 UTC
@@ -28,6 +28,7 @@
 import os
 import sys
 import jinja2
+from copy import deepcopy
 from dfa import Dfa
 from transition_keys import TransitionKey

@@ -100,6 +101,7 @@
       'can_elide_read' : len(transitions) == 0,
       'is_eos_handler' : False,
       'inline' : None,
+      'must_not_inline' : False,
       # transitions for code generator
       'if_transitions' : [],
       'switch_transitions' : [],
@@ -118,8 +120,9 @@
     }

   def __register_jump(self, node_id, label):
-    assert label in CodeGenerator.__jump_labels
-    state = self.__dfa_states[node_id]['entry_points'][label] = True
+    if label != 'inline':
+      assert label in CodeGenerator.__jump_labels
+      state = self.__dfa_states[node_id]['entry_points'][label] = True
     self.__jump_table.append((node_id, label))
     return len(self.__jump_table) - 1

@@ -127,7 +130,9 @@
     assert state['inline'] == None
     inline = False
     # inline terminal states
-    if not state['transitions']:
+    if state['must_not_inline']:
+      inline = False
+    elif not state['transitions']:
       inline = True
     # inline next to terminal states with 1 or 2 transitions
     elif state['distinct_keys'] < 3 and state['class_keys'] == 0:
@@ -290,6 +295,7 @@
       if action in mapped_actions:
         value = state['match_action'][1]
         target_id = goto_map[value[-1]]
+        states[target_id]['must_not_inline'] = True
         if action != 'goto_start':
           state['can_elide_read'] = False
           label = 'after_entry_code'
@@ -299,27 +305,61 @@
         jump_label = self.__register_jump(target_id, label)
state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label]))

-  def __rewrite_transitions_to_jumps(self):
+  def __inlined_state(self, target_id):
+    state = deepcopy(self.__dfa_states[target_id])
+    state['node_number'] = len(self.__dfa_states)
+    self.__dfa_states.append(state)
+    # mark inline as none, to be correctly handled below
+    state['inline'] = None
+    # clear transitions, they shouldn't be used anymore
+    state['transitions'] = []
+    # clear entry points
+ state['entry_points'] = {k : False for k in CodeGenerator.__jump_labels}
+    return state['node_number']
+
+ def __rewrite_transitions_to_jumps(self, start_id, count, inline_mapping_in):
+    # order here should match the order of code generation
     transition_names = [
-      'if_transitions',
       'switch_transitions',
-      'deferred_transitions',
-      'long_char_transitions']
-    def f((key, target_id)):
-      return (key, self.__register_jump(target_id, 'state_entry'))
-    for state in self.__dfa_states:
+      'if_transitions',
+      'long_char_transitions',
+      'deferred_transitions']
+    end_offset = start_id + count
+    assert len(self.__dfa_states) == end_offset
+    total_nodes_created = 0
+    for state_id in range(start_id, end_offset):
+      state = self.__dfa_states[state_id]
+      # this will be ignored during code generation,
+      # and it's needed as a template, so don't rewrite
+      if state['inline'] == True:
+        continue
+      # these is a new inline state, now mark as inline and rewrite
+      if state['inline'] == None:
+        state['inline'] = True
+      inline_mapping = inline_mapping_in.copy()
+      def generate_jump((key, target_id)):
+        jump_type = 'state_entry'
+        if self.__dfa_states[target_id]['inline']:
+          # generate at most one inline state for all transitions
+          if not target_id in inline_mapping:
+            inline_mapping[target_id] = self.__inlined_state(target_id)
+            jump_type = 'inline'
+          target_id = inline_mapping[target_id]
+        else:
+          assert not target_id in inline_mapping
+        return (key, self.__register_jump(target_id, jump_type))
       for name in transition_names:
-        state[name] = map(f, state[name])
-
-  def __mark_entry_points(self):
-    # mark the entry point in case there are implicit jumps to it
-    self.__dfa_states[0]['entry_points']['state_entry'] = True
-    # inlined states can write no labels
-    for state in self.__dfa_states:
-      entry_points = state['entry_points']
-      if state['inline']:
-        for k in entry_points.keys():
-          entry_points[k] = False
+        state[name] = map(generate_jump, state[name])
+      # now rewrite all nodes created
+      nodes_created = len(inline_mapping) - len(inline_mapping_in)
+      assert len(self.__dfa_states) == (
+        end_offset + total_nodes_created + nodes_created)
+      if nodes_created == 0:
+        continue
+      created = self.__rewrite_transitions_to_jumps(
+        end_offset + total_nodes_created, nodes_created, inline_mapping)
+      total_nodes_created += nodes_created + created
+    return total_nodes_created

   def process(self):

@@ -334,17 +374,17 @@
       self.__rewrite_deferred_transitions(state)
     # rewrite gotos
     self.__rewrite_gotos()
-    # rewrite transitions to use jumps
-    self.__rewrite_transitions_to_jumps()
     # set nodes to inline
     if self.__inline:
       inlined = reduce(self.__set_inline, dfa_states, 0)
       if self.__log:
         print "%s states inlined" % inlined
-    elif self.__log:
-      print "no inlining"
-    # mark all the entry points that will be used
-    self.__mark_entry_points()
+    # rewrite transitions to use jumps
+ inlined_nodes = self.__rewrite_transitions_to_jumps(0, len(dfa_states), {})
+    if self.__log:
+      print "%s inlined nodes created" % inlined_nodes
+    # mark the entry point in case there are implicit jumps to it
+    self.__dfa_states[0]['entry_points']['state_entry'] = True

     default_action = self.__default_action
     assert(default_action and default_action.match_action())

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to