Changeset 204500 in webkit


Ignore:
Timestamp:
Aug 15, 2016 11:50:58 PM (8 years ago)
Author:
rniwa@webkit.org
Message:

Conversion to sequence<T> is broken for iterable objects
https://bugs.webkit.org/show_bug.cgi?id=160801

Reviewed by Darin Adler.

Source/JavaScriptCore:

Export functions used to iterate over iterable objects.

  • runtime/IteratorOperations.h:

(JSC::forEachInIterable):

Source/WebCore:

Added the proper iterator support for sequence<T> with one caveat that we don't check for RegExp object
per https://github.com/heycam/webidl/issues/145.

See http://heycam.github.io/webidl/#es-sequence and http://heycam.github.io/webidl/#es-overloads

Tests: bindings/scripts/test/TestOverloadedConstructorsWithSequence.idl

  • bindings/js/JSDOMBinding.cpp:

(WebCore::hasIteratorMethod): Added. A helper function for checking whether a JSValue is iterable or not.

  • bindings/js/JSDOMBinding.h:

(WebCore::NativeValueTraits<unsigned>::nativeValue): Removed the check for isNumber to match the spec'ed
behavior at http://heycam.github.io/webidl/#es-unsigned-long which calls ToNumber first without checking
whether the value is a number or not.
(WebCore::toRefPtrNativeArray): Replaced isJSArray check by isObject check and throw a TypeError. Deployed
forEachInIterable to support non-JSArray iterable objects. Also removed the function pointer from the third
argument since we were always calling JSCT::toWrapped.
(WebCore::toNativeArray): Ditto.

  • bindings/js/JSDOMConvert.h:

(WebCore::Converter<Vector<T>>::convert): Removed the comment about toNativeArray not throwing when value
is not an object.

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateOverloadedFunctionOrConstructor): Removed the check for isJSArray for sequence<T> as an iterable
object is not necessary a JSArray.
(WillConvertUndefinedToDefaultParameterValue): Don't return 1 for all sequences since toNativeArray and
toRefPtrNativeArray now throws on undefined due to isObject check.
(JSValueToNative): Removed the third argument from toRefPtrNativeArray.

  • bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequence.cpp: Added.
  • bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequence.h: Added.
  • bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequencePrivate.h: Added.
  • bindings/scripts/test/JS/JSTestObj.cpp:

(WebCore::jsTestObjPrototypeFunctionMethodWithOptionalSequenceIsEmpty):

  • bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp: Added.
  • bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h: Added.
  • bindings/scripts/test/JS/JSTestTypedefs.cpp:

(WebCore::jsTestTypedefsPrototypeFunctionFunc):

  • bindings/scripts/test/TestOverloadedConstructorsWithSequence.idl: Added.

LayoutTests:

Added test cases for converting non-JSArray objects to sequence<T> for MutationObserver, FontFaceSet, and WebSocket.

  • fast/dom/MutationObserver/observe-exceptions-expected.txt:
  • fast/dom/MutationObserver/observe-exceptions.html:
  • fast/text/font-face-set-javascript-expected.txt:
  • fast/text/font-face-set-javascript.html:
  • http/tests/dom/window-open-about-webkit-org-and-access-document-expected.txt: Rebaselined due to js-test-pre.js change.
  • http/tests/resources/js-test-pre.js: Merged ToT from resources/js-test-pre.js.
  • http/tests/security/xssAuditor/block-does-not-leak-location-expected.txt: Rebaselined due to js-test-pre.js change.
  • http/tests/security/xssAuditor/block-does-not-leak-referrer-expected.txt: Ditto.
  • http/tests/websocket/tests/hybi/websocket-constructor-protocols-expected.txt: Added.
  • http/tests/websocket/tests/hybi/websocket-constructor-protocols.html: Added.
