blob: 73c94b3f793c7282d76fdd9ada538a4338805ff1 [file] [log] [blame] [edit]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This script generates the source files for WebGL GPU process IPC.
#
# python3 -m black -l 150 Tools/Scripts/generate-gpup-webgl
# python3 -m mypy Tools/Scripts/generate-gpup-webgl
#
import argparse
import enum
import pathlib
import re
import sys
import collections
from typing import List, Dict, Iterable, Callable, Tuple, Set, Optional, Generator, Iterator, Counter
root_dir = (pathlib.Path(__file__).parent / ".." / "..").resolve()
functions_input_fns = [root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxy.h"]
types_input_fn = root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxy.h"
template_preamble = """/* Copyright (C) 2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file is generated by generate-gpup-webgl. Do not edit.
"""
context_functions_header_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGLFunctionsGenerated.h"
context_functions_header_template = (
template_preamble
+ """// This file should be included in the private section of the
// RemoteGraphicsContextGL implementations.
#pragma once
{}
"""
)
context_functions_impl_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGLFunctionsGenerated.cpp"
context_functions_impl_template = (
template_preamble
+ """
#include "config.h"
#include "RemoteGraphicsContextGL.h"
#include "Logging.h"
#include <wtf/StdLibExtras.h>
#if ENABLE(GPU_PROCESS) && ENABLE(WEBGL)
#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_connection);
namespace WebKit {{
using namespace WebCore;
{}
}}
#undef MESSAGE_CHECK
#endif
"""
)
context_messages_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGL.messages.in"
context_messages_template = (
template_preamble
+ """#if ENABLE(GPU_PROCESS) && ENABLE(WEBGL)
[
DispatchedFrom=WebContent,
DispatchedTo=GPU,
EnabledBy=WebGLEnabled && UseGPUProcessForWebGLEnabled
]
messages -> RemoteGraphicsContextGL Stream {{
void Reshape(int32_t width, int32_t height)
#if PLATFORM(COCOA)
void PrepareForDisplay(IPC::Semaphore finishedFence) -> (MachSendRight displayBuffer) Synchronous NotStreamEncodable NotStreamEncodableReply
#endif
#if USE(GRAPHICS_LAYER_WC)
void PrepareForDisplay() -> (std::optional<WebKit::WCContentBufferIdentifier> contentBuffer) Synchronous
#endif
#if USE(GBM)
void PrepareForDisplay() -> (uint64_t bufferID, struct std::optional<WebCore::DMABufBufferAttributes> dmabufAttributes, UnixFileDescriptor fenceFD) Synchronous NotStreamEncodableReply
#endif
#if !PLATFORM(COCOA) && !USE(GRAPHICS_LAYER_WC) && !USE(GBM)
void PrepareForDisplay() -> () Synchronous
#endif
void EnsureExtensionEnabled(WebCore::GCGLExtension extension)
void GetErrors() -> (GCGLErrorCodeSet returnValue) Synchronous
void copyNativeImageYFlipped(enum:bool WebCore::GraphicsContextGLSurfaceBuffer buffer, WebCore::RenderingResourceIdentifier nativeImageIdentifier)
#if ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS)
void SurfaceBufferToVideoFrame(enum:bool WebCore::GraphicsContextGLSurfaceBuffer buffer) -> (struct std::optional<WebKit::RemoteVideoFrameProxyProperties> properties) Synchronous
#endif
#if ENABLE(VIDEO) && PLATFORM(COCOA)
void CopyTextureFromVideoFrame(struct WebKit::SharedVideoFrame frame, PlatformGLObject texture, uint32_t target, int32_t level, uint32_t internalFormat, uint32_t format, uint32_t type, bool premultiplyAlpha, bool flipY) -> (bool success) Synchronous NotStreamEncodable
void SetSharedVideoFrameSemaphore(IPC::Semaphore semaphore) NotStreamEncodable
void SetSharedVideoFrameMemory(WebCore::SharedMemory::Handle storageHandle) NotStreamEncodable
#endif
void SimulateEventForTesting(enum:uint8_t WebCore::GraphicsContextGLSimulatedEventForTesting event)
void GetBufferSubDataInline(uint32_t target, uint64_t offset, uint64_t dataSize) -> (std::span<const uint8_t> data) Synchronous
void GetBufferSubDataSharedMemory(uint32_t target, uint64_t offset, uint64_t dataSize, WebCore::SharedMemory::Handle handle) -> (bool valid) Synchronous NotStreamEncodable
void ReadPixelsInline(WebCore::IntRect rect, uint32_t format, uint32_t type, bool packReverseRowOrder) -> (std::optional<WebCore::IntSize> readArea, std::span<const uint8_t> data) Synchronous
void ReadPixelsSharedMemory(WebCore::IntRect rect, uint32_t format, uint32_t type, bool packReverseRowOrder, WebCore::SharedMemory::Handle handle) -> (std::optional<WebCore::IntSize> readArea) Synchronous NotStreamEncodable
void MultiDrawArraysANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t> firstsAndCounts)
void MultiDrawArraysInstancedANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t> firstsCountsAandInstanceCounts)
void MultiDrawElementsANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t> countsAndOffsets, uint32_t type)
void MultiDrawElementsInstancedANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t> countsOffsetsAndInstanceCounts, uint32_t type)
void MultiDrawArraysInstancedBaseInstanceANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t, uint32_t> firstsCountsInstanceCountsAndBaseInstances)
void MultiDrawElementsInstancedBaseVertexBaseInstanceANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t, int32_t, uint32_t> countsOffsetsInstanceCountsBaseVerticesAndBaseInstances, uint32_t type)
void DrawBuffers(std::span<const uint32_t> bufs)
void DrawBuffersEXT(std::span<const uint32_t> bufs)
void InvalidateFramebuffer(uint32_t target, std::span<const uint32_t> attachments)
void InvalidateSubFramebuffer(uint32_t target, std::span<const uint32_t> attachments, int32_t x, int32_t y, int32_t width, int32_t height)
#if ENABLE(WEBXR)
[EnabledBy=WebXREnabled] void FramebufferDiscard(uint32_t target, std::span<const uint32_t> attachments)
#endif
void SetDrawingBufferColorSpace(WebCore::DestinationColorSpace colorSpace)
{}
}}
#endif
"""
)
context_proxy_functions_fn = root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxyFunctionsGenerated.cpp"
context_proxy_functions_template = (
template_preamble
+ """
#include "config.h"
#include "RemoteGraphicsContextGLProxy.h"
#include <wtf/StdLibExtras.h>
#if ENABLE(GPU_PROCESS) && ENABLE(WEBGL)
namespace WebKit {{
{}
}}
#endif
"""
)
def write_file(fn, new_contents):
try:
with open(fn) as f:
if f.read() == new_contents:
return
except:
pass
with open(fn, "w") as f:
f.write(new_contents)
class cpp_type(object):
type_name: str
def __init__(self, type_name: str):
self.type_name = type_name
def __str__(self):
return self.type_name
def __hash__(self):
return hash(self.type_name)
def __repr__(self):
return self.type_name
def __eq__(self, other):
return self.type_name == other.type_name
def is_void(self) -> bool:
return self.type_name in ["void", "GCGLvoid", "const void", "const GCGLvoid"]
def is_const(self) -> bool:
return self.type_name.startswith("const ")
def is_container(self) -> bool:
return False
def is_output_buffer_type(self) -> bool:
return False
def is_span(self) -> bool:
return False
def is_dynamic_span(self) -> bool:
return False
def is_pointer(self) -> bool:
return False
def is_const_pointer(self) -> bool:
return False
def is_reference(self) -> bool:
return False
def is_rvalue_reference(self):
return False
def is_const_reference(self) -> bool:
return False
def get_value_type(self) -> "cpp_type":
return self
def get_decay_type(self) -> "cpp_type":
if self.is_const():
return get_cpp_type(self.type_name[6:])
return self
def get_rvalue_type(self) -> "cpp_type":
return get_cpp_type(self.type_name + "&&")
def get_pointer_type(self) -> "cpp_type":
return get_cpp_type(self.type_name + "*")
class cpp_type_container(cpp_type):
container_name: str
contained_type: cpp_type
arity: Optional[int]
def __init__(self, type_name: str, container_name: str, contained_type: cpp_type, arity: Optional[int] = None):
cpp_type.__init__(self, type_name)
self.container_name = container_name
self.contained_type = contained_type
self.arity = arity
def is_container(self) -> bool:
return True
def is_span(self) -> bool:
return self.container_name == "std::span"
def is_dynamic_span(self) -> bool:
return (self.container_name == "std::span" and self.arity is None) or self.container_name == "GCGLSpanTuple"
def is_array(self) -> bool:
return self.container_name == "std::array"
def get_container_name(self):
return self.container_name
def get_arity(self) -> Optional[int]:
return self.arity
def get_contained_type(self) -> cpp_type:
return self.contained_type
def is_output_buffer_type(self) -> bool:
return self.contained_type.is_const()
def create_cpp_type_container(type_name: str) -> Optional[cpp_type_container]:
# The logic to determine container is to just assume all templates are containers.
m = re.match(r"([\w:]+)<(.+)>$", type_name)
if not m:
return None
container_name = m[1]
# All templates are containers except these below.
if container_name in ["RefPtr", "Ref", "RetainPtr", "std::optional"]:
return None
templates = m[2]
arity = None
m = re.match(r"([^,]+),\s*(\d+)", templates)
if m:
templates = m[1]
arity = int(m[2])
return cpp_type_container(type_name, container_name, get_cpp_type(templates), arity)
class cpp_type_function(cpp_type):
def __init__(self, type_name: str, return_value_type: cpp_type, argument_types: List[cpp_type]):
cpp_type.__init__(self, type_name)
self.return_value_type = return_value_type
self.argument_types = argument_types
def cpp_split_args_specs(args_spec: str) -> Iterator[str]:
# https://stackoverflow.com/questions/33527245/python-split-by-comma-skipping-the-content-inside-parentheses
comma = r",(?!(?:[^<]*\<[^>]*\>)*[^<>]*\>)"
return filter(None, [a.strip() for a in re.split(comma, args_spec.strip())])
def create_cpp_type_function(type_name: str) -> Optional[cpp_type_function]:
m = re.match(r"(.*)\((.*)\)", type_name)
if not m:
return None
return_value_type = get_cpp_type(m[1])
args_types = [get_cpp_type(a) for a in cpp_split_args_specs(m[2])]
return cpp_type_function(type_name, return_value_type, args_types)
# Pointer or refererence
class cpp_type_indirect(cpp_type):
category: str
value_type: cpp_type
def __init__(self, type_name: str, category: str, value_type: cpp_type):
cpp_type.__init__(self, type_name)
self.category = category
self.value_type = value_type
def is_const_pointer(self):
return self.category == "*" and self.is_const()
def is_pointer(self):
return self.category == "*" and not self.is_const()
def is_const_reference(self):
return self.category == "&" and self.is_const()
def is_reference(self):
return self.category == "&" and not self.is_const()
def is_rvalue_reference(self):
return self.category == "&&"
def get_value_type(self):
return self.value_type
def create_cpp_type_indirect(type_name: str) -> Optional[cpp_type_indirect]:
m = re.match(r"const (.+)&&$", type_name)
if not m:
m = re.match(r"(.+)&&$", type_name)
if m:
return cpp_type_indirect(type_name, "&&", get_cpp_type(m[1]))
m = re.match(r"const (.+)&$", type_name)
if not m:
m = re.match(r"(.+)&$", type_name)
if m:
return cpp_type_indirect(type_name, "&", get_cpp_type(m[1]))
m = re.match(r"const (.+)\*$", type_name)
if not m:
m = re.match(r"(.+)\*$", type_name)
if m:
return cpp_type_indirect(type_name, "*", get_cpp_type(m[1]))
return None
class cpp_expr(object):
type: cpp_type
expr: str
def __init__(self, type: cpp_type, expr: str):
self.type = type
self.expr = expr
def __str__(self):
return self.expr
CppExprConverter = Callable[[cpp_expr, cpp_type], cpp_expr]
def cpp_reinterpret_cast_from_pointer_through(cast_through_type: cpp_type) -> Callable[[cpp_expr, cpp_type], cpp_expr]:
def cpp_reinterpret_cast_from_pointer(expr: cpp_expr, type: cpp_type) -> cpp_expr:
return cpp_expr(type, f"static_cast<{type.type_name}>(reinterpret_cast<{str(cast_through_type)}>({str(expr)}))")
return cpp_reinterpret_cast_from_pointer
def cpp_reinterpret_cast_to_pointer_through(cast_through_type: cpp_type) -> Callable[[cpp_expr, cpp_type], cpp_expr]:
def cpp_reinterpret_cast_to_pointer(expr: cpp_expr, type: cpp_type) -> cpp_expr:
return cpp_expr(type, f"reinterpret_cast<{type.type_name}>(static_cast<{str(cast_through_type)}>({str(expr)}))")
return cpp_reinterpret_cast_to_pointer
def cpp_static_cast(expr: cpp_expr, type: cpp_type) -> cpp_expr:
return cpp_expr(type, f"static_cast<{type.type_name}>({str(expr)})")
def cpp_implicit_cast(expr: cpp_expr, type: cpp_type) -> cpp_expr:
return cpp_expr(type, str(expr))
def cpp_array_reinterpret_cast_conversion(expr: cpp_expr, type: cpp_type_container) -> cpp_expr:
target_value_type = type.get_contained_type().get_decay_type()
target_arity = f", {type.arity}" if type.arity else ""
source_value_type = expr.type.get_contained_type().get_decay_type()
source_arity = f", {expr.type.arity}" if expr.type.arity else ""
if expr.type.is_array():
return cpp_expr(
type, f"spanReinterpretCast<const {target_value_type}{target_arity}>(std::span<const {source_value_type}{source_arity}>({str(expr)}))"
)
else:
return cpp_expr(type, f"spanReinterpretCast<const {target_value_type}{target_arity}>({str(expr)}.span())")
def cpp_move_expr(expr: cpp_expr) -> cpp_expr:
return cpp_expr(expr.type.get_rvalue_type(), f"WTF::move({str(expr)})")
cpp_types: Dict[str, cpp_type] = {}
cpp_type_constructors: List[Callable[[str], Optional[cpp_type]]] = [create_cpp_type_function, create_cpp_type_container, create_cpp_type_indirect]
def get_cpp_type(type_name: str):
r = cpp_types.get(type_name, None)
if r:
return r
for type_constr in cpp_type_constructors:
r = type_constr(type_name)
if r:
break
if not r:
r = cpp_type(type_name)
cpp_types[type_name] = r
return r
class cpp_arg(object):
name: str
type: cpp_type
def __init__(self, type: cpp_type, name: str):
self.name = name
self.type = type
def get_declaration(self):
if self.name == "completionHandler":
return "{}".format(self.type)
return str(self)
def __str__(self):
return "{} {}".format(self.type, self.name)
class cpp_decl(object):
type: cpp_type
name: str
def __init__(self, type: cpp_type, name: str):
self.type = type
self.name = name
def __str__(self):
return f"{str(self.type)} {self.name}"
class cpp_arg_list(object):
args: List[cpp_arg]
def __init__(self, args: List[cpp_arg]):
self.args = args
def names(self):
return ", ".join(a.name for a in self.args)
def exprs(self):
return [cpp_expr(a.type, a.name) for a in self.args]
def decls(self):
return [cpp_decl(a.type, a.name) for a in self.args]
def types(self):
return [a.type for a in self.args]
def get_declaration(self):
return ", ".join(a.get_declaration() for a in self.args)
def __str__(self):
return ", ".join(str(a) for a in self.args)
class cpp_func(object):
name: str
args: cpp_arg_list
return_type: cpp_type
enabled_by: str
message_check: str
cond: str
overload_suffix: str
def __init__(self, name: str, return_type: cpp_type, args: cpp_arg_list, enabled_by: str, message_check: str, cond: str):
self.name = name
self.return_type = return_type
self.args = args
self.enabled_by = enabled_by
self.message_check = message_check
self.cond = cond
self.overload_suffix = ""
def __str__(self):
return f"{self.return_type} {self.name}({str(self.args)})"
def get_args_categories(self) -> Tuple[List[cpp_arg], List[cpp_arg]]:
in_args = []
out_args = []
for a in self.args.args:
# fmt: off
if a.type.is_pointer() or \
a.type.is_reference():
out_args += [a]
elif isinstance(a.type, cpp_type_container) and (((a.type.is_span() or a.type.is_dynamic_span()) and not a.type.get_contained_type().is_const())):
out_args += [a]
else:
in_args += [a]
# fmt: on
return in_args, out_args
def is_implemented_type(self, type: cpp_type):
if type.is_const_pointer():
return False
return True
def is_implemented(self):
# " in a.type.type_name for a in self.args.args):
# return False
# if "GCGLsync" in self.return_type.type_name:
# return False
if any(a.name == "bufSize" for a in self.args.args):
return False
if any(a.type.is_pointer() and a.type.get_value_type().is_void() for a in self.args.args):
return False
if any(not self.is_implemented_type(a.type) for a in self.args.args):
return False
if self.return_type.is_pointer():
return False
if not self.is_implemented_type(self.return_type):
return False
return True
webkit_ipc_types: Dict[cpp_type, cpp_type] = {}
webkit_ipc_types_converters: Dict[Tuple[cpp_type, cpp_type], CppExprConverter] = {}
def webkit_ipc_convert_expr(expr: cpp_expr, type: cpp_type) -> cpp_expr:
"""Converts `expr` of type of `self` to `type`"""
convert = webkit_ipc_types_converters.get((expr.type, type), None)
if convert:
return convert(expr, type)
if expr.type == type:
return expr
elif expr.type.is_rvalue_reference() and expr.type.get_value_type() == type:
return webkit_ipc_move_expr(expr)
elif type.is_rvalue_reference() and type.get_value_type() == expr.type:
return webkit_ipc_move_expr(expr)
return cpp_implicit_cast(expr, type)
def webkit_ipc_get_span_transfer_type(type: cpp_type_container) -> cpp_type:
element_type = type.get_contained_type().get_decay_type()
arity = type.get_arity()
webkit_ipc_element_type = webkit_ipc_types[element_type] if not element_type.is_void() else get_cpp_type("uint8_t")
if arity is not None:
return get_cpp_type(f"std::span<const {str(webkit_ipc_element_type)}, {arity}>")
return get_cpp_type(f"std::span<const {str(webkit_ipc_element_type)}>")
def webkit_ipc_get_span_store_type(type: cpp_type_container) -> cpp_type:
element_type = type.get_contained_type().get_decay_type()
if element_type.is_void():
element_type = get_cpp_type("GCGLchar")
if type.is_dynamic_span():
inline_capacity = 16 if "float" in element_type.type_name else 4
return get_cpp_type(f"Vector<{str(element_type)}, {str(inline_capacity)}>")
return get_cpp_type(f"std::array<{str(element_type)}, {str(type.get_arity())}>")
# See messages.py function_parameter_type
webkit_ipc_builtin_types = set(
["uint8_t", "uint16_t", "uint32_t", "uint64_t", "int8_t", "int16_t", "int32_t", "int64_t", "bool", "float", "double" "bool"]
)
def webkit_ipc_get_message_forwarder_type(type: cpp_type) -> cpp_type:
if type.type_name in webkit_ipc_builtin_types:
return type
return type.get_rvalue_type()
def webkit_ipc_move_expr(expr: cpp_expr) -> cpp_expr:
if expr.type.type_name in webkit_ipc_builtin_types:
return expr
return cpp_move_expr(expr)
def webkit_ipc_msg_name(func: cpp_func):
return func.name[0].capitalize() + func.name[1:] + func.overload_suffix
def to_variable_name(name: str) -> str:
return name[0].lower() + name[1:]
def to_member_variable_name(name: str) -> str:
return f"m_{to_variable_name(name)}"
def is_create_func(func: cpp_func) -> bool:
return func.name.startswith("create")
def get_create_func_object_name(name: str) -> str:
return name[len("create") :]
def is_delete_func(func: cpp_func) -> bool:
return func.name.startswith("delete")
def get_delete_func_object_name(name: str) -> str:
return name[len("delete") :]
def webkit_ipc_msg_arg_type(cpp_type: cpp_type) -> cpp_type:
ipc_type = webkit_ipc_types[cpp_type]
# FIXME: the messages.py generator should read the serializers and not need this.
if ipc_type == get_cpp_type("WebCore::GraphicsContextGLFlipY"):
return get_cpp_type("enum:bool WebCore::GraphicsContextGLFlipY")
if ipc_type == get_cpp_type("WebCore::GraphicsContextGLSimulatedEventForTesting"):
return get_cpp_type("enum:uint8_t WebCore::GraphicsContextGLSimulatedEventForTesting")
return ipc_type
# FIXME: these should be removed and IPC should know this.
non_stream_types = set({"WebCore::GraphicsContextGL::ExternalImageSource&&", "WebCore::GraphicsContextGL::ExternalSyncSource&&"})
class webkit_ipc_msg(object):
cond: str
enabled_by: str
name: str
in_args: cpp_arg_list
out_args: cpp_arg_list
def __init__(self, func: cpp_func):
self.cond = func.cond
self.enabled_by = func.enabled_by
self.name = webkit_ipc_msg_name(func)
in_args, out_args = func.get_args_categories()
ipc_in_args = [cpp_arg(webkit_ipc_msg_arg_type(a.type), a.name) for a in in_args]
ipc_out_args = []
if is_create_func(func):
name = get_create_func_object_name(func.name)
ipc_in_args.insert(0, cpp_arg(webkit_ipc_types[func.return_type], to_variable_name(name)))
elif not func.return_type.is_void():
ipc_out_args += [cpp_arg(webkit_ipc_types[func.return_type], "returnValue")]
for a in out_args:
ipc_out_args += [cpp_arg(webkit_ipc_types[a.type], a.name)]
if a.type.is_dynamic_span():
ipc_in_args += [cpp_arg(get_cpp_type("uint64_t"), f"{a.name}Size")]
self.in_args = cpp_arg_list(ipc_in_args)
self.out_args = cpp_arg_list(ipc_out_args)
self.tags = []
if any(arg.type.type_name in non_stream_types for arg in in_args):
self.tags += ["NotStreamEncodable"]
def __str__(self):
tags = f" {' '.join(self.tags)}" if self.tags else ""
enabled_by = f"[EnabledBy={self.enabled_by}] " if self.enabled_by else ""
if len(self.out_args.args):
return f"\n {enabled_by}void {self.name}({str(self.in_args)}) -> ({str(self.out_args)}) Synchronous{tags}"
return f"\n {enabled_by}void {self.name}({str(self.in_args)}){tags}"
class webkit_ipc_cpp_proxy_impl(object):
cond: str
name: str
is_create: bool
msg_name: str
return_type: cpp_type
args: cpp_arg_list
pre_call_stmts: List[str]
call_stmts: List[str]
post_call_stmts: List[str]
return_stmts: List[str]
in_exprs: List[cpp_expr]
out_exprs: List[cpp_expr]
def __init__(self, cpp_func: cpp_func):
self.cond = cpp_func.cond
self.name = cpp_func.name
self.is_create = is_create_func(cpp_func)
self.msg_name = webkit_ipc_msg_name(cpp_func)
self.return_type = cpp_func.return_type
self.args = cpp_func.args
self.pre_call_stmts = []
self.call_stmts = []
self.post_call_stmts = []
self.return_stmts = []
self.in_exprs = []
self.out_exprs = []
in_args, out_args = cpp_func.get_args_categories()
self.process_return_value(cpp_func.return_type)
self.process_in_args(in_args)
self.process_out_args(out_args)
self.process_call()
def process_call(self):
in_exprs = ", ".join([str(i) for i in self.in_exprs])
out_exprs = ", ".join(str(o) for o in self.out_exprs)
is_async = (self.return_type.is_void() or self.is_create) and len(out_exprs) == 0
self.call_stmts += ["if (isContextLost())"]
if self.return_type.is_void():
self.call_stmts += [" return;"]
else:
self.call_stmts += [" return { };"]
if self.is_create:
self.call_stmts += [f"auto name = createObjectName();"]
if is_async:
self.call_stmts += [
f"auto sendResult = send(Messages::RemoteGraphicsContextGL::{self.msg_name}({in_exprs}));",
"if (sendResult != IPC::Error::NoError) {",
]
else:
self.call_stmts += [
f"auto sendResult = sendSync(Messages::RemoteGraphicsContextGL::{self.msg_name}({in_exprs}));",
"if (!sendResult.succeeded()) {",
]
if self.return_type.is_void():
self.call_stmts += [
" markContextLost();",
" return;",
"}",
]
else:
self.call_stmts += [
" markContextLost();",
" return { };",
"}",
]
def process_in_args(self, in_args: List[cpp_arg]):
if self.is_create:
self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(self.return_type, "name"), webkit_ipc_types[self.return_type])]
for i in in_args:
if i.type.is_const_pointer():
assert False
else:
self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(i.type, i.name), webkit_ipc_types[i.type])]
def process_out_args(self, out_args: List[cpp_arg]):
for o in out_args:
if o.type.is_pointer():
value_type = o.type.get_value_type()
webkit_ipc_value_type = webkit_ipc_types[value_type]
v = cpp_arg(webkit_ipc_value_type, o.name + "Reply")
e = cpp_expr(v.type, v.name)
self.out_exprs += [e]
self.post_call_stmts += [
# fmt: off
f"if ({o.name})",
f" *{o.name} = {webkit_ipc_convert_expr(e, value_type)};"
# fmt: on
]
elif o.type.is_reference():
value_type = o.type.get_value_type()
v = cpp_arg(value_type, o.name + "Reply")
e = cpp_expr(v.type, v.name)
self.out_exprs += [e]
self.post_call_stmts += [
f"{o.name} = WTF::move({v.name});",
]
elif o.type.is_span():
webkit_ipc_type = webkit_ipc_types[o.type]
assert isinstance(webkit_ipc_type, cpp_type_container)
v = cpp_arg(webkit_ipc_type, o.name + "Reply")
self.out_exprs += [cpp_expr(v.type, v.name)]
if o.type.is_dynamic_span():
self.in_exprs += [cpp_expr(get_cpp_type("size_t"), f"{o.name}.size()")]
self.post_call_stmts += [f"memcpySpan({o.name}, {v.name});"]
else:
self.out_exprs += [cpp_expr(o.type, o.name)]
if self.out_exprs:
out_exprs = ", ".join(str(o) for o in self.out_exprs)
self.post_call_stmts = [
f"auto& [{out_exprs}] = sendResult.reply();",
] + self.post_call_stmts
def process_return_value(self, return_type: cpp_type):
if return_type.is_void():
return
if self.is_create:
self.return_stmts = [f"return name;"]
return
self.return_type = return_type
ipc_return_type = webkit_ipc_types[return_type]
return_value_expr = cpp_expr(ipc_return_type, "returnValue")
self.out_exprs = [return_value_expr] + self.out_exprs
self.return_stmts = [f"return {str(webkit_ipc_convert_expr(return_value_expr, return_type))};"]
def __str__(self):
nolint = " // NOLINT" if "_" in self.name else ""
body = "".join(f"\n {b}" for b in self.pre_call_stmts + self.call_stmts + self.post_call_stmts + self.return_stmts)
return f"""\n{str(self.return_type)} RemoteGraphicsContextGLProxy::{self.name}({str(self.args)}){nolint}
{{{body}
}}"""
class webkit_ipc_cpp_proxy_placeholder(object):
name: str
return_type: cpp_type
args: cpp_arg_list
body: List[str]
def __init__(self, cpp_func: cpp_func):
self.name = cpp_func.name
self.return_type = cpp_func.return_type
self.args = cpp_func.args
self.body = ["notImplemented();"]
if cpp_func.return_type.type_name != "void":
self.body += ["return { };"]
def __str__(self):
nolint = " // NOLINT" if "_" in self.name else ""
body = "\n{\n " + "\n ".join(self.body) + "\n}"
return f"\n{str(self.return_type)} RemoteGraphicsContextGLProxy::{self.name}({str(self.args)}){nolint}{body}"
class context_proxy_cpp_webkit_ipc_generator(object):
"RemoteGraphicsContextGLProxy C++ implementation generator."
impls: List[webkit_ipc_cpp_proxy_impl]
unimpls: List[webkit_ipc_cpp_proxy_placeholder]
cond: str
def __init__(self, funcs: Iterable[cpp_func], unimplemented: Iterable[cpp_func]):
self.impls = [webkit_ipc_cpp_proxy_impl(f) for f in funcs]
self.unimpls = [webkit_ipc_cpp_proxy_placeholder(f) for f in unimplemented]
self.cond = ""
def open_cond(self, impl):
if self.cond != impl.cond:
close_cond = "#endif\n" if self.cond else ""
open_cond = f"\n#if {impl.cond}" if impl.cond else ""
self.cond = impl.cond
return f"{close_cond}{open_cond}"
return ""
def close_cond(self):
if self.cond:
self.cond = ""
return "\n#endif"
return ""
def get_functions(self):
return "\n".join(f"{self.open_cond(i)}{i}" for i in self.impls) + self.close_cond() + "\n".join(str(i) for i in self.unimpls)
def generate(self):
write_file(
context_proxy_functions_fn,
context_proxy_functions_template.format(self.get_functions()),
)
named_object_types = set(["PlatformGLObject", "GCGLExternalImage", "GCGLExternalSync"])
class webkit_ipc_cpp_impl(object):
cond: str
name: str
enabled_by: str
args: cpp_arg_list
pre_call_stmts: List[str]
call_stmts: List[str]
post_call_stmts: List[str]
in_exprs: List[cpp_expr]
out_exprs: List[cpp_expr]
return_value_expr: Optional[cpp_expr]
def __init__(self, cpp_func: cpp_func):
self.cond = cpp_func.cond
self.name = cpp_func.name
self.message_check = cpp_func.message_check
self.is_create = is_create_func(cpp_func)
self.is_delete = is_delete_func(cpp_func)
self.overload_suffix = cpp_func.overload_suffix
self.args = cpp_arg_list([])
self.pre_call_stmts = []
self.call_stmts = []
self.post_call_stmts = []
self.in_exprs = []
self.out_exprs = []
self.return_value_expr = None
self.pre_call_stmts += ["assertIsCurrent(workQueue());"]
if self.message_check:
self.pre_call_stmts += [f"MESSAGE_CHECK({self.message_check});"]
self.process_return_value(cpp_func.return_type)
in_args, out_args = cpp_func.get_args_categories()
self.process_args(cpp_func.args.args, set(in_args), set(out_args))
self.process_call()
def process_call(self):
in_exprs = ", ".join(str(e) for e in self.in_exprs)
is_async = len(self.out_exprs) == 0
call_expr = f"protectedContext()->{self.name}({in_exprs})"
if not self.return_value_expr:
self.call_stmts += [f"{call_expr};"]
else:
self.call_stmts += [f"{str(self.return_value_expr)} = {call_expr};"]
if not is_async:
out_exprs = ", ".join(str(e) for e in self.out_exprs)
self.post_call_stmts += [f"completionHandler({out_exprs});"]
def process_args(self, args: List[cpp_arg], in_args: Set[cpp_arg], out_args: Set[cpp_arg]):
for a in args:
if a.type.is_const_pointer():
assert False
if a in in_args:
self.process_in_arg(a)
else:
self.process_out_arg(a)
if self.out_exprs:
out_arg_decls = ", ".join(f"{str(e.type)}" for e in self.out_exprs)
self.args.args += [cpp_arg(get_cpp_type(f"CompletionHandler<void({out_arg_decls})>&&"), "completionHandler")]
def process_in_arg(self, a: cpp_arg):
self.args.args += [cpp_arg(webkit_ipc_get_message_forwarder_type(webkit_ipc_types[a.type]), a.name)]
self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(webkit_ipc_types[a.type], a.name), a.type)]
if a.type.type_name in named_object_types:
if self.is_create:
self.pre_call_stmts += [f"MESSAGE_CHECK({a.name});"]
if self.is_delete:
self.pre_call_stmts += [
f"MESSAGE_CHECK(m_objectNames.isValidKey({a.name}));",
f"if (!{a.name}) [[unlikely]]",
f" return;",
f"{a.name} = m_objectNames.take({a.name});",
]
else:
self.pre_call_stmts += [
f"MESSAGE_CHECK(m_objectNames.isValidKey({a.name}));",
f"if ({a.name})",
f" {a.name} = m_objectNames.get({a.name});",
]
def process_out_arg(self, a: cpp_arg):
if a.type.is_pointer():
value_arg = cpp_arg(a.type.get_value_type(), a.name)
self.pre_call_stmts += [f"{str(value_arg.type)} {str(value_arg.name)} = {{ }};"]
self.in_exprs += [cpp_expr(a.type, f"&{value_arg.name}")]
e = cpp_expr(value_arg.type, value_arg.name)
webkit_ipc_value_type = webkit_ipc_types[e.type]
self.out_exprs += [webkit_ipc_convert_expr(e, webkit_ipc_value_type)]
elif a.type.is_dynamic_span():
assert isinstance(a.type, cpp_type_container)
size_arg = cpp_arg(get_cpp_type("uint64_t"), f"{a.name}Size")
self.args.args += [size_arg]
store_arg = cpp_arg(webkit_ipc_get_span_store_type(a.type), a.name)
inline_capacity = store_arg.type.arity
contained_type = a.type.contained_type.type_name
self.pre_call_stmts += [f"if (!WTF::isValidCapacityForVector<{contained_type}>({a.name}Size))"]
self.pre_call_stmts += [f" {a.name}Size = {inline_capacity};"]
self.pre_call_stmts += [f"{str(store_arg.type)} {str(store_arg.name)}({a.name}Size, 0);"]
self.in_exprs += [cpp_expr(store_arg.type, f"{store_arg.name}")]
webkit_ipc_type = webkit_ipc_types[a.type]
self.out_exprs += [webkit_ipc_convert_expr(cpp_expr(store_arg.type, store_arg.name), webkit_ipc_type)]
elif a.type.is_span():
assert isinstance(a.type, cpp_type_container)
store_arg = cpp_arg(webkit_ipc_get_span_store_type(a.type), a.name)
self.pre_call_stmts += [f"{str(store_arg.type)} {str(store_arg.name)} {{ }};"]
self.in_exprs += [cpp_expr(store_arg.type, store_arg.name)]
webkit_ipc_type = webkit_ipc_types[a.type]
self.out_exprs += [webkit_ipc_convert_expr(cpp_expr(store_arg.type, store_arg.name), webkit_ipc_type)]
else:
assert a.type.is_reference()
webkit_ipc_type = webkit_ipc_types[a.type]
value_arg = cpp_arg(a.type.get_value_type(), a.name)
self.pre_call_stmts += [f"{self.ns(value_arg.type)} {str(value_arg.name)} {{ }};"]
e = cpp_expr(value_arg.type, value_arg.name)
self.in_exprs += [e]
self.out_exprs += [webkit_ipc_move_expr(webkit_ipc_convert_expr(e, webkit_ipc_type))]
def process_return_value(self, return_type: cpp_type):
if self.is_create:
ipc_return_type = webkit_ipc_types[return_type]
self.args.args += [cpp_arg(webkit_ipc_get_message_forwarder_type(ipc_return_type), "name")]
return_value_expr = cpp_expr(return_type, f"auto result")
self.return_value_expr = return_value_expr
self.pre_call_stmts += [f"MESSAGE_CHECK(m_objectNames.isValidKey(name));"]
self.post_call_stmts += [f"if (result)", f" m_objectNames.add(name, result);"]
return
if return_type.is_void():
return
ipc_return_type = webkit_ipc_types[return_type]
return_value_expr = cpp_expr(return_type, "returnValue")
self.pre_call_stmts += [f"{return_value_expr.type} {return_value_expr.expr} = {{ }};"]
self.out_exprs += [webkit_ipc_move_expr(webkit_ipc_convert_expr(return_value_expr, ipc_return_type))]
self.return_value_expr = return_value_expr
def get_declaration(self):
nolint = " // NOLINT" if "_" in self.name else ""
return f""" void {self.name}{self.overload_suffix}({self.args.get_declaration()});{nolint}"""
def get_definition(self):
nolint = " // NOLINT" if "_" in self.name else ""
body = "".join(f"\n {b}" for b in self.pre_call_stmts + self.call_stmts + self.post_call_stmts)
return f"""void RemoteGraphicsContextGL::{self.name}{self.overload_suffix}({str(self.args)}){nolint}
{{{body}
}}
"""
def ns(self, type: cpp_type):
# TODO: namespace info is not stored in names.
if type.type_name == "ActiveInfo":
return "WebCore::GraphicsContextGL::" + str(type)
return str(type)
def webkit_ipc_resolve_overload_suffix(funcs: Iterable[cpp_func]):
counts = collections.Counter(f.name for f in funcs)
suffixes: Counter[str] = collections.Counter()
for f in funcs:
if counts[f.name] > 1:
f.overload_suffix = str(suffixes[f.name])
suffixes.update([f.name])
class context_cpp_webkit_ipc_generator(object):
"RemoteGraphicsContextGL C++ implementation generator."
impls: List[webkit_ipc_cpp_impl]
cond: str
def __init__(self, funcs: Iterable[cpp_func]):
self.impls = [webkit_ipc_cpp_impl(f) for f in funcs]
self.cond = ""
def open_cond(self, impl):
if self.cond != impl.cond:
close_cond = "#endif\n" if self.cond else ""
open_cond = f"#if {impl.cond}\n" if impl.cond else ""
self.cond = impl.cond
return f"{close_cond}{open_cond}"
return ""
def close_cond(self):
if self.cond:
self.cond = ""
return "\n#endif"
return ""
def get_declarations(self):
return "\n".join(f"{self.open_cond(i)}{i.get_declaration()}" for i in self.impls) + self.close_cond()
def get_definitions(self):
return "\n".join(f"{self.open_cond(i)}{i.get_definition()}" for i in self.impls) + self.close_cond()
def generate(self):
write_file(
context_functions_header_fn,
context_functions_header_template.format(self.get_declarations()),
)
write_file(
context_functions_impl_fn,
context_functions_impl_template.format(self.get_definitions()),
)
class context_msg_webkit_ipc_generator(object):
"RemoteGraphicsContextGL WebKit IPC message definition generator."
msgs: List[webkit_ipc_msg]
cond: str
def __init__(self, funcs: Iterable[cpp_func]):
self.msgs = [webkit_ipc_msg(f) for f in funcs]
self.cond = ""
def open_cond(self, msg):
if self.cond != msg.cond:
close_cond = "\n#endif" if self.cond else ""
open_cond = f"\n#if {msg.cond}" if msg.cond else ""
self.cond = msg.cond
return f"{close_cond}{open_cond}"
return ""
def close_cond(self):
if self.cond:
self.cond = ""
return "\n#endif"
return ""
def get_messages(self):
return "".join(f"{self.open_cond(m)}{m}" for m in self.msgs) + self.close_cond()
def generate(self):
write_file(context_messages_fn, context_messages_template.format(self.get_messages()))
def create_cpp_arg(arg_spec: str, arg_index: int):
r = arg_spec.rsplit(" ", 1)
name = ""
type = None
if len(r) > 1 and r[0] != "const":
name = r[1].strip()
type = get_cpp_type(r[0])
else:
name = "arg{}".format(arg_index)
type = get_cpp_type(arg_spec)
return cpp_arg(type, name)
def create_cpp_arg_list(args_specs: Iterable[str]):
return cpp_arg_list([create_cpp_arg(arg_spec=e, arg_index=i) for i, e in enumerate(args_specs)])
def create_cpp_func(name: str, return_spec: str, args_specs: List[str], enabled_by: str, message_check: str, cond: str):
return cpp_func(
name=name,
return_type=get_cpp_type(return_spec),
args=create_cpp_arg_list(args_specs),
enabled_by=enabled_by,
message_check=message_check,
cond=cond,
)
def read_lines_until(lines: Iterable[str], match: str) -> Generator[str, None, None]:
for line in lines:
if re.match(match, line.strip()):
break
yield line
def main():
parser = argparse.ArgumentParser("usage: %prog [options]")
parser.add_argument("--verbose", action="store_true", help="Print some debug info from the generator script")
options = parser.parse_args()
# Construct the list of functions to remote from web process to GPU process.
funcs = []
unimplemented = []
cond = ""
message_checks = {}
for fn in functions_input_fns:
with open(fn) as f:
lines = iter(f.readlines())
for _ in read_lines_until(lines, "// Functions with a generated implementation. This list is used by generate-gpup-webgl script."):
pass
for line in read_lines_until(lines, "// End of list used by generate-gpup-webgl script."):
m = re.match(r"\s*#\s*if\s+(.*\S)\s*$", line)
if m:
# FIXME: Nested conditions are not handled
cond = m[1]
continue
m = re.match(r"\s*#\s*endif", line)
if m:
cond = ""
continue
m = re.match(r"\s*(\S+)\s+(\w+)\((.*?)\)\s+(IPC_ENABLED_BY_AND_MESSAGE_CHECK\((\S+?)\s*,\s*(\S+?)\)\s+)?final;", line)
if m:
func_name = m[2]
func = create_cpp_func(
name=func_name, return_spec=m[1], args_specs=cpp_split_args_specs(m[3]), enabled_by=m[5], message_check=m[6], cond=cond
)
if func.is_implemented():
funcs.append(func)
else:
unimplemented.append(func)
webkit_ipc_resolve_overload_suffix(funcs)
# Initialize WebKit IPC generation. Construct type mappings for the used C++ types -> IPC types.
# Populate types that are needed but not present in the interfaces.
for needed in ["unsigned"]:
cpp_type = get_cpp_type(needed)
webkit_ipc_types[cpp_type] = cpp_type
size_t_cpp_type = get_cpp_type("size_t")
webkit_ipc_types[size_t_cpp_type] = get_cpp_type("uint64_t")
active_info_types = set(["WebCore::GCGLAttribActiveInfo", "WebCore::GCGLUniformActiveInfo", "WebCore::GCGLTransformFeedbackActiveInfo"])
for builtin_type in webkit_ipc_builtin_types | active_info_types:
cpp_type = get_cpp_type(builtin_type)
webkit_ipc_types[cpp_type] = cpp_type
with open(types_input_fn) as f:
lines = iter(f.readlines())
for _ in read_lines_until(lines, "// The GCGL types map to following WebKit IPC types. The list is used by generate-gpup-webgl script."):
pass
for line in read_lines_until(lines, "// End of list used by generate-gpup-webgl script."):
m = re.match(r".*static_assert\(std::is_same_v<(\w+), (\w+)>\);", line)
if m:
webkit_ipc_types[get_cpp_type(m[1])] = get_cpp_type(m[2])
continue
m = re.match(r".*static_assert\(sizeof\((\w+)\) == sizeof\((\w+)\)\);", line)
if m:
cpp_type = get_cpp_type(m[1])
ipc_type = get_cpp_type(m[2])
webkit_ipc_types[cpp_type] = ipc_type
webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_static_cast
webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_static_cast
continue
# FIXME: Here we use <= instead of == due to pointers, such as GCGLsync, GCGLintptr, ....
# This ends up failing if there ever is arrays of these types, since arrays are currently
# reinterpret-casted.
# WebKit IPC requires one sized type, but the size of these pointer-based values will change
# based on the platform.
m = re.match(r".*static_assert\(sizeof\((\w+)\) <= sizeof\((\w+)\)\);", line)
if m:
cpp_type = get_cpp_type(m[1])
ipc_type = get_cpp_type(m[2])
webkit_ipc_types[cpp_type] = ipc_type
webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_static_cast
webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_static_cast
continue
m = re.match(r".*static_assert\(sizeof\((\w+)\) <= sizeof\((\w+)\) && sizeof\((\w+)\) == sizeof\((\w+)\)\);", line)
if m:
cpp_type = get_cpp_type(m[1])
ipc_type = get_cpp_type(m[2])
cpp_cast_through_type = get_cpp_type(m[4])
webkit_ipc_types[cpp_type] = ipc_type
webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_reinterpret_cast_from_pointer_through(cpp_cast_through_type)
webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_reinterpret_cast_to_pointer_through(cpp_cast_through_type)
continue
# For all types in the input API, form corresponding IPC types and conversions.
# TODO: this is not driven by the typing.
all_types = set()
for func in funcs:
all_types.update(func.args.types() + [func.return_type])
# Sort by len so that template args come before templates.
for cpp_type in sorted(all_types, key=lambda x: len(x.type_name)):
if cpp_type in webkit_ipc_types:
continue
if cpp_type.is_dynamic_span() or cpp_type.is_span():
transfer_type = webkit_ipc_get_span_transfer_type(cpp_type)
webkit_ipc_types[cpp_type] = transfer_type.get_value_type()
store_type = webkit_ipc_get_span_store_type(cpp_type)
webkit_ipc_types_converters[(store_type, transfer_type)] = cpp_array_reinterpret_cast_conversion
elif cpp_type.is_reference() or cpp_type.is_const_reference() or cpp_type.is_container():
value_type = cpp_type.get_value_type() if not cpp_type.is_container() else cpp_type
if value_type.is_container():
contained_type = value_type.get_contained_type()
webkit_ipc_contained_type = webkit_ipc_types[contained_type]
if webkit_ipc_contained_type == contained_type:
webkit_ipc_types[cpp_type] = value_type
else:
transfer_type = get_cpp_type(f"{value_type.get_container_name()}<{str(webkit_ipc_contained_type)}>")
webkit_ipc_types[cpp_type] = transfer_type
# TODO: Here might be case where Vector<GCGLint> was used in the interface and Vector<int32_t> is used
# in the IPC definition. There is no sensible way to do this at the moment. We do not convert, rather
# expect that all the invocations are taken care of the fact that GCGLint is the same type as int32_t.
# This will not hold for all types such as GCGLboolean.
# webkit_ipc_types_converters[(cpp_type, transfer_type)] = cpp_array_reinterpret_cast_conversion
else:
webkit_ipc_types[cpp_type] = value_type
elif cpp_type.is_rvalue_reference():
webkit_ipc_types[cpp_type] = cpp_type.get_value_type()
else:
webkit_ipc_types[cpp_type] = cpp_type.get_value_type()
# The input to the generators is list of functions to remote.
# Run the various generators.
generators = [
context_proxy_cpp_webkit_ipc_generator(funcs, unimplemented),
context_msg_webkit_ipc_generator(funcs),
context_cpp_webkit_ipc_generator(funcs),
]
for g in generators:
g.generate()
if options.verbose:
print("Implemented:")
print("".join(f" {str(i)} final\n" for i in funcs))
print("Unimplemented:")
print("".join(f" {str(u)} final\n" for u in unimplemented))
print(f"Implemented: {len(funcs)}, unimplemented: {len(unimplemented)}, total: {len(funcs)+len(unimplemented)}")
print("C++ type map to WebKit IPC type map:")
for _, t in cpp_types.items():
if t in webkit_ipc_types:
print(f" {str(t)} -> {str(webkit_ipc_types[t])}")
print("C++ types without WebKit IPC type:")
for _, t in cpp_types.items():
if t not in webkit_ipc_types:
print(f" {str(t)}")
print("WebKit IPC type conversions")
for (a, b), converter in webkit_ipc_types_converters.items():
print(f" {str(a)} -> {str(b)} : {converter.__name__}")
print("Done.")
return 0
if __name__ == "__main__":
sys.exit(main())