OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "content/child/v8_value_converter_impl.h" | 5 #include "content/child/v8_value_converter_impl.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "third_party/WebKit/public/web/WebArrayBuffer.h" | 15 #include "third_party/WebKit/public/web/WebArrayBuffer.h" |
16 #include "third_party/WebKit/public/web/WebArrayBufferConverter.h" | 16 #include "third_party/WebKit/public/web/WebArrayBufferConverter.h" |
17 #include "third_party/WebKit/public/web/WebArrayBufferView.h" | 17 #include "third_party/WebKit/public/web/WebArrayBufferView.h" |
18 #include "v8/include/v8.h" | 18 #include "v8/include/v8.h" |
19 | 19 |
20 namespace content { | 20 namespace content { |
21 | 21 |
22 // Default implementation of V8ValueConverter::Strategy | 22 // Default implementation of V8ValueConverter::Strategy |
23 | 23 |
24 bool V8ValueConverter::Strategy::FromV8Object( | 24 bool V8ValueConverter::Strategy::FromV8Object( |
25 v8::Handle<v8::Object> value, | 25 v8::Local<v8::Object> value, |
26 base::Value** out, | 26 base::Value** out, |
27 v8::Isolate* isolate, | 27 v8::Isolate* isolate, |
28 const FromV8ValueCallback& callback) const { | 28 const FromV8ValueCallback& callback) const { |
29 return false; | 29 return false; |
30 } | 30 } |
31 | 31 |
32 bool V8ValueConverter::Strategy::FromV8Array( | 32 bool V8ValueConverter::Strategy::FromV8Array( |
33 v8::Handle<v8::Array> value, | 33 v8::Local<v8::Array> value, |
34 base::Value** out, | 34 base::Value** out, |
35 v8::Isolate* isolate, | 35 v8::Isolate* isolate, |
36 const FromV8ValueCallback& callback) const { | 36 const FromV8ValueCallback& callback) const { |
37 return false; | 37 return false; |
38 } | 38 } |
39 | 39 |
40 bool V8ValueConverter::Strategy::FromV8ArrayBuffer(v8::Handle<v8::Object> value, | 40 bool V8ValueConverter::Strategy::FromV8ArrayBuffer(v8::Local<v8::Object> value, |
41 base::Value** out, | 41 base::Value** out, |
42 v8::Isolate* isolate) const { | 42 v8::Isolate* isolate) const { |
43 return false; | 43 return false; |
44 } | 44 } |
45 | 45 |
46 bool V8ValueConverter::Strategy::FromV8Number(v8::Handle<v8::Number> value, | 46 bool V8ValueConverter::Strategy::FromV8Number(v8::Local<v8::Number> value, |
47 base::Value** out) const { | 47 base::Value** out) const { |
48 return false; | 48 return false; |
49 } | 49 } |
50 | 50 |
51 bool V8ValueConverter::Strategy::FromV8Undefined(base::Value** out) const { | 51 bool V8ValueConverter::Strategy::FromV8Undefined(base::Value** out) const { |
52 return false; | 52 return false; |
53 } | 53 } |
54 | 54 |
55 | 55 |
56 namespace { | 56 namespace { |
(...skipping 24 matching lines...) Expand all Loading... |
81 : max_recursion_depth_(kMaxRecursionDepth), | 81 : max_recursion_depth_(kMaxRecursionDepth), |
82 avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {} | 82 avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {} |
83 | 83 |
84 // If |handle| is not in |unique_map_|, then add it to |unique_map_| and | 84 // If |handle| is not in |unique_map_|, then add it to |unique_map_| and |
85 // return true. | 85 // return true. |
86 // | 86 // |
87 // Otherwise do nothing and return false. Here "A is unique" means that no | 87 // Otherwise do nothing and return false. Here "A is unique" means that no |
88 // other handle B in the map points to the same object as A. Note that A can | 88 // other handle B in the map points to the same object as A. Note that A can |
89 // be unique even if there already is another handle with the same identity | 89 // be unique even if there already is another handle with the same identity |
90 // hash (key) in the map, because two objects can have the same hash. | 90 // hash (key) in the map, because two objects can have the same hash. |
91 bool UpdateAndCheckUniqueness(v8::Handle<v8::Object> handle) { | 91 bool UpdateAndCheckUniqueness(v8::Local<v8::Object> handle) { |
92 typedef HashToHandleMap::const_iterator Iterator; | 92 typedef HashToHandleMap::const_iterator Iterator; |
93 int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash(); | 93 int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash(); |
94 // We only compare using == with handles to objects with the same identity | 94 // We only compare using == with handles to objects with the same identity |
95 // hash. Different hash obviously means different objects, but two objects | 95 // hash. Different hash obviously means different objects, but two objects |
96 // in a couple of thousands could have the same identity hash. | 96 // in a couple of thousands could have the same identity hash. |
97 std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash); | 97 std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash); |
98 for (Iterator it = range.first; it != range.second; ++it) { | 98 for (Iterator it = range.first; it != range.second; ++it) { |
99 // Operator == for handles actually compares the underlying objects. | 99 // Operator == for handles actually compares the underlying objects. |
100 if (it->second == handle) | 100 if (it->second == handle) |
101 return false; | 101 return false; |
102 } | 102 } |
103 unique_map_.insert(std::make_pair(hash, handle)); | 103 unique_map_.insert(std::make_pair(hash, handle)); |
104 return true; | 104 return true; |
105 } | 105 } |
106 | 106 |
107 bool HasReachedMaxRecursionDepth() { | 107 bool HasReachedMaxRecursionDepth() { |
108 return max_recursion_depth_ < 0; | 108 return max_recursion_depth_ < 0; |
109 } | 109 } |
110 | 110 |
111 private: | 111 private: |
112 typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap; | 112 typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap; |
113 HashToHandleMap unique_map_; | 113 HashToHandleMap unique_map_; |
114 | 114 |
115 int max_recursion_depth_; | 115 int max_recursion_depth_; |
116 | 116 |
117 bool avoid_identity_hash_for_testing_; | 117 bool avoid_identity_hash_for_testing_; |
118 }; | 118 }; |
119 | 119 |
120 V8ValueConverter* V8ValueConverter::create() { | 120 V8ValueConverter* V8ValueConverter::create() { |
121 return new V8ValueConverterImpl(); | 121 return new V8ValueConverterImpl(); |
122 } | 122 } |
(...skipping 19 matching lines...) Expand all Loading... |
142 } | 142 } |
143 | 143 |
144 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { | 144 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { |
145 strip_null_from_objects_ = val; | 145 strip_null_from_objects_ = val; |
146 } | 146 } |
147 | 147 |
148 void V8ValueConverterImpl::SetStrategy(Strategy* strategy) { | 148 void V8ValueConverterImpl::SetStrategy(Strategy* strategy) { |
149 strategy_ = strategy; | 149 strategy_ = strategy; |
150 } | 150 } |
151 | 151 |
152 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value( | 152 v8::Local<v8::Value> V8ValueConverterImpl::ToV8Value( |
153 const base::Value* value, v8::Handle<v8::Context> context) const { | 153 const base::Value* value, v8::Local<v8::Context> context) const { |
154 v8::Context::Scope context_scope(context); | 154 v8::Context::Scope context_scope(context); |
155 v8::EscapableHandleScope handle_scope(context->GetIsolate()); | 155 v8::EscapableHandleScope handle_scope(context->GetIsolate()); |
156 return handle_scope.Escape( | 156 return handle_scope.Escape( |
157 ToV8ValueImpl(context->GetIsolate(), context->Global(), value)); | 157 ToV8ValueImpl(context->GetIsolate(), context->Global(), value)); |
158 } | 158 } |
159 | 159 |
160 base::Value* V8ValueConverterImpl::FromV8Value( | 160 base::Value* V8ValueConverterImpl::FromV8Value( |
161 v8::Handle<v8::Value> val, | 161 v8::Local<v8::Value> val, |
162 v8::Handle<v8::Context> context) const { | 162 v8::Local<v8::Context> context) const { |
163 v8::Context::Scope context_scope(context); | 163 v8::Context::Scope context_scope(context); |
164 v8::HandleScope handle_scope(context->GetIsolate()); | 164 v8::HandleScope handle_scope(context->GetIsolate()); |
165 FromV8ValueState state(avoid_identity_hash_for_testing_); | 165 FromV8ValueState state(avoid_identity_hash_for_testing_); |
166 return FromV8ValueImpl(&state, val, context->GetIsolate()); | 166 return FromV8ValueImpl(&state, val, context->GetIsolate()); |
167 } | 167 } |
168 | 168 |
169 v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( | 169 v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( |
170 v8::Isolate* isolate, | 170 v8::Isolate* isolate, |
171 v8::Handle<v8::Object> creation_context, | 171 v8::Local<v8::Object> creation_context, |
172 const base::Value* value) const { | 172 const base::Value* value) const { |
173 CHECK(value); | 173 CHECK(value); |
174 switch (value->GetType()) { | 174 switch (value->GetType()) { |
175 case base::Value::TYPE_NULL: | 175 case base::Value::TYPE_NULL: |
176 return v8::Null(isolate); | 176 return v8::Null(isolate); |
177 | 177 |
178 case base::Value::TYPE_BOOLEAN: { | 178 case base::Value::TYPE_BOOLEAN: { |
179 bool val = false; | 179 bool val = false; |
180 CHECK(value->GetAsBoolean(&val)); | 180 CHECK(value->GetAsBoolean(&val)); |
181 return v8::Boolean::New(isolate, val); | 181 return v8::Boolean::New(isolate, val); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 return ToArrayBuffer(isolate, | 214 return ToArrayBuffer(isolate, |
215 creation_context, | 215 creation_context, |
216 static_cast<const base::BinaryValue*>(value)); | 216 static_cast<const base::BinaryValue*>(value)); |
217 | 217 |
218 default: | 218 default: |
219 LOG(ERROR) << "Unexpected value type: " << value->GetType(); | 219 LOG(ERROR) << "Unexpected value type: " << value->GetType(); |
220 return v8::Null(isolate); | 220 return v8::Null(isolate); |
221 } | 221 } |
222 } | 222 } |
223 | 223 |
224 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Array( | 224 v8::Local<v8::Value> V8ValueConverterImpl::ToV8Array( |
225 v8::Isolate* isolate, | 225 v8::Isolate* isolate, |
226 v8::Handle<v8::Object> creation_context, | 226 v8::Local<v8::Object> creation_context, |
227 const base::ListValue* val) const { | 227 const base::ListValue* val) const { |
228 v8::Handle<v8::Array> result(v8::Array::New(isolate, val->GetSize())); | 228 v8::Local<v8::Array> result(v8::Array::New(isolate, val->GetSize())); |
229 | 229 |
230 for (size_t i = 0; i < val->GetSize(); ++i) { | 230 for (size_t i = 0; i < val->GetSize(); ++i) { |
231 const base::Value* child = NULL; | 231 const base::Value* child = NULL; |
232 CHECK(val->Get(i, &child)); | 232 CHECK(val->Get(i, &child)); |
233 | 233 |
234 v8::Handle<v8::Value> child_v8 = | 234 v8::Local<v8::Value> child_v8 = |
235 ToV8ValueImpl(isolate, creation_context, child); | 235 ToV8ValueImpl(isolate, creation_context, child); |
236 CHECK(!child_v8.IsEmpty()); | 236 CHECK(!child_v8.IsEmpty()); |
237 | 237 |
238 v8::TryCatch try_catch; | 238 v8::TryCatch try_catch; |
239 result->Set(static_cast<uint32>(i), child_v8); | 239 result->Set(static_cast<uint32>(i), child_v8); |
240 if (try_catch.HasCaught()) | 240 if (try_catch.HasCaught()) |
241 LOG(ERROR) << "Setter for index " << i << " threw an exception."; | 241 LOG(ERROR) << "Setter for index " << i << " threw an exception."; |
242 } | 242 } |
243 | 243 |
244 return result; | 244 return result; |
245 } | 245 } |
246 | 246 |
247 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Object( | 247 v8::Local<v8::Value> V8ValueConverterImpl::ToV8Object( |
248 v8::Isolate* isolate, | 248 v8::Isolate* isolate, |
249 v8::Handle<v8::Object> creation_context, | 249 v8::Local<v8::Object> creation_context, |
250 const base::DictionaryValue* val) const { | 250 const base::DictionaryValue* val) const { |
251 v8::Handle<v8::Object> result(v8::Object::New(isolate)); | 251 v8::Local<v8::Object> result(v8::Object::New(isolate)); |
252 | 252 |
253 for (base::DictionaryValue::Iterator iter(*val); | 253 for (base::DictionaryValue::Iterator iter(*val); |
254 !iter.IsAtEnd(); iter.Advance()) { | 254 !iter.IsAtEnd(); iter.Advance()) { |
255 const std::string& key = iter.key(); | 255 const std::string& key = iter.key(); |
256 v8::Handle<v8::Value> child_v8 = | 256 v8::Local<v8::Value> child_v8 = |
257 ToV8ValueImpl(isolate, creation_context, &iter.value()); | 257 ToV8ValueImpl(isolate, creation_context, &iter.value()); |
258 CHECK(!child_v8.IsEmpty()); | 258 CHECK(!child_v8.IsEmpty()); |
259 | 259 |
260 v8::TryCatch try_catch; | 260 v8::TryCatch try_catch; |
261 result->Set( | 261 result->Set( |
262 v8::String::NewFromUtf8( | 262 v8::String::NewFromUtf8( |
263 isolate, key.c_str(), v8::String::kNormalString, key.length()), | 263 isolate, key.c_str(), v8::String::kNormalString, key.length()), |
264 child_v8); | 264 child_v8); |
265 if (try_catch.HasCaught()) { | 265 if (try_catch.HasCaught()) { |
266 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " | 266 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " |
267 << "exception."; | 267 << "exception."; |
268 } | 268 } |
269 } | 269 } |
270 | 270 |
271 return result; | 271 return result; |
272 } | 272 } |
273 | 273 |
274 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( | 274 v8::Local<v8::Value> V8ValueConverterImpl::ToArrayBuffer( |
275 v8::Isolate* isolate, | 275 v8::Isolate* isolate, |
276 v8::Handle<v8::Object> creation_context, | 276 v8::Local<v8::Object> creation_context, |
277 const base::BinaryValue* value) const { | 277 const base::BinaryValue* value) const { |
278 blink::WebArrayBuffer buffer = | 278 blink::WebArrayBuffer buffer = |
279 blink::WebArrayBuffer::create(value->GetSize(), 1); | 279 blink::WebArrayBuffer::create(value->GetSize(), 1); |
280 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); | 280 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); |
281 return blink::WebArrayBufferConverter::toV8Value( | 281 return blink::WebArrayBufferConverter::toV8Value( |
282 &buffer, creation_context, isolate); | 282 &buffer, creation_context, isolate); |
283 } | 283 } |
284 | 284 |
285 base::Value* V8ValueConverterImpl::FromV8ValueImpl( | 285 base::Value* V8ValueConverterImpl::FromV8ValueImpl( |
286 FromV8ValueState* state, | 286 FromV8ValueState* state, |
287 v8::Handle<v8::Value> val, | 287 v8::Local<v8::Value> val, |
288 v8::Isolate* isolate) const { | 288 v8::Isolate* isolate) const { |
289 CHECK(!val.IsEmpty()); | 289 CHECK(!val.IsEmpty()); |
290 | 290 |
291 FromV8ValueState::Level state_level(state); | 291 FromV8ValueState::Level state_level(state); |
292 if (state->HasReachedMaxRecursionDepth()) | 292 if (state->HasReachedMaxRecursionDepth()) |
293 return NULL; | 293 return NULL; |
294 | 294 |
295 if (val->IsNull()) | 295 if (val->IsNull()) |
296 return base::Value::CreateNullValue(); | 296 return base::Value::CreateNullValue(); |
297 | 297 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 return FromV8ArrayBuffer(val.As<v8::Object>(), isolate); | 360 return FromV8ArrayBuffer(val.As<v8::Object>(), isolate); |
361 | 361 |
362 if (val->IsObject()) | 362 if (val->IsObject()) |
363 return FromV8Object(val.As<v8::Object>(), state, isolate); | 363 return FromV8Object(val.As<v8::Object>(), state, isolate); |
364 | 364 |
365 LOG(ERROR) << "Unexpected v8 value type encountered."; | 365 LOG(ERROR) << "Unexpected v8 value type encountered."; |
366 return NULL; | 366 return NULL; |
367 } | 367 } |
368 | 368 |
369 base::Value* V8ValueConverterImpl::FromV8Array( | 369 base::Value* V8ValueConverterImpl::FromV8Array( |
370 v8::Handle<v8::Array> val, | 370 v8::Local<v8::Array> val, |
371 FromV8ValueState* state, | 371 FromV8ValueState* state, |
372 v8::Isolate* isolate) const { | 372 v8::Isolate* isolate) const { |
373 if (!state->UpdateAndCheckUniqueness(val)) | 373 if (!state->UpdateAndCheckUniqueness(val)) |
374 return base::Value::CreateNullValue(); | 374 return base::Value::CreateNullValue(); |
375 | 375 |
376 scoped_ptr<v8::Context::Scope> scope; | 376 scoped_ptr<v8::Context::Scope> scope; |
377 // If val was created in a different context than our current one, change to | 377 // If val was created in a different context than our current one, change to |
378 // that context, but change back after val is converted. | 378 // that context, but change back after val is converted. |
379 if (!val->CreationContext().IsEmpty() && | 379 if (!val->CreationContext().IsEmpty() && |
380 val->CreationContext() != isolate->GetCurrentContext()) | 380 val->CreationContext() != isolate->GetCurrentContext()) |
381 scope.reset(new v8::Context::Scope(val->CreationContext())); | 381 scope.reset(new v8::Context::Scope(val->CreationContext())); |
382 | 382 |
383 if (strategy_) { | 383 if (strategy_) { |
384 // These base::Unretained's are safe, because Strategy::FromV8Value should | 384 // These base::Unretained's are safe, because Strategy::FromV8Value should |
385 // be synchronous, so this object can't be out of scope. | 385 // be synchronous, so this object can't be out of scope. |
386 V8ValueConverter::Strategy::FromV8ValueCallback callback = | 386 V8ValueConverter::Strategy::FromV8ValueCallback callback = |
387 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, | 387 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, |
388 base::Unretained(this), | 388 base::Unretained(this), |
389 base::Unretained(state)); | 389 base::Unretained(state)); |
390 base::Value* out = NULL; | 390 base::Value* out = NULL; |
391 if (strategy_->FromV8Array(val, &out, isolate, callback)) | 391 if (strategy_->FromV8Array(val, &out, isolate, callback)) |
392 return out; | 392 return out; |
393 } | 393 } |
394 | 394 |
395 base::ListValue* result = new base::ListValue(); | 395 base::ListValue* result = new base::ListValue(); |
396 | 396 |
397 // Only fields with integer keys are carried over to the ListValue. | 397 // Only fields with integer keys are carried over to the ListValue. |
398 for (uint32 i = 0; i < val->Length(); ++i) { | 398 for (uint32 i = 0; i < val->Length(); ++i) { |
399 v8::TryCatch try_catch; | 399 v8::TryCatch try_catch; |
400 v8::Handle<v8::Value> child_v8 = val->Get(i); | 400 v8::Local<v8::Value> child_v8 = val->Get(i); |
401 if (try_catch.HasCaught()) { | 401 if (try_catch.HasCaught()) { |
402 LOG(ERROR) << "Getter for index " << i << " threw an exception."; | 402 LOG(ERROR) << "Getter for index " << i << " threw an exception."; |
403 child_v8 = v8::Null(isolate); | 403 child_v8 = v8::Null(isolate); |
404 } | 404 } |
405 | 405 |
406 if (!val->HasRealIndexedProperty(i)) { | 406 if (!val->HasRealIndexedProperty(i)) { |
407 result->Append(base::Value::CreateNullValue()); | 407 result->Append(base::Value::CreateNullValue()); |
408 continue; | 408 continue; |
409 } | 409 } |
410 | 410 |
411 base::Value* child = FromV8ValueImpl(state, child_v8, isolate); | 411 base::Value* child = FromV8ValueImpl(state, child_v8, isolate); |
412 if (child) | 412 if (child) |
413 result->Append(child); | 413 result->Append(child); |
414 else | 414 else |
415 // JSON.stringify puts null in places where values don't serialize, for | 415 // JSON.stringify puts null in places where values don't serialize, for |
416 // example undefined and functions. Emulate that behavior. | 416 // example undefined and functions. Emulate that behavior. |
417 result->Append(base::Value::CreateNullValue()); | 417 result->Append(base::Value::CreateNullValue()); |
418 } | 418 } |
419 return result; | 419 return result; |
420 } | 420 } |
421 | 421 |
422 base::Value* V8ValueConverterImpl::FromV8ArrayBuffer( | 422 base::Value* V8ValueConverterImpl::FromV8ArrayBuffer( |
423 v8::Handle<v8::Object> val, | 423 v8::Local<v8::Object> val, |
424 v8::Isolate* isolate) const { | 424 v8::Isolate* isolate) const { |
425 if (strategy_) { | 425 if (strategy_) { |
426 base::Value* out = NULL; | 426 base::Value* out = NULL; |
427 if (strategy_->FromV8ArrayBuffer(val, &out, isolate)) | 427 if (strategy_->FromV8ArrayBuffer(val, &out, isolate)) |
428 return out; | 428 return out; |
429 } | 429 } |
430 | 430 |
431 char* data = NULL; | 431 char* data = NULL; |
432 size_t length = 0; | 432 size_t length = 0; |
433 | 433 |
(...skipping 11 matching lines...) Expand all Loading... |
445 } | 445 } |
446 } | 446 } |
447 | 447 |
448 if (data) | 448 if (data) |
449 return base::BinaryValue::CreateWithCopiedBuffer(data, length); | 449 return base::BinaryValue::CreateWithCopiedBuffer(data, length); |
450 else | 450 else |
451 return NULL; | 451 return NULL; |
452 } | 452 } |
453 | 453 |
454 base::Value* V8ValueConverterImpl::FromV8Object( | 454 base::Value* V8ValueConverterImpl::FromV8Object( |
455 v8::Handle<v8::Object> val, | 455 v8::Local<v8::Object> val, |
456 FromV8ValueState* state, | 456 FromV8ValueState* state, |
457 v8::Isolate* isolate) const { | 457 v8::Isolate* isolate) const { |
458 if (!state->UpdateAndCheckUniqueness(val)) | 458 if (!state->UpdateAndCheckUniqueness(val)) |
459 return base::Value::CreateNullValue(); | 459 return base::Value::CreateNullValue(); |
460 | 460 |
461 scoped_ptr<v8::Context::Scope> scope; | 461 scoped_ptr<v8::Context::Scope> scope; |
462 // If val was created in a different context than our current one, change to | 462 // If val was created in a different context than our current one, change to |
463 // that context, but change back after val is converted. | 463 // that context, but change back after val is converted. |
464 if (!val->CreationContext().IsEmpty() && | 464 if (!val->CreationContext().IsEmpty() && |
465 val->CreationContext() != isolate->GetCurrentContext()) | 465 val->CreationContext() != isolate->GetCurrentContext()) |
(...skipping 21 matching lines...) Expand all Loading... |
487 // | 487 // |
488 // NOTE: check this after |strategy_| so that callers have a chance to | 488 // NOTE: check this after |strategy_| so that callers have a chance to |
489 // do something else, such as convert to the node's name rather than NULL. | 489 // do something else, such as convert to the node's name rather than NULL. |
490 // | 490 // |
491 // ANOTHER NOTE: returning an empty dictionary here to minimise surprise. | 491 // ANOTHER NOTE: returning an empty dictionary here to minimise surprise. |
492 // See also http://crbug.com/330559. | 492 // See also http://crbug.com/330559. |
493 if (val->InternalFieldCount()) | 493 if (val->InternalFieldCount()) |
494 return new base::DictionaryValue(); | 494 return new base::DictionaryValue(); |
495 | 495 |
496 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 496 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
497 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); | 497 v8::Local<v8::Array> property_names(val->GetOwnPropertyNames()); |
498 | 498 |
499 for (uint32 i = 0; i < property_names->Length(); ++i) { | 499 for (uint32 i = 0; i < property_names->Length(); ++i) { |
500 v8::Handle<v8::Value> key(property_names->Get(i)); | 500 v8::Local<v8::Value> key(property_names->Get(i)); |
501 | 501 |
502 // Extend this test to cover more types as necessary and if sensible. | 502 // Extend this test to cover more types as necessary and if sensible. |
503 if (!key->IsString() && | 503 if (!key->IsString() && |
504 !key->IsNumber()) { | 504 !key->IsNumber()) { |
505 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " | 505 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " |
506 "is neither a string nor a number"; | 506 "is neither a string nor a number"; |
507 continue; | 507 continue; |
508 } | 508 } |
509 | 509 |
510 v8::String::Utf8Value name_utf8(key); | 510 v8::String::Utf8Value name_utf8(key); |
511 | 511 |
512 v8::TryCatch try_catch; | 512 v8::TryCatch try_catch; |
513 v8::Handle<v8::Value> child_v8 = val->Get(key); | 513 v8::Local<v8::Value> child_v8 = val->Get(key); |
514 | 514 |
515 if (try_catch.HasCaught()) { | 515 if (try_catch.HasCaught()) { |
516 LOG(WARNING) << "Getter for property " << *name_utf8 | 516 LOG(WARNING) << "Getter for property " << *name_utf8 |
517 << " threw an exception."; | 517 << " threw an exception."; |
518 child_v8 = v8::Null(isolate); | 518 child_v8 = v8::Null(isolate); |
519 } | 519 } |
520 | 520 |
521 scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate)); | 521 scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate)); |
522 if (!child) | 522 if (!child) |
523 // JSON.stringify skips properties whose values don't serialize, for | 523 // JSON.stringify skips properties whose values don't serialize, for |
(...skipping 24 matching lines...) Expand all Loading... |
548 continue; | 548 continue; |
549 | 549 |
550 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), | 550 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), |
551 child.release()); | 551 child.release()); |
552 } | 552 } |
553 | 553 |
554 return result.release(); | 554 return result.release(); |
555 } | 555 } |
556 | 556 |
557 } // namespace content | 557 } // namespace content |
OLD | NEW |