Location:
trunk
Files:
8 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r204492 r204500  
     12016-08-15  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Conversion to sequence<T> is broken for iterable objects
     4        https://bugs.webkit.org/show_bug.cgi?id=160801
     5
     6        Reviewed by Darin Adler.
     7
     8        Added test cases for converting non-JSArray objects to sequence<T> for MutationObserver, FontFaceSet, and WebSocket.
     9
     10        * fast/dom/MutationObserver/observe-exceptions-expected.txt:
     11        * fast/dom/MutationObserver/observe-exceptions.html:
     12        * fast/text/font-face-set-javascript-expected.txt:
     13        * fast/text/font-face-set-javascript.html:
     14        * http/tests/dom/window-open-about-webkit-org-and-access-document-expected.txt: Rebaselined due to js-test-pre.js change.
     15        * http/tests/resources/js-test-pre.js: Merged ToT from resources/js-test-pre.js.
     16        * http/tests/security/xssAuditor/block-does-not-leak-location-expected.txt: Rebaselined due to js-test-pre.js change.
     17        * http/tests/security/xssAuditor/block-does-not-leak-referrer-expected.txt: Ditto.
     18        * http/tests/websocket/tests/hybi/websocket-constructor-protocols-expected.txt: Added.
     19        * http/tests/websocket/tests/hybi/websocket-constructor-protocols.html: Added.
     20
    1212016-08-15  Daniel Bates  <dabates@apple.com>
    222
  • trunk/LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt

    r200583 r204500  
    1919PASS observer.observe(document.body, {attributes: false, attributeFilter: ["id"]}) threw exception TypeError: Type error.
    2020PASS observer.observe(document.body, {characterData: false, characterDataOldValue: true}) threw exception TypeError: Type error.
     21PASS observer.observe(document.body, {attributeFilter: 1}) threw exception TypeError: Value is not a sequence.
     22PASS observer.observe(document.body, {attributeFilter: "abc"}) threw exception TypeError: Value is not a sequence.
     23PASS x = { [Symbol.iterator]: function* () { yield "foo"; } }; observer.observe(document.body, {attributeFilter: x}) did not throw exception.
     24PASS x = { [Symbol.iterator]: 1 }; observer.observe(document.body, {attributeFilter: x}) threw exception TypeError: Type error.
     25PASS x = { [Symbol.iterator]: null }; observer.observe(document.body, {attributeFilter: x}) threw exception TypeError: Type error.
     26PASS x = { [Symbol.iterator]: function* () { throw {name: "error", toString: () => "error"}; } }; observer.observe(document.body, {attributeFilter: x}) threw exception error.
    2127PASS successfullyParsed is true
    2228
  • trunk/LayoutTests/fast/dom/MutationObserver/observe-exceptions.html

    r189271 r204500  
    77</head>
    88<body>
    9 <p id=description></p>
     9<p id="description"></p>
    1010<div id="console"></div>
    1111<script>
     
    1313function runTest() {
    1414    window.observer = new MutationObserver(function(mutations) { });
    15     shouldThrow('observer.observe()');
    16     shouldThrow('observer.observe(null)');
    17     shouldThrow('observer.observe(undefined)');
    18     shouldThrow('observer.observe(document.body)');
    19     shouldThrow('observer.observe(document.body, null)');
    20     shouldThrow('observer.observe(document.body, undefined)');
    21     shouldThrow('observer.observe(null, {attributes: true})');
    22     shouldThrow('observer.observe(undefined, {attributes: true})');
    23     shouldThrow('observer.observe(document.body, {subtree: true})');
     15    shouldThrowErrorName('observer.observe()', 'TypeError');
     16    shouldThrowErrorName('observer.observe(null)', 'TypeError');
     17    shouldThrowErrorName('observer.observe(undefined)', 'TypeError');
     18    shouldThrowErrorName('observer.observe(document.body)', 'TypeError');
     19    shouldThrowErrorName('observer.observe(document.body, null)', 'TypeError');
     20    shouldThrowErrorName('observer.observe(document.body, undefined)', 'TypeError');
     21    shouldThrowErrorName('observer.observe(null, {attributes: true})', 'TypeError');
     22    shouldThrowErrorName('observer.observe(undefined, {attributes: true})', 'TypeError');
     23    shouldThrowErrorName('observer.observe(document.body, {subtree: true})', 'TypeError');
    2424    shouldNotThrow('observer.observe(document.body, {childList: true, attributeOldValue: true})');
    2525    shouldNotThrow('observer.observe(document.body, {attributes: true, characterDataOldValue: true})');
    2626    shouldNotThrow('observer.observe(document.body, {characterData: true, attributeFilter: ["id"]})');
    2727
    28     shouldThrow('observer.observe(document.body, {attributes: false, attributeOldValue: true})');
    29     shouldThrow('observer.observe(document.body, {attributes: false, attributeFilter: ["id"]})');
    30     shouldThrow('observer.observe(document.body, {characterData: false, characterDataOldValue: true})');
     28    shouldThrowErrorName('observer.observe(document.body, {attributes: false, attributeOldValue: true})', 'TypeError');
     29    shouldThrowErrorName('observer.observe(document.body, {attributes: false, attributeFilter: ["id"]})', 'TypeError');
     30    shouldThrowErrorName('observer.observe(document.body, {characterData: false, characterDataOldValue: true})', 'TypeError');
     31
     32    shouldThrowErrorName('observer.observe(document.body, {attributeFilter: 1})', 'TypeError');
     33    shouldThrowErrorName('observer.observe(document.body, {attributeFilter: "abc"})', 'TypeError');
     34    shouldNotThrow('x = { [Symbol.iterator]: function* () { yield "foo"; } }; observer.observe(document.body, {attributeFilter: x})');
     35    shouldThrowErrorName('x = { [Symbol.iterator]: 1 }; observer.observe(document.body, {attributeFilter: x})', 'TypeError');
     36    shouldThrowErrorName('x = { [Symbol.iterator]: null }; observer.observe(document.body, {attributeFilter: x})', 'TypeError');
     37    shouldThrowErrorName('x = { [Symbol.iterator]: function* () { throw {name: "error", toString: () => "error"}; } }; '
     38        + 'observer.observe(document.body, {attributeFilter: x})', 'error');
    3139}
    3240
  • trunk/LayoutTests/fast/text/font-face-set-javascript-expected.txt

    r203333 r204500  
    22PASS new FontFaceSet([]).size is 0
    33PASS new FontFaceSet([fontFace1]).size is 1
     4PASS new FontFaceSet(1) threw exception TypeError: Value is not a sequence.
     5PASS new FontFaceSet('hello') threw exception TypeError: Value is not a sequence.
     6PASS new FontFaceSet(new Set([fontFace1])).size is 1
     7PASS x = { [Symbol.iterator]: function*() { yield fontFace1; yield fontFace2; } }; new FontFaceSet(x).size is 2
     8PASS x = { [Symbol.iterator]: 1 }; new FontFaceSet(x) threw exception TypeError: Type error.
     9PASS x = { [Symbol.iterator]: null }; new FontFaceSet(x) threw exception TypeError: Type error.
     10PASS x = { [Symbol.iterator]: function*() { yield fontFace1; throw {name: 'SomeError', toString: () => 'Some error'}; } }; new FontFaceSet(x) threw exception Some error.
    411PASS fontFaceSet.status is "loaded"
    512PASS item.done is false
  • trunk/LayoutTests/fast/text/font-face-set-javascript.html

    r203234 r204500  
    1717shouldBe("new FontFaceSet([]).size", "0");
    1818shouldBe("new FontFaceSet([fontFace1]).size", "1");
     19shouldThrowErrorName("new FontFaceSet(1)", "TypeError");
     20shouldThrowErrorName("new FontFaceSet('hello')", "TypeError");
     21shouldBe("new FontFaceSet(new Set([fontFace1])).size", "1");
     22shouldBe("x = { [Symbol.iterator]: function*() { yield fontFace1; yield fontFace2; } }; new FontFaceSet(x).size", "2");
     23shouldThrowErrorName("x = { [Symbol.iterator]: 1 }; new FontFaceSet(x)", "TypeError");
     24shouldThrowErrorName("x = { [Symbol.iterator]: null }; new FontFaceSet(x)", "TypeError");
     25shouldThrowErrorName("x = { [Symbol.iterator]: function*() { yield fontFace1; throw {name: 'SomeError', toString: () => 'Some error'}; } }; new FontFaceSet(x)", "SomeError");
    1926
    2027var fontFaceSet = new FontFaceSet([]);
  • trunk/LayoutTests/http/tests/dom/window-open-about-webkit-org-and-access-document-expected.txt

    r202428 r204500  
    11CONSOLE MESSAGE: line 34: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "null".  The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "about". Protocols must match.
    22
    3 CONSOLE MESSAGE: line 347: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "null".  The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "about". Protocols must match.
     3CONSOLE MESSAGE: line 526: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "null".  The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "about". Protocols must match.
    44
    55PASS newWindow.document is undefined.
  • trunk/LayoutTests/http/tests/resources/js-test-pre.js

    r178310 r204500  
    33    testRunner.dumpAsText(self.enablePixelTesting);
    44
    5 var description, debug, successfullyParsed, errorMessage;
     5var description, debug, successfullyParsed, errorMessage, silentTestPass, didPassSomeTestsSilently, didFailSomeTests;
     6
     7silentTestPass = false;
     8didPassSomeTestsSilently = false;
     9didFailSomeTests = false;
    610
    711(function() {
     12
     13    function createHTMLElement(tagName)
     14    {
     15        // FIXME: In an XML document, document.createElement() creates an element with a null namespace URI.
     16        // So, we need use document.createElementNS() to explicitly create an element with the specified
     17        // tag name in the HTML namespace. We can remove this function and use document.createElement()
     18        // directly once we fix <https://bugs.webkit.org/show_bug.cgi?id=131074>.
     19        if (document.createElementNS)
     20            return document.createElementNS("http://www.w3.org/1999/xhtml", tagName);
     21        return document.createElement(tagName);
     22    }
    823
    924    function getOrCreate(id, tagName)
     
    1328            return element;
    1429
    15         element = document.createElement(tagName);
     30        element = createHTMLElement(tagName);
    1631        element.id = id;
    1732        var refNode;
     
    2944    {
    3045        // For MSIE 6 compatibility
    31         var span = document.createElement("span");
     46        var span = createHTMLElement("span");
    3247        if (quiet)
    3348            span.innerHTML = '<p>' + msg + '</p><p>On success, you will see no "<span class="fail">FAIL</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
     
    4459    debug = function debug(msg)
    4560    {
    46         var span = document.createElement("span");
     61        var span = createHTMLElement("span");
    4762        getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
    4863        span.innerHTML = msg + '<br />';
     
    6580    function insertStyleSheet()
    6681    {
    67         var styleElement = document.createElement("style");
     82        var styleElement = createHTMLElement("style");
    6883        styleElement.textContent = css;
    6984        (document.head || document.documentElement).appendChild(styleElement);
     
    97112function testPassed(msg)
    98113{
    99     debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
     114    if (silentTestPass)
     115        didPassSomeTestsSilently = true;
     116    else
     117        debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
    100118}
    101119
    102120function testFailed(msg)
    103121{
     122    didFailSomeTests = true;
    104123    debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
    105124}
    106125
    107 function areArraysEqual(_a, _b)
    108 {
    109     try {
    110         if (_a.length !== _b.length)
    111             return false;
    112         for (var i = 0; i < _a.length; i++)
    113             if (_a[i] !== _b[i])
    114                 return false;
    115     } catch (ex) {
    116         return false;
    117     }
    118     return true;
    119 }
    120 
    121 function isMinusZero(n)
    122 {
    123     // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
    124     // -Infinity instead of Infinity
    125     return n === 0 && 1/n < 0;
    126 }
    127 
    128 function isResultCorrect(_actual, _expected)
     126function areNumbersEqual(_actual, _expected)
    129127{
    130128    if (_expected === 0)
     
    134132    if (typeof(_expected) == "number" && isNaN(_expected))
    135133        return typeof(_actual) == "number" && isNaN(_actual);
    136     if (_expected && (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([])))
     134    return false;
     135}
     136
     137function areArraysEqual(_a, _b)
     138{
     139    try {
     140        if (_a.length !== _b.length)
     141            return false;
     142        for (var i = 0; i < _a.length; i++)
     143            if (!areNumbersEqual(_a[i], _b[i]))
     144                return false;
     145    } catch (ex) {
     146        return false;
     147    }
     148    return true;
     149}
     150
     151function isMinusZero(n)
     152{
     153    // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
     154    // -Infinity instead of Infinity
     155    return n === 0 && 1/n < 0;
     156}
     157
     158function isTypedArray(array)
     159{
     160    return array instanceof Int8Array
     161        || array instanceof Int16Array
     162        || array instanceof Int32Array
     163        || array instanceof Uint8Array
     164        || array instanceof Uint8ClampedArray
     165        || array instanceof Uint16Array
     166        || array instanceof Uint32Array
     167        || array instanceof Float32Array
     168        || array instanceof Float64Array;
     169}
     170
     171function isResultCorrect(_actual, _expected)
     172{
     173    if (areNumbersEqual(_actual, _expected))
     174        return true;
     175    if (_expected
     176        && (Object.prototype.toString.call(_expected) ==
     177            Object.prototype.toString.call([])
     178            || isTypedArray(_expected)))
    137179        return areArraysEqual(_actual, _expected);
    138180    return false;
     
    143185    if (v === 0 && 1/v < 0)
    144186        return "-0";
    145     else return "" + v;
    146 }
    147 
    148 function evalAndLog(_a)
     187    else if (isTypedArray(v))
     188        return v.__proto__.constructor.name + ":[" + Array.prototype.join.call(v, ",") + "]";
     189    else
     190        return "" + v;
     191}
     192
     193function evalAndLog(_a, _quiet)
    149194{
    150195  if (typeof _a != "string")
     
    152197
    153198  // Log first in case things go horribly wrong or this causes a sync event.
    154   debug(_a);
     199  if (!_quiet)
     200    debug(_a);
    155201
    156202  var _av;
     
    177223
    178224  if (exception)
    179     testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
     225    testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + exception);
    180226  else if (isResultCorrect(_av, _bv)) {
    181227    if (!quiet) {
     
    183229    }
    184230  } else if (typeof(_av) == typeof(_bv))
    185     testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
     231    testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + ".");
    186232  else
    187     testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
     233    testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
     234}
     235
     236function dfgShouldBe(theFunction, _a, _b)
     237{
     238  if (typeof theFunction != "function" || typeof _a != "string" || typeof _b != "string")
     239    debug("WARN: dfgShouldBe() expects a function and two strings");
     240  noInline(theFunction);
     241  var exception;
     242  var values = [];
     243
     244  // Defend against tests that muck with numeric properties on array.prototype.
     245  values.__proto__ = null;
     246  values.push = Array.prototype.push;
     247 
     248  try {
     249    while (!dfgCompiled({f:theFunction}))
     250      values.push(eval(_a));
     251    values.push(eval(_a));
     252  } catch (e) {
     253    exception = e;
     254  }
     255
     256  var _bv = eval(_b);
     257  if (exception)
     258    testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (values.length + 1) + ", threw exception " + exception);
     259  else {
     260    var allPassed = true;
     261    for (var i = 0; i < values.length; ++i) {
     262      var _av = values[i];
     263      if (isResultCorrect(_av, _bv))
     264        continue;
     265      if (typeof(_av) == typeof(_bv))
     266        testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (i + 1) + ", was " + stringify(_av) + ".");
     267      else
     268        testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). On iteration " + (i + 1) + ", was " + _av + " (of type " + typeof _av + ").");
     269      allPassed = false;
     270    }
     271    if (allPassed)
     272      testPassed(_a + " is " + _b + " on all iterations including after DFG tier-up.");
     273  }
     274 
     275  return values.length;
     276}
     277
     278// Execute condition every 5 milliseconds until it succeeds.
     279function _waitForCondition(condition, completionHandler)
     280{
     281  if (condition())
     282    completionHandler();
     283  else
     284    setTimeout(_waitForCondition, 5, condition, completionHandler);
     285}
     286
     287function shouldBecomeEqual(_a, _b, completionHandler)
     288{
     289  if (typeof _a != "string" || typeof _b != "string")
     290    debug("WARN: shouldBecomeEqual() expects string arguments");
     291
     292  function condition() {
     293    var exception;
     294    var _av;
     295    try {
     296      _av = eval(_a);
     297    } catch (e) {
     298      exception = e;
     299    }
     300    var _bv = eval(_b);
     301    if (exception)
     302      testFailed(_a + " should become " + _bv + ". Threw exception " + exception);
     303    if (isResultCorrect(_av, _bv)) {
     304      testPassed(_a + " became " + _b);
     305      return true;
     306    }
     307    return false;
     308  }
     309  setTimeout(_waitForCondition, 0, condition, completionHandler);
     310}
     311
     312function shouldBecomeEqualToString(value, reference, completionHandler)
     313{
     314  if (typeof value !== "string" || typeof reference !== "string")
     315    debug("WARN: shouldBecomeEqualToString() expects string arguments");
     316  var unevaledString = JSON.stringify(reference);
     317  shouldBecomeEqual(value, unevaledString, completionHandler);
     318}
     319
     320function shouldBeType(_a, _type) {
     321  var exception;
     322  var _av;
     323  try {
     324    _av = eval(_a);
     325  } catch (e) {
     326    exception = e;
     327  }
     328
     329  var _typev = eval(_type);
     330  if (_av instanceof _typev) {
     331    testPassed(_a + " is an instance of " + _type);
     332  } else {
     333    testFailed(_a + " is not an instance of " + _type);
     334  }
    188335}
    189336
     
    250397}
    251398
     399function shouldBecomeDifferent(_a, _b, completionHandler)
     400{
     401  if (typeof _a != "string" || typeof _b != "string")
     402    debug("WARN: shouldBecomeDifferent() expects string arguments");
     403
     404  function condition() {
     405    var exception;
     406    var _av;
     407    try {
     408      _av = eval(_a);
     409    } catch (e) {
     410      exception = e;
     411    }
     412    var _bv = eval(_b);
     413    if (exception)
     414      testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + exception);
     415    if (!isResultCorrect(_av, _bv)) {
     416      testPassed(_a + " became different from " + _b);
     417      return true;
     418    }
     419    return false;
     420  }
     421  setTimeout(_waitForCondition, 0, condition, completionHandler);
     422}
     423
    252424function shouldBeTrue(_a) { shouldBe(_a, "true"); }
    253425function shouldBeTrueQuiet(_a) { shouldBe(_a, "true", true); }
     
    265437}
    266438
     439function shouldNotBeEqualToString(a, b)
     440{
     441  if (typeof a !== "string" || typeof b !== "string")
     442    debug("WARN: shouldBeEqualToString() expects string arguments");
     443  var unevaledString = JSON.stringify(b);
     444  shouldNotBe(a, unevaledString);
     445}
    267446function shouldBeEmptyString(_a) { shouldBeEqualToString(_a, ""); }
    268447
     
    397576}
    398577
    399 function shouldNotThrow(_a) {
     578function expectTrue(v, msg) {
     579  if (v) {
     580    testPassed(msg);
     581  } else {
     582    testFailed(msg);
     583  }
     584}
     585
     586function shouldNotThrow(_a, _message) {
    400587    try {
    401         eval(_a);
    402         testPassed(_a + " did not throw exception.");
     588        typeof _a == "function" ? _a() : eval(_a);
     589        testPassed((_message ? _message : _a) + " did not throw exception.");
    403590    } catch (e) {
    404         testFailed(_a + " should not throw exception. Threw exception " + e + ".");
    405     }
    406 }
    407 
    408 function shouldThrow(_a, _e)
    409 {
    410   var exception;
    411   var _av;
    412   try {
    413      _av = eval(_a);
    414   } catch (e) {
    415      exception = e;
    416   }
    417 
    418   var _ev;
    419   if (_e)
    420       _ev =  eval(_e);
    421 
    422   if (exception) {
    423     if (typeof _e == "undefined" || exception == _ev)
    424       testPassed(_a + " threw exception " + exception + ".");
     591        testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
     592    }
     593}
     594
     595function shouldThrow(_a, _e, _message)
     596{
     597    var _exception;
     598    var _av;
     599    try {
     600        _av = typeof _a == "function" ? _a() : eval(_a);
     601    } catch (e) {
     602        _exception = e;
     603    }
     604
     605    var _ev;
     606    if (_e)
     607        _ev = eval(_e);
     608
     609    if (_exception) {
     610        if (typeof _e == "undefined" || _exception == _ev)
     611            testPassed((_message ? _message : _a) + " threw exception " + _exception + ".");
     612        else
     613            testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + ".");
     614    } else if (typeof _av == "undefined")
     615        testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
    425616    else
    426       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
    427   } else if (typeof _av == "undefined")
    428     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
    429   else
    430     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
     617        testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
     618}
     619
     620function shouldThrowErrorName(_a, _name)
     621{
     622    var _exception;
     623    try {
     624        typeof _a == "function" ? _a() : eval(_a);
     625    } catch (e) {
     626        _exception = e;
     627    }
     628
     629    if (_exception) {
     630        if (_exception.name == _name)
     631            testPassed(_a + " threw exception " + _exception + ".");
     632        else
     633            testFailed(_a + " should throw a " + _name + ". Threw a " + _exception.name + ".");
     634    } else
     635        testFailed(_a + " should throw a " + _name + ". Did not throw.");
    431636}
    432637
     
    461666}
    462667
     668function dfgCompiled(argument)
     669{
     670    var numberOfCompiles = "compiles" in argument ? argument.compiles : 1;
     671   
     672    if (!("f" in argument))
     673        throw new Error("dfgCompiled called with invalid argument.");
     674   
     675    if (argument.f instanceof Array) {
     676        for (var i = 0; i < argument.f.length; ++i) {
     677            if (testRunner.numberOfDFGCompiles(argument.f[i]) < numberOfCompiles)
     678                return false;
     679        }
     680    } else {
     681        if (testRunner.numberOfDFGCompiles(argument.f) < numberOfCompiles)
     682            return false;
     683    }
     684   
     685    return true;
     686}
     687
     688function dfgIncrement(argument)
     689{
     690    if (!self.testRunner)
     691        return argument.i;
     692   
     693    if (argument.i < argument.n)
     694        return argument.i;
     695   
     696    if (didFailSomeTests)
     697        return argument.i;
     698   
     699    if (!dfgCompiled(argument))
     700        return "start" in argument ? argument.start : 0;
     701   
     702    return argument.i;
     703}
     704
     705function noInline(theFunction)
     706{
     707    if (!self.testRunner)
     708        return;
     709   
     710    testRunner.neverInlineFunction(theFunction);
     711}
     712
    463713function isSuccessfullyParsed()
    464714{
     
    467717        successfullyParsed = true;
    468718    shouldBeTrue("successfullyParsed");
     719    if (silentTestPass && didPassSomeTestsSilently)
     720        debug("Passed some tests silently.");
     721    if (silentTestPass && didFailSomeTests)
     722        debug("Some tests failed.");
    469723    debug('<br /><span class="pass">TEST COMPLETE</span>');
    470724}
  • trunk/LayoutTests/http/tests/security/xssAuditor/block-does-not-leak-location-expected.txt

    r194927 r204500  
    11CONSOLE MESSAGE: line 7: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?test=/security/xssAuditor/block-does-not-leak-location.html&enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53));%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
    2 CONSOLE MESSAGE: line 172: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    3 CONSOLE MESSAGE: line 172: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    4 CONSOLE MESSAGE: line 176: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    5 CONSOLE MESSAGE: line 347: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    6 CONSOLE MESSAGE: line 172: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    7 CONSOLE MESSAGE: line 176: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     2CONSOLE MESSAGE: line 218: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     3CONSOLE MESSAGE: line 218: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     4CONSOLE MESSAGE: line 222: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     5CONSOLE MESSAGE: line 526: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     6CONSOLE MESSAGE: line 218: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     7CONSOLE MESSAGE: line 222: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    88PASS xssed.contentDocument is null
    99PASS xssed.contentDocument is crossorigin.contentDocument
  • trunk/LayoutTests/http/tests/security/xssAuditor/block-does-not-leak-referrer-expected.txt

    r194927 r204500  
    11CONSOLE MESSAGE: line 4: The XSS Auditor blocked access to 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?enable-full-block=1&q=%3Cscript%3Ealert(String.fromCharCode(0x58,0x53,0x53))%3C/script%3E' because the source code of a script was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
    2 CONSOLE MESSAGE: line 172: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
     2CONSOLE MESSAGE: line 218: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
    33PASS frame.contentDocument is null
    44PASS successfullyParsed is true
  • trunk/Source/JavaScriptCore/ChangeLog

    r204495 r204500  
     12016-08-15  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Conversion to sequence<T> is broken for iterable objects
     4        https://bugs.webkit.org/show_bug.cgi?id=160801
     5
     6        Reviewed by Darin Adler.
     7
     8        Export functions used to iterate over iterable objects.
     9
     10        * runtime/IteratorOperations.h:
     11        (JSC::forEachInIterable):
     12
    1132016-08-15  Benjamin Poulain  <bpoulain@apple.com>
    214
  • trunk/Source/JavaScriptCore/runtime/IteratorOperations.h

    r204438 r204500  
    3434JSValue iteratorNext(ExecState*, JSValue iterator, JSValue);
    3535JSValue iteratorNext(ExecState*, JSValue iterator);
    36 JSValue iteratorValue(ExecState*, JSValue iterator);
     36JS_EXPORT_PRIVATE JSValue iteratorValue(ExecState*, JSValue iterator);
    3737bool iteratorComplete(ExecState*, JSValue iterator);
    38 JSValue iteratorStep(ExecState*, JSValue iterator);
    39 void iteratorClose(ExecState*, JSValue iterator);
     38JS_EXPORT_PRIVATE JSValue iteratorStep(ExecState*, JSValue iterator);
     39JS_EXPORT_PRIVATE void iteratorClose(ExecState*, JSValue iterator);
    4040JS_EXPORT_PRIVATE JSObject* createIteratorResultObject(ExecState*, JSValue, bool done);
    4141
    4242Structure* createIteratorResultObjectStructure(VM&, JSGlobalObject&);
    4343
    44 JSValue iteratorForIterable(ExecState*, JSValue iterable);
     44JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState*, JSValue iterable);
    4545
    4646template <typename CallBackType>
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r203957 r204500  
    774774    }
    775775
    776     JSValue getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage);
     776    JS_EXPORT_PRIVATE JSValue getMethod(ExecState*, CallData&, CallType&, const Identifier&, const String& errorMessage);
    777777
    778778    DECLARE_EXPORT_INFO;
  • trunk/Source/WebCore/ChangeLog

    r204499 r204500  
     12016-08-15  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Conversion to sequence<T> is broken for iterable objects
     4        https://bugs.webkit.org/show_bug.cgi?id=160801
     5
     6        Reviewed by Darin Adler.
     7
     8        Added the proper iterator support for sequence<T> with one caveat that we don't check for RegExp object
     9        per https://github.com/heycam/webidl/issues/145.
     10
     11        See http://heycam.github.io/webidl/#es-sequence and http://heycam.github.io/webidl/#es-overloads
     12
     13        Tests: bindings/scripts/test/TestOverloadedConstructorsWithSequence.idl
     14
     15        * bindings/js/JSDOMBinding.cpp:
     16        (WebCore::hasIteratorMethod): Added. A helper function for checking whether a JSValue is iterable or not.
     17        * bindings/js/JSDOMBinding.h:
     18        (WebCore::NativeValueTraits<unsigned>::nativeValue): Removed the check for isNumber to match the spec'ed
     19        behavior at http://heycam.github.io/webidl/#es-unsigned-long which calls ToNumber first without checking
     20        whether the value is a number or not.
     21        (WebCore::toRefPtrNativeArray): Replaced isJSArray check by isObject check and throw a TypeError. Deployed
     22        forEachInIterable to support non-JSArray iterable objects. Also removed the function pointer from the third
     23        argument since we were always calling JSCT::toWrapped.
     24        (WebCore::toNativeArray): Ditto.
     25        * bindings/js/JSDOMConvert.h:
     26        (WebCore::Converter<Vector<T>>::convert): Removed the comment about toNativeArray not throwing when value
     27        is not an object.
     28        * bindings/scripts/CodeGeneratorJS.pm:
     29        (GenerateOverloadedFunctionOrConstructor): Removed the check for isJSArray for sequence<T> as an iterable
     30        object is not necessary a JSArray.
     31        (WillConvertUndefinedToDefaultParameterValue): Don't return 1 for all sequences since toNativeArray and
     32        toRefPtrNativeArray now throws on undefined due to isObject check.
     33        (JSValueToNative): Removed the third argument from toRefPtrNativeArray.
     34
     35        * bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequence.cpp: Added.
     36        * bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequence.h: Added.
     37        * bindings/scripts/test/GObject/WebKitDOMTestOverloadedConstructorsWithSequencePrivate.h: Added.
     38        * bindings/scripts/test/JS/JSTestObj.cpp:
     39        (WebCore::jsTestObjPrototypeFunctionMethodWithOptionalSequenceIsEmpty):
     40        * bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp: Added.
     41        * bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h: Added.
     42        * bindings/scripts/test/JS/JSTestTypedefs.cpp:
     43        (WebCore::jsTestTypedefsPrototypeFunctionFunc):
     44        * bindings/scripts/test/TestOverloadedConstructorsWithSequence.idl: Added.
     45
    1462016-08-15  Chris Dumez  <cdumez@apple.com>
    247
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp

    r204228 r204500  
    366366#undef TRY_TO_CREATE_EXCEPTION
    367367
     368bool hasIteratorMethod(JSC::ExecState& state, JSC::JSValue value)
     369{
     370    if (!value.isObject())
     371        return false;
     372
     373    auto& vm = state.vm();
     374    JSObject* object = JSC::asObject(value);
     375    CallData callData;
     376    CallType callType;
     377    JSValue applyMethod = object->getMethod(&state, callData, callType, vm.propertyNames->iteratorSymbol, ASCIILiteral("Symbol.iterator property should be callable"));
     378    if (vm.exception())
     379        return false;
     380
     381    return !applyMethod.isUndefined();
     382}
     383
    368384bool shouldAllowAccessToNode(ExecState* exec, Node* node)
    369385{
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.h

    r204215 r204500  
    286286RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue);
    287287
    288 template<typename T, typename JSType> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState*, JSC::JSValue, T* (*)(JSC::JSValue));
     288template<typename T, typename JSType> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState*, JSC::JSValue);
    289289template<typename T> Vector<T> toNativeArray(JSC::ExecState&, JSC::JSValue);
    290290template<typename T> Vector<T> toNativeArguments(JSC::ExecState&, size_t startIndex = 0);
     291bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
    291292
    292293bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
     
    675676    static inline bool nativeValue(JSC::ExecState& exec, JSC::JSValue jsValue, unsigned& indexedValue)
    676677    {
    677         if (!jsValue.isNumber())
    678             return false;
    679 
    680678        indexedValue = jsValue.toUInt32(&exec);
    681         if (exec.hadException())
    682             return false;
    683 
    684         return true;
     679        return !exec.hadException();
    685680    }
    686681};
     
    702697};
    703698
    704 template<typename T, typename JST> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value))
    705 {
    706     if (!isJSArray(value))
     699template<typename T, typename JST> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState& exec, JSC::JSValue value)
     700{
     701    if (!value.isObject()) {
     702        throwSequenceTypeError(exec);
    707703        return Vector<RefPtr<T>>();
     704    }
    708705
    709706    Vector<RefPtr<T>> result;
    710     JSC::JSArray* array = asArray(value);
    711     size_t size = array->length();
    712     result.reserveInitialCapacity(size);
    713     for (size_t i = 0; i < size; ++i) {
    714         JSC::JSValue element = array->getIndex(exec, i);
    715         if (element.inherits(JST::info()))
    716             result.uncheckedAppend((*toT)(element));
    717         else {
    718             throwArrayElementTypeError(*exec);
    719             return Vector<RefPtr<T>>();
    720         }
    721     }
     707    forEachInIterable(&exec, value, [&result](JSC::VM&, JSC::ExecState* state, JSC::JSValue jsValue) {
     708        if (jsValue.inherits(JST::info()))
     709            result.append(JST::toWrapped(jsValue));
     710        else
     711            throwArrayElementTypeError(*state);
     712    });
    722713    return result;
    723714}
     
    725716template<typename T> Vector<T> toNativeArray(JSC::ExecState& exec, JSC::JSValue value)
    726717{
    727     JSC::JSObject* object = value.getObject();
    728     if (!object)
     718    if (!value.isObject()) {
     719        throwSequenceTypeError(exec);
    729720        return Vector<T>();
    730 
    731     unsigned length = 0;
    732     if (isJSArray(value)) {
    733         JSC::JSArray* array = asArray(value);
    734         length = array->length();
    735     } else
    736         toJSSequence(exec, value, length);
     721    }
    737722
    738723    Vector<T> result;
    739     result.reserveInitialCapacity(length);
    740     typedef NativeValueTraits<T> TraitsType;
    741 
    742     for (unsigned i = 0; i < length; ++i) {
    743         T indexValue;
    744         if (!TraitsType::nativeValue(exec, object->get(&exec, i), indexValue))
    745             return Vector<T>();
    746         result.uncheckedAppend(indexValue);
    747     }
     724    forEachInIterable(&exec, value, [&result](JSC::VM&, JSC::ExecState* state, JSC::JSValue jsValue) {
     725        T convertedValue;
     726        if (!NativeValueTraits<T>::nativeValue(*state, jsValue, convertedValue))
     727            return;
     728        ASSERT(!state->hadException());
     729        result.append(convertedValue);
     730    });
    748731    return result;
    749732}
  • trunk/Source/WebCore/bindings/js/JSDOMConvert.h

    r204497 r204500  
    143143    static Vector<T> convert(JSC::ExecState& state, JSC::JSValue value)
    144144    {
    145         // FIXME: The toNativeArray function doesn't throw a type error if the value is not an object. Is that OK?
    146145        return toNativeArray<T>(state, value);
    147146    }
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r204497 r204500  
    19251925            &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isFunction()");
    19261926
     1927            # FIXME: Avoid invoking GetMethod(object, Symbol.iterator) again in toNativeArray and toRefPtrNativeArray.
    19271928            $overload = GetOverloadThatMatches($S, $d, \&$isSequenceParameter);
    1928             &$generateOverloadCallIfNecessary($overload, "distinguishingArg.isObject() && isJSArray(distinguishingArg)");
     1929            &$generateOverloadCallIfNecessary($overload, "hasIteratorMethod(*state, distinguishingArg)");
    19291930
    19301931            $overload = GetOverloadThatMatches($S, $d, \&$isDictionaryOrObjectOrCallbackInterfaceParameter);
     
    37823783    return 1 if defined $automaticallyGeneratedDefaultValue && $automaticallyGeneratedDefaultValue eq $defaultValue;
    37833784
    3784     # toRefPtrNativeArray() will convert undefined to an empty Vector.
    3785     return 1 if $defaultValue eq "[]" && $codeGenerator->GetSequenceType($parameterType);
    3786 
    37873785    return 1 if $defaultValue eq "null" && $codeGenerator->IsWrapperType($parameterType);
    37883786
     
    46684666        if ($codeGenerator->IsRefPtrType($sequenceType)) {
    46694667            AddToImplIncludes("JS${sequenceType}.h");
    4670             return ("(toRefPtrNativeArray<${sequenceType}, JS${sequenceType}>(state, $value, &JS${sequenceType}::toWrapped))", 1);
     4668            return ("toRefPtrNativeArray<${sequenceType}, JS${sequenceType}>(*state, $value)", 1);
    46714669        }
    46724670        return ("toNativeArray<" . GetNativeVectorInnerType($sequenceType) . ">(*state, $value)", 1);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp

    r204497 r204500  
    51735173    ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
    51745174    auto& impl = castedThis->wrapped();
    5175     auto array = toNativeArray<String>(*state, state->argument(0));
     5175    auto array = state->argument(0).isUndefined() ? Vector<String>() : toNativeArray<String>(*state, state->uncheckedArgument(0));
    51765176    if (UNLIKELY(state->hadException()))
    51775177        return JSValue::encode(jsUndefined());
     
    57025702        if (distinguishingArg.isObject() && asObject(distinguishingArg)->inherits(JSBlob::info()))
    57035703            return jsTestObjPrototypeFunctionOverloadedMethod12(state);
    5704         if (distinguishingArg.isObject() && isJSArray(distinguishingArg))
     5704        if (hasIteratorMethod(*state, distinguishingArg))
    57055705            return jsTestObjPrototypeFunctionOverloadedMethod7(state);
    57065706        if (distinguishingArg.isObject() && asObject(distinguishingArg)->type() != RegExpObjectType)
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp

    r204497 r204500  
    454454    ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestTypedefs::info());
    455455    auto& impl = castedThis->wrapped();
    456     auto x = toNativeArray<int32_t>(*state, state->argument(0));
     456    auto x = state->argument(0).isUndefined() ? Vector<int32_t>() : toNativeArray<int32_t>(*state, state->uncheckedArgument(0));
    457457    if (UNLIKELY(state->hadException()))
    458458        return JSValue::encode(jsUndefined());
     
    500500    if (UNLIKELY(state->argumentCount() < 1))
    501501        return throwVMError(state, createNotEnoughArgumentsError(state));
    502     auto sequenceArg = (toRefPtrNativeArray<SerializedScriptValue, JSSerializedScriptValue>(state, state->argument(0), &JSSerializedScriptValue::toWrapped));
     502    auto sequenceArg = toRefPtrNativeArray<SerializedScriptValue, JSSerializedScriptValue>(*state, state->argument(0));
    503503    if (UNLIKELY(state->hadException()))
    504504        return JSValue::encode(jsUndefined());
     
    606606    if (UNLIKELY(state->argumentCount() < 1))
    607607        return throwVMError(state, createNotEnoughArgumentsError(state));
    608     auto sequenceArg = (toRefPtrNativeArray<TestEventTarget, JSTestEventTarget>(state, state->argument(0), &JSTestEventTarget::toWrapped));
     608    auto sequenceArg = toRefPtrNativeArray<TestEventTarget, JSTestEventTarget>(*state, state->argument(0));
    609609    if (UNLIKELY(state->hadException()))
    610610        return JSValue::encode(jsUndefined());
Note: See TracChangeset for help on using the changeset viewer.