| 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 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 JSObject::cast(current)->map()->is_hidden_prototype()) { | 640 JSObject::cast(current)->map()->is_hidden_prototype()) { |
| 641 current = current->GetPrototype(); | 641 current = current->GetPrototype(); |
| 642 } | 642 } |
| 643 return current; | 643 return current; |
| 644 } | 644 } |
| 645 | 645 |
| 646 | 646 |
| 647 Object* Accessors::ObjectSetPrototype(JSObject* receiver, | 647 Object* Accessors::ObjectSetPrototype(JSObject* receiver, |
| 648 Object* value, | 648 Object* value, |
| 649 void*) { | 649 void*) { |
| 650 // Before we can set the prototype we need to be sure | 650 const bool skip_hidden_prototypes = true; |
| 651 // prototype cycles are prevented. | |
| 652 // It is sufficient to validate that the receiver is not in the new prototype | |
| 653 // chain. | |
| 654 | |
| 655 // Silently ignore the change if value is not a JSObject or null. | |
| 656 // SpiderMonkey behaves this way. | |
| 657 if (!value->IsJSObject() && !value->IsNull()) return value; | |
| 658 | |
| 659 for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) { | |
| 660 if (JSObject::cast(pt) == receiver) { | |
| 661 // Cycle detected. | |
| 662 HandleScope scope; | |
| 663 return Top::Throw(*Factory::NewError("cyclic_proto", | |
| 664 HandleVector<Object>(NULL, 0))); | |
| 665 } | |
| 666 } | |
| 667 | |
| 668 // Find the first object in the chain whose prototype object is not | |
| 669 // hidden and set the new prototype on that object. | |
| 670 JSObject* current = receiver; | |
| 671 Object* current_proto = receiver->GetPrototype(); | |
| 672 while (current_proto->IsJSObject() && | |
| 673 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { | |
| 674 current = JSObject::cast(current_proto); | |
| 675 current_proto = current_proto->GetPrototype(); | |
| 676 } | |
| 677 | |
| 678 // Set the new prototype of the object. | |
| 679 Object* new_map = current->map()->CopyDropTransitions(); | |
| 680 if (new_map->IsFailure()) return new_map; | |
| 681 Map::cast(new_map)->set_prototype(value); | |
| 682 current->set_map(Map::cast(new_map)); | |
| 683 | |
| 684 // To be consistent with other Set functions, return the value. | 651 // To be consistent with other Set functions, return the value. |
| 685 return value; | 652 return receiver->SetPrototype(value, skip_hidden_prototypes); |
| 686 } | 653 } |
| 687 | 654 |
| 688 | 655 |
| 689 const AccessorDescriptor Accessors::ObjectPrototype = { | 656 const AccessorDescriptor Accessors::ObjectPrototype = { |
| 690 ObjectGetPrototype, | 657 ObjectGetPrototype, |
| 691 ObjectSetPrototype, | 658 ObjectSetPrototype, |
| 692 0 | 659 0 |
| 693 }; | 660 }; |
| 694 | 661 |
| 695 } } // namespace v8::internal | 662 } } // namespace v8::internal |
| OLD | NEW |