| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
| 8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
| 9 #include "src/property-descriptor.h" | 9 #include "src/property-descriptor.h" |
| 10 | 10 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 assembler.Return(assembler.BooleanConstant(true)); | 59 assembler.Return(assembler.BooleanConstant(true)); |
| 60 | 60 |
| 61 assembler.Bind(&return_false); | 61 assembler.Bind(&return_false); |
| 62 assembler.Return(assembler.BooleanConstant(false)); | 62 assembler.Return(assembler.BooleanConstant(false)); |
| 63 | 63 |
| 64 assembler.Bind(&call_runtime); | 64 assembler.Bind(&call_runtime); |
| 65 assembler.Return(assembler.CallRuntime(Runtime::kObjectHasOwnProperty, | 65 assembler.Return(assembler.CallRuntime(Runtime::kObjectHasOwnProperty, |
| 66 context, object, key)); | 66 context, object, key)); |
| 67 } | 67 } |
| 68 | 68 |
| 69 namespace { | |
| 70 | |
| 71 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> to, | |
| 72 Handle<Object> next_source) { | |
| 73 // Non-empty strings are the only non-JSReceivers that need to be handled | |
| 74 // explicitly by Object.assign. | |
| 75 if (!next_source->IsJSReceiver()) { | |
| 76 return Just(!next_source->IsString() || | |
| 77 String::cast(*next_source)->length() == 0); | |
| 78 } | |
| 79 | |
| 80 // If the target is deprecated, the object will be updated on first store. If | |
| 81 // the source for that store equals the target, this will invalidate the | |
| 82 // cached representation of the source. Preventively upgrade the target. | |
| 83 // Do this on each iteration since any property load could cause deprecation. | |
| 84 if (to->map()->is_deprecated()) { | |
| 85 JSObject::MigrateInstance(Handle<JSObject>::cast(to)); | |
| 86 } | |
| 87 | |
| 88 Isolate* isolate = to->GetIsolate(); | |
| 89 Handle<Map> map(JSReceiver::cast(*next_source)->map(), isolate); | |
| 90 | |
| 91 if (!map->IsJSObjectMap()) return Just(false); | |
| 92 if (!map->OnlyHasSimpleProperties()) return Just(false); | |
| 93 | |
| 94 Handle<JSObject> from = Handle<JSObject>::cast(next_source); | |
| 95 if (from->elements() != isolate->heap()->empty_fixed_array()) { | |
| 96 return Just(false); | |
| 97 } | |
| 98 | |
| 99 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); | |
| 100 int length = map->NumberOfOwnDescriptors(); | |
| 101 | |
| 102 bool stable = true; | |
| 103 | |
| 104 for (int i = 0; i < length; i++) { | |
| 105 Handle<Name> next_key(descriptors->GetKey(i), isolate); | |
| 106 Handle<Object> prop_value; | |
| 107 // Directly decode from the descriptor array if |from| did not change shape. | |
| 108 if (stable) { | |
| 109 PropertyDetails details = descriptors->GetDetails(i); | |
| 110 if (!details.IsEnumerable()) continue; | |
| 111 if (details.kind() == kData) { | |
| 112 if (details.location() == kDescriptor) { | |
| 113 prop_value = handle(descriptors->GetValue(i), isolate); | |
| 114 } else { | |
| 115 Representation representation = details.representation(); | |
| 116 FieldIndex index = FieldIndex::ForDescriptor(*map, i); | |
| 117 prop_value = JSObject::FastPropertyAt(from, representation, index); | |
| 118 } | |
| 119 } else { | |
| 120 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 121 isolate, prop_value, JSReceiver::GetProperty(from, next_key), | |
| 122 Nothing<bool>()); | |
| 123 stable = from->map() == *map; | |
| 124 } | |
| 125 } else { | |
| 126 // If the map did change, do a slower lookup. We are still guaranteed that | |
| 127 // the object has a simple shape, and that the key is a name. | |
| 128 LookupIterator it(from, next_key, from, | |
| 129 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
| 130 if (!it.IsFound()) continue; | |
| 131 DCHECK(it.state() == LookupIterator::DATA || | |
| 132 it.state() == LookupIterator::ACCESSOR); | |
| 133 if (!it.IsEnumerable()) continue; | |
| 134 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 135 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); | |
| 136 } | |
| 137 LookupIterator it(to, next_key, to); | |
| 138 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; | |
| 139 Maybe<bool> result = Object::SetProperty( | |
| 140 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); | |
| 141 if (result.IsNothing()) return result; | |
| 142 if (stable && call_to_js) stable = from->map() == *map; | |
| 143 } | |
| 144 | |
| 145 return Just(true); | |
| 146 } | |
| 147 | |
| 148 } // namespace | |
| 149 | |
| 150 // ES6 19.1.2.1 Object.assign | 69 // ES6 19.1.2.1 Object.assign |
| 151 BUILTIN(ObjectAssign) { | 70 BUILTIN(ObjectAssign) { |
| 152 HandleScope scope(isolate); | 71 HandleScope scope(isolate); |
| 153 Handle<Object> target = args.atOrUndefined(isolate, 1); | 72 Handle<Object> target = args.atOrUndefined(isolate, 1); |
| 154 | 73 |
| 155 // 1. Let to be ? ToObject(target). | 74 // 1. Let to be ? ToObject(target). |
| 156 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, | 75 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, |
| 157 Object::ToObject(isolate, target)); | 76 Object::ToObject(isolate, target)); |
| 158 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); | 77 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); |
| 159 // 2. If only one argument was passed, return to. | 78 // 2. If only one argument was passed, return to. |
| 160 if (args.length() == 2) return *to; | 79 if (args.length() == 2) return *to; |
| 161 // 3. Let sources be the List of argument values starting with the | 80 // 3. Let sources be the List of argument values starting with the |
| 162 // second argument. | 81 // second argument. |
| 163 // 4. For each element nextSource of sources, in ascending index order, | 82 // 4. For each element nextSource of sources, in ascending index order, |
| 164 for (int i = 2; i < args.length(); ++i) { | 83 for (int i = 2; i < args.length(); ++i) { |
| 165 Handle<Object> next_source = args.at(i); | 84 Handle<Object> next_source = args.at(i); |
| 166 Maybe<bool> fast_assign = FastAssign(to, next_source); | 85 MAYBE_RETURN( |
| 167 if (fast_assign.IsNothing()) return isolate->heap()->exception(); | 86 JSReceiver::SetOrCopyDataProperties(isolate, to, next_source, true), |
| 168 if (fast_assign.FromJust()) continue; | 87 isolate->heap()->exception()); |
| 169 // 4a. If nextSource is undefined or null, let keys be an empty List. | |
| 170 // 4b. Else, | |
| 171 // 4b i. Let from be ToObject(nextSource). | |
| 172 // Only non-empty strings and JSReceivers have enumerable properties. | |
| 173 Handle<JSReceiver> from = | |
| 174 Object::ToObject(isolate, next_source).ToHandleChecked(); | |
| 175 // 4b ii. Let keys be ? from.[[OwnPropertyKeys]](). | |
| 176 Handle<FixedArray> keys; | |
| 177 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 178 isolate, keys, KeyAccumulator::GetKeys( | |
| 179 from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
| 180 GetKeysConversion::kKeepNumbers)); | |
| 181 // 4c. Repeat for each element nextKey of keys in List order, | |
| 182 for (int j = 0; j < keys->length(); ++j) { | |
| 183 Handle<Object> next_key(keys->get(j), isolate); | |
| 184 // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey). | |
| 185 PropertyDescriptor desc; | |
| 186 Maybe<bool> found = | |
| 187 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); | |
| 188 if (found.IsNothing()) return isolate->heap()->exception(); | |
| 189 // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then | |
| 190 if (found.FromJust() && desc.enumerable()) { | |
| 191 // 4c ii 1. Let propValue be ? Get(from, nextKey). | |
| 192 Handle<Object> prop_value; | |
| 193 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 194 isolate, prop_value, | |
| 195 Runtime::GetObjectProperty(isolate, from, next_key)); | |
| 196 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). | |
| 197 Handle<Object> status; | |
| 198 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 199 isolate, status, Runtime::SetObjectProperty(isolate, to, next_key, | |
| 200 prop_value, STRICT)); | |
| 201 } | |
| 202 } | |
| 203 } | 88 } |
| 204 // 5. Return to. | 89 // 5. Return to. |
| 205 return *to; | 90 return *to; |
| 206 } | 91 } |
| 207 | 92 |
| 208 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V ) | 93 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V ) |
| 209 BUILTIN(ObjectPrototypePropertyIsEnumerable) { | 94 BUILTIN(ObjectPrototypePropertyIsEnumerable) { |
| 210 HandleScope scope(isolate); | 95 HandleScope scope(isolate); |
| 211 Handle<JSReceiver> object; | 96 Handle<JSReceiver> object; |
| 212 Handle<Name> name; | 97 Handle<Name> name; |
| (...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1100 CodeStubAssembler assembler(state); | 985 CodeStubAssembler assembler(state); |
| 1101 | 986 |
| 1102 Node* object = assembler.Parameter(Descriptor::kObject); | 987 Node* object = assembler.Parameter(Descriptor::kObject); |
| 1103 Node* context = assembler.Parameter(Descriptor::kContext); | 988 Node* context = assembler.Parameter(Descriptor::kContext); |
| 1104 | 989 |
| 1105 assembler.Return(assembler.GetSuperConstructor(object, context)); | 990 assembler.Return(assembler.GetSuperConstructor(object, context)); |
| 1106 } | 991 } |
| 1107 | 992 |
| 1108 } // namespace internal | 993 } // namespace internal |
| 1109 } // namespace v8 | 994 } // namespace v8 |
| OLD | NEW |