def compute_global_type_info(): ancestors = {} dictionaries = {} component_dirs = {} implemented_as_interfaces = {} will_be_garbage_collected_interfaces = set() garbage_collected_interfaces = set() callback_interfaces = set() for interface_name, interface_info in interfaces_info.iteritems(): component_dirs[interface_name] = idl_filename_to_component(interface_info['full_path']) if interface_info['ancestors']: ancestors[interface_name] = interface_info['ancestors'] if interface_info['is_callback_interface']: callback_interfaces.add(interface_name) if interface_info['is_dictionary']: dictionaries[interface_name] = interface_info['is_dictionary'] if interface_info['implemented_as']: implemented_as_interfaces[interface_name] = interface_info['implemented_as'] inherited_extended_attributes = interface_info['inherited_extended_attributes'] if 'WillBeGarbageCollected' in inherited_extended_attributes: will_be_garbage_collected_interfaces.add(interface_name) if 'GarbageCollected' in inherited_extended_attributes: garbage_collected_interfaces.add(interface_name) interfaces_info['ancestors'] = ancestors interfaces_info['callback_interfaces'] = callback_interfaces interfaces_info['dictionaries'] = dictionaries interfaces_info['implemented_as_interfaces'] = implemented_as_interfaces interfaces_info['garbage_collected_interfaces'] = garbage_collected_interfaces interfaces_info['will_be_garbage_collected_interfaces'] = will_be_garbage_collected_interfaces interfaces_info['component_dirs'] = component_dirs
def main(args): if len(args) <= 4: raise Exception('Expected at least 5 arguments.') component_dir = args[1] input_file_name = args[2] in_out_break_index = args.index('--') output_file_names = args[in_out_break_index + 1:] idl_file_names = read_idl_files_list_from_file(input_file_name, is_gyp_format=True) components = set( [idl_filename_to_component(filename) for filename in idl_file_names]) if len(components) != 1: raise Exception( 'Cannot aggregate generated codes in different components') aggregate_partial_interfaces = component_dir not in components files_meta_data = extract_meta_data(idl_file_names) total_partitions = len(output_file_names) for partition, file_name in enumerate(output_file_names): files_meta_data_this_partition = [ meta_data for meta_data in files_meta_data if hash(meta_data['name']) % total_partitions == partition ] file_contents = generate_content(component_dir, aggregate_partial_interfaces, files_meta_data_this_partition) write_content(file_contents, file_name)
def main(args): if len(args) <= 4: raise Exception('Expected at least 5 arguments.') component_dir = args[1] input_file_name = args[2] in_out_break_index = args.index('--') output_file_names = args[in_out_break_index + 1:] idl_file_names = read_idl_files_list_from_file(input_file_name) components = set([idl_filename_to_component(filename) for filename in idl_file_names]) if len(components) != 1: raise Exception('Cannot aggregate generated codes in different components') aggregate_partial_interfaces = component_dir not in components files_meta_data = extract_meta_data(idl_file_names) total_partitions = len(output_file_names) for partition, file_name in enumerate(output_file_names): files_meta_data_this_partition = [ meta_data for meta_data in files_meta_data if hash(meta_data['name']) % total_partitions == partition] file_contents = generate_content(component_dir, aggregate_partial_interfaces, files_meta_data_this_partition) write_content(file_contents, file_name)
def generate_interface_code(self, definitions, interface_name, interface): interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get('full_path') component = idl_filename_to_component(full_path) include_paths = interface_info.get('dependencies_include_paths') # Select appropriate Jinja template and contents function if interface.is_callback: header_template_filename = 'callback_interface.h.tmpl' cpp_template_filename = 'callback_interface.cc.tmpl' interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = 'partial_interface.h.tmpl' cpp_template_filename = 'partial_interface.cc.tmpl' interface_name += 'Partial' assert component == 'core' component = 'modules' include_paths = interface_info.get( 'dependencies_other_component_include_paths') else: header_template_filename = 'interface.h.tmpl' cpp_template_filename = 'interface.cc.tmpl' interface_context = v8_interface.interface_context template_context = interface_context(interface, definitions.interfaces) includes.update( interface_info.get('cpp_includes', {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): template_context['header_includes'].add( self.info_provider.include_path_for_export) template_context[ 'exported'] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context['header_includes'].add( 'core/typed_arrays/dom_typed_array.h') elif interface.is_callback: pass else: template_context['header_includes'].add( interface_info['include_path']) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) header_path, cpp_path = self.output_paths(interface_name) this_include_header_path = self.normalize_this_header_path(header_path) template_context['this_include_header_path'] = this_include_header_path template_context['header_guard'] = to_header_guard( this_include_header_path) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = self.render_templates(include_paths, header_template, cpp_template, template_context, component) return ( (header_path, header_text), (cpp_path, cpp_text), )
def render_template(self, include_paths, header_template, cpp_template, template_context, component=None): template_context['code_generator'] = self.generator_name # Add includes for any dependencies template_context['header_includes'] = normalize_and_sort_includes( template_context['header_includes'], self.snake_case_generated_files) for include_path in include_paths: if component: dependency = idl_filename_to_component(include_path) assert is_valid_component_dependency(component, dependency) includes.add(include_path) template_context['cpp_includes'] = normalize_and_sort_includes( includes, self.snake_case_generated_files) header_text = render_template(header_template, template_context) cpp_text = render_template(cpp_template, template_context) return header_text, cpp_text
def collect_unforgeable_attributes(definition, idl_filename): """Collects [Unforgeable] attributes so that we can define them on sub-interfaces later. The resulting structure is as follows. interfaces_info[interface_name] = { 'unforgeable_attributes': { 'core': [IdlAttribute, ...], 'modules': [IdlAttribute, ...], }, ... } """ interface_info = {} unforgeable_attributes = get_unforgeable_attributes_from_definition( definition) if not unforgeable_attributes: return interface_info if definition.is_partial: interface_basename = idl_filename_to_interface_name( idl_filename) # TODO(yukishiino): [PartialInterfaceImplementedAs] is treated # in interface_dependency_resolver.transfer_extended_attributes. # Come up with a better way to keep them consistent. for attr in unforgeable_attributes: attr.extended_attributes[ 'PartialInterfaceImplementedAs'] = definition.extended_attributes.get( 'ImplementedAs', interface_basename) component = idl_filename_to_component(idl_filename) interface_info['unforgeable_attributes'] = {} interface_info['unforgeable_attributes'][ component] = unforgeable_attributes return interface_info
def render_templates(self, include_paths, header_template, cpp_template, context, component=None): context['code_generator'] = self.generator_name # Add includes for any dependencies for include_path in include_paths: if component: dependency = idl_filename_to_component(include_path) assert is_valid_component_dependency(component, dependency) includes.add(include_path) context['header_forward_decls'] = sorted( context.get('header_forward_decls', set())) cpp_includes = set(context.get('cpp_includes', [])) context['cpp_includes'] = normalize_and_sort_includes(cpp_includes | includes) context['header_includes'] = normalize_and_sort_includes( context['header_includes']) header_text = render_template(header_template, context) cpp_text = render_template(cpp_template, context) return header_text, cpp_text
def compute_global_type_info(): ancestors = {} dictionaries = {} component_dirs = {} implemented_as_interfaces = {} garbage_collected_interfaces = set() callback_interfaces = set() for interface_name, interface_info in interfaces_info.iteritems(): component_dirs[interface_name] = idl_filename_to_component(interface_info["full_path"]) if interface_info["ancestors"]: ancestors[interface_name] = interface_info["ancestors"] if interface_info["is_callback_interface"]: callback_interfaces.add(interface_name) if interface_info["is_dictionary"]: dictionaries[interface_name] = interface_info["is_dictionary"] if interface_info["implemented_as"]: implemented_as_interfaces[interface_name] = interface_info["implemented_as"] inherited_extended_attributes = interface_info["inherited_extended_attributes"] garbage_collected_interfaces.add(interface_name) interfaces_info["ancestors"] = ancestors interfaces_info["callback_interfaces"] = callback_interfaces interfaces_info["dictionaries"] = dictionaries interfaces_info["implemented_as_interfaces"] = implemented_as_interfaces interfaces_info["garbage_collected_interfaces"] = garbage_collected_interfaces interfaces_info["component_dirs"] = component_dirs
def compute_global_type_info(): ancestors = {} dictionaries = {} component_dirs = {} implemented_as_interfaces = {} garbage_collected_interfaces = set() callback_interfaces = set() for interface_name, interface_info in interfaces_info.iteritems(): component_dirs[interface_name] = idl_filename_to_component(interface_info['full_path']) if interface_info['ancestors']: ancestors[interface_name] = interface_info['ancestors'] if interface_info['is_callback_interface']: callback_interfaces.add(interface_name) if interface_info['is_dictionary']: dictionaries[interface_name] = interface_info['is_dictionary'] if interface_info['implemented_as']: implemented_as_interfaces[interface_name] = interface_info['implemented_as'] inherited_extended_attributes = interface_info['inherited_extended_attributes'] garbage_collected_interfaces.add(interface_name) # Record a list of all interface names interfaces_info['all_interfaces'] = set( interface_name for interface_name, info in interfaces_info.iteritems() if not info['is_dependency']) interfaces_info['ancestors'] = ancestors interfaces_info['callback_interfaces'] = callback_interfaces interfaces_info['dictionaries'] = dictionaries interfaces_info['implemented_as_interfaces'] = implemented_as_interfaces interfaces_info['garbage_collected_interfaces'] = garbage_collected_interfaces interfaces_info['component_dirs'] = component_dirs
def collect_unforgeable_attributes(definition, idl_filename): """Collects [Unforgeable] attributes so that we can define them on sub-interfaces later. The resulting structure is as follows. interfaces_info[interface_name] = { 'unforgeable_attributes': { 'core': [IdlAttribute, ...], 'modules': [IdlAttribute, ...], }, ... } """ interface_info = {} unforgeable_attributes = get_unforgeable_attributes_from_definition(definition) if not unforgeable_attributes: return interface_info if definition.is_partial: interface_basename = idl_filename_to_interface_name(idl_filename) # TODO(yukishiino): [PartialInterfaceImplementedAs] is treated # in interface_dependency_resolver.transfer_extended_attributes. # Come up with a better way to keep them consistent. for attr in unforgeable_attributes: attr.extended_attributes['PartialInterfaceImplementedAs'] = definition.extended_attributes.get('ImplementedAs', interface_basename) component = idl_filename_to_component(idl_filename) interface_info['unforgeable_attributes'] = {} interface_info['unforgeable_attributes'][component] = unforgeable_attributes return interface_info
def compile_and_write(self, idl_filename): interface_name = idl_filename_to_interface_name(idl_filename) component = idl_filename_to_component(idl_filename) definitions = self.reader.read_idl_definitions(idl_filename) output_code_list = self.code_generator.generate_code( definitions[component], interface_name) for output_path, output_code in output_code_list: write_file(output_code, output_path, self.only_if_changed)
def generate_interface_code(self, definitions, interface_name, interface): interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get('full_path') component = idl_filename_to_component(full_path) include_paths = interface_info.get('dependencies_include_paths') # Select appropriate Jinja template and contents function # # A callback interface with constants needs a special handling. # https://heycam.github.io/webidl/#legacy-callback-interface-object if interface.is_callback and len(interface.constants) > 0: header_template_filename = 'legacy_callback_interface.h.tmpl' cpp_template_filename = 'legacy_callback_interface.cpp.tmpl' interface_context = v8_callback_interface.legacy_callback_interface_context elif interface.is_callback: header_template_filename = 'callback_interface.h.tmpl' cpp_template_filename = 'callback_interface.cpp.tmpl' interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = 'partial_interface.h.tmpl' cpp_template_filename = 'partial_interface.cpp.tmpl' interface_name += 'Partial' assert component == 'core' component = 'modules' include_paths = interface_info.get('dependencies_other_component_include_paths') else: header_template_filename = 'interface.h.tmpl' cpp_template_filename = 'interface.cpp.tmpl' interface_context = v8_interface.interface_context template_context = interface_context(interface, definitions.interfaces) includes.update(interface_info.get('cpp_includes', {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): template_context['header_includes'].add(self.info_provider.include_path_for_export) template_context['exported'] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context['header_includes'].add('core/typed_arrays/dom_typed_array.h') elif interface.is_callback: if len(interface.constants) > 0: # legacy callback interface includes.add(interface_info['include_path']) else: template_context['header_includes'].add(interface_info['include_path']) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) header_path, cpp_path = self.output_paths(interface_name) template_context['this_include_header_name'] = posixpath.basename(header_path) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = self.render_template( include_paths, header_template, cpp_template, template_context, component) return ( (header_path, header_text), (cpp_path, cpp_text), )
def generate_interface_code(self, definitions, interface_name, interface): interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get('full_path') component = idl_filename_to_component(full_path) include_paths = interface_info.get('dependencies_include_paths') # Select appropriate Jinja template and contents function # # A callback interface with constants needs a special handling. # https://heycam.github.io/webidl/#legacy-callback-interface-object if interface.is_callback and len(interface.constants) > 0: header_template_filename = 'legacy_callback_interface.h.tmpl' cpp_template_filename = 'legacy_callback_interface.cpp.tmpl' interface_context = v8_callback_interface.legacy_callback_interface_context elif interface.is_callback: header_template_filename = 'callback_interface.h.tmpl' cpp_template_filename = 'callback_interface.cpp.tmpl' interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = 'partial_interface.h.tmpl' cpp_template_filename = 'partial_interface.cpp.tmpl' interface_name += 'Partial' assert component == 'core' component = 'modules' include_paths = interface_info.get('dependencies_other_component_include_paths') else: header_template_filename = 'interface.h.tmpl' cpp_template_filename = 'interface.cpp.tmpl' interface_context = v8_interface.interface_context template_context = interface_context(interface, definitions.interfaces) includes.update(interface_info.get('cpp_includes', {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): template_context['header_includes'].add(self.info_provider.include_path_for_export) template_context['exported'] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context['header_includes'].add('core/typed_arrays/DOMTypedArray.h') else: template_context['header_includes'].add(interface_info['include_path']) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = self.render_template( include_paths, header_template, cpp_template, template_context, component) header_path, cpp_path = self.output_paths(interface_name) return ( (header_path, header_text), (cpp_path, cpp_text), )
def conditional_features_info(info_provider, reader, idl_filenames, target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. Returns a tuple (features_for_type, types_for_feature, includes): - features_for_type is a mapping of interface->feature - types_for_feature is the reverse mapping: feature->interface - includes is a set of header files which need to be included in the generated implementation code. """ features_for_type = defaultdict(set) types_for_feature = defaultdict(set) includes = set() for idl_filename in idl_filenames: interface = read_idl_file(reader, idl_filename) feature_names = get_conditional_feature_names_from_interface(interface) if feature_names: is_global = interface_is_global(interface) if interface.is_partial: # For partial interfaces, we need to generate different # includes if the parent interface is in a different # component. parent_interface_info = info_provider.interfaces_info[ interface.name] parent_interface = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: includes.add('bindings/%s/v8/V8%s.h' % (parent_component, interface.name)) includes.add('bindings/%s/v8/V8%sPartial.h' % (target_component, interface.name)) else: includes.add('bindings/%s/v8/V8%s.h' % (target_component, interface.name)) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False interface_info = ConditionalInterfaceInfo( interface.name, v8_class_name(interface), v8_class_name_or_partial(interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) return features_for_type, types_for_feature, includes
def read_idl_definitions(self, idl_filename): """Returns a dictionary whose key is component and value is an IdlDefinitions object for an IDL file, including all dependencies.""" definitions = self.read_idl_file(idl_filename) component = idl_filename_to_component(idl_filename) if not self.interface_dependency_resolver: return {component: definitions} # This definitions should have a dictionary. No need to resolve any # dependencies. if not definitions.interfaces: return {component: definitions} return self.interface_dependency_resolver.resolve_dependencies(definitions, component)
def generate_interface_code(self, definitions, interface_name, interface): # Store other interfaces for introspection interfaces.update(definitions.interfaces) interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get('full_path') component = idl_filename_to_component(full_path) include_paths = interface_info.get('dependencies_include_paths') # Select appropriate Jinja template and contents function if interface.is_callback: header_template_filename = 'callback_interface.h' cpp_template_filename = 'callback_interface.cpp' interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = 'partial_interface.h' cpp_template_filename = 'partial_interface.cpp' interface_name += 'Partial' assert component == 'core' component = 'modules' include_paths = interface_info.get( 'dependencies_other_component_include_paths') else: header_template_filename = 'interface.h' cpp_template_filename = 'interface.cpp' interface_context = v8_interface.interface_context header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) template_context = interface_context(interface) if not interface.is_partial and not is_testing_target(full_path): template_context['header_includes'].add( self.info_provider.include_path_for_export) template_context[ 'exported'] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context['header_includes'].add('core/dom/DOMTypedArray.h') elif interface_info['include_path']: template_context['header_includes'].add( interface_info['include_path']) header_text, cpp_text = render_template(include_paths, header_template, cpp_template, template_context, component) header_path, cpp_path = self.output_paths(interface_name) return ( (header_path, header_text), (cpp_path, cpp_text), )
def generate_interface_code(self, definitions, interface_name, interface): # Store other interfaces for introspection interfaces.update(definitions.interfaces) interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get('full_path') component = idl_filename_to_component(full_path) include_paths = interface_info.get('dependencies_include_paths') # Select appropriate Jinja template and contents function if interface.is_callback: header_template_filename = 'callback_interface.h' cpp_template_filename = 'callback_interface.cpp' interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = 'partial_interface.h' cpp_template_filename = 'partial_interface.cpp' interface_name += 'Partial' assert component == 'core' component = 'modules' include_paths = interface_info.get('dependencies_other_component_include_paths') else: header_template_filename = 'interface.h' cpp_template_filename = 'interface.cpp' interface_context = v8_interface.interface_context template_context = interface_context(interface) includes.update(interface_info.get('cpp_includes', {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): template_context['header_includes'].add(self.info_provider.include_path_for_export) template_context['exported'] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context['header_includes'].add('core/dom/DOMTypedArray.h') elif interface_info['include_path']: template_context['header_includes'].add(interface_info['include_path']) template_context['header_includes'].update( interface_info.get('additional_header_includes', [])) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = render_template( include_paths, header_template, cpp_template, template_context, component) header_path, cpp_path = self.output_paths(interface_name) return ( (header_path, header_text), (cpp_path, cpp_text), )
def render_template(self, include_paths, header_template, cpp_template, template_context, component=None): template_context['code_generator'] = self.generator_name # Add includes for any dependencies template_context['header_includes'] = normalize_and_sort_includes( template_context['header_includes']) for include_path in include_paths: if component: dependency = idl_filename_to_component(include_path) assert is_valid_component_dependency(component, dependency) includes.add(include_path) template_context['cpp_includes'] = normalize_and_sort_includes(includes) header_text = render_template(header_template, template_context) cpp_text = render_template(cpp_template, template_context) return header_text, cpp_text
def render_template(include_paths, header_template, cpp_template, template_context, component=None): template_context['code_generator'] = module_pyname # Add includes for any dependencies template_context['header_includes'] = sorted( template_context['header_includes']) for include_path in include_paths: if component: dependency = idl_filename_to_component(include_path) assert is_valid_component_dependency(component, dependency) includes.add(include_path) template_context['cpp_includes'] = sorted(includes) header_text = header_template.render(template_context) cpp_text = cpp_template.render(template_context) return header_text, cpp_text
def generate_interface_code(self, definitions, interface_name, interface): interface_info = self.info_provider.interfaces_info[interface_name] full_path = interface_info.get("full_path") component = idl_filename_to_component(full_path) include_paths = interface_info.get("dependencies_include_paths") # Select appropriate Jinja template and contents function if interface.is_callback: header_template_filename = "callback_interface.h.tmpl" cpp_template_filename = "callback_interface.cpp.tmpl" interface_context = v8_callback_interface.callback_interface_context elif interface.is_partial: interface_context = v8_interface.interface_context header_template_filename = "partial_interface.h.tmpl" cpp_template_filename = "partial_interface.cpp.tmpl" interface_name += "Partial" assert component == "core" component = "modules" include_paths = interface_info.get("dependencies_other_component_include_paths") else: header_template_filename = "interface.h.tmpl" cpp_template_filename = "interface.cpp.tmpl" interface_context = v8_interface.interface_context template_context = interface_context(interface, definitions.interfaces) includes.update(interface_info.get("cpp_includes", {}).get(component, set())) if not interface.is_partial and not is_testing_target(full_path): template_context["header_includes"].add(self.info_provider.include_path_for_export) template_context["exported"] = self.info_provider.specifier_for_export # Add the include for interface itself if IdlType(interface_name).is_typed_array: template_context["header_includes"].add("core/dom/DOMTypedArray.h") elif interface_info["include_path"]: template_context["header_includes"].add(interface_info["include_path"]) template_context["header_includes"].update(interface_info.get("additional_header_includes", [])) header_template = self.jinja_env.get_template(header_template_filename) cpp_template = self.jinja_env.get_template(cpp_template_filename) header_text, cpp_text = self.render_template( include_paths, header_template, cpp_template, template_context, component ) header_path, cpp_path = self.output_paths(interface_name) return ((header_path, header_text), (cpp_path, cpp_text))
def merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader): """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface. Args: definitions: IdlDefinitions object, modified in place component: string, describing where the above definitions are defined, 'core' or 'modules'. See KNOWN_COMPONENTS in utilities.py target_interface: IdlInterface object, modified in place dependency_idl_filenames: Idl filenames which depend on the above definitions. reader: IdlReader object. Returns: A dictionary whose key is component and value is IdlDefinitions object whose dependency is resolved. """ resolved_definitions = {component: definitions} # Sort so order consistent, so can compare output from run to run. for dependency_idl_filename in sorted(dependency_idl_filenames): dependency_definitions = reader.read_idl_file(dependency_idl_filename) dependency_component = idl_filename_to_component(dependency_idl_filename) dependency_interface = next(dependency_definitions.interfaces.itervalues()) dependency_interface_basename, _ = os.path.splitext(os.path.basename(dependency_idl_filename)) transfer_extended_attributes(dependency_interface, dependency_interface_basename) # We need to use different checkdeps here for partial interface and # inheritance. if dependency_interface.is_partial: # Case: dependency_interface is a partial interface of # target_interface. # So, # - A partial interface defined in modules can update # the original interface defined in core. # However, # - A partial interface defined in core cannot update # the original interface defined in modules. if not is_valid_component_dependency(dependency_component, component): raise Exception('The partial interface:%s in %s cannot update ' 'the original interface:%s in %s' % (dependency_interface.name, dependency_component, target_interface.name, component)) if dependency_component in resolved_definitions: # When merging a new partial interfaces, should not overwrite # ImpelemntedAs extended attributes in merged partial # interface. # See also the below "if 'ImplementedAs' not in ... " line's # comment. dependency_interface.extended_attributes.pop('ImplementedAs', None) resolved_definitions[dependency_component].update(dependency_definitions) continue dependency_interface.extended_attributes.update(target_interface.extended_attributes) assert target_interface == definitions.interfaces[dependency_interface.name] # A partial interface should use its original interface's # ImplementedAs. If the original interface doesn't have, # remove ImplementedAs defined in the partial interface. # Because partial interface needs the original interface's # cpp class to obtain partial interface's cpp class. # e.g.. V8WindowPartial.cpp: # DOMWindow* impl = V8Window::toImpl(holder); # RawPtr<...> cppValue(DOMWindowQuota::webkitStorageInfo(impl)); # TODO(tasak): remove ImplementedAs extended attributes # from all partial interfaces. Instead, rename all cpp/header # files correctly. ImplementedAs should not be allowed in # partial interfaces. if 'ImplementedAs' not in target_interface.extended_attributes: dependency_interface.extended_attributes.pop('ImplementedAs', None) dependency_interface.original_interface = target_interface target_interface.partial_interfaces.append(dependency_interface) resolved_definitions[dependency_component] = dependency_definitions else: # Case: target_interface implements dependency_interface. # So, # - An interface defined in modules can implement some interface # defined in core. # In this case, we need "NoInterfaceObject" extended attribute. # However, # - An interface defined in core cannot implement any interface # defined in modules. if not is_valid_component_dependency(component, dependency_component): raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s.' % (dependency_interface.name, dependency_component, target_interface.name, component)) if component != dependency_component and 'NoInterfaceObject' not in dependency_interface.extended_attributes: raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s because of ' 'missing NoInterfaceObject.' % (dependency_interface.name, dependency_component, target_interface.name, component)) resolved_definitions[component].update(dependency_definitions) # merges partial interfaces # Implemented interfaces (non-partial dependencies) are also merged # into the target interface, so Code Generator can just iterate # over one list (and not need to handle 'implements' itself). target_interface.merge(dependency_interface) return resolved_definitions
def compute_interfaces_info_overall(info_individuals): """Compute information about IDL files. Information is stored in global interfaces_info. """ for info in info_individuals: # No overlap between interface names, so ok to use dict.update interfaces_info.update(info['interfaces_info']) # Interfaces in one component may have partial interfaces in # another component. This is ok (not a layering violation), since # partial interfaces are used to *extend* interfaces. # We thus need to update or append if already present dict_of_dicts_of_lists_update_or_append( partial_interface_files, info['partial_interface_files']) # Record inheritance information individually for interface_name, interface_info in interfaces_info.iteritems(): extended_attributes = interface_info['extended_attributes'] inherited_extended_attributes_by_interface[interface_name] = dict( (key, value) for key, value in extended_attributes.iteritems() if key in INHERITED_EXTENDED_ATTRIBUTES) parent = interface_info['parent'] if parent: parent_interfaces[interface_name] = parent # Once all individual files handled, can compute inheritance information # and dependencies # Compute inheritance info for interface_name in interfaces_info: compute_inheritance_info(interface_name) # Compute dependencies # Move implements info from implement*ed* interface (rhs of 'implements') # to implement*ing* interface (lhs of 'implements'). # Note that moving an 'implements' statement between implementing and # implemented files does not change the info (or hence cause a rebuild)! for right_interface_name, interface_info in interfaces_info.iteritems(): for left_interface_name in interface_info['implemented_by_interfaces']: interfaces_info[left_interface_name]['implements_interfaces'].append(right_interface_name) del interface_info['implemented_by_interfaces'] # An IDL file's dependencies are partial interface files that extend it, # and files for other interfaces that this interfaces implements. for interface_name, interface_info in interfaces_info.iteritems(): partial_interface_paths = partial_interface_files[interface_name] partial_interfaces_full_paths = partial_interface_paths['full_paths'] # Partial interface definitions each need an include, as they are # implemented in separate classes from the main interface. partial_interfaces_include_paths = partial_interface_paths['include_paths'] implemented_interfaces = interface_info['implements_interfaces'] try: implemented_interfaces_info = [ interfaces_info[interface] for interface in implemented_interfaces] except KeyError as key_name: raise IdlInterfaceFileNotFoundError('Could not find the IDL file where the following implemented interface is defined: %s' % key_name) implemented_interfaces_full_paths = [ implemented_interface_info['full_path'] for implemented_interface_info in implemented_interfaces_info] # Implemented interfaces don't need includes, as this is handled in # the Blink implementation (they are implemented on |impl| itself, # hence header is included in implementing class). # However, they are needed for legacy implemented interfaces that # are being treated as partial interfaces, until we remove these. # http://crbug.com/360435 implemented_interfaces_include_paths = [] for implemented_interface_info in implemented_interfaces_info: if (implemented_interface_info['is_legacy_treat_as_partial_interface'] and implemented_interface_info['include_path']): implemented_interfaces_include_paths.append( implemented_interface_info['include_path']) dependencies_full_paths = implemented_interfaces_full_paths dependencies_include_paths = implemented_interfaces_include_paths dependencies_other_component_full_paths = [] dependencies_other_component_include_paths = [] component = idl_filename_to_component(interface_info['full_path']) for full_path in partial_interfaces_full_paths: partial_interface_component = idl_filename_to_component(full_path) if component == partial_interface_component: dependencies_full_paths.append(full_path) else: dependencies_other_component_full_paths.append(full_path) for include_path in partial_interfaces_include_paths: partial_interface_component = idl_filename_to_component(include_path) if component == partial_interface_component: dependencies_include_paths.append(include_path) else: dependencies_other_component_include_paths.append(include_path) if interface_info['has_union_types']: dependencies_include_paths.append( 'bindings/%s/v8/UnionTypes%s.h' % (component, component.capitalize())) interface_info.update({ 'dependencies_full_paths': dependencies_full_paths, 'dependencies_include_paths': dependencies_include_paths, 'dependencies_other_component_full_paths': dependencies_other_component_full_paths, 'dependencies_other_component_include_paths': dependencies_other_component_include_paths, }) # Clean up temporary private information for interface_info in interfaces_info.itervalues(): del interface_info['extended_attributes'] del interface_info['has_union_types'] del interface_info['is_legacy_treat_as_partial_interface'] del interface_info['parent'] # Compute global_type_info to interfaces_info so that idl_compiler does # not need to always calculate the info in __init__. compute_global_type_info()
def merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader): """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface. Args: definitions: IdlDefinitions object, modified in place component: string, describing where the above definitions are defined, 'core' or 'modules'. See KNOWN_COMPONENTS in utilities.py target_interface: IdlInterface object, modified in place dependency_idl_filenames: Idl filenames which depend on the above definitions. reader: IdlReader object. Returns: A dictionary whose key is component and value is IdlDefinitions object whose dependency is resolved. """ resolved_definitions = {component: definitions} # Sort so order consistent, so can compare output from run to run. for dependency_idl_filename in sorted(dependency_idl_filenames): dependency_definitions = reader.read_idl_file(dependency_idl_filename) dependency_component = idl_filename_to_component( dependency_idl_filename) dependency_interface = next( dependency_definitions.interfaces.itervalues()) dependency_interface_basename, _ = os.path.splitext( os.path.basename(dependency_idl_filename)) transfer_extended_attributes(dependency_interface, dependency_interface_basename) # We need to use different checkdeps here for partial interface and # inheritance. if dependency_interface.is_partial: # Case: dependency_interface is a partial interface of # target_interface. # So, # - A partial interface defined in modules can update # the original interface defined in core. # However, # - A partial interface defined in core cannot update # the original interface defined in modules. if not is_valid_component_dependency(dependency_component, component): raise Exception( 'The partial interface:%s in %s cannot update ' 'the original interface:%s in %s' % (dependency_interface.name, dependency_component, target_interface.name, component)) if dependency_component in resolved_definitions: resolved_definitions[dependency_component].update( dependency_definitions) continue dependency_interface.extended_attributes.update( target_interface.extended_attributes) assert target_interface == definitions.interfaces[ dependency_interface.name] dependency_interface.original_interface = target_interface target_interface.partial_interfaces.append(dependency_interface) resolved_definitions[dependency_component] = dependency_definitions else: # Case: target_interface implements dependency_interface. # So, # - An interface defined in modules can implement some interface # defined in core. # In this case, we need "NoInterfaceObject" extended attribute. # However, # - An interface defined in core cannot implement any interface # defined in modules. if not is_valid_component_dependency(component, dependency_component): raise Exception( 'The interface:%s in %s cannot implement ' 'the interface:%s in %s.' % (dependency_interface.name, dependency_component, target_interface.name, component)) if component != dependency_component and 'NoInterfaceObject' not in dependency_interface.extended_attributes: raise Exception( 'The interface:%s in %s cannot implement ' 'the interface:%s in %s because of ' 'missing NoInterfaceObject.' % (dependency_interface.name, dependency_component, target_interface.name, component)) resolved_definitions[component].update( dependency_definitions) # merges partial interfaces # Implemented interfaces (non-partial dependencies) are also merged # into the target interface, so Code Generator can just iterate # over one list (and not need to handle 'implements' itself). target_interface.merge(dependency_interface) return resolved_definitions
def collect_info(self, idl_filename): """Reads an idl file and collects information which is required by the binding code generation.""" def collect_unforgeable_attributes(definition, idl_filename): """Collects [Unforgeable] attributes so that we can define them on sub-interfaces later. The resulting structure is as follows. interfaces_info[interface_name] = { 'unforgeable_attributes': [IdlAttribute, ...], ... } """ interface_info = {} unforgeable_attributes = get_unforgeable_attributes_from_definition( definition) if not unforgeable_attributes: return interface_info if definition.is_partial: interface_basename = idl_filename_to_interface_name( idl_filename) # TODO(yukishiino): [PartialInterfaceImplementedAs] is treated # in interface_dependency_resolver.transfer_extended_attributes. # Come up with a better way to keep them consistent. for attr in unforgeable_attributes: attr.extended_attributes[ 'PartialInterfaceImplementedAs'] = definition.extended_attributes.get( 'ImplementedAs', interface_basename) interface_info['unforgeable_attributes'] = unforgeable_attributes return interface_info definitions = self.reader.read_idl_file(idl_filename) this_union_types = collect_union_types_from_definitions(definitions) self.union_types.update(this_union_types) self.typedefs.update(definitions.typedefs) for callback_function_name, callback_function in \ definitions.callback_functions.iteritems(): # Set 'component_dir' to specify a directory that callback function files belong to self.callback_functions[callback_function_name] = { 'callback_function': callback_function, 'component_dir': idl_filename_to_component(idl_filename), 'full_path': os.path.realpath(idl_filename), } # Check enum duplication. for enum in definitions.enumerations.values(): if not self.check_enum_consistency(enum): raise Exception('Enumeration "%s" is defined more than once ' 'with different valid values' % enum.name) self.enumerations.update(definitions.enumerations) if definitions.interfaces: 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 definitions.dictionaries: definition = next(definitions.dictionaries.itervalues()) interface_info = { 'is_callback_interface': False, 'is_dictionary': True, 'referenced_interfaces': None, } else: return if definition.name not in self.interfaces_info: self.interfaces_info[definition.name] = {} # Remember [Unforgeable] attributes. if definitions.interfaces: merge_dict_recursively( self.interfaces_info[definition.name], collect_unforgeable_attributes(definition, idl_filename)) component = idl_filename_to_component(idl_filename) extended_attributes = definition.extended_attributes implemented_as = extended_attributes.get('ImplementedAs') full_path = os.path.realpath(idl_filename) if interface_info['is_dictionary']: this_include_path = include_path(idl_filename) else: this_include_path = 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. partial_include_paths = [] if this_include_path: partial_include_paths.append(this_include_path) self.add_paths_to_partials_dict(definition.name, full_path, partial_include_paths) # Collects C++ header paths which should be included from generated # .cpp files. The resulting structure is as follows. # interfaces_info[interface_name] = { # 'cpp_includes': { # 'core': set(['core/foo/Foo.h', ...]), # 'modules': set(['modules/bar/Bar.h', ...]), # }, # ... # } if this_include_path: merge_dict_recursively( self.interfaces_info[definition.name], {'cpp_includes': { component: set([this_include_path]) }}) return # 'includes' statements can be included in either the file for the # interface (lhs of 'includes') or mixin (rhs of 'includes'). Store both # for now, then merge to the interface later. includes_interfaces, includes_mixins = get_includes_from_definitions( definitions, definition.name) interface_info.update({ 'extended_attributes': extended_attributes, 'full_path': full_path, 'union_types': this_union_types, 'implemented_as': implemented_as, 'included_by_interfaces': includes_interfaces, 'including_mixins': includes_mixins, '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, source_path), }) merge_dict_recursively(self.interfaces_info[definition.name], interface_info)
def collect_info(self, idl_filename): """Reads an idl file and collects information which is required by the binding code generation.""" def collect_unforgeable_attributes(definition, idl_filename): """Collects [Unforgeable] attributes so that we can define them on sub-interfaces later. The resulting structure is as follows. interfaces_info[interface_name] = { 'unforgeable_attributes': { 'core': [IdlAttribute, ...], 'modules': [IdlAttribute, ...], }, ... } """ interface_info = {} unforgeable_attributes = get_unforgeable_attributes_from_definition(definition) if not unforgeable_attributes: return interface_info if definition.is_partial: interface_basename = idl_filename_to_interface_name(idl_filename) # TODO(yukishiino): [PartialInterfaceImplementedAs] is treated # in interface_dependency_resolver.transfer_extended_attributes. # Come up with a better way to keep them consistent. for attr in unforgeable_attributes: attr.extended_attributes['PartialInterfaceImplementedAs'] = definition.extended_attributes.get('ImplementedAs', interface_basename) component = idl_filename_to_component(idl_filename) interface_info['unforgeable_attributes'] = {} interface_info['unforgeable_attributes'][component] = unforgeable_attributes return interface_info definitions = self.reader.read_idl_file(idl_filename) this_union_types = collect_union_types_from_definitions(definitions) self.union_types.update(this_union_types) self.typedefs.update(definitions.typedefs) # Check enum duplication. for enum_name in definitions.enumerations.keys(): for defined_enum in self.enumerations: if defined_enum.name == enum_name: raise Exception('Enumeration %s has multiple definitions' % enum_name) self.enumerations.update(definitions.enumerations.values()) if definitions.interfaces: 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 definitions.dictionaries: definition = next(definitions.dictionaries.itervalues()) interface_info = { 'is_callback_interface': False, 'is_dictionary': True, 'referenced_interfaces': None, } else: return if definition.name not in self.interfaces_info: self.interfaces_info[definition.name] = {} # Remember [Unforgeable] attributes. if definitions.interfaces: merge_dict_recursively(self.interfaces_info[definition.name], collect_unforgeable_attributes(definition, idl_filename)) component = idl_filename_to_component(idl_filename) 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. partial_include_paths = [] if this_include_path: partial_include_paths.append(this_include_path) if this_union_types: partial_include_paths.append( 'bindings/%s/v8/UnionTypes%s.h' % (component, component.capitalize())) self.add_paths_to_partials_dict(definition.name, full_path, partial_include_paths) # Collects C++ header paths which should be included from generated # .cpp files. The resulting structure is as follows. # interfaces_info[interface_name] = { # 'cpp_includes': { # 'core': set(['core/foo/Foo.h', ...]), # 'modules': set(['modules/bar/Bar.h', ...]), # }, # ... # } if this_include_path: merge_dict_recursively( self.interfaces_info[definition.name], {'cpp_includes': {component: set([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, 'has_union_types': bool(this_union_types), '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, source_path), }) merge_dict_recursively(self.interfaces_info[definition.name], interface_info)
def merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader): """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface. Args: definitions: IdlDefinitions object, modified in place component: string, describing where the above definitions are defined, 'core' or 'modules'. See KNOWN_COMPONENTS in utilities.py target_interface: IdlInterface object, modified in place dependency_idl_filenames: Idl filenames which depend on the above definitions. reader: IdlReader object. Returns: A dictionary whose key is component and value is IdlDefinitions object whose dependency is resolved. """ resolved_definitions = {component: definitions} # Sort so order consistent, so can compare output from run to run. for dependency_idl_filename in sorted(dependency_idl_filenames): dependency_definitions = reader.read_idl_file(dependency_idl_filename) dependency_component = idl_filename_to_component(dependency_idl_filename) dependency_interface = next(dependency_definitions.interfaces.itervalues()) dependency_interface_basename, _ = os.path.splitext(os.path.basename(dependency_idl_filename)) transfer_extended_attributes(dependency_interface, dependency_interface_basename) # We need to use different checkdeps here for partial interface and # inheritance. if dependency_interface.is_partial: # Case: dependency_interface is a partial interface of # target_interface. # So, # - A partial interface defined in modules can update # the original interface defined in core. # However, # - A partial interface defined in core cannot update # the original interface defined in modules. if not is_valid_component_dependency(dependency_component, component): raise Exception('The partial interface:%s in %s cannot update ' 'the original interface:%s in %s' % (dependency_interface.name, dependency_component, target_interface.name, component)) if dependency_component in resolved_definitions: resolved_definitions[dependency_component].update(dependency_definitions) continue dependency_interface.extended_attributes.update(target_interface.extended_attributes) assert target_interface == definitions.interfaces[dependency_interface.name] dependency_interface.original_interface = target_interface target_interface.partial_interfaces.append(dependency_interface) resolved_definitions[dependency_component] = dependency_definitions else: # Case: target_interface implements dependency_interface. # So, # - An interface defined in modules can implement some interface # defined in core. # In this case, we need "NoInterfaceObject" extended attribute. # However, # - An interface defined in core cannot implement any interface # defined in modules. if not is_valid_component_dependency(component, dependency_component): raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s.' % (dependency_interface.name, dependency_component, target_interface.name, component)) if component != dependency_component and 'NoInterfaceObject' not in dependency_interface.extended_attributes: raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s because of ' 'missing NoInterfaceObject.' % (dependency_interface.name, dependency_component, target_interface.name, component)) resolved_definitions[component].update(dependency_definitions) # merges partial interfaces # Implemented interfaces (non-partial dependencies) are also merged # into the target interface, so Code Generator can just iterate # over one list (and not need to handle 'implements' itself). target_interface.merge(dependency_interface) return resolved_definitions
def origin_trial_features_info(info_provider, reader, idl_filenames, target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. Returns a tuple (features_for_type, types_for_feature, includes): - features_for_type is a mapping of interface->feature - types_for_feature is the reverse mapping: feature->interface - includes is a set of header files which need to be included in the generated implementation code. """ features_for_type = defaultdict(set) types_for_feature = defaultdict(set) includes = set() for idl_filename in idl_filenames: interface, implements = read_idl_file(reader, idl_filename) feature_names = get_origin_trial_feature_names_from_interface( interface) # If this interface has NoInterfaceObject then we don't want to add # includes for it because it is a base interface to be implemented # by other interfaces, and does not generate an ECMAScript binding. if 'NoInterfaceObject' in interface.extended_attributes: continue # If this interface implements another one, # it inherits any conditional features from it. for implement in implements: assert implement.left_interface == interface.name implemented_interface, _ = read_idl_file( reader, info_provider.interfaces_info[ implement.right_interface].get('full_path')) feature_names |= get_origin_trial_feature_names_from_interface( implemented_interface) feature_names = list(feature_names) if feature_names: is_global = interface_is_global(interface) if interface.is_partial: # For partial interfaces, we need to generate different # includes if the parent interface is in a different # component. parent_interface_info = info_provider.interfaces_info[ interface.name] parent_interface, _ = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: includes.add('bindings/%s/v8/%s' % (parent_component, binding_header_basename(interface.name))) includes.add( 'bindings/%s/v8/%s' % (target_component, binding_header_basename(interface.name + 'Partial'))) else: includes.add('bindings/%s/v8/%s' % (target_component, binding_header_basename(interface.name))) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False interface_info = OriginTrialInterfaceInfo( interface.name, v8_class_name(interface), v8_class_name_or_partial(interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) return features_for_type, types_for_feature, includes
def collect_info(self, idl_filename): """Reads an idl file and collects information which is required by the binding code generation.""" definitions = self.reader.read_idl_file(idl_filename) this_union_types = collect_union_types_from_definitions(definitions) self.union_types.update(this_union_types) self.typedefs.update(definitions.typedefs) # Check enum duplication. for enum_name in definitions.enumerations.keys(): for defined_enum in self.enumerations: if defined_enum.name == enum_name: raise Exception('Enumeration %s has multiple definitions' % enum_name) self.enumerations.update(definitions.enumerations.values()) if definitions.interfaces: 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 definitions.dictionaries: definition = next(definitions.dictionaries.itervalues()) interface_info = { 'is_callback_interface': False, 'is_dictionary': True, 'referenced_interfaces': None, } else: return 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. partial_include_paths = [] if this_include_path: partial_include_paths.append(this_include_path) if this_union_types: component = idl_filename_to_component(idl_filename) partial_include_paths.append( 'bindings/%s/v8/UnionTypes%s.h' % (component, component.capitalize())) self.add_paths_to_partials_dict(definition.name, full_path, partial_include_paths) 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, 'has_union_types': bool(this_union_types), '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 merge_interface_dependencies(definitions, component, target_interface, dependency_idl_filenames, reader): """Merge dependencies ('partial interface' and 'implements') in dependency_idl_filenames into target_interface. Args: definitions: IdlDefinitions object, modified in place component: string, describing where the above definitions are defined, 'core' or 'modules'. See KNOWN_COMPONENTS in utilities.py target_interface: IdlInterface object, modified in place dependency_idl_filenames: Idl filenames which depend on the above definitions. reader: IdlReader object. Returns: A dictionary whose key is component and value is IdlDefinitions object whose dependency is resolved. """ resolved_definitions = {component: definitions} # Sort so order consistent, so can compare output from run to run. for dependency_idl_filename in sorted(dependency_idl_filenames): dependency_definitions = reader.read_idl_file(dependency_idl_filename) dependency_component = idl_filename_to_component(dependency_idl_filename) dependency_interface = next(dependency_definitions.interfaces.itervalues()) dependency_interface_basename, _ = os.path.splitext(os.path.basename(dependency_idl_filename)) transfer_extended_attributes(dependency_interface, dependency_interface_basename) # We need to use different checkdeps here for partial interface and # inheritance. if dependency_interface.is_partial: # Case: dependency_interface is a partial interface of # target_interface. # So, # - A partial interface defined in modules can update # the original interface defined in core. # However, # - A partial interface defined in core cannot update # the original interface defined in modules. if not is_valid_component_dependency(dependency_component, component): raise Exception('The partial interface:%s in %s cannot update ' 'the original interface:%s in %s' % (dependency_interface.name, dependency_component, target_interface.name, component)) if dependency_component in resolved_definitions: # When merging a new partial interfaces, should not overwrite # ImpelemntedAs extended attributes in merged partial # interface. # See also the below "if 'ImplementedAs' not in ... " line's # comment. dependency_interface.extended_attributes.pop('ImplementedAs', None) resolved_definitions[dependency_component].update(dependency_definitions) continue dependency_interface.extended_attributes.update(target_interface.extended_attributes) assert target_interface == definitions.interfaces[dependency_interface.name] # A partial interface should use its original interface's # ImplementedAs. If the original interface doesn't have, # remove ImplementedAs defined in the partial interface. # Because partial interface needs the original interface's # cpp class to obtain partial interface's cpp class. # e.g.. V8WindowPartial.cpp: # DOMWindow* impl = V8Window::toImpl(holder); # DOMWindowQuota* cppValue(DOMWindowQuota::webkitStorageInfo(impl)); # TODO(tasak): remove ImplementedAs extended attributes # from all partial interfaces. Instead, rename all cpp/header # files correctly. ImplementedAs should not be allowed in # partial interfaces. if 'ImplementedAs' not in target_interface.extended_attributes: dependency_interface.extended_attributes.pop('ImplementedAs', None) dependency_interface.original_interface = target_interface target_interface.partial_interfaces.append(dependency_interface) resolved_definitions[dependency_component] = dependency_definitions else: # Case: target_interface implements dependency_interface. # So, # - An interface defined in modules can implement some interface # defined in core. # In this case, we need "NoInterfaceObject" extended attribute. # However, # - An interface defined in core cannot implement any interface # defined in modules. if not is_valid_component_dependency(component, dependency_component): raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s.' % (dependency_interface.name, dependency_component, target_interface.name, component)) if component != dependency_component and 'NoInterfaceObject' not in dependency_interface.extended_attributes: raise Exception('The interface:%s in %s cannot implement ' 'the interface:%s in %s because of ' 'missing NoInterfaceObject.' % (dependency_interface.name, dependency_component, target_interface.name, component)) resolved_definitions[component].update(dependency_definitions) # merges partial interfaces # Implemented interfaces (non-partial dependencies) are also merged # into the target interface, so Code Generator can just iterate # over one list (and not need to handle 'implements' itself). target_interface.merge(dependency_interface) return resolved_definitions
def collect_info(self, idl_filename): """Reads an idl file and collects information which is required by the binding code generation.""" definitions = self.reader.read_idl_file(idl_filename) this_union_types = collect_union_types_from_definitions(definitions) self.union_types.update(this_union_types) self.typedefs.update(definitions.typedefs) # Check enum duplication. for enum_name in definitions.enumerations.keys(): for defined_enum in self.enumerations: if defined_enum.name == enum_name: raise Exception('Enumeration %s has multiple definitions' % enum_name) self.enumerations.update(definitions.enumerations.values()) if definitions.interfaces: 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 definitions.dictionaries: definition = next(definitions.dictionaries.itervalues()) interface_info = { 'is_callback_interface': False, 'is_dictionary': True, 'referenced_interfaces': None, } else: return 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. partial_include_paths = [] if this_include_path: partial_include_paths.append(this_include_path) if this_union_types: component = idl_filename_to_component(idl_filename) partial_include_paths.append( 'bindings/%s/v8/UnionTypes%s.h' % (component, component.capitalize())) self.add_paths_to_partials_dict(definition.name, full_path, partial_include_paths) 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, 'has_union_types': bool(this_union_types), '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 compute_interfaces_info_overall(info_individuals): """Compute information about IDL files. Information is stored in global interfaces_info. """ for info in info_individuals: merge_dict_recursively(interfaces_info, info['interfaces_info']) # Interfaces in one component may have partial interfaces in # another component. This is ok (not a layering violation), since # partial interfaces are used to *extend* interfaces. # We thus need to update or append if already present dict_of_dicts_of_lists_update_or_append( partial_interface_files, info['partial_interface_files']) interfaces_referenced_from_partial_interfaces.update( info['partial_interface_referenced_interfaces']) # Append interfaces referenced from partial interfaces into the full # interface's list of partial interfaces for interface_name, referenced_interfaces in interfaces_referenced_from_partial_interfaces.items(): interface_info = interfaces_info[interface_name] interface_info['referenced_interfaces'].extend(referenced_interfaces) # Record inheritance information individually for interface_name, interface_info in interfaces_info.iteritems(): extended_attributes = interface_info['extended_attributes'] inherited_extended_attributes_by_interface[interface_name] = dict( (key, value) for key, value in extended_attributes.iteritems() if key in INHERITED_EXTENDED_ATTRIBUTES) parent = interface_info['parent'] if parent: parent_interfaces[interface_name] = parent # Once all individual files handled, can compute inheritance information # and dependencies # Compute inheritance info for interface_name in interfaces_info: compute_inheritance_info(interface_name) # Compute dependencies # Move implements info from implement*ed* interface (rhs of 'implements') # to implement*ing* interface (lhs of 'implements'). # Note that moving an 'implements' statement between implementing and # implemented files does not change the info (or hence cause a rebuild)! for right_interface_name, interface_info in interfaces_info.iteritems(): for left_interface_name in interface_info['implemented_by_interfaces']: interfaces_info[left_interface_name]['implements_interfaces'].append(right_interface_name) del interface_info['implemented_by_interfaces'] # An IDL file's dependencies are partial interface files that extend it, # and files for other interfaces that this interfaces implements. for interface_name, interface_info in interfaces_info.iteritems(): partial_interface_paths = partial_interface_files[interface_name] partial_interfaces_full_paths = partial_interface_paths['full_paths'] # Partial interface definitions each need an include, as they are # implemented in separate classes from the main interface. partial_interfaces_include_paths = partial_interface_paths['include_paths'] implemented_interfaces = interface_info['implements_interfaces'] try: implemented_interfaces_info = [ interfaces_info[interface] for interface in implemented_interfaces] except KeyError as key_name: raise IdlInterfaceFileNotFoundError('Could not find the IDL file where the following implemented interface is defined: %s' % key_name) implemented_interfaces_full_paths = [ implemented_interface_info['full_path'] for implemented_interface_info in implemented_interfaces_info] # Implemented interfaces don't need includes, as this is handled in # the Blink implementation (they are implemented on |impl| itself, # hence header is included in implementing class). # However, they are needed for legacy implemented interfaces that # are being treated as partial interfaces, until we remove these. # http://crbug.com/360435 implemented_interfaces_include_paths = [ implemented_interface_info['include_path'] for implemented_interface_info in implemented_interfaces_info if implemented_interface_info['is_legacy_treat_as_partial_interface']] dependencies_full_paths = implemented_interfaces_full_paths dependencies_include_paths = implemented_interfaces_include_paths dependencies_other_component_full_paths = [] dependencies_other_component_include_paths = [] component = idl_filename_to_component(interface_info['full_path']) for full_path in partial_interfaces_full_paths: partial_interface_component = idl_filename_to_component(full_path) if component == partial_interface_component: dependencies_full_paths.append(full_path) else: dependencies_other_component_full_paths.append(full_path) for include_path in partial_interfaces_include_paths: partial_interface_component = idl_filename_to_component(include_path) if component == partial_interface_component: dependencies_include_paths.append(include_path) else: dependencies_other_component_include_paths.append(include_path) for union_type in interface_info.get('union_types', []): name = shorten_union_name(union_type) dependencies_include_paths.append( 'bindings/%s/v8/%s.h' % (component, name)) interface_info.update({ 'dependencies_full_paths': dependencies_full_paths, 'dependencies_include_paths': dependencies_include_paths, 'dependencies_other_component_full_paths': dependencies_other_component_full_paths, 'dependencies_other_component_include_paths': dependencies_other_component_include_paths, }) # Clean up temporary private information for interface_info in interfaces_info.itervalues(): del interface_info['extended_attributes'] del interface_info['union_types'] del interface_info['is_legacy_treat_as_partial_interface'] # Compute global_type_info to interfaces_info so that idl_compiler does # not need to always calculate the info in __init__. compute_global_type_info()
def origin_trial_features_info(info_provider, reader, idl_filenames, target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. Returns a tuple (features_for_type, types_for_feature, includes): - features_for_type is a mapping of interface->feature - types_for_feature is the reverse mapping: feature->interface - includes is a set of header files which need to be included in the generated implementation code. """ features_for_type = defaultdict(set) types_for_feature = defaultdict(set) include_files = set() runtime_features = info_provider.component_info['runtime_enabled_features'] for idl_filename in idl_filenames: interface, includes = read_idl_file(reader, idl_filename) feature_names = get_origin_trial_feature_names_from_interface( interface, runtime_features) # If this interface is a mixin, we don't generate V8 bindings code for # it. if interface.is_mixin: continue # If this interface include another one, # it inherits any conditional features from it. for include in includes: assert include.interface == interface.name mixin, _ = read_idl_file( reader, info_provider.interfaces_info[include.mixin].get('full_path')) feature_names |= get_origin_trial_feature_names_from_interface( mixin, runtime_features) feature_names = list(feature_names) if feature_names: is_global = interface_is_global(interface) if interface.is_partial: # For partial interfaces, we need to generate different # |include_files| if the parent interface is in a different # component. parent_interface_info = \ info_provider.interfaces_info[interface.name] parent_interface, _ = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: include_files.add('bindings/%s/v8/%s' % (parent_component, binding_header_filename(interface.name))) include_files.add( 'bindings/%s/v8/%s' % (target_component, binding_header_filename(interface.name + 'Partial'))) else: include_files.add('bindings/%s/v8/%s' % (target_component, binding_header_filename(interface.name))) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False interface_info = OriginTrialInterfaceInfo( interface.name, v8_class_name(interface), v8_class_name_or_partial(interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) return features_for_type, types_for_feature, include_files
def conditional_features_info(info_provider, reader, idl_filenames, target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. Returns a tuple (features_for_type, types_for_feature, includes): - features_for_type is a mapping of interface->feature - types_for_feature is the reverse mapping: feature->interface - includes is a set of header files which need to be included in the generated implementation code. """ features_for_type = defaultdict(set) types_for_feature = defaultdict(set) includes = set() for idl_filename in idl_filenames: interface, implements = read_idl_file(reader, idl_filename) feature_names = get_conditional_feature_names_from_interface(interface) # If this interface implements another one, # it inherits any conditional features from it. for implement in implements: assert implement.left_interface == interface.name implemented_interface, _ = read_idl_file( reader, info_provider.interfaces_info[implement.right_interface].get('full_path')) feature_names |= get_conditional_feature_names_from_interface(implemented_interface) feature_names = list(feature_names) if feature_names: is_global = interface_is_global(interface) if interface.is_partial: # For partial interfaces, we need to generate different # includes if the parent interface is in a different # component. parent_interface_info = info_provider.interfaces_info[interface.name] parent_interface, _ = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: includes.add('bindings/%s/v8/V8%s.h' % (parent_component, interface.name)) includes.add('bindings/%s/v8/V8%sPartial.h' % (target_component, interface.name)) else: includes.add('bindings/%s/v8/V8%s.h' % (target_component, interface.name)) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False interface_info = ConditionalInterfaceInfo(interface.name, v8_class_name(interface), v8_class_name_or_partial( interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) return features_for_type, types_for_feature, includes
def origin_trial_features_info(info_provider, reader, idl_filenames, target_component): """Read a set of IDL files and compile the mapping between interfaces and the conditional features defined on them. Returns a tuple (features_for_type, types_for_feature, includes): - features_for_type is a mapping of interface->feature - types_for_feature is the reverse mapping: feature->interface - includes is a set of header files which need to be included in the generated implementation code. """ features_for_type = defaultdict(set) types_for_feature = defaultdict(set) includes = set() # Gather interfaces which are implemented by other interfaces. implemented_interfaces = set() for name, interface_info in info_provider.interfaces_info.iteritems(): # Skip special entries such as 'dictionaries' or 'ancestors'. if name.lower() == name: continue implemented_interfaces.update(interface_info.get('implements_interfaces')) for idl_filename in idl_filenames: interface, implements = read_idl_file(reader, idl_filename) feature_names = get_origin_trial_feature_names_from_interface(interface) # If this interface is implemented by other interfaces, we don't generate # V8 bindings code for it. if interface.name in implemented_interfaces: continue # If this interface implements another one, # it inherits any conditional features from it. for implement in implements: assert implement.left_interface == interface.name implemented_interface, _ = read_idl_file( reader, info_provider.interfaces_info[implement.right_interface].get('full_path')) feature_names |= get_origin_trial_feature_names_from_interface(implemented_interface) feature_names = list(feature_names) if feature_names: is_global = interface_is_global(interface) if interface.is_partial: # For partial interfaces, we need to generate different # includes if the parent interface is in a different # component. parent_interface_info = info_provider.interfaces_info[interface.name] parent_interface, _ = read_idl_file( reader, parent_interface_info.get('full_path')) is_global = is_global or interface_is_global(parent_interface) parent_component = idl_filename_to_component( parent_interface_info.get('full_path')) if interface.is_partial and target_component != parent_component: includes.add('bindings/%s/v8/%s' % (parent_component, binding_header_filename(interface.name))) includes.add('bindings/%s/v8/%s' % (target_component, binding_header_filename(interface.name + 'Partial'))) else: includes.add('bindings/%s/v8/%s' % (target_component, binding_header_filename(interface.name))) # If this is a partial interface in the same component as # its parent, then treat it as a non-partial interface. interface.is_partial = False interface_info = OriginTrialInterfaceInfo(interface.name, v8_class_name(interface), v8_class_name_or_partial( interface), is_global) for feature_name in feature_names: features_for_type[interface_info].add(feature_name) types_for_feature[feature_name].add(interface_info) return features_for_type, types_for_feature, includes