Commit 9dfff6a5 authored by Raphael Kubo da Costa's avatar Raphael Kubo da Costa Committed by Commit Bot

bindings: Do not access @@iterator twice when converting union to sequence

A rough approximation of https://heycam.github.io/webidl/#es-union when
trying to convert an ES value to an IDL sequence or frozen array is:
1. Call the GetMethod abstract ES operation to retrieve the @@iterator
   property.
2. If it is not undefined, invoke
   https://heycam.github.io/webidl/#create-sequence-from-iterable with the
   ES value and the method obtained above.

So far, we were implementing it roughly like this:
1. Call the GetMethod abstract ES operation to retrieve the @@iterator
   property.
2. Invoke https://heycam.github.io/webidl/#es-sequence with the ES value,
   which disregards the method obtained in step 1 and goes through the whole
   process of calling GetMethod again and using that to create a sequence
   from an interable.

This is obviously not compliant with the spec, and the multiple calls to the
GetMethod abstract operation are user-visible, as can be seen in the test
case attached to the bug 1024388.

Properly fixing this requires changes to a few different classes and
functions:
* Make HasCallableIteratorSymbol(), which is called by the overload
  resolution algorithm implementation, be a small wrapper around
  GetEsIteratorMethod(). While HasCallableIteratorSymbol() precedes
  GetEsIteratorMethod(), the latter's implementation is more spec-compliant.
* Add a move constructor to ScriptIterator, as well as a static method that
  can create a ScriptIterator out of an ES value by invoking
  GetEsIteratorMethod() and GetEsIteratorWithMethod() underneath.
* Make NativeValueTraits<IDLSequence<T>>::ConvertSequenceSlow() take a
  ScriptIterator rather than a v8::Local<v8::Object>, which allows us to
  delegate getting an iterator out of an iterable object to the static
  ScriptIterator method mentioned above. This also helps reduce the size of
  the generated per-type NativeValueTraits<IDLSequence<T>> template code.
* Analogously, invoke ScriptIterator::FromIterable() in the union conversion
  code, and invoke a new NativeValueTraits<IDLSequence<T>>::NativeValue()
  overload that takes a ScriptIterator, so that we do not access the
  @@iterator property multiple times in the union conversion code.

