Optimize [StrictTypeChecking] on IDL operations
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 May 2016 19:46:35 +0000 (19:46 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 May 2016 19:46:35 +0000 (19:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157467

Reviewed by Darin Adler.

Source/WebCore:

Optimize [StrictTypeChecking] on IDL operations so that:
- Only generate extra code for nullable parameters because for non-nullable
  parameters, JSXXX::toWrapped() will return null in case of a bad input
  type. We will then throw a TypeError when null-checking it already.
- After the JSValue::isNullOrUndefined() check, avoid calling
  JSXXX::toWrapped() and set nativeValue to nullptr directly.
- Drop the check for JSValue::inherits(JSXXX::info()) and just do a null
  check on the value returned by JSXXX::toWrapped(). toWrapped() already
  does a JSValue::inherits(JSXXX::info() check. Since we only call
  toWrapped() if the JSValue is not null/undefined, a null return value
  always indicates a bad input type.

Also update the TypeError message to be more useful when passing null
for non-nullable parameters or assigning null to a non-nullable
attribute. The message is now consistent with the one used for strict
type checking.

No new tests, rebaselined existing tests.

* bindings/js/JSDOMBinding.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateImplementation):
(GenerateParametersCheck):
* bindings/scripts/test/JS/JSTestActiveDOMObject.cpp:
(WebCore::jsTestActiveDOMObjectPrototypeFunctionExcitingFunction):
* bindings/scripts/test/JS/JSTestInterface.cpp:
(WebCore::setJSTestInterfaceImplementsNode):
(WebCore::setJSTestInterfaceSupplementalNode):
(WebCore::jsTestInterfacePrototypeFunctionImplementsMethod2):
(WebCore::jsTestInterfacePrototypeFunctionSupplementalMethod2):
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::setJSTestObjTestObjAttr):
(WebCore::setJSTestObjLenientTestObjAttr):
(WebCore::setJSTestObjXMLObjAttr):
(WebCore::setJSTestObjTypedArrayAttr):
(WebCore::setJSTestObjWithScriptExecutionContextAttribute):
(WebCore::setJSTestObjWithScriptStateAttributeRaises):
(WebCore::setJSTestObjWithScriptExecutionContextAttributeRaises):
(WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateAttribute):
(WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateAttributeRaises):
(WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateWithSpacesAttribute):
(WebCore::setJSTestObjWithScriptArgumentsAndCallStackAttribute):
(WebCore::jsTestObjPrototypeFunctionVoidMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionByteMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionOctetMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionLongMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionObjMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionMethodWithXPathNSResolverParameter):
(WebCore::jsTestObjPrototypeFunctionMethodThatRequiresAllArgsAndThrows):
(WebCore::jsTestObjPrototypeFunctionOverloadedMethod8):
(WebCore::jsTestObjPrototypeFunctionDomStringListFunction):
(WebCore::jsTestObjPrototypeFunctionConvert1):
(WebCore::jsTestObjPrototypeFunctionStrictFunctionWithSequence):
(WebCore::jsTestObjPrototypeFunctionStrictFunctionWithArray):
(WebCore::jsTestObjPrototypeFunctionVariadicNodeMethod):
(WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2Promise):
* bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp:
(WebCore::constructJSTestOverloadedConstructors1):
(WebCore::constructJSTestOverloadedConstructors2):
(WebCore::constructJSTestOverloadedConstructors3):
* bindings/scripts/test/TestObj.idl:

LayoutTests:

Rebaseline existing tests now that we provide a more useful exception
message when passing null for a non-nullable parameter and assigning
null to a non-nullable attribute.

* editing/selection/extend-expected.txt:
* fast/dom/Document/adoptNode-null-expected.txt:
* fast/dom/Document/adoptNode-null.html:
* fast/dom/Document/importNode-null-expected.txt:
* fast/dom/Document/importNode-null.html:
* fast/dom/Element/attr-param-typechecking-expected.txt:
* fast/dom/MutationObserver/observe-exceptions-expected.txt:
* fast/dom/NamedNodeMap-setNamedItem-crash-expected.txt:
* fast/dom/Range/range-intersectsNode-expected.txt:
* fast/dom/createNodeIterator-parameters-expected.txt:
* fast/dom/createNodeIterator-parameters.html:
* fast/dom/createTreeWalker-parameters-expected.txt:
* fast/dom/createTreeWalker-parameters.html:
* fast/dom/xmlserializer-serialize-to-string-exception-expected.txt:
* fast/dynamic/insertAdjacentElement-expected.txt:
* fast/mediastream/MediaStream-add-remove-null-undefined-tracks-expected.txt:
* fast/speechsynthesis/speech-synthesis-crash-on-bad-utterance-expected.txt:
* fast/text/font-face-set-javascript-expected.txt:
* fast/text/text-combine-crash-expected.txt:
* media/encrypted-media/encrypted-media-v2-syntax-expected.txt:
* media/encrypted-media/encrypted-media-v2-syntax.html:
* webaudio/createMediaStreamSource-null-expected.txt:
* webaudio/createMediaStreamSource-null.html:
* webaudio/decode-audio-data-basic-expected.txt:
* webaudio/decode-audio-data-basic.html:
* webaudio/mediaelementaudiosourcenode-expected.txt:
* webaudio/mediaelementaudiosourcenode.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200583 268f45cc-cd09-0410-ab3c-d52691b4dbfc

36 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/selection/extend-expected.txt
LayoutTests/fast/dom/Document/adoptNode-null-expected.txt
LayoutTests/fast/dom/Document/adoptNode-null.html
LayoutTests/fast/dom/Document/importNode-null-expected.txt
LayoutTests/fast/dom/Document/importNode-null.html
LayoutTests/fast/dom/Element/attr-param-typechecking-expected.txt
LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt
LayoutTests/fast/dom/NamedNodeMap-setNamedItem-crash-expected.txt
LayoutTests/fast/dom/Range/range-intersectsNode-expected.txt
LayoutTests/fast/dom/createNodeIterator-parameters-expected.txt
LayoutTests/fast/dom/createNodeIterator-parameters.html
LayoutTests/fast/dom/createTreeWalker-parameters-expected.txt
LayoutTests/fast/dom/createTreeWalker-parameters.html
LayoutTests/fast/dom/xmlserializer-serialize-to-string-exception-expected.txt
LayoutTests/fast/dynamic/insertAdjacentElement-expected.txt
LayoutTests/fast/mediastream/MediaStream-add-remove-null-undefined-tracks-expected.txt
LayoutTests/fast/speechsynthesis/speech-synthesis-crash-on-bad-utterance-expected.txt
LayoutTests/fast/text/font-face-set-javascript-expected.txt
LayoutTests/fast/text/text-combine-crash-expected.txt
LayoutTests/media/encrypted-media/encrypted-media-v2-syntax-expected.txt
LayoutTests/media/encrypted-media/encrypted-media-v2-syntax.html
LayoutTests/webaudio/createMediaStreamSource-null-expected.txt
LayoutTests/webaudio/createMediaStreamSource-null.html
LayoutTests/webaudio/decode-audio-data-basic-expected.txt
LayoutTests/webaudio/decode-audio-data-basic.html
LayoutTests/webaudio/mediaelementaudiosourcenode-expected.txt
LayoutTests/webaudio/mediaelementaudiosourcenode.html
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp
Source/WebCore/bindings/scripts/test/TestObj.idl

index 85ea877..6533fee 100644 (file)
@@ -1,3 +1,42 @@
+2016-05-09  Chris Dumez  <cdumez@apple.com>
+
+        Optimize [StrictTypeChecking] on IDL operations
+        https://bugs.webkit.org/show_bug.cgi?id=157467
+
+        Reviewed by Darin Adler.
+
+        Rebaseline existing tests now that we provide a more useful exception
+        message when passing null for a non-nullable parameter and assigning
+        null to a non-nullable attribute.
+
+        * editing/selection/extend-expected.txt:
+        * fast/dom/Document/adoptNode-null-expected.txt:
+        * fast/dom/Document/adoptNode-null.html:
+        * fast/dom/Document/importNode-null-expected.txt:
+        * fast/dom/Document/importNode-null.html:
+        * fast/dom/Element/attr-param-typechecking-expected.txt:
+        * fast/dom/MutationObserver/observe-exceptions-expected.txt:
+        * fast/dom/NamedNodeMap-setNamedItem-crash-expected.txt:
+        * fast/dom/Range/range-intersectsNode-expected.txt:
+        * fast/dom/createNodeIterator-parameters-expected.txt:
+        * fast/dom/createNodeIterator-parameters.html:
+        * fast/dom/createTreeWalker-parameters-expected.txt:
+        * fast/dom/createTreeWalker-parameters.html:
+        * fast/dom/xmlserializer-serialize-to-string-exception-expected.txt:
+        * fast/dynamic/insertAdjacentElement-expected.txt:
+        * fast/mediastream/MediaStream-add-remove-null-undefined-tracks-expected.txt:
+        * fast/speechsynthesis/speech-synthesis-crash-on-bad-utterance-expected.txt:
+        * fast/text/font-face-set-javascript-expected.txt:
+        * fast/text/text-combine-crash-expected.txt:
+        * media/encrypted-media/encrypted-media-v2-syntax-expected.txt:
+        * media/encrypted-media/encrypted-media-v2-syntax.html:
+        * webaudio/createMediaStreamSource-null-expected.txt:
+        * webaudio/createMediaStreamSource-null.html:
+        * webaudio/decode-audio-data-basic-expected.txt:
+        * webaudio/decode-audio-data-basic.html:
+        * webaudio/mediaelementaudiosourcenode-expected.txt:
+        * webaudio/mediaelementaudiosourcenode.html:
+
 2016-05-09  Ryosuke Niwa  <rniwa@webkit.org>
 
         Focusing a shadow host places the slot content after the shadow DOM content
index 01ec74b..cf9f55a 100644 (file)
@@ -5,4 +5,4 @@ Success: s.extend(span2.firstChild, -1) raised Error: IndexSizeError: DOM Except
 Success: window.getSelection() is b.
 Success: window.getSelection() is arbaz.
 Success: s.extend() raised TypeError: Not enough arguments.
-Success: s.extend(null, 0) raised TypeError: Type error.
+Success: s.extend(null, 0) raised TypeError: Argument 1 ('node') to DOMSelection.extend must be an instance of Node.
index cae0a66..b3145a0 100644 (file)
@@ -3,7 +3,7 @@ Tests that document.adoptNode(null) throws a TypeError
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS document.adoptNode(null) threw exception TypeError: Type error.
+PASS document.adoptNode(null) threw exception TypeError: Argument 1 ('source') to Document.adoptNode must be an instance of Node.
 PASS document.adoptNode() threw exception TypeError: Not enough arguments.
 PASS successfullyParsed is true
 
index b083b84..d9a10b3 100644 (file)
@@ -5,7 +5,7 @@
 <script>
 description("Tests that document.adoptNode(null) throws a TypeError");
 
-shouldThrow("document.adoptNode(null)", "'TypeError: Type error'");
+shouldThrow("document.adoptNode(null)", "'TypeError: Argument 1 (\\'source\\') to Document.adoptNode must be an instance of Node'");
 shouldThrow("document.adoptNode()", "'TypeError: Not enough arguments'");
 </script>
 <script src="../../../resources/js-test-post.js"></script>
index 46d190a..1b1aa60 100644 (file)
@@ -3,7 +3,7 @@ Tests that document.importNode(null) throws a TypeError
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS document.importNode(null) threw exception TypeError: Type error.
+PASS document.importNode(null) threw exception TypeError: Argument 1 ('importedNode') to Document.importNode must be an instance of Node.
 PASS document.importNode() threw exception TypeError: Not enough arguments.
 PASS successfullyParsed is true
 
index c8a8671..a02ed87 100644 (file)
@@ -5,7 +5,7 @@
 <script>
 description("Tests that document.importNode(null) throws a TypeError");
 
-shouldThrow("document.importNode(null)", "'TypeError: Type error'");
+shouldThrow("document.importNode(null)", "'TypeError: Argument 1 (\\'importedNode\\') to Document.importNode must be an instance of Node'");
 shouldThrow("document.importNode()", "'TypeError: Not enough arguments'");
 </script>
 <script src="../../../resources/js-test-post.js"></script>
index 5451553..e8e9cb3 100644 (file)
@@ -3,18 +3,18 @@ This test checks whether passing wrong types to setAttributeNode causes a crash.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS element.setAttributeNode("style"); threw exception TypeError: Type error.
-PASS element.setAttributeNode(null); threw exception TypeError: Type error.
-PASS element.setAttributeNode(undefined); threw exception TypeError: Type error.
-PASS element.setAttributeNode(new Object); threw exception TypeError: Type error.
-PASS element.removeAttributeNode("style"); threw exception TypeError: Type error.
-PASS element.removeAttributeNode(null); threw exception TypeError: Type error.
-PASS element.removeAttributeNode(undefined); threw exception TypeError: Type error.
-PASS element.removeAttributeNode(new Object); threw exception TypeError: Type error.
-PASS element.setAttributeNodeNS("style"); threw exception TypeError: Type error.
-PASS element.setAttributeNodeNS(null); threw exception TypeError: Type error.
-PASS element.setAttributeNodeNS(undefined); threw exception TypeError: Type error.
-PASS element.setAttributeNodeNS(new Object); threw exception TypeError: Type error.
+PASS element.setAttributeNode("style"); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNode must be an instance of Attr.
+PASS element.setAttributeNode(null); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNode must be an instance of Attr.
+PASS element.setAttributeNode(undefined); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNode must be an instance of Attr.
+PASS element.setAttributeNode(new Object); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNode must be an instance of Attr.
+PASS element.removeAttributeNode("style"); threw exception TypeError: Argument 1 ('oldAttr') to Element.removeAttributeNode must be an instance of Attr.
+PASS element.removeAttributeNode(null); threw exception TypeError: Argument 1 ('oldAttr') to Element.removeAttributeNode must be an instance of Attr.
+PASS element.removeAttributeNode(undefined); threw exception TypeError: Argument 1 ('oldAttr') to Element.removeAttributeNode must be an instance of Attr.
+PASS element.removeAttributeNode(new Object); threw exception TypeError: Argument 1 ('oldAttr') to Element.removeAttributeNode must be an instance of Attr.
+PASS element.setAttributeNodeNS("style"); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNodeNS must be an instance of Attr.
+PASS element.setAttributeNodeNS(null); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNodeNS must be an instance of Attr.
+PASS element.setAttributeNodeNS(undefined); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNodeNS must be an instance of Attr.
+PASS element.setAttributeNodeNS(new Object); threw exception TypeError: Argument 1 ('newAttr') to Element.setAttributeNodeNS must be an instance of Attr.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 51eb460..ed9a2f5 100644 (file)
@@ -9,8 +9,8 @@ PASS observer.observe(undefined) threw exception TypeError: Not enough arguments
 PASS observer.observe(document.body) threw exception TypeError: Not enough arguments.
 PASS observer.observe(document.body, null) threw exception TypeError: Type error.
 PASS observer.observe(document.body, undefined) threw exception TypeError: Type error.
-PASS observer.observe(null, {attributes: true}) threw exception TypeError: Type error.
-PASS observer.observe(undefined, {attributes: true}) threw exception TypeError: Type error.
+PASS observer.observe(null, {attributes: true}) threw exception TypeError: Argument 1 ('target') to MutationObserver.observe must be an instance of Node.
+PASS observer.observe(undefined, {attributes: true}) threw exception TypeError: Argument 1 ('target') to MutationObserver.observe must be an instance of Node.
 PASS observer.observe(document.body, {subtree: true}) threw exception TypeError: Type error.
 PASS observer.observe(document.body, {childList: true, attributeOldValue: true}) did not throw exception.
 PASS observer.observe(document.body, {attributes: true, characterDataOldValue: true}) did not throw exception.
index 038056b..65e36f9 100644 (file)
@@ -1,2 +1,2 @@
-CONSOLE MESSAGE: line 7: TypeError: Type error
+CONSOLE MESSAGE: line 7: TypeError: Argument 1 ('node') to NamedNodeMap.setNamedItem must be an instance of Node
 This passes if it does not crash. (see https://bugs.webkit.org/show_bug.cgi?id=18958)
index 2a0b87a..30f3b4f 100644 (file)
@@ -59,7 +59,7 @@ PASS range.selectNode(document) threw exception Error: InvalidNodeTypeError: DOM
 PASS intersects is false
 
 2.6 Node deleted
-PASS range.intersectsNode(node) threw exception TypeError: Type error.
+PASS range.intersectsNode(node) threw exception TypeError: Argument 1 ('refNode') to Range.intersectsNode must be an instance of Node.
 
 PASS successfullyParsed is true
 
index 648aef0..32005b7 100644 (file)
@@ -7,7 +7,7 @@ No parameters
 PASS document.createNodeIterator() threw exception TypeError: Not enough arguments.
 
 Null root node
-PASS document.createNodeIterator(null) threw exception TypeError: Type error.
+PASS document.createNodeIterator(null) threw exception TypeError: Argument 1 ('root') to Document.createNodeIterator must be an instance of Node.
 
 Default parameters
 iterator = document.createNodeIterator(document)
index d68149f..5c47745 100644 (file)
@@ -10,7 +10,7 @@ shouldThrow("document.createNodeIterator()", "'TypeError: Not enough arguments'"
 
 debug("")
 debug("Null root node");
-shouldThrow("document.createNodeIterator(null)", "'TypeError: Type error'");
+shouldThrow("document.createNodeIterator(null)", "'TypeError: Argument 1 (\\'root\\') to Document.createNodeIterator must be an instance of Node'");
 
 debug("");
 debug("Default parameters");
index c6427b8..3ddcdb6 100644 (file)
@@ -7,7 +7,7 @@ No parameters
 PASS document.createTreeWalker() threw exception TypeError: Not enough arguments.
 
 Null root node
-PASS document.createTreeWalker(null) threw exception TypeError: Type error.
+PASS document.createTreeWalker(null) threw exception TypeError: Argument 1 ('root') to Document.createTreeWalker must be an instance of Node.
 
 Default parameters
 walker = document.createTreeWalker(document)
index 669f9a9..7c30f81 100644 (file)
@@ -10,7 +10,7 @@ shouldThrow("document.createTreeWalker()", "'TypeError: Not enough arguments'");
 
 debug("")
 debug("Null root node");
-shouldThrow("document.createTreeWalker(null)", "'TypeError: Type error'");
+shouldThrow("document.createTreeWalker(null)", "'TypeError: Argument 1 (\\'root\\') to Document.createTreeWalker must be an instance of Node'");
 
 debug("");
 debug("Default parameters");
index 2c0bd1c..f713712 100644 (file)
@@ -1,19 +1,19 @@
 This tests XMLSerializer.serializeToString() throwing exception when node value is invalid and passing otherwise.
 
 1. Verifying XMLSerializer.serializeToString() should THROW exception with node value = null
-Exception thrown = [TypeError: Type error]
+Exception thrown = [TypeError: Argument 1 ('node') to XMLSerializer.serializeToString must be an instance of Node]
 PASS
 
 2. Verifying XMLSerializer.serializeToString() should THROW exception with node value = undefined
-Exception thrown = [TypeError: Type error]
+Exception thrown = [TypeError: Argument 1 ('node') to XMLSerializer.serializeToString must be an instance of Node]
 PASS
 
 3. Verifying XMLSerializer.serializeToString() should THROW exception with node value = <html><title>Hello World</title></html>
-Exception thrown = [TypeError: Type error]
+Exception thrown = [TypeError: Argument 1 ('node') to XMLSerializer.serializeToString must be an instance of Node]
 PASS
 
 4. Verifying XMLSerializer.serializeToString() should THROW exception with node value = [object HTMLCollection]
-Exception thrown = [TypeError: Type error]
+Exception thrown = [TypeError: Argument 1 ('node') to XMLSerializer.serializeToString must be an instance of Node]
 PASS
 
 5. Verifying XMLSerializer.serializeToString() should NOT-THROW exception with node value = [object HTMLDocument]
index 33818ad..f30974e 100644 (file)
@@ -1,5 +1,5 @@
 Caught expected exception: Error: NotSupportedError: DOM Exception 9
-Caught expected exception: TypeError: Type error
+Caught expected exception: TypeError: Argument 2 ('element') to HTMLElement.insertAdjacentElement must be an instance of Element
 1 (black) 2 (green) 3 (green) 4 (black) 
 
 PASS
index bade8c6..730aa57 100644 (file)
@@ -5,12 +5,12 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 Calling addTrack with null and undefined parameters
-PASS stream.addTrack(null); threw exception TypeError: Type error.
-PASS stream.addTrack(undefined); threw exception TypeError: Type error.
+PASS stream.addTrack(null); threw exception TypeError: Argument 1 ('track') to MediaStream.addTrack must be an instance of MediaStreamTrack.
+PASS stream.addTrack(undefined); threw exception TypeError: Argument 1 ('track') to MediaStream.addTrack must be an instance of MediaStreamTrack.
 
 Calling removeTrack with null and undefined parameters
-PASS stream.removeTrack(null); threw exception TypeError: Type error.
-PASS stream.removeTrack(undefined); threw exception TypeError: Type error.
+PASS stream.removeTrack(null); threw exception TypeError: Argument 1 ('track') to MediaStream.removeTrack must be an instance of MediaStreamTrack.
+PASS stream.removeTrack(undefined); threw exception TypeError: Argument 1 ('track') to MediaStream.removeTrack must be an instance of MediaStreamTrack.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 536fa8e..dba789a 100644 (file)
@@ -3,7 +3,7 @@ This tests that passing in the wrong type of data won't crash speech synthesis c
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS speechSynthesis.speak('Hello World') threw exception TypeError: Type error.
+PASS speechSynthesis.speak('Hello World') threw exception TypeError: Argument 1 ('utterance') to SpeechSynthesis.speak must be an instance of SpeechSynthesisUtterance.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 7cf1263..9554d12 100644 (file)
@@ -13,7 +13,7 @@ PASS item.value is fontFace1
 PASS item.done is true
 PASS fontFaceSet.add(fontFace2) is fontFaceSet
 PASS fontFaceSet.size is 2
-PASS fontFaceSet.add(null) threw exception TypeError: Type error.
+PASS fontFaceSet.add(null) threw exception TypeError: Argument 1 ('font') to FontFaceSet.add must be an instance of FontFace.
 PASS item.done is false
 PASS item.value is fontFace1
 PASS item.done is false
@@ -21,10 +21,10 @@ PASS item.value is fontFace2
 PASS item.done is true
 PASS fontFaceSet.delete(fontFace1) is true
 PASS fontFaceSet.delete(fontFace3) is false
-PASS fontFaceSet.delete(null) threw exception TypeError: Type error.
+PASS fontFaceSet.delete(null) threw exception TypeError: Argument 1 ('font') to FontFaceSet.delete must be an instance of FontFace.
 PASS fontFaceSet.has(fontFace1) is false
 PASS fontFaceSet.has(fontFace2) is true
-PASS fontFaceSet.has(null) threw exception TypeError: Type error.
+PASS fontFaceSet.has(null) threw exception TypeError: Argument 1 ('font') to FontFaceSet.has must be an instance of FontFace.
 PASS fontFaceSet.size is 0
 PASS fontFaceSet.values().next().done is true
 PASS fontFaceSet.check('garbage') threw exception Error: SyntaxError: DOM Exception 12.
index 2f0e808..5335ff3 100644 (file)
@@ -6,12 +6,12 @@ Test passes if there's no crash.
 
 
 Errlog webtest_fn_1: TypeError: undefined is not an object (evaluating 'document.applets[0].addEventListener')
-Errlog webtest_fn_2: TypeError: Type error
+Errlog webtest_fn_2: TypeError: Argument 1 ('refNode') to Range.setStartBefore must be an instance of Node
 Errlog webtest_fn_3: TypeError: undefined is not an object (evaluating 'document.images[2].contentEditable="true"')
 Errlog webtest_fn_8: TypeError: null is not an object (evaluating 'lis.length')
 Errlog webtest_fn_9: TypeError: undefined is not an object (evaluating 'document.anchors[4].setAttribute')
-Errlog webtest_fn_10: TypeError: Type error
-Errlog webtest_fn_15: TypeError: Type error
+Errlog webtest_fn_10: TypeError: Argument 1 ('refNode') to Range.setStartAfter must be an instance of Node
+Errlog webtest_fn_15: TypeError: Argument 1 ('refNode') to Range.setStart must be an instance of Node
 Errlog webtest_fn_16: TypeError: undefined is not an object (evaluating 'elem.parentNode')
 ´┐╝´┐╝Errlog webtest_fn_18: TypeError: undefined is not an object (evaluating 'document.applets[0].contentEditable="true"')
 Errlog webtest_fn_21: TypeError: undefined is not an object (evaluating 'document.anchors[4].appendChild')
index 02a1830..3f58c85 100644 (file)
@@ -22,6 +22,6 @@ EXPECTED (mediaKeySession.sessionId != 'null') OK
 EXPECTED (mediaKeySession.onwebkitkeyadded == 'null') OK
 EXPECTED (mediaKeySession.onwebkitkeyerror == 'null') OK
 EXPECTED (mediaKeySession.onwebkitkeymessage == 'null') OK
-TEST(mediaKeySession.update(null)) THROWS('TypeError: Type error') OK
+TEST(mediaKeySession.update(null)) THROWS('TypeError: Argument 1 (\'key\') to MediaKeySession.update must be an instance of Uint8Array') OK
 END OF TEST
 
index 104cbbe..13dae4a 100644 (file)
@@ -47,7 +47,7 @@
                 testExpected('mediaKeySession.onwebkitkeyadded', null);
                 testExpected('mediaKeySession.onwebkitkeyerror', null);
                 testExpected('mediaKeySession.onwebkitkeymessage', null);
-                testException('mediaKeySession.update(null)', "'TypeError: Type error'");
+                testException('mediaKeySession.update(null)', "'TypeError: Argument 1 (\\'key\\') to MediaKeySession.update must be an instance of Uint8Array'");
                 endTest();
             }
         </script>
index 671414d..23f7042 100644 (file)
@@ -3,7 +3,7 @@ Tests that passing null to context.createMediaStreamSource() throws a TypeError.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS context.createMediaStreamSource(null) threw exception TypeError: Type error.
+PASS context.createMediaStreamSource(null) threw exception TypeError: Argument 1 ('mediaStream') to AudioContext.createMediaStreamSource must be an instance of MediaStream.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index bd6d5fb..02f7225 100644 (file)
@@ -9,7 +9,7 @@
 description("Tests that passing null to context.createMediaStreamSource() throws a TypeError.");
 
 var context = new webkitAudioContext();
-shouldThrow("context.createMediaStreamSource(null)", "'TypeError: Type error'");
+shouldThrow("context.createMediaStreamSource(null)", "'TypeError: Argument 1 (\\'mediaStream\\') to AudioContext.createMediaStreamSource must be an instance of MediaStream'");
 
 </script>
 <script src="../resources/js-test-post.js"></script>
index a761885..d8c8bd1 100644 (file)
@@ -3,7 +3,7 @@ Basic tests for decodeAudioData function.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS context.decodeAudioData(null, function(){}, function(){}); threw exception TypeError: Type error.
+PASS context.decodeAudioData(null, function(){}, function(){}); threw exception TypeError: Argument 1 ('audioData') to AudioContext.decodeAudioData must be an instance of ArrayBuffer.
 PASS The resources/media/24bit-44khz.wav test: successCallback has been called correctly.
 PASS The resources/media/invalid-audio-file.txt test: errorCallback has been called correctly.
 PASS successfullyParsed is true
index efc1315..9491061 100644 (file)
@@ -18,7 +18,7 @@ window.jsTestIsAsync = true;
 var context = new webkitAudioContext();
 
 // decodeAudioData should raise exception when arraybuffer parameter is null.
-shouldThrow("context.decodeAudioData(null, function(){}, function(){});", "'TypeError: Type error'");
+shouldThrow("context.decodeAudioData(null, function(){}, function(){});", "'TypeError: Argument 1 (\\'audioData\\') to AudioContext.decodeAudioData must be an instance of ArrayBuffer'");
 
 var decodeCaseArray = [{url: "resources/media/24bit-44khz.wav", result: true},
                        {url: "resources/media/invalid-audio-file.txt", result: false}];
index bf35a9b..cb8613d 100644 (file)
@@ -9,7 +9,7 @@ PASS connect() exception thrown for illegal output index.
 PASS connect() exception thrown for illegal input index.
 PASS audioNode.connect(context.destination) succeeded.
 PASS createMediaElementSource() threw error when called twice on same HTMLMediaElement.
-PASS context.createMediaElementSource(null) threw exception TypeError: Type error.
+PASS context.createMediaElementSource(null) threw exception TypeError: Argument 1 ('mediaElement') to AudioContext.createMediaElementSource must be an instance of HTMLMediaElement.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 42b0ae9..7832493 100644 (file)
@@ -79,7 +79,7 @@ function runTest() {
         testPassed("createMediaElementSource() threw error when called twice on same HTMLMediaElement.");
     }
 
-    shouldThrow("context.createMediaElementSource(null)", "'TypeError: Type error'");
+    shouldThrow("context.createMediaElementSource(null)", "'TypeError: Argument 1 (\\'mediaElement\\') to AudioContext.createMediaElementSource must be an instance of HTMLMediaElement'");
 
     finishJSTest();
 }
index 17722cb..8cede68 100644 (file)
@@ -1,3 +1,72 @@
+2016-05-09  Chris Dumez  <cdumez@apple.com>
+
+        Optimize [StrictTypeChecking] on IDL operations
+        https://bugs.webkit.org/show_bug.cgi?id=157467
+
+        Reviewed by Darin Adler.
+
+        Optimize [StrictTypeChecking] on IDL operations so that:
+        - Only generate extra code for nullable parameters because for non-nullable
+          parameters, JSXXX::toWrapped() will return null in case of a bad input
+          type. We will then throw a TypeError when null-checking it already.
+        - After the JSValue::isNullOrUndefined() check, avoid calling
+          JSXXX::toWrapped() and set nativeValue to nullptr directly.
+        - Drop the check for JSValue::inherits(JSXXX::info()) and just do a null
+          check on the value returned by JSXXX::toWrapped(). toWrapped() already
+          does a JSValue::inherits(JSXXX::info() check. Since we only call
+          toWrapped() if the JSValue is not null/undefined, a null return value
+          always indicates a bad input type.
+
+        Also update the TypeError message to be more useful when passing null
+        for non-nullable parameters or assigning null to a non-nullable
+        attribute. The message is now consistent with the one used for strict
+        type checking.
+
+        No new tests, rebaselined existing tests.
+
+        * bindings/js/JSDOMBinding.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateImplementation):
+        (GenerateParametersCheck):
+        * bindings/scripts/test/JS/JSTestActiveDOMObject.cpp:
+        (WebCore::jsTestActiveDOMObjectPrototypeFunctionExcitingFunction):
+        * bindings/scripts/test/JS/JSTestInterface.cpp:
+        (WebCore::setJSTestInterfaceImplementsNode):
+        (WebCore::setJSTestInterfaceSupplementalNode):
+        (WebCore::jsTestInterfacePrototypeFunctionImplementsMethod2):
+        (WebCore::jsTestInterfacePrototypeFunctionSupplementalMethod2):
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::setJSTestObjTestObjAttr):
+        (WebCore::setJSTestObjLenientTestObjAttr):
+        (WebCore::setJSTestObjXMLObjAttr):
+        (WebCore::setJSTestObjTypedArrayAttr):
+        (WebCore::setJSTestObjWithScriptExecutionContextAttribute):
+        (WebCore::setJSTestObjWithScriptStateAttributeRaises):
+        (WebCore::setJSTestObjWithScriptExecutionContextAttributeRaises):
+        (WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateAttribute):
+        (WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateAttributeRaises):
+        (WebCore::setJSTestObjWithScriptExecutionContextAndScriptStateWithSpacesAttribute):
+        (WebCore::setJSTestObjWithScriptArgumentsAndCallStackAttribute):
+        (WebCore::jsTestObjPrototypeFunctionVoidMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionByteMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionOctetMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionLongMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionObjMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionMethodWithXPathNSResolverParameter):
+        (WebCore::jsTestObjPrototypeFunctionMethodThatRequiresAllArgsAndThrows):
+        (WebCore::jsTestObjPrototypeFunctionOverloadedMethod8):
+        (WebCore::jsTestObjPrototypeFunctionDomStringListFunction):
+        (WebCore::jsTestObjPrototypeFunctionConvert1):
+        (WebCore::jsTestObjPrototypeFunctionStrictFunctionWithSequence):
+        (WebCore::jsTestObjPrototypeFunctionStrictFunctionWithArray):
+        (WebCore::jsTestObjPrototypeFunctionVariadicNodeMethod):
+        (WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2Promise):
+        * bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp:
+        (WebCore::constructJSTestOverloadedConstructors1):
+        (WebCore::constructJSTestOverloadedConstructors2):
+        (WebCore::constructJSTestOverloadedConstructors3):
+        * bindings/scripts/test/TestObj.idl:
+
 2016-05-09  Tim Horton  <timothy_horton@apple.com>
 
         Download progress on attachment elements sometimes exceeds element bounds
