OLD | NEW |
---|---|
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 } | 206 } |
207 RETURN_IF_SCHEDULED_EXCEPTION(); | 207 RETURN_IF_SCHEDULED_EXCEPTION(); |
208 if (result.IsEmpty()) return Heap::undefined_value(); | 208 if (result.IsEmpty()) return Heap::undefined_value(); |
209 return *v8::Utils::OpenHandle(*result); | 209 return *v8::Utils::OpenHandle(*result); |
210 } | 210 } |
211 | 211 |
212 // __defineGetter__ callback | 212 // __defineGetter__ callback |
213 if (structure->IsFixedArray()) { | 213 if (structure->IsFixedArray()) { |
214 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); | 214 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); |
215 if (getter->IsJSFunction()) { | 215 if (getter->IsJSFunction()) { |
216 HandleScope scope; | 216 return Object::GetPropertyWithDefinedGetter(receiver, |
217 Handle<JSFunction> fun(JSFunction::cast(getter)); | 217 JSFunction::cast(getter)); |
218 Handle<Object> self(receiver); | |
219 bool has_pending_exception; | |
220 Handle<Object> result = | |
221 Execution::Call(fun, self, 0, NULL, &has_pending_exception); | |
222 // Check for pending exception and return the result. | |
223 if (has_pending_exception) return Failure::Exception(); | |
224 return *result; | |
225 } | 218 } |
226 // Getter is not a function. | 219 // Getter is not a function. |
227 return Heap::undefined_value(); | 220 return Heap::undefined_value(); |
228 } | 221 } |
229 | 222 |
230 UNREACHABLE(); | 223 UNREACHABLE(); |
231 return 0; | 224 return 0; |
232 } | 225 } |
233 | 226 |
234 | 227 |
228 Object* Object::GetPropertyWithDefinedGetter(Object* receiver, | |
229 JSFunction* getter) { | |
230 HandleScope scope; | |
231 Handle<JSFunction> fun(JSFunction::cast(getter)); | |
232 Handle<Object> self(receiver); | |
233 bool has_pending_exception; | |
234 Handle<Object> result = | |
235 Execution::Call(fun, self, 0, NULL, &has_pending_exception); | |
236 // Check for pending exception and return the result. | |
237 if (has_pending_exception) return Failure::Exception(); | |
238 return *result; | |
239 } | |
240 | |
241 | |
235 // Only deal with CALLBACKS and INTERCEPTOR | 242 // Only deal with CALLBACKS and INTERCEPTOR |
236 Object* JSObject::GetPropertyWithFailedAccessCheck( | 243 Object* JSObject::GetPropertyWithFailedAccessCheck( |
237 Object* receiver, | 244 Object* receiver, |
238 LookupResult* result, | 245 LookupResult* result, |
239 String* name, | 246 String* name, |
240 PropertyAttributes* attributes) { | 247 PropertyAttributes* attributes) { |
241 if (result->IsValid()) { | 248 if (result->IsValid()) { |
242 switch (result->type()) { | 249 switch (result->type()) { |
243 case CALLBACKS: { | 250 case CALLBACKS: { |
244 // Only allow API accessors. | 251 // Only allow API accessors. |
(...skipping 1247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1492 v8::Utils::ToLocal(value_handle), | 1499 v8::Utils::ToLocal(value_handle), |
1493 info); | 1500 info); |
1494 } | 1501 } |
1495 RETURN_IF_SCHEDULED_EXCEPTION(); | 1502 RETURN_IF_SCHEDULED_EXCEPTION(); |
1496 return *value_handle; | 1503 return *value_handle; |
1497 } | 1504 } |
1498 | 1505 |
1499 if (structure->IsFixedArray()) { | 1506 if (structure->IsFixedArray()) { |
1500 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); | 1507 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); |
1501 if (setter->IsJSFunction()) { | 1508 if (setter->IsJSFunction()) { |
1502 Handle<JSFunction> fun(JSFunction::cast(setter)); | 1509 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); |
1503 Handle<JSObject> self(this); | |
1504 bool has_pending_exception; | |
1505 Object** argv[] = { value_handle.location() }; | |
1506 Execution::Call(fun, self, 1, argv, &has_pending_exception); | |
1507 // Check for pending exception and return the result. | |
1508 if (has_pending_exception) return Failure::Exception(); | |
1509 } else { | 1510 } else { |
1510 Handle<String> key(name); | 1511 Handle<String> key(name); |
1511 Handle<Object> holder_handle(holder); | 1512 Handle<Object> holder_handle(holder); |
1512 Handle<Object> args[2] = { key, holder_handle }; | 1513 Handle<Object> args[2] = { key, holder_handle }; |
1513 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", | 1514 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", |
1514 HandleVector(args, 2))); | 1515 HandleVector(args, 2))); |
1515 } | 1516 } |
1516 return *value_handle; | |
1517 } | 1517 } |
1518 | 1518 |
1519 UNREACHABLE(); | 1519 UNREACHABLE(); |
1520 return 0; | 1520 return 0; |
1521 } | 1521 } |
1522 | 1522 |
1523 | 1523 |
1524 Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, | |
1525 Object* value) { | |
1526 Handle<Object> value_handle(value); | |
1527 Handle<JSFunction> fun(JSFunction::cast(setter)); | |
1528 Handle<JSObject> self(this); | |
1529 bool has_pending_exception; | |
1530 Object** argv[] = { value_handle.location() }; | |
1531 Execution::Call(fun, self, 1, argv, &has_pending_exception); | |
1532 // Check for pending exception and return the result. | |
1533 if (has_pending_exception) return Failure::Exception(); | |
1534 return *value_handle; | |
1535 } | |
1536 | |
1524 void JSObject::LookupCallbackSetterInPrototypes(String* name, | 1537 void JSObject::LookupCallbackSetterInPrototypes(String* name, |
1525 LookupResult* result) { | 1538 LookupResult* result) { |
1526 for (Object* pt = GetPrototype(); | 1539 for (Object* pt = GetPrototype(); |
1527 pt != Heap::null_value(); | 1540 pt != Heap::null_value(); |
1528 pt = pt->GetPrototype()) { | 1541 pt = pt->GetPrototype()) { |
1529 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); | 1542 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); |
1530 if (result->IsValid()) { | 1543 if (result->IsValid()) { |
1531 if (!result->IsTransitionType() && result->IsReadOnly()) { | 1544 if (!result->IsTransitionType() && result->IsReadOnly()) { |
1532 result->NotFound(); | 1545 result->NotFound(); |
1533 return; | 1546 return; |
1534 } | 1547 } |
1535 if (result->type() == CALLBACKS) { | 1548 if (result->type() == CALLBACKS) { |
1536 return; | 1549 return; |
1537 } | 1550 } |
1538 } | 1551 } |
1539 } | 1552 } |
1540 result->NotFound(); | 1553 result->NotFound(); |
1541 } | 1554 } |
1542 | 1555 |
1543 | 1556 |
1557 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { | |
1558 for (Object* pt = GetPrototype(); | |
1559 pt != Heap::null_value(); | |
1560 pt = pt->GetPrototype()) { | |
1561 if (JSObject::cast(pt)->HasFastElements()) continue; | |
1562 Dictionary* dictionary = JSObject::cast(pt)->element_dictionary(); | |
1563 int entry = dictionary->FindNumberEntry(index); | |
1564 if (entry != -1) { | |
1565 Object* element = dictionary->ValueAt(entry); | |
1566 PropertyDetails details = dictionary->DetailsAt(entry); | |
1567 if (details.type() == CALLBACKS) { | |
1568 // Only accessors allowed as elements. | |
1569 return FixedArray::cast(element)->get(kSetterIndex); | |
1570 } | |
1571 } | |
1572 } | |
1573 return Heap::undefined_value(); | |
1574 } | |
1575 | |
1576 | |
1544 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { | 1577 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { |
1545 DescriptorArray* descriptors = map()->instance_descriptors(); | 1578 DescriptorArray* descriptors = map()->instance_descriptors(); |
1546 int number = descriptors->Search(name); | 1579 int number = descriptors->Search(name); |
1547 if (number != DescriptorArray::kNotFound) { | 1580 if (number != DescriptorArray::kNotFound) { |
1548 result->DescriptorResult(this, descriptors->GetDetails(number), number); | 1581 result->DescriptorResult(this, descriptors->GetDetails(number), number); |
1549 } else { | 1582 } else { |
1550 result->NotFound(); | 1583 result->NotFound(); |
1551 } | 1584 } |
1552 } | 1585 } |
1553 | 1586 |
(...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2489 // Check access rights if needed. | 2522 // Check access rights if needed. |
2490 if (IsAccessCheckNeeded() && | 2523 if (IsAccessCheckNeeded() && |
2491 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 2524 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
2492 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 2525 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
2493 return Heap::undefined_value(); | 2526 return Heap::undefined_value(); |
2494 } | 2527 } |
2495 | 2528 |
2496 // Try to flatten before operating on the string. | 2529 // Try to flatten before operating on the string. |
2497 name->TryFlattenIfNotFlat(StringShape(name)); | 2530 name->TryFlattenIfNotFlat(StringShape(name)); |
2498 | 2531 |
2499 // Make sure name is not an index. | |
2500 uint32_t index; | |
2501 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); | |
2502 | |
2503 // Check if there is an API defined callback object which prohibits | 2532 // Check if there is an API defined callback object which prohibits |
2504 // callback overwriting in this object or it's prototype chain. | 2533 // callback overwriting in this object or it's prototype chain. |
2505 // This mechanism is needed for instance in a browser setting, where | 2534 // This mechanism is needed for instance in a browser setting, where |
2506 // certain accessors such as window.location should not be allowed | 2535 // certain accessors such as window.location should not be allowed |
2507 // to be overwritten because allowing overwriting could potentially | 2536 // to be overwritten because allowing overwriting could potentially |
2508 // cause security problems. | 2537 // cause security problems. |
2509 LookupResult callback_result; | 2538 LookupResult callback_result; |
2510 LookupCallback(name, &callback_result); | 2539 LookupCallback(name, &callback_result); |
2511 if (callback_result.IsValid()) { | 2540 if (callback_result.IsValid()) { |
2512 Object* obj = callback_result.GetCallbackObject(); | 2541 Object* obj = callback_result.GetCallbackObject(); |
2513 if (obj->IsAccessorInfo() && | 2542 if (obj->IsAccessorInfo() && |
2514 AccessorInfo::cast(obj)->prohibits_overwriting()) { | 2543 AccessorInfo::cast(obj)->prohibits_overwriting()) { |
2515 return Heap::undefined_value(); | 2544 return Heap::undefined_value(); |
2516 } | 2545 } |
2517 } | 2546 } |
2518 | 2547 |
2519 // Lookup the name. | 2548 uint32_t index; |
2520 LookupResult result; | 2549 bool is_element = name->AsArrayIndex(&index); |
2521 LocalLookup(name, &result); | 2550 if (is_element && IsJSArray()) return Heap::undefined_value(); |
2522 if (result.IsValid()) { | 2551 |
2523 if (result.IsReadOnly()) return Heap::undefined_value(); | 2552 if (is_element) { |
2524 if (result.type() == CALLBACKS) { | 2553 // Lookup the index. |
2525 Object* obj = result.GetCallbackObject(); | 2554 if (!HasFastElements()) { |
2526 if (obj->IsFixedArray()) return obj; | 2555 Dictionary* dictionary = element_dictionary(); |
2556 int entry = dictionary->FindNumberEntry(index); | |
2557 if (entry != -1) { | |
2558 Object* result = dictionary->ValueAt(entry); | |
2559 PropertyDetails details = dictionary->DetailsAt(entry); | |
2560 if (details.IsReadOnly()) return Heap::undefined_value(); | |
2561 if (details.type() == CALLBACKS) { | |
2562 // Only accessors allowed as elements. | |
2563 ASSERT(result->IsFixedArray()); | |
2564 return result; | |
2565 } | |
2566 } | |
2567 } | |
2568 } else { | |
2569 // Lookup the name. | |
2570 LookupResult result; | |
2571 LocalLookup(name, &result); | |
2572 if (result.IsValid()) { | |
2573 if (result.IsReadOnly()) return Heap::undefined_value(); | |
2574 if (result.type() == CALLBACKS) { | |
2575 Object* obj = result.GetCallbackObject(); | |
2576 if (obj->IsFixedArray()) return obj; | |
2577 } | |
2527 } | 2578 } |
2528 } | 2579 } |
2529 | 2580 |
2530 // Normalize object to make this operation simple. | 2581 // Allocate the fixed array to hold getter and setter. |
2531 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); | 2582 Object* structure = Heap::AllocateFixedArray(2, TENURED); |
2532 if (ok->IsFailure()) return ok; | 2583 if (structure->IsFailure()) return structure; |
2584 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | |
2533 | 2585 |
2534 // Allocate the fixed array to hold getter and setter. | 2586 if (is_element) { |
2535 Object* array = Heap::AllocateFixedArray(2, TENURED); | 2587 // Normalize object to make this operation simple. |
2536 if (array->IsFailure()) return array; | 2588 Object* ok = NormalizeElements(); |
2589 if (ok->IsFailure()) return ok; | |
2537 | 2590 |
2538 // Update the dictionary with the new CALLBACKS property. | 2591 // Update the dictionary with the new CALLBACKS property. |
2539 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 2592 Object* dict = |
2540 Object* dict = | 2593 element_dictionary()->SetOrAddNumberEntry(index, structure, details); |
2541 property_dictionary()->SetOrAddStringEntry(name, array, details); | 2594 if (dict->IsFailure()) return dict; |
2542 if (dict->IsFailure()) return dict; | |
2543 | 2595 |
2544 // Set the potential new dictionary on the object. | 2596 // If name is an index we need to stay in slow case. |
2545 set_properties(Dictionary::cast(dict)); | 2597 Dictionary* elements = Dictionary::cast(dict); |
2546 return array; | 2598 elements->set_requires_slow_elements(); |
2599 // Set the potential new dictionary on the object. | |
2600 set_elements(Dictionary::cast(dict)); | |
2601 | |
2602 // Update the array length if this JSObject is an array. | |
Mads Ager (chromium)
2009/03/13 10:27:14
Since we do not do this for arrays, we can remove
olehougaard
2009/03/13 11:39:46
Fixed.
| |
2603 if (IsJSArray()) { | |
2604 JSArray* array = JSArray::cast(this); | |
2605 Object* return_value = | |
2606 array->JSArrayUpdateLengthFromIndex(index, structure); | |
2607 if (return_value->IsFailure()) return return_value; | |
2608 } | |
2609 } else { | |
2610 // Normalize object to make this operation simple. | |
2611 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); | |
2612 if (ok->IsFailure()) return ok; | |
2613 | |
2614 // Update the dictionary with the new CALLBACKS property. | |
2615 Object* dict = | |
2616 property_dictionary()->SetOrAddStringEntry(name, structure, details); | |
2617 if (dict->IsFailure()) return dict; | |
2618 | |
2619 // Set the potential new dictionary on the object. | |
2620 set_properties(Dictionary::cast(dict)); | |
2621 } | |
2622 | |
2623 return structure; | |
2547 } | 2624 } |
2548 | 2625 |
2549 | 2626 |
2550 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, | 2627 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, |
2551 PropertyAttributes attributes) { | 2628 PropertyAttributes attributes) { |
2552 // Check access rights if needed. | 2629 // Check access rights if needed. |
2553 if (IsAccessCheckNeeded() && | 2630 if (IsAccessCheckNeeded() && |
2554 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { | 2631 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { |
2555 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 2632 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
2556 return Heap::undefined_value(); | 2633 return Heap::undefined_value(); |
(...skipping 19 matching lines...) Expand all Loading... | |
2576 // interceptor calls. | 2653 // interceptor calls. |
2577 AssertNoContextChange ncc; | 2654 AssertNoContextChange ncc; |
2578 | 2655 |
2579 // Check access rights if needed. | 2656 // Check access rights if needed. |
2580 if (IsAccessCheckNeeded() && | 2657 if (IsAccessCheckNeeded() && |
2581 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { | 2658 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { |
2582 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 2659 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
2583 return Heap::undefined_value(); | 2660 return Heap::undefined_value(); |
2584 } | 2661 } |
2585 | 2662 |
2586 // Make sure name is not an index. | 2663 // Make the lookup and include prototypes. |
2664 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; | |
2587 uint32_t index; | 2665 uint32_t index; |
2588 if (name->AsArrayIndex(&index)) return Heap::undefined_value(); | 2666 if (name->AsArrayIndex(&index)) { |
2589 | 2667 for (Object* obj = this; |
2590 // Make the lookup and include prototypes. | 2668 obj != Heap::null_value(); |
2591 for (Object* obj = this; | 2669 obj = JSObject::cast(obj)->GetPrototype()) { |
2592 obj != Heap::null_value(); | 2670 JSObject* jsObject = JSObject::cast(obj); |
2593 obj = JSObject::cast(obj)->GetPrototype()) { | 2671 if (!jsObject->HasFastElements()) { |
2594 LookupResult result; | 2672 Dictionary* dictionary = jsObject->element_dictionary(); |
2595 JSObject::cast(obj)->LocalLookup(name, &result); | 2673 int entry = dictionary->FindNumberEntry(index); |
2596 if (result.IsValid()) { | 2674 if (entry != -1) { |
2597 if (result.IsReadOnly()) return Heap::undefined_value(); | 2675 Object* element = dictionary->ValueAt(entry); |
2598 if (result.type() == CALLBACKS) { | 2676 PropertyDetails details = dictionary->DetailsAt(entry); |
2599 Object* obj = result.GetCallbackObject(); | 2677 if (details.type() == CALLBACKS) { |
2600 if (obj->IsFixedArray()) { | 2678 // Only accessors allowed as elements. |
2601 return FixedArray::cast(obj)->get(is_getter | 2679 return FixedArray::cast(element)->get(accessor_index); |
2602 ? kGetterIndex | 2680 } |
2603 : kSetterIndex); | 2681 } |
2682 } | |
2683 } | |
2684 } else { | |
2685 for (Object* obj = this; | |
2686 obj != Heap::null_value(); | |
2687 obj = JSObject::cast(obj)->GetPrototype()) { | |
2688 LookupResult result; | |
2689 JSObject::cast(obj)->LocalLookup(name, &result); | |
2690 if (result.IsValid()) { | |
2691 if (result.IsReadOnly()) return Heap::undefined_value(); | |
2692 if (result.type() == CALLBACKS) { | |
2693 Object* obj = result.GetCallbackObject(); | |
2694 if (obj->IsFixedArray()) { | |
2695 return FixedArray::cast(obj)->get(accessor_index); | |
2696 } | |
2604 } | 2697 } |
2605 } | 2698 } |
2606 } | 2699 } |
2607 } | 2700 } |
2608 return Heap::undefined_value(); | 2701 return Heap::undefined_value(); |
2609 } | 2702 } |
2610 | 2703 |
2611 | 2704 |
2612 Object* JSObject::SlowReverseLookup(Object* value) { | 2705 Object* JSObject::SlowReverseLookup(Object* value) { |
2613 if (HasFastProperties()) { | 2706 if (HasFastProperties()) { |
(...skipping 2555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5169 | 5262 |
5170 // Adding n elements in fast case is O(n*n). | 5263 // Adding n elements in fast case is O(n*n). |
5171 // Note: revisit design to have dual undefined values to capture absent | 5264 // Note: revisit design to have dual undefined values to capture absent |
5172 // elements. | 5265 // elements. |
5173 Object* JSObject::SetFastElement(uint32_t index, Object* value) { | 5266 Object* JSObject::SetFastElement(uint32_t index, Object* value) { |
5174 ASSERT(HasFastElements()); | 5267 ASSERT(HasFastElements()); |
5175 | 5268 |
5176 FixedArray* elms = FixedArray::cast(elements()); | 5269 FixedArray* elms = FixedArray::cast(elements()); |
5177 uint32_t elms_length = static_cast<uint32_t>(elms->length()); | 5270 uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
5178 | 5271 |
5272 if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) { | |
5273 Object* setter = LookupCallbackSetterInPrototypes(index); | |
5274 if (setter->IsJSFunction()) { | |
5275 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); | |
5276 } | |
5277 } | |
5278 | |
5179 // Check whether there is extra space in fixed array.. | 5279 // Check whether there is extra space in fixed array.. |
5180 if (index < elms_length) { | 5280 if (index < elms_length) { |
5181 elms->set(index, value); | 5281 elms->set(index, value); |
5182 if (IsJSArray()) { | 5282 if (IsJSArray()) { |
5183 // Update the length of the array if needed. | 5283 // Update the length of the array if needed. |
5184 uint32_t array_length = 0; | 5284 uint32_t array_length = 0; |
5185 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), | 5285 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), |
5186 &array_length)); | 5286 &array_length)); |
5187 if (index >= array_length) { | 5287 if (index >= array_length) { |
5188 JSArray::cast(this)->set_length(Smi::FromInt(index + 1), | 5288 JSArray::cast(this)->set_length(Smi::FromInt(index + 1), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5238 | 5338 |
5239 // Fast case. | 5339 // Fast case. |
5240 if (HasFastElements()) return SetFastElement(index, value); | 5340 if (HasFastElements()) return SetFastElement(index, value); |
5241 | 5341 |
5242 // Dictionary case. | 5342 // Dictionary case. |
5243 ASSERT(!HasFastElements()); | 5343 ASSERT(!HasFastElements()); |
5244 | 5344 |
5245 // Insert element in the dictionary. | 5345 // Insert element in the dictionary. |
5246 FixedArray* elms = FixedArray::cast(elements()); | 5346 FixedArray* elms = FixedArray::cast(elements()); |
5247 Dictionary* dictionary = Dictionary::cast(elms); | 5347 Dictionary* dictionary = Dictionary::cast(elms); |
5248 Object* result = dictionary->AtNumberPut(index, value); | 5348 |
5249 if (result->IsFailure()) return result; | 5349 int entry = dictionary->FindNumberEntry(index); |
5250 if (elms != FixedArray::cast(result)) { | 5350 if (entry != -1) { |
5251 set_elements(FixedArray::cast(result)); | 5351 Object* element = dictionary->ValueAt(entry); |
5352 PropertyDetails details = dictionary->DetailsAt(entry); | |
5353 if (details.type() == CALLBACKS) { | |
5354 // Only accessors allowed as elements. | |
5355 FixedArray* structure = FixedArray::cast(element); | |
5356 if (structure->get(kSetterIndex)->IsJSFunction()) { | |
Mads Ager (chromium)
2009/03/13 10:27:14
I believe that we throw exceptions when setting na
olehougaard
2009/03/13 11:39:46
That's true. I've fixed it and added a test for it
| |
5357 JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex)); | |
5358 return SetPropertyWithDefinedSetter(setter, value); | |
5359 } | |
5360 } else { | |
5361 dictionary->UpdateMaxNumberKey(index); | |
5362 dictionary->ValueAtPut(entry, value); | |
5363 } | |
5364 } else { | |
5365 // Index not already used. Look for an accessor in the prototype chain. | |
5366 if (!IsJSArray()) { | |
5367 Object* setter = LookupCallbackSetterInPrototypes(index); | |
5368 if (setter->IsJSFunction()) { | |
5369 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); | |
5370 } | |
5371 } | |
5372 Object* result = dictionary->AtNumberPut(index, value); | |
5373 if (result->IsFailure()) return result; | |
5374 if (elms != FixedArray::cast(result)) { | |
5375 set_elements(FixedArray::cast(result)); | |
5376 } | |
5252 } | 5377 } |
5253 | 5378 |
5254 // Update the array length if this JSObject is an array. | 5379 // Update the array length if this JSObject is an array. |
5255 if (IsJSArray()) { | 5380 if (IsJSArray()) { |
5256 JSArray* array = JSArray::cast(this); | 5381 JSArray* array = JSArray::cast(this); |
5257 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value); | 5382 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value); |
5258 if (return_value->IsFailure()) return return_value; | 5383 if (return_value->IsFailure()) return return_value; |
5259 } | 5384 } |
5260 | 5385 |
5261 // Attempt to put this object back in fast case. | 5386 // Attempt to put this object back in fast case. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5374 if (HasFastElements()) { | 5499 if (HasFastElements()) { |
5375 FixedArray* elms = FixedArray::cast(elements()); | 5500 FixedArray* elms = FixedArray::cast(elements()); |
5376 if (index < static_cast<uint32_t>(elms->length())) { | 5501 if (index < static_cast<uint32_t>(elms->length())) { |
5377 Object* value = elms->get(index); | 5502 Object* value = elms->get(index); |
5378 if (!value->IsTheHole()) return value; | 5503 if (!value->IsTheHole()) return value; |
5379 } | 5504 } |
5380 } else { | 5505 } else { |
5381 Dictionary* dictionary = element_dictionary(); | 5506 Dictionary* dictionary = element_dictionary(); |
5382 int entry = dictionary->FindNumberEntry(index); | 5507 int entry = dictionary->FindNumberEntry(index); |
5383 if (entry != -1) { | 5508 if (entry != -1) { |
5384 return dictionary->ValueAt(entry); | 5509 Object* element = dictionary->ValueAt(entry); |
5510 PropertyDetails details = dictionary->DetailsAt(entry); | |
5511 if (details.type() == CALLBACKS) { | |
5512 // Only accessors allowed as elements. | |
5513 FixedArray* structure = FixedArray::cast(element); | |
5514 Object* getter = structure->get(kGetterIndex); | |
5515 if (getter->IsJSFunction()) { | |
5516 return GetPropertyWithDefinedGetter(receiver, | |
5517 JSFunction::cast(getter)); | |
5518 } | |
5519 } | |
5520 return element; | |
5385 } | 5521 } |
5386 } | 5522 } |
5387 | 5523 |
5388 Object* pt = GetPrototype(); | 5524 Object* pt = GetPrototype(); |
5389 if (pt == Heap::null_value()) return Heap::undefined_value(); | 5525 if (pt == Heap::null_value()) return Heap::undefined_value(); |
5390 return pt->GetElementWithReceiver(receiver, index); | 5526 return pt->GetElementWithReceiver(receiver, index); |
5391 } | 5527 } |
5392 | 5528 |
5393 | 5529 |
5394 bool JSObject::HasDenseElements() { | 5530 bool JSObject::HasDenseElements() { |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5889 return hash; | 6025 return hash; |
5890 } | 6026 } |
5891 | 6027 |
5892 | 6028 |
5893 // The NumberKey uses carries the uint32_t as key. | 6029 // The NumberKey uses carries the uint32_t as key. |
5894 // This avoids allocation in HasProperty. | 6030 // This avoids allocation in HasProperty. |
5895 class NumberKey : public HashTableKey { | 6031 class NumberKey : public HashTableKey { |
5896 public: | 6032 public: |
5897 explicit NumberKey(uint32_t number) : number_(number) { } | 6033 explicit NumberKey(uint32_t number) : number_(number) { } |
5898 | 6034 |
5899 private: | |
5900 bool IsMatch(Object* number) { | 6035 bool IsMatch(Object* number) { |
5901 return number_ == ToUint32(number); | 6036 return number_ == ToUint32(number); |
5902 } | 6037 } |
5903 | 6038 |
5904 uint32_t Hash() { return ComputeIntegerHash(number_); } | 6039 uint32_t Hash() { return ComputeIntegerHash(number_); } |
5905 | 6040 |
5906 HashFunction GetHashFunction() { return NumberHash; } | 6041 HashFunction GetHashFunction() { return NumberHash; } |
5907 | 6042 |
5908 Object* GetObject() { | 6043 Object* GetObject() { |
5909 return Heap::NumberFromDouble(number_); | 6044 return Heap::NumberFromDouble(number_); |
5910 } | 6045 } |
5911 | 6046 |
6047 bool IsStringKey() { return false; } | |
6048 | |
6049 private: | |
5912 static uint32_t NumberHash(Object* obj) { | 6050 static uint32_t NumberHash(Object* obj) { |
5913 return ComputeIntegerHash(ToUint32(obj)); | 6051 return ComputeIntegerHash(ToUint32(obj)); |
5914 } | 6052 } |
5915 | 6053 |
5916 static uint32_t ToUint32(Object* obj) { | 6054 static uint32_t ToUint32(Object* obj) { |
5917 ASSERT(obj->IsNumber()); | 6055 ASSERT(obj->IsNumber()); |
5918 return static_cast<uint32_t>(obj->Number()); | 6056 return static_cast<uint32_t>(obj->Number()); |
5919 } | 6057 } |
5920 | 6058 |
5921 bool IsStringKey() { return false; } | |
5922 | |
5923 uint32_t number_; | 6059 uint32_t number_; |
5924 }; | 6060 }; |
5925 | 6061 |
5926 | 6062 |
5927 // StringKey simply carries a string object as key. | 6063 // StringKey simply carries a string object as key. |
5928 class StringKey : public HashTableKey { | 6064 class StringKey : public HashTableKey { |
5929 public: | 6065 public: |
5930 explicit StringKey(String* string) : string_(string) { } | 6066 explicit StringKey(String* string) : string_(string) { } |
5931 | 6067 |
5932 bool IsMatch(Object* string) { | 6068 bool IsMatch(Object* string) { |
(...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6709 } | 6845 } |
6710 | 6846 |
6711 | 6847 |
6712 void Dictionary::UpdateMaxNumberKey(uint32_t key) { | 6848 void Dictionary::UpdateMaxNumberKey(uint32_t key) { |
6713 // If the dictionary requires slow elements an element has already | 6849 // If the dictionary requires slow elements an element has already |
6714 // been added at a high index. | 6850 // been added at a high index. |
6715 if (requires_slow_elements()) return; | 6851 if (requires_slow_elements()) return; |
6716 // Check if this index is high enough that we should require slow | 6852 // Check if this index is high enough that we should require slow |
6717 // elements. | 6853 // elements. |
6718 if (key > kRequiresSlowElementsLimit) { | 6854 if (key > kRequiresSlowElementsLimit) { |
6719 set(kMaxNumberKeyIndex, | 6855 set_requires_slow_elements(); |
6720 Smi::FromInt(kRequiresSlowElementsMask), | |
6721 SKIP_WRITE_BARRIER); | |
6722 return; | 6856 return; |
6723 } | 6857 } |
6724 // Update max key value. | 6858 // Update max key value. |
6725 Object* max_index_object = get(kMaxNumberKeyIndex); | 6859 Object* max_index_object = get(kMaxNumberKeyIndex); |
6726 if (!max_index_object->IsSmi() || max_number_key() < key) { | 6860 if (!max_index_object->IsSmi() || max_number_key() < key) { |
6727 set(kMaxNumberKeyIndex, | 6861 set(kMaxNumberKeyIndex, |
6728 Smi::FromInt(key << kRequiresSlowElementsTagSize), | 6862 Smi::FromInt(key << kRequiresSlowElementsTagSize), |
6729 SKIP_WRITE_BARRIER); | 6863 SKIP_WRITE_BARRIER); |
6730 } | 6864 } |
6731 } | 6865 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6771 if (entry == -1) return AddStringEntry(key, value, details); | 6905 if (entry == -1) return AddStringEntry(key, value, details); |
6772 // Preserve enumeration index. | 6906 // Preserve enumeration index. |
6773 details = PropertyDetails(details.attributes(), | 6907 details = PropertyDetails(details.attributes(), |
6774 details.type(), | 6908 details.type(), |
6775 DetailsAt(entry).index()); | 6909 DetailsAt(entry).index()); |
6776 SetEntry(entry, key, value, details); | 6910 SetEntry(entry, key, value, details); |
6777 return this; | 6911 return this; |
6778 } | 6912 } |
6779 | 6913 |
6780 | 6914 |
6915 Object* Dictionary::SetOrAddNumberEntry(uint32_t key, | |
6916 Object* value, | |
6917 PropertyDetails details) { | |
6918 NumberKey k(key); | |
6919 int entry = FindEntry(&k); | |
6920 if (entry == -1) return AddNumberEntry(key, value, details); | |
6921 // Preserve enumeration index. | |
6922 details = PropertyDetails(details.attributes(), | |
6923 details.type(), | |
6924 DetailsAt(entry).index()); | |
6925 SetEntry(entry, k.GetObject(), value, details); | |
6926 return this; | |
6927 } | |
6928 | |
6929 | |
6781 int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) { | 6930 int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) { |
6782 int capacity = Capacity(); | 6931 int capacity = Capacity(); |
6783 int result = 0; | 6932 int result = 0; |
6784 for (int i = 0; i < capacity; i++) { | 6933 for (int i = 0; i < capacity; i++) { |
6785 Object* k = KeyAt(i); | 6934 Object* k = KeyAt(i); |
6786 if (IsKey(k)) { | 6935 if (IsKey(k)) { |
6787 PropertyAttributes attr = DetailsAt(i).attributes(); | 6936 PropertyAttributes attr = DetailsAt(i).attributes(); |
6788 if ((attr & filter) == 0) result++; | 6937 if ((attr & filter) == 0) result++; |
6789 } | 6938 } |
6790 } | 6939 } |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7214 // No break point. | 7363 // No break point. |
7215 if (break_point_objects()->IsUndefined()) return 0; | 7364 if (break_point_objects()->IsUndefined()) return 0; |
7216 // Single beak point. | 7365 // Single beak point. |
7217 if (!break_point_objects()->IsFixedArray()) return 1; | 7366 if (!break_point_objects()->IsFixedArray()) return 1; |
7218 // Multiple break points. | 7367 // Multiple break points. |
7219 return FixedArray::cast(break_point_objects())->length(); | 7368 return FixedArray::cast(break_point_objects())->length(); |
7220 } | 7369 } |
7221 | 7370 |
7222 | 7371 |
7223 } } // namespace v8::internal | 7372 } } // namespace v8::internal |
OLD | NEW |