| 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 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 elif t == 'LATIN_1': | 123 elif t == 'LATIN_1': |
| 124 distinct_keys += r[1] - r[0] + 1 | 124 distinct_keys += r[1] - r[0] + 1 |
| 125 ranges += 1 | 125 ranges += 1 |
| 126 else: | 126 else: |
| 127 raise Exception() | 127 raise Exception() |
| 128 return { | 128 return { |
| 129 'node_number' : state.node_number(), | 129 'node_number' : state.node_number(), |
| 130 'original_node_number' : state.node_number(), | 130 'original_node_number' : state.node_number(), |
| 131 'transitions' : transitions, | 131 'transitions' : transitions, |
| 132 'switch_transitions' : [], | 132 'switch_transitions' : [], |
| 133 'deferred_transitions' : [], |
| 133 'disjoint_keys' : disjoint_keys, | 134 'disjoint_keys' : disjoint_keys, |
| 134 'inline' : None, | 135 'inline' : None, |
| 135 'depth' : None, | 136 'depth' : None, |
| 136 'action' : action, | 137 'action' : action, |
| 137 'entry_action' : entry_action, | 138 'entry_action' : entry_action, |
| 138 'match_action' : match_action, | 139 'match_action' : match_action, |
| 139 'class_keys' : class_keys, | 140 'class_keys' : class_keys, |
| 140 'distinct_keys' : distinct_keys, | 141 'distinct_keys' : distinct_keys, |
| 141 'ranges' : ranges | 142 'ranges' : ranges |
| 142 } | 143 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 160 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: | 161 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: |
| 161 inline = True | 162 inline = True |
| 162 # ensure state terminates in 1 step | 163 # ensure state terminates in 1 step |
| 163 for key, state_id in state['transitions']: | 164 for key, state_id in state['transitions']: |
| 164 if self.__dfa_states[state_id]['transitions']: | 165 if self.__dfa_states[state_id]['transitions']: |
| 165 inline = False | 166 inline = False |
| 166 break | 167 break |
| 167 state['inline'] = inline | 168 state['inline'] = inline |
| 168 return count + 1 if inline else count | 169 return count + 1 if inline else count |
| 169 | 170 |
| 170 @staticmethod | 171 def __split_transitions(self, split_count, state): |
| 171 def __split_transitions(split_count, state): | |
| 172 '''Goes through the transitions for 'state' and decides which of them should | 172 '''Goes through the transitions for 'state' and decides which of them should |
| 173 use the if statement and which should use the switch statement.''' | 173 use the if statement and which should use the switch statement.''' |
| 174 assert not state['switch_transitions'] | 174 assert not state['switch_transitions'] |
| 175 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges']) | 175 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges']) |
| 176 if distinct_keys <= 7 or float(distinct_keys)/float(ranges) >= 7.0: | 176 no_switch = distinct_keys <= 7 or float(distinct_keys)/float(ranges) >= 7.0 |
| 177 return split_count | 177 if_transitions = [] |
| 178 switch_transitions = [] | 178 switch_transitions = [] |
| 179 if_transitions = [] | 179 deferred_transitions = [] |
| 180 for (ranges, node_id) in state['transitions']: | 180 for (ranges, node_id) in state['transitions']: |
| 181 i = [] | 181 i = [] |
| 182 s = [] | 182 s = [] |
| 183 d = [] |
| 183 for r in ranges: | 184 for r in ranges: |
| 185 # all class checks will be deferred to after all other checks |
| 184 if r[0] == 'CLASS': | 186 if r[0] == 'CLASS': |
| 187 d.append(r) |
| 188 elif no_switch: |
| 185 i.append(r) | 189 i.append(r) |
| 186 else: | 190 else: |
| 187 s.append(r[1]) | 191 s.append(r[1]) |
| 188 if i: | 192 if i: |
| 189 if_transitions.append((i, node_id)) | 193 if_transitions.append((i, node_id)) |
| 190 if s: | 194 if s: |
| 191 switch_transitions.append((s, node_id)) | 195 switch_transitions.append((s, node_id)) |
| 196 if d: |
| 197 deferred_transitions.append((d, node_id)) |
| 192 state['transitions'] = if_transitions | 198 state['transitions'] = if_transitions |
| 193 state['switch_transitions'] = switch_transitions | 199 state['switch_transitions'] = switch_transitions |
| 194 return split_count + 1 | 200 state['deferred_transitions'] = deferred_transitions |
| 201 return split_count + (0 if no_switch else 1) |
| 195 | 202 |
| 196 def __canonicalize_traversal(self): | 203 def __canonicalize_traversal(self): |
| 197 dfa_states = [] | 204 dfa_states = [] |
| 198 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) | 205 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) |
| 199 dfa_states = map(CodeGenerator.__transform_state, dfa_states) | 206 dfa_states = map(CodeGenerator.__transform_state, dfa_states) |
| 200 id_map = {x['original_node_number'] : x for x in dfa_states} | 207 id_map = {x['original_node_number'] : x for x in dfa_states} |
| 201 CodeGenerator.__compute_depths(self.__start_node_number, 1, id_map) | 208 CodeGenerator.__compute_depths(self.__start_node_number, 1, id_map) |
| 202 dfa_states = sorted(dfa_states, cmp=self.__state_cmp) | 209 dfa_states = sorted(dfa_states, cmp=self.__state_cmp) |
| 203 # remap all node numbers | 210 # remap all node numbers |
| 204 for i, state in enumerate(dfa_states): | 211 for i, state in enumerate(dfa_states): |
| 205 state['node_number'] = i | 212 state['node_number'] = i |
| 206 def f((key, original_node_number)): | 213 def f((key, original_node_number)): |
| 207 return (key, id_map[original_node_number]['node_number']) | 214 return (key, id_map[original_node_number]['node_number']) |
| 208 for state in dfa_states: | 215 for state in dfa_states: |
| 209 state['transitions'] = map(f, state['transitions']) | 216 state['transitions'] = map(f, state['transitions']) |
| 210 assert id_map[self.__start_node_number]['node_number'] == 0 | 217 assert id_map[self.__start_node_number]['node_number'] == 0 |
| 211 assert len(dfa_states) == self.__dfa.node_count() | 218 assert len(dfa_states) == self.__dfa.node_count() |
| 212 # store states | 219 # store states |
| 213 self.__dfa_states = dfa_states | 220 self.__dfa_states = dfa_states |
| 214 # set nodes to inline | 221 # set nodes to inline |
| 215 if self.__inline: | 222 if self.__inline: |
| 216 inlined = reduce(self.__set_inline, dfa_states, 0) | 223 inlined = reduce(self.__set_inline, dfa_states, 0) |
| 217 if self.__log: | 224 if self.__log: |
| 218 print "%s states inlined" % inlined | 225 print "%s states inlined" % inlined |
| 219 elif self.__log: | 226 elif self.__log: |
| 220 print "no inlining" | 227 print "no inlining" |
| 221 # split transitions | 228 # split transitions |
| 222 if self.__switching: | 229 switched = reduce(self.__split_transitions, dfa_states, 0) |
| 223 switched = reduce(CodeGenerator.__split_transitions, dfa_states, 0) | 230 if self.__log: |
| 224 if self.__log: | 231 print "%s states use switch (instead of if)" % switched |
| 225 print "%s states use switch (instead of if)" % switched | |
| 226 elif self.__log: | |
| 227 print "no switching" | |
| 228 | 232 |
| 229 def process(self): | 233 def process(self): |
| 230 | 234 |
| 231 self.__canonicalize_traversal() | 235 self.__canonicalize_traversal() |
| 232 | 236 |
| 233 dfa_states = self.__dfa_states | 237 dfa_states = self.__dfa_states |
| 234 | 238 |
| 235 default_action = self.__default_action | 239 default_action = self.__default_action |
| 236 assert(default_action and default_action.match_action()) | 240 assert(default_action and default_action.match_action()) |
| 237 default_action = default_action.match_action() | 241 default_action = default_action.match_action() |
| (...skipping 10 matching lines...) Expand all Loading... |
| 248 char_type = 'uint16_t' | 252 char_type = 'uint16_t' |
| 249 else: | 253 else: |
| 250 raise Exception('Unsupported encoding %s' % encoding) | 254 raise Exception('Unsupported encoding %s' % encoding) |
| 251 return template.render( | 255 return template.render( |
| 252 start_node_number = 0, | 256 start_node_number = 0, |
| 253 debug_print = self.__debug_print, | 257 debug_print = self.__debug_print, |
| 254 default_action = default_action, | 258 default_action = default_action, |
| 255 dfa_states = dfa_states, | 259 dfa_states = dfa_states, |
| 256 encoding = self.__encoding, | 260 encoding = self.__encoding, |
| 257 char_type = char_type) | 261 char_type = char_type) |
| OLD | NEW |