index f87654b..5cdfa5b 100644 (file)
@@ -123,7 +123,7 @@ WEBCORE_EXPORT void throwNonFiniteTypeError(JSC::ExecState&);
 
 WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues);
 JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
-JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
+WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
 JSC::EncodedJSValue throwConstructorDocumentUnavailableError(JSC::ExecState&, const char* interfaceName);
 WEBCORE_EXPORT JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
 WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, const char* interfaceName, const char* functionName);
index 8e3c78d..e45f8a1 100644 (file)
@@ -2917,13 +2917,15 @@ sub GenerateImplementation
                     push(@implContent, "    ExceptionCode ec = 0;\n");
                 }
 
+                my $shouldPassByReference = ShouldPassWrapperByReference($attribute->signature, $interface);
+
                 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
                 # interface type, then if the incoming value does not implement that interface, a TypeError
                 # is thrown rather than silently passing NULL to the C++ code.
                 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
                 # both strings and numbers, so do not throw TypeError if the attribute is of these types.
                 my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $attribute->signature, "value", $attribute->signature->extendedAttributes->{"Conditional"});
-                if ($codeGenerator->IsWrapperType($type) && $attribute->signature->extendedAttributes->{"StrictTypeChecking"} && $attribute->signature->isNullable) {
+                if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"} && !$shouldPassByReference && $codeGenerator->IsWrapperType($type)) {
                     $implIncludes{"<runtime/Error.h>"} = 1;
                     push(@implContent, "    " . GetNativeTypeFromSignature($interface, $attribute->signature) . " nativeValue = nullptr;\n");
                     push(@implContent, "    if (!value.isUndefinedOrNull()) {\n");
@@ -2950,10 +2952,9 @@ sub GenerateImplementation
                     push (@implContent, "        return false;\n");
                 }
 
