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 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 |
85 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, | 188 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
86 Handle<Object> object, | 189 Handle<Object> object, |
87 Handle<Object> key, | 190 Handle<Object> key, |
88 Handle<Object> value, | 191 Handle<Object> value, |
89 LanguageMode language_mode) { | 192 LanguageMode language_mode) { |
90 if (object->IsUndefined() || object->IsNull()) { | 193 if (object->IsUndefined() || object->IsNull()) { |
91 THROW_NEW_ERROR( | 194 THROW_NEW_ERROR( |
92 isolate, | 195 isolate, |
93 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), | 196 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
94 Object); | 197 Object); |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 !object->map()->is_observed() && !object->IsJSProxy()); | 479 !object->map()->is_observed() && !object->IsJSProxy()); |
377 | 480 |
378 Handle<Object> result; | 481 Handle<Object> result; |
379 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); | 482 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); |
380 return *result; | 483 return *result; |
381 } | 484 } |
382 | 485 |
383 | 486 |
384 RUNTIME_FUNCTION(Runtime_GetProperty) { | 487 RUNTIME_FUNCTION(Runtime_GetProperty) { |
385 HandleScope scope(isolate); | 488 HandleScope scope(isolate); |
386 DCHECK(args.length() == 2); | 489 DCHECK(args.length() == 3); |
387 | 490 |
388 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | 491 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
389 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | 492 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| 493 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); |
| 494 |
390 Handle<Object> result; | 495 Handle<Object> result; |
391 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 496 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
392 isolate, result, Runtime::GetObjectProperty(isolate, object, key)); | 497 isolate, result, |
| 498 Runtime::GetObjectProperty(isolate, object, key, language_mode)); |
393 return *result; | 499 return *result; |
394 } | 500 } |
395 | 501 |
396 | 502 |
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. | |
416 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { | 503 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
417 HandleScope scope(isolate); | 504 HandleScope scope(isolate); |
418 DCHECK(args.length() == 2); | 505 DCHECK(args.length() == 3); |
419 | 506 |
420 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); | 507 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
421 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); | 508 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
| 509 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); |
422 | 510 |
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. | |
498 Handle<Object> result; | 511 Handle<Object> result; |
499 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 512 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
500 isolate, result, | 513 isolate, result, Runtime::KeyedGetObjectProperty(isolate, receiver_obj, |
501 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); | 514 key_obj, language_mode)); |
502 return *result; | 515 return *result; |
503 } | 516 } |
504 | 517 |
505 | 518 |
506 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { | 519 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { |
507 HandleScope scope(isolate); | 520 HandleScope scope(isolate); |
508 RUNTIME_ASSERT(args.length() == 4); | 521 RUNTIME_ASSERT(args.length() == 4); |
509 | 522 |
510 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 523 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
511 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | 524 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1424 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 1437 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
1425 | 1438 |
1426 RETURN_FAILURE_ON_EXCEPTION( | 1439 RETURN_FAILURE_ON_EXCEPTION( |
1427 isolate, | 1440 isolate, |
1428 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), | 1441 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), |
1429 setter, attrs)); | 1442 setter, attrs)); |
1430 return isolate->heap()->undefined_value(); | 1443 return isolate->heap()->undefined_value(); |
1431 } | 1444 } |
1432 } // namespace internal | 1445 } // namespace internal |
1433 } // namespace v8 | 1446 } // namespace v8 |
OLD | NEW |