From 4098828954a27e4c3ce12e23ac5caf724e67309a Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 4 Mar 2018 20:32:08 +0100 Subject: [PATCH 1/3] WIP: Accept typed array arguments in codegen --- .../dom/bindings/codegen/CodegenRust.py | 63 +++++++++++++++++-- components/script/dom/testbinding.rs | 4 ++ .../script/dom/webidls/TestBinding.webidl | 3 + 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d2d090f83502..06d8e84d49ba 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -563,6 +563,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, isMember=False, isArgument=False, isAutoRooted=False, + needsRootingInto=False, invalidEnumValueFatal=True, defaultValue=None, treatNullAs="Default", @@ -871,7 +872,45 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, return handleOptional(templateBody, declType, handleDefaultNull("None")) if type.isSpiderMonkeyInterface(): - raise TypeError("Can't handle SpiderMonkey interface arguments yet") + # Typed arrays can be constructed only with a prior rooted value + assert isArgument or isinstance(needsRootingInto, basestring) + + if failureCode is None: + substitutions = { + "sourceDescription": sourceDescription, + "exceptionCode": exceptionCode, + } + unwrapFailureCode = string.Template( + 'throw_type_error(cx, "${sourceDescription} is not a typed array.");\n' + '${exceptionCode}').substitute(substitutions) + else: + unwrapFailureCode = failureCode + + + templateBody = fill( + """ + match typedarray::${ty}::from(cx, &mut ${stackRootName}, + $${val}.get().to_object()) { + Ok(val) => val, + Err(()) => { + $*{failureCode} + } + } + """, + ty=type.name, + stackRootName=needsRootingInto, + failureCode=unwrapFailureCode + "\n", + ) + + declType = CGGeneric("typedarray::%s" % type.name) + if type.nullable(): + templateBody = "Some(%s)" % templateBody + declType = CGWrapper(declType, pre="Option<", post=">") + + templateBody = wrapObjectTemplate(templateBody, "None", + isDefinitelyObject, type, failureCode) + + return handleOptional(templateBody, declType, handleDefaultNull("None")) if type.isDOMString(): nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -1245,6 +1284,7 @@ def __init__(self, argument, index, args, argc, descriptorProvider, isClamp=argument.clamp, isMember="Variadic" if argument.variadic else False, isAutoRooted=type_needs_auto_root(argument.type), + needsRootingInto="arg_root" if type_conversion_needs_root(argument.type) else False, allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull()) template = info.template default = info.default @@ -1269,12 +1309,17 @@ def __init__(self, argument, index, args, argc, descriptorProvider, arg = "arg%d" % index - self.converter = instantiateJSToNativeConversionTemplate( - template, replacementVariables, declType, arg) + converter = [instantiateJSToNativeConversionTemplate( + template, replacementVariables, declType, arg)] + + if type_conversion_needs_root(argument.type): + converter.insert(0, CGGeneric("let mut arg_root = Rooted::new_unrooted();")) # The auto rooting is done only after the conversion is performed if type_needs_auto_root(argument.type): - self.converter.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (arg, arg))) + converter.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (arg, arg))) + + self.converter = CGList(converter, "\n") else: assert argument.optional @@ -5687,6 +5732,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::jsapi::MutableHandleValue', 'js::jsapi::ObjectOpResult', 'js::jsapi::PropertyDescriptor', + 'js::jsapi::Rooted', 'js::jsapi::RootedId', 'js::jsapi::RootedObject', 'js::jsapi::RootedString', @@ -5718,6 +5764,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries 'js::rust::define_methods', 'js::rust::define_properties', 'js::rust::get_object_class', + 'js::typedarray', 'dom', 'dom::bindings', 'dom::bindings::codegen::InterfaceObjectMap', @@ -6438,6 +6485,14 @@ def type_needs_tracing(t): assert False, (t, type(t)) +def type_conversion_needs_root(t): + assert isinstance(t, IDLObject), (t, type(t)) + + if t.isType(): + return t.isSpiderMonkeyInterface() + + assert False, (t, type(t)) + def type_needs_auto_root(t): """ Certain IDL types, such as `sequence` or `sequence` need to be diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 2dd774275909..1b6d74720008 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -38,6 +38,7 @@ use js::jsapi::{HandleObject, HandleValue, Heap, JSContext, JSObject}; use js::jsapi::{JS_NewPlainObject, JS_NewUint8ClampedArray}; use js::jsval::{JSVal, NullValue}; use js::rust::CustomAutoRooterGuard; +use js::typedarray; use script_traits::MsDuration; use servo_config::prefs::PREFS; use std::borrow::ToOwned; @@ -428,6 +429,9 @@ impl TestBindingMethods for TestBinding { fn PassByteString(&self, _: ByteString) {} fn PassEnum(&self, _: TestEnum) {} fn PassInterface(&self, _: &Blob) {} + fn PassTypedArray(&self, _: typedarray::Int8Array) {} + fn PassTypedArray2(&self, _: typedarray::ArrayBuffer) {} + fn PassTypedArray3(&self, _: typedarray::ArrayBufferView) {} fn PassUnion(&self, _: HTMLElementOrLong) {} fn PassUnion2(&self, _: EventOrString) {} fn PassUnion3(&self, _: BlobOrString) {} diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 25292953d60a..24473dbcd844 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -246,6 +246,9 @@ interface TestBinding { void passByteString(ByteString arg); void passEnum(TestEnum arg); void passInterface(Blob arg); + void passTypedArray(Int8Array arg); + void passTypedArray2(ArrayBuffer arg); + void passTypedArray3(ArrayBufferView arg); void passUnion((HTMLElement or long) arg); void passUnion2((Event or DOMString) data); void passUnion3((Blob or DOMString) data); From e4f59804c69af25113afee6e6fbaec96efb9fdaa Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Mon, 5 Mar 2018 20:41:33 +0100 Subject: [PATCH 2/3] Appease test-tidy --- components/script/dom/bindings/codegen/CodegenRust.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 06d8e84d49ba..368b7b42aeef 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -881,12 +881,11 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, "exceptionCode": exceptionCode, } unwrapFailureCode = string.Template( - 'throw_type_error(cx, "${sourceDescription} is not a typed array.");\n' - '${exceptionCode}').substitute(substitutions) + 'throw_type_error(cx, "${sourceDescription} is not a typed array.");\n' + '${exceptionCode}').substitute(substitutions) else: unwrapFailureCode = failureCode - templateBody = fill( """ match typedarray::${ty}::from(cx, &mut ${stackRootName}, @@ -6493,6 +6492,7 @@ def type_conversion_needs_root(t): assert False, (t, type(t)) + def type_needs_auto_root(t): """ Certain IDL types, such as `sequence` or `sequence` need to be From 6e5d3f007769d9c8bb3027753e37bd29c25422f4 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Wed, 7 Mar 2018 22:55:40 +0100 Subject: [PATCH 3/3] Apply feedback --- .../script/dom/bindings/codegen/CodegenRust.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 368b7b42aeef..ae415bd97da3 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -871,7 +871,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, return handleOptional(templateBody, declType, handleDefaultNull("None")) - if type.isSpiderMonkeyInterface(): + if type.isTypedArray() or type.isArrayBuffer() or type.isArrayBufferView() or type.isSharedArrayBuffer(): # Typed arrays can be constructed only with a prior rooted value assert isArgument or isinstance(needsRootingInto, basestring) @@ -911,6 +911,9 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, return handleOptional(templateBody, declType, handleDefaultNull("None")) + elif type.isSpiderMonkeyInterface(): + raise TypeError("Can't handle SpiderMonkey interface arguments other than typed arrays yet") + if type.isDOMString(): nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -6485,12 +6488,9 @@ def type_needs_tracing(t): def type_conversion_needs_root(t): - assert isinstance(t, IDLObject), (t, type(t)) + assert isinstance(t, IDLType) - if t.isType(): - return t.isSpiderMonkeyInterface() - - assert False, (t, type(t)) + return t.isSpiderMonkeyInterface() def type_needs_auto_root(t):