-                my $shouldPassByReference = ShouldPassWrapperByReference($attribute->signature, $interface);
                 if ($shouldPassByReference) {
                     push(@implContent, "    if (UNLIKELY(!nativeValue)) {\n");
-                    push(@implContent, "        throwVMTypeError(state);\n");
+                    push(@implContent, "        throwAttributeTypeError(*state, \"$interfaceName\", \"$name\", \"$type\");\n");
                     push(@implContent, "        return false;\n");
                     push(@implContent, "    }\n");
                 }
@@ -3733,68 +3734,71 @@ sub GenerateParametersCheck
 
             push(@$outputArray, "    }\n") if $indent ne "";
         } else {
-            # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
-            # interface type, then if the incoming value does not implement that interface, a TypeError
-            # is thrown rather than silently passing NULL to the C++ code.
-            # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both
-            # strings and numbers, so do not throw TypeError if the argument is of these types.
-            if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
-                $implIncludes{"<runtime/Error.h>"} = 1;
-
-                my $argValue = "state->argument($argumentIndex)";
-                if ($codeGenerator->IsWrapperType($type)) {
-                    push(@$outputArray, "    if (UNLIKELY(!${argValue}.isUndefinedOrNull() && !${argValue}.inherits(JS${type}::info())))\n");
-                    push(@$outputArray, "        return throwArgumentTypeError(*state, $argumentIndex, \"$name\", \"$interfaceName\", $quotedFunctionName, \"$type\");\n");
-                }
-            }
-
             my $outer;
             my $inner;
             my $nativeType = GetNativeTypeFromSignature($interface, $parameter);
