Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(939)

Side by Side Diff: src/objects.cc

Issue 1368753003: Add C++ implementation of Object.defineProperties (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: refactored Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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/objects.h" 5 #include "src/objects.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <iomanip> 8 #include <iomanip>
9 #include <sstream> 9 #include <sstream>
10 10
(...skipping 19 matching lines...) Expand all
30 #include "src/hydrogen.h" 30 #include "src/hydrogen.h"
31 #include "src/ic/ic.h" 31 #include "src/ic/ic.h"
32 #include "src/interpreter/bytecodes.h" 32 #include "src/interpreter/bytecodes.h"
33 #include "src/isolate-inl.h" 33 #include "src/isolate-inl.h"
34 #include "src/log.h" 34 #include "src/log.h"
35 #include "src/lookup.h" 35 #include "src/lookup.h"
36 #include "src/macro-assembler.h" 36 #include "src/macro-assembler.h"
37 #include "src/messages.h" 37 #include "src/messages.h"
38 #include "src/objects-inl.h" 38 #include "src/objects-inl.h"
39 #include "src/profiler/cpu-profiler.h" 39 #include "src/profiler/cpu-profiler.h"
40 #include "src/property-descriptor.h"
40 #include "src/prototype.h" 41 #include "src/prototype.h"
41 #include "src/safepoint-table.h" 42 #include "src/safepoint-table.h"
42 #include "src/string-builder.h" 43 #include "src/string-builder.h"
43 #include "src/string-search.h" 44 #include "src/string-search.h"
44 #include "src/string-stream.h" 45 #include "src/string-stream.h"
45 #include "src/utils.h" 46 #include "src/utils.h"
46 47
47 #ifdef ENABLE_DISASSEMBLER 48 #ifdef ENABLE_DISASSEMBLER
48 #include "src/disasm.h" 49 #include "src/disasm.h"
49 #include "src/disassembler.h" 50 #include "src/disassembler.h"
(...skipping 5769 matching lines...) Expand 10 before | Expand all | Expand 10 after
5819 5820
5820 5821
5821 MaybeHandle<Object> JSReceiver::DeletePropertyOrElement( 5822 MaybeHandle<Object> JSReceiver::DeletePropertyOrElement(
5822 Handle<JSReceiver> object, Handle<Name> name, LanguageMode language_mode) { 5823 Handle<JSReceiver> object, Handle<Name> name, LanguageMode language_mode) {
5823 LookupIterator it = LookupIterator::PropertyOrElement( 5824 LookupIterator it = LookupIterator::PropertyOrElement(
5824 name->GetIsolate(), object, name, LookupIterator::HIDDEN); 5825 name->GetIsolate(), object, name, LookupIterator::HIDDEN);
5825 return JSObject::DeleteProperty(&it, language_mode); 5826 return JSObject::DeleteProperty(&it, language_mode);
5826 } 5827 }
5827 5828
5828 5829
5830 // ES6 7.1.14
5831 MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) {
5832 // 1. Let key be ToPrimitive(argument, hint String).
5833 MaybeHandle<Object> maybe_key =
5834 Object::ToPrimitive(value, ToPrimitiveHint::kString);
5835 // 2. ReturnIfAbrupt(key).
5836 Handle<Object> key;
5837 if (!maybe_key.ToHandle(&key)) return key;
5838 // 3. If Type(key) is Symbol, then return key.
5839 if (key->IsSymbol()) return key;
5840 // 4. Return ToString(key).
5841 // Extending spec'ed behavior, we'd be happy to return an element index.
5842 if (key->IsSmi()) return key;
5843 if (key->IsHeapNumber()) {
5844 uint32_t uint_value;
5845 if (value->ToArrayLength(&uint_value) &&
5846 uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
5847 return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
5848 }
5849 }
5850 return Object::ToString(isolate, key);
5851 }
5852
5853
5854 // ES6 19.1.2.4
5855 // static
5856 Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> o,
5857 Handle<Object> name,
5858 Handle<Object> attributes) {
5859 // 1. If Type(O) is not Object, throw a TypeError exception.
5860 // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject".
5861 if (!o->IsJSObject()) {
5862 Handle<String> fun_name =
5863 isolate->factory()->InternalizeUtf8String("Object.defineProperty");
5864 THROW_NEW_ERROR_RETURN_FAILURE(
5865 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
5866 }
5867 // 2. Let key be ToPropertyKey(P).
5868 // 3. ReturnIfAbrupt(key).
5869 Handle<Object> key;
5870 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
5871 ToPropertyKey(isolate, name));
5872 // 4. Let desc be ToPropertyDescriptor(Attributes).
5873 // 5. ReturnIfAbrupt(desc).
5874 PropertyDescriptor desc;
5875 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
5876 return isolate->heap()->exception();
5877 }
5878 // 6. Let success be DefinePropertyOrThrow(O,key, desc).
5879 bool success = DefineOwnProperty(isolate, Handle<JSObject>::cast(o), key,
5880 &desc, true /* should_throw */);
5881 // 7. ReturnIfAbrupt(success).
5882 if (isolate->has_pending_exception()) return isolate->heap()->exception();
5883 CHECK(success == true);
5884 // 8. Return O.
5885 return *o;
5886 }
5887
5888
5889 // ES6 19.1.2.3.1
5890 // static
5891 Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> o,
5892 Handle<Object> properties) {
5893 // 1. If Type(O) is not Object, throw a TypeError exception.
5894 // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject".
5895 if (!o->IsJSObject()) {
5896 Handle<String> fun_name =
5897 isolate->factory()->InternalizeUtf8String("Object.defineProperties");
5898 THROW_NEW_ERROR_RETURN_FAILURE(
5899 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
5900 }
5901 // 2. Let props be ToObject(Properties).
5902 // 3. ReturnIfAbrupt(props).
5903 Handle<JSReceiver> props;
5904 if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
5905 THROW_NEW_ERROR_RETURN_FAILURE(
5906 isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
5907 }
5908 // 4. Let keys be props.[[OwnPropertyKeys]]().
5909 // 5. ReturnIfAbrupt(keys).
5910 Handle<FixedArray> keys;
5911 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5912 isolate, keys,
5913 JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, INCLUDE_SYMBOLS));
5914 // 6. Let descriptors be an empty List.
5915 int capacity = keys->length();
5916 std::vector<PropertyDescriptor> descriptors(capacity);
5917 // 7. Repeat for each element nextKey of keys in List order,
5918 for (int i = 0; i < keys->length(); ++i) {
5919 Handle<Object> next_key(keys->get(i), isolate);
5920 // 7a. Let propDesc be props.[[GetOwnProperty]](nextKey).
5921 // 7b. ReturnIfAbrupt(propDesc).
5922 bool success = false;
5923 LookupIterator it = LookupIterator::PropertyOrElement(
5924 isolate, props, next_key, &success, LookupIterator::HIDDEN);
5925 DCHECK(success);
5926 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
Toon Verwaest 2015/10/06 15:55:18 On proxy props this will call getPropertyDescripto
Jakob Kummerow 2015/10/09 13:46:12 Ack. Follow-up -> added TODO comment.
5927 if (!maybe.IsJust()) return isolate->heap()->exception();
5928 PropertyAttributes attrs = maybe.FromJust();
5929 // 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
5930 if (attrs == ABSENT) continue;
5931 // GetKeys() only returns enumerable keys.
5932 DCHECK((attrs & DONT_ENUM) == 0);
5933 // 7c i. Let descObj be Get(props, nextKey).
5934 // 7c ii. ReturnIfAbrupt(descObj).
5935 Handle<Object> desc_obj;
5936 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, desc_obj,
5937 JSObject::GetProperty(&it));
5938 // 7c iii. Let desc be ToPropertyDescriptor(descObj).
5939 success = PropertyDescriptor::ToPropertyDescriptor(isolate, desc_obj,
5940 &descriptors[i]);
5941 // 7c iv. ReturnIfAbrupt(desc).
5942 if (!success) return isolate->heap()->exception();
5943 // 7c v. Append the pair (a two element List) consisting of nextKey and
5944 // desc to the end of descriptors.
5945 descriptors[i].set_name(next_key);
5946 }
5947 // 8. For each pair from descriptors in list order,
5948 for (int i = 0; i < descriptors.size(); ++i) {
5949 PropertyDescriptor* desc = &descriptors[i];
5950 // 8a. Let P be the first element of pair.
5951 // 8b. Let desc be the second element of pair.
5952 // 8c. Let status be DefinePropertyOrThrow(O, P, desc).
5953 bool status =
5954 DefineOwnProperty(isolate, Handle<JSObject>::cast(o), desc->name(),
5955 desc, true /* should_throw */);
5956 // 8d. ReturnIfAbrupt(status).
5957 if (isolate->has_pending_exception()) return isolate->heap()->exception();
5958 CHECK(status == true);
5959 }
5960 // 9. Return o.
5961 return *o;
5962 }
5963
5964
5965 // static
5966 bool JSReceiver::DefineOwnProperty(Isolate* isolate, Handle<JSObject> obj,
5967 Handle<Object> name,
Toon Verwaest 2015/10/06 15:55:18 DefineOwnProperty is defined in 9.1.6 to be called
Jakob Kummerow 2015/10/09 13:46:12 Done.
5968 PropertyDescriptor* desc,
5969 bool should_throw) {
5970 if (obj->IsJSArray()) {
5971 return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(obj), name,
5972 desc, should_throw);
5973 }
5974 // TODO(jkummerow): Do we need special support for arguments? (ES6 9.4.4.2)
Toon Verwaest 2015/10/06 15:55:18 I don't think so. For data properties: DefineOwnP
Jakob Kummerow 2015/10/09 13:46:12 Acknowledged.
5975 // TODO(jkummerow): Do we need special support for IntegerIndexedExotic?
Toon Verwaest 2015/10/06 15:55:18 IntegerIndexedExotic for data properties is alread
Jakob Kummerow 2015/10/09 13:46:12 Acknowledged, changed the comment to reflect that.
5976 // (ES6 9.4.5.3)
5977 // TODO(jkummerow): Support Modules (ES6 9.4.6.6)
5978 // TODO(jkummerow): Support Proxies (ES6 9.5.6)
5979 return OrdinaryDefineOwnProperty(isolate, obj, name, desc, should_throw);
5980 }
5981
5982
5983 // static
5984 bool JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, Handle<JSObject> o,
5985 Handle<Object> name,
5986 PropertyDescriptor* desc,
5987 bool should_throw) {
5988 bool success = false;
5989 LookupIterator it = LookupIterator::PropertyOrElement(
5990 isolate, o, name, &success, LookupIterator::HIDDEN);
5991 if (!success) return false;
Toon Verwaest 2015/10/06 15:55:18 name -> property_key, so shouldn't happen(?).
Jakob Kummerow 2015/10/09 13:46:12 Done.
5992 return OrdinaryDefineOwnProperty(&it, desc, should_throw);
5993 }
5994
5995
5996 // ES6 9.1.6.1
5997 // static
5998 bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
5999 PropertyDescriptor* desc,
6000 bool should_throw) {
6001 Isolate* isolate = it->isolate();
6002 // == OrdinaryDefineOwnProperty (O, P, Desc) ==
6003 // 1. Let current be O.[[GetOwnProperty]](P).
6004 // 2. ReturnIfAbrupt(current).
6005 PropertyDescriptor current;
6006 if (!GetOwnPropertyDescriptor(it, &current) &&
6007 isolate->has_pending_exception()) {
6008 return false;
6009 }
6010 // 3. Let extensible be the value of the [[Extensible]] internal slot of O.
6011 Handle<JSObject> o = Handle<JSObject>::cast(it->GetReceiver());
6012 bool extensible = JSObject::IsExtensible(o);
6013
6014 bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
6015 bool desc_is_accessor_descriptor =
6016 PropertyDescriptor::IsAccessorDescriptor(desc);
6017 bool desc_is_generic_descriptor =
6018 PropertyDescriptor::IsGenericDescriptor(desc);
6019
6020 // == ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current) ==
6021 // 2. If current is undefined, then
6022 if (current.is_empty()) {
6023 // 2a. If extensible is false, return false.
6024 if (!extensible) {
6025 if (should_throw) {
6026 isolate->Throw(*isolate->factory()->NewTypeError(
6027 MessageTemplate::kDefineDisallowed, it->GetName()));
6028 }
6029 return false;
6030 }
6031 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
6032 // (This is equivalent to !IsAccessorDescriptor(desc).)
6033 DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
6034 !desc_is_accessor_descriptor);
6035 if (!desc_is_accessor_descriptor) {
6036 // 2c i. If O is not undefined, create an own data property named P of
6037 // object O whose [[Value]], [[Writable]], [[Enumerable]] and
6038 // [[Configurable]] attribute values are described by Desc. If the value
6039 // of an attribute field of Desc is absent, the attribute of the newly
6040 // created property is set to its default value.
6041 if (!o->IsUndefined()) {
6042 if (!desc->has_writable()) desc->set_writable(false);
6043 if (!desc->has_enumerable()) desc->set_enumerable(false);
6044 if (!desc->has_configurable()) desc->set_configurable(false);
6045 Handle<Object> value(
6046 desc->has_value()
6047 ? desc->value()
6048 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6049 MaybeHandle<Object> result =
6050 JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
6051 desc->ToAttributes());
6052 if (result.is_null()) return false;
6053 }
6054 } else {
6055 // 2d. Else Desc must be an accessor Property Descriptor,
6056 DCHECK(desc_is_accessor_descriptor);
6057 // 2d i. If O is not undefined, create an own accessor property named P
6058 // of object O whose [[Get]], [[Set]], [[Enumerable]] and
6059 // [[Configurable]] attribute values are described by Desc. If the value
6060 // of an attribute field of Desc is absent, the attribute of the newly
6061 // created property is set to its default value.
6062 if (!o->IsUndefined()) {
6063 if (!desc->has_enumerable()) desc->set_enumerable(false);
6064 if (!desc->has_configurable()) desc->set_configurable(false);
6065 Handle<Object> getter(
6066 desc->has_get()
6067 ? desc->get()
6068 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6069 Handle<Object> setter(
6070 desc->has_set()
6071 ? desc->set()
6072 : Handle<Object>::cast(isolate->factory()->undefined_value()));
6073 MaybeHandle<Object> result =
6074 JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
6075 if (result.is_null()) return false;
6076 }
6077 }
6078 // 2e. Return true.
6079 return true;
6080 }
6081 // 3. Return true, if every field in Desc is absent.
6082 // 4. Return true, if every field in Desc also occurs in current and the
6083 // value of every field in Desc is the same value as the corresponding field
6084 // in current when compared using the SameValue algorithm.
6085 if ((!desc->has_enumerable() || desc->enumerable() == current.enumerable()) &&
6086 (!desc->has_configurable() ||
6087 desc->configurable() == current.configurable()) &&
6088 (!desc->has_value() ||
6089 (current.has_value() && current.value()->SameValue(*desc->value()))) &&
6090 (!desc->has_writable() ||
6091 (current.has_writable() && current.writable() == desc->writable())) &&
6092 (!desc->has_get() ||
6093 (current.has_get() && current.get()->SameValue(*desc->get()))) &&
6094 (!desc->has_set() ||
6095 (current.has_set() && current.set()->SameValue(*desc->set())))) {
6096 return true;
6097 }
6098 // 5. If the [[Configurable]] field of current is false, then
6099 if (!current.configurable()) {
6100 // 5a. Return false, if the [[Configurable]] field of Desc is true.
6101 if (desc->has_configurable() && desc->configurable()) {
6102 if (should_throw) {
6103 isolate->Throw(*isolate->factory()->NewTypeError(
6104 MessageTemplate::kRedefineDisallowed, it->GetName()));
6105 }
6106 return false;
6107 }
6108 // 5b. Return false, if the [[Enumerable]] field of Desc is present and the
6109 // [[Enumerable]] fields of current and Desc are the Boolean negation of
6110 // each other.
6111 if (desc->has_enumerable() && desc->enumerable() != current.enumerable()) {
6112 if (should_throw) {
6113 isolate->Throw(*isolate->factory()->NewTypeError(
6114 MessageTemplate::kRedefineDisallowed, it->GetName()));
6115 }
6116 return false;
6117 }
6118 }
6119
6120 bool current_is_data_descriptor =
6121 PropertyDescriptor::IsDataDescriptor(&current);
6122 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
6123 if (desc_is_generic_descriptor) {
6124 // Nothing to see here.
6125
6126 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have
6127 // different results, then:
6128 } else if (current_is_data_descriptor != desc_is_data_descriptor) {
6129 // 7a. Return false, if the [[Configurable]] field of current is false.
6130 if (!current.configurable()) {
6131 if (should_throw) {
6132 isolate->Throw(*isolate->factory()->NewTypeError(
6133 MessageTemplate::kRedefineDisallowed, it->GetName()));
6134 }
6135 return false;
6136 }
6137 // 7b. If IsDataDescriptor(current) is true, then:
6138 if (current_is_data_descriptor) {
6139 // 7b i. If O is not undefined, convert the property named P of object O
6140 // from a data property to an accessor property. Preserve the existing
6141 // values of the converted property's [[Configurable]] and [[Enumerable]]
6142 // attributes and set the rest of the property's attributes to their
6143 // default values.
6144 // --> Folded into step 10.
6145 } else {
6146 // 7c i. If O is not undefined, convert the property named P of object O
6147 // from an accessor property to a data property. Preserve the existing
6148 // values of the converted property’s [[Configurable]] and [[Enumerable]]
6149 // attributes and set the rest of the property’s attributes to their
6150 // default values.
6151 // --> Folded into step 10.
6152 }
6153
6154 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both
6155 // true, then:
6156 } else if (current_is_data_descriptor && desc_is_data_descriptor) {
6157 // 8a. If the [[Configurable]] field of current is false, then:
6158 if (!current.configurable()) {
6159 // [Strong mode] Disallow changing writable -> readonly for
6160 // non-configurable properties.
6161 if (current.writable() && desc->has_writable() && !desc->writable() &&
6162 o->map()->is_strong()) {
6163 if (should_throw) {
6164 isolate->Throw(*isolate->factory()->NewTypeError(
6165 MessageTemplate::kStrongRedefineDisallowed, o, it->GetName()));
6166 }
6167 return false;
6168 }
6169 // 8a i. Return false, if the [[Writable]] field of current is false and
6170 // the [[Writable]] field of Desc is true.
6171 if (!current.writable() && desc->has_writable() && desc->writable()) {
6172 if (should_throw) {
6173 isolate->Throw(*isolate->factory()->NewTypeError(
6174 MessageTemplate::kRedefineDisallowed, it->GetName()));
6175 }
6176 return false;
6177 }
6178 // 8a ii. If the [[Writable]] field of current is false, then:
6179 if (!current.writable()) {
6180 // 8a ii 1. Return false, if the [[Value]] field of Desc is present and
6181 // SameValue(Desc.[[Value]], current.[[Value]]) is false.
6182 if (desc->has_value() && !desc->value()->SameValue(*current.value())) {
6183 if (should_throw) {
6184 isolate->Throw(*isolate->factory()->NewTypeError(
6185 MessageTemplate::kRedefineDisallowed, it->GetName()));
6186 }
6187 return false;
6188 }
6189 }
6190 }
6191 } else {
6192 // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
6193 // are both true,
6194 DCHECK(PropertyDescriptor::IsAccessorDescriptor(&current) &&
6195 desc_is_accessor_descriptor);
6196 // 9a. If the [[Configurable]] field of current is false, then:
6197 if (!current.configurable()) {
6198 // 9a i. Return false, if the [[Set]] field of Desc is present and
6199 // SameValue(Desc.[[Set]], current.[[Set]]) is false.
6200 if (desc->has_set() && !desc->set()->SameValue(*current.set())) {
6201 if (should_throw) {
6202 isolate->Throw(*isolate->factory()->NewTypeError(
6203 MessageTemplate::kRedefineDisallowed, it->GetName()));
6204 }
6205 return false;
6206 }
6207 // 9a ii. Return false, if the [[Get]] field of Desc is present and
6208 // SameValue(Desc.[[Get]], current.[[Get]]) is false.
6209 if (desc->has_get() && !desc->get()->SameValue(*current.get())) {
6210 if (should_throw) {
6211 isolate->Throw(*isolate->factory()->NewTypeError(
6212 MessageTemplate::kRedefineDisallowed, it->GetName()));
6213 }
6214 return false;
6215 }
6216 }
6217 }
6218
6219 // 10. If O is not undefined, then:
6220 if (!o->IsUndefined()) {
6221 // 10a. For each field of Desc that is present, set the corresponding
6222 // attribute of the property named P of object O to the value of the field.
6223 PropertyAttributes attrs = NONE;
6224
6225 if (desc->has_enumerable()) {
6226 attrs = static_cast<PropertyAttributes>(
6227 attrs | (desc->enumerable() ? NONE : DONT_ENUM));
6228 } else {
6229 attrs = static_cast<PropertyAttributes>(
6230 attrs | (current.enumerable() ? NONE : DONT_ENUM));
6231 }
6232 if (desc->has_configurable()) {
6233 attrs = static_cast<PropertyAttributes>(
6234 attrs | (desc->configurable() ? NONE : DONT_DELETE));
6235 } else {
6236 attrs = static_cast<PropertyAttributes>(
6237 attrs | (current.configurable() ? NONE : DONT_DELETE));
6238 }
6239 if (desc_is_data_descriptor ||
6240 (desc_is_generic_descriptor && current_is_data_descriptor)) {
6241 if (desc->has_writable()) {
6242 attrs = static_cast<PropertyAttributes>(
6243 attrs | (desc->writable() ? NONE : READ_ONLY));
6244 } else {
6245 attrs = static_cast<PropertyAttributes>(
6246 attrs | (current.writable() ? NONE : READ_ONLY));
6247 }
6248 Handle<Object> value(
6249 desc->has_value() ? desc->value()
6250 : current.has_value()
6251 ? current.value()
6252 : Handle<Object>::cast(
6253 isolate->factory()->undefined_value()));
6254 MaybeHandle<Object> result = JSObject::DefineOwnPropertyIgnoreAttributes(
6255 it, value, attrs, JSObject::DONT_FORCE_FIELD);
6256 if (result.is_null()) return false;
6257 } else {
6258 DCHECK(desc_is_accessor_descriptor ||
6259 (desc_is_generic_descriptor &&
6260 PropertyDescriptor::IsAccessorDescriptor(&current)));
6261 Handle<Object> getter(
6262 desc->has_get()
6263 ? desc->get()
6264 : current.has_get() ? current.get()
6265 : Handle<Object>::cast(
6266 isolate->factory()->undefined_value()));
6267 Handle<Object> setter(
6268 desc->has_set()
6269 ? desc->set()
6270 : current.has_set() ? current.set()
6271 : Handle<Object>::cast(
6272 isolate->factory()->undefined_value()));
6273 MaybeHandle<Object> result =
6274 JSObject::DefineAccessor(it, getter, setter, attrs);
6275 if (result.is_null()) return false;
6276 }
6277 }
6278
6279 // 11. Return true.
6280 return true;
6281 }
6282
6283
6284 // TODO(jkummerow): Consider unification with FastAsArrayLength() in
6285 // accessors.cc.
6286 bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
6287 DCHECK(value->IsNumber() || value->IsName());
6288 if (value->ToArrayLength(length)) return true;
6289 if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
Toon Verwaest 2015/10/06 15:55:18 Ugh ... :)
Jakob Kummerow 2015/10/09 13:46:12 Acknowledged.
6290 return false;
6291 }
6292
6293
6294 bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
6295 return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
6296 }
6297
6298
6299 // ES6 9.4.2.1
6300 // static
6301 bool JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
6302 Handle<Object> name, PropertyDescriptor* desc,
6303 bool should_throw) {
6304 // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
6305 // 2. If P is "length", then:
6306 // TODO(jkummerow): Check if we need slow string comparison.
6307 if (*name == isolate->heap()->length_string()) {
6308 // 2a. Return ArraySetLength(A, Desc).
6309 return ArraySetLength(isolate, o, desc, should_throw);
6310 }
6311 // 3. Else if P is an array index, then:
6312 uint32_t index = 0;
6313 if (PropertyKeyToArrayIndex(name, &index)) {
6314 // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6315 PropertyDescriptor old_len_desc;
6316 bool success = GetOwnPropertyDescriptor(
6317 isolate, o, isolate->factory()->length_string(), &old_len_desc);
6318 // 3b. (Assert)
6319 DCHECK(success);
6320 USE(success);
6321 // 3c. Let oldLen be oldLenDesc.[[Value]].
6322 uint32_t old_len = 0;
6323 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6324 // 3d. Let index be ToUint32(P).
6325 // (Already done above.)
6326 // 3e. (Assert)
6327 // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false,
6328 // return false.
6329 if (index >= old_len && old_len_desc.has_writable() &&
6330 !old_len_desc.writable()) {
6331 if (should_throw) {
6332 isolate->Throw(*isolate->factory()->NewTypeError(
6333 MessageTemplate::kDefineDisallowed, name));
6334 }
6335 return false;
6336 }
6337 // 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
6338 bool succeeded =
6339 OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6340 // 3h. (Assert)
6341 // 3i. If succeeded is false, return false.
6342 if (!succeeded) return false;
6343 // 3j. If index >= oldLen, then:
6344 if (index >= old_len) {
6345 // 3j i. Set oldLenDesc.[[Value]] to index + 1.
6346 old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
6347 // 3j ii. Let succeeded be
6348 // OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
6349 OrdinaryDefineOwnProperty(isolate, o, isolate->factory()->length_string(),
6350 &old_len_desc, should_throw);
6351 // 3j iii. (Assert)
6352 }
6353 // 3k. Return true.
6354 return true;
6355 }
6356
6357 // 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
6358 return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
6359 }
6360
6361
6362 // TODO(jkummerow): Consider unification with ArrayLengthSetter in accessors.cc.
6363 bool AnythingToArrayLength(Isolate* isolate, Handle<Object> length_obj,
6364 uint32_t* output) {
6365 // Fast path: check numbers and strings that can be converted directly
6366 // and unobservably.
6367 if (length_obj->ToUint32(output)) return true;
6368 if (length_obj->IsString() &&
6369 Handle<String>::cast(length_obj)->AsArrayIndex(output)) {
6370 return true;
6371 }
6372 // Slow path: follow steps in ES6 9.4.2.4 "ArraySetLength".
6373 // 3. Let newLen be ToUint32(Desc.[[Value]]).
6374 Handle<Object> uint32_v;
6375 if (!Object::ToUint32(isolate, length_obj).ToHandle(&uint32_v)) {
6376 // 4. ReturnIfAbrupt(newLen).
6377 return false;
6378 }
6379 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
6380 Handle<Object> number_v;
6381 if (!Object::ToNumber(length_obj).ToHandle(&number_v)) {
6382 // 6. ReturnIfAbrupt(newLen).
6383 return false;
6384 }
6385 // 7. If newLen != numberLen, throw a RangeError exception.
6386 if (uint32_v->Number() != number_v->Number()) {
6387 Handle<Object> exception =
6388 isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
6389 isolate->Throw(*exception);
6390 return false;
6391 }
6392 return uint32_v->ToArrayLength(output);
6393 }
6394
6395
6396 // ES6 9.4.2.4
6397 // static
6398 bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
6399 PropertyDescriptor* desc, bool should_throw) {
6400 // 1. If the [[Value]] field of Desc is absent, then
Toon Verwaest 2015/10/06 15:55:18 Most of this code duplicates the ArrayLengthSetter
Jakob Kummerow 2015/10/09 13:46:12 Well, ArrayLengthSetter is mostly concerned with c
6401 if (!desc->has_value()) {
6402 // 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
6403 return OrdinaryDefineOwnProperty(
6404 isolate, a, isolate->factory()->length_string(), desc, should_throw);
6405 }
6406 // 2. Let newLenDesc be a copy of Desc.
6407 // (Actual copying is not necessary.)
6408 PropertyDescriptor* new_len_desc = desc;
6409 // 3. - 7. Convert Desc.[[Value]] to newLen.
6410 uint32_t new_len = 0;
6411 if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
6412 if (should_throw && !isolate->has_pending_exception()) {
6413 isolate->Throw(*isolate->factory()->NewTypeError(
6414 MessageTemplate::kCannotConvertToPrimitive));
6415 }
6416 return false;
6417 }
6418 // 8. Set newLenDesc.[[Value]] to newLen.
6419 // (Done below, if needed.)
6420 // 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
6421 PropertyDescriptor old_len_desc;
6422 bool success = GetOwnPropertyDescriptor(
6423 isolate, a, isolate->factory()->length_string(), &old_len_desc);
6424 // 10. (Assert)
6425 DCHECK(success);
6426 USE(success);
6427 // 11. Let oldLen be oldLenDesc.[[Value]].
6428 uint32_t old_len = 0;
6429 CHECK(old_len_desc.value()->ToArrayLength(&old_len));
6430 // 12. If newLen >= oldLen, then
6431 if (new_len >= old_len) {
6432 // 8. Set newLenDesc.[[Value]] to newLen.
6433 // 12a. Return OrdinaryDefineOwnProperty(A, "length", newLenDesc).
6434 new_len_desc->set_value(isolate->factory()->NewNumberFromUint(new_len));
6435 return OrdinaryDefineOwnProperty(isolate, a,
6436 isolate->factory()->length_string(),
6437 new_len_desc, should_throw);
6438 }
6439 // 13. If oldLenDesc.[[Writable]] is false, return false.
6440 if (!old_len_desc.writable()) {
6441 if (should_throw)
6442 isolate->Throw(*isolate->factory()->NewTypeError(
6443 MessageTemplate::kRedefineDisallowed,
6444 isolate->factory()->length_string()));
6445 return false;
6446 }
6447 // 14. If newLenDesc.[[Writable]] is absent or has the value true,
6448 // let newWritable be true.
6449 bool new_writable = false;
6450 if (!new_len_desc->has_writable() || new_len_desc->writable()) {
6451 new_writable = true;
6452 } else {
6453 // 15. Else,
6454 // 15a. Need to defer setting the [[Writable]] attribute to false in case
6455 // any elements cannot be deleted.
Toon Verwaest 2015/10/06 15:55:18 gee ...
6456 // 15b. Let newWritable be false. (It's initialized as "false" anyway.)
6457 // 15c. Set newLenDesc.[[Writable]] to true.
6458 // (Not needed.)
6459 }
6460 // Most of steps 16 through 19 is implemented by JSArray::SetLength.
6461 if (JSArray::ObservableSetLength(a, new_len).is_null()) {
6462 if (should_throw) isolate->OptionalRescheduleException(false);
6463 return false;
6464 }
6465 // Steps 19d-ii, 20.
6466 if (!new_writable) {
6467 PropertyDescriptor readonly;
6468 readonly.set_writable(false);
6469 OrdinaryDefineOwnProperty(isolate, a, isolate->factory()->length_string(),
6470 &readonly, should_throw);
6471 }
6472 uint32_t actual_new_len = 0;
6473 CHECK(a->length()->ToArrayLength(&actual_new_len));
6474 // Steps 19d-v, 21. Return false if there were non-deletable elements.
6475 return actual_new_len == new_len;
6476 }
6477
6478
6479 // static
6480 bool JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
6481 Handle<JSObject> obj,
6482 Handle<Object> name,
6483 PropertyDescriptor* desc) {
6484 bool success = false;
6485 LookupIterator it = LookupIterator::PropertyOrElement(
6486 isolate, obj, name, &success, LookupIterator::HIDDEN);
Toon Verwaest 2015/10/06 15:55:18 property key "p" (spec) (name -> key), so cannot f
Jakob Kummerow 2015/10/09 13:46:12 Done.
6487 if (!success) return false;
6488 return GetOwnPropertyDescriptor(&it, desc);
6489 }
6490
6491
6492 // ES6 9.1.5.1
6493 // TODO(jkummerow): Any chance to unify this with
6494 // "MaybeHandle<Object> GetOwnProperty()" in runtime-object.cc?
Toon Verwaest 2015/10/06 15:55:18 TODO(): proxies: call getOwnPropertyDescriptor tra
Jakob Kummerow 2015/10/09 13:46:12 Done.
6495 // Returns true on success; false if there was an exception or no property.
6496 // static
6497 bool JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
6498 PropertyDescriptor* desc) {
6499 Isolate* isolate = it->isolate();
6500 // 1. (Assert)
6501 // 2. If O does not have an own property with key P, return undefined.
6502 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
6503
6504 if (!maybe.IsJust()) return false;
6505 PropertyAttributes attrs = maybe.FromJust();
6506 if (attrs == ABSENT) return false;
6507 DCHECK(!isolate->has_pending_exception());
6508
6509 // 3. Let D be a newly created Property Descriptor with no fields.
6510 DCHECK(desc->is_empty());
6511 // 4. Let X be O's own property whose key is P.
6512 // 5. If X is a data property, then
6513 bool is_accessor_pair = it->state() == LookupIterator::ACCESSOR &&
6514 it->GetAccessors()->IsAccessorPair();
6515 if (!is_accessor_pair) {
6516 // 5a. Set D.[[Value]] to the value of X's [[Value]] attribute.
6517 Handle<Object> value = JSObject::GetProperty(it).ToHandleChecked();
6518 desc->set_value(value);
6519 // 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
6520 desc->set_writable((attrs & READ_ONLY) == 0);
6521 } else {
6522 // 6. Else X is an accessor property, so
6523 Handle<AccessorPair> accessors =
6524 Handle<AccessorPair>::cast(it->GetAccessors());
6525 // 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
6526 desc->set_get(handle(accessors->GetComponent(ACCESSOR_GETTER), isolate));
6527 // 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
6528 desc->set_set(handle(accessors->GetComponent(ACCESSOR_SETTER), isolate));
6529 }
6530
6531 // 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
6532 desc->set_enumerable((attrs & DONT_ENUM) == 0);
6533 // 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
6534 desc->set_configurable((attrs & DONT_DELETE) == 0);
6535 // 9. Return D.
6536 return true;
6537 }
6538
6539
5829 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, 6540 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5830 ElementsKind kind, 6541 ElementsKind kind,
5831 Object* object) { 6542 Object* object) {
5832 DCHECK(IsFastObjectElementsKind(kind) || 6543 DCHECK(IsFastObjectElementsKind(kind) ||
5833 kind == DICTIONARY_ELEMENTS); 6544 kind == DICTIONARY_ELEMENTS);
5834 if (IsFastObjectElementsKind(kind)) { 6545 if (IsFastObjectElementsKind(kind)) {
5835 int length = IsJSArray() 6546 int length = IsJSArray()
5836 ? Smi::cast(JSArray::cast(this)->length())->value() 6547 ? Smi::cast(JSArray::cast(this)->length())->value()
5837 : elements->length(); 6548 : elements->length();
5838 for (int i = 0; i < length; ++i) { 6549 for (int i = 0; i < length; ++i) {
(...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after
6976 7687
6977 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object, 7688 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
6978 Handle<Name> name, 7689 Handle<Name> name,
6979 Handle<Object> getter, 7690 Handle<Object> getter,
6980 Handle<Object> setter, 7691 Handle<Object> setter,
6981 PropertyAttributes attributes) { 7692 PropertyAttributes attributes) {
6982 Isolate* isolate = object->GetIsolate(); 7693 Isolate* isolate = object->GetIsolate();
6983 7694
6984 LookupIterator it = LookupIterator::PropertyOrElement( 7695 LookupIterator it = LookupIterator::PropertyOrElement(
6985 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); 7696 isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
7697 return DefineAccessor(&it, getter, setter, attributes);
7698 }
6986 7699
6987 if (it.state() == LookupIterator::ACCESS_CHECK) { 7700
6988 if (!it.HasAccess()) { 7701 MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
6989 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 7702 Handle<Object> getter,
7703 Handle<Object> setter,
7704 PropertyAttributes attributes) {
7705 Isolate* isolate = it->isolate();
7706
7707 if (it->state() == LookupIterator::ACCESS_CHECK) {
7708 if (!it->HasAccess()) {
7709 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
6990 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 7710 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6991 return isolate->factory()->undefined_value(); 7711 return isolate->factory()->undefined_value();
6992 } 7712 }
6993 it.Next(); 7713 it->Next();
6994 } 7714 }
6995 7715
7716 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
6996 // Ignore accessors on typed arrays. 7717 // Ignore accessors on typed arrays.
6997 if (it.IsElement() && object->HasFixedTypedArrayElements()) { 7718 if (it->IsElement() && object->HasFixedTypedArrayElements()) {
6998 return it.factory()->undefined_value(); 7719 return it->factory()->undefined_value();
6999 } 7720 }
7000 7721
7001 Handle<Object> old_value = isolate->factory()->the_hole_value(); 7722 Handle<Object> old_value = isolate->factory()->the_hole_value();
7002 bool is_observed = object->map()->is_observed() && 7723 bool is_observed = object->map()->is_observed() &&
7003 !isolate->IsInternallyUsedPropertyName(name); 7724 !isolate->IsInternallyUsedPropertyName(it->GetName());
7004 bool preexists = false; 7725 bool preexists = false;
7005 if (is_observed) { 7726 if (is_observed) {
7006 CHECK(GetPropertyAttributes(&it).IsJust()); 7727 CHECK(GetPropertyAttributes(it).IsJust());
7007 preexists = it.IsFound(); 7728 preexists = it->IsFound();
7008 if (preexists && (it.state() == LookupIterator::DATA || 7729 if (preexists && (it->state() == LookupIterator::DATA ||
7009 it.GetAccessors()->IsAccessorInfo())) { 7730 it->GetAccessors()->IsAccessorInfo())) {
7010 old_value = GetProperty(&it).ToHandleChecked(); 7731 old_value = GetProperty(it).ToHandleChecked();
7011 } 7732 }
7012 } 7733 }
7013 7734
7014 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull()); 7735 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull());
7015 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull()); 7736 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull());
7016 // At least one of the accessors needs to be a new value. 7737 // At least one of the accessors needs to be a new value.
7017 DCHECK(!getter->IsNull() || !setter->IsNull()); 7738 DCHECK(!getter->IsNull() || !setter->IsNull());
7018 if (!getter->IsNull()) { 7739 if (!getter->IsNull()) {
7019 it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes); 7740 it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
7020 } 7741 }
7021 if (!setter->IsNull()) { 7742 if (!setter->IsNull()) {
7022 it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes); 7743 it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
7023 } 7744 }
7024 7745
7025 if (is_observed) { 7746 if (is_observed) {
7026 // Make sure the top context isn't changed. 7747 // Make sure the top context isn't changed.
7027 AssertNoContextChange ncc(isolate); 7748 AssertNoContextChange ncc(isolate);
7028 const char* type = preexists ? "reconfigure" : "add"; 7749 const char* type = preexists ? "reconfigure" : "add";
7029 RETURN_ON_EXCEPTION( 7750 RETURN_ON_EXCEPTION(
7030 isolate, EnqueueChangeRecord(object, type, name, old_value), Object); 7751 isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value),
7752 Object);
7031 } 7753 }
7032 7754
7033 return isolate->factory()->undefined_value(); 7755 return isolate->factory()->undefined_value();
7034 } 7756 }
7035 7757
7036 7758
7037 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 7759 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
7038 Handle<AccessorInfo> info) { 7760 Handle<AccessorInfo> info) {
7039 Isolate* isolate = object->GetIsolate(); 7761 Isolate* isolate = object->GetIsolate();
7040 Handle<Name> name(Name::cast(info->name()), isolate); 7762 Handle<Name> name(Name::cast(info->name()), isolate);
(...skipping 9827 matching lines...) Expand 10 before | Expand all | Expand 10 after
16868 if (cell->value() != *new_value) { 17590 if (cell->value() != *new_value) {
16869 cell->set_value(*new_value); 17591 cell->set_value(*new_value);
16870 Isolate* isolate = cell->GetIsolate(); 17592 Isolate* isolate = cell->GetIsolate();
16871 cell->dependent_code()->DeoptimizeDependentCodeGroup( 17593 cell->dependent_code()->DeoptimizeDependentCodeGroup(
16872 isolate, DependentCode::kPropertyCellChangedGroup); 17594 isolate, DependentCode::kPropertyCellChangedGroup);
16873 } 17595 }
16874 } 17596 }
16875 17597
16876 } // namespace internal 17598 } // namespace internal
16877 } // namespace v8 17599 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698