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

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

Issue 2732093003: bindings: Add support for the record<K,V> WebIDL type. (Closed)
Patch Set: Make isPropertyEnumerable rethrow exceptions in Get(), add more tests Created 3 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef NativeValueTraitsImpl_h 5 #ifndef NativeValueTraitsImpl_h
6 #define NativeValueTraitsImpl_h 6 #define NativeValueTraitsImpl_h
7 7
8 #include "bindings/core/v8/IDLTypes.h" 8 #include "bindings/core/v8/IDLTypes.h"
9 #include "bindings/core/v8/NativeValueTraits.h" 9 #include "bindings/core/v8/NativeValueTraits.h"
10 #include "bindings/core/v8/V8Binding.h" 10 #include "bindings/core/v8/V8Binding.h"
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 } 298 }
299 299
300 static inline ImplType nativeValue(v8::Isolate* isolate, 300 static inline ImplType nativeValue(v8::Isolate* isolate,
301 v8::Local<v8::Value> value, 301 v8::Local<v8::Value> value,
302 ExceptionState& exceptionState, 302 ExceptionState& exceptionState,
303 int index) { 303 int index) {
304 return toImplArray<ImplType, T>(value, index, isolate, exceptionState); 304 return toImplArray<ImplType, T>(value, index, isolate, exceptionState);
305 } 305 }
306 }; 306 };
307 307
308 // Records
309 template <typename K, typename V>
310 struct NativeValueTraits<IDLRecord<K, V>>
311 : public NativeValueTraitsBase<IDLRecord<K, V>> {
312 // Nondependent types need to be explicitly qualified to be accessible.
313 using typename NativeValueTraitsBase<IDLRecord<K, V>>::ImplType;
314
315 // Converts a JavaScript value |O| to an IDL record<K, V> value. In C++, a
316 // record is represented as a Vector<std::pair<k, v>> (or a HeapVector if
317 // necessary). See https://heycam.github.io/webidl/#es-record.
318 static inline ImplType nativeValue(v8::Isolate* isolate,
319 v8::Local<v8::Value> v8Value,
320 ExceptionState& exceptionState) {
321 v8::Local<v8::Context> context = isolate->GetCurrentContext();
322
323 // "1. If Type(O) is not Object, throw a TypeError."
324 if (!v8Value->IsObject()) {
325 exceptionState.throwTypeError(
326 "Only objects can be converted to record<K,V> types");
327 return ImplType();
328 }
329 v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);
330 v8::TryCatch block(isolate);
331
332 // "3. Let keys be ? O.[[OwnPropertyKeys]]()."
333 v8::Local<v8::Array> keys;
334 // While we could pass v8::ONLY_ENUMERABLE below, doing so breaks
335 // web-platform-tests' headers-record.html and deviates from the spec
336 // algorithm.
337 // Symbols are being skipped due to
338 // https://github.com/heycam/webidl/issues/294.
339 if (!v8Object
340 ->GetOwnPropertyNames(context,
341 static_cast<v8::PropertyFilter>(
342 v8::PropertyFilter::ALL_PROPERTIES |
343 v8::PropertyFilter::SKIP_SYMBOLS))
344 .ToLocal(&keys)) {
345 exceptionState.rethrowV8Exception(block.Exception());
346 return ImplType();
347 }
348 if (keys->Length() > ImplType::maxCapacity()) {
349 exceptionState.throwRangeError("Array length exceeds supported limit.");
350 return ImplType();
351 }
352
353 // "2. Let result be a new empty instance of record<K, V>."
354 ImplType result;
355 result.reserveInitialCapacity(keys->Length());
356
357 // The conversion algorithm needs a data structure with fast insertion at
358 // the end while at the same time requiring fast checks for previous insert
359 // of a given key. |seenKeys| is a key/position in |result| map that aids in
360 // the latter part.
361 HashMap<String, size_t> seenKeys;
362
363 for (uint32_t i = 0; i < keys->Length(); ++i) {
364 // "4. Repeat, for each element key of keys in List order:"
365 v8::Local<v8::Value> key;
366 if (!keys->Get(context, i).ToLocal(&key)) {
367 exceptionState.rethrowV8Exception(block.Exception());
368 return ImplType();
369 }
370
371 // "4.1. Let desc be ? O.[[GetOwnProperty]](key)."
372 v8::Local<v8::Value> desc;
373 if (!v8Object
374 ->GetOwnPropertyDescriptor(
375 context, key->ToString(context).ToLocalChecked())
376 .ToLocal(&desc)) {
377 exceptionState.rethrowV8Exception(block.Exception());
378 return ImplType();
379 }
380
381 // "4.2. If desc is not undefined and desc.[[Enumerable]] is true:"
382 if (!isPropertyEnumerable(isolate, desc, exceptionState)) {
383 if (exceptionState.hadException())
384 return ImplType();
385 continue;
386 }
387
388 // "4.2.1. Let typedKey be key converted to an IDL value of type K."
389 String typedKey =
390 NativeValueTraits<K>::nativeValue(isolate, key, exceptionState);
391 if (exceptionState.hadException())
392 return ImplType();
393
394 // "4.2.2. Let value be ? Get(O, key)."
395 v8::Local<v8::Value> value;
396 if (!v8Object->Get(context, key).ToLocal(&value)) {
397 exceptionState.rethrowV8Exception(block.Exception());
398 return ImplType();
399 }
400
401 // "4.2.3. Let typedValue be value converted to an IDL value of type V."
402 typename ImplType::ValueType::second_type typedValue =
403 NativeValueTraits<V>::nativeValue(isolate, value, exceptionState);
404 if (exceptionState.hadException())
405 return ImplType();
406
407 if (seenKeys.contains(typedKey)) {
408 // "4.2.4. If typedKey is already a key in result, set its value to
409 // typedValue.
410 // Note: This can happen when O is a proxy object."
411 const size_t pos = seenKeys.at(typedKey);
412 result[pos] = std::make_pair(typedKey, typedValue);
413 } else {
414 // "4.2.5. Otherwise, append to result a mapping (typedKey,
415 // typedValue)."
416 // Note we can take this shortcut because we are always appending.
417 const size_t pos = result.size();
418 seenKeys.set(typedKey, pos);
419 result.uncheckedAppend(std::make_pair(typedKey, typedValue));
420 }
421 }
422 // "5. Return result."
423 return result;
424 }
425
426 private:
427 static bool isPropertyEnumerable(v8::Isolate* isolate,
428 v8::Local<v8::Value> descriptor,
429 ExceptionState& exceptionState) {
430 if (!descriptor->IsObject())
431 return false;
432 v8::TryCatch block(isolate);
433 v8::Local<v8::Value> enumerable;
434 if (!v8::Local<v8::Object>::Cast(descriptor)
435 ->Get(isolate->GetCurrentContext(),
436 v8String(isolate, "enumerable"))
437 .ToLocal(&enumerable)) {
Yuki 2017/03/10 06:54:32 You can safely use ToLocalChecked() here because |
Raphael Kubo da Costa (rakuco) 2017/03/10 08:19:09 Are you sure about this? One of the tests I added
Yuki 2017/03/10 09:52:21 I didn't test anything for myself, so I can be wro
438 exceptionState.rethrowV8Exception(block.Exception());
439 return false;
440 }
441 return toBoolean(isolate, enumerable, exceptionState);
Yuki 2017/03/10 06:54:32 This is okay, but you can write return enumera
Raphael Kubo da Costa (rakuco) 2017/03/10 08:19:09 Same here: while V8 itself performs some boolean c
Yuki 2017/03/10 09:52:21 IIUC, there is no way for author script to install
Raphael Kubo da Costa (rakuco) 2017/03/10 10:42:37 You're right about those 2 points: while the proxy
442 }
443 };
444
308 } // namespace blink 445 } // namespace blink
309 446
310 #endif // NativeValueTraitsImpl_h 447 #endif // NativeValueTraitsImpl_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698