+            my $isTearOff = $codeGenerator->IsSVGTypeNeedingTearOff($type) && $interfaceName !~ /List$/;
+            my $shouldPassByReference = $isTearOff || ShouldPassWrapperByReference($parameter, $interface);
 
-            if ($parameter->isOptional && defined($parameter->default) && !WillConvertUndefinedToDefaultParameterValue($type, $parameter->default)) {
-                my $defaultValue = $parameter->default;
-
-                # String-related optimizations.
-                if ($type eq "DOMString") {
-                    my $useAtomicString = $parameter->extendedAttributes->{"AtomicString"};
-                    if ($defaultValue eq "null") {
-                        $defaultValue = $useAtomicString ? "nullAtom" : "String()";
-                    } elsif ($defaultValue eq "\"\"") {
-                        $defaultValue = $useAtomicString ? "emptyAtom" : "emptyString()";
+            if ($function->signature->extendedAttributes->{"StrictTypeChecking"} && !$shouldPassByReference && $codeGenerator->IsWrapperType($type)) {
+                $implIncludes{"<runtime/Error.h>"} = 1;
+                my $checkedArgument = "state->argument($argumentIndex)";
+                my $uncheckedArgument = "state->uncheckedArgument($argumentIndex)";
+                my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $parameter, $uncheckedArgument, $function->signature->extendedAttributes->{"Conditional"});
+                push(@$outputArray, "    $nativeType $name = nullptr;\n");
+                push(@$outputArray, "    if (!$checkedArgument.isUndefinedOrNull()) {\n");
+                push(@$outputArray, "        $name = $nativeValue;\n");
+                if ($mayThrowException) {
+                    push(@$outputArray, "    if (UNLIKELY(state->hadException()))\n");
+                    push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
+                }
+                push(@$outputArray, "        if (UNLIKELY(!$name))\n");
+                push(@$outputArray, "            return throwArgumentTypeError(*state, $argumentIndex, \"$name\", \"$interfaceName\", $quotedFunctionName, \"$type\");\n");
+                push(@$outputArray, "    }\n");
+            } else {
+                if ($parameter->isOptional && defined($parameter->default) && !WillConvertUndefinedToDefaultParameterValue($type, $parameter->default)) {
+                    my $defaultValue = $parameter->default;
+    
+                    # String-related optimizations.
+                    if ($type eq "DOMString") {
+                        my $useAtomicString = $parameter->extendedAttributes->{"AtomicString"};
+                        if ($defaultValue eq "null") {
+                            $defaultValue = $useAtomicString ? "nullAtom" : "String()";
+                        } elsif ($defaultValue eq "\"\"") {
+                            $defaultValue = $useAtomicString ? "emptyAtom" : "emptyString()";
+                        } else {
+                            $defaultValue = $useAtomicString ? "AtomicString($defaultValue, AtomicString::ConstructFromLiteral)" : "ASCIILiteral($defaultValue)";
+                        }
                     } else {
-                        $defaultValue = $useAtomicString ? "AtomicString($defaultValue, AtomicString::ConstructFromLiteral)" : "ASCIILiteral($defaultValue)";
+                        $defaultValue = "nullptr" if $defaultValue eq "null";
+                        $defaultValue = "PNaN" if $defaultValue eq "NaN";
+                        $defaultValue = "$nativeType()" if $defaultValue eq "[]";
+                        $defaultValue = "JSValue::JSUndefined" if $defaultValue eq "undefined";
                     }
+    
+                    $outer = "state->argument($argumentIndex).isUndefined() ? $defaultValue : ";
+                    $inner = "state->uncheckedArgument($argumentIndex)";
+                } elsif ($parameter->isOptional && !defined($parameter->default)) {
+                    # Use WTF::Optional<>() for optional parameters that are missing or undefined and that do not have a default value in the IDL.
+                    $outer = "state->argument($argumentIndex).isUndefined() ? Optional<$nativeType>() : ";
+                    $inner = "state->uncheckedArgument($argumentIndex)";
                 } else {
-                    $defaultValue = "nullptr" if $defaultValue eq "null";
-                    $defaultValue = "PNaN" if $defaultValue eq "NaN";
-                    $defaultValue = "$nativeType()" if $defaultValue eq "[]";
-                    $defaultValue = "JSValue::JSUndefined" if $defaultValue eq "undefined";
+                    $outer = "";
+                    $inner = "state->argument($argumentIndex)";
                 }
 
-                $outer = "state->argument($argumentIndex).isUndefined() ? $defaultValue : ";
-                $inner = "state->uncheckedArgument($argumentIndex)";
-            } elsif ($parameter->isOptional && !defined($parameter->default)) {
-                # Use WTF::Optional<>() for optional parameters that are missing or undefined and that do not have a default value in the IDL.
-                $outer = "state->argument($argumentIndex).isUndefined() ? Optional<$nativeType>() : ";
-                $inner = "state->uncheckedArgument($argumentIndex)";
-            } else {
-                $outer = "";
-                $inner = "state->argument($argumentIndex)";
-            }
-            my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $parameter, $inner, $function->signature->extendedAttributes->{"Conditional"});
-            push(@$outputArray, "    auto $name = ${outer}${nativeValue};\n");
-            $value = "WTFMove($name)";
-            if ($mayThrowException) {
-                push(@$outputArray, "    if (UNLIKELY(state->hadException()))\n");
-                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
+                my ($nativeValue, $mayThrowException) = JSValueToNative($interface, $parameter, $inner, $function->signature->extendedAttributes->{"Conditional"});
+                push(@$outputArray, "    auto $name = ${outer}${nativeValue};\n");
+                $value = "WTFMove($name)";
+                if ($mayThrowException) {
+                    push(@$outputArray, "    if (UNLIKELY(state->hadException()))\n");
+                    push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
+                }
             }
 
-            my $isTearOff = $codeGenerator->IsSVGTypeNeedingTearOff($type) && $interfaceName !~ /List$/;
-            my $shouldPassByReference = ShouldPassWrapperByReference($parameter, $interface);
-            if ($isTearOff or $shouldPassByReference) {
+            if ($shouldPassByReference) {
                 push(@$outputArray, "    if (UNLIKELY(!$name))\n");
-                push(@$outputArray, "        return throwVMTypeError(state);\n");
+                push(@$outputArray, "        return throwArgumentTypeError(*state, $argumentIndex, \"$name\", \"$interfaceName\", $quotedFunctionName, \"$type\");\n");
                 $value = $isTearOff ? "$name->propertyReference()" : "*$name";
             }
 
index 6db72a9..b377d85 100644 (file)
@@ -205,7 +205,7 @@ EncodedJSValue JSC_HOST_CALL jsTestActiveDOMObjectPrototypeFunctionExcitingFunct
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto nextChild = JSNode::toWrapped(state->argument(0));
     if (UNLIKELY(!nextChild))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "nextChild", "TestActiveDOMObject", "excitingFunction", "Node");
     impl.excitingFunction(*nextChild);
     return JSValue::encode(jsUndefined());
 }
