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" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 | 125 |
126 JSObject::ValidateElements(js_object); | 126 JSObject::ValidateElements(js_object); |
127 if (js_object->HasExternalArrayElements() || | 127 if (js_object->HasExternalArrayElements() || |
128 js_object->HasFixedTypedArrayElements()) { | 128 js_object->HasFixedTypedArrayElements()) { |
129 if (!value->IsNumber() && !value->IsUndefined()) { | 129 if (!value->IsNumber() && !value->IsUndefined()) { |
130 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, | 130 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, |
131 Execution::ToNumber(isolate, value), Object); | 131 Execution::ToNumber(isolate, value), Object); |
132 } | 132 } |
133 } | 133 } |
134 | 134 |
135 MaybeHandle<Object> result = JSObject::SetElement( | 135 MaybeHandle<Object> result = |
136 js_object, index, value, NONE, language_mode, true, SET_PROPERTY); | 136 JSObject::SetElement(js_object, index, value, language_mode); |
137 JSObject::ValidateElements(js_object); | 137 JSObject::ValidateElements(js_object); |
138 | 138 |
139 return result.is_null() ? result : value; | 139 return result.is_null() ? result : value; |
140 } | 140 } |
141 | 141 |
142 if (key->IsName()) { | 142 if (key->IsName()) { |
143 Handle<Name> name = Handle<Name>::cast(key); | 143 Handle<Name> name = Handle<Name>::cast(key); |
144 if (name->AsArrayIndex(&index)) { | 144 if (name->AsArrayIndex(&index)) { |
145 // TODO(verwaest): Support non-JSObject receivers. | 145 // TODO(verwaest): Support non-JSObject receivers. |
146 if (!object->IsJSObject()) return value; | 146 if (!object->IsJSObject()) return value; |
147 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 147 Handle<JSObject> js_object = Handle<JSObject>::cast(object); |
148 if (js_object->HasExternalArrayElements()) { | 148 if (js_object->HasExternalArrayElements()) { |
149 if (!value->IsNumber() && !value->IsUndefined()) { | 149 if (!value->IsNumber() && !value->IsUndefined()) { |
150 ASSIGN_RETURN_ON_EXCEPTION( | 150 ASSIGN_RETURN_ON_EXCEPTION( |
151 isolate, value, Execution::ToNumber(isolate, value), Object); | 151 isolate, value, Execution::ToNumber(isolate, value), Object); |
152 } | 152 } |
153 } | 153 } |
154 return JSObject::SetElement(js_object, index, value, NONE, language_mode, | 154 return JSObject::SetElement(js_object, index, value, language_mode); |
155 true, SET_PROPERTY); | |
156 } else { | 155 } else { |
157 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); | 156 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); |
158 return Object::SetProperty(object, name, value, language_mode); | 157 return Object::SetProperty(object, name, value, language_mode); |
159 } | 158 } |
160 } | 159 } |
161 | 160 |
162 // Call-back into JavaScript to convert the key to a string. | 161 // Call-back into JavaScript to convert the key to a string. |
163 Handle<Object> converted; | 162 Handle<Object> converted; |
164 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, | 163 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, |
165 Execution::ToString(isolate, key), Object); | 164 Execution::ToString(isolate, key), Object); |
166 Handle<String> name = Handle<String>::cast(converted); | 165 Handle<String> name = Handle<String>::cast(converted); |
167 | 166 |
168 if (name->AsArrayIndex(&index)) { | 167 if (name->AsArrayIndex(&index)) { |
169 // TODO(verwaest): Support non-JSObject receivers. | 168 // TODO(verwaest): Support non-JSObject receivers. |
170 if (!object->IsJSObject()) return value; | 169 if (!object->IsJSObject()) return value; |
171 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | 170 Handle<JSObject> js_object = Handle<JSObject>::cast(object); |
172 return JSObject::SetElement(js_object, index, value, NONE, language_mode, | 171 return JSObject::SetElement(js_object, index, value, language_mode); |
173 true, SET_PROPERTY); | |
174 } | 172 } |
175 return Object::SetProperty(object, name, value, language_mode); | 173 return Object::SetProperty(object, name, value, language_mode); |
176 } | 174 } |
177 | 175 |
178 | 176 |
179 MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object, | 177 MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object, |
180 Handle<Object> key, | 178 Handle<Object> key, |
181 Handle<Object> value, | 179 Handle<Object> value, |
182 PropertyAttributes attrs) { | 180 PropertyAttributes attrs) { |
183 Isolate* isolate = js_object->GetIsolate(); | 181 Isolate* isolate = js_object->GetIsolate(); |
184 // Check if the given key is an array index. | 182 // Check if the given key is an array index. |
185 uint32_t index = 0; | 183 uint32_t index = 0; |
186 if (key->ToArrayIndex(&index)) { | 184 if (key->ToArrayIndex(&index)) { |
187 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | 185 return JSObject::SetOwnElementIgnoreAttributes(js_object, index, value, |
188 // of a string using [] notation. We need to support this too in | 186 attrs); |
189 // JavaScript. | |
190 // In the case of a String object we just need to redirect the assignment to | |
191 // the underlying string if the index is in range. Since the underlying | |
192 // string does nothing with the assignment then we can ignore such | |
193 // assignments. | |
194 if (js_object->IsStringObjectWithCharacterAt(index)) { | |
195 return value; | |
196 } | |
197 | |
198 return JSObject::SetElement(js_object, index, value, attrs, SLOPPY, false, | |
199 DEFINE_PROPERTY); | |
200 } | 187 } |
201 | 188 |
| 189 Handle<Name> name; |
202 if (key->IsName()) { | 190 if (key->IsName()) { |
203 Handle<Name> name = Handle<Name>::cast(key); | 191 name = Handle<Name>::cast(key); |
204 if (name->AsArrayIndex(&index)) { | 192 } else { |
205 return JSObject::SetElement(js_object, index, value, attrs, SLOPPY, false, | 193 // Call-back into JavaScript to convert the key to a string. |
206 DEFINE_PROPERTY); | 194 Handle<Object> converted; |
207 } else { | 195 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, |
208 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); | 196 Execution::ToString(isolate, key), Object); |
209 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value, | 197 name = Handle<String>::cast(converted); |
210 attrs); | |
211 } | |
212 } | 198 } |
213 | 199 |
214 // Call-back into JavaScript to convert the key to a string. | |
215 Handle<Object> converted; | |
216 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted, | |
217 Execution::ToString(isolate, key), Object); | |
218 Handle<String> name = Handle<String>::cast(converted); | |
219 | |
220 if (name->AsArrayIndex(&index)) { | 200 if (name->AsArrayIndex(&index)) { |
221 return JSObject::SetElement(js_object, index, value, attrs, SLOPPY, false, | 201 return JSObject::SetOwnElementIgnoreAttributes(js_object, index, value, |
222 DEFINE_PROPERTY); | 202 attrs); |
223 } else { | 203 } else { |
| 204 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); |
224 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value, | 205 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value, |
225 attrs); | 206 attrs); |
226 } | 207 } |
227 } | 208 } |
228 | 209 |
229 | 210 |
230 MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate, | 211 MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate, |
231 Handle<Object> obj) { | 212 Handle<Object> obj) { |
232 // We don't expect access checks to be needed on JSProxy objects. | 213 // We don't expect access checks to be needed on JSProxy objects. |
233 DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); | 214 DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); | 598 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); |
618 return *result; | 599 return *result; |
619 } | 600 } |
620 | 601 |
621 | 602 |
622 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { | 603 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { |
623 HandleScope scope(isolate); | 604 HandleScope scope(isolate); |
624 RUNTIME_ASSERT(args.length() == 4); | 605 RUNTIME_ASSERT(args.length() == 4); |
625 | 606 |
626 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 607 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
627 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | 608 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
628 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | 609 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
629 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 610 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
630 | 611 |
631 #ifdef DEBUG | 612 #ifdef DEBUG |
632 uint32_t index = 0; | 613 uint32_t index = 0; |
633 DCHECK(!key->ToArrayIndex(&index)); | 614 DCHECK(!name->ToArrayIndex(&index)); |
634 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR); | 615 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
635 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | 616 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); |
636 if (!maybe.IsJust()) return isolate->heap()->exception(); | 617 if (!maybe.IsJust()) return isolate->heap()->exception(); |
637 RUNTIME_ASSERT(!it.IsFound()); | 618 RUNTIME_ASSERT(!it.IsFound()); |
638 #endif | 619 #endif |
639 | 620 |
640 Handle<Object> result; | 621 Handle<Object> result; |
641 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 622 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
642 isolate, result, | 623 isolate, result, |
643 JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attrs)); | 624 JSObject::SetOwnPropertyIgnoreAttributes(object, name, value, attrs)); |
644 return *result; | 625 return *result; |
645 } | 626 } |
646 | 627 |
647 | |
648 RUNTIME_FUNCTION(Runtime_SetProperty) { | |
649 HandleScope scope(isolate); | |
650 RUNTIME_ASSERT(args.length() == 4); | |
651 | |
652 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
653 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
654 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
655 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode_arg, 3); | |
656 LanguageMode language_mode = language_mode_arg; | |
657 | |
658 Handle<Object> result; | |
659 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
660 isolate, result, | |
661 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); | |
662 return *result; | |
663 } | |
664 | |
665 | 628 |
666 // Adds an element to an array. | 629 // Adds an element to an array. |
667 // This is used to create an indexed data property into an array. | 630 // This is used to create an indexed data property into an array. |
668 RUNTIME_FUNCTION(Runtime_AddElement) { | 631 RUNTIME_FUNCTION(Runtime_AddElement) { |
669 HandleScope scope(isolate); | 632 HandleScope scope(isolate); |
670 RUNTIME_ASSERT(args.length() == 4); | 633 RUNTIME_ASSERT(args.length() == 3); |
671 | 634 |
672 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 635 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
673 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | 636 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
674 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | 637 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
675 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | |
676 | 638 |
677 uint32_t index = 0; | 639 uint32_t index = 0; |
678 key->ToArrayIndex(&index); | 640 CHECK(key->ToArrayIndex(&index)); |
| 641 |
| 642 #ifdef DEBUG |
| 643 LookupIterator it(isolate, object, index, |
| 644 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 645 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); |
| 646 if (!maybe.IsJust()) return isolate->heap()->exception(); |
| 647 RUNTIME_ASSERT(!it.IsFound()); |
| 648 |
| 649 if (object->IsJSArray()) { |
| 650 Handle<JSArray> array = Handle<JSArray>::cast(object); |
| 651 RUNTIME_ASSERT(!JSArray::WouldChangeReadOnlyLength(array, index)); |
| 652 } |
| 653 #endif |
679 | 654 |
680 Handle<Object> result; | 655 Handle<Object> result; |
681 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 656 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
682 isolate, result, JSObject::SetElement(object, index, value, attrs, SLOPPY, | 657 isolate, result, |
683 false, DEFINE_PROPERTY)); | 658 JSObject::SetOwnElementIgnoreAttributes(object, index, value, NONE)); |
684 return *result; | 659 return *result; |
685 } | 660 } |
686 | 661 |
687 | 662 |
688 RUNTIME_FUNCTION(Runtime_AppendElement) { | 663 RUNTIME_FUNCTION(Runtime_AppendElement) { |
689 HandleScope scope(isolate); | 664 HandleScope scope(isolate); |
690 RUNTIME_ASSERT(args.length() == 2); | 665 RUNTIME_ASSERT(args.length() == 2); |
691 | 666 |
692 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | 667 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |
693 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | 668 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
694 | 669 |
695 int index = Smi::cast(array->length())->value(); | 670 uint32_t index; |
| 671 CHECK(array->length()->ToArrayIndex(&index)); |
696 | 672 |
697 Handle<Object> result; | 673 Handle<Object> result; |
698 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 674 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
699 isolate, result, JSObject::SetElement(array, index, value, NONE, SLOPPY, | 675 isolate, result, JSObject::AddDataElement(array, index, value, NONE)); |
700 false, DEFINE_PROPERTY)); | |
701 return *array; | 676 return *array; |
702 } | 677 } |
703 | 678 |
704 | 679 |
| 680 RUNTIME_FUNCTION(Runtime_SetProperty) { |
| 681 HandleScope scope(isolate); |
| 682 RUNTIME_ASSERT(args.length() == 4); |
| 683 |
| 684 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| 685 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| 686 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| 687 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode_arg, 3); |
| 688 LanguageMode language_mode = language_mode_arg; |
| 689 |
| 690 Handle<Object> result; |
| 691 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 692 isolate, result, |
| 693 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); |
| 694 return *result; |
| 695 } |
| 696 |
| 697 |
705 RUNTIME_FUNCTION(Runtime_DeleteProperty) { | 698 RUNTIME_FUNCTION(Runtime_DeleteProperty) { |
706 HandleScope scope(isolate); | 699 HandleScope scope(isolate); |
707 DCHECK(args.length() == 3); | 700 DCHECK(args.length() == 3); |
708 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); | 701 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); |
709 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | 702 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); |
710 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); | 703 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); |
711 Handle<Object> result; | 704 Handle<Object> result; |
712 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 705 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
713 isolate, result, JSReceiver::DeleteProperty(object, key, language_mode)); | 706 isolate, result, JSReceiver::DeleteProperty(object, key, language_mode)); |
714 return *result; | 707 return *result; |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1368 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 1361 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
1369 | 1362 |
1370 LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 1363 LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
1371 if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) { | 1364 if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) { |
1372 if (!isolate->MayAccess(js_object)) { | 1365 if (!isolate->MayAccess(js_object)) { |
1373 return isolate->heap()->undefined_value(); | 1366 return isolate->heap()->undefined_value(); |
1374 } | 1367 } |
1375 it.Next(); | 1368 it.Next(); |
1376 } | 1369 } |
1377 | 1370 |
1378 // Take special care when attributes are different and there is already | |
1379 // a property. | |
1380 if (it.state() == LookupIterator::ACCESSOR) { | |
1381 // Use IgnoreAttributes version since a readonly property may be | |
1382 // overridden and SetProperty does not allow this. | |
1383 Handle<Object> result; | |
1384 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1385 isolate, result, | |
1386 JSObject::SetOwnPropertyIgnoreAttributes( | |
1387 js_object, name, obj_value, attrs, JSObject::DONT_FORCE_FIELD)); | |
1388 return *result; | |
1389 } | |
1390 | |
1391 Handle<Object> result; | 1371 Handle<Object> result; |
1392 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1372 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
1393 isolate, result, | 1373 isolate, result, |
1394 Runtime::DefineObjectProperty(js_object, name, obj_value, attrs)); | 1374 Runtime::DefineObjectProperty(js_object, name, obj_value, attrs)); |
1395 return *result; | 1375 return *result; |
1396 } | 1376 } |
1397 | 1377 |
1398 | 1378 |
1399 // Return property without being observable by accessors or interceptors. | 1379 // Return property without being observable by accessors or interceptors. |
1400 RUNTIME_FUNCTION(Runtime_GetDataProperty) { | 1380 RUNTIME_FUNCTION(Runtime_GetDataProperty) { |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1542 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); | 1522 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
1543 | 1523 |
1544 RETURN_FAILURE_ON_EXCEPTION( | 1524 RETURN_FAILURE_ON_EXCEPTION( |
1545 isolate, | 1525 isolate, |
1546 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), | 1526 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), |
1547 setter, attrs)); | 1527 setter, attrs)); |
1548 return isolate->heap()->undefined_value(); | 1528 return isolate->heap()->undefined_value(); |
1549 } | 1529 } |
1550 } // namespace internal | 1530 } // namespace internal |
1551 } // namespace v8 | 1531 } // namespace v8 |
OLD | NEW |