| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 1659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1670 | 1670 |
| 1671 MaybeObject* JSObject::AddProperty(String* name, | 1671 MaybeObject* JSObject::AddProperty(String* name, |
| 1672 Object* value, | 1672 Object* value, |
| 1673 PropertyAttributes attributes, | 1673 PropertyAttributes attributes, |
| 1674 StrictModeFlag strict_mode, | 1674 StrictModeFlag strict_mode, |
| 1675 JSReceiver::StoreFromKeyed store_mode, | 1675 JSReceiver::StoreFromKeyed store_mode, |
| 1676 ExtensibilityCheck extensibility_check) { | 1676 ExtensibilityCheck extensibility_check) { |
| 1677 ASSERT(!IsJSGlobalProxy()); | 1677 ASSERT(!IsJSGlobalProxy()); |
| 1678 Map* map_of_this = map(); | 1678 Map* map_of_this = map(); |
| 1679 Heap* heap = GetHeap(); | 1679 Heap* heap = GetHeap(); |
| 1680 MaybeObject* result; |
| 1680 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && | 1681 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && |
| 1681 !map_of_this->is_extensible()) { | 1682 !map_of_this->is_extensible()) { |
| 1682 if (strict_mode == kNonStrictMode) { | 1683 if (strict_mode == kNonStrictMode) { |
| 1683 return value; | 1684 return value; |
| 1684 } else { | 1685 } else { |
| 1685 Handle<Object> args[1] = {Handle<String>(name)}; | 1686 Handle<Object> args[1] = {Handle<String>(name)}; |
| 1686 return heap->isolate()->Throw( | 1687 return heap->isolate()->Throw( |
| 1687 *FACTORY->NewTypeError("object_not_extensible", | 1688 *FACTORY->NewTypeError("object_not_extensible", |
| 1688 HandleVector(args, 1))); | 1689 HandleVector(args, 1))); |
| 1689 } | 1690 } |
| 1690 } | 1691 } |
| 1692 |
| 1691 if (HasFastProperties()) { | 1693 if (HasFastProperties()) { |
| 1692 // Ensure the descriptor array does not get too big. | 1694 // Ensure the descriptor array does not get too big. |
| 1693 if (map_of_this->NumberOfOwnDescriptors() < | 1695 if (map_of_this->NumberOfOwnDescriptors() < |
| 1694 DescriptorArray::kMaxNumberOfDescriptors) { | 1696 DescriptorArray::kMaxNumberOfDescriptors) { |
| 1695 if (value->IsJSFunction()) { | 1697 if (value->IsJSFunction()) { |
| 1696 return AddConstantFunctionProperty(name, | 1698 result = AddConstantFunctionProperty(name, |
| 1697 JSFunction::cast(value), | 1699 JSFunction::cast(value), |
| 1698 attributes); | 1700 attributes); |
| 1699 } else { | 1701 } else { |
| 1700 return AddFastProperty(name, value, attributes, store_mode); | 1702 result = AddFastProperty(name, value, attributes, store_mode); |
| 1701 } | 1703 } |
| 1702 } else { | 1704 } else { |
| 1703 // Normalize the object to prevent very large instance descriptors. | 1705 // Normalize the object to prevent very large instance descriptors. |
| 1704 // This eliminates unwanted N^2 allocation and lookup behavior. | 1706 // This eliminates unwanted N^2 allocation and lookup behavior. |
| 1705 Object* obj; | 1707 Object* obj; |
| 1706 { MaybeObject* maybe_obj = | 1708 MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 1707 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 1709 if (!maybe->To(&obj)) return maybe; |
| 1708 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1710 result = AddSlowProperty(name, value, attributes); |
| 1709 } | |
| 1710 } | 1711 } |
| 1712 } else { |
| 1713 result = AddSlowProperty(name, value, attributes); |
| 1711 } | 1714 } |
| 1712 return AddSlowProperty(name, value, attributes); | 1715 |
| 1716 Handle<Object> hresult; |
| 1717 if (!result->ToHandle(&hresult)) return result; |
| 1718 |
| 1719 if (FLAG_harmony_observation && map()->is_observed()) { |
| 1720 this->EnqueueChangeRecord( |
| 1721 "new", handle(name), handle(heap->the_hole_value())); |
| 1722 } |
| 1723 |
| 1724 return *hresult; |
| 1713 } | 1725 } |
| 1714 | 1726 |
| 1715 | 1727 |
| 1728 void JSObject::EnqueueChangeRecord( |
| 1729 const char* type_str, Handle<String> name, Handle<Object> old_value) { |
| 1730 Isolate* isolate = GetIsolate(); |
| 1731 HandleScope scope; |
| 1732 Handle<String> type = isolate->factory()->LookupAsciiSymbol(type_str); |
| 1733 Handle<JSObject> object(this); |
| 1734 Handle<Object> args[] = { type, object, name, old_value }; |
| 1735 bool threw; |
| 1736 Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()), |
| 1737 Handle<Object>(isolate->heap()->undefined_value()), |
| 1738 old_value->IsTheHole() ? 3 : 4, args, |
| 1739 &threw); |
| 1740 ASSERT(!threw); |
| 1741 } |
| 1742 |
| 1743 |
| 1716 MaybeObject* JSObject::SetPropertyPostInterceptor( | 1744 MaybeObject* JSObject::SetPropertyPostInterceptor( |
| 1717 String* name, | 1745 String* name, |
| 1718 Object* value, | 1746 Object* value, |
| 1719 PropertyAttributes attributes, | 1747 PropertyAttributes attributes, |
| 1720 StrictModeFlag strict_mode, | 1748 StrictModeFlag strict_mode, |
| 1721 ExtensibilityCheck extensibility_check) { | 1749 ExtensibilityCheck extensibility_check) { |
| 1722 // Check local property, ignore interceptor. | 1750 // Check local property, ignore interceptor. |
| 1723 LookupResult result(GetIsolate()); | 1751 LookupResult result(GetIsolate()); |
| 1724 LocalLookupRealNamedProperty(name, &result); | 1752 LocalLookupRealNamedProperty(name, &result); |
| 1725 if (!result.IsFound()) map()->LookupTransition(this, name, &result); | 1753 if (!result.IsFound()) map()->LookupTransition(this, name, &result); |
| (...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2795 | 2823 |
| 2796 | 2824 |
| 2797 void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, | 2825 void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, |
| 2798 Handle<Map> map) { | 2826 Handle<Map> map) { |
| 2799 CALL_HEAP_FUNCTION_VOID( | 2827 CALL_HEAP_FUNCTION_VOID( |
| 2800 object->GetIsolate(), | 2828 object->GetIsolate(), |
| 2801 object->AddFastPropertyUsingMap(*map)); | 2829 object->AddFastPropertyUsingMap(*map)); |
| 2802 } | 2830 } |
| 2803 | 2831 |
| 2804 | 2832 |
| 2805 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, | 2833 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, |
| 2806 String* name_raw, | 2834 String* name_raw, |
| 2807 Object* value_raw, | 2835 Object* value_raw, |
| 2808 PropertyAttributes attributes, | 2836 PropertyAttributes attributes, |
| 2809 StrictModeFlag strict_mode, | 2837 StrictModeFlag strict_mode, |
| 2810 StoreFromKeyed store_mode) { | 2838 StoreFromKeyed store_mode) { |
| 2811 Heap* heap = GetHeap(); | 2839 Heap* heap = GetHeap(); |
| 2812 // Make sure that the top context does not change when doing callbacks or | 2840 // Make sure that the top context does not change when doing callbacks or |
| 2813 // interceptor calls. | 2841 // interceptor calls. |
| 2814 AssertNoContextChange ncc; | 2842 AssertNoContextChange ncc; |
| 2815 | 2843 |
| 2816 // Optimization for 2-byte strings often used as keys in a decompression | 2844 // Optimization for 2-byte strings often used as keys in a decompression |
| 2817 // dictionary. We make these short keys into symbols to avoid constantly | 2845 // dictionary. We make these short keys into symbols to avoid constantly |
| 2818 // reallocating them. | 2846 // reallocating them. |
| 2819 if (!name_raw->IsSymbol() && name_raw->length() <= 2) { | 2847 if (!name_raw->IsSymbol() && name_raw->length() <= 2) { |
| 2820 Object* symbol_version; | 2848 Object* symbol_version; |
| 2821 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name_raw); | 2849 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name_raw); |
| 2822 if (maybe_symbol_version->ToObject(&symbol_version)) { | 2850 if (maybe_symbol_version->ToObject(&symbol_version)) { |
| 2823 name_raw = String::cast(symbol_version); | 2851 name_raw = String::cast(symbol_version); |
| 2824 } | 2852 } |
| 2825 } | 2853 } |
| 2826 } | 2854 } |
| 2827 | 2855 |
| 2828 // Check access rights if needed. | 2856 // Check access rights if needed. |
| 2829 if (IsAccessCheckNeeded()) { | 2857 if (IsAccessCheckNeeded()) { |
| 2830 if (!heap->isolate()->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { | 2858 if (!heap->isolate()->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { |
| 2831 return SetPropertyWithFailedAccessCheck( | 2859 return SetPropertyWithFailedAccessCheck( |
| 2832 result, name_raw, value_raw, true, strict_mode); | 2860 lookup, name_raw, value_raw, true, strict_mode); |
| 2833 } | 2861 } |
| 2834 } | 2862 } |
| 2835 | 2863 |
| 2836 if (IsJSGlobalProxy()) { | 2864 if (IsJSGlobalProxy()) { |
| 2837 Object* proto = GetPrototype(); | 2865 Object* proto = GetPrototype(); |
| 2838 if (proto->IsNull()) return value_raw; | 2866 if (proto->IsNull()) return value_raw; |
| 2839 ASSERT(proto->IsJSGlobalObject()); | 2867 ASSERT(proto->IsJSGlobalObject()); |
| 2840 return JSObject::cast(proto)->SetPropertyForResult( | 2868 return JSObject::cast(proto)->SetPropertyForResult( |
| 2841 result, name_raw, value_raw, attributes, strict_mode, store_mode); | 2869 lookup, name_raw, value_raw, attributes, strict_mode, store_mode); |
| 2842 } | 2870 } |
| 2843 | 2871 |
| 2844 // From this point on everything needs to be handlified, because | 2872 // From this point on everything needs to be handlified, because |
| 2845 // SetPropertyViaPrototypes might call back into JavaScript. | 2873 // SetPropertyViaPrototypes might call back into JavaScript. |
| 2846 HandleScope scope(GetIsolate()); | 2874 HandleScope scope(GetIsolate()); |
| 2847 Handle<JSObject> self(this); | 2875 Handle<JSObject> self(this); |
| 2848 Handle<String> name(name_raw); | 2876 Handle<String> name(name_raw); |
| 2849 Handle<Object> value(value_raw); | 2877 Handle<Object> value(value_raw); |
| 2850 | 2878 |
| 2851 if (!result->IsProperty() && !self->IsJSContextExtensionObject()) { | 2879 if (!lookup->IsProperty() && !self->IsJSContextExtensionObject()) { |
| 2852 bool done = false; | 2880 bool done = false; |
| 2853 MaybeObject* result_object = self->SetPropertyViaPrototypes( | 2881 MaybeObject* result_object = self->SetPropertyViaPrototypes( |
| 2854 *name, *value, attributes, strict_mode, &done); | 2882 *name, *value, attributes, strict_mode, &done); |
| 2855 if (done) return result_object; | 2883 if (done) return result_object; |
| 2856 } | 2884 } |
| 2857 | 2885 |
| 2858 if (!result->IsFound()) { | 2886 if (!lookup->IsFound()) { |
| 2859 // Neither properties nor transitions found. | 2887 // Neither properties nor transitions found. |
| 2860 return self->AddProperty( | 2888 return self->AddProperty( |
| 2861 *name, *value, attributes, strict_mode, store_mode); | 2889 *name, *value, attributes, strict_mode, store_mode); |
| 2862 } | 2890 } |
| 2863 if (result->IsProperty() && result->IsReadOnly()) { | 2891 |
| 2892 if (lookup->IsProperty() && lookup->IsReadOnly()) { |
| 2864 if (strict_mode == kStrictMode) { | 2893 if (strict_mode == kStrictMode) { |
| 2865 Handle<Object> args[] = { name, self }; | 2894 Handle<Object> args[] = { name, self }; |
| 2866 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( | 2895 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( |
| 2867 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); | 2896 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); |
| 2868 } else { | 2897 } else { |
| 2869 return *value; | 2898 return *value; |
| 2870 } | 2899 } |
| 2871 } | 2900 } |
| 2872 | 2901 |
| 2902 Handle<Object> old_value(heap->the_hole_value()); |
| 2903 if (FLAG_harmony_observation && map()->is_observed()) { |
| 2904 // TODO(observe): save oldValue |
| 2905 } |
| 2906 |
| 2873 // This is a real property that is not read-only, or it is a | 2907 // This is a real property that is not read-only, or it is a |
| 2874 // transition or null descriptor and there are no setters in the prototypes. | 2908 // transition or null descriptor and there are no setters in the prototypes. |
| 2875 switch (result->type()) { | 2909 MaybeObject* result = *value; |
| 2910 switch (lookup->type()) { |
| 2876 case NORMAL: | 2911 case NORMAL: |
| 2877 return self->SetNormalizedProperty(result, *value); | 2912 result = self->SetNormalizedProperty(lookup, *value); |
| 2913 break; |
| 2878 case FIELD: | 2914 case FIELD: |
| 2879 return self->FastPropertyAtPut(result->GetFieldIndex(), *value); | 2915 result = self->FastPropertyAtPut(lookup->GetFieldIndex(), *value); |
| 2916 break; |
| 2880 case CONSTANT_FUNCTION: | 2917 case CONSTANT_FUNCTION: |
| 2881 // Only replace the function if necessary. | 2918 // Only replace the function if necessary. |
| 2882 if (*value == result->GetConstantFunction()) return *value; | 2919 if (*value == lookup->GetConstantFunction()) return *value; |
| 2883 // Preserve the attributes of this existing property. | 2920 // Preserve the attributes of this existing property. |
| 2884 attributes = result->GetAttributes(); | 2921 attributes = lookup->GetAttributes(); |
| 2885 return self->ConvertDescriptorToField(*name, *value, attributes); | 2922 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 2923 break; |
| 2886 case CALLBACKS: { | 2924 case CALLBACKS: { |
| 2887 Object* callback_object = result->GetCallbackObject(); | 2925 Object* callback_object = lookup->GetCallbackObject(); |
| 2888 return self->SetPropertyWithCallback(callback_object, | 2926 return self->SetPropertyWithCallback(callback_object, |
| 2889 *name, | 2927 *name, |
| 2890 *value, | 2928 *value, |
| 2891 result->holder(), | 2929 lookup->holder(), |
| 2892 strict_mode); | 2930 strict_mode); |
| 2893 } | 2931 } |
| 2894 case INTERCEPTOR: | 2932 case INTERCEPTOR: |
| 2895 return self->SetPropertyWithInterceptor(*name, | 2933 result = self->SetPropertyWithInterceptor(*name, |
| 2896 *value, | 2934 *value, |
| 2897 attributes, | 2935 attributes, |
| 2898 strict_mode); | 2936 strict_mode); |
| 2937 break; |
| 2899 case TRANSITION: { | 2938 case TRANSITION: { |
| 2900 Map* transition_map = result->GetTransitionTarget(); | 2939 Map* transition_map = lookup->GetTransitionTarget(); |
| 2901 int descriptor = transition_map->LastAdded(); | 2940 int descriptor = transition_map->LastAdded(); |
| 2902 | 2941 |
| 2903 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 2942 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
| 2904 PropertyDetails details = descriptors->GetDetails(descriptor); | 2943 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 2905 | 2944 |
| 2906 if (details.type() == FIELD) { | 2945 if (details.type() == FIELD) { |
| 2907 if (attributes == details.attributes()) { | 2946 if (attributes == details.attributes()) { |
| 2908 int field_index = descriptors->GetFieldIndex(descriptor); | 2947 int field_index = descriptors->GetFieldIndex(descriptor); |
| 2909 return self->AddFastPropertyUsingMap(transition_map, | 2948 result = self->AddFastPropertyUsingMap(transition_map, |
| 2910 *name, | 2949 *name, |
| 2911 *value, | 2950 *value, |
| 2912 field_index); | 2951 field_index); |
| 2952 } else { |
| 2953 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 2913 } | 2954 } |
| 2914 return self->ConvertDescriptorToField(*name, *value, attributes); | |
| 2915 } else if (details.type() == CALLBACKS) { | 2955 } else if (details.type() == CALLBACKS) { |
| 2916 return ConvertDescriptorToField(*name, *value, attributes); | 2956 result = ConvertDescriptorToField(*name, *value, attributes); |
| 2957 } else { |
| 2958 ASSERT(details.type() == CONSTANT_FUNCTION); |
| 2959 |
| 2960 Object* constant_function = descriptors->GetValue(descriptor); |
| 2961 if (constant_function == *value) { |
| 2962 // If the same constant function is being added we can simply |
| 2963 // transition to the target map. |
| 2964 self->set_map(transition_map); |
| 2965 result = constant_function; |
| 2966 } else { |
| 2967 // Otherwise, replace with a map transition to a new map with a FIELD, |
| 2968 // even if the value is a constant function. |
| 2969 result = ConvertTransitionToMapTransition( |
| 2970 lookup->GetTransitionIndex(), *name, *value, attributes); |
| 2971 } |
| 2917 } | 2972 } |
| 2918 | 2973 break; |
| 2919 ASSERT(details.type() == CONSTANT_FUNCTION); | |
| 2920 | |
| 2921 Object* constant_function = descriptors->GetValue(descriptor); | |
| 2922 // If the same constant function is being added we can simply | |
| 2923 // transition to the target map. | |
| 2924 if (constant_function == *value) { | |
| 2925 self->set_map(transition_map); | |
| 2926 return constant_function; | |
| 2927 } | |
| 2928 // Otherwise, replace with a map transition to a new map with a FIELD, | |
| 2929 // even if the value is a constant function. | |
| 2930 return ConvertTransitionToMapTransition( | |
| 2931 result->GetTransitionIndex(), *name, *value, attributes); | |
| 2932 } | 2974 } |
| 2933 case HANDLER: | 2975 case HANDLER: |
| 2934 case NONEXISTENT: | 2976 case NONEXISTENT: |
| 2935 UNREACHABLE(); | 2977 UNREACHABLE(); |
| 2936 return *value; | |
| 2937 } | 2978 } |
| 2938 UNREACHABLE(); // keep the compiler happy | 2979 |
| 2939 return *value; | 2980 Handle<Object> hresult; |
| 2981 if (!result->ToHandle(&hresult)) return result; |
| 2982 |
| 2983 if (FLAG_harmony_observation && map()->is_observed()) { |
| 2984 this->EnqueueChangeRecord("updated", name, old_value); |
| 2985 } |
| 2986 |
| 2987 return *hresult; |
| 2940 } | 2988 } |
| 2941 | 2989 |
| 2942 | 2990 |
| 2943 // Set a real local property, even if it is READ_ONLY. If the property is not | 2991 // Set a real local property, even if it is READ_ONLY. If the property is not |
| 2944 // present, add it with attributes NONE. This code is an exact clone of | 2992 // present, add it with attributes NONE. This code is an exact clone of |
| 2945 // SetProperty, with the check for IsReadOnly and the check for a | 2993 // SetProperty, with the check for IsReadOnly and the check for a |
| 2946 // callback setter removed. The two lines looking up the LookupResult | 2994 // callback setter removed. The two lines looking up the LookupResult |
| 2947 // result are also added. If one of the functions is changed, the other | 2995 // result are also added. If one of the functions is changed, the other |
| 2948 // should be. | 2996 // should be. |
| 2949 // Note that this method cannot be used to set the prototype of a function | 2997 // Note that this method cannot be used to set the prototype of a function |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2962 | 3010 |
| 2963 | 3011 |
| 2964 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( | 3012 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( |
| 2965 String* name, | 3013 String* name, |
| 2966 Object* value, | 3014 Object* value, |
| 2967 PropertyAttributes attributes) { | 3015 PropertyAttributes attributes) { |
| 2968 // Make sure that the top context does not change when doing callbacks or | 3016 // Make sure that the top context does not change when doing callbacks or |
| 2969 // interceptor calls. | 3017 // interceptor calls. |
| 2970 AssertNoContextChange ncc; | 3018 AssertNoContextChange ncc; |
| 2971 Isolate* isolate = GetIsolate(); | 3019 Isolate* isolate = GetIsolate(); |
| 2972 LookupResult result(isolate); | 3020 LookupResult lookup(isolate); |
| 2973 LocalLookup(name, &result); | 3021 LocalLookup(name, &lookup); |
| 2974 if (!result.IsFound()) map()->LookupTransition(this, name, &result); | 3022 if (!lookup.IsFound()) map()->LookupTransition(this, name, &lookup); |
| 2975 // Check access rights if needed. | 3023 // Check access rights if needed. |
| 2976 if (IsAccessCheckNeeded()) { | 3024 if (IsAccessCheckNeeded()) { |
| 2977 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 3025 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { |
| 2978 return SetPropertyWithFailedAccessCheck(&result, | 3026 return SetPropertyWithFailedAccessCheck(&lookup, |
| 2979 name, | 3027 name, |
| 2980 value, | 3028 value, |
| 2981 false, | 3029 false, |
| 2982 kNonStrictMode); | 3030 kNonStrictMode); |
| 2983 } | 3031 } |
| 2984 } | 3032 } |
| 2985 | 3033 |
| 2986 if (IsJSGlobalProxy()) { | 3034 if (IsJSGlobalProxy()) { |
| 2987 Object* proto = GetPrototype(); | 3035 Object* proto = GetPrototype(); |
| 2988 if (proto->IsNull()) return value; | 3036 if (proto->IsNull()) return value; |
| 2989 ASSERT(proto->IsJSGlobalObject()); | 3037 ASSERT(proto->IsJSGlobalObject()); |
| 2990 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( | 3038 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( |
| 2991 name, | 3039 name, |
| 2992 value, | 3040 value, |
| 2993 attributes); | 3041 attributes); |
| 2994 } | 3042 } |
| 2995 | 3043 |
| 2996 // Check for accessor in prototype chain removed here in clone. | 3044 // Check for accessor in prototype chain removed here in clone. |
| 2997 if (!result.IsFound()) { | 3045 if (!lookup.IsFound()) { |
| 2998 // Neither properties nor transitions found. | 3046 // Neither properties nor transitions found. |
| 2999 return AddProperty(name, value, attributes, kNonStrictMode); | 3047 return AddProperty(name, value, attributes, kNonStrictMode); |
| 3000 } | 3048 } |
| 3001 | 3049 |
| 3050 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 3051 if (FLAG_harmony_observation && map()->is_observed()) { |
| 3052 // TODO(observe): save oldValue |
| 3053 } |
| 3054 |
| 3002 // Check of IsReadOnly removed from here in clone. | 3055 // Check of IsReadOnly removed from here in clone. |
| 3003 switch (result.type()) { | 3056 MaybeObject* result = value; |
| 3057 switch (lookup.type()) { |
| 3004 case NORMAL: { | 3058 case NORMAL: { |
| 3005 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 3059 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
| 3006 return SetNormalizedProperty(name, value, details); | 3060 result = SetNormalizedProperty(name, value, details); |
| 3061 break; |
| 3007 } | 3062 } |
| 3008 case FIELD: | 3063 case FIELD: |
| 3009 return FastPropertyAtPut(result.GetFieldIndex(), value); | 3064 result = FastPropertyAtPut(lookup.GetFieldIndex(), value); |
| 3065 break; |
| 3010 case CONSTANT_FUNCTION: | 3066 case CONSTANT_FUNCTION: |
| 3011 // Only replace the function if necessary. | 3067 // Only replace the function if necessary. |
| 3012 if (value == result.GetConstantFunction()) return value; | 3068 if (value == lookup.GetConstantFunction()) return value; |
| 3013 // Preserve the attributes of this existing property. | 3069 // Preserve the attributes of this existing property. |
| 3014 attributes = result.GetAttributes(); | 3070 attributes = lookup.GetAttributes(); |
| 3015 return ConvertDescriptorToField(name, value, attributes); | 3071 result = ConvertDescriptorToField(name, value, attributes); |
| 3072 break; |
| 3016 case CALLBACKS: | 3073 case CALLBACKS: |
| 3017 case INTERCEPTOR: | 3074 case INTERCEPTOR: |
| 3018 // Override callback in clone | 3075 // Override callback in clone |
| 3019 return ConvertDescriptorToField(name, value, attributes); | 3076 result = ConvertDescriptorToField(name, value, attributes); |
| 3077 break; |
| 3020 case TRANSITION: { | 3078 case TRANSITION: { |
| 3021 Map* transition_map = result.GetTransitionTarget(); | 3079 Map* transition_map = lookup.GetTransitionTarget(); |
| 3022 int descriptor = transition_map->LastAdded(); | 3080 int descriptor = transition_map->LastAdded(); |
| 3023 | 3081 |
| 3024 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3082 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
| 3025 PropertyDetails details = descriptors->GetDetails(descriptor); | 3083 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 3026 | 3084 |
| 3027 if (details.type() == FIELD) { | 3085 if (details.type() == FIELD) { |
| 3028 if (attributes == details.attributes()) { | 3086 if (attributes == details.attributes()) { |
| 3029 int field_index = descriptors->GetFieldIndex(descriptor); | 3087 int field_index = descriptors->GetFieldIndex(descriptor); |
| 3030 return AddFastPropertyUsingMap(transition_map, | 3088 result = AddFastPropertyUsingMap(transition_map, |
| 3031 name, | 3089 name, |
| 3032 value, | 3090 value, |
| 3033 field_index); | 3091 field_index); |
| 3092 } else { |
| 3093 result = ConvertDescriptorToField(name, value, attributes); |
| 3034 } | 3094 } |
| 3035 return ConvertDescriptorToField(name, value, attributes); | |
| 3036 } else if (details.type() == CALLBACKS) { | 3095 } else if (details.type() == CALLBACKS) { |
| 3037 return ConvertDescriptorToField(name, value, attributes); | 3096 result = ConvertDescriptorToField(name, value, attributes); |
| 3097 } else { |
| 3098 ASSERT(details.type() == CONSTANT_FUNCTION); |
| 3099 |
| 3100 // Replace transition to CONSTANT FUNCTION with a map transition to a |
| 3101 // new map with a FIELD, even if the value is a function. |
| 3102 result = ConvertTransitionToMapTransition( |
| 3103 lookup.GetTransitionIndex(), name, value, attributes); |
| 3038 } | 3104 } |
| 3039 | 3105 break; |
| 3040 ASSERT(details.type() == CONSTANT_FUNCTION); | |
| 3041 | |
| 3042 // Replace transition to CONSTANT FUNCTION with a map transition to a new | |
| 3043 // map with a FIELD, even if the value is a function. | |
| 3044 return ConvertTransitionToMapTransition( | |
| 3045 result.GetTransitionIndex(), name, value, attributes); | |
| 3046 } | 3106 } |
| 3047 case HANDLER: | 3107 case HANDLER: |
| 3048 case NONEXISTENT: | 3108 case NONEXISTENT: |
| 3049 UNREACHABLE(); | 3109 UNREACHABLE(); |
| 3050 } | 3110 } |
| 3051 UNREACHABLE(); // keep the compiler happy | 3111 |
| 3052 return value; | 3112 Handle<Object> hresult; |
| 3113 if (!result->ToHandle(&hresult)) return result; |
| 3114 |
| 3115 if (FLAG_harmony_observation && map()->is_observed()) { |
| 3116 const char* type = |
| 3117 attributes == lookup.GetAttributes() ? "updated" : "reconfigured"; |
| 3118 this->EnqueueChangeRecord(type, handle(name), old_value); |
| 3119 } |
| 3120 |
| 3121 return *hresult; |
| 3053 } | 3122 } |
| 3054 | 3123 |
| 3055 | 3124 |
| 3056 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 3125 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
| 3057 JSObject* receiver, | 3126 JSObject* receiver, |
| 3058 String* name, | 3127 String* name, |
| 3059 bool continue_search) { | 3128 bool continue_search) { |
| 3060 // Check local property, ignore interceptor. | 3129 // Check local property, ignore interceptor. |
| 3061 LookupResult result(GetIsolate()); | 3130 LookupResult result(GetIsolate()); |
| 3062 LocalLookupRealNamedProperty(name, &result); | 3131 LocalLookupRealNamedProperty(name, &result); |
| (...skipping 883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3946 if (IsJSGlobalProxy()) { | 4015 if (IsJSGlobalProxy()) { |
| 3947 Object* proto = GetPrototype(); | 4016 Object* proto = GetPrototype(); |
| 3948 if (proto->IsNull()) return isolate->heap()->false_value(); | 4017 if (proto->IsNull()) return isolate->heap()->false_value(); |
| 3949 ASSERT(proto->IsJSGlobalObject()); | 4018 ASSERT(proto->IsJSGlobalObject()); |
| 3950 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); | 4019 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); |
| 3951 } | 4020 } |
| 3952 | 4021 |
| 3953 uint32_t index = 0; | 4022 uint32_t index = 0; |
| 3954 if (name->AsArrayIndex(&index)) { | 4023 if (name->AsArrayIndex(&index)) { |
| 3955 return DeleteElement(index, mode); | 4024 return DeleteElement(index, mode); |
| 4025 } |
| 4026 |
| 4027 LookupResult lookup(isolate); |
| 4028 LocalLookup(name, &lookup); |
| 4029 if (!lookup.IsFound()) return isolate->heap()->true_value(); |
| 4030 // Ignore attributes if forcing a deletion. |
| 4031 if (lookup.IsDontDelete() && mode != FORCE_DELETION) { |
| 4032 if (mode == STRICT_DELETION) { |
| 4033 // Deleting a non-configurable property in strict mode. |
| 4034 HandleScope scope(isolate); |
| 4035 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; |
| 4036 return isolate->Throw(*isolate->factory()->NewTypeError( |
| 4037 "strict_delete_property", HandleVector(args, 2))); |
| 4038 } |
| 4039 return isolate->heap()->false_value(); |
| 4040 } |
| 4041 |
| 4042 HandleScope scope(isolate); |
| 4043 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 4044 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4045 // TODO(observe): save oldValue |
| 4046 } |
| 4047 MaybeObject* result; |
| 4048 |
| 4049 // Check for interceptor. |
| 4050 if (lookup.IsInterceptor()) { |
| 4051 // Skip interceptor if forcing a deletion. |
| 4052 if (mode == FORCE_DELETION) { |
| 4053 result = DeletePropertyPostInterceptor(name, mode); |
| 4054 } else { |
| 4055 result = DeletePropertyWithInterceptor(name); |
| 4056 } |
| 3956 } else { | 4057 } else { |
| 3957 LookupResult result(isolate); | |
| 3958 LocalLookup(name, &result); | |
| 3959 if (!result.IsFound()) return isolate->heap()->true_value(); | |
| 3960 // Ignore attributes if forcing a deletion. | |
| 3961 if (result.IsDontDelete() && mode != FORCE_DELETION) { | |
| 3962 if (mode == STRICT_DELETION) { | |
| 3963 // Deleting a non-configurable property in strict mode. | |
| 3964 HandleScope scope(isolate); | |
| 3965 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; | |
| 3966 return isolate->Throw(*isolate->factory()->NewTypeError( | |
| 3967 "strict_delete_property", HandleVector(args, 2))); | |
| 3968 } | |
| 3969 return isolate->heap()->false_value(); | |
| 3970 } | |
| 3971 // Check for interceptor. | |
| 3972 if (result.IsInterceptor()) { | |
| 3973 // Skip interceptor if forcing a deletion. | |
| 3974 if (mode == FORCE_DELETION) { | |
| 3975 return DeletePropertyPostInterceptor(name, mode); | |
| 3976 } | |
| 3977 return DeletePropertyWithInterceptor(name); | |
| 3978 } | |
| 3979 // Normalize object if needed. | 4058 // Normalize object if needed. |
| 3980 Object* obj; | 4059 Object* obj; |
| 3981 { MaybeObject* maybe_obj = | 4060 result = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 3982 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 4061 if (!result->ToObject(&obj)) return result; |
| 3983 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 3984 } | |
| 3985 // Make sure the properties are normalized before removing the entry. | 4062 // Make sure the properties are normalized before removing the entry. |
| 3986 return DeleteNormalizedProperty(name, mode); | 4063 result = DeleteNormalizedProperty(name, mode); |
| 3987 } | 4064 } |
| 4065 |
| 4066 Handle<Object> hresult; |
| 4067 if (!result->ToHandle(&hresult)) return result; |
| 4068 |
| 4069 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4070 this->EnqueueChangeRecord("deleted", handle(name), old_value); |
| 4071 } |
| 4072 |
| 4073 return *hresult; |
| 3988 } | 4074 } |
| 3989 | 4075 |
| 3990 | 4076 |
| 3991 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { | 4077 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { |
| 3992 if (IsJSProxy()) { | 4078 if (IsJSProxy()) { |
| 3993 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); | 4079 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); |
| 3994 } | 4080 } |
| 3995 return JSObject::cast(this)->DeleteElement(index, mode); | 4081 return JSObject::cast(this)->DeleteElement(index, mode); |
| 3996 } | 4082 } |
| 3997 | 4083 |
| (...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4605 | 4691 |
| 4606 // Make sure that the top context does not change when doing callbacks or | 4692 // Make sure that the top context does not change when doing callbacks or |
| 4607 // interceptor calls. | 4693 // interceptor calls. |
| 4608 AssertNoContextChange ncc; | 4694 AssertNoContextChange ncc; |
| 4609 | 4695 |
| 4610 // Try to flatten before operating on the string. | 4696 // Try to flatten before operating on the string. |
| 4611 name->TryFlatten(); | 4697 name->TryFlatten(); |
| 4612 | 4698 |
| 4613 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4699 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); |
| 4614 | 4700 |
| 4701 Handle<Object> old_value(isolate->heap()->the_hole_value()); |
| 4702 bool preexists; |
| 4703 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4704 LookupResult result(isolate); |
| 4705 LocalLookup(name, &result); |
| 4706 preexists = result.IsFound(); |
| 4707 // TODO(observe): save oldValue |
| 4708 } |
| 4709 |
| 4615 uint32_t index = 0; | 4710 uint32_t index = 0; |
| 4616 return name->AsArrayIndex(&index) ? | 4711 MaybeObject* result = name->AsArrayIndex(&index) |
| 4617 DefineElementAccessor(index, getter, setter, attributes) : | 4712 ? DefineElementAccessor(index, getter, setter, attributes) |
| 4618 DefinePropertyAccessor(name, getter, setter, attributes); | 4713 : DefinePropertyAccessor(name, getter, setter, attributes); |
| 4714 |
| 4715 Handle<Object> hresult; |
| 4716 if (!result->ToHandle(&hresult)) return result; |
| 4717 |
| 4718 if (FLAG_harmony_observation && map()->is_observed()) { |
| 4719 const char* type = preexists ? "reconfigured" : "new"; |
| 4720 this->EnqueueChangeRecord(type, handle(name), old_value); |
| 4721 } |
| 4722 |
| 4723 return *hresult; |
| 4619 } | 4724 } |
| 4620 | 4725 |
| 4621 | 4726 |
| 4622 static MaybeObject* TryAccessorTransition(JSObject* self, | 4727 static MaybeObject* TryAccessorTransition(JSObject* self, |
| 4623 Map* transitioned_map, | 4728 Map* transitioned_map, |
| 4624 int target_descriptor, | 4729 int target_descriptor, |
| 4625 AccessorComponent component, | 4730 AccessorComponent component, |
| 4626 Object* accessor, | 4731 Object* accessor, |
| 4627 PropertyAttributes attributes) { | 4732 PropertyAttributes attributes) { |
| 4628 DescriptorArray* descs = transitioned_map->instance_descriptors(); | 4733 DescriptorArray* descs = transitioned_map->instance_descriptors(); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4889 MaybeObject* Map::RawCopy(int instance_size) { | 4994 MaybeObject* Map::RawCopy(int instance_size) { |
| 4890 Map* result; | 4995 Map* result; |
| 4891 MaybeObject* maybe_result = | 4996 MaybeObject* maybe_result = |
| 4892 GetHeap()->AllocateMap(instance_type(), instance_size); | 4997 GetHeap()->AllocateMap(instance_type(), instance_size); |
| 4893 if (!maybe_result->To(&result)) return maybe_result; | 4998 if (!maybe_result->To(&result)) return maybe_result; |
| 4894 | 4999 |
| 4895 result->set_prototype(prototype()); | 5000 result->set_prototype(prototype()); |
| 4896 result->set_constructor(constructor()); | 5001 result->set_constructor(constructor()); |
| 4897 result->set_bit_field(bit_field()); | 5002 result->set_bit_field(bit_field()); |
| 4898 result->set_bit_field2(bit_field2()); | 5003 result->set_bit_field2(bit_field2()); |
| 4899 result->set_bit_field3(bit_field3()); | |
| 4900 int new_bit_field3 = bit_field3(); | 5004 int new_bit_field3 = bit_field3(); |
| 4901 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); | 5005 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); |
| 4902 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); | 5006 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); |
| 4903 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); | 5007 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); |
| 4904 result->set_bit_field3(new_bit_field3); | 5008 result->set_bit_field3(new_bit_field3); |
| 4905 return result; | 5009 return result; |
| 4906 } | 5010 } |
| 4907 | 5011 |
| 4908 | 5012 |
| 4909 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, | 5013 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, |
| (...skipping 2602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7512 PropertyNormalizationMode mode) { | 7616 PropertyNormalizationMode mode) { |
| 7513 return | 7617 return |
| 7514 constructor() == other->constructor() && | 7618 constructor() == other->constructor() && |
| 7515 prototype() == other->prototype() && | 7619 prototype() == other->prototype() && |
| 7516 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? | 7620 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| 7517 0 : | 7621 0 : |
| 7518 other->inobject_properties()) && | 7622 other->inobject_properties()) && |
| 7519 instance_type() == other->instance_type() && | 7623 instance_type() == other->instance_type() && |
| 7520 bit_field() == other->bit_field() && | 7624 bit_field() == other->bit_field() && |
| 7521 bit_field2() == other->bit_field2() && | 7625 bit_field2() == other->bit_field2() && |
| 7626 is_observed() == other->is_observed() && |
| 7522 function_with_prototype() == other->function_with_prototype(); | 7627 function_with_prototype() == other->function_with_prototype(); |
| 7523 } | 7628 } |
| 7524 | 7629 |
| 7525 | 7630 |
| 7526 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { | 7631 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { |
| 7527 // Iterate over all fields in the body but take care in dealing with | 7632 // Iterate over all fields in the body but take care in dealing with |
| 7528 // the code entry. | 7633 // the code entry. |
| 7529 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); | 7634 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); |
| 7530 v->VisitCodeEntry(this->address() + kCodeEntryOffset); | 7635 v->VisitCodeEntry(this->address() + kCodeEntryOffset); |
| 7531 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); | 7636 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); |
| (...skipping 5941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13473 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13578 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
| 13474 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13579 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
| 13475 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13580 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
| 13476 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13581 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
| 13477 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13582 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
| 13478 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13583 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
| 13479 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13584 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
| 13480 } | 13585 } |
| 13481 | 13586 |
| 13482 } } // namespace v8::internal | 13587 } } // namespace v8::internal |
| OLD | NEW |