index 72d7d2f..9370a73 100644 (file)
@@ -685,7 +685,7 @@ bool setJSTestInterfaceImplementsNode(ExecState* state, EncodedJSValue thisValue
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSNode::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestInterface", "implementsNode", "Node");
         return false;
     }
     impl.setImplementsNode(*nativeValue);
@@ -753,7 +753,7 @@ bool setJSTestInterfaceSupplementalNode(ExecState* state, EncodedJSValue thisVal
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSNode::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestInterface", "supplementalNode", "Node");
         return false;
     }
     WebCore::TestSupplemental::setSupplementalNode(impl, *nativeValue);
@@ -802,7 +802,7 @@ EncodedJSValue JSC_HOST_CALL jsTestInterfacePrototypeFunctionImplementsMethod2(E
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(1));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 1, "objArg", "TestInterface", "implementsMethod2", "TestObj");
     JSValue result = toJS(state, castedThis->globalObject(), WTF::getPtr(impl.implementsMethod2(*context, WTFMove(strArg), *objArg, ec)));
 
     setDOMException(state, ec);
@@ -868,7 +868,7 @@ EncodedJSValue JSC_HOST_CALL jsTestInterfacePrototypeFunctionSupplementalMethod2
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(1));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 1, "objArg", "TestInterface", "supplementalMethod2", "TestObj");
     JSValue result = toJS(state, castedThis->globalObject(), WTF::getPtr(WebCore::TestSupplemental::supplementalMethod2(impl, *context, WTFMove(strArg), *objArg, ec)));
 
     setDOMException(state, ec);
