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) { | |
31 // Handle [] indexing on Strings | 30 // Handle [] indexing on Strings |
32 if (object->IsString() && | 31 if (object->IsString() && |
33 index < static_cast<uint32_t>(String::cast(*object)->length())) { | 32 index < static_cast<uint32_t>(String::cast(*object)->length())) { |
34 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 33 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
35 if (!result->IsUndefined()) return result; | 34 if (!result->IsUndefined()) return result; |
36 } | 35 } |
37 | 36 |
38 return Object::GetElement(isolate, object, index, language_mode); | 37 return Object::GetElement(isolate, object, index); |
39 } | 38 } |
40 | 39 |
41 | 40 |
42 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) { | 41 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) { |
43 if (key->IsName()) { | 42 if (key->IsName()) { |
44 return Handle<Name>::cast(key); | 43 return Handle<Name>::cast(key); |
45 } else { | 44 } else { |
46 Handle<Object> converted; | 45 Handle<Object> converted; |
47 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, | 46 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, |
48 Execution::ToString(isolate, key), Name); | 47 Execution::ToString(isolate, key), Name); |
49 return Handle<Name>::cast(converted); | 48 return Handle<Name>::cast(converted); |
50 } | 49 } |
51 } | 50 } |
52 | 51 |
53 | 52 |
54 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, | 53 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
55 Handle<Object> object, | 54 Handle<Object> object, |
56 Handle<Object> key, | 55 Handle<Object> key) { |
57 LanguageMode language_mode) { | |
58 if (object->IsUndefined() || object->IsNull()) { | 56 if (object->IsUndefined() || object->IsNull()) { |
59 THROW_NEW_ERROR( | 57 THROW_NEW_ERROR( |
60 isolate, | 58 isolate, |
61 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), | 59 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), |
62 Object); | 60 Object); |
63 } | 61 } |
64 | 62 |
65 // Check if the given key is an array index. | 63 // Check if the given key is an array index. |
66 uint32_t index = 0; | 64 uint32_t index = 0; |
67 if (key->ToArrayIndex(&index)) { | 65 if (key->ToArrayIndex(&index)) { |
68 return GetElementOrCharAt(isolate, object, index, language_mode); | 66 return GetElementOrCharAt(isolate, object, index); |
69 } | 67 } |
70 | 68 |
71 // Convert the key to a name - possibly by calling back into JavaScript. | 69 // Convert the key to a name - possibly by calling back into JavaScript. |
72 Handle<Name> name; | 70 Handle<Name> name; |
73 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); | 71 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); |
74 | 72 |
75 // Check if the name is trivially convertible to an index and get | 73 // Check if the name is trivially convertible to an index and get |
76 // the element if so. | 74 // the element if so. |
77 // TODO(verwaest): Make sure GetProperty(LookupIterator*) can handle this, and | 75 // TODO(verwaest): Make sure GetProperty(LookupIterator*) can handle this, and |
78 // remove the special casing here. | 76 // remove the special casing here. |
79 if (name->AsArrayIndex(&index)) { | 77 if (name->AsArrayIndex(&index)) { |
80 return GetElementOrCharAt(isolate, object, index); | 78 return GetElementOrCharAt(isolate, object, index); |
81 } else { | 79 } else { |
82 return Object::GetProperty(object, name, language_mode); | 80 return Object::GetProperty(object, name); |
83 } | 81 } |
84 } | 82 } |
85 | 83 |
86 | 84 |
87 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( | |
88 Handle<Object> object, ElementsKind to_kind, Isolate* isolate) { | |
89 HandleScope scope(isolate); | |
90 if (!object->IsJSObject()) { | |
91 isolate->ThrowIllegalOperation(); | |
92 return MaybeHandle<Object>(); | |
93 } | |
94 ElementsKind from_kind = | |
95 Handle<JSObject>::cast(object)->map()->elements_kind(); | |
96 if (Map::IsValidElementsTransition(from_kind, to_kind)) { | |
97 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); | |
98 return object; | |
99 } | |
100 isolate->ThrowIllegalOperation(); | |
101 return MaybeHandle<Object>(); | |
102 } | |
103 | |
104 | |
105 MaybeHandle<Object> Runtime::KeyedGetObjectProperty( | |
106 Isolate* isolate, Handle<Object> receiver_obj, Handle<Object> key_obj, | |
107 LanguageMode language_mode) { | |
108 // Fast cases for getting named properties of the receiver JSObject | |
109 // itself. | |
110 // | |
111 // The global proxy objects has to be excluded since LookupOwn on | |
112 // the global proxy object can return a valid result even though the | |
113 // global proxy object never has properties. This is the case | |
114 // because the global proxy object forwards everything to its hidden | |
115 // prototype including own lookups. | |
116 // | |
117 // Additionally, we need to make sure that we do not cache results | |
118 // for objects that require access checks. | |
119 if (receiver_obj->IsJSObject()) { | |
120 if (!receiver_obj->IsJSGlobalProxy() && | |
121 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { | |
122 DisallowHeapAllocation no_allocation; | |
123 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); | |
124 Handle<Name> key = Handle<Name>::cast(key_obj); | |
125 if (receiver->IsGlobalObject()) { | |
126 // Attempt dictionary lookup. | |
127 GlobalDictionary* dictionary = receiver->global_dictionary(); | |
128 int entry = dictionary->FindEntry(key); | |
129 if (entry != GlobalDictionary::kNotFound) { | |
130 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); | |
131 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); | |
132 if (cell->property_details().type() == DATA) { | |
133 Object* value = cell->value(); | |
134 if (!value->IsTheHole()) return Handle<Object>(value, isolate); | |
135 // If value is the hole (meaning, absent) do the general lookup. | |
136 } | |
137 } | |
138 } else if (!receiver->HasFastProperties()) { | |
139 // Attempt dictionary lookup. | |
140 NameDictionary* dictionary = receiver->property_dictionary(); | |
141 int entry = dictionary->FindEntry(key); | |
142 if ((entry != NameDictionary::kNotFound) && | |
143 (dictionary->DetailsAt(entry).type() == DATA)) { | |
144 Object* value = dictionary->ValueAt(entry); | |
145 return Handle<Object>(value, isolate); | |
146 } | |
147 } | |
148 } else if (key_obj->IsSmi()) { | |
149 // JSObject without a name key. If the key is a Smi, check for a | |
150 // definite out-of-bounds access to elements, which is a strong indicator | |
151 // that subsequent accesses will also call the runtime. Proactively | |
152 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of | |
153 // doubles for those future calls in the case that the elements would | |
154 // become FAST_DOUBLE_ELEMENTS. | |
155 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); | |
156 ElementsKind elements_kind = js_object->GetElementsKind(); | |
157 if (IsFastDoubleElementsKind(elements_kind)) { | |
158 Handle<Smi> key = Handle<Smi>::cast(key_obj); | |
159 if (key->value() >= js_object->elements()->length()) { | |
160 if (IsFastHoleyElementsKind(elements_kind)) { | |
161 elements_kind = FAST_HOLEY_ELEMENTS; | |
162 } else { | |
163 elements_kind = FAST_ELEMENTS; | |
164 } | |
165 RETURN_ON_EXCEPTION( | |
166 isolate, TransitionElements(js_object, elements_kind, isolate), | |
167 Object); | |
168 } | |
169 } else { | |
170 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
171 !IsFastElementsKind(elements_kind)); | |
172 } | |
173 } | |
174 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { | |
175 // Fast case for string indexing using [] with a smi index. | |
176 Handle<String> str = Handle<String>::cast(receiver_obj); | |
177 int index = Handle<Smi>::cast(key_obj)->value(); | |
178 if (index >= 0 && index < str->length()) { | |
179 return GetCharAt(str, index); | |
180 } | |
181 } | |
182 | |
183 // Fall back to GetObjectProperty. | |
184 return GetObjectProperty(isolate, receiver_obj, key_obj, language_mode); | |
185 } | |
186 | |
187 | |
188 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, | 85 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
189 Handle<Object> object, | 86 Handle<Object> object, |
190 Handle<Object> key, | 87 Handle<Object> key, |
191 Handle<Object> value, | 88 Handle<Object> value, |
192 LanguageMode language_mode) { | 89 LanguageMode language_mode) { |
193 if (object->IsUndefined() || object->IsNull()) { | 90 if (object->IsUndefined() || object->IsNull()) { |
194 THROW_NEW_ERROR( | 91 THROW_NEW_ERROR( |
195 isolate, | 92 isolate, |
196 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), | 93 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
197 Object); | 94 Object); |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 !object->map()->is_observed() && !object->IsJSProxy()); | 376 !object->map()->is_observed() && !object->IsJSProxy()); |
480 | 377 |
481 Handle<Object> result; | 378 Handle<Object> result; |
482 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); | 379 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); |
483 return *result; | 380 return *result; |
484 } | 381 } |
485 | 382 |
486 | 383 |
487 RUNTIME_FUNCTION(Runtime_GetProperty) { | 384 RUNTIME_FUNCTION(Runtime_GetProperty) { |
488 HandleScope scope(isolate); | 385 HandleScope scope(isolate); |
489 DCHECK(args.length() == 3); | 386 DCHECK(args.length() == 2); |
490 | 387 |
491 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | 388 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
492 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | 389 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
493 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); | |
494 | |
495 Handle<Object> result; | 390 Handle<Object> result; |
496 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 391 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
497 isolate, result, | 392 isolate, result, Runtime::GetObjectProperty(isolate, object, key)); |
498 Runtime::GetObjectProperty(isolate, object, key, language_mode)); | |
499 return *result; | 393 return *result; |
500 } | 394 } |
501 | 395 |
502 | 396 |
| 397 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( |
| 398 Handle<Object> object, ElementsKind to_kind, Isolate* isolate) { |
| 399 HandleScope scope(isolate); |
| 400 if (!object->IsJSObject()) { |
| 401 isolate->ThrowIllegalOperation(); |
| 402 return MaybeHandle<Object>(); |
| 403 } |
| 404 ElementsKind from_kind = |
| 405 Handle<JSObject>::cast(object)->map()->elements_kind(); |
| 406 if (Map::IsValidElementsTransition(from_kind, to_kind)) { |
| 407 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); |
| 408 return object; |
| 409 } |
| 410 isolate->ThrowIllegalOperation(); |
| 411 return MaybeHandle<Object>(); |
| 412 } |
| 413 |
| 414 |
| 415 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. |
503 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { | 416 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
504 HandleScope scope(isolate); | 417 HandleScope scope(isolate); |
505 DCHECK(args.length() == 3); | 418 DCHECK(args.length() == 2); |
506 | 419 |
507 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); | 420 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
508 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); | 421 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
509 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); | |
510 | 422 |
| 423 // Fast cases for getting named properties of the receiver JSObject |
| 424 // itself. |
| 425 // |
| 426 // The global proxy objects has to be excluded since LookupOwn on |
| 427 // the global proxy object can return a valid result even though the |
| 428 // global proxy object never has properties. This is the case |
| 429 // because the global proxy object forwards everything to its hidden |
| 430 // prototype including own lookups. |
| 431 // |
| 432 // Additionally, we need to make sure that we do not cache results |
| 433 // for objects that require access checks. |
| 434 if (receiver_obj->IsJSObject()) { |
| 435 if (!receiver_obj->IsJSGlobalProxy() && |
| 436 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { |
| 437 DisallowHeapAllocation no_allocation; |
| 438 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); |
| 439 Handle<Name> key = Handle<Name>::cast(key_obj); |
| 440 if (receiver->IsGlobalObject()) { |
| 441 // Attempt dictionary lookup. |
| 442 GlobalDictionary* dictionary = receiver->global_dictionary(); |
| 443 int entry = dictionary->FindEntry(key); |
| 444 if (entry != GlobalDictionary::kNotFound) { |
| 445 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); |
| 446 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); |
| 447 if (cell->property_details().type() == DATA) { |
| 448 Object* value = cell->value(); |
| 449 if (!value->IsTheHole()) return value; |
| 450 // If value is the hole (meaning, absent) do the general lookup. |
| 451 } |
| 452 } |
| 453 } else if (!receiver->HasFastProperties()) { |
| 454 // Attempt dictionary lookup. |
| 455 NameDictionary* dictionary = receiver->property_dictionary(); |
| 456 int entry = dictionary->FindEntry(key); |
| 457 if ((entry != NameDictionary::kNotFound) && |
| 458 (dictionary->DetailsAt(entry).type() == DATA)) { |
| 459 Object* value = dictionary->ValueAt(entry); |
| 460 return value; |
| 461 } |
| 462 } |
| 463 } else if (key_obj->IsSmi()) { |
| 464 // JSObject without a name key. If the key is a Smi, check for a |
| 465 // definite out-of-bounds access to elements, which is a strong indicator |
| 466 // that subsequent accesses will also call the runtime. Proactively |
| 467 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of |
| 468 // doubles for those future calls in the case that the elements would |
| 469 // become FAST_DOUBLE_ELEMENTS. |
| 470 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); |
| 471 ElementsKind elements_kind = js_object->GetElementsKind(); |
| 472 if (IsFastDoubleElementsKind(elements_kind)) { |
| 473 Handle<Smi> key = Handle<Smi>::cast(key_obj); |
| 474 if (key->value() >= js_object->elements()->length()) { |
| 475 if (IsFastHoleyElementsKind(elements_kind)) { |
| 476 elements_kind = FAST_HOLEY_ELEMENTS; |
| 477 } else { |
| 478 elements_kind = FAST_ELEMENTS; |
| 479 } |
| 480 RETURN_FAILURE_ON_EXCEPTION( |
| 481 isolate, TransitionElements(js_object, elements_kind, isolate)); |
| 482 } |
| 483 } else { |
| 484 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
| 485 !IsFastElementsKind(elements_kind)); |
| 486 } |
| 487 } |
| 488 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { |
| 489 // Fast case for string indexing using [] with a smi index. |
| 490 Handle<String> str = Handle<String>::cast(receiver_obj); |
| 491 int index = args.smi_at(1); |
| 492 if (index >= 0 && index < str->length()) { |
| 493 return *GetCharAt(str, index); |
| 494 } |
| 495 } |
| 496 |
| 497 // Fall back to GetObjectProperty. |
511 Handle<Object> result; | 498 Handle<Object> result; |
512 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 499 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
513 isolate, result, Runtime::KeyedGetObjectProperty(isolate, receiver_obj, | 500 isolate, result, |
514 key_obj, language_mode)); | 501 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); |
515 return *result; | 502 return *result; |
516 } | 503 } |
517 | 504 |
518 | 505 |
519 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { | 506 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { |
520 HandleScope scope(isolate); | 507 HandleScope scope(isolate); |
521 RUNTIME_ASSERT(args.length() == 4); | 508 RUNTIME_ASSERT(args.length() == 4); |
522 | 509 |
523 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 510 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
524 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | 511 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1437 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 1424 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
1438 | 1425 |
1439 RETURN_FAILURE_ON_EXCEPTION( | 1426 RETURN_FAILURE_ON_EXCEPTION( |
1440 isolate, | 1427 isolate, |
1441 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), | 1428 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), |
1442 setter, attrs)); | 1429 setter, attrs)); |
1443 return isolate->heap()->undefined_value(); | 1430 return isolate->heap()->undefined_value(); |
1444 } | 1431 } |
1445 } // namespace internal | 1432 } // namespace internal |
1446 } // namespace v8 | 1433 } // namespace v8 |
OLD | NEW |