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 |