Bug 1118978 part 1. Introduce "Affects" and "DependsOn" state for IDL attributes and operations and desugar [Pure] and [Constant] into that state. r=peterv

This does not change the generated binding code in any way for our existing IDL files.
This commit is contained in:
Boris Zbarsky 2015-01-15 17:39:01 -05:00
parent 94ea67ad55
commit cb9b43858f
2 changed files with 89 additions and 34 deletions

View File

@ -10,7 +10,7 @@ import string
import math
import textwrap
from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLInterfaceMember, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor
AUTOGENERATED_WARNING_COMMENT = \
@ -2114,8 +2114,7 @@ def clearableCachedAttrs(descriptor):
return (m for m in descriptor.interface.members if
m.isAttr() and
# Constants should never need clearing!
not m.getExtendedAttribute("Constant") and
not m.getExtendedAttribute("SameObject") and
m.dependsOn != "Nothing" and
m.slotIndex is not None)
def MakeClearCachedValueNativeName(member):
@ -8080,16 +8079,9 @@ class CGMemberJITInfo(CGThing):
getter = ("(JSJitGetterOp)get_%s" %
IDLToCIdentifier(self.member.identifier.name))
getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
getterconst = (self.member.getExtendedAttribute("SameObject") or
self.member.getExtendedAttribute("Constant"))
getterpure = getterconst or self.member.getExtendedAttribute("Pure")
if getterconst:
aliasSet = "AliasNone"
elif getterpure:
aliasSet = "AliasDOMSets"
else:
aliasSet = "AliasEverything"
movable = getterpure and getterinfal
movable = self.mayBeMovable() and getterinfal
aliasSet = self.aliasSet()
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
@ -8134,7 +8126,6 @@ class CGMemberJITInfo(CGThing):
name = CGMethodPromiseWrapper.makeName(name)
# Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
method = ("(JSJitGetterOp)%s" % name)
methodPure = self.member.getExtendedAttribute("Pure")
# Methods are infallible if they are infallible, have no arguments
# to unwrap, and have a return type that's infallible to wrap up for
@ -8148,13 +8139,13 @@ class CGMemberJITInfo(CGThing):
movable = False
else:
sig = sigs[0]
# For pure methods, it's OK to set movable to our notion of
# infallible on the C++ side, without considering argument
# conversions, since argument conversions that can reliably
# throw would be effectful anyway and the jit doesn't move
# effectful things.
# For methods that affect nothing, it's OK to set movable to our
# notion of infallible on the C++ side, without considering
# argument conversions, since argument conversions that can
# reliably throw would be effectful anyway and the jit doesn't
# move effectful things.
hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
movable = methodPure and hasInfallibleImpl
movable = self.mayBeMovable() and hasInfallibleImpl
# XXXbz can we move the smarts about fallibility due to arg
# conversions into the JIT, using our new args stuff?
if (len(sig[1]) != 0 or
@ -8163,16 +8154,13 @@ class CGMemberJITInfo(CGThing):
methodInfal = False
else:
methodInfal = hasInfallibleImpl
# For now, only bother to output args if we're pure
if methodPure:
# For now, only bother to output args if we're side-effect-free.
if self.member.affects == "Nothing":
args = sig[1]
else:
args = None
if args is not None:
aliasSet = "AliasDOMSets"
else:
aliasSet = "AliasEverything"
aliasSet = self.aliasSet()
result = self.defineJitInfo(methodinfo, method, "Method",
methodInfal, movable, aliasSet,
False, False, "0",
@ -8180,6 +8168,37 @@ class CGMemberJITInfo(CGThing):
return result
raise TypeError("Illegal member type to CGPropertyJITInfo")
def mayBeMovable(self):
"""
Returns whether this attribute or method may be movable, just
based on Affects/DependsOn annotations.
"""
affects = self.member.affects
dependsOn = self.member.dependsOn
assert affects in IDLInterfaceMember.AffectsValues
assert dependsOn in IDLInterfaceMember.DependsOnValues
return affects == "Nothing" and dependsOn != "Everything"
def aliasSet(self):
"""Returns the alias set to store in the jitinfo. This may not be the
effective alias set the JIT uses, depending on whether we have enough
information about our args to allow the JIT to prove that effectful
argument conversions won't happen.
"""
dependsOn = self.member.dependsOn
assert dependsOn in IDLInterfaceMember.DependsOnValues
if dependsOn == "Nothing":
assert self.member.affects == "Nothing"
return "AliasNone"
if dependsOn == "DOMState":
assert self.member.affects == "Nothing"
return "AliasDOMSets"
return "AliasEverything"
@staticmethod
def getJSReturnTypeTag(t):
if t.nullable():

View File

@ -3043,6 +3043,9 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
'Stringifier'
)
AffectsValues = ("Nothing", "Everything")
DependsOnValues = ("Nothing", "DOMState", "Everything")
def __init__(self, location, identifier, tag):
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
self.tag = tag
@ -3097,6 +3100,22 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
self._scope.primaryGlobalName,
[self.location])
def _setDependsOn(self, dependsOn):
if self.dependsOn != "Everything":
raise WebIDLError("Trying to specify multiple different "
"Pure, or Constant extended attributes for "
"attribute", [self.location])
assert dependsOn in IDLInterfaceMember.DependsOnValues:
self.dependsOn = dependsOn
def _setAffects(self, affects):
if self.affects != "Everything":
raise WebIDLError("Trying to specify multiple different "
"Pure, or Constant extended attributes for "
"attribute", [self.location])
assert affects in IDLInterfaceMember.AffectsValues:
self.affects = affects
class IDLConst(IDLInterfaceMember):
def __init__(self, location, identifier, type, value):
IDLInterfaceMember.__init__(self, location, identifier,
@ -3175,6 +3194,8 @@ class IDLAttribute(IDLInterfaceMember):
self.enforceRange = False
self.clamp = False
self.slotIndex = None
self.dependsOn = "Everything"
self.affects = "Everything"
if static and identifier.name == "prototype":
raise WebIDLError("The identifier of a static attribute must not be 'prototype'",
@ -3243,10 +3264,9 @@ class IDLAttribute(IDLInterfaceMember):
if ((self.getExtendedAttribute("Cached") or
self.getExtendedAttribute("StoreInSlot")) and
not self.getExtendedAttribute("Constant") and
not self.getExtendedAttribute("Pure")):
not self.affects == "Nothing"):
raise WebIDLError("Cached attributes and attributes stored in "
"slots must be constant or pure, since the "
"slots must be Constant or Pure, since the "
"getter won't always be called.",
[self.location])
if self.getExtendedAttribute("Frozen"):
@ -3372,14 +3392,23 @@ class IDLAttribute(IDLInterfaceMember):
[attr.location, self.location])
elif identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
elif identifier == "Pure":
if not attr.noArguments():
raise WebIDLError("[Pure] must take no arguments",
[attr.location])
self._setDependsOn("DOMState")
self._setAffects("Nothing")
elif identifier == "Constant" or identifier == "SameObject":
if not attr.noArguments():
raise WebIDLError("[%s] must take no arguments" % identifier,
[attr.location])
self._setDependsOn("Nothing")
self._setAffects("Nothing")
elif (identifier == "Pref" or
identifier == "SetterThrows" or
identifier == "Pure" or
identifier == "Throws" or
identifier == "GetterThrows" or
identifier == "ChromeOnly" or
identifier == "SameObject" or
identifier == "Constant" or
identifier == "Func" or
identifier == "Frozen" or
identifier == "AvailableIn" or
@ -3663,6 +3692,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self._jsonifier = jsonifier
self._specialType = specialType
self._unforgeable = False
self.dependsOn = "Everything"
self.affects = "Everything"
if static and identifier.name == "prototype":
raise WebIDLError("The identifier of a static operation must not be 'prototype'",
@ -3974,13 +4005,18 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
[attr.location, self.location])
elif identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
elif (identifier == "Pure" or
identifier == "CrossOriginCallable" or
elif (identifier == "CrossOriginCallable" or
identifier == "WebGLHandlesContextLoss"):
# Known no-argument attributes.
if not attr.noArguments():
raise WebIDLError("[%s] must take no arguments" % identifier,
[attr.location])
elif identifier == "Pure":
if not attr.noArguments():
raise WebIDLError("[Pure] must take no arguments",
[attr.location])
self._setDependsOn("DOMState")
self._setAffects("Nothing")
elif (identifier == "Throws" or
identifier == "NewObject" or
identifier == "ChromeOnly" or