import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

27
ipc/ipdl/Makefile.in Normal file
View file

@ -0,0 +1,27 @@
# 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/.
GARBAGE_DIRS += _ipdlheaders
GARBAGE += ipdl_lextab.py ipdl_yacctab.py $(wildcard *.pyc $(srcdir)/ipdl/*.pyc $(srcdir)/ipdl/cxx/*.pyc)
ifdef COMPILE_ENVIRONMENT
# This file is generated by the moz.build backend.
include ipdlsrcs.mk
include $(topsrcdir)/config/rules.mk
# NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself,
# which is why we don't have explicit .h/.cpp targets here
export:: $(ALL_IPDLSRCS)
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) \
$(srcdir)/ipdl.py \
--outheaders-dir=_ipdlheaders \
--outcpp-dir=. \
$(IPDLDIRS:%=-I%) \
$^
endif

232
ipc/ipdl/ipdl.py Normal file
View file

@ -0,0 +1,232 @@
# 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/.
import optparse, os, re, sys
from cStringIO import StringIO
from mozbuild.pythonutil import iter_modules_in_path
import mozpack.path as mozpath
import itertools
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('-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
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')
# Compiling the IPDL files can take a long time, even on a fast machine.
# Check to see whether we need to do any work.
latestipdlmod = max(os.stat(f).st_mtime
for f in itertools.chain(files,
iter_modules_in_path(mozpath.dirname(__file__))))
def outputModTime(f):
# A non-existant file is newer than everything.
if not os.path.exists(f):
return 0
return os.stat(f).st_mtime
# Because the IPDL headers are placed into directories reflecting their
# namespace, collect a list here so we can easily map output names without
# parsing the actual IPDL files themselves.
headersmap = {}
for (path, dirs, headers) in os.walk(headersdir):
for h in headers:
base = os.path.basename(h)
if base in headersmap:
root, ext = os.path.splitext(base)
print >>sys.stderr, 'A protocol named', root, 'exists in multiple namespaces'
sys.exit(1)
headersmap[base] = os.path.join(path, h)
def outputfiles(f):
base = os.path.basename(f)
root, ext = os.path.splitext(base)
suffixes = ['']
if ext == '.ipdl':
suffixes += ['Child', 'Parent']
for suffix in suffixes:
yield os.path.join(cppdir, "%s%s.cpp" % (root, suffix))
header = "%s%s.h" % (root, suffix)
# If the header already exists on disk, use that. Otherwise,
# just claim that the header is found in headersdir.
if header in headersmap:
yield headersmap[header]
else:
yield os.path.join(headersdir, header)
def alloutputfiles():
for f in files:
for s in outputfiles(f):
yield s
yield ipcmessagestartpath
earliestoutputmod = min(outputModTime(f) for f in alloutputfiles())
if latestipdlmod < earliestoutputmod:
sys.exit(0)
log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
allmessages = {}
allprotocols = []
def normalizedFilename(f):
if f == '-':
return '<stdin>'
return f
# 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 >>sys.stderr, 'Specification could not be parsed.'
sys.exit(1)
log(2, 'checking types')
if not ipdl.typecheck(ast):
print >>sys.stderr, 'Specification is not well typed.'
sys.exit(1)
if _verbosity > 2:
log(3, ' pretty printed code:')
ipdl.genipdl(ast, codedir)
# 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)
if ast.protocol:
allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
allprotocols.append('%sMsgStart' % ast.protocol.name)
allprotocols.sort()
ipcmsgstart = StringIO()
print >>ipcmsgstart, """
// CODE GENERATED by ipdl.py. Do not edit.
#ifndef IPCMessageStart_h
#define IPCMessageStart_h
enum IPCMessageStart {
"""
for name in allprotocols:
print >>ipcmsgstart, " %s," % name
print >>ipcmsgstart, " %sChild," % name
print >>ipcmsgstart, """
LastMsgIndex
};
static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
#endif // ifndef IPCMessageStart_h
"""
ipc_msgtype_name = StringIO()
print >>ipc_msgtype_name, """
// CODE GENERATED by ipdl.py. Do not edit.
#include <cstdint>
#include "IPCMessageStart.h"
using std::uint32_t;
namespace {
enum IPCMessages {
"""
for protocol in sorted(allmessages.keys()):
for (msg, num) in allmessages[protocol].idnums:
if num:
print >>ipc_msgtype_name, " %s = %s," % (msg, num)
elif not msg.endswith('End'):
print >>ipc_msgtype_name, " %s__%s," % (protocol, msg)
print >>ipc_msgtype_name, """
};
} // anonymous namespace
namespace mozilla {
namespace ipc {
const char* StringFromIPCMessageType(uint32_t aMessageType)
{
switch (aMessageType) {
"""
for protocol in sorted(allmessages.keys()):
for (msg, num) in allmessages[protocol].idnums:
if num or msg.endswith('End'):
continue
print >>ipc_msgtype_name, """
case %s__%s:
return "%s::%s";""" % (protocol, msg, protocol, msg)
print >>ipc_msgtype_name, """
default:
return "???";
}
}
} // namespace ipc
} // namespace mozilla
"""
ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)

77
ipc/ipdl/ipdl/__init__.py Normal file
View file

@ -0,0 +1,77 @@
# 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/.
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ]
import os, sys
from cStringIO import StringIO
from ipdl.cgen import IPDLCodeGen
from ipdl.lower import LowerToCxx, msgenums
from ipdl.parser import Parser
from ipdl.type import TypeCheck
from ipdl.cxx.cgen import CxxCodeGen
def parse(specstring, filename='/stdin', includedirs=[ ], errout=sys.stderr):
'''Return an IPDL AST if parsing was successful. Print errors to |errout|
if it is not.'''
# The file type and name are later enforced by the type checker.
# This is just a hint to the parser.
prefix, ext = os.path.splitext(filename)
name = os.path.basename(prefix)
if ext == '.ipdlh':
type = 'header'
else:
type = 'protocol'
return Parser(type, name).parse(specstring, os.path.abspath(filename), includedirs, errout)
def typecheck(ast, errout=sys.stderr):
'''Return True iff |ast| is well typed. Print errors to |errout| if
it is not.'''
return TypeCheck().check(ast, errout)
def gencxx(ipdlfilename, ast, outheadersdir, outcppdir):
headers, cpps = LowerToCxx().lower(ast)
def resolveHeader(hdr):
return [
hdr,
os.path.join(
outheadersdir,
*([ns.name for ns in ast.namespaces] + [hdr.name]))
]
def resolveCpp(cpp):
return [ cpp, os.path.join(outcppdir, cpp.name) ]
for ast, filename in ([ resolveHeader(hdr) for hdr in headers ]
+ [ resolveCpp(cpp) for cpp in cpps ]):
tempfile = StringIO()
CxxCodeGen(tempfile).cgen(ast)
writeifmodified(tempfile.getvalue(), filename)
def genipdl(ast, outdir):
return IPDLCodeGen().cgen(ast)
def genmsgenum(ast):
return msgenums(ast.protocol, pretty=True)
def writeifmodified(contents, file):
dir = os.path.dirname(file)
os.path.exists(dir) or os.makedirs(dir)
oldcontents = None
if os.path.exists(file):
fd = open(file, 'rb')
oldcontents = fd.read()
fd.close()
if oldcontents != contents:
fd = open(file, 'wb')
fd.write(contents)
fd.close()

454
ipc/ipdl/ipdl/ast.py Normal file
View file

@ -0,0 +1,454 @@
# 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/.
import sys
NOT_NESTED = 1
INSIDE_SYNC_NESTED = 2
INSIDE_CPOW_NESTED = 3
NORMAL_PRIORITY = 1
HIGH_PRIORITY = 2
class Visitor:
def defaultVisit(self, node):
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
node.__class__.__name__)
def visitTranslationUnit(self, tu):
for cxxInc in tu.cxxIncludes:
cxxInc.accept(self)
for inc in tu.includes:
inc.accept(self)
for su in tu.structsAndUnions:
su.accept(self)
for using in tu.builtinUsing:
using.accept(self)
for using in tu.using:
using.accept(self)
if tu.protocol:
tu.protocol.accept(self)
def visitCxxInclude(self, inc):
pass
def visitInclude(self, inc):
# Note: we don't visit the child AST here, because that needs delicate
# and pass-specific handling
pass
def visitStructDecl(self, struct):
for f in struct.fields:
f.accept(self)
def visitStructField(self, field):
field.typespec.accept(self)
def visitUnionDecl(self, union):
for t in union.components:
t.accept(self)
def visitUsingStmt(self, using):
pass
def visitProtocol(self, p):
for namespace in p.namespaces:
namespace.accept(self)
for spawns in p.spawnsStmts:
spawns.accept(self)
for bridges in p.bridgesStmts:
bridges.accept(self)
for opens in p.opensStmts:
opens.accept(self)
for mgr in p.managers:
mgr.accept(self)
for managed in p.managesStmts:
managed.accept(self)
for msgDecl in p.messageDecls:
msgDecl.accept(self)
for transitionStmt in p.transitionStmts:
transitionStmt.accept(self)
def visitNamespace(self, ns):
pass
def visitSpawnsStmt(self, spawns):
pass
def visitBridgesStmt(self, bridges):
pass
def visitOpensStmt(self, opens):
pass
def visitManager(self, mgr):
pass
def visitManagesStmt(self, mgs):
pass
def visitMessageDecl(self, md):
for inParam in md.inParams:
inParam.accept(self)
for outParam in md.outParams:
outParam.accept(self)
def visitTransitionStmt(self, ts):
ts.state.accept(self)
for trans in ts.transitions:
trans.accept(self)
def visitTransition(self, t):
for toState in t.toStates:
toState.accept(self)
def visitState(self, s):
pass
def visitParam(self, decl):
pass
def visitTypeSpec(self, ts):
pass
def visitDecl(self, d):
pass
class Loc:
def __init__(self, filename='<??>', lineno=0):
assert filename
self.filename = filename
self.lineno = lineno
def __repr__(self):
return '%r:%r'% (self.filename, self.lineno)
def __str__(self):
return '%s:%s'% (self.filename, self.lineno)
Loc.NONE = Loc(filename='<??>', lineno=0)
class _struct:
pass
class Node:
def __init__(self, loc=Loc.NONE):
self.loc = loc
def accept(self, visitor):
visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
if visit is None:
return getattr(visitor, 'defaultVisit')(self)
return visit(self)
def addAttrs(self, attrsName):
if not hasattr(self, attrsName):
setattr(self, attrsName, _struct())
class NamespacedNode(Node):
def __init__(self, loc=Loc.NONE, name=None):
Node.__init__(self, loc)
self.name = name
self.namespaces = [ ]
def addOuterNamespace(self, namespace):
self.namespaces.insert(0, namespace)
def qname(self):
return QualifiedId(self.loc, self.name,
[ ns.name for ns in self.namespaces ])
class TranslationUnit(NamespacedNode):
def __init__(self, type, name):
NamespacedNode.__init__(self, name=name)
self.filetype = type
self.filename = None
self.cxxIncludes = [ ]
self.includes = [ ]
self.builtinUsing = [ ]
self.using = [ ]
self.structsAndUnions = [ ]
self.protocol = None
def addCxxInclude(self, cxxInclude): self.cxxIncludes.append(cxxInclude)
def addInclude(self, inc): self.includes.append(inc)
def addStructDecl(self, struct): self.structsAndUnions.append(struct)
def addUnionDecl(self, union): self.structsAndUnions.append(union)
def addUsingStmt(self, using): self.using.append(using)
def setProtocol(self, protocol): self.protocol = protocol
class CxxInclude(Node):
def __init__(self, loc, cxxFile):
Node.__init__(self, loc)
self.file = cxxFile
class Include(Node):
def __init__(self, loc, type, name):
Node.__init__(self, loc)
suffix = 'ipdl'
if type == 'header':
suffix += 'h'
self.file = "%s.%s" % (name, suffix)
class UsingStmt(Node):
def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None):
Node.__init__(self, loc)
assert not isinstance(cxxTypeSpec, str)
assert cxxHeader is None or isinstance(cxxHeader, str);
assert kind is None or kind == 'class' or kind == 'struct'
self.type = cxxTypeSpec
self.header = cxxHeader
self.kind = kind
def canBeForwardDeclared(self):
return self.isClass() or self.isStruct()
def isClass(self):
return self.kind == 'class'
def isStruct(self):
return self.kind == 'struct'
# "singletons"
class PrettyPrinted:
@classmethod
def __hash__(cls): return hash(cls.pretty)
@classmethod
def __str__(cls): return cls.pretty
class ASYNC(PrettyPrinted):
pretty = 'async'
class INTR(PrettyPrinted):
pretty = 'intr'
class SYNC(PrettyPrinted):
pretty = 'sync'
class INOUT(PrettyPrinted):
pretty = 'inout'
class IN(PrettyPrinted):
pretty = 'in'
class OUT(PrettyPrinted):
pretty = 'out'
class Namespace(Node):
def __init__(self, loc, namespace):
Node.__init__(self, loc)
self.name = namespace
class Protocol(NamespacedNode):
def __init__(self, loc):
NamespacedNode.__init__(self, loc)
self.sendSemantics = ASYNC
self.nested = NOT_NESTED
self.spawnsStmts = [ ]
self.bridgesStmts = [ ]
self.opensStmts = [ ]
self.managers = [ ]
self.managesStmts = [ ]
self.messageDecls = [ ]
self.transitionStmts = [ ]
self.startStates = [ ]
class StructField(Node):
def __init__(self, loc, type, name):
Node.__init__(self, loc)
self.typespec = type
self.name = name
class StructDecl(NamespacedNode):
def __init__(self, loc, name, fields):
NamespacedNode.__init__(self, loc, name)
self.fields = fields
class UnionDecl(NamespacedNode):
def __init__(self, loc, name, components):
NamespacedNode.__init__(self, loc, name)
self.components = components
class SpawnsStmt(Node):
def __init__(self, loc, side, proto, spawnedAs):
Node.__init__(self, loc)
self.side = side
self.proto = proto
self.spawnedAs = spawnedAs
class BridgesStmt(Node):
def __init__(self, loc, parentSide, childSide):
Node.__init__(self, loc)
self.parentSide = parentSide
self.childSide = childSide
class OpensStmt(Node):
def __init__(self, loc, side, proto):
Node.__init__(self, loc)
self.side = side
self.proto = proto
class Manager(Node):
def __init__(self, loc, managerName):
Node.__init__(self, loc)
self.name = managerName
class ManagesStmt(Node):
def __init__(self, loc, managedName):
Node.__init__(self, loc)
self.name = managedName
class MessageDecl(Node):
def __init__(self, loc):
Node.__init__(self, loc)
self.name = None
self.sendSemantics = ASYNC
self.nested = NOT_NESTED
self.prio = NORMAL_PRIORITY
self.direction = None
self.inParams = [ ]
self.outParams = [ ]
self.compress = ''
self.verify = ''
def addInParams(self, inParamsList):
self.inParams += inParamsList
def addOutParams(self, outParamsList):
self.outParams += outParamsList
def addModifiers(self, modifiers):
for modifier in modifiers:
if modifier.startswith('compress'):
self.compress = modifier
elif modifier == 'verify':
self.verify = modifier
elif modifier != '':
raise Exception, "Unexpected message modifier `%s'"% modifier
class Transition(Node):
def __init__(self, loc, trigger, msg, toStates):
Node.__init__(self, loc)
self.trigger = trigger
self.msg = msg
self.toStates = toStates
def __cmp__(self, o):
c = cmp(self.msg, o.msg)
if c: return c
c = cmp(self.trigger, o.trigger)
if c: return c
def __hash__(self): return hash(str(self))
def __str__(self): return '%s %s'% (self.trigger, self.msg)
@staticmethod
def nameToTrigger(name):
return { 'send': SEND, 'recv': RECV, 'call': CALL, 'answer': ANSWER }[name]
Transition.NULL = Transition(Loc.NONE, None, None, [ ])
class TransitionStmt(Node):
def __init__(self, loc, state, transitions):
Node.__init__(self, loc)
self.state = state
self.transitions = transitions
@staticmethod
def makeNullStmt(state):
return TransitionStmt(Loc.NONE, state, [ Transition.NULL ])
class SEND:
pretty = 'send'
@classmethod
def __hash__(cls): return hash(cls.pretty)
@classmethod
def direction(cls): return OUT
class RECV:
pretty = 'recv'
@classmethod
def __hash__(cls): return hash(cls.pretty)
@classmethod
def direction(cls): return IN
class CALL:
pretty = 'call'
@classmethod
def __hash__(cls): return hash(cls.pretty)
@classmethod
def direction(cls): return OUT
class ANSWER:
pretty = 'answer'
@classmethod
def __hash__(cls): return hash(cls.pretty)
@classmethod
def direction(cls): return IN
class State(Node):
def __init__(self, loc, name, start=False):
Node.__init__(self, loc)
self.name = name
self.start = start
def __eq__(self, o):
return (isinstance(o, State)
and o.name == self.name
and o.start == self.start)
def __hash__(self):
return hash(repr(self))
def __ne__(self, o):
return not (self == o)
def __repr__(self): return '<State %r start=%r>'% (self.name, self.start)
def __str__(self): return '<State %s start=%s>'% (self.name, self.start)
State.ANY = State(Loc.NONE, '[any]', start=True)
State.DEAD = State(Loc.NONE, '[dead]', start=False)
State.DYING = State(Loc.NONE, '[dying]', start=False)
class Param(Node):
def __init__(self, loc, typespec, name):
Node.__init__(self, loc)
self.name = name
self.typespec = typespec
class TypeSpec(Node):
def __init__(self, loc, spec, state=None, array=0, nullable=0,
myChmod=None, otherChmod=None):
Node.__init__(self, loc)
self.spec = spec # QualifiedId
self.state = state # None or State
self.array = array # bool
self.nullable = nullable # bool
self.myChmod = myChmod # None or string
self.otherChmod = otherChmod # None or string
def basename(self):
return self.spec.baseid
def isActor(self):
return self.state is not None
def __str__(self): return str(self.spec)
class QualifiedId: # FIXME inherit from node?
def __init__(self, loc, baseid, quals=[ ]):
assert isinstance(baseid, str)
for qual in quals: assert isinstance(qual, str)
self.loc = loc
self.baseid = baseid
self.quals = quals
def qualify(self, id):
self.quals.append(self.baseid)
self.baseid = id
def __str__(self):
if 0 == len(self.quals):
return self.baseid
return '::'.join(self.quals) +'::'+ self.baseid
# added by type checking passes
class Decl(Node):
def __init__(self, loc):
Node.__init__(self, loc)
self.progname = None # what the programmer typed, if relevant
self.shortname = None # shortest way to refer to this decl
self.fullname = None # full way to refer to this decl
self.loc = loc
self.type = None
self.scope = None

59
ipc/ipdl/ipdl/builtin.py Normal file
View file

@ -0,0 +1,59 @@
# 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/.
# WARNING: the syntax of the builtin types is not checked, so please
# don't add something syntactically invalid. It will not be fun to
# track down the bug.
Types = (
# C types
'bool',
'char',
'short',
'int',
'long',
'float',
'double',
# stdint types
'int8_t',
'uint8_t',
'int16_t',
'uint16_t',
'int32_t',
'uint32_t',
'int64_t',
'uint64_t',
'intptr_t',
'uintptr_t',
# stddef types
'size_t',
'ssize_t',
# Mozilla types: "less" standard things we know how serialize/deserialize
'nsresult',
'nsString',
'nsCString',
'mozilla::ipc::Shmem',
'mozilla::ipc::FileDescriptor'
)
HeaderIncludes = (
'mozilla/Attributes.h',
'IPCMessageStart.h',
'ipc/IPCMessageUtils.h',
'mozilla/RefPtr.h',
'nsStringGlue.h',
'nsTArray.h',
'mozilla/ipc/ProtocolUtils.h',
'nsTHashtable.h',
'mozilla/OperatorNewExtensions.h',
)
CppIncludes = (
'nsIFile.h',
'GeckoProfiler.h',
)

101
ipc/ipdl/ipdl/cgen.py Normal file
View file

@ -0,0 +1,101 @@
# 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/.
import os, sys
from ipdl.ast import Visitor
from ipdl.ast import IN, OUT, INOUT, ASYNC, SYNC, INTR
class CodePrinter:
def __init__(self, outf=sys.stdout, indentCols=4):
self.outf = outf
self.col = 0
self.indentCols = indentCols
def write(self, str):
self.outf.write(str)
def printdent(self, str=''):
self.write((' '* self.col) + str)
def println(self, str=''):
self.write(str +'\n')
def printdentln(self, str):
self.write((' '* self.col) + str +'\n')
def indent(self): self.col += self.indentCols
def dedent(self): self.col -= self.indentCols
##-----------------------------------------------------------------------------
class IPDLCodeGen(CodePrinter, Visitor):
'''Spits back out equivalent IPDL to the code that generated this.
Also known as pretty-printing.'''
def __init__(self, outf=sys.stdout, indentCols=4, printed=set()):
CodePrinter.__init__(self, outf, indentCols)
self.printed = printed
def visitTranslationUnit(self, tu):
self.printed.add(tu.filename)
self.println('//\n// Automatically generated by ipdlc\n//')
CodeGen.visitTranslationUnit(self, tu)
def visitCxxInclude(self, inc):
self.println('include "'+ inc.file +'";')
def visitProtocolInclude(self, inc):
self.println('include protocol "'+ inc.file +'";')
if inc.tu.filename not in self.printed:
self.println('/* Included file:')
IPDLCodeGen(outf=self.outf, indentCols=self.indentCols,
printed=self.printed).visitTranslationUnit(inc.tu)
self.println('*/')
def visitProtocol(self, p):
self.println()
for namespace in p.namespaces: namespace.accept(self)
self.println('%s protocol %s\n{'% (p.sendSemantics[0], p.name))
self.indent()
for mgs in p.managesStmts:
mgs.accept(self)
if len(p.managesStmts): self.println()
for msgDecl in p.messageDecls: msgDecl.accept(self)
self.println()
for transStmt in p.transitionStmts: transStmt.accept(self)
self.dedent()
self.println('}')
self.write('}\n'* len(p.namespaces))
def visitManagerStmt(self, mgr):
self.printdentln('manager '+ mgr.name +';')
def visitManagesStmt(self, mgs):
self.printdentln('manages '+ mgs.name +';')
def visitMessageDecl(self, msg):
self.printdent('%s %s %s('% (msg.sendSemantics[0], msg.direction[0], msg.name))
for i, inp in enumerate(msg.inParams):
inp.accept(self)
if i != (len(msg.inParams) - 1): self.write(', ')
self.write(')')
if 0 == len(msg.outParams):
self.println(';')
return
self.println()
self.indent()
self.printdent('returns (')
for i, outp in enumerate(msg.outParams):
outp.accept(self)
if i != (len(msg.outParams) - 1): self.write(', ')
self.println(');')
self.dedent()

View file

@ -0,0 +1,6 @@
# 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/.
import ipdl.cxx.ast
import ipdl.cxx.cgen

809
ipc/ipdl/ipdl/cxx/ast.py Normal file
View file

@ -0,0 +1,809 @@
# 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/.
import copy, sys
class Visitor:
def defaultVisit(self, node):
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
node.__class__.__name__)
def visitWhitespace(self, ws):
pass
def visitFile(self, f):
for thing in f.stuff:
thing.accept(self)
def visitCppDirective(self, ppd):
pass
def visitBlock(self, block):
for stmt in block.stmts:
stmt.accept(self)
def visitNamespace(self, ns):
self.visitBlock(ns)
def visitType(self, type):
pass
def visitTypeArray(self, ta):
ta.basetype.accept(self)
ta.nmemb.accept(self)
def visitTypeEnum(self, enum):
pass
def visitTypeUnion(self, union):
for t, name in union.components:
t.accept(self)
def visitTypedef(self, tdef):
tdef.fromtype.accept(self)
def visitUsing(self, us):
us.type.accept(self)
def visitForwardDecl(self, fd):
pass
def visitDecl(self, decl):
decl.type.accept(self)
def visitParam(self, param):
self.visitDecl(param)
if param.default is not None:
param.default.accept(self)
def visitClass(self, cls):
for inherit in cls.inherits:
inherit.accept(self)
self.visitBlock(cls)
def visitInherit(self, inh):
pass
def visitFriendClassDecl(self, fcd):
pass
def visitMethodDecl(self, meth):
for param in meth.params:
param.accept(self)
if meth.ret is not None:
meth.ret.accept(self)
if meth.typeop is not None:
meth.typeop.accept(self)
if meth.T is not None:
meth.T.accept(self)
def visitMethodDefn(self, meth):
meth.decl.accept(self)
self.visitBlock(meth)
def visitFunctionDecl(self, fun):
self.visitMethodDecl(fun)
def visitFunctionDefn(self, fd):
self.visitMethodDefn(fd)
def visitConstructorDecl(self, ctor):
self.visitMethodDecl(ctor)
def visitConstructorDefn(self, cd):
cd.decl.accept(self)
for init in cd.memberinits:
init.accept(self)
self.visitBlock(cd)
def visitDestructorDecl(self, dtor):
self.visitMethodDecl(dtor)
def visitDestructorDefn(self, dd):
dd.decl.accept(self)
self.visitBlock(dd)
def visitExprLiteral(self, l):
pass
def visitExprVar(self, v):
pass
def visitExprPrefixUnop(self, e):
e.expr.accept(self)
def visitExprBinary(self, e):
e.left.accept(self)
e.right.accept(self)
def visitExprConditional(self, c):
c.cond.accept(self)
c.ife.accept(self)
c.elsee.accept(self)
def visitExprAddrOf(self, eao):
self.visitExprPrefixUnop(eao)
def visitExprDeref(self, ed):
self.visitExprPrefixUnop(ed)
def visitExprNot(self, en):
self.visitExprPrefixUnop(en)
def visitExprCast(self, ec):
ec.expr.accept(self)
def visitExprIndex(self, ei):
ei.arr.accept(self)
ei.idx.accept(self)
def visitExprSelect(self, es):
es.obj.accept(self)
def visitExprAssn(self, ea):
ea.lhs.accept(self)
ea.rhs.accept(self)
def visitExprCall(self, ec):
ec.func.accept(self)
for arg in ec.args:
arg.accept(self)
def visitExprNew(self, en):
en.ctype.accept(self)
if en.newargs is not None:
for arg in en.newargs:
arg.accept(self)
if en.args is not None:
for arg in en.args:
arg.accept(self)
def visitExprDelete(self, ed):
ed.obj.accept(self)
def visitExprMemberInit(self, minit):
self.visitExprCall(minit)
def visitExprSizeof(self, es):
self.visitExprCall(es)
def visitStmtBlock(self, sb):
self.visitBlock(sb)
def visitStmtDecl(self, sd):
sd.decl.accept(self)
if sd.init is not None:
sd.init.accept(self)
def visitLabel(self, label):
pass
def visitCaseLabel(self, case):
pass
def visitDefaultLabel(self, dl):
pass
def visitStmtIf(self, si):
si.cond.accept(self)
si.ifb.accept(self)
if si.elseb is not None:
si.elseb.accept(self)
def visitStmtFor(self, sf):
if sf.init is not None:
sf.init.accept(self)
if sf.cond is not None:
sf.cond.accept(self)
if sf.update is not None:
sf.update.accept(self)
def visitStmtSwitch(self, ss):
ss.expr.accept(self)
self.visitBlock(ss)
def visitStmtBreak(self, sb):
pass
def visitStmtExpr(self, se):
se.expr.accept(self)
def visitStmtReturn(self, sr):
if sr.expr is not None:
sr.expr.accept(self)
##------------------------------
class Node:
def __init__(self):
pass
def accept(self, visitor):
visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
if visit is None:
return getattr(visitor, 'defaultVisit')(self)
return visit(self)
class Whitespace(Node):
# yes, this is silly. but we need to stick comments in the
# generated code without resorting to more serious hacks
def __init__(self, ws, indent=0):
Node.__init__(self)
self.ws = ws
self.indent = indent
Whitespace.NL = Whitespace('\n')
class File(Node):
def __init__(self, filename):
Node.__init__(self)
self.name = filename
# array of stuff in the file --- stmts and preprocessor thingies
self.stuff = [ ]
def addthing(self, thing):
assert thing is not None
assert not isinstance(thing, list)
self.stuff.append(thing)
def addthings(self, things):
for t in things: self.addthing(t)
# "look like" a Block so code doesn't have to care whether they're
# in global scope or not
def addstmt(self, stmt):
assert stmt is not None
assert not isinstance(stmt, list)
self.stuff.append(stmt)
def addstmts(self, stmts):
for s in stmts: self.addstmt(s)
class CppDirective(Node):
'''represents |#[directive] [rest]|, where |rest| is any string'''
def __init__(self, directive, rest=None):
Node.__init__(self)
self.directive = directive
self.rest = rest
class Block(Node):
def __init__(self):
Node.__init__(self)
self.stmts = [ ]
def addstmt(self, stmt):
assert stmt is not None
assert not isinstance(stmt, tuple)
self.stmts.append(stmt)
def addstmts(self, stmts):
for s in stmts: self.addstmt(s)
##------------------------------
# type and decl thingies
class Namespace(Block):
def __init__(self, name):
assert isinstance(name, str)
Block.__init__(self)
self.name = name
class Type(Node):
def __init__(self, name, const=0,
ptr=0, ptrconst=0, ptrptr=0, ptrconstptr=0,
ref=0,
hasimplicitcopyctor=True,
T=None):
"""
To avoid getting fancy with recursive types, we limit the kinds
of pointer types that can be be constructed.
ptr => T*
ptrconst => T* const
ptrptr => T**
ptrconstptr => T* const*
Any type, naked or pointer, can be const (const T) or ref (T&).
"""
assert isinstance(name, str)
assert not isinstance(const, str)
assert not isinstance(T, str)
Node.__init__(self)
self.name = name
self.const = const
self.ptr = ptr
self.ptrconst = ptrconst
self.ptrptr = ptrptr
self.ptrconstptr = ptrconstptr
self.ref = ref
self.hasimplicitcopyctor = hasimplicitcopyctor
self.T = T
# XXX could get serious here with recursive types, but shouldn't
# need that for this codegen
def __deepcopy__(self, memo):
return Type(self.name,
const=self.const,
ptr=self.ptr, ptrconst=self.ptrconst,
ptrptr=self.ptrptr, ptrconstptr=self.ptrconstptr,
ref=self.ref,
T=copy.deepcopy(self.T, memo))
Type.BOOL = Type('bool')
Type.INT = Type('int')
Type.INT32 = Type('int32_t')
Type.INTPTR = Type('intptr_t')
Type.NSRESULT = Type('nsresult')
Type.UINT32 = Type('uint32_t')
Type.UINT32PTR = Type('uint32_t', ptr=1)
Type.SIZE = Type('size_t')
Type.VOID = Type('void')
Type.VOIDPTR = Type('void', ptr=1)
Type.AUTO = Type('auto')
class TypeArray(Node):
def __init__(self, basetype, nmemb):
'''the type |basetype DECLNAME[nmemb]|. |nmemb| is an Expr'''
self.basetype = basetype
self.nmemb = nmemb
def __deepcopy__(self, memo):
return TypeArray(deepcopy(self.basetype, memo), nmemb)
class TypeEnum(Node):
def __init__(self, name=None):
'''name can be None'''
Node.__init__(self)
self.name = name
self.idnums = [ ] # pairs of ('Foo', [num]) or ('Foo', None)
def addId(self, id, num=None):
self.idnums.append((id, num))
class TypeUnion(Node):
def __init__(self, name=None):
Node.__init__(self)
self.name = name
self.components = [ ] # [ Decl ]
def addComponent(self, type, name):
self.components.append(Decl(type, name))
class Typedef(Node):
def __init__(self, fromtype, totypename, templateargs=[]):
assert isinstance(totypename, str)
Node.__init__(self)
self.fromtype = fromtype
self.totypename = totypename
self.templateargs = templateargs
def __cmp__(self, o):
return cmp(self.totypename, o.totypename)
def __eq__(self, o):
return (self.__class__ == o.__class__
and 0 == cmp(self, o))
def __hash__(self):
return hash(self.totypename)
class Using(Node):
def __init__(self, type):
Node.__init__(self)
self.type = type
class ForwardDecl(Node):
def __init__(self, pqname, cls=0, struct=0):
assert (not cls and struct) or (cls and not struct)
self.pqname = pqname
self.cls = cls
self.struct = struct
class Decl(Node):
'''represents |Foo bar|, e.g. in a function signature'''
def __init__(self, type, name):
assert type is not None
assert not isinstance(type, str)
assert isinstance(name, str)
Node.__init__(self)
self.type = type
self.name = name
def __deepcopy__(self, memo):
return Decl(copy.deepcopy(self.type, memo), self.name)
class Param(Decl):
def __init__(self, type, name, default=None):
Decl.__init__(self, type, name)
self.default = default
def __deepcopy__(self, memo):
return Param(copy.deepcopy(self.type, memo), self.name,
copy.deepcopy(self.default, memo))
##------------------------------
# class stuff
class Class(Block):
def __init__(self, name, inherits=[ ],
interface=0, abstract=0, final=0,
specializes=None, struct=0):
assert not (interface and abstract)
assert not (abstract and final)
assert not (interface and final)
assert not (inherits and specializes)
Block.__init__(self)
self.name = name
self.inherits = inherits # [ Type ]
self.interface = interface # bool
self.abstract = abstract # bool
self.final = final # bool
self.specializes = specializes # Type or None
self.struct = struct # bool
class Inherit(Node):
def __init__(self, type, viz='public'):
assert isinstance(viz, str)
Node.__init__(self)
self.type = type
self.viz = viz
class FriendClassDecl(Node):
def __init__(self, friend):
Node.__init__(self)
self.friend = friend
class MethodDecl(Node):
def __init__(self, name, params=[ ], ret=Type('void'),
virtual=0, const=0, pure=0, static=0, warn_unused=0,
inline=0, force_inline=0, never_inline=0,
typeop=None,
T=None):
assert not (virtual and static)
assert not pure or virtual # pure => virtual
assert not (static and typeop)
assert not (name and typeop)
assert name is None or isinstance(name, str)
assert not isinstance(ret, list)
for decl in params: assert not isinstance(decl, str)
assert not isinstance(T, int)
assert not (inline and never_inline)
assert not (force_inline and never_inline)
if typeop is not None:
ret = None
Node.__init__(self)
self.name = name
self.params = params # [ Param ]
self.ret = ret # Type or None
self.virtual = virtual # bool
self.const = const # bool
self.pure = pure # bool
self.static = static # bool
self.warn_unused = warn_unused # bool
self.force_inline = (force_inline or T) # bool
self.inline = inline # bool
self.never_inline = never_inline # bool
self.typeop = typeop # Type or None
self.T = T # Type or None
self.only_for_definition = False
def __deepcopy__(self, memo):
return MethodDecl(
self.name,
params=copy.deepcopy(self.params, memo),
ret=copy.deepcopy(self.ret, memo),
virtual=self.virtual,
const=self.const,
pure=self.pure,
static=self.static,
warn_unused=self.warn_unused,
inline=self.inline,
force_inline=self.force_inline,
never_inline=self.never_inline,
typeop=copy.deepcopy(self.typeop, memo),
T=copy.deepcopy(self.T, memo))
class MethodDefn(Block):
def __init__(self, decl):
Block.__init__(self)
self.decl = decl
class FunctionDecl(MethodDecl):
def __init__(self, name, params=[ ], ret=Type('void'),
static=0, warn_unused=0,
inline=0, force_inline=0,
T=None):
MethodDecl.__init__(self, name, params=params, ret=ret,
static=static, warn_unused=warn_unused,
inline=inline, force_inline=force_inline,
T=T)
class FunctionDefn(MethodDefn):
def __init__(self, decl):
MethodDefn.__init__(self, decl)
class ConstructorDecl(MethodDecl):
def __init__(self, name, params=[ ], explicit=0, force_inline=0):
MethodDecl.__init__(self, name, params=params, ret=None,
force_inline=force_inline)
self.explicit = explicit
def __deepcopy__(self, memo):
return ConstructorDecl(self.name,
copy.deepcopy(self.params, memo),
self.explicit)
class ConstructorDefn(MethodDefn):
def __init__(self, decl, memberinits=[ ]):
MethodDefn.__init__(self, decl)
self.memberinits = memberinits
class DestructorDecl(MethodDecl):
def __init__(self, name, virtual=0, force_inline=0, inline=0):
MethodDecl.__init__(self, name, params=[ ], ret=None,
virtual=virtual,
force_inline=force_inline, inline=inline)
def __deepcopy__(self, memo):
return DestructorDecl(self.name,
virtual=self.virtual,
force_inline=self.force_inline,
inline=self.inline)
class DestructorDefn(MethodDefn):
def __init__(self, decl): MethodDefn.__init__(self, decl)
##------------------------------
# expressions
class ExprVar(Node):
def __init__(self, name):
assert isinstance(name, str)
Node.__init__(self)
self.name = name
ExprVar.THIS = ExprVar('this')
class ExprLiteral(Node):
def __init__(self, value, type):
'''|type| is a Python format specifier; 'd' for example'''
Node.__init__(self)
self.value = value
self.type = type
@staticmethod
def Int(i): return ExprLiteral(i, 'd')
@staticmethod
def String(s): return ExprLiteral('"'+ s +'"', 's')
@staticmethod
def WString(s): return ExprLiteral('L"'+ s +'"', 's')
def __str__(self):
return ('%'+ self.type)% (self.value)
ExprLiteral.ZERO = ExprLiteral.Int(0)
ExprLiteral.ONE = ExprLiteral.Int(1)
ExprLiteral.NULL = ExprVar('nullptr')
ExprLiteral.TRUE = ExprVar('true')
ExprLiteral.FALSE = ExprVar('false')
class ExprPrefixUnop(Node):
def __init__(self, expr, op):
assert not isinstance(expr, tuple)
self.expr = expr
self.op = op
class ExprNot(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, '!')
class ExprAddrOf(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, '&')
class ExprDeref(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, '*')
class ExprCast(Node):
def __init__(self, expr, type,
dynamic=0, static=0, reinterpret=0, const=0, C=0):
assert 1 == reduce(lambda a, x: a+x, [ dynamic, static, reinterpret, const, C ])
Node.__init__(self)
self.expr = expr
self.type = type
self.dynamic = dynamic
self.static = static
self.reinterpret = reinterpret
self.const = const
self.C = C
class ExprBinary(Node):
def __init__(self, left, op, right):
Node.__init__(self)
self.left = left
self.op = op
self.right = right
class ExprConditional(Node):
def __init__(self, cond, ife, elsee):
Node.__init__(self)
self.cond = cond
self.ife = ife
self.elsee = elsee
class ExprIndex(Node):
def __init__(self, arr, idx):
Node.__init__(self)
self.arr = arr
self.idx = idx
class ExprSelect(Node):
def __init__(self, obj, op, field):
assert obj and op and field
assert not isinstance(obj, str)
assert isinstance(field, str)
Node.__init__(self)
self.obj = obj
self.op = op
self.field = field
class ExprAssn(Node):
def __init__(self, lhs, rhs, op='='):
Node.__init__(self)
self.lhs = lhs
self.op = op
self.rhs = rhs
class ExprCall(Node):
def __init__(self, func, args=[ ]):
assert hasattr(func, 'accept')
assert isinstance(args, list)
for arg in args: assert arg and not isinstance(arg, str)
Node.__init__(self)
self.func = func
self.args = args
class ExprMove(ExprCall):
def __init__(self, arg):
ExprCall.__init__(self, ExprVar("mozilla::Move"), args=[arg])
class ExprNew(Node):
# XXX taking some poetic license ...
def __init__(self, ctype, args=[ ], newargs=None):
assert not (ctype.const or ctype.ref)
Node.__init__(self)
self.ctype = ctype
self.args = args
self.newargs = newargs
class ExprDelete(Node):
def __init__(self, obj):
Node.__init__(self)
self.obj = obj
class ExprMemberInit(ExprCall):
def __init__(self, member, args=[ ]):
ExprCall.__init__(self, member, args)
class ExprSizeof(ExprCall):
def __init__(self, t):
ExprCall.__init__(self, ExprVar('sizeof'), [ t ])
##------------------------------
# statements etc.
class StmtBlock(Block):
def __init__(self, stmts=[ ]):
Block.__init__(self)
self.addstmts(stmts)
class StmtDecl(Node):
def __init__(self, decl, init=None, initargs=None):
assert not (init and initargs)
assert not isinstance(init, str) # easy to confuse with Decl
assert not isinstance(init, list)
assert not isinstance(decl, tuple)
Node.__init__(self)
self.decl = decl
self.init = init
self.initargs = initargs
class Label(Node):
def __init__(self, name):
Node.__init__(self)
self.name = name
Label.PUBLIC = Label('public')
Label.PROTECTED = Label('protected')
Label.PRIVATE = Label('private')
class CaseLabel(Node):
def __init__(self, name):
Node.__init__(self)
self.name = name
class DefaultLabel(Node):
def __init__(self):
Node.__init__(self)
class StmtIf(Node):
def __init__(self, cond):
Node.__init__(self)
self.cond = cond
self.ifb = Block()
self.elseb = None
def addifstmt(self, stmt):
self.ifb.addstmt(stmt)
def addifstmts(self, stmts):
self.ifb.addstmts(stmts)
def addelsestmt(self, stmt):
if self.elseb is None: self.elseb = Block()
self.elseb.addstmt(stmt)
def addelsestmts(self, stmts):
if self.elseb is None: self.elseb = Block()
self.elseb.addstmts(stmts)
class StmtFor(Block):
def __init__(self, init=None, cond=None, update=None):
Block.__init__(self)
self.init = init
self.cond = cond
self.update = update
class StmtRangedFor(Block):
def __init__(self, var, iteree):
assert isinstance(var, ExprVar)
assert iteree
Block.__init__(self)
self.var = var
self.iteree = iteree
class StmtSwitch(Block):
def __init__(self, expr):
Block.__init__(self)
self.expr = expr
self.nr_cases = 0
def addcase(self, case, block):
'''NOTE: |case| is not checked for uniqueness'''
assert not isinstance(case, str)
assert (isinstance(block, StmtBreak)
or isinstance(block, StmtReturn)
or isinstance(block, StmtSwitch)
or (hasattr(block, 'stmts')
and (isinstance(block.stmts[-1], StmtBreak)
or isinstance(block.stmts[-1], StmtReturn))))
self.addstmt(case)
self.addstmt(block)
self.nr_cases += 1
def addfallthrough(self, case):
self.addstmt(case)
self.nr_cases += 1
class StmtBreak(Node):
def __init__(self):
Node.__init__(self)
class StmtExpr(Node):
def __init__(self, expr):
assert expr is not None
Node.__init__(self)
self.expr = expr
class StmtReturn(Node):
def __init__(self, expr=None):
Node.__init__(self)
self.expr = expr
StmtReturn.TRUE = StmtReturn(ExprLiteral.TRUE)
StmtReturn.FALSE = StmtReturn(ExprLiteral.FALSE)

