Chromium Code Reviews
[email protected] (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(503)

Side by Side Diff: content/renderer/v8_value_converter_impl.cc

Issue 12633013: Improve the v8::Object uniqueness check in V8ValueConverterImpl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
OLDNEW
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/renderer/v8_value_converter_impl.h" 5 #include "content/renderer/v8_value_converter_impl.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 v8::Context::Scope context_scope(context); 47 v8::Context::Scope context_scope(context);
48 v8::HandleScope handle_scope; 48 v8::HandleScope handle_scope;
49 return handle_scope.Close(ToV8ValueImpl(value)); 49 return handle_scope.Close(ToV8ValueImpl(value));
50 } 50 }
51 51
52 Value* V8ValueConverterImpl::FromV8Value( 52 Value* V8ValueConverterImpl::FromV8Value(
53 v8::Handle<v8::Value> val, 53 v8::Handle<v8::Value> val,
54 v8::Handle<v8::Context> context) const { 54 v8::Handle<v8::Context> context) const {
55 v8::Context::Scope context_scope(context); 55 v8::Context::Scope context_scope(context);
56 v8::HandleScope handle_scope; 56 v8::HandleScope handle_scope;
57 std::set<int> unique_set; 57 HashToHandleMap unique_map;
58 return FromV8ValueImpl(val, &unique_set); 58 return FromV8ValueImpl(val, &unique_map);
59 } 59 }
60 60
61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( 61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
62 const base::Value* value) const { 62 const base::Value* value) const {
63 CHECK(value); 63 CHECK(value);
64 switch (value->GetType()) { 64 switch (value->GetType()) {
65 case base::Value::TYPE_NULL: 65 case base::Value::TYPE_NULL:
66 return v8::Null(); 66 return v8::Null();
67 67
68 case base::Value::TYPE_BOOLEAN: { 68 case base::Value::TYPE_BOOLEAN: {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 147
148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( 148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
149 const base::BinaryValue* value) const { 149 const base::BinaryValue* value) const {
150 WebKit::WebArrayBuffer buffer = 150 WebKit::WebArrayBuffer buffer =
151 WebKit::WebArrayBuffer::create(value->GetSize(), 1); 151 WebKit::WebArrayBuffer::create(value->GetSize(), 1);
152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); 152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize());
153 return buffer.toV8Value(); 153 return buffer.toV8Value();
154 } 154 }
155 155
156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, 156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val,
157 std::set<int>* unique_set) const { 157 HashToHandleMap* unique_map) const {
158 CHECK(!val.IsEmpty()); 158 CHECK(!val.IsEmpty());
159 159
160 if (val->IsNull()) 160 if (val->IsNull())
161 return base::Value::CreateNullValue(); 161 return base::Value::CreateNullValue();
162 162
163 if (val->IsBoolean()) 163 if (val->IsBoolean())
164 return new base::FundamentalValue(val->ToBoolean()->Value()); 164 return new base::FundamentalValue(val->ToBoolean()->Value());
165 165
166 if (val->IsInt32()) 166 if (val->IsInt32())
167 return new base::FundamentalValue(val->ToInt32()->Value()); 167 return new base::FundamentalValue(val->ToInt32()->Value());
168 168
169 if (val->IsNumber()) 169 if (val->IsNumber())
170 return new base::FundamentalValue(val->ToNumber()->Value()); 170 return new base::FundamentalValue(val->ToNumber()->Value());
171 171
172 if (val->IsString()) { 172 if (val->IsString()) {
173 v8::String::Utf8Value utf8(val->ToString()); 173 v8::String::Utf8Value utf8(val->ToString());
174 return new base::StringValue(std::string(*utf8, utf8.length())); 174 return new base::StringValue(std::string(*utf8, utf8.length()));
175 } 175 }
176 176
177 if (val->IsUndefined()) 177 if (val->IsUndefined())
178 // JSON.stringify ignores undefined. 178 // JSON.stringify ignores undefined.
179 return NULL; 179 return NULL;
180 180
181 if (val->IsDate()) { 181 if (val->IsDate()) {
182 if (!date_allowed_) 182 if (!date_allowed_)
183 // JSON.stringify would convert this to a string, but an object is more 183 // JSON.stringify would convert this to a string, but an object is more
184 // consistent within this class. 184 // consistent within this class.
185 return FromV8Object(val->ToObject(), unique_set); 185 return FromV8Object(val->ToObject(), unique_map);
186 v8::Date* date = v8::Date::Cast(*val); 186 v8::Date* date = v8::Date::Cast(*val);
187 return new base::FundamentalValue(date->NumberValue() / 1000.0); 187 return new base::FundamentalValue(date->NumberValue() / 1000.0);
188 } 188 }
189 189
190 if (val->IsRegExp()) { 190 if (val->IsRegExp()) {
191 if (!reg_exp_allowed_) 191 if (!reg_exp_allowed_)
192 // JSON.stringify converts to an object. 192 // JSON.stringify converts to an object.
193 return FromV8Object(val->ToObject(), unique_set); 193 return FromV8Object(val->ToObject(), unique_map);
194 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); 194 return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
195 } 195 }
196 196
197 // v8::Value doesn't have a ToArray() method for some reason. 197 // v8::Value doesn't have a ToArray() method for some reason.
198 if (val->IsArray()) 198 if (val->IsArray())
199 return FromV8Array(val.As<v8::Array>(), unique_set); 199 return FromV8Array(val.As<v8::Array>(), unique_map);
200 200
201 if (val->IsFunction()) { 201 if (val->IsFunction()) {
202 if (!function_allowed_) 202 if (!function_allowed_)
203 // JSON.stringify refuses to convert function(){}. 203 // JSON.stringify refuses to convert function(){}.
204 return NULL; 204 return NULL;
205 return FromV8Object(val->ToObject(), unique_set); 205 return FromV8Object(val->ToObject(), unique_map);
206 } 206 }
207 207
208 if (val->IsObject()) { 208 if (val->IsObject()) {
209 base::BinaryValue* binary_value = FromV8Buffer(val); 209 base::BinaryValue* binary_value = FromV8Buffer(val);
210 if (binary_value) { 210 if (binary_value) {
211 return binary_value; 211 return binary_value;
212 } else { 212 } else {
213 return FromV8Object(val->ToObject(), unique_set); 213 return FromV8Object(val->ToObject(), unique_map);
214 } 214 }
215 } 215 }
216 216
217 LOG(ERROR) << "Unexpected v8 value type encountered."; 217 LOG(ERROR) << "Unexpected v8 value type encountered.";
218 return NULL; 218 return NULL;
219 } 219 }
220 220
221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, 221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val,
222 std::set<int>* unique_set) const { 222 HashToHandleMap* unique_map) const {
223 if (unique_set && unique_set->count(val->GetIdentityHash())) 223 if (!UpdateAndCheckUniqueness(unique_map, v8::Handle<v8::Array>::Cast(val)))
eaugusti 2013/03/14 17:21:09 Why the cast? Is it necessary?
vabr (Chromium) 2013/03/14 17:59:37 It was not! Thanks. :)
224 return base::Value::CreateNullValue(); 224 return base::Value::CreateNullValue();
225 225
226 scoped_ptr<v8::Context::Scope> scope; 226 scoped_ptr<v8::Context::Scope> scope;
227 // If val was created in a different context than our current one, change to 227 // If val was created in a different context than our current one, change to
228 // that context, but change back after val is converted. 228 // that context, but change back after val is converted.
229 if (!val->CreationContext().IsEmpty() && 229 if (!val->CreationContext().IsEmpty() &&
230 val->CreationContext() != v8::Context::GetCurrent()) 230 val->CreationContext() != v8::Context::GetCurrent())
231 scope.reset(new v8::Context::Scope(val->CreationContext())); 231 scope.reset(new v8::Context::Scope(val->CreationContext()));
232 232
233 base::ListValue* result = new base::ListValue(); 233 base::ListValue* result = new base::ListValue();
234 234
235 if (unique_set)
236 unique_set->insert(val->GetIdentityHash());
237 // Only fields with integer keys are carried over to the ListValue. 235 // Only fields with integer keys are carried over to the ListValue.
238 for (uint32 i = 0; i < val->Length(); ++i) { 236 for (uint32 i = 0; i < val->Length(); ++i) {
239 v8::TryCatch try_catch; 237 v8::TryCatch try_catch;
240 v8::Handle<v8::Value> child_v8 = val->Get(i); 238 v8::Handle<v8::Value> child_v8 = val->Get(i);
241 if (try_catch.HasCaught()) { 239 if (try_catch.HasCaught()) {
242 LOG(ERROR) << "Getter for index " << i << " threw an exception."; 240 LOG(ERROR) << "Getter for index " << i << " threw an exception.";
243 child_v8 = v8::Null(); 241 child_v8 = v8::Null();
244 } 242 }
245 243
246 if (!val->HasRealIndexedProperty(i)) 244 if (!val->HasRealIndexedProperty(i))
247 continue; 245 continue;
248 246
249 base::Value* child = FromV8ValueImpl(child_v8, unique_set); 247 base::Value* child = FromV8ValueImpl(child_v8, unique_map);
250 if (child) 248 if (child)
251 result->Append(child); 249 result->Append(child);
252 else 250 else
253 // JSON.stringify puts null in places where values don't serialize, for 251 // JSON.stringify puts null in places where values don't serialize, for
254 // example undefined and functions. Emulate that behavior. 252 // example undefined and functions. Emulate that behavior.
255 result->Append(base::Value::CreateNullValue()); 253 result->Append(base::Value::CreateNullValue());
256 } 254 }
257 return result; 255 return result;
258 } 256 }
259 257
(...skipping 17 matching lines...) Expand all
277 } 275 }
278 276
279 if (data) 277 if (data)
280 return base::BinaryValue::CreateWithCopiedBuffer(data, length); 278 return base::BinaryValue::CreateWithCopiedBuffer(data, length);
281 else 279 else
282 return NULL; 280 return NULL;
283 } 281 }
284 282
285 Value* V8ValueConverterImpl::FromV8Object( 283 Value* V8ValueConverterImpl::FromV8Object(
286 v8::Handle<v8::Object> val, 284 v8::Handle<v8::Object> val,
287 std::set<int>* unique_set) const { 285 HashToHandleMap* unique_map) const {
288 if (unique_set && unique_set->count(val->GetIdentityHash())) 286 if (!UpdateAndCheckUniqueness(unique_map, val))
289 return base::Value::CreateNullValue(); 287 return base::Value::CreateNullValue();
290 scoped_ptr<v8::Context::Scope> scope; 288 scoped_ptr<v8::Context::Scope> scope;
291 // If val was created in a different context than our current one, change to 289 // If val was created in a different context than our current one, change to
292 // that context, but change back after val is converted. 290 // that context, but change back after val is converted.
293 if (!val->CreationContext().IsEmpty() && 291 if (!val->CreationContext().IsEmpty() &&
294 val->CreationContext() != v8::Context::GetCurrent()) 292 val->CreationContext() != v8::Context::GetCurrent())
295 scope.reset(new v8::Context::Scope(val->CreationContext())); 293 scope.reset(new v8::Context::Scope(val->CreationContext()));
296 294
297 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 295 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
298 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); 296 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames());
299 297
300 if (unique_set)
301 unique_set->insert(val->GetIdentityHash());
302
303 for (uint32 i = 0; i < property_names->Length(); ++i) { 298 for (uint32 i = 0; i < property_names->Length(); ++i) {
304 v8::Handle<v8::Value> key(property_names->Get(i)); 299 v8::Handle<v8::Value> key(property_names->Get(i));
305 300
306 // Extend this test to cover more types as necessary and if sensible. 301 // Extend this test to cover more types as necessary and if sensible.
307 if (!key->IsString() && 302 if (!key->IsString() &&
308 !key->IsNumber()) { 303 !key->IsNumber()) {
309 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " 304 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" "
310 "is neither a string nor a number"; 305 "is neither a string nor a number";
311 continue; 306 continue;
312 } 307 }
313 308
314 // Skip all callbacks: crbug.com/139933 309 // Skip all callbacks: crbug.com/139933
315 if (val->HasRealNamedCallbackProperty(key->ToString())) 310 if (val->HasRealNamedCallbackProperty(key->ToString()))
316 continue; 311 continue;
317 312
318 v8::String::Utf8Value name_utf8(key->ToString()); 313 v8::String::Utf8Value name_utf8(key->ToString());
319 314
320 v8::TryCatch try_catch; 315 v8::TryCatch try_catch;
321 v8::Handle<v8::Value> child_v8 = val->Get(key); 316 v8::Handle<v8::Value> child_v8 = val->Get(key);
322 317
323 if (try_catch.HasCaught()) { 318 if (try_catch.HasCaught()) {
324 LOG(ERROR) << "Getter for property " << *name_utf8 319 LOG(ERROR) << "Getter for property " << *name_utf8
325 << " threw an exception."; 320 << " threw an exception.";
326 child_v8 = v8::Null(); 321 child_v8 = v8::Null();
327 } 322 }
328 323
329 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_set)); 324 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map));
330 if (!child.get()) 325 if (!child.get())
331 // JSON.stringify skips properties whose values don't serialize, for 326 // JSON.stringify skips properties whose values don't serialize, for
332 // example undefined and functions. Emulate that behavior. 327 // example undefined and functions. Emulate that behavior.
333 continue; 328 continue;
334 329
335 // Strip null if asked (and since undefined is turned into null, undefined 330 // Strip null if asked (and since undefined is turned into null, undefined
336 // too). The use case for supporting this is JSON-schema support, 331 // too). The use case for supporting this is JSON-schema support,
337 // specifically for extensions, where "optional" JSON properties may be 332 // specifically for extensions, where "optional" JSON properties may be
338 // represented as null, yet due to buggy legacy code elsewhere isn't 333 // represented as null, yet due to buggy legacy code elsewhere isn't
339 // treated as such (potentially causing crashes). For example, the 334 // treated as such (potentially causing crashes). For example, the
(...skipping 15 matching lines...) Expand all
355 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) 350 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL))
356 continue; 351 continue;
357 352
358 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), 353 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
359 child.release()); 354 child.release());
360 } 355 }
361 356
362 return result.release(); 357 return result.release();
363 } 358 }
364 359
360 // static
361 bool V8ValueConverterImpl::UpdateAndCheckUniqueness(
eaugusti 2013/03/14 17:21:09 Maybe add a comment about how uniqueness is define
vabr (Chromium) 2013/03/14 17:59:37 Done. I added a comment about the uniqueness to th
362 HashToHandleMap* map,
363 v8::Handle<v8::Object> handle) {
364 typedef HashToHandleMap::const_iterator Iterator;
365
366 int hash = handle->GetIdentityHash();
367 std::pair<Iterator, Iterator> range = map->equal_range(hash);
368 bool found = false;
369 for (Iterator it = range.first; !false && it != range.second; ++it) {
eaugusti 2013/03/14 17:21:09 Why the "!false"?
vabr (Chromium) 2013/03/14 17:59:37 Thanks for catching that, was meant to be !found.
370 found |= it->second == handle;
371 }
eaugusti 2013/03/14 17:21:09 nit: drop the braces on the for.
vabr (Chromium) 2013/03/14 17:59:37 No longer can due to the added comment.
372
373 if (found)
374 return false;
375
376 map->insert(std::pair<int, v8::Handle<v8::Object> >(hash, handle));
377 return true;
378 }
379
365 } // namespace content 380 } // namespace content
OLDNEW
« content/renderer/v8_value_converter_impl.h ('K') | « content/renderer/v8_value_converter_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698