Bug 747287 - Part 1: Generate JSJitInfos and specialized accessors for Paris bindings. (r=peterv)

This commit is contained in:
Eric Faust 2012-08-07 22:26:18 -07:00
parent 028d3cc41a
commit b5fcc44a40
3 changed files with 136 additions and 33 deletions

View File

@ -458,8 +458,8 @@ XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
if (id == attributeIds[i]) { if (id == attributeIds[i]) {
desc->attrs = attributeSpecs[i].flags; desc->attrs = attributeSpecs[i].flags;
desc->obj = wrapper; desc->obj = wrapper;
desc->setter = attributeSpecs[i].setter; desc->setter = attributeSpecs[i].setter.op;
desc->getter = attributeSpecs[i].getter; desc->getter = attributeSpecs[i].getter.op;
return true; return true;
} }
} }

View File

@ -961,12 +961,14 @@ class AttrDefiner(PropertyDefiner):
return flags return flags
def getter(attr): def getter(attr):
return "get_" + attr.identifier.name return ("{(JSPropertyOp)get_%(name)s, &%(name)s_getterinfo}"
% {"name" : attr.identifier.name})
def setter(attr): def setter(attr):
if attr.readonly: if attr.readonly:
return "NULL" return "JSOP_NULLWRAPPER"
return "set_" + attr.identifier.name return ("{(JSStrictPropertyOp)set_%(name)s, &%(name)s_setterinfo}"
% {"name" : attr.identifier.name})
def specData(attr): def specData(attr):
return (attr.identifier.name, flags(attr), getter(attr), return (attr.identifier.name, flags(attr), getter(attr),
@ -974,8 +976,8 @@ class AttrDefiner(PropertyDefiner):
return self.generatePrefableArray( return self.generatePrefableArray(
array, name, array, name,
' { "%s", 0, %s, (JSPropertyOp)%s, (JSStrictPropertyOp)%s }', ' { "%s", 0, %s, %s, %s}',
' { 0, 0, 0, 0, 0 }', ' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }',
'JSPropertySpec', 'JSPropertySpec',
PropertyDefiner.getControllingPref, specData, doIdArrays) PropertyDefiner.getControllingPref, specData, doIdArrays)
@ -3180,23 +3182,12 @@ class CGSetterCall(CGGetterSetterCall):
nativeMethodName, descriptor, attr, nativeMethodName, descriptor, attr,
setter=True) setter=True)
def wrap_return_value(self): def wrap_return_value(self):
if generateNativeAccessors:
return CGGetterSetterCall.wrap_return_value(self)
# We have no return value # We have no return value
return "\nreturn true;" return "\nreturn true;"
def getArgc(self): def getArgc(self):
if generateNativeAccessors:
return CGGetterSetterCall.getArgc(self)
return "1" return "1"
def getArgvDecl(self): def getArgvDecl(self):
if generateNativeAccessors: # We just get our stuff from our last arg no matter what
return (CGPerSignatureCall.getArgvDecl(self) +
"jsval undef = JS::UndefinedValue();\n"
"if (argc == 0) {\n"
" argv = &undef;\n"
" argc = 1;\n"
"}")
# We just get our stuff from vp
return "" return ""
class FakeCastableDescriptor(): class FakeCastableDescriptor():
@ -3231,7 +3222,7 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
def getThis(self): def getThis(self):
return CGIndenter( return CGIndenter(
CGGeneric("JSObject* obj = JS_THIS_OBJECT(cx, vp);\n" CGGeneric("JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n"
"if (!obj) {\n" "if (!obj) {\n"
" return false;\n" " return false;\n"
"}\n" "}\n"
@ -3282,10 +3273,29 @@ class CGNativeGetter(CGAbstractBindingMethod):
CGGeneric("%s* self;" % self.descriptor.nativeType)) CGGeneric("%s* self;" % self.descriptor.nativeType))
def generate_code(self): def generate_code(self):
return CGIndenter(CGGeneric(
"return specialized_get_%s(cx, obj, self, vp);" %
self.attr.identifier.name))
class CGSpecializedGetter(CGAbstractStaticMethod):
"""
A class for generating the code for a specialized attribute getter
that the JIT can call with lower overhead.
"""
def __init__(self, descriptor, attr):
self.attr = attr
name = 'specialized_get_' + attr.identifier.name
args = [ Argument('JSContext*', 'cx'),
Argument('JSHandleObject', 'obj'),
Argument('%s*' % descriptor.nativeType, 'self'),
Argument('JS::Value*', 'vp') ]
CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
def definition_body(self):
name = self.attr.identifier.name name = self.attr.identifier.name
nativeName = "Get" + MakeNativeName(self.descriptor.binaryNames.get(name, name)) nativeName = "Get" + MakeNativeName(self.descriptor.binaryNames.get(name, name))
return CGIndenter(CGGetterCall(self.attr.type, nativeName, self.descriptor, return CGIndenter(CGGetterCall(self.attr.type, nativeName,
self.attr)) self.descriptor, self.attr)).define()
class CGNativeSetter(CGAbstractBindingMethod): class CGNativeSetter(CGAbstractBindingMethod):
""" """
@ -3311,10 +3321,89 @@ class CGNativeSetter(CGAbstractBindingMethod):
CGGeneric("%s* self;" % self.descriptor.nativeType)) CGGeneric("%s* self;" % self.descriptor.nativeType))
def generate_code(self): def generate_code(self):
if generateNativeAccessors:
argv = ("JS::Value* argv = JS_ARGV(cx, vp);\n"
"jsval undef = JS::UndefinedValue();\n"
"if (argc == 0) {\n"
" argv = &undef;\n"
"}\n")
retval = "*vp = JSVAL_VOID;\n"
else:
argv = "JS::Value* argv = vp;\n"
retval = ""
return CGIndenter(CGGeneric(
argv +
("if (!specialized_set_%s(cx, obj, self, argv)) {\n"
" return false;\n"
"}\n" % self.attr.identifier.name) +
retval +
"return true;"))
class CGSpecializedSetter(CGAbstractStaticMethod):
"""
A class for generating the code for a specialized attribute setter
that the JIT can call with lower overhead.
"""
def __init__(self, descriptor, attr):
self.attr = attr
name = 'specialized_set_' + attr.identifier.name
args = [ Argument('JSContext*', 'cx'),
Argument('JSHandleObject', 'obj'),
Argument('%s*' % descriptor.nativeType, 'self') ]
# Our last argument is named differently depending on whether we're
# in the native accessors case or not
if generateNativeAccessors:
args.append(Argument('JS::Value*', 'argv'))
else:
args.append(Argument('JS::Value*', 'vp'))
CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
def definition_body(self):
name = self.attr.identifier.name name = self.attr.identifier.name
nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name)) nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name))
return CGIndenter(CGSetterCall(self.attr.type, nativeName, self.descriptor, return CGIndenter(CGSetterCall(self.attr.type, nativeName,
self.attr)) self.descriptor, self.attr)).define()
class CGPropertyJITInfo(CGThing):
"""
A class for generating the JITInfo for a property that points to
our specialized getter and setter.
"""
def __init__(self, descriptor, attr):
self.attr = attr
self.descriptor = descriptor
def declare(self):
return ""
def defineJitInfo(self, infoName, opName, infallible):
protoID = "prototypes::id::%s" % self.descriptor.interface.identifier.name
depth = "PrototypeTraits<%s>::Depth" % protoID
failstr = "true" if infallible else "false"
return ("\n"
"const JSJitInfo %s = {\n"
" %s,\n"
" %s,\n"
" %s,\n"
" %s, /* isInfallible. False for setters. */\n"
" false /* isConstant. False for setters. */\n"
"};\n" % (infoName, opName, protoID, depth, failstr))
def define(self):
getterinfo = ("%s_getterinfo" % self.attr.identifier.name)
getter = ("(JSJitPropertyOp)specialized_get_%s" %
self.attr.identifier.name)
# For now, mark all getters fallible, until argument wrapping has been
# handled.
result = self.defineJitInfo(getterinfo, getter, False)
if not self.attr.readonly:
setterinfo = ("%s_setterinfo" % self.attr.identifier.name)
setter = ("(JSJitPropertyOp)specialized_set_%s" %
self.attr.identifier.name)
# Setters are always fallible, since they have to do a typed unwrap.
result += self.defineJitInfo(setterinfo, setter, False)
return result
def getEnumValueName(value): def getEnumValueName(value):
# Some enum values can be empty strings. Others might have weird # Some enum values can be empty strings. Others might have weird
@ -4052,14 +4141,16 @@ class CGDescriptor(CGThing):
cgThings = [] cgThings = []
if descriptor.interface.hasInterfacePrototypeObject(): if descriptor.interface.hasInterfacePrototypeObject():
cgThings.extend([CGNativeMethod(descriptor, m) for m in for m in descriptor.interface.members:
descriptor.interface.members if if m.isMethod() and not m.isStatic():
m.isMethod() and not m.isStatic()]) cgThings.append(CGNativeMethod(descriptor, m))
cgThings.extend([CGNativeGetter(descriptor, a) for a in elif m.isAttr():
descriptor.interface.members if a.isAttr()]) cgThings.append(CGSpecializedGetter(descriptor, m))
cgThings.extend([CGNativeSetter(descriptor, a) for a in cgThings.append(CGNativeGetter(descriptor, m))
descriptor.interface.members if if not m.readonly:
a.isAttr() and not a.readonly]) cgThings.append(CGSpecializedSetter(descriptor, m))
cgThings.append(CGNativeSetter(descriptor, m))
cgThings.append(CGPropertyJITInfo(descriptor, m))
if descriptor.concrete: if descriptor.concrete:
if not descriptor.workers and descriptor.wrapperCache: if not descriptor.workers and descriptor.wrapperCache:

View File

@ -1292,11 +1292,23 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *cx);
JS_FRIEND_API(void *) JS_FRIEND_API(void *)
JS_GetDataViewData(JSObject *obj, JSContext *cx); JS_GetDataViewData(JSObject *obj, JSContext *cx);
#ifdef __cplusplus
/* /*
* This struct contains metadata passed from the DOM to the JS Engine for JIT * This struct contains metadata passed from the DOM to the JS Engine for JIT
* optimizations on DOM property accessors. Eventually, this should be made * optimizations on DOM property accessors. Eventually, this should be made
* available to general JSAPI users, but we are not currently ready to do so. * available to general JSAPI users, but we are not currently ready to do so.
*/ */
struct JSJitInfo; typedef bool
(* JSJitPropertyOp)(JSContext *cx, JSObject *thisObj,
void *specializedThis, JS::Value *vp);
struct JSJitInfo {
JSJitPropertyOp op;
uint32_t protoID;
uint32_t depth;
bool isInfallible; /* Is op fallible? Getters only */
bool isConstant; /* Getting a construction-time constant? */
};
#endif
#endif /* jsfriendapi_h___ */ #endif /* jsfriendapi_h___ */