520
ipc/ipdl/ipdl/cxx/cgen.py Normal file
View file

@ -0,0 +1,520 @@
# 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/.
import sys
from ipdl.cgen import CodePrinter
from ipdl.cxx.ast import TypeArray, Visitor
class CxxCodeGen(CodePrinter, Visitor):
def __init__(self, outf=sys.stdout, indentCols=4):
CodePrinter.__init__(self, outf, indentCols)
def cgen(self, cxxfile):
cxxfile.accept(self)
def visitWhitespace(self, ws):
if ws.indent:
self.printdent('')
self.write(ws.ws)
def visitCppDirective(self, cd):
if cd.rest:
self.println('#%s %s'% (cd.directive, cd.rest))
else:
self.println('#%s'% (cd.directive))
def visitNamespace(self, ns):
self.println('namespace '+ ns.name +' {')
self.visitBlock(ns)
self.println('} // namespace '+ ns.name)
def visitType(self, t):
if t.const:
self.write('const ')
self.write(t.name)
if t.T is not None:
self.write('<')
t.T.accept(self)
self.write('>')
ts = ''
if t.ptr: ts += '*'
elif t.ptrconst: ts += '* const'
elif t.ptrptr: ts += '**'
elif t.ptrconstptr: ts += '* const*'
ts += '&' * t.ref
self.write(ts)
def visitTypeEnum(self, te):
self.write('enum')
if te.name:
self.write(' '+ te.name)
self.println(' {')
self.indent()
nids = len(te.idnums)
for i, (id, num) in enumerate(te.idnums):
self.printdent(id)
if num:
self.write(' = '+ str(num))
if i != (nids-1):
self.write(',')
self.println()
self.dedent()
self.printdent('}')
def visitTypeUnion(self, u):
self.write('union')
if u.name:
self.write(' '+ u.name)
self.println(' {')
self.indent()
for decl in u.components:
self.printdent()
decl.accept(self)
self.println(';')
self.dedent()
self.printdent('}')
def visitTypedef(self, td):
if td.templateargs:
formals = ', '.join([ 'class ' + T for T in td.templateargs ])
args = ', '.join(td.templateargs)
self.printdent('template<' + formals + '> using ' + td.totypename + ' = ')
td.fromtype.accept(self)
self.println('<' + args + '>;')
else:
self.printdent('typedef ')
td.fromtype.accept(self)
self.println(' '+ td.totypename +';')
def visitUsing(self, us):
self.printdent('using ')
us.type.accept(self)
self.println(';')
def visitForwardDecl(self, fd):
if fd.cls: self.printdent('class ')
elif fd.struct: self.printdent('struct ')
self.write(str(fd.pqname))
self.println(';')
def visitDecl(self, d):
# C-syntax arrays make code generation much more annoying
if isinstance(d.type, TypeArray):
d.type.basetype.accept(self)
else:
d.type.accept(self)
if d.name:
self.write(' '+ d.name)
if isinstance(d.type, TypeArray):
self.write('[')
d.type.nmemb.accept(self)
self.write(']')
def visitParam(self, p):
self.visitDecl(p)
if p.default is not None:
self.write(' = ')
p.default.accept(self)
def visitClass(self, c):
if c.specializes is not None:
self.printdentln('template<>')
if c.struct:
self.printdent('struct')
else:
self.printdent('class')
self.write(' '+ c.name)
if c.final:
self.write(' final')
if c.specializes is not None:
self.write(' <')
c.specializes.accept(self)
self.write('>')
ninh = len(c.inherits)
if 0 < ninh:
self.println(' :')
self.indent()
for i, inherit in enumerate(c.inherits):
self.printdent()
inherit.accept(self)
if i != (ninh - 1):
self.println(',')
self.dedent()
self.println()
self.printdentln('{')
self.indent()
self.visitBlock(c)
self.dedent()
self.printdentln('};')
def visitInherit(self, inh):
self.write(inh.viz +' ')
inh.type.accept(self)
def visitFriendClassDecl(self, fcd):
self.printdentln('friend class '+ fcd.friend +';')
def visitMethodDecl(self, md):
assert not (md.static and md.virtual)
if md.T:
self.write('template<')
self.write('typename ')
md.T.accept(self)
self.println('>')
self.printdent()
if md.warn_unused:
self.write('MOZ_MUST_USE ')
if md.inline:
self.write('inline ')
if md.never_inline:
self.write('MOZ_NEVER_INLINE ')
if md.static:
self.write('static ')
if md.virtual:
self.write('virtual ')
if md.ret:
if md.only_for_definition:
self.write('auto ')
else:
md.ret.accept(self)
self.println()
self.printdent()
if md.typeop is not None:
self.write('operator ')
md.typeop.accept(self)
else:
self.write(md.name)
self.write('(')
self.writeDeclList(md.params)
self.write(')')
if md.const:
self.write(' const')
if md.ret and md.only_for_definition:
self.write(' -> ')
md.ret.accept(self)
if md.pure:
self.write(' = 0')
def visitMethodDefn(self, md):
if md.decl.pure:
return
self.printdent()
md.decl.accept(self)
self.println()
self.printdentln('{')
self.indent()
self.visitBlock(md)
self.dedent()
self.printdentln('}')
def visitConstructorDecl(self, cd):
if cd.explicit:
self.write('explicit ')
else:
self.write('MOZ_IMPLICIT ')
self.visitMethodDecl(cd)
def visitConstructorDefn(self, cd):
self.printdent()
cd.decl.accept(self)
if len(cd.memberinits):
self.println(' :')
self.indent()
ninits = len(cd.memberinits)
for i, init in enumerate(cd.memberinits):
self.printdent()
init.accept(self)
if i != (ninits-1):
self.println(',')
self.dedent()
self.println()
self.printdentln('{')
self.indent()
self.visitBlock(cd)
self.dedent()
self.printdentln('}')
def visitDestructorDecl(self, dd):
if dd.inline:
self.write('inline ')
if dd.virtual:
self.write('virtual ')
# hack alert
parts = dd.name.split('::')
parts[-1] = '~'+ parts[-1]
self.write('::'.join(parts) +'()')
def visitDestructorDefn(self, dd):
self.printdent()
dd.decl.accept(self)
self.println()
self.printdentln('{')
self.indent()
self.visitBlock(dd)
self.dedent()
self.printdentln('}')
def visitExprLiteral(self, el):
self.write(str(el))
def visitExprVar(self, ev):
self.write(ev.name)
def visitExprPrefixUnop(self, e):
self.write('(')
self.write(e.op)
self.write('(')
e.expr.accept(self)
self.write(')')
self.write(')')
def visitExprCast(self, c):
pfx, sfx = '', ''
if c.dynamic: pfx, sfx = 'dynamic_cast<', '>'
elif c.static: pfx, sfx = 'static_cast<', '>'
elif c.reinterpret: pfx, sfx = 'reinterpret_cast<', '>'
elif c.const: pfx, sfx = 'const_cast<', '>'
elif c.C: pfx, sfx = '(', ')'
self.write(pfx)
c.type.accept(self)
self.write(sfx +'(')
c.expr.accept(self)
self.write(')')
def visitExprBinary(self, e):
self.write('(')
e.left.accept(self)
self.write(') '+ e.op +' (')
e.right.accept(self)
self.write(')')
def visitExprConditional(self, c):
self.write('(')
c.cond.accept(self)
self.write(' ? ')
c.ife.accept(self)
self.write(' : ')
c.elsee.accept(self)
self.write(')')
def visitExprIndex(self, ei):
ei.arr.accept(self)
self.write('[')
ei.idx.accept(self)
self.write(']')
def visitExprSelect(self, es):
self.write('(')
es.obj.accept(self)
self.write(')')
self.write(es.op + es.field)
def visitExprAssn(self, ea):
ea.lhs.accept(self)
self.write(' '+ ea.op +' ')
ea.rhs.accept(self)
def visitExprCall(self, ec):
ec.func.accept(self)
self.write('(')
self.writeExprList(ec.args)
self.write(')')
def visitExprMove(self, em):
self.visitExprCall(em)
def visitExprNew(self, en):
self.write('new ')
if en.newargs is not None:
self.write('(')
self.writeExprList(en.newargs)
self.write(') ')
en.ctype.accept(self)
if en.args is not None:
self.write('(')
self.writeExprList(en.args)
self.write(')')
def visitExprDelete(self, ed):
self.write('delete ')
ed.obj.accept(self)
def visitStmtBlock(self, b):
self.printdentln('{')
self.indent()
self.visitBlock(b)
self.dedent()
self.printdentln('}')
def visitLabel(self, label):
self.dedent() # better not be at global scope ...
self.printdentln(label.name +':')
self.indent()
def visitCaseLabel(self, cl):
self.dedent()
self.printdentln('case '+ cl.name +':')
self.indent()
def visitDefaultLabel(self, dl):
self.dedent()
self.printdentln('default:')
self.indent()
def visitStmtIf(self, si):
self.printdent('if (')
si.cond.accept(self)
self.println(') {')
self.indent()
si.ifb.accept(self)
self.dedent()
self.printdentln('}')
if si.elseb is not None:
self.printdentln('else {')
self.indent()
si.elseb.accept(self)
self.dedent()
self.printdentln('}')
def visitStmtFor(self, sf):
self.printdent('for (')
if sf.init is not None:
sf.init.accept(self)
self.write('; ')
if sf.cond is not None:
sf.cond.accept(self)
self.write('; ')
if sf.update is not None:
sf.update.accept(self)
self.println(') {')
self.indent()
self.visitBlock(sf)
self.dedent()
self.printdentln('}')
def visitStmtRangedFor(self, rf):
self.printdent('for (auto& ')
rf.var.accept(self)
self.write(' : ')
rf.iteree.accept(self)
self.println(') {')
self.indent()
self.visitBlock(rf)
self.dedent()
self.printdentln('}')
def visitStmtSwitch(self, sw):
self.printdent('switch (')
sw.expr.accept(self)
self.println(') {')
self.indent()
self.visitBlock(sw)
self.dedent()
self.printdentln('}')
def visitStmtBreak(self, sb):
self.printdentln('break;')
def visitStmtDecl(self, sd):
self.printdent()
sd.decl.accept(self)
if sd.initargs is not None:
self.write('(')
self.writeDeclList(sd.initargs)
self.write(')')
if sd.init is not None:
self.write(' = ')
sd.init.accept(self)
self.println(';')
def visitStmtExpr(self, se):
self.printdent()
se.expr.accept(self)
self.println(';')
def visitStmtReturn(self, sr):
self.printdent('return')
if sr.expr:
self.write (' ')
sr.expr.accept(self)
self.println(';')
def writeDeclList(self, decls):
# FIXME/cjones: try to do nice formatting of these guys
ndecls = len(decls)
if 0 == ndecls:
return
elif 1 == ndecls:
decls[0].accept(self)
return
self.indent()
self.indent()
for i, decl in enumerate(decls):
self.println()
self.printdent()
decl.accept(self)
if i != (ndecls-1):
self.write(',')
self.dedent()
self.dedent()
def writeExprList(self, exprs):
# FIXME/cjones: try to do nice formatting and share code with
# writeDeclList()
nexprs = len(exprs)
for i, expr in enumerate(exprs):
expr.accept(self)
if i != (nexprs-1):
self.write(', ')

