Diff
Modified: trunk/LayoutTests/ChangeLog (217528 => 217529)
--- trunk/LayoutTests/ChangeLog 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/LayoutTests/ChangeLog 2017-05-29 01:30:58 UTC (rev 217529)
@@ -1,3 +1,15 @@
+2017-05-28 Sam Weinig <[email protected]>
+
+ [WebIDL] @@iterator should only be accessed once when disambiguating a union type
+ https://bugs.webkit.org/show_bug.cgi?id=172684
+
+ Reviewed by Yusuke Suzuki.
+
+ * js/dom/sequence-in-union-iterator-access-expected.txt: Added.
+ * js/dom/sequence-in-union-iterator-access.html: Added.
+ Add test case showing that @@iterator is only accessed once when converting a sequence
+ as part of a union.
+
2017-05-27 Chris Dumez <[email protected]>
imported/w3c/web-platform-tests/html/semantics/forms/form-control-infrastructure/form_attribute.html is crashing
Added: trunk/LayoutTests/js/dom/sequence-in-union-iterator-access-expected.txt (0 => 217529)
--- trunk/LayoutTests/js/dom/sequence-in-union-iterator-access-expected.txt (rev 0)
+++ trunk/LayoutTests/js/dom/sequence-in-union-iterator-access-expected.txt 2017-05-29 01:30:58 UTC (rev 217529)
@@ -0,0 +1,4 @@
+
+PASS @@iterator should only be accessed once, tested via replacement of @@iterator on instance.
+PASS @@iterator should only be accessed once, tested via replacement of @@iterator on prototype.
+
Added: trunk/LayoutTests/js/dom/sequence-in-union-iterator-access.html (0 => 217529)
--- trunk/LayoutTests/js/dom/sequence-in-union-iterator-access.html (rev 0)
+++ trunk/LayoutTests/js/dom/sequence-in-union-iterator-access.html 2017-05-29 01:30:58 UTC (rev 217529)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src=""
+ <script src=""
+</head>
+<body>
+<script>
+ const originalIterator = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
+
+ test(() => {
+ let callCount = 0;
+ let array = [2.0, 0.0, 0.0, 2.0, 10.0, 10.0];
+ Object.defineProperty(array, Symbol.iterator, {
+ get() {
+ ++callCount;
+ return originalIterator.value;
+ }
+ });
+
+ let matrix = new DOMMatrix(array);
+
+ assert_equals(callCount, 1, "@@iterator must only be accessed once.");
+ assert_equals(matrix.toString(), "matrix(2, 0, 0, 2, 10, 10)", "DOMMatrix constructor should work correctly.");
+ }, "@@iterator should only be accessed once, tested via replacement of @@iterator on instance.");
+
+ test((t) => {
+ t.add_cleanup(() => {
+ Object.defineProperty(Array.prototype, Symbol.iterator, originalIterator);
+ });
+
+ let callCount = 0;
+ const array = [2.0, 0.0, 0.0, 2.0, 10.0, 10.0];
+ Object.defineProperty(Array.prototype, Symbol.iterator, {
+ get() {
+ ++callCount;
+ return originalIterator.value;
+ }
+ });
+
+ let matrix = new DOMMatrix(array);
+
+ assert_equals(callCount, 1, "@@iterator must only be accessed once.");
+ assert_equals(matrix.toString(), "matrix(2, 0, 0, 2, 10, 10)", "DOMMatrix constructor should work correctly.");
+ }, "@@iterator should only be accessed once, tested via replacement of @@iterator on prototype.");
+</script>
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (217528 => 217529)
--- trunk/Source/_javascript_Core/ChangeLog 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-05-29 01:30:58 UTC (rev 217529)
@@ -1,3 +1,19 @@
+2017-05-28 Sam Weinig <[email protected]>
+
+ [WebIDL] @@iterator should only be accessed once when disambiguating a union type
+ https://bugs.webkit.org/show_bug.cgi?id=172684
+
+ Reviewed by Yusuke Suzuki.
+
+ * runtime/IteratorOperations.cpp:
+ (JSC::iteratorMethod):
+ (JSC::iteratorForIterable):
+ * runtime/IteratorOperations.h:
+ (JSC::forEachInIterable):
+ Add additional iterator helpers to allow union + sequence conversion code
+ to check for iterability by getting the iterator method, and iterate using
+ that method later on.
+
2017-05-28 Yusuke Suzuki <[email protected]>
Unreviewed, build fix for Windows
Modified: trunk/Source/_javascript_Core/runtime/IteratorOperations.cpp (217528 => 217529)
--- trunk/Source/_javascript_Core/runtime/IteratorOperations.cpp 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/_javascript_Core/runtime/IteratorOperations.cpp 2017-05-29 01:30:58 UTC (rev 217529)
@@ -176,6 +176,43 @@
return !applyMethod.isUndefined();
}
+JSValue iteratorMethod(ExecState& state, JSObject* object)
+{
+ auto& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ CallData callData;
+ CallType callType;
+ JSValue method = object->getMethod(&state, callData, callType, vm.propertyNames->iteratorSymbol, ASCIILiteral("Symbol.iterator property should be callable"));
+ RETURN_IF_EXCEPTION(scope, jsUndefined());
+
+ return method;
+}
+
+JSValue iteratorForIterable(ExecState& state, JSObject* object, JSValue iteratorMethod)
+{
+ VM& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ CallData iteratorMethodCallData;
+ CallType iteratorMethodCallType = getCallData(iteratorMethod, iteratorMethodCallData);
+ if (iteratorMethodCallType == CallType::None) {
+ throwTypeError(&state, scope);
+ return { };
+ }
+
+ ArgList iteratorMethodArguments;
+ JSValue iterator = call(&state, iteratorMethod, iteratorMethodCallType, iteratorMethodCallData, object, iteratorMethodArguments);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ if (!iterator.isObject()) {
+ throwTypeError(&state, scope);
+ return { };
+ }
+
+ return iterator;
+}
+
JSValue iteratorForIterable(ExecState* state, JSValue iterable)
{
VM& vm = state->vm();
Modified: trunk/Source/_javascript_Core/runtime/IteratorOperations.h (217528 => 217529)
--- trunk/Source/_javascript_Core/runtime/IteratorOperations.h 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/_javascript_Core/runtime/IteratorOperations.h 2017-05-29 01:30:58 UTC (rev 217529)
@@ -42,10 +42,15 @@
Structure* createIteratorResultObjectStructure(VM&, JSGlobalObject&);
+JS_EXPORT_PRIVATE JSValue iteratorMethod(ExecState&, JSObject*);
+JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState&, JSObject*, JSValue iteratorMethod);
+
+JS_EXPORT_PRIVATE JSValue iteratorMethod(ExecState&, JSObject*);
JS_EXPORT_PRIVATE bool hasIteratorMethod(ExecState&, JSValue);
+
JS_EXPORT_PRIVATE JSValue iteratorForIterable(ExecState*, JSValue iterable);
-template <typename CallBackType>
+template<typename CallBackType>
void forEachInIterable(ExecState* exec, JSValue iterable, const CallBackType& callback)
{
auto& vm = exec->vm();
@@ -70,4 +75,29 @@
}
}
+template<typename CallBackType>
+void forEachInIterable(ExecState& state, JSObject* iterable, JSValue iteratorMethod, const CallBackType& callback)
+{
+ auto& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto iterator = iteratorForIterable(state, iterable, iteratorMethod);
+ RETURN_IF_EXCEPTION(scope, void());
+ while (true) {
+ JSValue next = iteratorStep(&state, iterator);
+ if (UNLIKELY(scope.exception()) || next.isFalse())
+ return;
+
+ JSValue nextValue = iteratorValue(&state, next);
+ RETURN_IF_EXCEPTION(scope, void());
+
+ callback(vm, state, nextValue);
+ if (UNLIKELY(scope.exception())) {
+ scope.release();
+ iteratorClose(&state, iterator);
+ return;
+ }
+ }
+}
+
} // namespace JSC
Modified: trunk/Source/WebCore/ChangeLog (217528 => 217529)
--- trunk/Source/WebCore/ChangeLog 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/WebCore/ChangeLog 2017-05-29 01:30:58 UTC (rev 217529)
@@ -1,3 +1,45 @@
+2017-05-28 Sam Weinig <[email protected]>
+
+ [WebIDL] @@iterator should only be accessed once when disambiguating a union type
+ https://bugs.webkit.org/show_bug.cgi?id=172684
+
+ Reviewed by Yusuke Suzuki.
+
+ WebIDL specifies that when determining if the value you are converting to a union
+ is a sequence, you must get the @@iterator property and, should it exist, use it
+ to iterate the sequence. While we correctly accessing the property to make the
+ determination, we were not passing it into the sequence conversion code, and thus
+ the sequence conversion code re-accessed it, which is observable and wrong.
+
+ This patch pipes the @@iterator method through the sequence conversion code to avoid
+ this.
+
+ Test: js/dom/sequence-in-union-iterator-access.html
+
+ * bindings/js/JSDOMConvertSequences.h:
+ (WebCore::Detail::GenericSequenceConverter::convert):
+ (WebCore::Detail::NumericSequenceConverter::convertArray):
+ (WebCore::Detail::NumericSequenceConverter::convert):
+ (WebCore::Detail::SequenceConverter::convertArray):
+ (WebCore::Detail::SequenceConverter::convert):
+ (WebCore::Detail::SequenceConverter<IDLLong>::convert):
+ (WebCore::Detail::SequenceConverter<IDLFloat>::convert):
+ (WebCore::Detail::SequenceConverter<IDLUnrestrictedFloat>::convert):
+ (WebCore::Detail::SequenceConverter<IDLDouble>::convert):
+ (WebCore::Detail::SequenceConverter<IDLUnrestrictedDouble>::convert):
+ (WebCore::Converter<IDLSequence<T>>::convert):
+ (WebCore::Converter<IDLFrozenArray<T>>::convert):
+ Add variants of convert that take a JSObject* (sequence) / JSValue (iterator method)
+ rather than just the JSValue (sequence). To avoid too much duplication, split some
+ parts of SequenceConverter and NumericSequenceConverter up so they could be reused.
+
+ * bindings/js/JSDOMConvertUnion.h:
+ - Fix incorrect step 3 (WebIDL got updated at some point and we didn't notice) to remove
+ records.
+ - Update sequence and FrozenArray checking/conversion to get the iterator method and pass
+ it along, using the new ConditionalSequenceConverter helper which forwards to the new
+ sequence converters that accept the iterator method.
+
2017-05-27 Chris Dumez <[email protected]>
imported/w3c/web-platform-tests/html/semantics/forms/form-control-infrastructure/form_attribute.html is crashing
Modified: trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h (217528 => 217529)
--- trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h 2017-05-29 01:30:58 UTC (rev 217529)
@@ -39,17 +39,17 @@
struct GenericSequenceConverter {
using ReturnType = Vector<typename IDLType::ImplementationType>;
- static ReturnType convert(JSC::ExecState& state, JSC::JSObject* jsObject)
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object)
{
- return convert(state, jsObject, ReturnType());
+ return convert(state, object, ReturnType());
}
- static ReturnType convert(JSC::ExecState& state, JSC::JSObject* jsObject, ReturnType&& result)
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, ReturnType&& result)
{
- forEachInIterable(&state, jsObject, [&result](JSC::VM& vm, JSC::ExecState* state, JSC::JSValue jsValue) {
+ forEachInIterable(&state, object, [&result](JSC::VM& vm, JSC::ExecState* state, JSC::JSValue nextValue) {
auto scope = DECLARE_THROW_SCOPE(vm);
- auto convertedValue = Converter<IDLType>::convert(*state, jsValue);
+ auto convertedValue = Converter<IDLType>::convert(*state, nextValue);
if (UNLIKELY(scope.exception()))
return;
result.append(WTFMove(convertedValue));
@@ -56,6 +56,24 @@
});
return result;
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return convert(state, object, method, ReturnType());
+ }
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method, ReturnType&& result)
+ {
+ forEachInIterable(state, object, method, [&result](JSC::VM& vm, JSC::ExecState& state, JSC::JSValue nextValue) {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto convertedValue = Converter<IDLType>::convert(state, nextValue);
+ if (UNLIKELY(scope.exception()))
+ return;
+ result.append(WTFMove(convertedValue));
+ });
+ return result;
+ }
};
// Specialization for numeric types
@@ -67,6 +85,35 @@
using GenericConverter = GenericSequenceConverter<IDLType>;
using ReturnType = typename GenericConverter::ReturnType;
+ static ReturnType convertArray(JSC::ExecState& state, JSC::ThrowScope& scope, JSC::JSArray* array, unsigned length, JSC::IndexingType indexingType, ReturnType&& result)
+ {
+ if (indexingType == JSC::Int32Shape) {
+ for (unsigned i = 0; i < length; i++) {
+ auto indexValue = array->butterfly()->contiguousInt32()[i].get();
+ ASSERT(!indexValue || indexValue.isInt32());
+ if (!indexValue)
+ result.uncheckedAppend(0);
+ else
+ result.uncheckedAppend(indexValue.asInt32());
+ }
+ return result;
+ }
+
+ ASSERT(indexingType == JSC::DoubleShape);
+ for (unsigned i = 0; i < length; i++) {
+ auto doubleValue = array->butterfly()->contiguousDouble()[i];
+ if (std::isnan(doubleValue))
+ result.uncheckedAppend(0);
+ else {
+ auto convertedValue = Converter<IDLType>::convert(state, scope, doubleValue);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ result.uncheckedAppend(convertedValue);
+ }
+ }
+ return result;
+ }
+
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
auto& vm = state.vm();
@@ -103,31 +150,40 @@
if (indexingType != JSC::Int32Shape && indexingType != JSC::DoubleShape)
return GenericConverter::convert(state, object, WTFMove(result));
- if (indexingType == JSC::Int32Shape) {
- for (unsigned i = 0; i < length; i++) {
- auto indexValue = array->butterfly()->contiguousInt32()[i].get();
- ASSERT(!indexValue || indexValue.isInt32());
- if (!indexValue)
- result.uncheckedAppend(0);
- else
- result.uncheckedAppend(indexValue.asInt32());
- }
- return result;
- }
+ return convertArray(state, scope, array, length, indexingType, WTFMove(result));
+ }
- ASSERT(indexingType == JSC::DoubleShape);
- for (unsigned i = 0; i < length; i++) {
- auto doubleValue = array->butterfly()->contiguousDouble()[i];
- if (std::isnan(doubleValue))
- result.uncheckedAppend(0);
- else {
- auto convertedValue = Converter<IDLType>::convert(state, scope, doubleValue);
- RETURN_IF_EXCEPTION(scope, { });
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ auto& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
- result.uncheckedAppend(convertedValue);
- }
+ if (!JSC::isJSArray(object))
+ return GenericConverter::convert(state, object, method);
+
+ JSC::JSArray* array = JSC::asArray(object);
+ if (!array->isIteratorProtocolFastAndNonObservable())
+ return GenericConverter::convert(state, object, method);
+
+ unsigned length = array->length();
+ ReturnType result;
+ // If we're not an int32/double array, it's possible that converting a
+ // JSValue to a number could cause the iterator protocol to change, hence,
+ // we may need more capacity, or less. In such cases, we use the length
+ // as a proxy for the capacity we will most likely need (it's unlikely that
+ // a program is written with a valueOf that will augment the iterator protocol).
+ // If we are an int32/double array, then length is precisely the capacity we need.
+ if (!result.tryReserveCapacity(length)) {
+ // FIXME: Is the right exception to throw?
+ throwTypeError(&state, scope);
+ return { };
}
- return result;
+
+ JSC::IndexingType indexingType = array->indexingType() & JSC::IndexingShapeMask;
+ if (indexingType != JSC::Int32Shape && indexingType != JSC::DoubleShape)
+ return GenericConverter::convert(state, object, method, WTFMove(result));
+
+ return convertArray(state, scope, array, length, indexingType, WTFMove(result));
}
};
@@ -136,27 +192,8 @@
using GenericConverter = GenericSequenceConverter<IDLType>;
using ReturnType = typename GenericConverter::ReturnType;
- static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
+ static ReturnType convertArray(JSC::ExecState& state, JSC::ThrowScope& scope, JSC::JSArray* array)
{
- auto& vm = state.vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
-
- if (!value.isObject()) {
- throwSequenceTypeError(state, scope);
- return { };
- }
-
- JSC::JSObject* object = JSC::asObject(value);
- if (Converter<IDLType>::conversionHasSideEffects)
- return GenericConverter::convert(state, object);
-
- if (!JSC::isJSArray(object))
- return GenericConverter::convert(state, object);
-
- JSC::JSArray* array = JSC::asArray(object);
- if (!array->isIteratorProtocolFastAndNonObservable())
- return GenericConverter::convert(state, object);
-
unsigned length = array->length();
ReturnType result;
@@ -196,6 +233,48 @@
}
return result;
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
+ {
+ auto& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (!value.isObject()) {
+ throwSequenceTypeError(state, scope);
+ return { };
+ }
+
+ JSC::JSObject* object = JSC::asObject(value);
+ if (Converter<IDLType>::conversionHasSideEffects)
+ return GenericConverter::convert(state, object);
+
+ if (!JSC::isJSArray(object))
+ return GenericConverter::convert(state, object);
+
+ JSC::JSArray* array = JSC::asArray(object);
+ if (!array->isIteratorProtocolFastAndNonObservable())
+ return GenericConverter::convert(state, object);
+
+ return convertArray(state, scope, array);
+ }
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ auto& vm = state.vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (Converter<IDLType>::conversionHasSideEffects)
+ return GenericConverter::convert(state, object, method);
+
+ if (!JSC::isJSArray(object))
+ return GenericConverter::convert(state, object, method);
+
+ JSC::JSArray* array = JSC::asArray(object);
+ if (!array->isIteratorProtocolFastAndNonObservable())
+ return GenericConverter::convert(state, object, method);
+
+ return convertArray(state, scope, array);
+ }
};
template<>
@@ -206,6 +285,11 @@
{
return NumericSequenceConverter<IDLLong>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return NumericSequenceConverter<IDLLong>::convert(state, object, method);
+ }
};
template<>
@@ -216,6 +300,11 @@
{
return NumericSequenceConverter<IDLFloat>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return NumericSequenceConverter<IDLFloat>::convert(state, object, method);
+ }
};
template<>
@@ -226,6 +315,11 @@
{
return NumericSequenceConverter<IDLUnrestrictedFloat>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return NumericSequenceConverter<IDLUnrestrictedFloat>::convert(state, object, method);
+ }
};
template<>
@@ -236,6 +330,11 @@
{
return NumericSequenceConverter<IDLDouble>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return NumericSequenceConverter<IDLDouble>::convert(state, object, method);
+ }
};
template<>
@@ -246,6 +345,11 @@
{
return NumericSequenceConverter<IDLUnrestrictedDouble>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return NumericSequenceConverter<IDLUnrestrictedDouble>::convert(state, object, method);
+ }
};
}
@@ -257,6 +361,11 @@
{
return Detail::SequenceConverter<T>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return Detail::SequenceConverter<T>::convert(state, object, method);
+ }
};
template<typename T> struct JSConverter<IDLSequence<T>> {
@@ -280,6 +389,11 @@
{
return Detail::SequenceConverter<T>::convert(state, value);
}
+
+ static ReturnType convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return Detail::SequenceConverter<T>::convert(state, object, method);
+ }
};
template<typename T> struct JSConverter<IDLFrozenArray<T>> {
Modified: trunk/Source/WebCore/bindings/js/JSDOMConvertUnion.h (217528 => 217529)
--- trunk/Source/WebCore/bindings/js/JSDOMConvertUnion.h 2017-05-28 14:11:56 UTC (rev 217528)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvertUnion.h 2017-05-29 01:30:58 UTC (rev 217529)
@@ -51,6 +51,26 @@
}
};
+
+template<typename ReturnType, typename T, bool enabled>
+struct ConditionalSequenceConverter;
+
+template<typename ReturnType, typename T>
+struct ConditionalSequenceConverter<ReturnType, T, true> {
+ static std::optional<ReturnType> convert(JSC::ExecState& state, JSC::JSObject* object, JSC::JSValue method)
+ {
+ return ReturnType(Converter<T>::convert(state, object, method));
+ }
+};
+
+template<typename ReturnType, typename T>
+struct ConditionalSequenceConverter<ReturnType, T, false> {
+ static std::optional<ReturnType> convert(JSC::ExecState&, JSC::JSObject*, JSC::JSValue)
+ {
+ return std::nullopt;
+ }
+};
+
namespace Detail {
template<typename List, bool condition>
@@ -128,15 +148,10 @@
// NOTE: Union is expected to be pre-flattented.
// 3. If V is null or undefined then:
- if (hasDictionaryType || hasRecordType) {
+ if (hasDictionaryType) {
if (value.isUndefinedOrNull()) {
// 1. If types includes a dictionary type, then return the result of converting V to that dictionary type.
- if (hasDictionaryType)
- return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
-
- // 2. If types includes a record type, then return the result of converting V to that record type.
- if (hasRecordType)
- return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, RecordType, hasRecordType>::convert(state, value).value());
+ return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
}
}
@@ -173,8 +188,7 @@
if (value.isCell()) {
JSC::JSCell* cell = value.asCell();
if (cell->isObject()) {
- // FIXME: We should be able to optimize the following code by making use
- // of the fact that we have proved that the value is an object.
+ auto object = asObject(value);
// 1. If types includes a sequence type, then:
// 1. Let method be the result of GetMethod(V, @@iterator).
@@ -183,10 +197,10 @@
// sequence of that type from V and method.
constexpr bool hasSequenceType = numberOfSequenceTypes != 0;
if (hasSequenceType) {
- bool hasIterator = JSC::hasIteratorMethod(state, value);
+ auto method = JSC::iteratorMethod(state, object);
RETURN_IF_EXCEPTION(scope, ReturnType());
- if (hasIterator)
- return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, value).value());
+ if (!method.isUndefined())
+ return std::move<WTF::CheckMoveParameter>(ConditionalSequenceConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, object, method).value());
}
// 2. If types includes a frozen array type, then:
@@ -196,10 +210,10 @@
// frozen array of that type from V and method.
constexpr bool hasFrozenArrayType = numberOfFrozenArrayTypes != 0;
if (hasFrozenArrayType) {
- bool hasIterator = JSC::hasIteratorMethod(state, value);
+ auto method = JSC::iteratorMethod(state, object);
RETURN_IF_EXCEPTION(scope, ReturnType());
- if (hasIterator)
- return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, value).value());
+ if (!method.isUndefined())
+ return std::move<WTF::CheckMoveParameter>(ConditionalSequenceConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, object, method).value());
}
// 3. If types includes a dictionary type, then return the result of