Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Unified Diff: third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h

Issue 2810843002: bindings: Make the sequence conversion code more complaint with WebIDL. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
diff --git a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
index 81ac17909631c209bd314b72a5317d50e8c55b72..3fc39e52d433e44dd87cb94c3ef0e923fed76710 100644
--- a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
+++ b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
@@ -283,17 +283,128 @@ struct NativeValueTraits<IDLSequence<T>>
// Nondependent types need to be explicitly qualified to be accessible.
using typename NativeValueTraitsBase<IDLSequence<T>>::ImplType;
+ // https://heycam.github.io/webidl/#es-sequence
static ImplType NativeValue(v8::Isolate* isolate,
v8::Local<v8::Value> value,
ExceptionState& exception_state) {
- return NativeValue(isolate, value, exception_state, 0);
+ if (!value->IsObject()) {
+ exception_state.ThrowTypeError(
+ "The provided value cannot be converted to a sequence.");
+ return ImplType();
+ }
+
+ ImplType result;
+ // TODO(rakuco): Checking for IsArray() may not be enough. Other engines
+ // also prefer regular array iteration over a custom @@iterator when the
+ // latter is defined, but it is not clear if this is a valid optimization.
+ if (value->IsArray()) {
bashi 2017/04/11 00:34:00 We may want to ask v8 team this?
Yuki 2017/04/11 07:17:10 I think that this should be: if (value->Get(v8:
+ result.ReserveInitialCapacity(value.As<v8::Array>()->Length());
+ iteratorForEachFast(
+ isolate, value.As<v8::Object>(), exception_state,
+ [&isolate, &result, &exception_state](v8::Local<v8::Value> element) {
+ result.UncheckedAppend(NativeValueTraits<T>::NativeValue(
+ isolate, element, exception_state));
+ return !exception_state.HadException();
+ });
+ } else {
+ iteratorForEachSlow(
+ isolate, value.As<v8::Object>(), exception_state,
+ [&isolate, &result, &exception_state](v8::Local<v8::Value> element) {
+ result.emplace_back(NativeValueTraits<T>::NativeValue(
+ isolate, element, exception_state));
+ return !exception_state.HadException();
+ });
+ }
+
+ if (exception_state.HadException())
+ return ImplType();
+ return result;
}
- static ImplType NativeValue(v8::Isolate* isolate,
- v8::Local<v8::Value> value,
- ExceptionState& exception_state,
- int index) {
- return ToImplArray<ImplType, T>(value, index, isolate, exception_state);
+ private:
+ // Fast case: we're interating over an Array that adheres to
+ // %ArrayIteratorPrototype%'s protocol.
+ template <typename CallbackFunction>
+ static void iteratorForEachFast(v8::Isolate* isolate,
+ v8::Local<v8::Object> v8Object,
+ ExceptionState& exception_state,
+ CallbackFunction&& callback) {
+ DCHECK(v8Object->IsArray());
+ v8::TryCatch block(isolate);
+ const uint32_t length = v8Object.As<v8::Array>()->Length();
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Local<v8::Value> element;
+ if (!V8Call(v8Object->Get(isolate->GetCurrentContext(), i), element,
Yuki 2017/04/11 07:17:10 nit: V8Call is deprecated. Please use V8's ToLoca
+ block)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+ if (!callback(element))
bashi 2017/04/11 00:34:00 Help me understand: Why does the callback need to
+ return;
+ }
+ }
+
+ // Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to
+ // iterate through each element.
+ // https://heycam.github.io/webidl/#create-sequence-from-iterable
+ template <typename CallbackFunction>
+ static void iteratorForEachSlow(v8::Isolate* isolate,
+ v8::Local<v8::Object> v8Object,
+ ExceptionState& exception_state,
+ CallbackFunction&& callback) {
+ v8::TryCatch block(isolate);
+
+ v8::Local<v8::Object> iterator =
+ GetEsIterator(isolate, v8Object, exception_state);
+ if (exception_state.HadException())
+ return;
+
+ v8::Local<v8::String> next_key = V8String(isolate, "next");
+ v8::Local<v8::String> value_key = V8String(isolate, "value");
+ v8::Local<v8::String> done_key = V8String(isolate, "done");
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ while (true) {
+ v8::Local<v8::Value> next;
+ if (!iterator->Get(context, next_key).ToLocal(&next)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+ // TODO(bashi): Support callable objects.
bashi 2017/04/11 00:34:00 nit: My vague recollection is that yukishiino@ sai
Yuki 2017/04/11 07:17:10 Yes, a callable object is a function by definition
+ if (!next->IsObject() || !next.As<v8::Object>()->IsFunction()) {
+ exception_state.ThrowTypeError("Iterator.next should be callable.");
+ return;
+ }
+ v8::Local<v8::Value> nextResult;
Yuki 2017/04/11 07:17:10 nit: s/nextResult/next_result/ Last week end, Bli
+ if (!V8ScriptRunner::CallFunction(next.As<v8::Function>(),
+ ToExecutionContext(context), iterator,
+ 0, nullptr, isolate)
+ .ToLocal(&nextResult)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+ if (!nextResult->IsObject()) {
+ exception_state.ThrowTypeError(
+ "Iterator.next() did not return an object.");
+ return;
+ }
+ v8::Local<v8::Object> result_object = nextResult.As<v8::Object>();
+ v8::Local<v8::Value> element;
+ v8::Local<v8::Value> done;
+ if (!result_object->Get(context, value_key).ToLocal(&element) ||
+ !result_object->Get(context, done_key).ToLocal(&done)) {
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+ v8::Local<v8::Boolean> done_boolean;
+ if (!done->ToBoolean(context).ToLocal(&done_boolean)) {
Yuki 2017/04/11 07:17:10 nit: You can use done->BooleanValue(context).To(&d
+ exception_state.RethrowV8Exception(block.Exception());
+ return;
+ }
+ if (done_boolean->Value())
+ break;
+ if (!callback(element))
+ return;
+ }
}
};

Powered by Google App Engine
This is Rietveld 408576698