Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 } | 300 } |
| 301 | 301 |
| 302 CORE_EXPORT static inline ImplType nativeValue(v8::Isolate* isolate, | 302 CORE_EXPORT static inline ImplType nativeValue(v8::Isolate* isolate, |
| 303 v8::Local<v8::Value> value, | 303 v8::Local<v8::Value> value, |
| 304 ExceptionState& exceptionState, | 304 ExceptionState& exceptionState, |
| 305 int index) { | 305 int index) { |
| 306 return toImplArray<ImplType, T>(value, index, isolate, exceptionState); | 306 return toImplArray<ImplType, T>(value, index, isolate, exceptionState); |
| 307 } | 307 } |
| 308 }; | 308 }; |
| 309 | 309 |
| 310 // Records | |
| 311 template <typename K, typename V> | |
| 312 struct NativeValueTraits<IDLRecord<K, V>> | |
| 313 : public NativeValueTraitsBase<IDLRecord<K, V>> { | |
| 314 private: | |
|
Yuki
2017/03/08 13:37:52
Sort the sections public: first and private: last
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
Done.
| |
| 315 static inline bool isPropertyEnumerable(v8::Isolate* isolate, | |
|
Yuki
2017/03/08 13:37:52
It's |inline| by default if member functions are d
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
Done.
| |
| 316 v8::Local<v8::Value> descriptor, | |
| 317 ExceptionState& exceptionState) { | |
| 318 if (descriptor->IsUndefined()) | |
|
Yuki
2017/03/08 13:37:52
We don't need this because we're checking IsObject
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:18
Done.
| |
| 319 return false; | |
| 320 if (!descriptor->IsObject()) | |
| 321 return false; | |
| 322 v8::Local<v8::Value> enumerable; | |
| 323 if (!v8::Local<v8::Object>::Cast(descriptor) | |
| 324 ->Get(isolate->GetCurrentContext(), | |
| 325 v8String(isolate, "enumerable")) | |
| 326 .ToLocal(&enumerable)) | |
| 327 return false; | |
| 328 return toBoolean(isolate, enumerable, exceptionState); | |
| 329 } | |
| 330 | |
| 331 public: | |
| 332 // Nondependent types need to be explicitly qualified to be accessible. | |
| 333 using typename NativeValueTraitsBase<IDLRecord<K, V>>::ImplType; | |
| 334 | |
| 335 // Converts a JavaScript value |O| to an IDL record<K, V> value. In C++, a | |
| 336 // record is represented as a Vector<std::pair<k, v>> (or a HeapVector if | |
| 337 // necessary). See https://heycam.github.io/webidl/#es-record. | |
| 338 CORE_EXPORT static inline ImplType nativeValue( | |
| 339 v8::Isolate* isolate, | |
| 340 v8::Local<v8::Value> originalValue, | |
|
Yuki
2017/03/08 13:37:52
Can we name this |value| simply?
Since this is a
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
We can, but I thought the preference was to leave
Yuki
2017/03/09 08:32:55
I didn't notice your intention, and later use of |
| |
| 341 ExceptionState& exceptionState) { | |
| 342 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
| 343 | |
| 344 // "1. If Type(O) is not Object, throw a TypeError." | |
| 345 if (!originalValue->IsObject()) { | |
| 346 exceptionState.throwTypeError( | |
| 347 "Only objects can be converted to record<K,V> types"); | |
| 348 return ImplType(); | |
| 349 } | |
| 350 v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(originalValue); | |
| 351 v8::TryCatch block(isolate); | |
| 352 | |
| 353 // "3. Let keys be ? O.[[OwnPropertyKeys]]()." | |
| 354 v8::Local<v8::Array> keys; | |
| 355 // While we could pass v8::ONLY_ENUMERABLE below, doing so breaks | |
| 356 // web-platform-tests' headers-record.html and deviates from the spec | |
| 357 // algorithm. | |
| 358 // Symbols are being skipped due to | |
| 359 // https://github.com/heycam/webidl/issues/294. | |
| 360 if (!v8Object | |
| 361 ->GetOwnPropertyNames(context, | |
| 362 static_cast<v8::PropertyFilter>( | |
| 363 v8::PropertyFilter::ALL_PROPERTIES | | |
| 364 v8::PropertyFilter::SKIP_SYMBOLS)) | |
| 365 .ToLocal(&keys)) { | |
| 366 exceptionState.rethrowV8Exception(block.Exception()); | |
| 367 return ImplType(); | |
| 368 } | |
| 369 if (keys->Length() > ImplType::maxCapacity()) { | |
| 370 exceptionState.throwRangeError("Array length exceeds supported limit."); | |
| 371 return ImplType(); | |
| 372 } | |
| 373 | |
| 374 // "2. Let result be a new empty instance of record<K, V>." | |
| 375 ImplType result; | |
| 376 result.reserveInitialCapacity(keys->Length()); | |
| 377 | |
| 378 // The conversion algorithm needs a data structure with fast insertion at | |
| 379 // the end while at the same time requiring fast checks for previous insert | |
| 380 // of a given key. |seenKeys| is a key/position in |result| map that aids in | |
| 381 // the latter part. | |
| 382 HashMap<String, size_t> seenKeys; | |
| 383 | |
| 384 for (uint32_t i = 0; i < keys->Length(); ++i) { | |
| 385 // "4. Repeat, for each element key of keys in List order:" | |
| 386 v8::Local<v8::Value> key; | |
| 387 if (!keys->Get(context, i).ToLocal(&key)) { | |
| 388 exceptionState.rethrowV8Exception(block.Exception()); | |
| 389 return ImplType(); | |
| 390 } | |
| 391 | |
| 392 // "4.1. Let desc be ? O.[[GetOwnProperty]](key)." | |
| 393 v8::Local<v8::Value> desc; | |
| 394 if (!v8Object | |
| 395 ->GetOwnPropertyDescriptor( | |
| 396 context, key->ToString(context).ToLocalChecked()) | |
| 397 .ToLocal(&desc)) { | |
| 398 exceptionState.rethrowV8Exception(block.Exception()); | |
| 399 return ImplType(); | |
| 400 } | |
| 401 | |
| 402 // "4.2. If desc is not undefined and desc.[[Enumerable]] is true:" | |
| 403 if (!isPropertyEnumerable(isolate, desc, exceptionState)) { | |
| 404 if (exceptionState.hadException()) | |
| 405 return ImplType(); | |
| 406 continue; | |
| 407 } | |
| 408 | |
| 409 // "4.2.1. Let typedKey be key converted to an IDL value of type K." | |
| 410 String typedKey = | |
| 411 NativeValueTraits<K>::nativeValue(isolate, key, exceptionState); | |
| 412 if (exceptionState.hadException()) | |
| 413 return ImplType(); | |
| 414 | |
| 415 // "4.2.2. Let value be ? Get(O, key)." | |
| 416 v8::Local<v8::Value> value; | |
| 417 if (!v8Object->Get(context, key).ToLocal(&value)) { | |
| 418 exceptionState.rethrowV8Exception(block.Exception()); | |
| 419 return ImplType(); | |
| 420 } | |
| 421 | |
| 422 // "4.2.3. Let typedValue be value converted to an IDL value of type V." | |
| 423 typename ImplType::ValueType::second_type typedValue = | |
| 424 NativeValueTraits<V>::nativeValue(isolate, value, exceptionState); | |
| 425 if (exceptionState.hadException()) | |
| 426 return ImplType(); | |
| 427 | |
| 428 if (seenKeys.contains(typedKey)) { | |
| 429 // "4.2.4. If typedKey is already a key in result, set its value to | |
| 430 // typedValue. | |
| 431 // Note: This can happen when O is a proxy object." | |
| 432 const size_t pos = seenKeys.at(typedKey); | |
| 433 result[pos] = std::make_pair(typedKey, typedValue); | |
| 434 } else { | |
| 435 // "4.2.5. Otherwise, append to result a mapping (typedKey, | |
| 436 // typedValue)." | |
| 437 const size_t pos = result.size(); // We can take this shortcut because | |
| 438 // we are always appending. | |
| 439 seenKeys.set(typedKey, pos); | |
| 440 result.uncheckedAppend(std::make_pair(typedKey, typedValue)); | |
| 441 } | |
| 442 } | |
| 443 // "5. Return result." | |
| 444 return result; | |
| 445 } | |
| 446 }; | |
| 447 | |
| 310 } // namespace blink | 448 } // namespace blink |
| 311 | 449 |
| 312 #endif // NativeValueTraitsImpl_h | 450 #endif // NativeValueTraitsImpl_h |
| OLD | NEW |