| OLD | NEW |
| 1 # Copyright 2013 the V8 project authors. All rights reserved. | 1 # Copyright 2013 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without | 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are | 3 # modification, are permitted provided that the following conditions are |
| 4 # met: | 4 # met: |
| 5 # | 5 # |
| 6 # * Redistributions of source code must retain the above copyright | 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above | 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following | 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided | 10 # disclaimer in the documentation and/or other materials provided |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 def cmp(left, right): | 68 def cmp(left, right): |
| 69 return TransitionKey.canonical_compare(left[0], right[0]) | 69 return TransitionKey.canonical_compare(left[0], right[0]) |
| 70 transitions = sorted(transitions, cmp) | 70 transitions = sorted(transitions, cmp) |
| 71 # map transition keys to disjoint ranges and collect stats | 71 # map transition keys to disjoint ranges and collect stats |
| 72 disjoint_keys = [] | 72 disjoint_keys = [] |
| 73 unique_transitions = {} | 73 unique_transitions = {} |
| 74 old_transitions = transitions | 74 old_transitions = transitions |
| 75 transitions = [] | 75 transitions = [] |
| 76 (class_keys, distinct_keys, ranges) = (0, 0, 0) | 76 (class_keys, distinct_keys, ranges) = (0, 0, 0) |
| 77 zero_transition = None | 77 zero_transition = None |
| 78 total_transitions = 0 |
| 78 for key, transition_id in old_transitions: | 79 for key, transition_id in old_transitions: |
| 79 keys = [] | 80 keys = [] |
| 80 for (t, r) in key.range_iter(encoding): | 81 for (t, r) in key.range_iter(encoding): |
| 81 if t == 'CLASS': | 82 if t == 'CLASS': |
| 82 class_keys += 1 | 83 class_keys += 1 |
| 83 keys.append((t, r)) | 84 keys.append((t, r)) |
| 84 elif t == 'PRIMARY_RANGE': | 85 elif t == 'PRIMARY_RANGE': |
| 85 distinct_keys += r[1] - r[0] + 1 | 86 distinct_keys += r[1] - r[0] + 1 |
| 86 ranges += 1 | 87 ranges += 1 |
| 87 # split 0 out of range, don't bother updating stats | 88 # split 0 out of range |
| 88 assert r[0] >= 0 | 89 assert r[0] >= 0 |
| 89 if r[0] == 0: | 90 if r[0] == 0: |
| 90 assert zero_transition == None | 91 assert zero_transition == None |
| 91 zero_transition = transition_id | 92 zero_transition = transition_id |
| 92 if r[0] == r[1]: | 93 if r[0] == r[1]: |
| 93 continue | 94 continue |
| 94 r = (r[0] + 1, r[1]) | 95 r = (r[0] + 1, r[1]) |
| 95 keys.append((t, r)) | 96 keys.append((t, r)) |
| 96 elif t == 'UNIQUE': | 97 elif t == 'UNIQUE': |
| 97 assert r == 'no_match' or r == 'eos' | 98 assert r == 'no_match' or r == 'eos' |
| 98 assert r not in unique_transitions | 99 assert r not in unique_transitions |
| 99 unique_transitions[r] = transition_id | 100 unique_transitions[r] = transition_id |
| 101 if r != 'no_match': |
| 102 total_transitions += 1 |
| 100 else: | 103 else: |
| 101 raise Exception() | 104 raise Exception() |
| 102 if keys: | 105 if keys: |
| 103 transitions.append((keys, transition_id)) | 106 transitions.append((keys, transition_id)) |
| 104 # delay zero transition until last | 107 # delay zero transition until last |
| 105 if zero_transition != None: | 108 if zero_transition != None: |
| 106 transitions.append(([('PRIMARY_RANGE', (0, 0))], transition_id)) | 109 transitions.append(([('PRIMARY_RANGE', (0, 0))], transition_id)) |
| 110 ranges += 1 |
| 111 total_transitions += len(transitions) |
| 107 return { | 112 return { |
| 108 'node_number' : None, | 113 'node_number' : None, |
| 109 'original_node_number' : state.node_number(), | 114 'original_node_number' : state.node_number(), |
| 110 'transitions' : transitions, | 115 'transitions' : transitions, |
| 111 # flags for code generator | 116 # flags for code generator |
| 112 'can_elide_read' : len(transitions) == 0, | 117 'can_elide_read' : total_transitions == 0, |
| 113 'is_eos_handler' : False, | 118 'is_eos_handler' : False, |
| 114 'inline' : False, | 119 'inline' : False, |
| 115 'must_not_inline' : False, | 120 'must_not_inline' : False, |
| 116 # transitions for code generator | 121 # transitions for code generator |
| 117 'if_transitions' : [], | 122 'if_transitions' : [], |
| 118 'switch_transitions' : [], | 123 'switch_transitions' : [], |
| 119 'deferred_transitions' : [], | 124 'deferred_transitions' : [], |
| 120 'unique_transitions' : unique_transitions, | 125 'unique_transitions' : unique_transitions, |
| 121 # state actions | 126 # state actions |
| 122 'entry_action' : entry_action, | 127 'entry_action' : entry_action, |
| 123 'match_action' : match_action, | 128 'match_action' : match_action, |
| 124 # statistics for states | 129 # statistics for state |
| 130 'total_transitions' : total_transitions, |
| 125 'class_keys' : class_keys, | 131 'class_keys' : class_keys, |
| 126 'distinct_keys' : distinct_keys, | 132 'distinct_keys' : distinct_keys, |
| 127 'ranges' : ranges, | 133 'ranges' : ranges, |
| 128 # record of which entry points will be needed | 134 # record of which entry points will be needed |
| 129 'entry_points' : {k : False for k in CodeGenerator.__jump_labels} | 135 'entry_points' : {k : False for k in CodeGenerator.__jump_labels} |
| 130 } | 136 } |
| 131 | 137 |
| 132 def __register_jump(self, node_id, label): | 138 def __register_jump(self, node_id, label): |
| 133 if label != 'inline': | 139 if label != 'inline': |
| 134 assert label in CodeGenerator.__jump_labels | 140 assert label in CodeGenerator.__jump_labels |
| 135 state = self.__dfa_states[node_id]['entry_points'][label] = True | 141 state = self.__dfa_states[node_id]['entry_points'][label] = True |
| 136 self.__jump_table.append((node_id, label)) | 142 self.__jump_table.append((node_id, label)) |
| 137 return len(self.__jump_table) - 1 | 143 return len(self.__jump_table) - 1 |
| 138 | 144 |
| 139 def __set_inline(self, count, state): | 145 def __set_inline(self, count, state): |
| 140 inline = False | 146 inline = False |
| 141 if state['must_not_inline']: | 147 if state['must_not_inline']: |
| 142 inline = False | 148 inline = False |
| 143 # inline terminal states | 149 # inline terminal states |
| 144 elif not state['transitions']: | 150 elif not state['total_transitions']: |
| 145 inline = True | 151 inline = True |
| 146 # inline next to terminal states with 1 or 2 transitions | 152 # inline next to terminal states with 1 or 2 transitions |
| 147 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: | 153 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: |
| 148 inline = True | 154 inline = True |
| 149 # ensure state terminates in 1 step | 155 # ensure state terminates in 1 step |
| 150 for key, state_id in state['transitions']: | 156 for key, state_id in state['transitions']: |
| 151 if self.__dfa_states[state_id]['transitions']: | 157 if self.__dfa_states[state_id]['total_transitions']: |
| 152 inline = False | 158 inline = False |
| 153 break | 159 break |
| 154 state['inline'] = inline | 160 state['inline'] = inline |
| 155 return count + 1 if inline else count | 161 return count + 1 if inline else count |
| 156 | 162 |
| 157 def __split_transitions(self, split_count, state): | 163 def __split_transitions(self, split_count, state): |
| 158 '''Goes through the transitions for 'state' and decides which of them should | 164 '''Goes through the transitions for 'state' and decides which of them should |
| 159 use the if statement and which should use the switch statement.''' | 165 use the if statement and which should use the switch statement.''' |
| 160 assert not state['switch_transitions'] | 166 assert not state['switch_transitions'] |
| 161 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges']) | 167 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges']) |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 CodeGenerator.__reorder(node_number, id_map, dfa_states) | 261 CodeGenerator.__reorder(node_number, id_map, dfa_states) |
| 256 | 262 |
| 257 @staticmethod | 263 @staticmethod |
| 258 def __mark_eos_states(dfa_states, eos_states): | 264 def __mark_eos_states(dfa_states, eos_states): |
| 259 for state_id in eos_states: | 265 for state_id in eos_states: |
| 260 state = dfa_states[state_id] | 266 state = dfa_states[state_id] |
| 261 state['is_eos_handler'] = True | 267 state['is_eos_handler'] = True |
| 262 state['must_not_inline'] = True | 268 state['must_not_inline'] = True |
| 263 assert state['match_action'] | 269 assert state['match_action'] |
| 264 assert not state['entry_action'] | 270 assert not state['entry_action'] |
| 265 assert not state['transitions'] | 271 assert not state['total_transitions'] |
| 266 assert not state['unique_transitions'] | |
| 267 | 272 |
| 268 def __build_dfa_states(self): | 273 def __build_dfa_states(self): |
| 269 dfa_states = [] | 274 dfa_states = [] |
| 270 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) | 275 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) |
| 271 encoding = self.__dfa.encoding() | 276 encoding = self.__dfa.encoding() |
| 272 f = lambda state : CodeGenerator.__transform_state(encoding, state) | 277 f = lambda state : CodeGenerator.__transform_state(encoding, state) |
| 273 dfa_states = map(f, dfa_states) | 278 dfa_states = map(f, dfa_states) |
| 274 id_map = {x['original_node_number'] : x for x in dfa_states} | 279 id_map = {x['original_node_number'] : x for x in dfa_states} |
| 275 dfa_states = [] | 280 dfa_states = [] |
| 276 CodeGenerator.__reorder(self.__start_node_number, id_map, dfa_states) | 281 CodeGenerator.__reorder(self.__start_node_number, id_map, dfa_states) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 else: | 321 else: |
| 317 states[target_id]['can_elide_read'] = False | 322 states[target_id]['can_elide_read'] = False |
| 318 label = 'state_entry' | 323 label = 'state_entry' |
| 319 jump_label = self.__register_jump(target_id, label) | 324 jump_label = self.__register_jump(target_id, label) |
| 320 state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label])) | 325 state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label])) |
| 321 | 326 |
| 322 def __inlined_state(self, target_id): | 327 def __inlined_state(self, target_id): |
| 323 state = deepcopy(self.__dfa_states[target_id]) | 328 state = deepcopy(self.__dfa_states[target_id]) |
| 324 state['node_number'] = len(self.__dfa_states) | 329 state['node_number'] = len(self.__dfa_states) |
| 325 self.__dfa_states.append(state) | 330 self.__dfa_states.append(state) |
| 326 # mark inline as none, to be correctly handled below | 331 # mark as just generated, so it will correctly rewritten |
| 327 state['inline'] = None | 332 state['just_generated_inline_state'] = True |
| 328 # clear entry points | 333 # clear entry points |
| 329 state['entry_points'] = {k : False for k in CodeGenerator.__jump_labels} | 334 state['entry_points'] = {k : False for k in CodeGenerator.__jump_labels} |
| 330 return state['node_number'] | 335 return state['node_number'] |
| 331 | 336 |
| 332 def __rewrite_transitions_to_jumps(self, start_id, count, inline_mapping_in): | 337 def __rewrite_transitions_to_jumps(self, start_id, count, inline_mapping_in): |
| 333 # order here should match the order of code generation | 338 # order here should match the order of code generation |
| 334 transition_names = [ | 339 transition_names = [ |
| 335 'switch_transitions', | 340 'switch_transitions', |
| 336 'if_transitions', | 341 'if_transitions', |
| 337 'deferred_transitions'] | 342 'deferred_transitions'] |
| 338 end_offset = start_id + count | 343 end_offset = start_id + count |
| 339 assert len(self.__dfa_states) == end_offset | 344 assert len(self.__dfa_states) == end_offset |
| 340 total_nodes_created = 0 | 345 total_nodes_created = 0 |
| 341 for state_id in range(start_id, end_offset): | 346 for state_id in range(start_id, end_offset): |
| 342 state = self.__dfa_states[state_id] | 347 state = self.__dfa_states[state_id] |
| 343 # this will be ignored during code generation, | 348 if state['inline']: |
| 344 # and it's needed as a template, so don't rewrite | 349 if not 'just_generated_inline_state' in state: |
| 345 if state['inline'] == True: | 350 # this will be ignored during code generation, |
| 346 continue | 351 # and it's needed as a template, so don't rewrite |
| 347 # these is a new inline state, now mark as inline and rewrite | 352 continue |
| 348 if state['inline'] == None: | 353 # these is a new inline state, rewrite |
| 349 state['inline'] = True | 354 del state['just_generated_inline_state'] |
| 355 assert not 'just_generated_inline_state' in state |
| 350 inline_mapping = inline_mapping_in.copy() | 356 inline_mapping = inline_mapping_in.copy() |
| 351 def generate_jump((key, target_id)): | 357 def generate_jump((key, target_id)): |
| 352 jump_type = 'state_entry' | 358 jump_type = 'state_entry' |
| 353 if self.__dfa_states[target_id]['inline']: | 359 if self.__dfa_states[target_id]['inline']: |
| 354 # generate at most one inline state for all transitions | 360 # generate at most one inline state for all transitions |
| 355 if not target_id in inline_mapping: | 361 if not target_id in inline_mapping: |
| 356 inline_mapping[target_id] = self.__inlined_state(target_id) | 362 inline_mapping[target_id] = self.__inlined_state(target_id) |
| 357 jump_type = 'inline' | 363 jump_type = 'inline' |
| 358 target_id = inline_mapping[target_id] | 364 target_id = inline_mapping[target_id] |
| 359 else: | 365 else: |
| 360 assert not target_id in inline_mapping | 366 assert not target_id in inline_mapping |
| 361 return (key, self.__register_jump(target_id, jump_type)) | 367 return (key, self.__register_jump(target_id, jump_type)) |
| 362 for name in transition_names: | 368 for name in transition_names: |
| 363 state[name] = map(generate_jump, state[name]) | 369 state[name] = map(generate_jump, state[name]) |
| 364 if 'eos' in state['unique_transitions']: | 370 if 'eos' in state['unique_transitions']: |
| 365 # eos state is not inlined | |
| 366 eos_state_id = state['unique_transitions']['eos'] | 371 eos_state_id = state['unique_transitions']['eos'] |
| 372 # eos state is not inlined, don't need to look in map |
| 373 assert not self.__dfa_states[eos_state_id]['inline'] |
| 367 jump = self.__register_jump(eos_state_id, 'state_entry') | 374 jump = self.__register_jump(eos_state_id, 'state_entry') |
| 368 state['unique_transitions']['eos'] = jump | 375 state['unique_transitions']['eos'] = jump |
| 369 # now rewrite all nodes created | 376 # now rewrite all nodes created |
| 370 nodes_created = len(inline_mapping) - len(inline_mapping_in) | 377 nodes_created = len(inline_mapping) - len(inline_mapping_in) |
| 371 assert len(self.__dfa_states) == ( | 378 assert len(self.__dfa_states) == ( |
| 372 end_offset + total_nodes_created + nodes_created) | 379 end_offset + total_nodes_created + nodes_created) |
| 373 if nodes_created == 0: | 380 if nodes_created == 0: |
| 374 continue | 381 continue |
| 375 created = self.__rewrite_transitions_to_jumps( | 382 created = self.__rewrite_transitions_to_jumps( |
| 376 end_offset + total_nodes_created, nodes_created, inline_mapping) | 383 end_offset + total_nodes_created, nodes_created, inline_mapping) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 | 425 |
| 419 return template.render( | 426 return template.render( |
| 420 start_node_number = 0, | 427 start_node_number = 0, |
| 421 debug_print = self.__debug_print, | 428 debug_print = self.__debug_print, |
| 422 default_action = default_action, | 429 default_action = default_action, |
| 423 dfa_states = dfa_states, | 430 dfa_states = dfa_states, |
| 424 jump_table = self.__jump_table, | 431 jump_table = self.__jump_table, |
| 425 encoding = encoding.name(), | 432 encoding = encoding.name(), |
| 426 char_type = char_type, | 433 char_type = char_type, |
| 427 upper_bound = encoding.primary_range()[1]) | 434 upper_bound = encoding.primary_range()[1]) |
| OLD | NEW |