index c309afd..d675598 100644 (file)
@@ -2866,7 +2866,7 @@ bool setJSTestObjTestObjAttr(ExecState* state, EncodedJSValue thisValue, Encoded
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "testObjAttr", "TestObj");
         return false;
     }
     impl.setTestObjAttr(*nativeValue);
@@ -2900,7 +2900,7 @@ bool setJSTestObjLenientTestObjAttr(ExecState* state, EncodedJSValue thisValue,
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "lenientTestObjAttr", "TestObj");
         return false;
     }
     impl.setLenientTestObjAttr(*nativeValue);
@@ -2936,7 +2936,7 @@ bool setJSTestObjXMLObjAttr(ExecState* state, EncodedJSValue thisValue, EncodedJ
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "XMLObjAttr", "TestObj");
         return false;
     }
     impl.setXMLObjAttr(*nativeValue);
@@ -3146,7 +3146,7 @@ bool setJSTestObjTypedArrayAttr(ExecState* state, EncodedJSValue thisValue, Enco
     if (UNLIKELY(state->hadException()))
         return false;
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "typedArrayAttr", "Float32Array");
         return false;
     }
     impl.setTypedArrayAttr(nativeValue.get());
@@ -3368,7 +3368,7 @@ bool setJSTestObjWithScriptExecutionContextAttribute(ExecState* state, EncodedJS
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptExecutionContextAttribute", "TestObj");
         return false;
     }
     auto* context = jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())->scriptExecutionContext();
@@ -3390,7 +3390,7 @@ bool setJSTestObjWithScriptStateAttributeRaises(ExecState* state, EncodedJSValue
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptStateAttributeRaises", "TestObj");
         return false;
     }
     impl.setWithScriptStateAttributeRaises(*state, *nativeValue);
@@ -3409,7 +3409,7 @@ bool setJSTestObjWithScriptExecutionContextAttributeRaises(ExecState* state, Enc
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptExecutionContextAttributeRaises", "TestObj");
         return false;
     }
     auto* context = jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())->scriptExecutionContext();
@@ -3431,7 +3431,7 @@ bool setJSTestObjWithScriptExecutionContextAndScriptStateAttribute(ExecState* st
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptExecutionContextAndScriptStateAttribute", "TestObj");
         return false;
     }
     auto* context = jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())->scriptExecutionContext();
@@ -3453,7 +3453,7 @@ bool setJSTestObjWithScriptExecutionContextAndScriptStateAttributeRaises(ExecSta
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptExecutionContextAndScriptStateAttributeRaises", "TestObj");
         return false;
     }
     auto* context = jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())->scriptExecutionContext();
@@ -3475,7 +3475,7 @@ bool setJSTestObjWithScriptExecutionContextAndScriptStateWithSpacesAttribute(Exe
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptExecutionContextAndScriptStateWithSpacesAttribute", "TestObj");
         return false;
     }
     auto* context = jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject())->scriptExecutionContext();
@@ -3497,7 +3497,7 @@ bool setJSTestObjWithScriptArgumentsAndCallStackAttribute(ExecState* state, Enco
     auto& impl = castedThis->wrapped();
     auto nativeValue = JSTestObj::toWrapped(value);
     if (UNLIKELY(!nativeValue)) {
-        throwVMTypeError(state);
+        throwAttributeTypeError(*state, "TestObj", "withScriptArgumentsAndCallStackAttribute", "TestObj");
         return false;
     }
     impl.setWithScriptArgumentsAndCallStackAttribute(*nativeValue);
@@ -3926,7 +3926,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVoidMethodWithArgs(ExecSt
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(2));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 2, "objArg", "TestObj", "voidMethodWithArgs", "TestObj");
     impl.voidMethodWithArgs(WTFMove(longArg), WTFMove(strArg), *objArg);
     return JSValue::encode(jsUndefined());
 }
@@ -3961,7 +3961,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionByteMethodWithArgs(ExecSt
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(2));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 2, "objArg", "TestObj", "byteMethodWithArgs", "TestObj");
     JSValue result = jsNumber(impl.byteMethodWithArgs(WTFMove(byteArg), WTFMove(strArg), *objArg));
     return JSValue::encode(result);
 }
@@ -3996,7 +3996,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionOctetMethodWithArgs(ExecS
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(2));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 2, "objArg", "TestObj", "octetMethodWithArgs", "TestObj");
     JSValue result = jsNumber(impl.octetMethodWithArgs(WTFMove(octetArg), WTFMove(strArg), *objArg));
     return JSValue::encode(result);
 }
@@ -4031,7 +4031,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionLongMethodWithArgs(ExecSt
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(2));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 2, "objArg", "TestObj", "longMethodWithArgs", "TestObj");
     JSValue result = jsNumber(impl.longMethodWithArgs(WTFMove(longArg), WTFMove(strArg), *objArg));
     return JSValue::encode(result);
 }
@@ -4066,7 +4066,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionObjMethodWithArgs(ExecSta
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(2));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 2, "objArg", "TestObj", "objMethodWithArgs", "TestObj");
     JSValue result = toJS(state, castedThis->globalObject(), WTF::getPtr(impl.objMethodWithArgs(WTFMove(longArg), WTFMove(strArg), *objArg)));
     return JSValue::encode(result);
 }
