Commit 12bc6093 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Improve the auto-insertion of SymbolDefinitionNode

The old implementation counted the number of "unique scope chains".
This patch counts the number of "unique direct child scopes" which
makes more sense to decide where a symbol definition should be
inserted.

Bug: 839389
Change-Id: I04eb2c2179fb8b95a97f1e85068dee9c4b4fa1d5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1955249Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#722481}
parent 5f4f67aa
...@@ -89,7 +89,7 @@ class CodeNode(object): ...@@ -89,7 +89,7 @@ class CodeNode(object):
# (Scope1, Scope2A, Scope3), # [1] # (Scope1, Scope2A, Scope3), # [1]
# (Scope1, Scope2B), # [4] # (Scope1, Scope2B), # [4]
# ]) # ])
self.undefined_code_symbols_scope_chains = {} self.symbol_to_scope_chains = {}
_gensym_seq_id = 0 _gensym_seq_id = 0
...@@ -336,6 +336,15 @@ class CodeNode(object): ...@@ -336,6 +336,15 @@ class CodeNode(object):
return self.outer.is_code_symbol_registered(symbol_node) return self.outer.is_code_symbol_registered(symbol_node)
return False return False
def on_code_symbol_referenced(self, symbol_node, symbol_scope_chain):
"""Receives a report of use of a symbol node."""
assert isinstance(symbol_node, SymbolNode)
assert isinstance(symbol_scope_chain, tuple)
assert all(
isinstance(scope, SymbolScopeNode) for scope in symbol_scope_chain)
self.current_render_state.symbol_to_scope_chains.setdefault(
symbol_node, set()).add(symbol_scope_chain)
def on_undefined_code_symbol_found(self, symbol_node, symbol_scope_chain): def on_undefined_code_symbol_found(self, symbol_node, symbol_scope_chain):
"""Receives a report of use of an undefined symbol node.""" """Receives a report of use of an undefined symbol node."""
assert isinstance(symbol_node, SymbolNode) assert isinstance(symbol_node, SymbolNode)
...@@ -345,8 +354,6 @@ class CodeNode(object): ...@@ -345,8 +354,6 @@ class CodeNode(object):
state = self.current_render_state state = self.current_render_state
if symbol_node not in state.undefined_code_symbols: if symbol_node not in state.undefined_code_symbols:
state.undefined_code_symbols.append(symbol_node) state.undefined_code_symbols.append(symbol_node)
state.undefined_code_symbols_scope_chains.setdefault(
symbol_node, set()).add(symbol_scope_chain)
class LiteralNode(CodeNode): class LiteralNode(CodeNode):
...@@ -571,32 +578,48 @@ class SymbolScopeNode(SequenceNode): ...@@ -571,32 +578,48 @@ class SymbolScopeNode(SequenceNode):
renderer=renderer, last_render_state=last_render_state) renderer=renderer, last_render_state=last_render_state)
def _insert_symbol_definition(self, symbol_node, last_render_state): def _insert_symbol_definition(self, symbol_node, last_render_state):
def count_by_likeliness(render_state): DIRECT_USES = "u"
counts = { DIRECT_CHILD_SCOPES = "s"
Likeliness.UNLIKELY: 0, ANALYSIS_RESULT_KEYS = (
Likeliness.LIKELY: 0, # Number of direct uses in this scope
Likeliness.ALWAYS: 0, DIRECT_USES,
} # Number of direct child scopes
DIRECT_CHILD_SCOPES,
scope_chains = (render_state.undefined_code_symbols_scope_chains. # Number of direct child scopes per likeliness
get(symbol_node)) Likeliness.ALWAYS,
Likeliness.LIKELY,
Likeliness.UNLIKELY,
)
def analyze_symbol_usage(render_state):
counts = dict.fromkeys(ANALYSIS_RESULT_KEYS, 0)
scope_chains = render_state.symbol_to_scope_chains.get(symbol_node)
if not scope_chains: if not scope_chains:
return counts return counts
self_index = iter(scope_chains).next().index(self) self_index = iter(scope_chains).next().index(self)
scope_chains = map( scope_chains = map(
lambda scope_chain: scope_chain[self_index + 1:], scope_chains) lambda scope_chain: scope_chain[self_index + 1:], scope_chains)
scope_to_likeliness = {}
for scope_chain in scope_chains: for scope_chain in scope_chains:
if not scope_chain: if not scope_chain:
counts[Likeliness.ALWAYS] += 1 counts[DIRECT_USES] += 1
else: else:
likeliness = min( likeliness = min(
map(lambda scope: scope.likeliness, scope_chain)) map(lambda scope: scope.likeliness, scope_chain))
counts[likeliness] += 1 scope = scope_chain[0]
scope_to_likeliness[scope] = max(
likeliness, scope_to_likeliness.get(scope, likeliness))
for likeliness in scope_to_likeliness.itervalues():
counts[DIRECT_CHILD_SCOPES] += 1
counts[likeliness] += 1
return counts return counts
def likeliness_at(render_state): def likeliness_at(render_state):
counts = count_by_likeliness(render_state) counts = analyze_symbol_usage(render_state)
if counts[DIRECT_USES] >= 1:
return Likeliness.ALWAYS
for likeliness in (Likeliness.ALWAYS, Likeliness.LIKELY, for likeliness in (Likeliness.ALWAYS, Likeliness.LIKELY,
Likeliness.UNLIKELY): Likeliness.UNLIKELY):
if counts[likeliness] > 0: if counts[likeliness] > 0:
...@@ -616,15 +639,17 @@ class SymbolScopeNode(SequenceNode): ...@@ -616,15 +639,17 @@ class SymbolScopeNode(SequenceNode):
return True return True
return False return False
counts = count_by_likeliness(last_render_state) counts = analyze_symbol_usage(last_render_state)
if counts[Likeliness.ALWAYS] >= 1: if counts[DIRECT_USES] >= 1:
did_insert = insert_before_threshold(self, Likeliness.UNLIKELY) did_insert = insert_before_threshold(self, Likeliness.UNLIKELY)
assert did_insert assert did_insert
elif counts[DIRECT_CHILD_SCOPES] == 1:
pass # Let the child SymbolScopeNode do the work.
elif counts[Likeliness.LIKELY] >= 2: elif counts[Likeliness.LIKELY] >= 2:
did_insert = insert_before_threshold(self, Likeliness.LIKELY) did_insert = insert_before_threshold(self, Likeliness.LIKELY)
assert did_insert assert did_insert
else: else:
pass # Do nothing and let descendant SymbolScopeNodes do the work. pass # Let descendant SymbolScopeNodes do the work.
def is_code_symbol_registered(self, symbol_node): def is_code_symbol_registered(self, symbol_node):
if symbol_node in self._registered_code_symbols: if symbol_node in self._registered_code_symbols:
...@@ -704,6 +729,9 @@ class SymbolNode(CodeNode): ...@@ -704,6 +729,9 @@ class SymbolNode(CodeNode):
filter(lambda node: isinstance(node, SymbolScopeNode), filter(lambda node: isinstance(node, SymbolScopeNode),
renderer.callers_from_first_to_last)) renderer.callers_from_first_to_last))
for caller in renderer.callers_from_last_to_first:
caller.on_code_symbol_referenced(self, symbol_scope_chain)
for caller in renderer.callers_from_last_to_first: for caller in renderer.callers_from_last_to_first:
if caller.is_code_symbol_defined(self): if caller.is_code_symbol_defined(self):
break break
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment