| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project 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 "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
| 8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
| 9 #include "src/debug.h" | 9 #include "src/debug.h" |
| 10 #include "src/messages.h" | 10 #include "src/messages.h" |
| 11 #include "src/runtime/runtime.h" | 11 #include "src/runtime/runtime.h" |
| 12 #include "src/runtime/runtime-utils.h" | 12 #include "src/runtime/runtime-utils.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 // Returns a single character string where first character equals | 17 // Returns a single character string where first character equals |
| 18 // string->Get(index). | 18 // string->Get(index). |
| 19 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 19 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
| 20 DCHECK_LT(index, static_cast<uint32_t>(string->length())); | 20 DCHECK_LT(index, static_cast<uint32_t>(string->length())); |
| 21 Factory* factory = string->GetIsolate()->factory(); | 21 Factory* factory = string->GetIsolate()->factory(); |
| 22 return factory->LookupSingleCharacterStringFromCode( | 22 return factory->LookupSingleCharacterStringFromCode( |
| 23 String::Flatten(string)->Get(index)); | 23 String::Flatten(string)->Get(index)); |
| 24 } | 24 } |
| 25 | 25 |
| 26 | 26 |
| 27 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, | 27 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, |
| 28 Handle<Object> object, | 28 Handle<Object> object, |
| 29 uint32_t index) { | 29 uint32_t index, |
| 30 LanguageMode language_mode) { |
| 30 // Handle [] indexing on Strings | 31 // Handle [] indexing on Strings |
| 31 if (object->IsString() && | 32 if (object->IsString() && |
| 32 index < static_cast<uint32_t>(String::cast(*object)->length())) { | 33 index < static_cast<uint32_t>(String::cast(*object)->length())) { |
| 33 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 34 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
| 34 if (!result->IsUndefined()) return result; | 35 if (!result->IsUndefined()) return result; |
| 35 } | 36 } |
| 36 | 37 |
| 37 return Object::GetElement(isolate, object, index); | 38 return Object::GetElement(isolate, object, index, language_mode); |
| 38 } | 39 } |
| 39 | 40 |
| 40 | 41 |
| 41 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) { | 42 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) { |
| 42 if (key->IsName()) { | 43 if (key->IsName()) { |
| 43 return Handle<Name>::cast(key); | 44 return Handle<Name>::cast(key); |
| 44 } else { | 45 } else { |
| 45 Handle<Object> converted; | 46 Handle<Object> converted; |
| 46 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, | 47 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, |
| 47 Execution::ToString(isolate, key), Name); | 48 Execution::ToString(isolate, key), Name); |
| 48 return Handle<Name>::cast(converted); | 49 return Handle<Name>::cast(converted); |
| 49 } | 50 } |
| 50 } | 51 } |
| 51 | 52 |
| 52 | 53 |
| 53 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, | 54 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
| 54 Handle<Object> object, | 55 Handle<Object> object, |
| 55 Handle<Object> key) { | 56 Handle<Object> key, |
| 57 LanguageMode language_mode) { |
| 56 if (object->IsUndefined() || object->IsNull()) { | 58 if (object->IsUndefined() || object->IsNull()) { |
| 57 THROW_NEW_ERROR( | 59 THROW_NEW_ERROR( |
| 58 isolate, | 60 isolate, |
| 59 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), | 61 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), |
| 60 Object); | 62 Object); |
| 61 } | 63 } |
| 62 | 64 |
| 63 // Check if the given key is an array index. | 65 // Check if the given key is an array index. |
| 64 uint32_t index = 0; | 66 uint32_t index = 0; |
| 65 if (key->ToArrayIndex(&index)) { | 67 if (key->ToArrayIndex(&index)) { |
| 66 return GetElementOrCharAt(isolate, object, index); | 68 return GetElementOrCharAt(isolate, object, index, language_mode); |
| 67 } | 69 } |
| 68 | 70 |
| 69 // Convert the key to a name - possibly by calling back into JavaScript. | 71 // Convert the key to a name - possibly by calling back into JavaScript. |
| 70 Handle<Name> name; | 72 Handle<Name> name; |
| 71 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); | 73 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); |
| 72 | 74 |
| 73 // Check if the name is trivially convertible to an index and get | 75 // Check if the name is trivially convertible to an index and get |
| 74 // the element if so. | 76 // the element if so. |
| 75 // TODO(verwaest): Make sure GetProperty(LookupIterator*) can handle this, and | 77 // TODO(verwaest): Make sure GetProperty(LookupIterator*) can handle this, and |
| 76 // remove the special casing here. | 78 // remove the special casing here. |
| 77 if (name->AsArrayIndex(&index)) { | 79 if (name->AsArrayIndex(&index)) { |
| 78 return GetElementOrCharAt(isolate, object, index); | 80 return GetElementOrCharAt(isolate, object, index); |
| 79 } else { | 81 } else { |
| 80 return Object::GetProperty(object, name); | 82 return Object::GetProperty(object, name, language_mode); |
| 81 } | 83 } |
| 82 } | 84 } |
| 83 | 85 |
| 84 | 86 |
| 87 MaybeHandle<Object> Runtime::KeyedGetObjectProperty( |
| 88 Isolate* isolate, Handle<Object> receiver_obj, Handle<Object> key_obj, |
| 89 LanguageMode language_mode) { |
| 90 // Fast cases for getting named properties of the receiver JSObject |
| 91 // itself. |
| 92 // |
| 93 // The global proxy objects has to be excluded since LookupOwn on |
| 94 // the global proxy object can return a valid result even though the |
| 95 // global proxy object never has properties. This is the case |
| 96 // because the global proxy object forwards everything to its hidden |
| 97 // prototype including own lookups. |
| 98 // |
| 99 // Additionally, we need to make sure that we do not cache results |
| 100 // for objects that require access checks. |
| 101 if (receiver_obj->IsJSObject()) { |
| 102 if (!receiver_obj->IsJSGlobalProxy() && |
| 103 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { |
| 104 DisallowHeapAllocation no_allocation; |
| 105 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); |
| 106 Handle<Name> key = Handle<Name>::cast(key_obj); |
| 107 if (receiver->IsGlobalObject()) { |
| 108 // Attempt dictionary lookup. |
| 109 GlobalDictionary* dictionary = receiver->global_dictionary(); |
| 110 int entry = dictionary->FindEntry(key); |
| 111 if (entry != GlobalDictionary::kNotFound) { |
| 112 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); |
| 113 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); |
| 114 if (cell->property_details().type() == DATA) { |
| 115 Object* value = cell->value(); |
| 116 if (!value->IsTheHole()) return Handle<Object>(value, isolate); |
| 117 // If value is the hole (meaning, absent) do the general lookup. |
| 118 } |
| 119 } |
| 120 } else if (!receiver->HasFastProperties()) { |
| 121 // Attempt dictionary lookup. |
| 122 NameDictionary* dictionary = receiver->property_dictionary(); |
| 123 int entry = dictionary->FindEntry(key); |
| 124 if ((entry != NameDictionary::kNotFound) && |
| 125 (dictionary->DetailsAt(entry).type() == DATA)) { |
| 126 Object* value = dictionary->ValueAt(entry); |
| 127 return Handle<Object>(value, isolate); |
| 128 } |
| 129 } |
| 130 } else if (key_obj->IsSmi()) { |
| 131 // JSObject without a name key. If the key is a Smi, check for a |
| 132 // definite out-of-bounds access to elements, which is a strong indicator |
| 133 // that subsequent accesses will also call the runtime. Proactively |
| 134 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of |
| 135 // doubles for those future calls in the case that the elements would |
| 136 // become FAST_DOUBLE_ELEMENTS. |
| 137 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); |
| 138 ElementsKind elements_kind = js_object->GetElementsKind(); |
| 139 if (IsFastDoubleElementsKind(elements_kind)) { |
| 140 if (Smi::cast(*key_obj)->value() >= js_object->elements()->length()) { |
| 141 elements_kind = IsFastHoleyElementsKind(elements_kind) |
| 142 ? FAST_HOLEY_ELEMENTS |
| 143 : FAST_ELEMENTS; |
| 144 JSObject::TransitionElementsKind(js_object, elements_kind); |
| 145 } |
| 146 } else { |
| 147 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
| 148 !IsFastElementsKind(elements_kind)); |
| 149 } |
| 150 } |
| 151 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { |
| 152 // Fast case for string indexing using [] with a smi index. |
| 153 Handle<String> str = Handle<String>::cast(receiver_obj); |
| 154 int index = Handle<Smi>::cast(key_obj)->value(); |
| 155 if (index >= 0 && index < str->length()) { |
| 156 return GetCharAt(str, index); |
| 157 } |
| 158 } |
| 159 |
| 160 // Fall back to GetObjectProperty. |
| 161 return GetObjectProperty(isolate, receiver_obj, key_obj, language_mode); |
| 162 } |
| 163 |
| 164 |
| 85 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, | 165 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
| 86 Handle<Object> object, | 166 Handle<Object> object, |
| 87 Handle<Object> key, | 167 Handle<Object> key, |
| 88 Handle<Object> value, | 168 Handle<Object> value, |
| 89 LanguageMode language_mode) { | 169 LanguageMode language_mode) { |
| 90 if (object->IsUndefined() || object->IsNull()) { | 170 if (object->IsUndefined() || object->IsNull()) { |
| 91 THROW_NEW_ERROR( | 171 THROW_NEW_ERROR( |
| 92 isolate, | 172 isolate, |
| 93 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), | 173 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
| 94 Object); | 174 Object); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 return *result; | 460 return *result; |
| 381 } | 461 } |
| 382 | 462 |
| 383 | 463 |
| 384 RUNTIME_FUNCTION(Runtime_GetProperty) { | 464 RUNTIME_FUNCTION(Runtime_GetProperty) { |
| 385 HandleScope scope(isolate); | 465 HandleScope scope(isolate); |
| 386 DCHECK(args.length() == 2); | 466 DCHECK(args.length() == 2); |
| 387 | 467 |
| 388 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | 468 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| 389 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | 469 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| 470 |
| 390 Handle<Object> result; | 471 Handle<Object> result; |
| 391 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 472 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 392 isolate, result, Runtime::GetObjectProperty(isolate, object, key)); | 473 isolate, result, |
| 474 Runtime::GetObjectProperty(isolate, object, key, SLOPPY)); |
| 393 return *result; | 475 return *result; |
| 394 } | 476 } |
| 395 | 477 |
| 478 |
| 479 RUNTIME_FUNCTION(Runtime_GetPropertyStrong) { |
| 480 HandleScope scope(isolate); |
| 481 DCHECK(args.length() == 2); |
| 482 |
| 483 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| 484 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| 485 |
| 486 Handle<Object> result; |
| 487 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 488 isolate, result, |
| 489 Runtime::GetObjectProperty(isolate, object, key, STRONG)); |
| 490 return *result; |
| 491 } |
| 492 |
| 396 | 493 |
| 397 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. | 494 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. |
| 398 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { | 495 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
| 399 HandleScope scope(isolate); | 496 HandleScope scope(isolate); |
| 400 DCHECK(args.length() == 2); | 497 DCHECK(args.length() == 2); |
| 401 | 498 |
| 402 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); | 499 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
| 403 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); | 500 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
| 404 | 501 |
| 405 // Fast cases for getting named properties of the receiver JSObject | |
| 406 // itself. | |
| 407 // | |
| 408 // The global proxy objects has to be excluded since LookupOwn on | |
| 409 // the global proxy object can return a valid result even though the | |
| 410 // global proxy object never has properties. This is the case | |
| 411 // because the global proxy object forwards everything to its hidden | |
| 412 // prototype including own lookups. | |
| 413 // | |
| 414 // Additionally, we need to make sure that we do not cache results | |
| 415 // for objects that require access checks. | |
| 416 if (receiver_obj->IsJSObject()) { | |
| 417 if (!receiver_obj->IsJSGlobalProxy() && | |
| 418 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { | |
| 419 DisallowHeapAllocation no_allocation; | |
| 420 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); | |
| 421 Handle<Name> key = Handle<Name>::cast(key_obj); | |
| 422 if (receiver->IsGlobalObject()) { | |
| 423 // Attempt dictionary lookup. | |
| 424 GlobalDictionary* dictionary = receiver->global_dictionary(); | |
| 425 int entry = dictionary->FindEntry(key); | |
| 426 if (entry != GlobalDictionary::kNotFound) { | |
| 427 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); | |
| 428 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); | |
| 429 if (cell->property_details().type() == DATA) { | |
| 430 Object* value = cell->value(); | |
| 431 if (!value->IsTheHole()) return value; | |
| 432 // If value is the hole (meaning, absent) do the general lookup. | |
| 433 } | |
| 434 } | |
| 435 } else if (!receiver->HasFastProperties()) { | |
| 436 // Attempt dictionary lookup. | |
| 437 NameDictionary* dictionary = receiver->property_dictionary(); | |
| 438 int entry = dictionary->FindEntry(key); | |
| 439 if ((entry != NameDictionary::kNotFound) && | |
| 440 (dictionary->DetailsAt(entry).type() == DATA)) { | |
| 441 Object* value = dictionary->ValueAt(entry); | |
| 442 return value; | |
| 443 } | |
| 444 } | |
| 445 } else if (key_obj->IsSmi()) { | |
| 446 // JSObject without a name key. If the key is a Smi, check for a | |
| 447 // definite out-of-bounds access to elements, which is a strong indicator | |
| 448 // that subsequent accesses will also call the runtime. Proactively | |
| 449 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of | |
| 450 // doubles for those future calls in the case that the elements would | |
| 451 // become FAST_DOUBLE_ELEMENTS. | |
| 452 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); | |
| 453 ElementsKind elements_kind = js_object->GetElementsKind(); | |
| 454 if (IsFastDoubleElementsKind(elements_kind)) { | |
| 455 if (Smi::cast(*key_obj)->value() >= js_object->elements()->length()) { | |
| 456 elements_kind = IsFastHoleyElementsKind(elements_kind) | |
| 457 ? FAST_HOLEY_ELEMENTS | |
| 458 : FAST_ELEMENTS; | |
| 459 JSObject::TransitionElementsKind(js_object, elements_kind); | |
| 460 } | |
| 461 } else { | |
| 462 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
| 463 !IsFastElementsKind(elements_kind)); | |
| 464 } | |
| 465 } | |
| 466 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { | |
| 467 // Fast case for string indexing using [] with a smi index. | |
| 468 Handle<String> str = Handle<String>::cast(receiver_obj); | |
| 469 int index = args.smi_at(1); | |
| 470 if (index >= 0 && index < str->length()) { | |
| 471 return *GetCharAt(str, index); | |
| 472 } | |
| 473 } | |
| 474 | |
| 475 // Fall back to GetObjectProperty. | |
| 476 Handle<Object> result; | 502 Handle<Object> result; |
| 477 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 503 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 478 isolate, result, | 504 isolate, result, |
| 479 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); | 505 Runtime::KeyedGetObjectProperty(isolate, receiver_obj, key_obj, SLOPPY)); |
| 480 return *result; | 506 return *result; |
| 481 } | 507 } |
| 482 | 508 |
| 509 |
| 510 RUNTIME_FUNCTION(Runtime_KeyedGetPropertyStrong) { |
| 511 HandleScope scope(isolate); |
| 512 DCHECK(args.length() == 2); |
| 513 |
| 514 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
| 515 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
| 516 |
| 517 Handle<Object> result; |
| 518 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 519 isolate, result, |
| 520 Runtime::KeyedGetObjectProperty(isolate, receiver_obj, key_obj, STRONG)); |
| 521 return *result; |
| 522 } |
| 523 |
| 483 | 524 |
| 484 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { | 525 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { |
| 485 HandleScope scope(isolate); | 526 HandleScope scope(isolate); |
| 486 RUNTIME_ASSERT(args.length() == 4); | 527 RUNTIME_ASSERT(args.length() == 4); |
| 487 | 528 |
| 488 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 529 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| 489 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | 530 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| 490 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | 531 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| 491 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 532 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
| 492 | 533 |
| (...skipping 910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 1444 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
| 1404 | 1445 |
| 1405 RETURN_FAILURE_ON_EXCEPTION( | 1446 RETURN_FAILURE_ON_EXCEPTION( |
| 1406 isolate, | 1447 isolate, |
| 1407 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), | 1448 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), |
| 1408 setter, attrs)); | 1449 setter, attrs)); |
| 1409 return isolate->heap()->undefined_value(); | 1450 return isolate->heap()->undefined_value(); |
| 1410 } | 1451 } |
| 1411 } // namespace internal | 1452 } // namespace internal |
| 1412 } // namespace v8 | 1453 } // namespace v8 |
| OLD | NEW |