@@ -4114,7 +4114,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMethodWithXPathNSResolver
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
     if (UNLIKELY(!resolver))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "resolver", "TestObj", "methodWithXPathNSResolverParameter", "XPathNSResolver");
     impl.methodWithXPathNSResolverParameter(*resolver);
     return JSValue::encode(jsUndefined());
 }
@@ -4250,7 +4250,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMethodThatRequiresAllArgs
         return JSValue::encode(jsUndefined());
     auto objArg = JSTestObj::toWrapped(state->argument(1));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 1, "objArg", "TestObj", "methodThatRequiresAllArgsAndThrows", "TestObj");
     JSValue result = toJS(state, castedThis->globalObject(), WTF::getPtr(impl.methodThatRequiresAllArgsAndThrows(WTFMove(strArg), *objArg, ec)));
 
     setDOMException(state, ec);
@@ -5277,7 +5277,7 @@ static inline EncodedJSValue jsTestObjPrototypeFunctionOverloadedMethod8(ExecSta
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto objArg = JSTestObj::toWrapped(state->argument(0));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "objArg", "TestObj", "overloadedMethod", "TestObj");
     impl.overloadedMethod(*objArg);
     return JSValue::encode(jsUndefined());
 }
@@ -5594,7 +5594,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionDomStringListFunction(Exe
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
     if (UNLIKELY(!values))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "values", "TestObj", "domStringListFunction", "DOMStringList");
     JSValue result = toJS(state, castedThis->globalObject(), WTF::getPtr(impl.domStringListFunction(*values, ec)));
 
     setDOMException(state, ec);
@@ -5687,7 +5687,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionConvert1(ExecState* state
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto value = JSTestNode::toWrapped(state->argument(0));
     if (UNLIKELY(!value))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "value", "TestObj", "convert1", "TestNode");
     impl.convert1(*value);
     return JSValue::encode(jsUndefined());
 }
@@ -5814,15 +5814,16 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunctionWithSequenc
     if (UNLIKELY(state->argumentCount() < 2))
         return throwVMError(state, createNotEnoughArgumentsError(state));
     ExceptionCode ec = 0;
-    if (UNLIKELY(!state->argument(0).isUndefinedOrNull() && !state->argument(0).inherits(JSTestObj::info())))
-        return throwArgumentTypeError(*state, 0, "objArg", "TestObj", "strictFunctionWithSequence", "TestObj");
-    auto objArg = JSTestObj::toWrapped(state->argument(0));
-    if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+    TestObj* objArg = nullptr;
+    if (!state->argument(0).isUndefinedOrNull()) {
+        objArg = JSTestObj::toWrapped(state->uncheckedArgument(0));
+        if (UNLIKELY(!objArg))
+            return throwArgumentTypeError(*state, 0, "objArg", "TestObj", "strictFunctionWithSequence", "TestObj");
+    }
     auto a = toNativeArray<uint32_t>(state, state->argument(1));
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
-    JSValue result = jsBoolean(impl.strictFunctionWithSequence(*objArg, WTFMove(a), ec));
+    JSValue result = jsBoolean(impl.strictFunctionWithSequence(objArg, WTFMove(a), ec));
 
     setDOMException(state, ec);
     return JSValue::encode(result);
@@ -5839,11 +5840,9 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunctionWithArray(E
     if (UNLIKELY(state->argumentCount() < 2))
         return throwVMError(state, createNotEnoughArgumentsError(state));
     ExceptionCode ec = 0;
-    if (UNLIKELY(!state->argument(0).isUndefinedOrNull() && !state->argument(0).inherits(JSTestObj::info())))
-        return throwArgumentTypeError(*state, 0, "objArg", "TestObj", "strictFunctionWithArray", "TestObj");
     auto objArg = JSTestObj::toWrapped(state->argument(0));
     if (UNLIKELY(!objArg))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "objArg", "TestObj", "strictFunctionWithArray", "TestObj");
     auto array = toNativeArray<int32_t>(state, state->argument(1));
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
@@ -5905,7 +5904,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicNodeMethod(ExecSt
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto head = JSNode::toWrapped(state->argument(0));
     if (UNLIKELY(!head))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "head", "TestObj", "variadicNodeMethod", "Node");
     Vector<Node*> tail;
     for (unsigned i = 1, count = state->argumentCount(); i < count; ++i) {
         if (!state->uncheckedArgument(i).inherits(JSNode::info()))
@@ -6059,7 +6058,7 @@ static inline EncodedJSValue jsTestObjPrototypeFunctionTestPromiseOverloadedFunc
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto request = JSFetchRequest::toWrapped(state->argument(0));
     if (UNLIKELY(!request))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "request", "TestObj", "testPromiseOverloadedFunction", "FetchRequest");
     impl.testPromiseOverloadedFunction(*request, DeferredWrapper(state, castedThis->globalObject(), promiseDeferred));
     return JSValue::encode(jsUndefined());
 }
index 0876f85..2356e87 100644 (file)
@@ -74,7 +74,7 @@ static inline EncodedJSValue constructJSTestOverloadedConstructors1(ExecState* s
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
     if (UNLIKELY(!arrayBuffer))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "arrayBuffer", "TestOverloadedConstructors", nullptr, "ArrayBuffer");
     RefPtr<TestOverloadedConstructors> object = TestOverloadedConstructors::create(*arrayBuffer);
     return JSValue::encode(asObject(toJS(state, castedThis->globalObject(), object.get())));
 }
@@ -88,7 +88,7 @@ static inline EncodedJSValue constructJSTestOverloadedConstructors2(ExecState* s
     if (UNLIKELY(state->hadException()))
         return JSValue::encode(jsUndefined());
     if (UNLIKELY(!arrayBufferView))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "arrayBufferView", "TestOverloadedConstructors", nullptr, "ArrayBufferView");
     RefPtr<TestOverloadedConstructors> object = TestOverloadedConstructors::create(*arrayBufferView);
     return JSValue::encode(asObject(toJS(state, castedThis->globalObject(), object.get())));
 }
@@ -100,7 +100,7 @@ static inline EncodedJSValue constructJSTestOverloadedConstructors3(ExecState* s
         return throwVMError(state, createNotEnoughArgumentsError(state));
     auto blob = JSBlob::toWrapped(state->argument(0));
     if (UNLIKELY(!blob))
-        return throwVMTypeError(state);
+        return throwArgumentTypeError(*state, 0, "blob", "TestOverloadedConstructors", nullptr, "Blob");
     RefPtr<TestOverloadedConstructors> object = TestOverloadedConstructors::create(*blob);
     return JSValue::encode(asObject(toJS(state, castedThis->globalObject(), object.get())));
 }
index 921a315..b5a119f 100644 (file)
@@ -313,7 +313,7 @@ enum TestConfidence { "high", "kinda-low" };
     [StrictTypeChecking] attribute unrestricted float strictFloat;
     [StrictTypeChecking, RaisesException] boolean strictFunction(DOMString str, unrestricted float a, long b);
 
-    [StrictTypeChecking, RaisesException] boolean strictFunctionWithSequence(TestObj objArg, sequence<unsigned long> a);
+    [StrictTypeChecking, RaisesException] boolean strictFunctionWithSequence(TestObj? objArg, sequence<unsigned long> a);
     [StrictTypeChecking, RaisesException] boolean strictFunctionWithArray(TestObj objArg, long[] array);
 
     // ObjectiveC reserved words.