ipc/ipdl/ipdl.py
author Bas Schouten <bschouten@mozilla.com>
Tue, 26 Feb 2019 08:46:08 +0100
changeset 513319 46f0f4418eddc69b08f223b7766ef55725df3920
parent 507243 0bb1f2417265f9c9fbcf1a07f553ea08ad7308d5
child 535153 15293a40e833a9b6159d7e4114f7167a3a39e85b
permissions -rwxr-xr-x
Bug 1526045 - Part 2: Verify all DrawTargets created through CreateOffscreenContentDrawTarget. r=rhunt a=lizzard Preferrably CreateOffscreenContentDrawTarget would create Capture DrawTargets when we intend to use OMTP. This is not the case at the moment though and changing this would likely introduce more unforseen issues. For now all of these calls basically mean a DrawTarget will be used on the main thread and we should use a no-op ClearRect to ensure that the DrawTarget is actually initialized. Since IsValid for the moment won't do this for DrawTargetD2D. (See bug 1521368)

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import print_function

import optparse
import os
import sys
from cStringIO import StringIO
from ConfigParser import RawConfigParser

import ipdl


def log(minv, fmt, *args):
    if _verbosity >= minv:
        print(fmt % args)

# process command line


op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
op.add_option('-I', '--include', dest='includedirs', default=[],
              action='append',
              help='Additional directory to search for included protocol specifications')
op.add_option('-s', '--sync-msg-list', dest='syncMsgList', default='sync-messages.ini',
              help="Config file listing allowed sync messages")
op.add_option('-m', '--msg-metadata', dest='msgMetadata', default='message-metadata.ini',
              help="Predicted message sizes for reducing serialization malloc overhead.")
op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
              help='Verbose logging (specify -vv or -vvv for very verbose logging)')
op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
              help="Suppress logging output")
op.add_option('-d', '--outheaders-dir', dest='headersdir', default='.',
              help="""Directory into which C++ headers will be generated.
A protocol Foo in the namespace bar will cause the headers
  dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
to be generated""")
op.add_option('-o', '--outcpp-dir', dest='cppdir', default='.',
              help="""Directory into which C++ sources will be generated
A protocol Foo in the namespace bar will cause the sources
  cppdir/FooParent.cpp, cppdir/FooChild.cpp
to be generated""")

options, files = op.parse_args()
_verbosity = options.verbosity
syncMsgList = options.syncMsgList
msgMetadata = options.msgMetadata
headersdir = options.headersdir
cppdir = options.cppdir
includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]

if not len(files):
    op.error("No IPDL files specified")

ipcmessagestartpath = os.path.join(headersdir, 'IPCMessageStart.h')
ipc_msgtype_name_path = os.path.join(cppdir, 'IPCMessageTypeName.cpp')

log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
log(2, 'Generated C++ sources will be generated in "%s"', cppdir)

allmessages = {}
allmessageprognames = []
allprotocols = []


def normalizedFilename(f):
    if f == '-':
        return '<stdin>'
    return f


log(2, 'Reading sync message list')
parser = RawConfigParser()
parser.readfp(open(options.syncMsgList))
syncMsgList = parser.sections()

# Read message metadata. Right now we only have 'segment_capacity'
# for the standard segment size used for serialization.
log(2, 'Reading message metadata...')
msgMetadataConfig = RawConfigParser()
msgMetadataConfig.readfp(open(options.msgMetadata))

segmentCapacityDict = {}
for msgName in msgMetadataConfig.sections():
    if msgMetadataConfig.has_option(msgName, 'segment_capacity'):
        capacity = msgMetadataConfig.get(msgName, 'segment_capacity')
        segmentCapacityDict[msgName] = capacity

