Commit 79c6adce authored by bashi@chromium.org's avatar bashi@chromium.org

IDL: Avoid global variables in compute_interfaces_info_individual.py

compute_interfaces_info_individual has global variables. These variables
are updated each time we call compute_info_individual(). This could be
a problem when we want to call compute_info_individual() for separate
components in the same process. Such cases could happen in
run-bindings-test when we add union types collection in
compute_info_individual(). We would want to collect all union types
which are used by IDL files under Source/bindings/test/idls, but we
don't want to collect them for IDL files under Source/{core,modules}.
This CL introduces a class and moves global variables into the class
as instance variables.

This CL doesn't change generated bindings code at this moment.

BUG=425916

Review URL: https://codereview.chromium.org/671863002

git-svn-id: svn://svn.chromium.org/blink/trunk@184314 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 5ac77eb5
...@@ -53,13 +53,6 @@ from utilities import get_file_contents, read_file_to_list, idl_filename_to_inte ...@@ -53,13 +53,6 @@ from utilities import get_file_contents, read_file_to_list, idl_filename_to_inte
module_path = os.path.dirname(__file__) module_path = os.path.dirname(__file__)
source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir))
# Global variables (filled in and exported)
interfaces_info = {}
partial_interface_files = defaultdict(lambda: {
'full_paths': [],
'include_paths': [],
})
class IdlBadFilenameError(Exception): class IdlBadFilenameError(Exception):
"""Raised if an IDL filename disagrees with the interface name in the file.""" """Raised if an IDL filename disagrees with the interface name in the file."""
...@@ -111,13 +104,6 @@ def include_path(idl_filename, implemented_as=None): ...@@ -111,13 +104,6 @@ def include_path(idl_filename, implemented_as=None):
return posixpath.join(relative_dir, cpp_class_name + '.h') return posixpath.join(relative_dir, cpp_class_name + '.h')
def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_path=None):
paths_dict = partial_interface_files[partial_interface_name]
paths_dict['full_paths'].append(full_path)
if this_include_path:
paths_dict['include_paths'].append(this_include_path)
def get_implements_from_definitions(definitions, definition_name): def get_implements_from_definitions(definitions, definition_name):
left_interfaces = [] left_interfaces = []
right_interfaces = [] right_interfaces = []
...@@ -142,70 +128,90 @@ def get_put_forward_interfaces_from_definition(definition): ...@@ -142,70 +128,90 @@ def get_put_forward_interfaces_from_definition(definition):
if 'PutForwards' in attribute.extended_attributes)) if 'PutForwards' in attribute.extended_attributes))
def compute_info_individual(idl_filename, reader): class InterfaceInfoCollector(object):
definitions = reader.read_idl_file(idl_filename) """A class that collects interface information from idl files."""
if len(definitions.interfaces) > 0: def __init__(self, cache_directory=None):
definition = next(definitions.interfaces.itervalues()) self.reader = IdlReader(interfaces_info=None, outputdir=cache_directory)
interface_info = { self.interfaces_info = {}
'is_callback_interface': definition.is_callback, self.partial_interface_files = defaultdict(lambda: {
'is_dictionary': False, 'full_paths': [],
# Interfaces that are referenced (used as types) and that we introspect 'include_paths': [],
# during code generation (beyond interface-level data ([ImplementedAs], })
# is_callback_interface, ancestors, and inherited extended attributes):
# deep dependencies. def add_paths_to_partials_dict(self, partial_interface_name, full_path,
# These cause rebuilds of referrers, due to the dependency, so these this_include_path=None):
# should be minimized; currently only targets of [PutForwards]. paths_dict = self.partial_interface_files[partial_interface_name]
'referenced_interfaces': get_put_forward_interfaces_from_definition(definition), paths_dict['full_paths'].append(full_path)
} if this_include_path:
elif len(definitions.dictionaries) > 0: paths_dict['include_paths'].append(this_include_path)
definition = next(definitions.dictionaries.itervalues())
interface_info = { def collect_info(self, idl_filename):
'is_callback_interface': False, """Reads an idl file and collects information which is required by the
'is_dictionary': True, binding code generation."""
'referenced_interfaces': None, definitions = self.reader.read_idl_file(idl_filename)
if len(definitions.interfaces) > 0:
definition = next(definitions.interfaces.itervalues())
interface_info = {
'is_callback_interface': definition.is_callback,
'is_dictionary': False,
# Interfaces that are referenced (used as types) and that we
# introspect during code generation (beyond interface-level
# data ([ImplementedAs], is_callback_interface, ancestors, and
# inherited extended attributes): deep dependencies.
# These cause rebuilds of referrers, due to the dependency,
# so these should be minimized; currently only targets of
# [PutForwards].
'referenced_interfaces': get_put_forward_interfaces_from_definition(definition),
}
elif len(definitions.dictionaries) > 0:
definition = next(definitions.dictionaries.itervalues())
interface_info = {
'is_callback_interface': False,
'is_dictionary': True,
'referenced_interfaces': None,
}
else:
raise Exception('IDL file must contain one interface or dictionary')
extended_attributes = definition.extended_attributes
implemented_as = extended_attributes.get('ImplementedAs')
full_path = os.path.realpath(idl_filename)
this_include_path = None if 'NoImplHeader' in extended_attributes else include_path(idl_filename, implemented_as)
if definition.is_partial:
# We don't create interface_info for partial interfaces, but
# adds paths to another dict.
self.add_paths_to_partials_dict(definition.name, full_path, this_include_path)
return
# 'implements' statements can be included in either the file for the
# implement*ing* interface (lhs of 'implements') or implement*ed* interface
# (rhs of 'implements'). Store both for now, then merge to implement*ing*
# interface later.
left_interfaces, right_interfaces = get_implements_from_definitions(
definitions, definition.name)
interface_info.update({
'extended_attributes': extended_attributes,
'full_path': full_path,
'implemented_as': implemented_as,
'implemented_by_interfaces': left_interfaces,
'implements_interfaces': right_interfaces,
'include_path': this_include_path,
# FIXME: temporary private field, while removing old treatement of
# 'implements': http://crbug.com/360435
'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' in extended_attributes,
'parent': definition.parent,
'relative_dir': relative_dir_posix(idl_filename),
})
self.interfaces_info[definition.name] = interface_info
def get_info_as_dict(self):
"""Returns info packaged as a dict."""
return {
'interfaces_info': self.interfaces_info,
# Can't pickle defaultdict, convert to dict
'partial_interface_files': dict(self.partial_interface_files),
} }
else:
raise Exception('IDL file must contain one interface or dictionary')
extended_attributes = definition.extended_attributes
implemented_as = extended_attributes.get('ImplementedAs')
full_path = os.path.realpath(idl_filename)
this_include_path = None if 'NoImplHeader' in extended_attributes else include_path(idl_filename, implemented_as)
if definition.is_partial:
# We don't create interface_info for partial interfaces, but
# adds paths to another dict.
add_paths_to_partials_dict(definition.name, full_path, this_include_path)
return
# 'implements' statements can be included in either the file for the
# implement*ing* interface (lhs of 'implements') or implement*ed* interface
# (rhs of 'implements'). Store both for now, then merge to implement*ing*
# interface later.
left_interfaces, right_interfaces = get_implements_from_definitions(definitions, definition.name)
interface_info.update({
'extended_attributes': extended_attributes,
'full_path': full_path,
'implemented_as': implemented_as,
'implemented_by_interfaces': left_interfaces,
'implements_interfaces': right_interfaces,
'include_path': this_include_path,
# FIXME: temporary private field, while removing old treatement of
# 'implements': http://crbug.com/360435
'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' in extended_attributes,
'parent': definition.parent,
'relative_dir': relative_dir_posix(idl_filename),
})
interfaces_info[definition.name] = interface_info
def info_individual():
"""Returns info packaged as a dict."""
return {
'interfaces_info': interfaces_info,
# Can't pickle defaultdict, convert to dict
'partial_interface_files': dict(partial_interface_files),
}
################################################################################ ################################################################################
...@@ -224,12 +230,12 @@ def main(): ...@@ -224,12 +230,12 @@ def main():
# Compute information for individual files # Compute information for individual files
# Information is stored in global variables interfaces_info and # Information is stored in global variables interfaces_info and
# partial_interface_files. # partial_interface_files.
reader = IdlReader(interfaces_info=None, outputdir=options.cache_directory) info_collector = InterfaceInfoCollector(options.cache_directory)
for idl_filename in idl_files: for idl_filename in idl_files:
compute_info_individual(idl_filename, reader) info_collector.collect_info(idl_filename)
write_pickle_file(options.interfaces_info_file, write_pickle_file(options.interfaces_info_file,
info_individual(), info_collector.get_info_as_dict(),
options.write_file_only_if_changed) options.write_file_only_if_changed)
......
...@@ -41,7 +41,7 @@ source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir, ...@@ -41,7 +41,7 @@ source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir,
sys.path.append(source_path) # for Source/bindings imports sys.path.append(source_path) # for Source/bindings imports
import bindings.scripts.compute_interfaces_info_individual import bindings.scripts.compute_interfaces_info_individual
from bindings.scripts.compute_interfaces_info_individual import compute_info_individual, info_individual from bindings.scripts.compute_interfaces_info_individual import InterfaceInfoCollector
import bindings.scripts.compute_interfaces_info_overall import bindings.scripts.compute_interfaces_info_overall
from bindings.scripts.compute_interfaces_info_overall import compute_interfaces_info_overall, interfaces_info from bindings.scripts.compute_interfaces_info_overall import compute_interfaces_info_overall, interfaces_info
from bindings.scripts.idl_compiler import IdlCompilerDictionaryImpl, IdlCompilerV8 from bindings.scripts.idl_compiler import IdlCompilerDictionaryImpl, IdlCompilerV8
...@@ -106,6 +106,14 @@ def generate_interface_dependencies(output_directory): ...@@ -106,6 +106,14 @@ def generate_interface_dependencies(output_directory):
for filename in fnmatch.filter(files, '*.idl')) for filename in fnmatch.filter(files, '*.idl'))
return idl_paths return idl_paths
def collect_blink_idl_paths():
"""Returns IDL file paths which blink actually uses."""
idl_paths = []
for component in COMPONENT_DIRECTORY:
directory = os.path.join(source_path, component)
idl_paths.extend(idl_paths_recursive(directory))
return idl_paths
# We compute interfaces info for *all* IDL files, not just test IDL # We compute interfaces info for *all* IDL files, not just test IDL
# files, as code generator output depends on inheritance (both ancestor # files, as code generator output depends on inheritance (both ancestor
# chain and inherited extended attributes), and some real interfaces # chain and inherited extended attributes), and some real interfaces
...@@ -116,14 +124,8 @@ def generate_interface_dependencies(output_directory): ...@@ -116,14 +124,8 @@ def generate_interface_dependencies(output_directory):
# since this is also special-cased and Node inherits from EventTarget, # since this is also special-cased and Node inherits from EventTarget,
# but this inheritance information requires computing dependencies for # but this inheritance information requires computing dependencies for
# the real Node.idl file. # the real Node.idl file.
non_test_idl_paths = [] non_test_idl_paths = collect_blink_idl_paths()
test_idl_paths = [] test_idl_paths = idl_paths_recursive(test_input_directory)
test_idl_dir = test_input_directory + os.sep
for idl_path in idl_paths_recursive(source_path):
if idl_path.startswith(test_idl_dir):
test_idl_paths.append(idl_path)
else:
non_test_idl_paths.append(idl_path)
# 2-stage computation: individual, then overall # 2-stage computation: individual, then overall
# #
# Properly should compute separately by component (currently test # Properly should compute separately by component (currently test
...@@ -134,13 +136,14 @@ def generate_interface_dependencies(output_directory): ...@@ -134,13 +136,14 @@ def generate_interface_dependencies(output_directory):
# In order to allow test IDL files to override the production IDL files if # In order to allow test IDL files to override the production IDL files if
# they have the same interface name, process the test IDL files after the # they have the same interface name, process the test IDL files after the
# non-test IDL files. # non-test IDL files.
reader = IdlReader() info_individuals = []
info_collector = InterfaceInfoCollector()
for idl_path_list in (non_test_idl_paths, test_idl_paths): for idl_path_list in (non_test_idl_paths, test_idl_paths):
for idl_path in idl_path_list: for idl_path in idl_path_list:
if os.path.basename(idl_path) in NON_BLINK_IDL_FILES: if os.path.basename(idl_path) in NON_BLINK_IDL_FILES:
continue continue
compute_info_individual(idl_path, reader) info_collector.collect_info(idl_path)
info_individuals = [info_individual()] info_individuals.append(info_collector.get_info_as_dict())
# TestDictionary.{h,cpp} are placed under Source/bindings/tests/idls/core. # TestDictionary.{h,cpp} are placed under Source/bindings/tests/idls/core.
# However, IdlCompiler generates TestDictionary.{h,cpp} by using relative_dir. # However, IdlCompiler generates TestDictionary.{h,cpp} by using relative_dir.
# So the files will be generated under output_dir/core/bindings/tests/idls/core. # So the files will be generated under output_dir/core/bindings/tests/idls/core.
......
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