4822
ipc/ipdl/ipdl/lower.py Normal file

File diff suppressed because it is too large Load diff

807
ipc/ipdl/ipdl/parser.py Normal file
View file

@ -0,0 +1,807 @@
# 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/.
import os, sys
from ply import lex, yacc
from ipdl.ast import *
def _getcallerpath():
'''Return the absolute path of the file containing the code that
**CALLED** this function.'''
return os.path.abspath(sys._getframe(1).f_code.co_filename)
##-----------------------------------------------------------------------------
class ParseError(Exception):
def __init__(self, loc, fmt, *args):
self.loc = loc
self.error = ('%s%s: error: %s'% (
Parser.includeStackString(), loc, fmt)) % args
def __str__(self):
return self.error
def _safeLinenoValue(t):
lineno, value = 0, '???'
if hasattr(t, 'lineno'): lineno = t.lineno
if hasattr(t, 'value'): value = t.value
return lineno, value
def _error(loc, fmt, *args):
raise ParseError(loc, fmt, *args)
class Parser:
# when we reach an |include [protocol] foo;| statement, we need to
# save the current parser state and create a new one. this "stack" is
# where that state is saved
#
# there is one Parser per file
current = None
parseStack = [ ]
parsed = { }
def __init__(self, type, name, debug=0):
assert type and name
self.type = type
self.debug = debug
self.filename = None
self.includedirs = None
self.loc = None # not always up to date
self.lexer = None
self.parser = None
self.tu = TranslationUnit(type, name)
self.direction = None
self.errout = None
def parse(self, input, filename, includedirs, errout):
assert os.path.isabs(filename)
if filename in Parser.parsed:
return Parser.parsed[filename].tu
self.lexer = lex.lex(debug=self.debug,
optimize=not self.debug,
lextab="ipdl_lextab")
self.parser = yacc.yacc(debug=self.debug,
optimize=not self.debug,
tabmodule="ipdl_yacctab")
self.filename = filename
self.includedirs = includedirs
self.tu.filename = filename
self.errout = errout
Parser.parsed[filename] = self
Parser.parseStack.append(Parser.current)
Parser.current = self
try:
ast = self.parser.parse(input=input, lexer=self.lexer,
debug=self.debug)
except ParseError, p:
print >>errout, p
return None
Parser.current = Parser.parseStack.pop()
return ast
def resolveIncludePath(self, filepath):
'''Return the absolute path from which the possibly partial
|filepath| should be read, or |None| if |filepath| cannot be located.'''
for incdir in self.includedirs +[ '' ]:
realpath = os.path.join(incdir, filepath)
if os.path.isfile(realpath):
return os.path.abspath(realpath)
return None
# returns a GCC-style string representation of the include stack.
# e.g.,
# in file included from 'foo.ipdl', line 120:
# in file included from 'bar.ipd', line 12:
# which can be printed above a proper error message or warning
@staticmethod
def includeStackString():
s = ''
for parse in Parser.parseStack[1:]:
s += " in file included from `%s', line %d:\n"% (
parse.loc.filename, parse.loc.lineno)
return s
def locFromTok(p, num):
return Loc(Parser.current.filename, p.lineno(num))
##-----------------------------------------------------------------------------
reserved = set((
'answer',
'as',
'async',
'both',
'bridges',
'call',
'child',
'class',
'compress',
'compressall',
'__delete__',
'delete', # reserve 'delete' to prevent its use
'from',
'goto',
'include',
'intr',
'manager',
'manages',
'namespace',
'nested',
'nullable',
'opens',
'or',
'parent',
'prio',
'protocol',
'recv',
'returns',
'send',
'spawns',
'start',
'state',
'struct',
'sync',
'union',
'upto',
'using',
'verify'))
tokens = [
'COLONCOLON', 'ID', 'STRING',
] + [ r.upper() for r in reserved ]
t_COLONCOLON = '::'
literals = '(){}[]<>;:,~'
t_ignore = ' \f\t\v'
def t_linecomment(t):
r'//[^\n]*'
def t_multilinecomment(t):
r'/\*(\n|.)*?\*/'
t.lexer.lineno += t.value.count('\n')
def t_NL(t):
r'(?:\r\n|\n|\n)+'
t.lexer.lineno += len(t.value)
def t_ID(t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
if t.value in reserved:
t.type = t.value.upper()
return t
def t_STRING(t):
r'"[^"\n]*"'
t.value = t.value[1:-1]
return t
def t_error(t):
_error(Loc(Parser.current.filename, t.lineno),
'lexically invalid characters `%s', t.value)
##-----------------------------------------------------------------------------
def p_TranslationUnit(p):
"""TranslationUnit : Preamble NamespacedStuff"""
tu = Parser.current.tu
tu.loc = Loc(tu.filename)
for stmt in p[1]:
if isinstance(stmt, CxxInclude):
tu.addCxxInclude(stmt)
elif isinstance(stmt, Include):
tu.addInclude(stmt)
elif isinstance(stmt, UsingStmt):
tu.addUsingStmt(stmt)
else:
assert 0
for thing in p[2]:
if isinstance(thing, StructDecl):
tu.addStructDecl(thing)
elif isinstance(thing, UnionDecl):
tu.addUnionDecl(thing)
elif isinstance(thing, Protocol):
if tu.protocol is not None:
_error(thing.loc, "only one protocol definition per file")
tu.protocol = thing
else:
assert(0)
# The "canonical" namespace of the tu, what it's considered to be
# in for the purposes of C++: |#include "foo/bar/TU.h"|
if tu.protocol:
assert tu.filetype == 'protocol'
tu.namespaces = tu.protocol.namespaces
tu.name = tu.protocol.name
else:
assert tu.filetype == 'header'
# There's not really a canonical "thing" in headers. So
# somewhat arbitrarily use the namespace of the last
# interesting thing that was declared.
for thing in reversed(tu.structsAndUnions):
tu.namespaces = thing.namespaces
break
p[0] = tu
##--------------------
## Preamble
def p_Preamble(p):
"""Preamble : Preamble PreambleStmt ';'
|"""
if 1 == len(p):
p[0] = [ ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_PreambleStmt(p):
"""PreambleStmt : CxxIncludeStmt
| IncludeStmt
| UsingStmt"""
p[0] = p[1]
def p_CxxIncludeStmt(p):
"""CxxIncludeStmt : INCLUDE STRING"""
p[0] = CxxInclude(locFromTok(p, 1), p[2])
def p_IncludeStmt(p):
"""IncludeStmt : INCLUDE PROTOCOL ID
| INCLUDE ID"""
loc = locFromTok(p, 1)
Parser.current.loc = loc
if 4 == len(p):
id = p[3]
type = 'protocol'
else:
id = p[2]
type = 'header'
inc = Include(loc, type, id)
path = Parser.current.resolveIncludePath(inc.file)
if path is None:
raise ParseError(loc, "can't locate include file `%s'"% (
inc.file))
inc.tu = Parser(type, id).parse(open(path).read(), path, Parser.current.includedirs, Parser.current.errout)
p[0] = inc
def p_UsingStmt(p):
"""UsingStmt : USING CxxType FROM STRING
| USING CLASS CxxType FROM STRING
| USING STRUCT CxxType FROM STRING"""
if 6 == len(p):
header = p[5]
elif 5 == len(p):
header = p[4]
else:
header = None
if 6 == len(p):
kind = p[2]
else:
kind = None
if 6 == len(p):
cxxtype = p[3]
else:
cxxtype = p[2]
p[0] = UsingStmt(locFromTok(p, 1), cxxtype, header, kind)
##--------------------
## Namespaced stuff
def p_NamespacedStuff(p):
"""NamespacedStuff : NamespacedStuff NamespaceThing
| NamespaceThing"""
if 2 == len(p):
p[0] = p[1]
else:
p[1].extend(p[2])
p[0] = p[1]
def p_NamespaceThing(p):
"""NamespaceThing : NAMESPACE ID '{' NamespacedStuff '}'
| StructDecl
| UnionDecl
| ProtocolDefn"""
if 2 == len(p):
p[0] = [ p[1] ]
else:
for thing in p[4]:
thing.addOuterNamespace(Namespace(locFromTok(p, 1), p[2]))
p[0] = p[4]
def p_StructDecl(p):
"""StructDecl : STRUCT ID '{' StructFields '}' ';'
| STRUCT ID '{' '}' ';'"""
if 7 == len(p):
p[0] = StructDecl(locFromTok(p, 1), p[2], p[4])
else:
p[0] = StructDecl(locFromTok(p, 1), p[2], [ ])
def p_StructFields(p):
"""StructFields : StructFields StructField ';'
| StructField ';'"""
if 3 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_StructField(p):
"""StructField : Type ID"""
p[0] = StructField(locFromTok(p, 1), p[1], p[2])
def p_UnionDecl(p):
"""UnionDecl : UNION ID '{' ComponentTypes '}' ';'"""
p[0] = UnionDecl(locFromTok(p, 1), p[2], p[4])
def p_ComponentTypes(p):
"""ComponentTypes : ComponentTypes Type ';'
| Type ';'"""
if 3 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_ProtocolDefn(p):
"""ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
protocol = p[5]
protocol.loc = locFromTok(p, 2)
protocol.name = p[3]
protocol.nestedRange = p[1][0]
protocol.sendSemantics = p[1][1]
p[0] = protocol
if Parser.current.type == 'header':
_error(protocol.loc, 'can\'t define a protocol in a header. Do it in a protocol spec instead.')
def p_ProtocolBody(p):
"""ProtocolBody : SpawnsStmtsOpt"""
p[0] = p[1]
##--------------------
## spawns/bridges/opens stmts
def p_SpawnsStmtsOpt(p):
"""SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
| BridgesStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].spawnsStmts.insert(0, p[1])
p[0] = p[2]
def p_SpawnsStmt(p):
"""SpawnsStmt : PARENT SPAWNS ID AsOpt ';'
| CHILD SPAWNS ID AsOpt ';'"""
p[0] = SpawnsStmt(locFromTok(p, 1), p[1], p[3], p[4])
def p_AsOpt(p):
"""AsOpt : AS PARENT
| AS CHILD
| """
if 3 == len(p):
p[0] = p[2]
else:
p[0] = 'child'
def p_BridgesStmtsOpt(p):
"""BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
| OpensStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].bridgesStmts.insert(0, p[1])
p[0] = p[2]
def p_BridgesStmt(p):
"""BridgesStmt : BRIDGES ID ',' ID ';'"""
p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])
def p_OpensStmtsOpt(p):
"""OpensStmtsOpt : OpensStmt OpensStmtsOpt
| ManagersStmtOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].opensStmts.insert(0, p[1])
p[0] = p[2]
def p_OpensStmt(p):
"""OpensStmt : PARENT OPENS ID ';'
| CHILD OPENS ID ';'"""
p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])
##--------------------
## manager/manages stmts
def p_ManagersStmtOpt(p):
"""ManagersStmtOpt : ManagersStmt ManagesStmtsOpt
| ManagesStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].managers = p[1]
p[0] = p[2]
def p_ManagersStmt(p):
"""ManagersStmt : MANAGER ManagerList ';'"""
if 1 == len(p):
p[0] = [ ]
else:
p[0] = p[2]
def p_ManagerList(p):
"""ManagerList : ID
| ManagerList OR ID"""
if 2 == len(p):
p[0] = [ Manager(locFromTok(p, 1), p[1]) ]
else:
p[1].append(Manager(locFromTok(p, 3), p[3]))
p[0] = p[1]
def p_ManagesStmtsOpt(p):
"""ManagesStmtsOpt : ManagesStmt ManagesStmtsOpt
| MessageDeclsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].managesStmts.insert(0, p[1])
p[0] = p[2]
def p_ManagesStmt(p):
"""ManagesStmt : MANAGES ID ';'"""
p[0] = ManagesStmt(locFromTok(p, 1), p[2])
##--------------------
## Message decls
def p_MessageDeclsOpt(p):
"""MessageDeclsOpt : MessageDeclThing MessageDeclsOpt
| TransitionStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].messageDecls.insert(0, p[1])
p[0] = p[2]
def p_MessageDeclThing(p):
"""MessageDeclThing : MessageDirectionLabel ':' MessageDecl ';'
| MessageDecl ';'"""
if 3 == len(p):
p[0] = p[1]
else:
p[0] = p[3]
def p_MessageDirectionLabel(p):
"""MessageDirectionLabel : PARENT
| CHILD
| BOTH"""
if p[1] == 'parent':
Parser.current.direction = IN
elif p[1] == 'child':
Parser.current.direction = OUT
elif p[1] == 'both':
Parser.current.direction = INOUT
else:
assert 0
def p_MessageDecl(p):
"""MessageDecl : SendSemanticsQual MessageBody"""
msg = p[2]
msg.nested = p[1][0]
msg.prio = p[1][1]
msg.sendSemantics = p[1][2]
if Parser.current.direction is None:
_error(msg.loc, 'missing message direction')
msg.direction = Parser.current.direction
p[0] = msg
def p_MessageBody(p):
"""MessageBody : MessageId MessageInParams MessageOutParams OptionalMessageModifiers"""
# FIXME/cjones: need better loc info: use one of the quals
loc, name = p[1]
msg = MessageDecl(loc)
msg.name = name
msg.addInParams(p[2])
msg.addOutParams(p[3])
msg.addModifiers(p[4])
p[0] = msg
def p_MessageId(p):
"""MessageId : ID
| __DELETE__
| DELETE
| '~' ID"""
loc = locFromTok(p, 1)
if 3 == len(p):
_error(loc, "sorry, `%s()' destructor syntax is a relic from a bygone era. Declare `__delete__()' in the `%s' protocol instead", p[1]+p[2], p[2])
elif 'delete' == p[1]:
_error(loc, "`delete' is a reserved identifier")
p[0] = [ loc, p[1] ]
def p_MessageInParams(p):
"""MessageInParams : '(' ParamList ')'"""
p[0] = p[2]
def p_MessageOutParams(p):
"""MessageOutParams : RETURNS '(' ParamList ')'
| """
if 1 == len(p):
p[0] = [ ]
else:
p[0] = p[3]
def p_OptionalMessageModifiers(p):
"""OptionalMessageModifiers : OptionalMessageModifiers MessageModifier
| MessageModifier
| """
if 1 == len(p):
p[0] = [ ]
elif 2 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_MessageModifier(p):
""" MessageModifier : MessageVerify
| MessageCompress """
p[0] = p[1]
def p_MessageVerify(p):
"""MessageVerify : VERIFY"""
p[0] = p[1]
def p_MessageCompress(p):
"""MessageCompress : COMPRESS
| COMPRESSALL"""
p[0] = p[1]
##--------------------
## State machine
def p_TransitionStmtsOpt(p):
"""TransitionStmtsOpt : TransitionStmt TransitionStmtsOpt
|"""
if 1 == len(p):
# we fill in |loc| in the Protocol rule
p[0] = Protocol(None)
else:
p[2].transitionStmts.insert(0, p[1])
p[0] = p[2]
def p_TransitionStmt(p):
"""TransitionStmt : OptionalStart STATE State ':' Transitions"""
p[3].start = p[1]
p[0] = TransitionStmt(locFromTok(p, 2), p[3], p[5])
def p_OptionalStart(p):
"""OptionalStart : START
| """
p[0] = (len(p) == 2) # True iff 'start' specified
def p_Transitions(p):
"""Transitions : Transitions Transition
| Transition"""
if 3 == len(p):
p[1].append(p[2])
p[0] = p[1]
else:
p[0] = [ p[1] ]
def p_Transition(p):
"""Transition : Trigger ID GOTO StateList ';'
| Trigger __DELETE__ ';'
| Trigger DELETE ';'"""
if 'delete' == p[2]:
_error(locFromTok(p, 1), "`delete' is a reserved identifier")
loc, trigger = p[1]
if 6 == len(p):
nextstates = p[4]
else:
nextstates = [ State.DEAD ]
p[0] = Transition(loc, trigger, p[2], nextstates)
def p_Trigger(p):
"""Trigger : SEND
| RECV
| CALL
| ANSWER"""
p[0] = [ locFromTok(p, 1), Transition.nameToTrigger(p[1]) ]
def p_StateList(p):
"""StateList : StateList OR State
| State"""
if 2 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[3])
p[0] = p[1]
def p_State(p):
"""State : ID"""
p[0] = State(locFromTok(p, 1), p[1])
##--------------------
## Minor stuff
def p_Nested(p):
"""Nested : ID"""
kinds = {'not': 1,
'inside_sync': 2,
'inside_cpow': 3}
if p[1] not in kinds:
_error(locFromTok(p, 1), "Expected not, inside_sync, or inside_cpow for nested()")
p[0] = { 'nested': kinds[p[1]] }
def p_Priority(p):
"""Priority : ID"""
kinds = {'normal': 1,
'high': 2}
if p[1] not in kinds:
_error(locFromTok(p, 1), "Expected normal or high for prio()")
p[0] = { 'prio': kinds[p[1]] }
def p_SendQualifier(p):
"""SendQualifier : NESTED '(' Nested ')'
| PRIO '(' Priority ')'"""
p[0] = p[3]
def p_SendQualifierList(p):
"""SendQualifierList : SendQualifier SendQualifierList
| """
if len(p) > 1:
p[0] = p[1]
p[0].update(p[2])
else:
p[0] = {}
def p_SendSemanticsQual(p):
"""SendSemanticsQual : SendQualifierList ASYNC
| SendQualifierList SYNC
| INTR"""
quals = {}
if len(p) == 3:
quals = p[1]
mtype = p[2]
else:
mtype = 'intr'
if mtype == 'async': mtype = ASYNC
elif mtype == 'sync': mtype = SYNC
elif mtype == 'intr': mtype = INTR
else: assert 0
p[0] = [ quals.get('nested', NOT_NESTED), quals.get('prio', NORMAL_PRIORITY), mtype ]
def p_OptionalProtocolSendSemanticsQual(p):
"""OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
| """
if 2 == len(p): p[0] = p[1]
else: p[0] = [ (NOT_NESTED, NOT_NESTED), ASYNC ]
def p_ProtocolSendSemanticsQual(p):
"""ProtocolSendSemanticsQual : ASYNC
| SYNC
| NESTED '(' UPTO Nested ')' ASYNC
| NESTED '(' UPTO Nested ')' SYNC
| INTR"""
if p[1] == 'nested':
mtype = p[6]
nested = (NOT_NESTED, p[4])
else:
mtype = p[1]
nested = (NOT_NESTED, NOT_NESTED)
if mtype == 'async': mtype = ASYNC
elif mtype == 'sync': mtype = SYNC
elif mtype == 'intr': mtype = INTR
else: assert 0
p[0] = [ nested, mtype ]
def p_ParamList(p):
"""ParamList : ParamList ',' Param
| Param
| """
if 1 == len(p):
p[0] = [ ]
elif 2 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[3])
p[0] = p[1]
def p_Param(p):
"""Param : Type ID"""
p[0] = Param(locFromTok(p, 1), p[1], p[2])
def p_Type(p):
"""Type : MaybeNullable BasicType"""
# only actor types are nullable; we check this in the type checker
p[2].nullable = p[1]
p[0] = p[2]
def p_BasicType(p):
"""BasicType : ScalarType
| ScalarType '[' ']'"""
if 4 == len(p):
p[1].array = 1
p[0] = p[1]
def p_ScalarType(p):
"""ScalarType : ActorType
| CxxID""" # ID == CxxType; we forbid qnames here,
# in favor of the |using| declaration
if isinstance(p[1], TypeSpec):
p[0] = p[1]
else:
loc, id = p[1]
p[0] = TypeSpec(loc, QualifiedId(loc, id))
def p_ActorType(p):
"""ActorType : ID ':' State"""
loc = locFromTok(p, 1)
p[0] = TypeSpec(loc, QualifiedId(loc, p[1]), state=p[3])
def p_MaybeNullable(p):
"""MaybeNullable : NULLABLE
| """
p[0] = (2 == len(p))
##--------------------
## C++ stuff
def p_CxxType(p):
"""CxxType : QualifiedID
| CxxID"""
if isinstance(p[1], QualifiedId):
p[0] = TypeSpec(p[1].loc, p[1])
else:
loc, id = p[1]
p[0] = TypeSpec(loc, QualifiedId(loc, id))
def p_QualifiedID(p):
"""QualifiedID : QualifiedID COLONCOLON CxxID
| CxxID COLONCOLON CxxID"""
if isinstance(p[1], QualifiedId):
loc, id = p[3]
p[1].qualify(id)
p[0] = p[1]
else:
loc1, id1 = p[1]
_, id2 = p[3]
p[0] = QualifiedId(loc1, id2, [ id1 ])
def p_CxxID(p):
"""CxxID : ID
| CxxTemplateInst"""
if isinstance(p[1], tuple):
p[0] = p[1]
else:
p[0] = (locFromTok(p, 1), str(p[1]))
def p_CxxTemplateInst(p):
"""CxxTemplateInst : ID '<' ID '>'"""
p[0] = (locFromTok(p, 1), str(p[1]) +'<'+ str(p[3]) +'>')
def p_error(t):
lineno, value = _safeLinenoValue(t)
_error(Loc(Parser.current.filename, lineno),
"bad syntax near `%s'", value)

2200
ipc/ipdl/ipdl/type.py Normal file

File diff suppressed because it is too large Load diff

19
ipc/ipdl/moz.build Normal file
View file

@ -0,0 +1,19 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
if CONFIG['MOZ_IPDL_TESTS']:
DIRS += ['test']
include('/ipc/chromium/chromium-config.mozbuild')
# Generated by ipdl.py
SOURCES += ['!IPCMessageTypeName.cpp']
FINAL_LIBRARY = 'xul'
# We #include some things in the dom/plugins/ directory that rely on
# toolkit libraries.
CXXFLAGS += CONFIG['TK_CFLAGS']

View file

@ -0,0 +1,13 @@
#!/usr/bin/python
# 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/.
import sys
msgid = int(sys.argv[1])
protocol = (msgid >> 16)
msg = (msgid - (protocol << 16))
print 'protocol', protocol, 'message', msg

10
ipc/ipdl/test/README.txt Normal file
View file

@ -0,0 +1,10 @@
There are two major categories of tests, segregated into different
top-level directories under test/.
The first category (ipdl/) is IPDL-compiler tests. These tests check
that the IPDL compiler is successfully compiling correct
specifications, and successfully rejecting erroneous specifications.
The second category (cxx/) is C++ tests of IPDL semantics. These
tests check that async/sync/rpc semantics are implemented correctly,
ctors/dtors behave as they should, etc.

View file

@ -0,0 +1,32 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#include "mozilla/ipc/IOThreadChild.h"
#include "IPDLUnitTestProcessChild.h"
#include "IPDLUnitTests.h"
#include "nsRegion.h"
using mozilla::ipc::IOThreadChild;
namespace mozilla {
namespace _ipdltest {
bool
IPDLUnitTestProcessChild::Init()
{
IPDLUnitTestChildInit(IOThreadChild::channel(),
ParentPid(),
IOThreadChild::message_loop());
if (NS_FAILED(nsRegion::InitStatic()))
return false;
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,32 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1
#include "mozilla/ipc/ProcessChild.h"
namespace mozilla {
namespace _ipdltest {
class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild
{
typedef mozilla::ipc::ProcessChild ProcessChild;
public:
explicit IPDLUnitTestProcessChild(ProcessId aParentPid) :
ProcessChild(aParentPid)
{ }
~IPDLUnitTestProcessChild()
{ }
virtual bool Init();
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#include "IPDLUnitTestSubprocess.h"
using mozilla::ipc::GeckoChildProcessHost;
namespace mozilla {
namespace _ipdltest {
IPDLUnitTestSubprocess::IPDLUnitTestSubprocess() :
GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest)
{
}
IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess()
{
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1
#include "mozilla/ipc/GeckoChildProcessHost.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost
{
public:
IPDLUnitTestSubprocess();
~IPDLUnitTestSubprocess();
/**
* Asynchronously launch the plugin process.
*/
// Could override parent Launch, but don't need to here
//bool Launch();
private:
DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess);
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
#define mozilla__ipdltest_IPDLUnitTestTypes_h
#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason
namespace mozilla {
namespace _ipdltest {
struct DirtyRect
{
int x; int y; int w; int h;
};
}
}
namespace IPC {
template<>
struct ParamTraits<mozilla::_ipdltest::DirtyRect>
{
typedef mozilla::_ipdltest::DirtyRect paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.x);
WriteParam(aMsg, aParam.y);
WriteParam(aMsg, aParam.w);
WriteParam(aMsg, aParam.h);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->x) &&
ReadParam(aMsg, aIter, &aResult->y) &&
ReadParam(aMsg, aIter, &aResult->w) &&
ReadParam(aMsg, aIter, &aResult->h));
}
};
}
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h

View file

@ -0,0 +1,27 @@
#ifndef mozilla__ipdltest_IPDLUnitTestUtils
#define mozilla__ipdltest_IPDLUnitTestUtils 1
namespace mozilla {
namespace _ipdltest {
struct Bad {};
} // namespace _ipdltest
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::_ipdltest::Bad>
{
typedef mozilla::_ipdltest::Bad paramType;
// Defined in TestActorPunning.cpp.
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
};
} // namespace IPC
#endif // mozilla__ipdltest_IPDLUnitTestUtils

View file

@ -0,0 +1,93 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#ifndef mozilla__ipdltest_IPDLUnitTests_h
#define mozilla__ipdltest_IPDLUnitTests_h 1
#include "base/message_loop.h"
#include "base/process.h"
#include "chrome/common/ipc_channel.h"
#include "nsIAppShell.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsServiceManagerUtils.h" // do_GetService()
#include "nsWidgetsCID.h" // NS_APPSHELL_CID
#include "nsXULAppAPI.h"
#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL"
#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS"
#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// both processes
const char* IPDLUnitTestName();
// NB: these are named like the similar functions in
// xpcom/test/TestHarness.h. The names should nominally be kept in
// sync.
inline void fail(const char* fmt, ...)
{
va_list ap;
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName());
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
NS_RUNTIMEABORT("failed test");
}
inline void passed(const char* fmt, ...)
{
va_list ap;
printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName());
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
}
//-----------------------------------------------------------------------------
// parent process only
class IPDLUnitTestSubprocess;
extern void* gParentActor;
extern IPDLUnitTestSubprocess* gSubprocess;
void IPDLUnitTestMain(void* aData);
void QuitParent();
//-----------------------------------------------------------------------------
// child process only
extern void* gChildActor;
void IPDLUnitTestChildInit(IPC::Channel* transport,
base::ProcessId parentPid,
MessageLoop* worker);
void QuitChild();
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h

View file

@ -0,0 +1,390 @@
//
// Autogenerated from Python template. Hands off.
//
#include <stdlib.h>
#include <string.h>
#include "IPDLUnitTests.h"
#include "base/command_line.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "nsRegion.h"
#include "IPDLUnitTestSubprocess.h"
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${INCLUDES}
//-----------------------------------------------------------------------------
using namespace std;
using base::Thread;
namespace mozilla {
namespace _ipdltest {
void* gParentActor;
IPDLUnitTestSubprocess* gSubprocess;
void* gChildActor;
// Note: in threaded mode, this will be non-null (for both parent and
// child, since they share one set of globals).
Thread* gChildThread;
MessageLoop *gParentMessageLoop;
bool gParentDone;
bool gChildDone;
void
DeleteChildActor();
//-----------------------------------------------------------------------------
// data/functions accessed by both parent and child processes
char* gIPDLUnitTestName = nullptr;
const char*
IPDLUnitTestName()
{
if (!gIPDLUnitTestName) {
#if defined(OS_WIN)
vector<wstring> args =
CommandLine::ForCurrentProcess()->GetLooseValues();
gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str());
#elif defined(OS_POSIX)
vector<string> argv = CommandLine::ForCurrentProcess()->argv();
gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str());
#else
# error Sorry
#endif
}
return gIPDLUnitTestName;
}
} // namespace _ipdltest
} // namespace mozilla
namespace {
enum IPDLUnitTestType {
NoneTest = 0,
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_VALUES}
LastTest = ${LAST_ENUM}
//-----------------------------------------------------------------------------
};
IPDLUnitTestType
IPDLUnitTestFromString(const char* const aString)
{
if (!aString)
return static_cast<IPDLUnitTestType>(0);
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${STRING_TO_ENUMS}
//-----------------------------------------------------------------------------
else
return static_cast<IPDLUnitTestType>(0);
}
const char*
IPDLUnitTestToString(IPDLUnitTestType aTest)
{
switch (aTest) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_TO_STRINGS}
//-----------------------------------------------------------------------------
default:
return nullptr;
}
}
IPDLUnitTestType
IPDLUnitTest()
{
return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName());
}
} // namespace <anon>
//-----------------------------------------------------------------------------
// parent process only
namespace mozilla {
namespace _ipdltest {
void
DeferredParentShutdown();
void
IPDLUnitTestThreadMain(char *testString);
void
IPDLUnitTestMain(void* aData)
{
char* testString = reinterpret_cast<char*>(aData);
// Check if we are to run the test using threads instead:
const char *prefix = "thread:";
const int prefixLen = strlen(prefix);
if (!strncmp(testString, prefix, prefixLen)) {
IPDLUnitTestThreadMain(testString + prefixLen);
return;
}
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
if (!test) {
// use this instead of |fail()| because we don't know what the test is
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
"<--->", testString);
NS_RUNTIMEABORT("can't continue");
}
gIPDLUnitTestName = testString;
// Check whether this test is enabled for processes:
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_ENABLED_CASES_PROC}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
std::vector<std::string> testCaseArgs;
testCaseArgs.push_back(testString);
gSubprocess = new IPDLUnitTestSubprocess();
if (!gSubprocess->SyncLaunch(testCaseArgs))
fail("problem launching subprocess");
IPC::Channel* transport = gSubprocess->GetChannel();
if (!transport)
fail("no transport");
base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle());
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_MAIN_CASES_PROC}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
void
IPDLUnitTestThreadMain(char *testString)
{
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
if (!test) {
// use this instead of |fail()| because we don't know what the test is
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
"<--->", testString);
NS_RUNTIMEABORT("can't continue");
}
gIPDLUnitTestName = testString;
// Check whether this test is enabled for threads:
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_ENABLED_CASES_THREAD}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
std::vector<std::string> testCaseArgs;
testCaseArgs.push_back(testString);
gChildThread = new Thread("ParentThread");
if (!gChildThread->Start())
fail("starting parent thread");
gParentMessageLoop = MessageLoop::current();
MessageLoop *childMessageLoop = gChildThread->message_loop();
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_MAIN_CASES_THREAD}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
void
DeleteParentActor()
{
if (!gParentActor)
return;
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_DELETE_CASES}
//-----------------------------------------------------------------------------
default: ::mozilla::_ipdltest::fail("???");
}
}
void
QuitXPCOM()
{
DeleteParentActor();
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
appShell->Exit();
}
void
DeleteSubprocess(MessageLoop* uiLoop)
{
// pong to QuitXPCOM
delete gSubprocess;
uiLoop->PostTask(NewRunnableFunction(QuitXPCOM));
}
void
DeferredParentShutdown()
{
// ping to DeleteSubprocess
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(DeleteSubprocess, MessageLoop::current()));
}
void
TryThreadedShutdown()
{
// Stop if either:
// - the child has not finished,
// - the parent has not finished,
// - or this code has already executed.
// Remember: this TryThreadedShutdown() task is enqueued
// by both parent and child (though always on parent's msg loop).
if (!gChildDone || !gParentDone || !gChildThread)
return;
delete gChildThread;
gChildThread = 0;
DeferredParentShutdown();
}
void
ChildCompleted()
{
// Executes on the parent message loop once child has completed.
gChildDone = true;
TryThreadedShutdown();
}
void
QuitParent()
{
if (gChildThread) {
gParentDone = true;
MessageLoop::current()->PostTask(
NewRunnableFunction(TryThreadedShutdown));
} else {
// defer "real" shutdown to avoid *Channel::Close() racing with the
// deletion of the subprocess
MessageLoop::current()->PostTask(
NewRunnableFunction(DeferredParentShutdown));
}
}
static void
ChildDie()
{
DeleteChildActor();
XRE_ShutdownChildProcess();
}
void
QuitChild()
{
if (gChildThread) { // Threaded-mode test
gParentMessageLoop->PostTask(
NewRunnableFunction(ChildCompleted));
} else { // Process-mode test
MessageLoop::current()->PostTask(
NewRunnableFunction(ChildDie));
}
}
} // namespace _ipdltest
} // namespace mozilla
//-----------------------------------------------------------------------------
// child process only
namespace mozilla {
namespace _ipdltest {
void
DeleteChildActor()
{
if (!gChildActor)
return;
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_DELETE_CASES}
//-----------------------------------------------------------------------------
default: ::mozilla::_ipdltest::fail("???");
}
}
void
IPDLUnitTestChildInit(IPC::Channel* transport,
base::ProcessId parentPid,
MessageLoop* worker)
{
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_INIT_CASES}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,46 @@
# 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/.
IPDLTESTSRCS = $(filter Test%,$(CPPSRCS))
IPDLTESTS = $(IPDLTESTSRCS:.cpp=)
EXTRA_PROTOCOLS = \
TestBridgeSub \
TestEndpointBridgeSub \
$(NULL)
IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
GENTESTER := $(srcdir)/genIPDLUnitTests.py
include $(topsrcdir)/config/rules.mk
IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
check-proc::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \
done
check-thread::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \
done
check:: check-proc check-thread
check-valgrind::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) -g -d \
valgrind -a '--leak-check=full --trace-children=yes -q' \
$(IPDLUNITTEST_BIN) $$test ; \
done

View file

@ -0,0 +1,39 @@
include protocol PTestActorPunningPunned;
include protocol PTestActorPunningSub;
include "mozilla/_ipdltest/IPDLUnitTestUtils.h";
using struct mozilla::_ipdltest::Bad from "mozilla/_ipdltest/IPDLUnitTestUtils.h";
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunning {
manages PTestActorPunningPunned;
manages PTestActorPunningSub;
child:
async Start();
parent:
async PTestActorPunningPunned();
async PTestActorPunningSub();
async Pun(PTestActorPunningSub a, Bad bad);
async __delete__();
state PING:
send Start goto CONSTRUCTING;
state CONSTRUCTING:
recv PTestActorPunningPunned goto CONSTRUCTING;
recv PTestActorPunningSub goto CONSTRUCTING;
recv Pun goto DEAD;
// We never make it past this transition, --> error.
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,15 @@
include protocol PTestActorPunning;
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunningPunned {
manager PTestActorPunning;
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltes

View file

@ -0,0 +1,16 @@
include protocol PTestActorPunning;
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunningSub {
manager PTestActorPunning;
child:
async Bad();
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltes

View file

@ -0,0 +1,18 @@
include protocol PTestBadActorSub;
namespace mozilla {
namespace _ipdltest {
// Test that a parent sending a reentrant __delete__ message
// is not killed if a child's message races with the reply.
intr protocol PTestBadActor {
manages PTestBadActorSub;
child:
async PTestBadActorSub();
async __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,17 @@
include protocol PTestBadActor;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestBadActorSub {
manager PTestBadActor;
child:
intr __delete__();
parent:
async Ping();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,26 @@
include protocol PTestBridgeMainSub;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeMain {
child spawns PTestBridgeSub;
child opens PTestBridgeMainSub;
child:
async Start();
parent:
async __delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,33 @@
include protocol PTestBridgeMain;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
intr protocol PTestBridgeMainSub {
bridges PTestBridgeMain, PTestBridgeSub;
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
include protocol PTestBridgeMainSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeSub {
child:
async Ping();
parent:
async BridgeEm();
async __delete__();
state START:
send Ping goto BRIDGEEM;
state BRIDGEEM:
recv BridgeEm goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,36 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_sync) sync protocol PTestCancel
{
// Test1
child:
nested(inside_sync) sync Test1_1();
parent:
async Done1();
// Test2
child:
async Start2();
nested(inside_sync) sync Test2_2();
parent:
sync Test2_1();
// Test3
child:
nested(inside_sync) sync Test3_1();
parent:
async Start3();
nested(inside_sync) sync Test3_2();
parent:
async Done();
child:
nested(inside_sync) sync CheckChild() returns (uint32_t reply);
parent:
nested(inside_sync) sync CheckParent() returns (uint32_t reply);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,22 @@
// See bug 538586: if the top-level protocol's actor is deleted before
// the "connection error" notification comes in from the IO thread,
// IPDL teardown never occurs, even if Channel::Close() is called
// after the error.
namespace mozilla {
namespace _ipdltest {
// NB: needs to be RPC so that the parent blocks on the child's crash.
intr protocol PTestCrashCleanup {
child:
intr DIEDIEDIE();
async __delete__();
state ALIVE:
call DIEDIEDIE goto CRASH;
state CRASH:
send __delete__;
};
}
}

View file

@ -0,0 +1,132 @@
include protocol PTestDataStructuresSub;
include PTestDataStructuresCommon;
include "mozilla/GfxMessageUtils.h";
namespace mozilla {
namespace _ipdltest {
sync protocol PTestDataStructures {
manages PTestDataStructuresSub;
child:
async PTestDataStructuresSub(int i);
async Start();
parent:
async __delete__();
sync Test1(int[] i1)
returns (int[] o1);
sync Test2(PTestDataStructuresSub[] i1)
returns (PTestDataStructuresSub[] o1);
sync Test3(IntDouble i1,
IntDouble i2)
returns (IntDouble o1,
IntDouble o2);
sync Test4(IntDouble[] i1)
returns (IntDouble[] o1);
sync Test5(IntDoubleArrays i1,
IntDoubleArrays i2,
IntDoubleArrays i3)
returns (IntDoubleArrays o1,
IntDoubleArrays o2,
IntDoubleArrays o3);
sync Test6(IntDoubleArrays[] i1)
returns (IntDoubleArrays[] o1);
sync Test7_0(ActorWrapper a1)
returns (ActorWrapper o1);
sync Test7(Actors i1,
Actors i2,
Actors i3)
returns (Actors o1,
Actors o2,
Actors o3);
sync Test8(Actors[] i1)
returns (Actors[] o1);
sync Test9(Unions i1,
Unions i2,
Unions i3,
Unions i4)
returns (Unions o1,
Unions o2,
Unions o3,
Unions o4);
sync Test10(Unions[] i1)
returns (Unions[] o1);
sync Test11(SIntDouble i)
returns (SIntDouble o);
sync Test12(SIntDoubleArrays i)
returns (SIntDoubleArrays o);
sync Test13(SActors i)
returns (SActors o);
sync Test14(Structs i)
returns (Structs o);
sync Test15(WithStructs i1,
WithStructs i2,
WithStructs i3,
WithStructs i4,
WithStructs i5)
returns (WithStructs o1,
WithStructs o2,
WithStructs o3,
WithStructs o4,
WithStructs o5);
sync Test16(WithUnions i)
returns (WithUnions o);
sync Test17(Op[] ops);
// test that the ParamTraits<nsTArray>::Read() workaround for
// nsTArray's incorrect memmove() semantics works properly
// (nsIntRegion isn't memmove()able)
sync Test18(nsIntRegion[] ops);
sync Dummy(ShmemUnion su) returns (ShmemUnion rsu);
state CONSTRUCTING:
send PTestDataStructuresSub goto CONSTRUCTING;
send Start goto TEST1;
state TEST1: recv Test1 goto TEST2;
state TEST2: recv Test2 goto TEST3;
state TEST3: recv Test3 goto TEST4;
state TEST4: recv Test4 goto TEST5;
state TEST5: recv Test5 goto TEST6;
state TEST6: recv Test6 goto TEST7;
state TEST7: recv Test7 goto TEST8;
state TEST8: recv Test8 goto TEST9;
state TEST9: recv Test9 goto TEST10;
state TEST10: recv Test10 goto TEST11;
state TEST11: recv Test11 goto TEST12;
state TEST12: recv Test12 goto TEST13;
state TEST13: recv Test13 goto TEST14;
state TEST14: recv Test14 goto TEST15;
state TEST15: recv Test15 goto TEST16;
state TEST16: recv Test16 goto TEST17;
state TEST17: recv Test17 goto TEST18;
state TEST18: recv Test18 goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,107 @@
include protocol PTestDataStructuresSub;
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using nsIntRegion from "nsRegion.h";
namespace mozilla {
namespace _foo {
union IntDouble {
int;
double;
};
struct SIntDouble {
int i;
double d;
};
union IntDoubleArrays {
int;
int[];
double[];
};
struct SIntDoubleArrays {
int i;
int[] ai;
double[] ad;
};
struct ActorWrapper {
PTestDataStructuresSub actor;
};
union Actors {
int;
int[];
PTestDataStructuresSub[];
};
struct SActors {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
};
union Unions {
int;
int[];
PTestDataStructuresSub[];
Actors[];
};
struct Structs {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
SActors[] aa;
};
union WithStructs {
int;
int[];
PTestDataStructuresSub[];
SActors[];
Structs[];
};
struct WithUnions {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
Actors[] aa;
Unions[] au;
};
struct CommonAttrs { bool dummy; };
struct FooAttrs { int dummy; };
struct BarAttrs { float dummy; };
union SpecificAttrs {
FooAttrs;
BarAttrs;
};
struct Attrs {
CommonAttrs common;
SpecificAttrs specific;
};
struct SetAttrs {
PTestDataStructuresSub x;
Attrs attrs;
};
union Op { null_t; SetAttrs; };
struct ShmemStruct {
int i;
Shmem mem;
};
union ShmemUnion {
int;
Shmem;
};
struct Empty { };
} // namespace _foo
} // namespace mozilla

View file

@ -0,0 +1,15 @@
include PTestDataStructuresCommon;
include protocol PTestDataStructures;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestDataStructuresSub {
manager PTestDataStructures;
parent:
sync __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestDemon
{
child:
async Start();
both:
async AsyncMessage(int n);
nested(inside_sync) sync HiPrioSyncMessage();
parent:
sync SyncMessage(int n);
nested(inside_cpow) async UrgentAsyncMessage(int n);
nested(inside_cpow) sync UrgentSyncMessage(int n);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,31 @@
include protocol PTestDescSub;
include protocol PTestDescSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDesc {
manages PTestDescSub;
child:
intr PTestDescSub(nullable PTestDescSubsub dummy);
async Test(PTestDescSubsub a);
async __delete__();
parent:
async Ok(PTestDescSubsub a);
state CONSTRUCT:
call PTestDescSub goto TEST;
state TEST:
send Test goto ACK;
state ACK:
recv Ok goto DEAD;
state DEAD:
send __delete__;
};
}
}

View file

@ -0,0 +1,18 @@
include protocol PTestDesc;
include protocol PTestDescSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDescSub {
manager PTestDesc;
manages PTestDescSubsub;
child:
async __delete__();
intr PTestDescSubsub();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestDescSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDescSubsub {
manager PTestDescSub;
child:
intr __delete__();
};
}
}

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMainSub;
include protocol PTestEndpointBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointBridgeMain {
child spawns PTestEndpointBridgeSub;
child:
async Start();
parent:
async Bridged(Endpoint<PTestEndpointBridgeMainSubParent> endpoint);
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMain;
include protocol PTestEndpointBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
intr protocol PTestEndpointBridgeMainSub {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMainSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointBridgeSub {
child:
async Ping();
async Bridged(Endpoint<PTestEndpointBridgeMainSubChild> endpoint);
parent:
async BridgeEm();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointOpens {
child:
async Start();
parent:
async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint);
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
namespace mozilla {
namespace _ipdltest2 {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
intr protocol PTestEndpointOpensOpened {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest2

View file

@ -0,0 +1,19 @@
include protocol PTestFailedCtorSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtor {
manages PTestFailedCtorSub;
child:
intr PTestFailedCtorSub();
async __delete__();
state CONSTRUCT:
call PTestFailedCtorSub goto DEAD;
state DEAD:
send __delete__;
};
}
}

View file

@ -0,0 +1,18 @@
include protocol PTestFailedCtor;
include protocol PTestFailedCtorSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtorSub {
manager PTestFailedCtor;
manages PTestFailedCtorSubsub;
parent:
async PTestFailedCtorSubsub();
sync Sync();
async __delete__();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestFailedCtorSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtorSubsub {
manager PTestFailedCtorSub;
parent:
async __delete__();
};
}
}

View file

@ -0,0 +1,14 @@
include protocol PTestJSON;
namespace mozilla {
namespace _ipdltest {
protocol PTestHandle {
manager PTestJSON;
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,40 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestHangs {
both:
intr StackFrame();
parent:
async Nonce();
child:
async Start();
intr Hang();
async __delete__();
state START:
send Start goto RACE;
state RACE:
recv Nonce goto RACE1;
call StackFrame goto RACE2;
state RACE1:
call StackFrame goto FRAME2;
state RACE2:
recv Nonce goto FRAME2;
// So as to test unwinding the RPC stack
state FRAME2: answer StackFrame goto FRAME3;
state FRAME3: call StackFrame goto FRAME4;
state FRAME4: answer StackFrame goto HANG;
state HANG: call Hang goto DEATH;
state DEATH:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,18 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestHighestPrio
{
parent:
nested(inside_cpow) async Msg1();
nested(inside_sync) sync Msg2();
nested(inside_cpow) async Msg3();
nested(inside_cpow) sync Msg4();
child:
async Start();
nested(inside_sync) sync StartInner();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestIndirectProtocolParamSecond;
namespace mozilla {
namespace _ipdltest {
struct IndirectParamStruct {
PTestIndirectProtocolParamSecond actor;
};
union IndirectParamUnion {
IndirectParamStruct;
};
}
}

View file

@ -0,0 +1,19 @@
include protocol PTestIndirectProtocolParamManage;
// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is
// already included in PTestIndirectProtocolParam.ipdlh
include protocol PTestIndirectProtocolParamSecond;
include PTestIndirectProtocolParam;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamFirst {
manager PTestIndirectProtocolParamManage;
parent:
sync Test(IndirectParamUnion actor);
both:
async __delete__();
};
}
}

View file

@ -0,0 +1,17 @@
include protocol PTestIndirectProtocolParamFirst;
include protocol PTestIndirectProtocolParamSecond;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamManage {
manages PTestIndirectProtocolParamFirst;
manages PTestIndirectProtocolParamSecond;
both:
async PTestIndirectProtocolParamFirst();
async PTestIndirectProtocolParamSecond();
async __delete__();
};
}
}

View file

@ -0,0 +1,13 @@
include protocol PTestIndirectProtocolParamManage;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamSecond {
manager PTestIndirectProtocolParamManage;
both:
async __delete__();
};
}
}

View file

@ -0,0 +1,11 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptErrorCleanup {
child:
intr Error();
intr __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,82 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptRaces {
both:
intr Race() returns (bool hasReply);
intr StackFrame() returns ();
intr StackFrame3() returns ();
parent:
sync StartRace();
intr Parent();
sync GetAnsweredParent() returns (bool answeredParent);
child:
async Start();
async Wakeup();
async Wakeup3();
intr Child();
async __delete__();
state START:
send Start goto TEST1;
// First test: race while no other messages are on the Interrupt stack
state TEST1:
recv StartRace goto RACE1;
state RACE1:
call Race goto DUMMY1_1;
answer Race goto DUMMY1_2;
state DUMMY1_1:
answer Race goto TEST2;
state DUMMY1_2:
call Race goto TEST2;
// Second test: race while other messages are on the Interrupt stack
state TEST2:
call StackFrame goto MORESTACK;
state MORESTACK:
answer StackFrame goto STARTRACE;
state STARTRACE:
send Wakeup goto RACE2;
state RACE2:
call Race goto DUMMY2_1;
answer Race goto DUMMY2_2;
state DUMMY2_1:
answer Race goto TEST3;
state DUMMY2_2:
call Race goto TEST3;
// Third test: resolve race using custom policy
state TEST3:
call StackFrame3 goto MORESTACK3;
state MORESTACK3:
answer StackFrame3 goto STARTRACE3;
state STARTRACE3:
send Wakeup3 goto RACE3;
state RACE3:
call Child goto DUMMY3_1;
answer Parent goto DUMMY3_2;
state DUMMY3_1:
// the parent receives this from the child in this state
recv GetAnsweredParent goto CHECK;
// this transition is never taken (if the custom race resolution
// works correctly)
answer Parent goto CHECK;
state DUMMY3_2:
call Child goto CHECK;
state CHECK:
// the child sends this from this state
recv GetAnsweredParent goto DYING;
// because of deferred processing, the parent receives the child's
// message here
answer Parent goto DYING;
state DYING:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptShutdownRace {
parent:
sync StartDeath();
async Orphan();
child:
async Start();
intr Exit();
async __delete__();
state START:
send Start goto START_DEATH;
state START_DEATH:
recv StartDeath goto EXITING;
state EXITING:
recv Orphan goto QUITTING1;
call Exit goto QUITTING2;
state QUITTING1:
call Exit goto DEAD;
state QUITTING2:
recv Orphan goto DEAD;
state DEAD:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,54 @@
include protocol PTestHandle;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace _ipdltest {
union Key {
// int;
// double;
nsString;
};
struct KeyValue {
Key key;
JSONVariant value;
};
union JSONVariant {
void_t;
null_t;
bool;
int;
double;
nsString;
PTestHandle;
KeyValue[];
JSONVariant[];
};
sync protocol PTestJSON {
manages PTestHandle;
child:
async Start();
parent:
async PTestHandle();
sync Test(JSONVariant i)
returns (JSONVariant o);
async __delete__();
state START:
send Start goto TEST;
state TEST:
recv PTestHandle goto TEST;
recv Test goto TEST;
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,75 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestLatency {
child:
async __delete__();
async Ping();
async Ping5();
intr Rpc();
async Spam();
intr Synchro();
async CompressedSpam(uint32_t seqno) compress;
intr Synchro2() returns (uint32_t lastSeqno,
uint32_t numMessagesDispatched);
parent:
async Pong();
async Pong5();
state START:
// if the timing resolution is too low, abort the test
send __delete__;
// otherwise, kick off the ping/pong trials
send Ping goto PONG;
// Trial 1: single ping/pong latency
state PING:
send Ping goto PONG;
send Ping5 goto PING4;
state PONG:
recv Pong goto PING;
// Trial 2: "overlapped" ping/pong latency
state PING5:
send Ping5 goto PING4;
call Rpc goto RPC;
state PING4: send Ping5 goto PING3;
state PING3: send Ping5 goto PING2;
state PING2: send Ping5 goto PING1;
state PING1: send Ping5 goto PONG1;
state PONG1: recv Pong5 goto PONG2;
state PONG2: recv Pong5 goto PONG3;
state PONG3: recv Pong5 goto PONG4;
state PONG4: recv Pong5 goto PONG5;
state PONG5: recv Pong5 goto PING5;
// Trial 3: lotsa RPC
state RPC:
call Rpc goto RPC;
send Spam goto SPAM;
// Trial 4: lots of sequential asyn messages, which tests pipelining
state SPAM:
send Spam goto SPAM;
call Synchro goto COMPRESSED_SPAM;
// Trial 5: lots of async spam, but compressed to cut down on
// dispatch overhead
state COMPRESSED_SPAM: // compressed spam, mmm
send CompressedSpam goto COMPRESSED_SPAM;
call Synchro2 goto DONE;
state DONE:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,19 @@
include protocol PTestManyChildAllocsSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestManyChildAllocs {
manages PTestManyChildAllocsSub;
child:
async Go(); // start allocating
parent:
async Done();
async PTestManyChildAllocsSub();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,19 @@
include protocol PTestManyChildAllocs;
namespace mozilla {
namespace _ipdltest {
protocol PTestManyChildAllocsSub {
manager PTestManyChildAllocs;
child:
async __delete__();
parent:
async Hello();
// empty
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
include protocol PTestMultiMgrsLeft;
include protocol PTestMultiMgrsRight;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrs {
manages PTestMultiMgrsLeft;
manages PTestMultiMgrsRight;
parent:
async OK();
child:
async PTestMultiMgrsLeft();
async PTestMultiMgrsRight();
async Check();
async __delete__();
state START:
send PTestMultiMgrsLeft goto CONSTRUCT_RIGHT;
state CONSTRUCT_RIGHT:
send PTestMultiMgrsRight goto CHILD_CHECK;
state CHILD_CHECK:
send Check goto CHILD_ACK;
state CHILD_ACK:
recv OK goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,18 @@
include protocol PTestMultiMgrsLeft;
include protocol PTestMultiMgrsRight;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsBottom {
manager PTestMultiMgrsLeft or PTestMultiMgrsRight;
child:
async __delete__();
state DOA:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,24 @@
include protocol PTestMultiMgrs;
include protocol PTestMultiMgrsBottom;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsLeft {
manager PTestMultiMgrs;
manages PTestMultiMgrsBottom;
child:
async PTestMultiMgrsBottom();
async __delete__();
state START:
send PTestMultiMgrsBottom goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,24 @@
include protocol PTestMultiMgrs;
include protocol PTestMultiMgrsBottom;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsRight {
manager PTestMultiMgrs;
manages PTestMultiMgrsBottom;
child:
async PTestMultiMgrsBottom();
async __delete__();
state START:
send PTestMultiMgrsBottom goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestNestedLoops {
child:
async Start();
intr R();
async __delete__();
parent:
async Nonce();
state START:
send Start goto RACE;
state RACE:
recv Nonce goto RACE1;
call R goto RACE2;
state RACE1:
call R goto DEAD;
state RACE2:
recv Nonce goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
include protocol PTestOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestOpens {
// This channel is opened and parked on a non-main thread
child opens PTestOpensOpened;
child:
async Start();
parent:
async __delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest2 {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
intr protocol PTestOpensOpened {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest2

View file

@ -0,0 +1,14 @@
namespace mozilla {
namespace _ipdltest {
sync protocol PTestPriority {
parent:
prio(high) async Msg1();
prio(high) sync Msg2();
child:
prio(high) async Msg3();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_sync) sync protocol PTestRPC
{
parent:
nested(inside_sync) sync Test1_Start() returns (uint32_t result);
nested(inside_sync) sync Test1_InnerEvent() returns (uint32_t result);
async Test2_Start();
nested(inside_sync) sync Test2_OutOfOrder();
child:
async Start();
nested(inside_sync) sync Test1_InnerQuery() returns (uint32_t result);
nested(inside_sync) sync Test1_NoReenter() returns (uint32_t result);
nested(inside_sync) sync Test2_FirstUrgent();
nested(inside_sync) sync Test2_SecondUrgent();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,20 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRaceDeadlock {
both:
async StartRace();
parent:
intr Lose();
child:
intr Win();
intr Rpc();
async __delete__();
/* Tests that race resolution does not cause deadlocks */
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,45 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRaceDeferral {
parent:
intr Lose();
child:
async StartRace();
intr Win();
intr Rpc();
async __delete__();
// Test that messages deferred due to race resolution are
// re-considered when the winner makes later RPCs
// IPDL's type system can't express this protocol because the race
// resolution causes state to diverge for multiple steps, so we'll
// leave it "stateless"
/*
state START:
send StartRace goto DEFER;
state DEFER:
call Win goto PARENT;
answer Lose goto CHILD;
state PARENT:
// 'Lose' is received here but deferred
call Rpc goto PARENT_LOSE;
state PARENT_LOSE:
// Calling 'Rpc' undefers 'Lose', and it wins the "race" with 'Rpc'
answer Lose goto DONE;
state CHILD:
call Win goto CHILD_RPC;
state CHILD_RPC:
call Rpc goto DONE;
state DONE:
send __delete__;
*/
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,41 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyInterruptReplies {
child:
intr R_() returns (int replyNum);
async _A();
async ChildTest();
async __delete__();
parent:
intr _R() returns (int replyNum);
async A_();
state PARENT_START:
call R_ goto PARENT_S1;
state PARENT_S1:
recv A_ goto PARENT_S2;
state PARENT_S2:
call R_ goto CHILD_TEST;
state CHILD_TEST:
send ChildTest goto CHILD_START;
state CHILD_START:
answer _R goto CHILD_S1;
state CHILD_S1:
send _A goto CHILD_S2;
state CHILD_S2:
answer _R goto DYING;
state DYING:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyReentry {
parent:
intr E();
async __delete__();
child:
async Start();
async N();
intr H();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyUndefer {
child:
async Start();
async AwakenSpam();
async AwakenRaceWinTwice();
intr Race();
async __delete__();
parent:
intr Spam();
intr RaceWinTwice();
async Done();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestSanity {
child:
async Ping(int zero, float zeroPtFive, int8_t dummy);
async __delete__();
parent:
async Pong(int one, float zeroPtTwoFive, uint8_t dummy);
state PING:
send Ping goto PONG;
state PONG:
recv Pong goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
include protocol PTestSelfManageRoot;
namespace mozilla {
namespace _ipdltest {
protocol PTestSelfManage {
manager PTestSelfManageRoot or PTestSelfManage;
manages PTestSelfManage;
child:
async PTestSelfManage();
async __delete__();
state LIVE:
send PTestSelfManage goto LIVE;
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,23 @@
include protocol PTestSelfManage;
namespace mozilla {
namespace _ipdltest {
protocol PTestSelfManageRoot {
manages PTestSelfManage;
child:
async PTestSelfManage();
async __delete__();
state LIVE:
send PTestSelfManage goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestShmem {
child:
async Give(Shmem mem, Shmem unsafe, size_t expectedSize);
parent:
async Take(Shmem mem, Shmem unsafe, size_t expectedSize);
async __delete__();
state GIVING:
send Give goto TAKING;
state TAKING:
recv Take goto TAKING;
recv __delete__;
};
}
}

View file

@ -0,0 +1,37 @@
include protocol PTestShutdownSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestShutdown {
manages PTestShutdownSub;
child:
async Start();
parent:
// NB: we test deletion and crashing only, not shutdown, because
// crashing is the same code path as shutdown, and other IPDL unit
// tests check shutdown semantics
async PTestShutdownSub(bool expectCrash);
// Used to synchronize between parent and child, to avoid races
// around flushing socket write queues
sync Sync();
async __delete__();
state START:
send Start goto TESTING;
state TESTING:
recv PTestShutdownSub goto TESTING;
recv Sync goto DYING;
state DYING:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,30 @@
include protocol PTestShutdown;
include protocol PTestShutdownSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestShutdownSub {
manager PTestShutdown;
manages PTestShutdownSubsub;
both:
intr StackFrame();
parent:
async PTestShutdownSubsub(bool expectParentDeleted);
sync __delete__();
state CREATING:
recv PTestShutdownSubsub goto CREATING;
answer StackFrame goto DUMMYFRAME;
state DUMMYFRAME:
call StackFrame goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,17 @@
include protocol PTestShutdownSub;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestShutdownSubsub {
manager PTestShutdownSub;
parent:
sync __delete__();
state LIVE:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,56 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestStackHooks {
child:
async Start();
// These tests are more fruitful running child->parent, because
// children can send |sync| messages
parent:
async Async();
sync Sync();
intr Rpc();
both:
intr StackFrame();
parent:
async __delete__();
state START:
send Start goto TEST1;
state TEST1:
recv Async goto TEST2;
state TEST2:
recv Sync goto TEST3;
state TEST3:
answer Rpc goto TEST4;
state TEST4:
answer StackFrame goto TEST4_2;
state TEST4_2:
call StackFrame goto TEST4_3;
state TEST4_3:
recv Async goto TEST5;
state TEST5:
answer StackFrame goto TEST5_2;
state TEST5_2:
call StackFrame goto TEST5_3;
state TEST5_3:
recv Sync goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
sync protocol PTestSyncError {
child:
async Start();
parent:
sync Error();
async __delete__();
state START:
send Start goto SYNC_ERROR;
state SYNC_ERROR:
recv Error goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,15 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestSyncHang {
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,41 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestSyncWakeup {
both:
intr StackFrame();
child:
async Start();
async Note1();
async Note2();
parent:
sync Sync1();
sync Sync2();
async __delete__();
state START:
send Start goto TEST1;
state TEST1:
recv Sync1 goto TEST1_P2;
state TEST1_P2:
send Note1 goto TEST2;
state TEST2:
answer StackFrame goto TEST2_P2;
state TEST2_P2:
call StackFrame goto TEST2_P3;
state TEST2_P3:
recv Sync2 goto TEST2_P4;
state TEST2_P4:
send Note2 goto DONE;
state DONE:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,19 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestUrgency
{
parent:
nested(inside_sync) sync Test1() returns (uint32_t result);
async Test2();
sync Test3() returns (uint32_t result);
sync FinalTest_Begin();
child:
async Start();
nested(inside_sync) sync Reply1() returns (uint32_t result);
nested(inside_sync) sync Reply2() returns (uint32_t result);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestUrgentHangs
{
parent:
nested(inside_sync) sync Test1_2();
nested(inside_sync) sync TestInner();
nested(inside_cpow) sync TestInnerUrgent();
child:
nested(inside_sync) sync Test1_1();
nested(inside_sync) sync Test1_3();
nested(inside_sync) sync Test2();
nested(inside_sync) sync Test3();
async Test4();
nested(inside_sync) sync Test4_1();
async Test5();
nested(inside_sync) sync Test5_1();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,61 @@
To add a new IPDL C++ unit test, you need to create (at least) the
following files (for a test "TestFoo"):
- PTestFoo.ipdl, specifying the top-level protocol used for the test
- TestFoo.h, declaring the top-level parent/child actors used for
the test
- TestFoo.cpp, defining the top-level actors
- (make sure all are in the namespace mozilla::_ipdltest)
Next
- add PTestFoo.ipdl to ipdl.mk
- append TestFoo to the variable IPDLTESTS in Makefile.in
You must define three methods in your |TestFooParent| class:
- static methods |bool RunTestInProcesses()| and
|bool RunTestInThreads()|. These methods control whether
to execute the test using actors in separate processes and
threads respectively. Generally, both should return true.
- an instance method |void Main()|. The test harness wil first
initialize the processes or threads, create and open both actors,
and then kick off the test using |Main()|. Make sure you define
it.
If your test passes its criteria, please call
|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully".
If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit
ungracefully", preferably by abort()ing.
If all goes well, running
make -C $OBJDIR/ipc/ipdl/test/cxx
will update the file IPDLUnitTests.cpp (the test launcher), and your
new code will be built automatically.
You can launch your new test by invoking one of
make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests)
make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests)
make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both)
If you want to launch only your test, run
cd $OBJDIR/dist/bin
./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.)
./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.)
For a bare-bones example of adding a test, take a look at
PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity"
is included in ipdl.mk and Makefile.in.

View file

@ -0,0 +1,128 @@
#include "TestActorPunning.h"
#include "IPDLUnitTests.h" // fail etc.
#include "mozilla/Unused.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
void
TestActorPunningParent::Main()
{
if (!SendStart())
fail("sending Start");
}
bool
TestActorPunningParent::RecvPun(PTestActorPunningSubParent* a, const Bad& bad)
{
if (a->SendBad())
fail("bad!");
fail("shouldn't have received this message in the first place");
return true;
}
PTestActorPunningPunnedParent*
TestActorPunningParent::AllocPTestActorPunningPunnedParent()
{
return new TestActorPunningPunnedParent();
}
bool
TestActorPunningParent::DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a)
{
delete a;
return true;
}
PTestActorPunningSubParent*
TestActorPunningParent::AllocPTestActorPunningSubParent()
{
return new TestActorPunningSubParent();
}
bool
TestActorPunningParent::DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a)
{
delete a;
return true;
}
//-----------------------------------------------------------------------------
// child
PTestActorPunningPunnedChild*
TestActorPunningChild::AllocPTestActorPunningPunnedChild()
{
return new TestActorPunningPunnedChild();
}
bool
TestActorPunningChild::DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild*)
{
fail("should have died by now");
return true;
}
PTestActorPunningSubChild*
TestActorPunningChild::AllocPTestActorPunningSubChild()
{
return new TestActorPunningSubChild();
}
bool
TestActorPunningChild::DeallocPTestActorPunningSubChild(PTestActorPunningSubChild*)
{
fail("should have died by now");
return true;
}
bool
TestActorPunningChild::RecvStart()
{
SendPTestActorPunningSubConstructor();
SendPTestActorPunningPunnedConstructor();
PTestActorPunningSubChild* a = SendPTestActorPunningSubConstructor();
// We can't assert whether this succeeds or fails, due to race
// conditions.
SendPun(a, Bad());
return true;
}
bool
TestActorPunningSubChild::RecvBad()
{
fail("things are going really badly right now");
return true;
}
} // namespace _ipdltest
} // namespace mozilla
namespace IPC {
using namespace mozilla::_ipdltest;
using namespace mozilla::ipc;
/*static*/ void
ParamTraits<Bad>::Write(Message* aMsg, const paramType& aParam)
{
// Skip past the sentinel for the actor as well as the actor.
int32_t* ptr = aMsg->GetInt32PtrForTest(2 * sizeof(int32_t));
ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr);
if (ah->mId != -3)
fail("guessed wrong offset (value is %d, should be -3)", ah->mId);
ah->mId = -2;
}
/*static*/ bool
ParamTraits<Bad>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return true;
}
} // namespace IPC

View file

@ -0,0 +1,110 @@
#ifndef mozilla__ipdltest_TestActorPunning_h
#define mozilla__ipdltest_TestActorPunning_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestActorPunningParent.h"
#include "mozilla/_ipdltest/PTestActorPunningPunnedParent.h"
#include "mozilla/_ipdltest/PTestActorPunningSubParent.h"
#include "mozilla/_ipdltest/PTestActorPunningChild.h"
#include "mozilla/_ipdltest/PTestActorPunningPunnedChild.h"
#include "mozilla/_ipdltest/PTestActorPunningSubChild.h"
namespace mozilla {
namespace _ipdltest {
class TestActorPunningParent :
public PTestActorPunningParent
{
public:
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
PTestActorPunningPunnedParent* AllocPTestActorPunningPunnedParent() override;
bool DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a) override;
PTestActorPunningSubParent* AllocPTestActorPunningSubParent() override;
bool DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a) override;
virtual bool RecvPun(PTestActorPunningSubParent* a, const Bad& bad) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown == why)
fail("should have died from error!");
passed("ok");
QuitParent();
}
};
class TestActorPunningPunnedParent :
public PTestActorPunningPunnedParent
{
public:
TestActorPunningPunnedParent() {}
virtual ~TestActorPunningPunnedParent() {}
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
class TestActorPunningSubParent :
public PTestActorPunningSubParent
{
public:
TestActorPunningSubParent() {}
virtual ~TestActorPunningSubParent() {}
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
class TestActorPunningChild :
public PTestActorPunningChild
{
public:
TestActorPunningChild() {}
virtual ~TestActorPunningChild() {}
protected:
PTestActorPunningPunnedChild* AllocPTestActorPunningPunnedChild() override;
bool DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild* a) override;
PTestActorPunningSubChild* AllocPTestActorPunningSubChild() override;
bool DeallocPTestActorPunningSubChild(PTestActorPunningSubChild* a) override;
virtual bool RecvStart() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
fail("should have been killed off!");
}
};
class TestActorPunningPunnedChild :
public PTestActorPunningPunnedChild
{
public:
TestActorPunningPunnedChild() {}
virtual ~TestActorPunningPunnedChild() {}
};
class TestActorPunningSubChild :
public PTestActorPunningSubChild
{
public:
TestActorPunningSubChild() {}
virtual ~TestActorPunningSubChild() {}
virtual bool RecvBad() override;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestActorPunning_h

View file

@ -0,0 +1,51 @@
#include "TestBadActor.h"
#include "IPDLUnitTests.h"
#include "mozilla/Unused.h"
namespace mozilla {
namespace _ipdltest {
void
TestBadActorParent::Main()
{
// This test is designed to test a race condition where the child sends us
// a message on an actor that we've already destroyed. The child process
// should die, and the parent process should not abort.
PTestBadActorSubParent* child = SendPTestBadActorSubConstructor();
if (!child)
fail("Sending constructor");
Unused << child->Call__delete__(child);
}
PTestBadActorSubParent*
TestBadActorParent::AllocPTestBadActorSubParent()
{
return new TestBadActorSubParent();
}
bool
TestBadActorSubParent::RecvPing()
{
fail("Shouldn't have received ping.");
return false;
}
PTestBadActorSubChild*
TestBadActorChild::AllocPTestBadActorSubChild()
{
return new TestBadActorSubChild();
}
bool
TestBadActorChild::RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor)
{
if (!actor->SendPing()) {
fail("Couldn't send ping to an actor which supposedly isn't dead yet.");
}
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,91 @@
#ifndef mozilla__ipdltest_TestBadActor_h
#define mozilla__ipdltest_TestBadActor_h
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBadActorParent.h"
#include "mozilla/_ipdltest/PTestBadActorChild.h"
#include "mozilla/_ipdltest/PTestBadActorSubParent.h"
#include "mozilla/_ipdltest/PTestBadActorSubChild.h"
namespace mozilla {
namespace _ipdltest {
class TestBadActorParent
: public PTestBadActorParent
{
public:
TestBadActorParent() { }
virtual ~TestBadActorParent() { }
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction");
passed("ok");
QuitParent();
}
virtual PTestBadActorSubParent*
AllocPTestBadActorSubParent();
virtual bool
DeallocPTestBadActorSubParent(PTestBadActorSubParent* actor) {
delete actor;
return true;
}
};
class TestBadActorSubParent
: public PTestBadActorSubParent
{
public:
TestBadActorSubParent() { }
virtual ~TestBadActorSubParent() { }
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
virtual bool RecvPing();
};
class TestBadActorChild
: public PTestBadActorChild
{
public:
TestBadActorChild() { }
virtual ~TestBadActorChild() { }
protected:
virtual PTestBadActorSubChild*
AllocPTestBadActorSubChild();
virtual bool
DeallocPTestBadActorSubChild(PTestBadActorSubChild* actor)
{
delete actor;
return true;
}
virtual bool
RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor);
};
class TestBadActorSubChild
: public PTestBadActorSubChild
{
public:
TestBadActorSubChild() { }
virtual ~TestBadActorSubChild() { }
};
} // namespace _ipdltest
} // namespace mozilla
#endif // mozilla__ipdltest_TestBadActor_h

View file

@ -0,0 +1,227 @@
#include "TestBridgeMain.h"
#include "base/task.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
#include "nsAutoPtr.h"
using namespace std;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// main process
void
TestBridgeMainParent::Main()
{
if (!SendStart())
fail("sending Start");
}
PTestBridgeMainSubParent*
TestBridgeMainParent::AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ParentSide)) {
return nullptr;
}
return a.forget();
}
void
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
bool
TestBridgeMainSubParent::RecvHello()
{
return SendHi();
}
bool
TestBridgeMainSubParent::RecvHelloSync()
{
return true;
}
bool
TestBridgeMainSubParent::AnswerHelloRpc()
{
return CallHiRpc();
}
void
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubParent>(this)));
}
//-----------------------------------------------------------------------------
// sub process --- child of main
TestBridgeMainChild* gBridgeMainChild;
TestBridgeMainChild::TestBridgeMainChild()
: mSubprocess(nullptr)
{
gBridgeMainChild = this;
}
bool
TestBridgeMainChild::RecvStart()
{
vector<string> subsubArgs;
subsubArgs.push_back("TestBridgeSub");
mSubprocess = new IPDLUnitTestSubprocess();
if (!mSubprocess->SyncLaunch(subsubArgs))
fail("problem launching subprocess");
IPC::Channel* transport = mSubprocess->GetChannel();
if (!transport)
fail("no transport");
TestBridgeSubParent* bsp = new TestBridgeSubParent();
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
bsp->Main();
return true;
}
void
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// NB: this is kosher because QuitChild() joins with the IO thread
XRE_GetIOMessageLoop()->PostTask(
do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
QuitChild();
}
void
TestBridgeSubParent::Main()
{
if (!SendPing())
fail("sending Ping");
}
bool
TestBridgeSubParent::RecvBridgeEm()
{
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
fail("bridging Main and Sub");
return true;
}
void
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeMainChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeSubParent>(this)));
}
//-----------------------------------------------------------------------------
// subsub process --- child of sub
static TestBridgeSubChild* gBridgeSubChild;
TestBridgeSubChild::TestBridgeSubChild()
{
gBridgeSubChild = this;
}
bool
TestBridgeSubChild::RecvPing()
{
if (!SendBridgeEm())
fail("sending BridgeEm");
return true;
}
PTestBridgeMainSubChild*
TestBridgeSubChild::AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ChildSide)) {
return nullptr;
}
if (!a->SendHello())
fail("sending Hello");
return a.forget();
}
void
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
bool
TestBridgeMainSubChild::RecvHi()
{
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestBridgeMainSubChild::Close));
return true;
}
bool
TestBridgeMainSubChild::AnswerHiRpc()
{
mGotHi = true; // d00d
return true;
}
void
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeSubChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubChild>(this)));
}
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,149 @@
#ifndef mozilla__ipdltest_TestBridgeMain_h
#define mozilla__ipdltest_TestBridgeMain_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBridgeMainParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainChild.h"
#include "mozilla/_ipdltest/PTestBridgeSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeSubChild.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// "Main" process
//
class TestBridgeMainParent :
public PTestBridgeMainParent
{
public:
TestBridgeMainParent() {}
virtual ~TestBridgeMainParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual PTestBridgeMainSubParent*
AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubParent :
public PTestBridgeMainSubParent
{
public:
explicit TestBridgeMainSubParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestBridgeMainSubParent() {}
protected:
virtual bool RecvHello() override;
virtual bool RecvHelloSync() override;
virtual bool AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
Transport* mTransport;
};
//-----------------------------------------------------------------------------
// "Sub" process --- child of "main"
//
class TestBridgeSubParent;
class TestBridgeMainChild :
public PTestBridgeMainChild
{
public:
TestBridgeMainChild();
virtual ~TestBridgeMainChild() {}
protected:
virtual bool RecvStart() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override
{
// This shouldn't be called. It's just a byproduct of testing that
// the right code is generated for a bridged protocol that's also
// opened, but we only test bridging here.
MOZ_CRASH();
}
virtual void ActorDestroy(ActorDestroyReason why) override;
IPDLUnitTestSubprocess* mSubprocess;
};
class TestBridgeSubParent :
public PTestBridgeSubParent
{
public:
TestBridgeSubParent() {}
virtual ~TestBridgeSubParent() {}
void Main();
protected:
virtual bool RecvBridgeEm() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// "Subsub" process --- child of "sub"
//
class TestBridgeSubChild :
public PTestBridgeSubChild
{
public:
TestBridgeSubChild();
virtual ~TestBridgeSubChild() {}
protected:
virtual bool RecvPing() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubChild :
public PTestBridgeMainSubChild
{
public:
explicit TestBridgeMainSubChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestBridgeMainSubChild() {}
protected:
virtual bool RecvHi() override;
virtual bool AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestBridgeMain_h

View file

@ -0,0 +1,168 @@
#include "TestCancel.h"
#include "IPDLUnitTests.h" // fail etc.
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
TestCancelParent::TestCancelParent()
{
MOZ_COUNT_CTOR(TestCancelParent);
}
TestCancelParent::~TestCancelParent()
{
MOZ_COUNT_DTOR(TestCancelParent);
}
void
TestCancelParent::Main()
{
if (SendTest1_1())
fail("sending Test1_1");
uint32_t value = 0;
if (!SendCheckChild(&value))
fail("Test1 CheckChild");
if (value != 12)
fail("Test1 CheckChild reply");
}
bool
TestCancelParent::RecvDone1()
{
if (!SendStart2())
fail("sending Start2");
return true;
}
bool
TestCancelParent::RecvTest2_1()
{
if (SendTest2_2())
fail("sending Test2_2");
return true;
}
bool
TestCancelParent::RecvStart3()
{
if (SendTest3_1())
fail("sending Test3_1");
uint32_t value = 0;
if (!SendCheckChild(&value))
fail("Test1 CheckChild");
if (value != 12)
fail("Test1 CheckChild reply");
return true;
}
bool
TestCancelParent::RecvTest3_2()
{
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
bool
TestCancelParent::RecvDone()
{
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestCancelParent::Close));
return true;
}
bool
TestCancelParent::RecvCheckParent(uint32_t *reply)
{
*reply = 12;
return true;
}
//-----------------------------------------------------------------------------
// child
bool
TestCancelChild::RecvTest1_1()
{
GetIPCChannel()->CancelCurrentTransaction();
uint32_t value = 0;
if (!SendCheckParent(&value))
fail("Test1 CheckParent");
if (value != 12)
fail("Test1 CheckParent reply");
if (!SendDone1())
fail("Test1 CheckParent");
return true;
}
bool
TestCancelChild::RecvStart2()
{
if (!SendTest2_1())
fail("sending Test2_1");
if (!SendStart3())
fail("sending Start3");
return true;
}
bool
TestCancelChild::RecvTest2_2()
{
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
bool
TestCancelChild::RecvTest3_1()
{
if (SendTest3_2())
fail("sending Test3_2");
uint32_t value = 0;
if (!SendCheckParent(&value))
fail("Test1 CheckParent");
if (value != 12)
fail("Test1 CheckParent reply");
if (!SendDone())
fail("sending Done");
return true;
}
bool
TestCancelChild::RecvCheckChild(uint32_t *reply)
{
*reply = 12;
return true;
}
TestCancelChild::TestCancelChild()
{
MOZ_COUNT_CTOR(TestCancelChild);
}
TestCancelChild::~TestCancelChild()
{
MOZ_COUNT_DTOR(TestCancelChild);
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,66 @@
#ifndef mozilla__ipdltest_TestCancel_h
#define mozilla__ipdltest_TestCancel_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestCancelParent.h"
#include "mozilla/_ipdltest/PTestCancelChild.h"
namespace mozilla {
namespace _ipdltest {
class TestCancelParent :
public PTestCancelParent
{
public:
TestCancelParent();
virtual ~TestCancelParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
virtual bool RecvDone1() override;
virtual bool RecvTest2_1() override;
virtual bool RecvStart3() override;
virtual bool RecvTest3_2() override;
virtual bool RecvDone() override;
virtual bool RecvCheckParent(uint32_t *reply) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
passed("ok");
QuitParent();
}
};
class TestCancelChild :
public PTestCancelChild
{
public:
TestCancelChild();
virtual ~TestCancelChild();
virtual bool RecvTest1_1() override;
virtual bool RecvStart2() override;
virtual bool RecvTest2_2() override;
virtual bool RecvTest3_1() override;
virtual bool RecvCheckChild(uint32_t *reply) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
QuitChild();
}
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestCancel_h

View file

@ -0,0 +1,116 @@
#include "TestCrashCleanup.h"
#include "base/task.h"
#include "mozilla/CondVar.h"
#include "mozilla/Mutex.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
using mozilla::CondVar;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
namespace {
// NB: this test does its own shutdown, rather than going through
// QuitParent(), because it's testing degenerate edge cases
void DeleteSubprocess(Mutex* mutex, CondVar* cvar)
{
MutexAutoLock lock(*mutex);
delete gSubprocess;
gSubprocess = nullptr;
cvar->Notify();
}
void DeleteTheWorld()
{
delete static_cast<TestCrashCleanupParent*>(gParentActor);
gParentActor = nullptr;
// needs to be synchronous to avoid affecting event ordering on
// the main thread
Mutex mutex("TestCrashCleanup.DeleteTheWorld.mutex");
CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar");
MutexAutoLock lock(mutex);
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(DeleteSubprocess, &mutex, &cvar));
cvar.Wait();
}
void Done()
{
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
appShell->Exit();
passed(__FILE__);
}
} // namespace <anon>
TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false)
{
MOZ_COUNT_CTOR(TestCrashCleanupParent);
}
TestCrashCleanupParent::~TestCrashCleanupParent()
{
MOZ_COUNT_DTOR(TestCrashCleanupParent);
if (!mCleanedUp)
fail("should have been ActorDestroy()d!");
}
void
TestCrashCleanupParent::Main()
{
// NB: has to be enqueued before IO thread's error notification
MessageLoop::current()->PostTask(
NewRunnableFunction(DeleteTheWorld));
if (CallDIEDIEDIE())
fail("expected an error!");
Close();
MessageLoop::current()->PostTask(NewRunnableFunction(Done));
}
//-----------------------------------------------------------------------------
// child
TestCrashCleanupChild::TestCrashCleanupChild()
{
MOZ_COUNT_CTOR(TestCrashCleanupChild);
}
TestCrashCleanupChild::~TestCrashCleanupChild()
{
MOZ_COUNT_DTOR(TestCrashCleanupChild);
}
bool
TestCrashCleanupChild::AnswerDIEDIEDIE()
{
_exit(0);
NS_RUNTIMEABORT("unreached");
return false;
}
} // namespace _ipdltest
} // namespace mozilla

Some files were not shown because too many files have changed in this diff Show more