# First pass: parse and type-check all protocols
for f in files:
    log(2, os.path.basename(f))
    filename = normalizedFilename(f)
    if f == '-':
        fd = sys.stdin
    else:
        fd = open(f)

    specstring = fd.read()
    fd.close()

    ast = ipdl.parse(specstring, filename, includedirs=includedirs)
    if ast is None:
        print('Specification could not be parsed.', file=sys.stderr)
        sys.exit(1)

    log(2, 'checking types')
    if not ipdl.typecheck(ast):
        print('Specification is not well typed.', file=sys.stderr)
        sys.exit(1)

    if not ipdl.checkSyncMessage(ast, syncMsgList):
        print('Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s' % options.syncMsgList, file=sys.stderr)  # NOQA: E501
        sys.exit(1)

if not ipdl.checkFixedSyncMessages(parser):
    # Errors have alraedy been printed to stderr, just exit
    sys.exit(1)

# Second pass: generate code
for f in files:
    # Read from parser cache
    filename = normalizedFilename(f)
    ast = ipdl.parse(None, filename, includedirs=includedirs)
    ipdl.gencxx(filename, ast, headersdir, cppdir, segmentCapacityDict)

    if ast.protocol:
        allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
        allprotocols.append('%sMsgStart' % ast.protocol.name)
        # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
        for md in ast.protocol.messageDecls:
            allmessageprognames.append('%s::%s' % (md.namespace, md.decl.progname))

allprotocols.sort()

# Check if we have undefined message names in segmentCapacityDict.
# This is a fool-proof of the 'message-metadata.ini' file.
undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
if len(undefinedMessages) > 0:
    print('Error: Undefined message names in message-metadata.ini:', file=sys.stderr)
    print(undefinedMessages, file=sys.stderr)
    sys.exit(1)

ipcmsgstart = StringIO()

print("""
// CODE GENERATED by ipdl.py. Do not edit.

#ifndef IPCMessageStart_h
#define IPCMessageStart_h

enum IPCMessageStart {
""", file=ipcmsgstart)

for name in allprotocols:
    print("  %s," % name, file=ipcmsgstart)

print("""
  LastMsgIndex
};

static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");

#endif // ifndef IPCMessageStart_h
""", file=ipcmsgstart)

ipc_msgtype_name = StringIO()
print("""
// CODE GENERATED by ipdl.py. Do not edit.
#include <cstdint>

#include "mozilla/ipc/ProtocolUtils.h"
#include "IPCMessageStart.h"

using std::uint32_t;

namespace {

enum IPCMessages {
""", file=ipc_msgtype_name)

for protocol in sorted(allmessages.keys()):
    for (msg, num) in allmessages[protocol].idnums:
        if num:
            print("  %s = %s," % (msg, num), file=ipc_msgtype_name)
        elif not msg.endswith('End'):
            print("  %s__%s," % (protocol, msg), file=ipc_msgtype_name)

print("""
};

} // anonymous namespace

namespace IPC {

const char* StringFromIPCMessageType(uint32_t aMessageType)
{
  switch (aMessageType) {
""", file=ipc_msgtype_name)

for protocol in sorted(allmessages.keys()):
    for (msg, num) in allmessages[protocol].idnums:
        if num or msg.endswith('End'):
            continue
        print("""
  case %s__%s:
    return "%s::%s";""" % (protocol, msg, protocol, msg), file=ipc_msgtype_name)

print("""
  case CHANNEL_OPENED_MESSAGE_TYPE:
    return "CHANNEL_OPENED_MESSAGE";
  case SHMEM_DESTROYED_MESSAGE_TYPE:
    return "SHMEM_DESTROYED_MESSAGE";
  case SHMEM_CREATED_MESSAGE_TYPE:
    return "SHMEM_CREATED_MESSAGE";
  case GOODBYE_MESSAGE_TYPE:
    return "GOODBYE_MESSAGE";
  case CANCEL_MESSAGE_TYPE:
    return "CANCEL_MESSAGE";
  default:
    return "<unknown IPC msg name>";
  }
}

} // namespace IPC
""", file=ipc_msgtype_name)

ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)