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.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/contexts.h" | 9 #include "src/contexts.h" |
10 #include "src/elements.h" | 10 #include "src/elements.h" |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 HandleScope handleScope(isolate); | 143 HandleScope handleScope(isolate); |
144 int argc = args.length() - 1; | 144 int argc = args.length() - 1; |
145 ScopedVector<Handle<Object>> argv(argc); | 145 ScopedVector<Handle<Object>> argv(argc); |
146 for (int i = 0; i < argc; ++i) { | 146 for (int i = 0; i < argc; ++i) { |
147 argv[i] = args.at<Object>(i + 1); | 147 argv[i] = args.at<Object>(i + 1); |
148 } | 148 } |
149 RETURN_RESULT_OR_FAILURE( | 149 RETURN_RESULT_OR_FAILURE( |
150 isolate, | 150 isolate, |
151 Execution::Call(isolate, function, args.receiver(), argc, argv.start())); | 151 Execution::Call(isolate, function, args.receiver(), argc, argv.start())); |
152 } | 152 } |
| 153 } // namespace |
153 | 154 |
154 Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) { | 155 BUILTIN(ArrayPush) { |
155 HandleScope scope(isolate); | 156 HandleScope scope(isolate); |
156 Handle<Object> receiver = args.receiver(); | 157 Handle<Object> receiver = args.receiver(); |
157 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { | 158 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { |
158 return CallJsIntrinsic(isolate, isolate->array_push(), args); | 159 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
159 } | 160 } |
160 // Fast Elements Path | 161 // Fast Elements Path |
161 int to_add = args.length() - 1; | 162 int to_add = args.length() - 1; |
162 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 163 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
163 int len = Smi::cast(array->length())->value(); | 164 int len = Smi::cast(array->length())->value(); |
164 if (to_add == 0) return Smi::FromInt(len); | 165 if (to_add == 0) return Smi::FromInt(len); |
165 | 166 |
166 // Currently fixed arrays cannot grow too big, so we should never hit this. | 167 // Currently fixed arrays cannot grow too big, so we should never hit this. |
167 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value()); | 168 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value()); |
168 | 169 |
169 if (JSArray::HasReadOnlyLength(array)) { | 170 if (JSArray::HasReadOnlyLength(array)) { |
170 return CallJsIntrinsic(isolate, isolate->array_push(), args); | 171 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
171 } | 172 } |
172 | 173 |
173 ElementsAccessor* accessor = array->GetElementsAccessor(); | 174 ElementsAccessor* accessor = array->GetElementsAccessor(); |
174 int new_length = accessor->Push(array, &args, to_add); | 175 int new_length = accessor->Push(array, &args, to_add); |
175 return Smi::FromInt(new_length); | 176 return Smi::FromInt(new_length); |
176 } | 177 } |
177 } // namespace | |
178 | 178 |
179 BUILTIN(ArrayPush) { return DoArrayPush(isolate, args); } | 179 void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) { |
| 180 typedef compiler::Node Node; |
| 181 typedef CodeStubAssembler::Label Label; |
| 182 typedef CodeStubAssembler::Variable Variable; |
| 183 CodeStubAssembler assembler(state); |
| 184 Variable arg_index(&assembler, MachineType::PointerRepresentation()); |
| 185 Label default_label(&assembler, &arg_index); |
| 186 Label smi_transition(&assembler); |
| 187 Label object_push_pre(&assembler); |
| 188 Label object_push(&assembler, &arg_index); |
| 189 Label double_push(&assembler, &arg_index); |
| 190 Label double_transition(&assembler); |
| 191 Label runtime(&assembler, Label::kDeferred); |
180 | 192 |
181 // TODO(verwaest): This is a temporary helper until the FastArrayPush stub can | 193 Node* argc = assembler.Parameter(1); |
182 // tailcall to the builtin directly. | 194 Node* context = assembler.Parameter(2); |
183 RUNTIME_FUNCTION(Runtime_ArrayPush) { | 195 Node* new_target = assembler.Parameter(0); |
184 DCHECK_EQ(2, args.length()); | 196 |
185 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 197 CodeStubArguments args(&assembler, argc); |
186 // Rewrap the arguments as builtins arguments. | 198 Node* receiver = args.GetReceiver(); |
187 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 199 Node* kind = nullptr; |
188 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 200 |
189 return DoArrayPush(isolate, caller_args); | 201 Label fast(&assembler); |
| 202 { |
| 203 assembler.BranchIfFastJSArray( |
| 204 receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS, |
| 205 &fast, &runtime); |
| 206 } |
| 207 |
| 208 assembler.Bind(&fast); |
| 209 { |
| 210 // Disallow pushing onto prototypes. It might be the JSArray prototype. |
| 211 // Disallow pushing onto non-extensible objects. |
| 212 assembler.Comment("Disallow pushing onto prototypes"); |
| 213 Node* map = assembler.LoadMap(receiver); |
| 214 Node* bit_field2 = assembler.LoadMapBitField2(map); |
| 215 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | |
| 216 (1 << Map::kIsExtensible); |
| 217 Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask)); |
| 218 assembler.GotoIf( |
| 219 assembler.Word32NotEqual( |
| 220 test, assembler.Int32Constant(1 << Map::kIsExtensible)), |
| 221 &runtime); |
| 222 |
| 223 // Disallow pushing onto arrays in dictionary named property mode. We need |
| 224 // to figure out whether the length property is still writable. |
| 225 assembler.Comment( |
| 226 "Disallow pushing onto arrays in dictionary named property mode"); |
| 227 Node* bit_field3 = assembler.LoadMapBitField3(map); |
| 228 assembler.GotoIf(assembler.IsSetWord32<Map::DictionaryMap>(bit_field3), |
| 229 &runtime); |
| 230 |
| 231 // Check whether the length property is writable. The length property is the |
| 232 // only default named property on arrays. It's nonconfigurable, hence is |
| 233 // guaranteed to stay the first property. |
| 234 Node* descriptors = assembler.LoadMapDescriptors(map); |
| 235 Node* details = assembler.LoadFixedArrayElement( |
| 236 descriptors, |
| 237 assembler.Int32Constant(DescriptorArray::ToDetailsIndex(0))); |
| 238 mask = READ_ONLY << PropertyDetails::AttributesField::kShift; |
| 239 Node* mask_node = assembler.SmiConstant(mask); |
| 240 test = assembler.WordAnd(details, mask_node); |
| 241 assembler.GotoIf(assembler.WordEqual(test, mask_node), &runtime); |
| 242 |
| 243 arg_index.Bind(assembler.IntPtrConstant(0)); |
| 244 kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); |
| 245 |
| 246 assembler.GotoIf( |
| 247 assembler.IntPtrGreaterThan( |
| 248 kind, assembler.IntPtrConstant(FAST_HOLEY_SMI_ELEMENTS)), |
| 249 &object_push_pre); |
| 250 |
| 251 Node* new_length = assembler.BuildAppendJSArray( |
| 252 FAST_SMI_ELEMENTS, context, receiver, args, arg_index, &smi_transition); |
| 253 args.PopAndReturn(new_length); |
| 254 } |
| 255 |
| 256 // If the argument is not a smi, then use a heavyweight SetProperty to |
| 257 // transition the array for only the single next element. If the argument is |
| 258 // a smi, the failure is due to some other reason and we should fall back on |
| 259 // the most generic implementation for the rest of the array. |
| 260 assembler.Bind(&smi_transition); |
| 261 { |
| 262 Node* arg = args.AtIndex(arg_index.value()); |
| 263 assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label); |
| 264 Node* length = assembler.LoadJSArrayLength(receiver); |
| 265 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, |
| 266 // calling into the runtime to do the elements transition is overkill. |
| 267 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, |
| 268 assembler.SmiConstant(STRICT)); |
| 269 assembler.Increment(arg_index); |
| 270 assembler.GotoIfNotNumber(arg, &object_push); |
| 271 assembler.Goto(&double_push); |
| 272 } |
| 273 |
| 274 assembler.Bind(&object_push_pre); |
| 275 { |
| 276 assembler.Branch(assembler.IntPtrGreaterThan( |
| 277 kind, assembler.IntPtrConstant(FAST_HOLEY_ELEMENTS)), |
| 278 &double_push, &object_push); |
| 279 } |
| 280 |
| 281 assembler.Bind(&object_push); |
| 282 { |
| 283 Node* new_length = assembler.BuildAppendJSArray( |
| 284 FAST_ELEMENTS, context, receiver, args, arg_index, &default_label); |
| 285 args.PopAndReturn(new_length); |
| 286 } |
| 287 |
| 288 assembler.Bind(&double_push); |
| 289 { |
| 290 Node* new_length = |
| 291 assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, |
| 292 args, arg_index, &double_transition); |
| 293 args.PopAndReturn(new_length); |
| 294 } |
| 295 |
| 296 // If the argument is not a double, then use a heavyweight SetProperty to |
| 297 // transition the array for only the single next element. If the argument is |
| 298 // a double, the failure is due to some other reason and we should fall back |
| 299 // on the most generic implementation for the rest of the array. |
| 300 assembler.Bind(&double_transition); |
| 301 { |
| 302 Node* arg = args.AtIndex(arg_index.value()); |
| 303 assembler.GotoIfNumber(arg, &default_label); |
| 304 Node* length = assembler.LoadJSArrayLength(receiver); |
| 305 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, |
| 306 // calling into the runtime to do the elements transition is overkill. |
| 307 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg, |
| 308 assembler.SmiConstant(STRICT)); |
| 309 assembler.Increment(arg_index); |
| 310 assembler.Goto(&object_push); |
| 311 } |
| 312 |
| 313 // Fallback that stores un-processed arguments using the full, heavyweight |
| 314 // SetProperty machinery. |
| 315 assembler.Bind(&default_label); |
| 316 { |
| 317 args.ForEach( |
| 318 [receiver, context, &arg_index](CodeStubAssembler* assembler, |
| 319 Node* arg) { |
| 320 Node* length = assembler->LoadJSArrayLength(receiver); |
| 321 assembler->CallRuntime(Runtime::kSetProperty, context, receiver, |
| 322 length, arg, assembler->SmiConstant(STRICT)); |
| 323 }, |
| 324 arg_index.value()); |
| 325 args.PopAndReturn(assembler.LoadJSArrayLength(receiver)); |
| 326 } |
| 327 |
| 328 assembler.Bind(&runtime); |
| 329 { |
| 330 Node* target = assembler.LoadFromFrame( |
| 331 StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); |
| 332 assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), context, |
| 333 target, new_target, argc); |
| 334 } |
190 } | 335 } |
191 | 336 |
192 BUILTIN(ArrayPop) { | 337 BUILTIN(ArrayPop) { |
193 HandleScope scope(isolate); | 338 HandleScope scope(isolate); |
194 Handle<Object> receiver = args.receiver(); | 339 Handle<Object> receiver = args.receiver(); |
195 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { | 340 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { |
196 return CallJsIntrinsic(isolate, isolate->array_pop(), args); | 341 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
197 } | 342 } |
198 | 343 |
199 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 344 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
(...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1287 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), | 1432 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), |
1288 call_runtime(&assembler); | 1433 call_runtime(&assembler); |
1289 | 1434 |
1290 Label init_len(&assembler); | 1435 Label init_len(&assembler); |
1291 | 1436 |
1292 index_var.Bind(intptr_zero); | 1437 index_var.Bind(intptr_zero); |
1293 len_var.Bind(intptr_zero); | 1438 len_var.Bind(intptr_zero); |
1294 | 1439 |
1295 // Take slow path if not a JSArray, if retrieving elements requires | 1440 // Take slow path if not a JSArray, if retrieving elements requires |
1296 // traversing prototype, or if access checks are required. | 1441 // traversing prototype, or if access checks are required. |
1297 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); | 1442 assembler.BranchIfFastJSArray( |
| 1443 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
| 1444 &init_len, &call_runtime); |
1298 | 1445 |
1299 assembler.Bind(&init_len); | 1446 assembler.Bind(&init_len); |
1300 { | 1447 { |
1301 // Handle case where JSArray length is not an Smi in the runtime | 1448 // Handle case where JSArray length is not an Smi in the runtime |
1302 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); | 1449 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); |
1303 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); | 1450 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); |
1304 | 1451 |
1305 len_var.Bind(assembler.SmiToWord(len)); | 1452 len_var.Bind(assembler.SmiToWord(len)); |
1306 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), | 1453 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), |
1307 &return_false, &init_k); | 1454 &return_false, &init_k); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1728 Label init_k(&assembler), return_found(&assembler), | 1875 Label init_k(&assembler), return_found(&assembler), |
1729 return_not_found(&assembler), call_runtime(&assembler); | 1876 return_not_found(&assembler), call_runtime(&assembler); |
1730 | 1877 |
1731 Label init_len(&assembler); | 1878 Label init_len(&assembler); |
1732 | 1879 |
1733 index_var.Bind(intptr_zero); | 1880 index_var.Bind(intptr_zero); |
1734 len_var.Bind(intptr_zero); | 1881 len_var.Bind(intptr_zero); |
1735 | 1882 |
1736 // Take slow path if not a JSArray, if retrieving elements requires | 1883 // Take slow path if not a JSArray, if retrieving elements requires |
1737 // traversing prototype, or if access checks are required. | 1884 // traversing prototype, or if access checks are required. |
1738 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); | 1885 assembler.BranchIfFastJSArray( |
| 1886 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
| 1887 &init_len, &call_runtime); |
1739 | 1888 |
1740 assembler.Bind(&init_len); | 1889 assembler.Bind(&init_len); |
1741 { | 1890 { |
1742 // Handle case where JSArray length is not an Smi in the runtime | 1891 // Handle case where JSArray length is not an Smi in the runtime |
1743 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); | 1892 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); |
1744 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); | 1893 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); |
1745 | 1894 |
1746 len_var.Bind(assembler.SmiToWord(len)); | 1895 len_var.Bind(assembler.SmiToWord(len)); |
1747 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), | 1896 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), |
1748 &return_not_found, &init_k); | 1897 &return_not_found, &init_k); |
(...skipping 864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2613 Runtime::kThrowIncompatibleMethodReceiver, context, | 2762 Runtime::kThrowIncompatibleMethodReceiver, context, |
2614 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( | 2763 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( |
2615 "Array Iterator.prototype.next", TENURED)), | 2764 "Array Iterator.prototype.next", TENURED)), |
2616 iterator); | 2765 iterator); |
2617 assembler.Return(result); | 2766 assembler.Return(result); |
2618 } | 2767 } |
2619 } | 2768 } |
2620 | 2769 |
2621 } // namespace internal | 2770 } // namespace internal |
2622 } // namespace v8 | 2771 } // namespace v8 |
OLD | NEW |