Bug: 1024388
Change-Id: I47e6c0ca881e6e77f883ee78b5e1611138cdcc4a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1917169
Commit-Queue: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#716960}
parent 82c6dae9
...@@ -416,6 +416,7 @@ struct NativeValueTraits<IDLSequence<T>> ...@@ -416,6 +416,7 @@ struct NativeValueTraits<IDLSequence<T>>
static ImplType NativeValue(v8::Isolate* isolate, static ImplType NativeValue(v8::Isolate* isolate,
v8::Local<v8::Value> value, v8::Local<v8::Value> value,
ExceptionState& exception_state) { ExceptionState& exception_state) {
// 1. If Type(V) is not Object, throw a TypeError.
if (!value->IsObject()) { if (!value->IsObject()) {
exception_state.ThrowTypeError( exception_state.ThrowTypeError(
"The provided value cannot be converted to a sequence."); "The provided value cannot be converted to a sequence.");
...@@ -431,7 +432,21 @@ struct NativeValueTraits<IDLSequence<T>> ...@@ -431,7 +432,21 @@ struct NativeValueTraits<IDLSequence<T>>
ConvertSequenceFast(isolate, value.As<v8::Array>(), exception_state, ConvertSequenceFast(isolate, value.As<v8::Array>(), exception_state,
result); result);
} else { } else {
ConvertSequenceSlow(isolate, value.As<v8::Object>(), exception_state, // 2. Let method be ? GetMethod(V, @@iterator).
// 3. If method is undefined, throw a TypeError.
// 4. Return the result of creating a sequence from V and method.
auto script_iterator = ScriptIterator::FromIterable(
isolate, value.As<v8::Object>(), exception_state);
if (exception_state.HadException())
return ImplType();
if (script_iterator.IsNull()) {
// A null ScriptIterator with an empty |exception_state| means the
// object is lacking a callable @@iterator property.
exception_state.ThrowTypeError(
"The object must have a callable @@iterator property.");
return ImplType();
}
ConvertSequenceSlow(isolate, std::move(script_iterator), exception_state,
result); result);
} }
...@@ -440,6 +455,19 @@ struct NativeValueTraits<IDLSequence<T>> ...@@ -440,6 +455,19 @@ struct NativeValueTraits<IDLSequence<T>>
return result; return result;
} }
// https://heycam.github.io/webidl/#es-sequence
// This is a special case, used when converting an IDL union that contains a
// sequence or frozen array type.
static ImplType NativeValue(v8::Isolate* isolate,
ScriptIterator script_iterator,
ExceptionState& exception_state) {
DCHECK(!script_iterator.IsNull());
ImplType result;
ConvertSequenceSlow(isolate, std::move(script_iterator), exception_state,
result);
return result;
}
private: private:
// Fast case: we're interating over an Array that adheres to // Fast case: we're interating over an Array that adheres to
// %ArrayIteratorPrototype%'s protocol. // %ArrayIteratorPrototype%'s protocol.
...@@ -470,38 +498,15 @@ struct NativeValueTraits<IDLSequence<T>> ...@@ -470,38 +498,15 @@ struct NativeValueTraits<IDLSequence<T>>
// Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to // Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to
// iterate through each element. // iterate through each element.
// https://heycam.github.io/webidl/#create-sequence-from-iterable
static void ConvertSequenceSlow(v8::Isolate* isolate, static void ConvertSequenceSlow(v8::Isolate* isolate,
v8::Local<v8::Object> v8_object, ScriptIterator script_iterator,
ExceptionState& exception_state, ExceptionState& exception_state,
ImplType& result) { ImplType& result) {
// https://heycam.github.io/webidl/#es-sequence
// 2. Let method be ? GetMethod(V, @@iterator).
// 3. If method is undefined, throw a TypeError.
// 4. Return the result of creating a sequence from V and method.
const v8::Local<v8::Function> iterator_method =
GetEsIteratorMethod(isolate, v8_object, exception_state);
if (exception_state.HadException())
return;
if (iterator_method.IsEmpty()) {
exception_state.ThrowTypeError("Iterator getter is not callable.");
return;
}
// https://heycam.github.io/webidl/#create-sequence-from-iterable // https://heycam.github.io/webidl/#create-sequence-from-iterable
// To create an IDL value of type sequence<T> given an iterable iterable
// and an iterator getter method, perform the following steps:
// 1. Let iter be ? GetIterator(iterable, sync, method).
const v8::Local<v8::Object> iterator = GetEsIteratorWithMethod(
isolate, iterator_method, v8_object, exception_state);
if (exception_state.HadException())
return;
// 2. Initialize i to be 0. // 2. Initialize i to be 0.
// 3. Repeat: // 3. Repeat:
ExecutionContext* execution_context = ExecutionContext* execution_context =
ToExecutionContext(isolate->GetCurrentContext()); ToExecutionContext(isolate->GetCurrentContext());
ScriptIterator script_iterator(iterator, isolate);
while (script_iterator.Next(execution_context, exception_state)) { while (script_iterator.Next(execution_context, exception_state)) {
// 3.1. Let next be ? IteratorStep(iter). // 3.1. Let next be ? IteratorStep(iter).
// 3.2. If next is false, then return an IDL sequence value of type // 3.2. If next is false, then return an IDL sequence value of type
......
...@@ -11,6 +11,28 @@ ...@@ -11,6 +11,28 @@
namespace blink { namespace blink {
// static
ScriptIterator ScriptIterator::FromIterable(v8::Isolate* isolate,
v8::Local<v8::Object> value,
ExceptionState& exception_state) {
// First, call the GetMethod(V, @@iterator) abstract ES operation.
const v8::Local<v8::Function> iterator_method =
GetEsIteratorMethod(isolate, value, exception_state);
if (exception_state.HadException())
return ScriptIterator(nullptr);
if (iterator_method.IsEmpty())
return ScriptIterator(nullptr);
// Use the method returned above to invoke the GetIterator(V, sync, method)
// abstract ES operation.
const v8::Local<v8::Object> iterator =
GetEsIteratorWithMethod(isolate, iterator_method, value, exception_state);
if (exception_state.HadException())
return ScriptIterator(nullptr);
return ScriptIterator(iterator, isolate);
}
ScriptIterator::ScriptIterator(v8::Local<v8::Object> iterator, ScriptIterator::ScriptIterator(v8::Local<v8::Object> iterator,
v8::Isolate* isolate) v8::Isolate* isolate)
: isolate_(isolate), : isolate_(isolate),
......
...@@ -14,14 +14,67 @@ namespace blink { ...@@ -14,14 +14,67 @@ namespace blink {
class ExceptionState; class ExceptionState;
class ExecutionContext; class ExecutionContext;
// This class provides a wrapper for iterating over any ES object that
// implements the iterable and iterator protocols. Namely:
// * The object or an object in its prototype chain has an @@iterator property
// that is a function that returns an iterator object.
// * The iterator object has a next() method that returns an object with at
// least two properties:
// 1. done: A boolean indicating whether iteration should stop. Can be
// omitted when false.
// 2. value: Any object. Can be omitted when |done| is true.
//
// In general, this class should be preferred over using the
// GetEsIteratorMethod() and GetEsIteratorWithMethod() functions directly.
//
// Usage:
// v8::Local<v8::Object> es_object = ...;
// auto script_iterator = ScriptIterator::FromIterable(
// isolate, es_object, exception_state,
// ScriptIterator::ConversionFailureMode::kDoNotThrowTypeError);
// if (exception_state.HadException())
// return;
// if (!script_iterator.IsNull()) {
// while (script_iterator.Next(execution_context, exception_state)) {
// // V8 may have thrown an exception.
// if (exception_state.HadException())
// return;
// v8::Local<v8::Value> value =
// script_iterator.GetValue().ToLocalChecked();
// // Do something with |value|.
// }
// }
// // If the very first call to Next() throws, the loop above will not be
// // entered, so we need to catch any exceptions here.
// if (exception_state.HadException())
// return;
class CORE_EXPORT ScriptIterator { class CORE_EXPORT ScriptIterator {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
// Creates a ScriptIterator out of an ES object that implements the iterable
// and iterator protocols.
// Both the return value and the ExceptionState should be checked:
// - The ExceptionState will contain an exception if V8 throws one, or if the
// ES objects do not conform to the expected protocols. In this case, the
// returned ScriptIterator will be null.
// - ScriptIterator can be null even if there is no exception. In this case,
// it indicates that the given ES object does not have an @@iterator
// property.
static ScriptIterator FromIterable(v8::Isolate*,
v8::Local<v8::Object>,
ExceptionState&);
ScriptIterator(std::nullptr_t) : isolate_(nullptr), done_(true) {} ScriptIterator(std::nullptr_t) : isolate_(nullptr), done_(true) {}
ScriptIterator(v8::Local<v8::Object> iterator, v8::Isolate*); ScriptIterator(v8::Local<v8::Object> iterator, v8::Isolate*);
ScriptIterator(ScriptIterator&&) noexcept = default;
ScriptIterator& operator=(ScriptIterator&&) noexcept = default;
ScriptIterator(const ScriptIterator&) = delete;
ScriptIterator& operator=(const ScriptIterator&) = delete;
bool IsNull() const { return iterator_.IsEmpty(); } bool IsNull() const { return iterator_.IsEmpty(); }
// Returns true if the iterator is still not done. // Returns true if the iterator is still not done.
......
...@@ -872,16 +872,9 @@ bool HasCallableIteratorSymbol(v8::Isolate* isolate, ...@@ -872,16 +872,9 @@ bool HasCallableIteratorSymbol(v8::Isolate* isolate,
ExceptionState& exception_state) { ExceptionState& exception_state) {
if (!value->IsObject()) if (!value->IsObject())
return false; return false;
v8::TryCatch block(isolate); v8::Local<v8::Function> iterator_method =
v8::Local<v8::Context> context = isolate->GetCurrentContext(); GetEsIteratorMethod(isolate, value.As<v8::Object>(), exception_state);
v8::Local<v8::Value> iterator_getter; return !iterator_method.IsEmpty();
if (!value.As<v8::Object>()
->Get(context, v8::Symbol::GetIterator(isolate))
.ToLocal(&iterator_getter)) {
exception_state.RethrowV8Exception(block.Exception());
return false;
}
return iterator_getter->IsFunction();
} }
v8::Isolate* ToIsolate(const LocalFrame* frame) { v8::Isolate* ToIsolate(const LocalFrame* frame) {
......
...@@ -133,6 +133,7 @@ def _update_includes_and_forward_decls(member, info_provider): ...@@ -133,6 +133,7 @@ def _update_includes_and_forward_decls(member, info_provider):
_update_includes_and_forward_decls(member.value_type, info_provider) _update_includes_and_forward_decls(member.value_type, info_provider)
elif member.is_array_or_sequence_type: elif member.is_array_or_sequence_type:
_update_includes_and_forward_decls(member.element_type, info_provider) _update_includes_and_forward_decls(member.element_type, info_provider)
cpp_includes.add('bindings/core/v8/script_iterator.h')
elif member.is_union_type: elif member.is_union_type:
# Reaching this block means we have a union that is inside a # Reaching this block means we have a union that is inside a
# record or sequence. # record or sequence.
...@@ -146,6 +147,14 @@ def member_context(member, info_provider): ...@@ -146,6 +147,14 @@ def member_context(member, info_provider):
if member.is_nullable: if member.is_nullable:
member = member.inner_type member = member.inner_type
type_name = (member.inner_type if member.is_annotated_type else member).name type_name = (member.inner_type if member.is_annotated_type else member).name
# When converting a sequence or frozen array, we need to call the GetMethod(V, @@iterator)
# ES abstract operation and then use the result of that call to create a sequence from an
# iterable. For the purposes of this method, it means we need to pass |script_iterator|
# rather than |v8_value| in v8_value_to_local_cpp_value().
if member.is_array_or_sequence_type:
v8_value_name = 'std::move(script_iterator)'
else:
v8_value_name = 'v8_value'
return { return {
'cpp_name': to_snake_case(v8_utilities.cpp_name(member)), 'cpp_name': to_snake_case(v8_utilities.cpp_name(member)),
'cpp_type': member.cpp_type_args(used_in_cpp_sequence=True), 'cpp_type': member.cpp_type_args(used_in_cpp_sequence=True),
...@@ -162,6 +171,6 @@ def member_context(member, info_provider): ...@@ -162,6 +171,6 @@ def member_context(member, info_provider):
'specific_type_enum': 'k' + member.name, 'specific_type_enum': 'k' + member.name,
'type_name': type_name, 'type_name': type_name,
'v8_value_to_local_cpp_value': member.v8_value_to_local_cpp_value( 'v8_value_to_local_cpp_value': member.v8_value_to_local_cpp_value(
{}, 'v8_value', 'cpp_value', isolate='isolate', {}, v8_value_name, 'cpp_value', isolate='isolate',
use_exception_state=True) use_exception_state=True)
} }
...@@ -114,15 +114,22 @@ void {{v8_class}}::ToImpl( ...@@ -114,15 +114,22 @@ void {{v8_class}}::ToImpl(
{% endif %} {% endif %}
{% if array_or_sequence_type %} {% if array_or_sequence_type %}
{# 11.1, 11.2. Sequences and frozen arrays #} {# 11.1, 11.2. Sequences and frozen arrays #}
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
{{v8_value_to_local_cpp_value(array_or_sequence_type) | trim | indent}} ScriptIterator script_iterator = ScriptIterator::FromIterable(
{% if array_or_sequence_type.enum_values %} isolate, v8_value.As<v8::Object>(), exception_state);
{{declare_enum_validation_variable(array_or_sequence_type.enum_values) | trim | indent(4)}} if (exception_state.HadException())
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues), "{{array_or_sequence_type.enum_type}}", exception_state))
return; return;
{% endif %} if (!script_iterator.IsNull()) {
impl.Set{{array_or_sequence_type.type_name}}(cpp_value); {{v8_value_to_local_cpp_value(array_or_sequence_type) | trim | indent(6)}}
return; {% if array_or_sequence_type.enum_values %}
{{declare_enum_validation_variable(array_or_sequence_type.enum_values) | trim | indent(6)}}
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues),
"{{array_or_sequence_type.enum_type}}", exception_state))
return;
{% endif %}
impl.Set{{array_or_sequence_type.type_name}}(cpp_value);
return;
}
} }
{% endif %} {% endif %}
...@@ -232,3 +239,4 @@ v8::Local<v8::Value> ToV8(const {{cpp_class}}& impl, v8::Local<v8::Object> creat ...@@ -232,3 +239,4 @@ v8::Local<v8::Value> ToV8(const {{cpp_class}}& impl, v8::Local<v8::Object> creat
} // namespace blink } // namespace blink
{% endfilter %}{# format_blink_cpp_source_code #} {% endfilter %}{# format_blink_cpp_source_code #}
...@@ -140,3 +140,4 @@ ArrayBufferOrArrayBufferViewOrDictionary NativeValueTraits<ArrayBufferOrArrayBuf ...@@ -140,3 +140,4 @@ ArrayBufferOrArrayBufferViewOrDictionary NativeValueTraits<ArrayBufferOrArrayBuf
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_element.h" #include "third_party/blink/renderer/bindings/core/v8/v8_element.h"
#include "third_party/blink/renderer/core/css/cssom/element_computed_style_map.h" #include "third_party/blink/renderer/core/css/cssom/element_computed_style_map.h"
...@@ -79,12 +80,18 @@ void V8BooleanOrElementSequence::ToImpl( ...@@ -79,12 +80,18 @@ void V8BooleanOrElementSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
HeapVector<Member<Element>> cpp_value = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetElementSequence(cpp_value); if (!script_iterator.IsNull()) {
return; HeapVector<Member<Element>> cpp_value = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetElementSequence(cpp_value);
return;
}
} }
if (v8_value->IsBoolean()) { if (v8_value->IsBoolean()) {
...@@ -120,3 +127,4 @@ BooleanOrElementSequence NativeValueTraits<BooleanOrElementSequence>::NativeValu ...@@ -120,3 +127,4 @@ BooleanOrElementSequence NativeValueTraits<BooleanOrElementSequence>::NativeValu
} }
} // namespace blink } // namespace blink
...@@ -135,3 +135,4 @@ BooleanOrStringOrUnrestrictedDouble NativeValueTraits<BooleanOrStringOrUnrestric ...@@ -135,3 +135,4 @@ BooleanOrStringOrUnrestrictedDouble NativeValueTraits<BooleanOrStringOrUnrestric
} }
} // namespace blink } // namespace blink
...@@ -113,3 +113,4 @@ BooleanOrTestCallbackInterface NativeValueTraits<BooleanOrTestCallbackInterface> ...@@ -113,3 +113,4 @@ BooleanOrTestCallbackInterface NativeValueTraits<BooleanOrTestCallbackInterface>
} }
} // namespace blink } // namespace blink
...@@ -115,3 +115,4 @@ ByteStringOrNodeList NativeValueTraits<ByteStringOrNodeList>::NativeValue( ...@@ -115,3 +115,4 @@ ByteStringOrNodeList NativeValueTraits<ByteStringOrNodeList>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -72,12 +73,18 @@ void V8ByteStringSequenceSequenceOrByteStringByteStringRecord::ToImpl( ...@@ -72,12 +73,18 @@ void V8ByteStringSequenceSequenceOrByteStringByteStringRecord::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<Vector<String>> cpp_value = NativeValueTraits<IDLSequence<IDLSequence<IDLByteString>>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetByteStringSequenceSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<Vector<String>> cpp_value = NativeValueTraits<IDLSequence<IDLSequence<IDLByteString>>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetByteStringSequenceSequence(cpp_value);
return;
}
} }
if (v8_value->IsObject()) { if (v8_value->IsObject()) {
...@@ -113,3 +120,4 @@ ByteStringSequenceSequenceOrByteStringByteStringRecord NativeValueTraits<ByteStr ...@@ -113,3 +120,4 @@ ByteStringSequenceSequenceOrByteStringByteStringRecord NativeValueTraits<ByteStr
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -72,12 +73,18 @@ void V8DoubleOrDoubleOrNullSequence::ToImpl( ...@@ -72,12 +73,18 @@ void V8DoubleOrDoubleOrNullSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<base::Optional<double>> cpp_value = NativeValueTraits<IDLSequence<IDLNullable<IDLDouble>>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetDoubleOrNullSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<base::Optional<double>> cpp_value = NativeValueTraits<IDLSequence<IDLNullable<IDLDouble>>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetDoubleOrNullSequence(cpp_value);
return;
}
} }
if (v8_value->IsNumber()) { if (v8_value->IsNumber()) {
...@@ -119,3 +126,4 @@ DoubleOrDoubleOrNullSequence NativeValueTraits<DoubleOrDoubleOrNullSequence>::Na ...@@ -119,3 +126,4 @@ DoubleOrDoubleOrNullSequence NativeValueTraits<DoubleOrDoubleOrNullSequence>::Na
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -72,12 +73,18 @@ void V8DoubleOrDoubleSequence::ToImpl( ...@@ -72,12 +73,18 @@ void V8DoubleOrDoubleSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<double> cpp_value = NativeValueTraits<IDLSequence<IDLDouble>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetDoubleSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<double> cpp_value = NativeValueTraits<IDLSequence<IDLDouble>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetDoubleSequence(cpp_value);
return;
}
} }
if (v8_value->IsNumber()) { if (v8_value->IsNumber()) {
...@@ -119,3 +126,4 @@ DoubleOrDoubleSequence NativeValueTraits<DoubleOrDoubleSequence>::NativeValue( ...@@ -119,3 +126,4 @@ DoubleOrDoubleSequence NativeValueTraits<DoubleOrDoubleSequence>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/long_or_boolean.h" #include "third_party/blink/renderer/bindings/core/v8/long_or_boolean.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -74,12 +75,18 @@ void V8DoubleOrLongOrBooleanSequence::ToImpl( ...@@ -74,12 +75,18 @@ void V8DoubleOrLongOrBooleanSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
HeapVector<LongOrBoolean> cpp_value = NativeValueTraits<IDLSequence<LongOrBoolean>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetLongOrBooleanSequence(cpp_value); if (!script_iterator.IsNull()) {
return; HeapVector<LongOrBoolean> cpp_value = NativeValueTraits<IDLSequence<LongOrBoolean>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetLongOrBooleanSequence(cpp_value);
return;
}
} }
if (v8_value->IsNumber()) { if (v8_value->IsNumber()) {
...@@ -121,3 +128,4 @@ DoubleOrLongOrBooleanSequence NativeValueTraits<DoubleOrLongOrBooleanSequence>:: ...@@ -121,3 +128,4 @@ DoubleOrLongOrBooleanSequence NativeValueTraits<DoubleOrLongOrBooleanSequence>::
} }
} // namespace blink } // namespace blink
...@@ -111,3 +111,4 @@ DoubleOrString NativeValueTraits<DoubleOrString>::NativeValue( ...@@ -111,3 +111,4 @@ DoubleOrString NativeValueTraits<DoubleOrString>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/double_or_string.h" #include "third_party/blink/renderer/bindings/core/v8/double_or_string.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -91,12 +92,18 @@ void V8DoubleOrStringOrDoubleOrStringSequence::ToImpl( ...@@ -91,12 +92,18 @@ void V8DoubleOrStringOrDoubleOrStringSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
HeapVector<DoubleOrString> cpp_value = NativeValueTraits<IDLSequence<DoubleOrString>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetDoubleOrStringSequence(cpp_value); if (!script_iterator.IsNull()) {
return; HeapVector<DoubleOrString> cpp_value = NativeValueTraits<IDLSequence<DoubleOrString>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetDoubleOrStringSequence(cpp_value);
return;
}
} }
if (v8_value->IsNumber()) { if (v8_value->IsNumber()) {
...@@ -140,3 +147,4 @@ DoubleOrStringOrDoubleOrStringSequence NativeValueTraits<DoubleOrStringOrDoubleO ...@@ -140,3 +147,4 @@ DoubleOrStringOrDoubleOrStringSequence NativeValueTraits<DoubleOrStringOrDoubleO
} }
} // namespace blink } // namespace blink
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/double_or_string.h" #include "third_party/blink/renderer/bindings/core/v8/double_or_string.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_element.h" #include "third_party/blink/renderer/bindings/core/v8/v8_element.h"
#include "third_party/blink/renderer/core/css/cssom/element_computed_style_map.h" #include "third_party/blink/renderer/core/css/cssom/element_computed_style_map.h"
...@@ -81,12 +82,18 @@ void V8ElementSequenceOrByteStringDoubleOrStringRecord::ToImpl( ...@@ -81,12 +82,18 @@ void V8ElementSequenceOrByteStringDoubleOrStringRecord::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
HeapVector<Member<Element>> cpp_value = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetElementSequence(cpp_value); if (!script_iterator.IsNull()) {
return; HeapVector<Member<Element>> cpp_value = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetElementSequence(cpp_value);
return;
}
} }
if (v8_value->IsObject()) { if (v8_value->IsObject()) {
...@@ -122,3 +129,4 @@ ElementSequenceOrByteStringDoubleOrStringRecord NativeValueTraits<ElementSequenc ...@@ -122,3 +129,4 @@ ElementSequenceOrByteStringDoubleOrStringRecord NativeValueTraits<ElementSequenc
} }
} // namespace blink } // namespace blink
...@@ -116,3 +116,4 @@ FloatOrBoolean NativeValueTraits<FloatOrBoolean>::NativeValue( ...@@ -116,3 +116,4 @@ FloatOrBoolean NativeValueTraits<FloatOrBoolean>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -116,3 +116,4 @@ LongOrBoolean NativeValueTraits<LongOrBoolean>::NativeValue( ...@@ -116,3 +116,4 @@ LongOrBoolean NativeValueTraits<LongOrBoolean>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -128,3 +128,4 @@ LongOrTestDictionary NativeValueTraits<LongOrTestDictionary>::NativeValue( ...@@ -128,3 +128,4 @@ LongOrTestDictionary NativeValueTraits<LongOrTestDictionary>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_event.h" #include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
...@@ -80,12 +81,18 @@ void V8LongSequenceOrEvent::ToImpl( ...@@ -80,12 +81,18 @@ void V8LongSequenceOrEvent::ToImpl(
return; return;
} }
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<int32_t> cpp_value = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetLongSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<int32_t> cpp_value = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetLongSequence(cpp_value);
return;
}
} }
exception_state.ThrowTypeError("The provided value is not of type '(sequence<long> or Event)'"); exception_state.ThrowTypeError("The provided value is not of type '(sequence<long> or Event)'");
...@@ -113,3 +120,4 @@ LongSequenceOrEvent NativeValueTraits<LongSequenceOrEvent>::NativeValue( ...@@ -113,3 +120,4 @@ LongSequenceOrEvent NativeValueTraits<LongSequenceOrEvent>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "third_party/blink/renderer/bindings/core/v8/byte_string_or_node_list.h" #include "third_party/blink/renderer/bindings/core/v8/byte_string_or_node_list.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_event.h" #include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_node.h" #include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
...@@ -171,12 +172,18 @@ void V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNode ...@@ -171,12 +172,18 @@ void V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNode
return; return;
} }
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<int32_t> cpp_value = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetLongSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<int32_t> cpp_value = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetLongSequence(cpp_value);
return;
}
} }
if (v8_value->IsObject()) { if (v8_value->IsObject()) {
...@@ -226,3 +233,4 @@ NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRec ...@@ -226,3 +233,4 @@ NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRec
} }
} // namespace blink } // namespace blink
...@@ -115,3 +115,4 @@ NodeOrNodeList NativeValueTraits<NodeOrNodeList>::NativeValue( ...@@ -115,3 +115,4 @@ NodeOrNodeList NativeValueTraits<NodeOrNodeList>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -139,3 +139,4 @@ StringOrArrayBufferOrArrayBufferView NativeValueTraits<StringOrArrayBufferOrArra ...@@ -139,3 +139,4 @@ StringOrArrayBufferOrArrayBufferView NativeValueTraits<StringOrArrayBufferOrArra
} }
} // namespace blink } // namespace blink
...@@ -111,3 +111,4 @@ StringOrDouble NativeValueTraits<StringOrDouble>::NativeValue( ...@@ -111,3 +111,4 @@ StringOrDouble NativeValueTraits<StringOrDouble>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -72,12 +73,18 @@ void V8StringOrStringSequence::ToImpl( ...@@ -72,12 +73,18 @@ void V8StringOrStringSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
impl.SetStringSequence(cpp_value); if (!script_iterator.IsNull()) {
return; Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, std::move(script_iterator), exception_state);
if (exception_state.HadException())
return;
impl.SetStringSequence(cpp_value);
return;
}
} }
{ {
...@@ -111,3 +118,4 @@ StringOrStringSequence NativeValueTraits<StringOrStringSequence>::NativeValue( ...@@ -111,3 +118,4 @@ StringOrStringSequence NativeValueTraits<StringOrStringSequence>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -111,3 +111,4 @@ StringTreatNullAsEmptyStringOrLong NativeValueTraits<StringTreatNullAsEmptyStrin ...@@ -111,3 +111,4 @@ StringTreatNullAsEmptyStringOrLong NativeValueTraits<StringTreatNullAsEmptyStrin
} }
} // namespace blink } // namespace blink
...@@ -130,3 +130,4 @@ TestEnumOrDouble NativeValueTraits<TestEnumOrDouble>::NativeValue( ...@@ -130,3 +130,4 @@ TestEnumOrDouble NativeValueTraits<TestEnumOrDouble>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -95,21 +96,28 @@ void V8TestEnumOrTestEnumOrNullSequence::ToImpl( ...@@ -95,21 +96,28 @@ void V8TestEnumOrTestEnumOrNullSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLStringOrNull>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
const char* const kValidValues[] = { if (!script_iterator.IsNull()) {
nullptr, Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLStringOrNull>>::NativeValue(isolate, std::move(script_iterator), exception_state);
"", if (exception_state.HadException())
"EnumValue1", return;
"EnumValue2", const char* const kValidValues[] = {
"EnumValue3", nullptr,
}; "",
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues), "TestEnum", exception_state)) "EnumValue1",
"EnumValue2",
"EnumValue3",
};
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues),
"TestEnum", exception_state))
return;
impl.SetTestEnumOrNullSequence(cpp_value);
return; return;
impl.SetTestEnumOrNullSequence(cpp_value); }
return;
} }
{ {
...@@ -151,3 +159,4 @@ TestEnumOrTestEnumOrNullSequence NativeValueTraits<TestEnumOrTestEnumOrNullSeque ...@@ -151,3 +159,4 @@ TestEnumOrTestEnumOrNullSequence NativeValueTraits<TestEnumOrTestEnumOrNullSeque
} }
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
namespace blink { namespace blink {
...@@ -94,20 +95,27 @@ void V8TestEnumOrTestEnumSequence::ToImpl( ...@@ -94,20 +95,27 @@ void V8TestEnumOrTestEnumSequence::ToImpl(
if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value)) if (conversion_mode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8_value))
return; return;
if (HasCallableIteratorSymbol(isolate, v8_value, exception_state)) { if (v8_value->IsObject()) {
Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, v8_value, exception_state); ScriptIterator script_iterator = ScriptIterator::FromIterable(
isolate, v8_value.As<v8::Object>(), exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return; return;
const char* const kValidValues[] = { if (!script_iterator.IsNull()) {
"", Vector<String> cpp_value = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, std::move(script_iterator), exception_state);
"EnumValue1", if (exception_state.HadException())
"EnumValue2", return;
"EnumValue3", const char* const kValidValues[] = {
}; "",
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues), "TestEnum", exception_state)) "EnumValue1",
"EnumValue2",
"EnumValue3",
};
if (!IsValidEnum(cpp_value, kValidValues, base::size(kValidValues),
"TestEnum", exception_state))
return;
impl.SetTestEnumSequence(cpp_value);
return; return;
impl.SetTestEnumSequence(cpp_value); }
return;
} }
{ {
...@@ -149,3 +157,4 @@ TestEnumOrTestEnumSequence NativeValueTraits<TestEnumOrTestEnumSequence>::Native ...@@ -149,3 +157,4 @@ TestEnumOrTestEnumSequence NativeValueTraits<TestEnumOrTestEnumSequence>::Native
} }
} // namespace blink } // namespace blink
...@@ -112,3 +112,4 @@ TestInterface2OrUint8Array NativeValueTraits<TestInterface2OrUint8Array>::Native ...@@ -112,3 +112,4 @@ TestInterface2OrUint8Array NativeValueTraits<TestInterface2OrUint8Array>::Native
} }
} // namespace blink } // namespace blink
...@@ -124,3 +124,4 @@ TestInterfaceOrLong NativeValueTraits<TestInterfaceOrLong>::NativeValue( ...@@ -124,3 +124,4 @@ TestInterfaceOrLong NativeValueTraits<TestInterfaceOrLong>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -116,3 +116,4 @@ TestInterfaceOrTestInterfaceEmpty NativeValueTraits<TestInterfaceOrTestInterface ...@@ -116,3 +116,4 @@ TestInterfaceOrTestInterfaceEmpty NativeValueTraits<TestInterfaceOrTestInterface
} }
} // namespace blink } // namespace blink
...@@ -111,3 +111,4 @@ UnrestrictedDoubleOrString NativeValueTraits<UnrestrictedDoubleOrString>::Native ...@@ -111,3 +111,4 @@ UnrestrictedDoubleOrString NativeValueTraits<UnrestrictedDoubleOrString>::Native
} }
} // namespace blink } // namespace blink
...@@ -143,3 +143,4 @@ UnsignedLongLongOrBooleanOrTestCallbackInterface NativeValueTraits<UnsignedLongL ...@@ -143,3 +143,4 @@ UnsignedLongLongOrBooleanOrTestCallbackInterface NativeValueTraits<UnsignedLongL
} }
} // namespace blink } // namespace blink
...@@ -111,3 +111,4 @@ XMLHttpRequestOrString NativeValueTraits<XMLHttpRequestOrString>::NativeValue( ...@@ -111,3 +111,4 @@ XMLHttpRequestOrString NativeValueTraits<XMLHttpRequestOrString>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -108,3 +108,4 @@ BooleanOrString NativeValueTraits<BooleanOrString>::NativeValue( ...@@ -108,3 +108,4 @@ BooleanOrString NativeValueTraits<BooleanOrString>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -128,3 +128,4 @@ TestDictionaryOrLong NativeValueTraits<TestDictionaryOrLong>::NativeValue( ...@@ -128,3 +128,4 @@ TestDictionaryOrLong NativeValueTraits<TestDictionaryOrLong>::NativeValue(
} }
} // namespace blink } // namespace blink
...@@ -38,7 +38,7 @@ PASS unionTypesTest.doubleOrStringSequenceArg([1, "foo", "bar", 2]) is "double: ...@@ -38,7 +38,7 @@ PASS unionTypesTest.doubleOrStringSequenceArg([1, "foo", "bar", 2]) is "double:
PASS unionTypesTest.doubleOrStringSequenceArg([null, undefined, {}, []]) is "string: null, string: undefined, string: [object Object], string: " PASS unionTypesTest.doubleOrStringSequenceArg([null, undefined, {}, []]) is "string: null, string: undefined, string: [object Object], string: "
PASS unionTypesTest.doubleOrStringSequenceArg(null) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': The provided value cannot be converted to a sequence.. PASS unionTypesTest.doubleOrStringSequenceArg(null) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': The provided value cannot be converted to a sequence..
PASS unionTypesTest.doubleOrStringSequenceArg(undefined) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': The provided value cannot be converted to a sequence.. PASS unionTypesTest.doubleOrStringSequenceArg(undefined) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': The provided value cannot be converted to a sequence..
PASS unionTypesTest.doubleOrStringSequenceArg({}) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': Iterator getter is not callable.. PASS unionTypesTest.doubleOrStringSequenceArg({}) threw exception TypeError: Failed to execute 'doubleOrStringSequenceArg' on 'UnionTypesTest': The object must have a callable @@iterator property..
Tests for method arguments with defaults Tests for method arguments with defaults
......
...@@ -2,6 +2,7 @@ This is a testharness.js-based test. ...@@ -2,6 +2,7 @@ This is a testharness.js-based test.
PASS An array PASS An array
PASS A generator PASS A generator
FAIL An array with an overridden Symbol.iterator assert_array_equals: property 0, expected 6 but got 1 FAIL An array with an overridden Symbol.iterator assert_array_equals: property 0, expected 6 but got 1
PASS An object with an overriden Symbol.iterator
FAIL An array with an overridden Symbol.iterator on the prototype assert_array_equals: property 0, expected 11 but got 1 FAIL An array with an overridden Symbol.iterator on the prototype assert_array_equals: property 0, expected 11 but got 1
FAIL An array with an overridden %ArrayIterator%.prototype.next assert_array_equals: property 0, expected 8 but got 1 FAIL An array with an overridden %ArrayIterator%.prototype.next assert_array_equals: property 0, expected 8 but got 1
PASS A holey array with fallback to an accessor on the prototype PASS A holey array with fallback to an accessor on the prototype
......
...@@ -51,6 +51,27 @@ test(() => { ...@@ -51,6 +51,27 @@ test(() => {
assert_equals(callCount, 1, "@@iterator must only have been gotten once"); assert_equals(callCount, 1, "@@iterator must only have been gotten once");
}, "An array with an overridden Symbol.iterator"); }, "An array with an overridden Symbol.iterator");
test(t => {
function* generatorFunc() {
yield ["foo", "bar"];
yield ["baz", "quux"];
}
let callCount = 0;
const obj = {};
Object.defineProperty(obj, Symbol.iterator, {
get() {
++callCount;
return generatorFunc;
}
});
const searchParams = new URLSearchParams(obj);
assert_equals(searchParams.get("foo"), "bar");
assert_equals(searchParams.get("baz"), "quux");
assert_equals(callCount, 1, "@@iterator must only have been gotten once");
}, "An object with an overriden Symbol.iterator");
test(t => { test(t => {
const originalIterator = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator); const originalIterator = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
t.add_cleanup(() => { t.add_cleanup(() => {
......
...@@ -4,8 +4,8 @@ Test that the second argument of window.postMessage is ignored or triggers an er ...@@ -4,8 +4,8 @@ Test that the second argument of window.postMessage is ignored or triggers an er
PASS Posting message ('1', 1): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence. PASS Posting message ('1', 1): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence.
PASS Posting message ('2', c): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence. PASS Posting message ('2', c): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence.
PASS Posting message ('3', [object Object]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Iterator getter is not callable. PASS Posting message ('3', [object Object]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The object must have a callable @@iterator property.
PASS Posting message ('4', [object Window]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Iterator getter is not callable. PASS Posting message ('4', [object Window]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The object must have a callable @@iterator property.
PASS Posting message ('5', undefined) did not throw an exception PASS Posting message ('5', undefined) did not throw an exception
PASS Posting message ('5a', null): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence. PASS Posting message ('5a', null): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence.
PASS Posting message ('6', undefined) did not throw an exception PASS Posting message ('6', undefined) did not throw an exception
...@@ -25,7 +25,7 @@ PASS Posting message ('[object ArrayBuffer]', ): threw exception DataCloneError: ...@@ -25,7 +25,7 @@ PASS Posting message ('[object ArrayBuffer]', ): threw exception DataCloneError:
PASS Posting message ('data', [object ArrayBuffer]): threw exception DataCloneError: Failed to execute 'postMessage' on 'Window': ArrayBuffer at index 0 is already detached. PASS Posting message ('data', [object ArrayBuffer]): threw exception DataCloneError: Failed to execute 'postMessage' on 'Window': ArrayBuffer at index 0 is already detached.
PASS Posting message ('[detached TypedArray]', ): threw exception DataCloneError: Failed to execute 'postMessage' on 'Window': An ArrayBuffer is detached and could not be cloned. PASS Posting message ('[detached TypedArray]', ): threw exception DataCloneError: Failed to execute 'postMessage' on 'Window': An ArrayBuffer is detached and could not be cloned.
PASS Posting message ('data', [detached TypedArray]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type. PASS Posting message ('data', [detached TypedArray]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type.
PASS Posting message ('data', [object Object]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Iterator getter is not callable. PASS Posting message ('data', [object Object]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': The object must have a callable @@iterator property.
PASS Posting message ('data', 1,,2): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type. PASS Posting message ('data', 1,,2): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type.
PASS Posting message ('data', ,function postMessage() { [native code] }): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 is an untransferable 'null' value. PASS Posting message ('data', ,function postMessage() { [native code] }): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 is an untransferable 'null' value.
PASS window.postMessage() threw exception TypeError: Failed to execute 'postMessage' on 'Window': 1 argument required, but only 0 present.. PASS window.postMessage() threw exception TypeError: Failed to execute 'postMessage' on 'Window': 1 argument required, but only 0 present..
......
...@@ -82,8 +82,8 @@ PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, chann ...@@ -82,8 +82,8 @@ PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, chann
PASS new MessageEvent('eventType', { ports: [] }).ports is [] PASS new MessageEvent('eventType', { ports: [] }).ports is []
PASS new MessageEvent('eventType', { ports: undefined }).ports is [] PASS new MessageEvent('eventType', { ports: undefined }).ports is []
PASS new MessageEvent('eventType', { ports: [1, 2, 3] }).ports[2] threw exception TypeError: Failed to construct 'MessageEvent': Failed to convert value to 'MessagePort'.. PASS new MessageEvent('eventType', { ports: [1, 2, 3] }).ports[2] threw exception TypeError: Failed to construct 'MessageEvent': Failed to convert value to 'MessagePort'..
PASS new MessageEvent('eventType', { ports: test_object }).ports threw exception TypeError: Failed to construct 'MessageEvent': Iterator getter is not callable.. PASS new MessageEvent('eventType', { ports: test_object }).ports threw exception TypeError: Failed to construct 'MessageEvent': The object must have a callable @@iterator property..
PASS new MessageEvent('eventType', { ports: document }).ports threw exception TypeError: Failed to construct 'MessageEvent': Iterator getter is not callable.. PASS new MessageEvent('eventType', { ports: document }).ports threw exception TypeError: Failed to construct 'MessageEvent': The object must have a callable @@iterator property..
PASS new MessageEvent('eventType', { ports: false }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence.. PASS new MessageEvent('eventType', { ports: false }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence..
PASS new MessageEvent('eventType', { ports: true }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence.. PASS new MessageEvent('eventType', { ports: true }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence..
PASS new MessageEvent('eventType', { ports: '' }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence.. PASS new MessageEvent('eventType', { ports: '' }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence..
...@@ -94,8 +94,8 @@ PASS new MessageEvent('eventType', { ports: NaN }).ports threw exception TypeErr ...@@ -94,8 +94,8 @@ PASS new MessageEvent('eventType', { ports: NaN }).ports threw exception TypeErr
PASS new MessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence.. PASS new MessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence..
PASS new MessageEvent('eventType', { get ports() { throw 'MessageEvent Error'; } }) threw exception MessageEvent Error. PASS new MessageEvent('eventType', { get ports() { throw 'MessageEvent Error'; } }) threw exception MessageEvent Error.
PASS new MessageEvent('eventType', { ports: null }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence.. PASS new MessageEvent('eventType', { ports: null }).ports threw exception TypeError: Failed to construct 'MessageEvent': The provided value cannot be converted to a sequence..
PASS new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Failed to construct 'MessageEvent': Iterator getter is not callable.. PASS new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Failed to construct 'MessageEvent': The object must have a callable @@iterator property..
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: {length: 3, 0: channel.port1, 1: channel.port2, 2: channel2.port1} }).ports[2] threw exception TypeError: Failed to construct 'MessageEvent': Iterator getter is not callable.. PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: {length: 3, 0: channel.port1, 1: channel.port2, 2: channel2.port1} }).ports[2] threw exception TypeError: Failed to construct 'MessageEvent': The object must have a callable @@iterator property..
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles is true PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles is true
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable is true PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable is true
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).data is test_object PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).data is test_object
......
...@@ -2,7 +2,7 @@ Checks that initMessageEvent() is working ...@@ -2,7 +2,7 @@ Checks that initMessageEvent() is working
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, {x:1}); threw exception TypeError: Failed to execute 'initMessageEvent' on 'MessageEvent': Iterator getter is not callable.. PASS newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, {x:1}); threw exception TypeError: Failed to execute 'initMessageEvent' on 'MessageEvent': The object must have a callable @@iterator property..
PASS newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, undefined) did not throw exception. PASS newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, undefined) did not throw exception.
PASS [object MessageEvent] is an instance of function MessageEvent() { [native code] } PASS [object MessageEvent] is an instance of function MessageEvent() { [native code] }
PASS successfullyParsed is true PASS successfullyParsed is true
......
...@@ -11,7 +11,7 @@ description("Checks that initMessageEvent() is working"); ...@@ -11,7 +11,7 @@ description("Checks that initMessageEvent() is working");
var newEvent; var newEvent;
function runTest() { function runTest() {
newEvent = document.createEvent("MessageEvent"); newEvent = document.createEvent("MessageEvent");
shouldThrow('newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, {x:1});', '"TypeError: Failed to execute \'initMessageEvent\' on \'MessageEvent\': Iterator getter is not callable."'); shouldThrow('newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, {x:1});', '"TypeError: Failed to execute \'initMessageEvent\' on \'MessageEvent\': The object must have a callable @@iterator property."');
shouldNotThrow('newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, undefined)'); shouldNotThrow('newEvent.initMessageEvent("message", true, true, "ff", "*", 43, window, undefined)');
shouldBeType(newEvent, MessageEvent); shouldBeType(newEvent, MessageEvent);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment