REVERT-use-v8-Array-Iterate-for-converting-script-wrappables.patch 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. From ce71348a09f6689dd01a68db64b172191d0182d8 Mon Sep 17 00:00:00 2001
  2. From: Andrey Kosyakov <caseq@chromium.org>
  3. Date: Thu, 21 Dec 2023 18:38:38 +0000
  4. Subject: [PATCH] [bindings] Use v8::Array::Iterate for converting script
  5. wrappables
  6. This changes CreateIDLSequenceFromV8Array to use the new
  7. v8::Array::Iterate() operation.
  8. This speeds up the "execBundles" part of the microbenchmark
  9. at crbug.com/dawn/1858 by around 3x.
  10. This depends on crrev.com/c/4846594 landing (and rolling) first.
  11. This is a slight re-work of https://crrev.com/c/4847447/3,
  12. originally by jkummerow@chromium.org
  13. Bug: v8:14218, dawn:1858, 1511239
  14. Change-Id: Ia266556d05b4d53e6942e12609d1c08882b4ff0f
  15. Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5132129
  16. Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
  17. Reviewed-by: Yuki Shiino <yukishiino@chromium.org>
  18. Cr-Commit-Position: refs/heads/main@{#1240236}
  19. ---
  20. .../bindings/core/v8/native_value_traits.h | 6 ++
  21. .../core/v8/native_value_traits_impl.h | 91 ++++++++++++++++++-
  22. 2 files changed, 95 insertions(+), 2 deletions(-)
  23. diff --git a/third_party/blink/renderer/bindings/core/v8/native_value_traits.h b/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
  24. index 1e5a0790df6d..a5c28b37e945 100644
  25. --- a/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
  26. +++ b/third_party/blink/renderer/bindings/core/v8/native_value_traits.h
  27. @@ -84,6 +84,12 @@ struct NativeValueTraitsBase {
  28. std::is_pointer_v<ImplType> ||
  29. requires(ImplType value) { value.IsNull(); };
  30. + // This should only be true for certain subclasses of ScriptWrappable
  31. + // that satisfy the assumptions of CreateIDLSequenceFromV8ArraySlow() with
  32. + // regards to how NativeValue() is implemented for the underlying type.
  33. + static constexpr bool supports_scriptwrappable_specific_fast_array_iteration =
  34. + false;
  35. +
  36. template <typename... ExtraArgs>
  37. static decltype(auto) ArgumentValue(v8::Isolate* isolate,
  38. int argument_index,
  39. diff --git a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
  40. index 5011503dcf1c..f085b6e90516 100644
  41. --- a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
  42. +++ b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
  43. @@ -1037,10 +1037,86 @@ CreateIDLSequenceFromV8ArraySlow(v8::Isolate* isolate,
  44. return {};
  45. }
  46. - typename NativeValueTraits<IDLSequence<T>>::ImplType result;
  47. + using ResultType = typename NativeValueTraits<IDLSequence<T>>::ImplType;
  48. + ResultType result;
  49. result.ReserveInitialCapacity(length);
  50. v8::Local<v8::Context> current_context = isolate->GetCurrentContext();
  51. v8::TryCatch try_block(isolate);
  52. +
  53. + // Fast path -- we're creating a sequence of script wrappables, which can be
  54. + // done by directly getting underlying object as long as array types are
  55. + // homogeneous. With ScriptWrappables, we don't expect to enter JS during
  56. + // iteration, so we can rely on v8::Array::Iterate() which is much faster than
  57. + // iterating an array on the client side of the v8. Additionally, for most
  58. + // subsptyes of ScriptWrappables, we can speed up type checks (see more on
  59. + // that below next to supports_scriptwrappable_specific_fast_array_iteration
  60. + // check.
  61. + if constexpr (std::is_base_of_v<ScriptWrappable, T>) {
  62. + struct CallbackData {
  63. + STACK_ALLOCATED();
  64. +
  65. + public:
  66. + v8::Isolate* isolate;
  67. + v8::TypecheckWitness witness;
  68. + ResultType& result;
  69. + ExceptionState& exception_state;
  70. + CallbackData(v8::Isolate* isolate,
  71. + ResultType& result,
  72. + ExceptionState& exception_state)
  73. + : isolate(isolate),
  74. + witness(isolate),
  75. + result(result),
  76. + exception_state(exception_state) {}
  77. + };
  78. +
  79. + CallbackData callback_data(isolate, result, exception_state);
  80. + v8::Array::IterationCallback callback = [](uint32_t index,
  81. + v8::Local<v8::Value> v8_element,
  82. + void* data) {
  83. + CallbackData* callback_data = reinterpret_cast<CallbackData*>(data);
  84. + // 3.4. Initialize Si to the result of converting nextItem to an IDL value
  85. + // of type T.
  86. + v8::TypecheckWitness& witness = callback_data->witness;
  87. + // We can speed up type check by taking advantage of V8's type witness,
  88. + // provided traits' NativeValue implementation doesn't have additional
  89. + // logic beyond checking the type and calling ToScriptWrappable().
  90. + if constexpr (
  91. + NativeValueTraits<
  92. + T>::supports_scriptwrappable_specific_fast_array_iteration) {
  93. + if (witness.Matches(v8_element)) {
  94. + auto&& value = ToScriptWrappable(v8_element.As<v8::Object>())
  95. + ->template ToImpl<T>();
  96. + callback_data->result.push_back(std::move(value));
  97. + return v8::Array::CallbackResult::kContinue;
  98. + }
  99. + }
  100. + auto&& element = NativeValueTraits<T>::NativeValue(
  101. + callback_data->isolate, v8_element, callback_data->exception_state);
  102. + if (callback_data->exception_state.HadException()) {
  103. + // It doesn't matter whether we return `kException` or `kBreak` here,
  104. + // as that only affects the return value of `v8_array->Iterate()`,
  105. + // which we are ignoring.
  106. + return v8::Array::CallbackResult::kException;
  107. + }
  108. + if constexpr (
  109. + NativeValueTraits<
  110. + T>::supports_scriptwrappable_specific_fast_array_iteration) {
  111. + witness.Update(v8_element);
  112. + }
  113. + callback_data->result.push_back(std::move(element));
  114. + return v8::Array::CallbackResult::kContinue;
  115. + };
  116. + if (!v8_array->Iterate(current_context, callback, &callback_data)
  117. + .IsJust()) {
  118. + if (try_block.HasCaught()) {
  119. + exception_state.RethrowV8Exception(try_block.Exception());
  120. + }
  121. + DCHECK(exception_state.HadException());
  122. + return {};
  123. + }
  124. + return result;
  125. + }
  126. +
  127. // Array length may change if array is mutated during iteration.
  128. for (uint32_t i = 0; i < v8_array->Length(); ++i) {
  129. v8::Local<v8::Value> v8_element;
  130. @@ -1056,6 +1132,7 @@ CreateIDLSequenceFromV8ArraySlow(v8::Isolate* isolate,
  131. return {};
  132. result.push_back(std::move(element));
  133. }
  134. +
  135. // 3.2. If next is false, then return an IDL sequence value of type
  136. // sequence<T> of length i, where the value of the element at index j is Sj.
  137. return result;
  138. @@ -1398,6 +1475,7 @@ struct NativeValueTraits<T> : public NativeValueTraitsBase<T*> {
  139. }
  140. };
  141. +// Interface types
  142. template <typename T>
  143. requires std::derived_from<T, CallbackInterfaceBase>
  144. struct NativeValueTraits<IDLNullable<T>>
  145. @@ -1470,12 +1548,21 @@ struct NativeValueTraits<T> : public NativeValueTraitsBase<T> {
  146. template <typename T>
  147. requires std::derived_from<T, ScriptWrappable>
  148. struct NativeValueTraits<T> : public NativeValueTraitsBase<T*> {
  149. + // This signifies that CreateIDLSequenceFromV8ArraySlow() may apply
  150. + // certain optimization based on assumptions about `NativeValue()`
  151. + // implementation below. For subclasses of ScriptWrappable that have
  152. + // different implementation of NativeValue(), this should remain false.
  153. + static constexpr bool supports_scriptwrappable_specific_fast_array_iteration =
  154. + true;
  155. +
  156. static inline T* NativeValue(v8::Isolate* isolate,
  157. v8::Local<v8::Value> value,
  158. ExceptionState& exception_state) {
  159. const WrapperTypeInfo* wrapper_type_info = T::GetStaticWrapperTypeInfo();
  160. - if (V8PerIsolateData::From(isolate)->HasInstance(wrapper_type_info, value))
  161. + if (V8PerIsolateData::From(isolate)->HasInstance(wrapper_type_info,
  162. + value)) {
  163. return ToScriptWrappable(value.As<v8::Object>())->template ToImpl<T>();
  164. + }
  165. bindings::NativeValueTraitsInterfaceNotOfType(wrapper_type_info,
  166. exception_state);