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 Label runtime(&assembler, Label::kDeferred); | |
180 | 185 |
181 // TODO(verwaest): This is a temporary helper until the FastArrayPush stub can | 186 Node* argc = assembler.Parameter(1); |
182 // tailcall to the builtin directly. | 187 Node* context = assembler.Parameter(2); |
183 RUNTIME_FUNCTION(Runtime_ArrayPush) { | 188 Node* new_target = assembler.Parameter(0); |
184 DCHECK_EQ(2, args.length()); | 189 |
185 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 190 CodeStubArguments args(&assembler, argc); |
186 // Rewrap the arguments as builtins arguments. | 191 Node* receiver = args.GetReceiver(); |
187 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 192 |
188 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 193 Label fast(&assembler); |
189 return DoArrayPush(isolate, caller_args); | 194 assembler.BranchIfFastJSArray( |
195 receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS, | |
196 &fast, &runtime); | |
197 | |
198 assembler.Bind(&fast); | |
199 { | |
Jakob Kummerow
2016/11/23 17:17:05
nit: this identation level doesn't add anything (e
danno
2016/11/29 14:39:59
Done.
| |
200 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
201 // Disallow pushing onto non-extensible objects. | |
202 assembler.Comment("Disallow pushing onto prototypes"); | |
203 Node* map = assembler.LoadMap(receiver); | |
204 Node* bit_field2 = assembler.LoadObjectField(map, Map::kBitField2Offset, | |
Jakob Kummerow
2016/11/23 17:17:05
... = assembler.LoadMapBitField2(map);
danno
2016/11/29 14:39:59
Done.
| |
205 MachineType::Uint8()); | |
206 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
207 (1 << Map::kIsExtensible); | |
208 Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask)); | |
209 assembler.GotoIf( | |
210 assembler.Word32NotEqual( | |
211 test, assembler.Int32Constant(1 << Map::kIsExtensible)), | |
212 &runtime); | |
213 | |
214 // Disallow pushing onto arrays in dictionary named property mode. We need | |
215 // to figure out whether the length property is still writable. | |
216 assembler.Comment( | |
217 "Disallow pushing onto arrays in dictionary named property mode"); | |
218 Node* bit_field3 = assembler.LoadObjectField(map, Map::kBitField3Offset, | |
Jakob Kummerow
2016/11/23 17:17:05
... = assembler.LoadMapBitField3(map);
danno
2016/11/29 14:39:59
Done.
| |
219 MachineType::Uint32()); | |
220 mask = static_cast<int>(Map::DictionaryMap::kMask); | |
221 Node* mask_node = assembler.Int32Constant(mask); | |
222 test = assembler.Word32And(bit_field3, mask_node); | |
223 assembler.GotoIf(assembler.Word32Equal(test, mask_node), &runtime); | |
Jakob Kummerow
2016/11/23 17:17:05
assembler.GotoIf(assembler.IsSetWord32<Map::Dictio
| |
224 | |
225 // Check whether the length property is writable. The length property is the | |
Jakob Kummerow
2016/11/23 17:17:05
Most excellent point. The KeyedStoreGeneric stub h
danno
2016/11/29 14:39:59
Done.
| |
226 // only default named property on arrays. It's nonconfigurable, hence is | |
227 // guaranteed to stay the first property. | |
228 Node* descriptors = assembler.LoadObjectField(map, Map::kDescriptorsOffset); | |
Jakob Kummerow
2016/11/23 17:17:05
... = assembler.LoadMapDescriptors(map);
danno
2016/11/29 14:39:59
Done.
| |
229 Node* details = assembler.LoadFixedArrayElement( | |
230 descriptors, | |
231 assembler.Int32Constant(DescriptorArray::ToDetailsIndex(0))); | |
232 mask = READ_ONLY << PropertyDetails::AttributesField::kShift; | |
233 mask_node = assembler.SmiConstant(Smi::FromInt(mask)); | |
Jakob Kummerow
2016/11/23 17:17:05
nit: s/Smi::FromInt(mask)/mask/
danno
2016/11/29 14:39:59
Done.
| |
234 test = assembler.WordAnd(details, mask_node); | |
235 assembler.GotoIf(assembler.WordEqual(test, mask_node), &runtime); | |
236 | |
237 Variable arg_index(&assembler, MachineType::PointerRepresentation()); | |
238 arg_index.Bind(assembler.IntPtrConstant(0)); | |
239 Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
240 CodeStubAssembler::VariableList vars({&arg_index}, assembler.zone()); | |
241 Label default_label(&assembler, vars); | |
Jakob Kummerow
2016/11/23 17:17:05
nit: why not just s/vars/&arg_index/ here and once
danno
2016/11/29 14:39:59
Done.
| |
242 Label smi_transition(&assembler); | |
243 Label object_push_pre(&assembler); | |
244 Label object_push(&assembler, vars); | |
245 Label double_push(&assembler); | |
246 Label double_transition(&assembler); | |
247 | |
248 assembler.GotoIf( | |
249 assembler.IntPtrGreaterThan( | |
250 kind, assembler.IntPtrConstant(FAST_HOLEY_SMI_ELEMENTS)), | |
251 &object_push_pre); | |
252 | |
253 { | |
254 Node* new_length = | |
255 assembler.BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, | |
256 args, arg_index, &smi_transition); | |
257 args.PopAndReturn(new_length); | |
258 } | |
259 | |
260 // If the argument is not a smi, then use a heavyweight SetProperty to | |
261 // transition the array for only the single next element. If the argument is | |
262 // a smi, the failure is due to some other reason and we should fall back on | |
263 // the most generic implementation for the rest of the array. | |
264 assembler.Bind(&smi_transition); | |
265 { | |
266 Node* arg = args.AtIndex(arg_index.value()); | |
267 assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label); | |
268 Node* length = assembler.LoadJSArrayLength(receiver); | |
269 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, | |
270 // calling into the runtime to do the elements transition is overkill. | |
271 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, | |
272 arg, assembler.SmiConstant(Smi::FromInt(STRICT))); | |
Jakob Kummerow
2016/11/23 17:17:05
nit: s/Smi::FromInt(STRICT)/STRICT/
danno
2016/11/29 14:39:59
Done.
| |
273 assembler.Increment(arg_index); | |
274 assembler.GotoIfNotNumber(arg, &object_push); | |
275 assembler.Goto(&double_push); | |
276 } | |
277 | |
278 assembler.Bind(&object_push_pre); | |
279 assembler.Branch(assembler.IntPtrGreaterThan( | |
280 kind, assembler.IntPtrConstant(FAST_HOLEY_ELEMENTS)), | |
281 &double_push, &object_push); | |
282 | |
283 assembler.Bind(&object_push); | |
284 { | |
285 Node* new_length = assembler.BuildAppendJSArray( | |
286 FAST_ELEMENTS, context, receiver, args, arg_index, &default_label); | |
287 args.PopAndReturn(new_length); | |
288 } | |
289 | |
290 assembler.Bind(&double_push); | |
291 { | |
292 Node* new_length = | |
293 assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, | |
294 args, arg_index, &double_transition); | |
295 args.PopAndReturn(new_length); | |
296 } | |
297 | |
298 // If the argument is not a double, then use a heavyweight SetProperty to | |
299 // transition the array for only the single next element. If the argument is | |
300 // a double, the failure is due to some other reason and we should fall back | |
301 // on the most generic implementation for the rest of the array. | |
302 assembler.Bind(&double_transition); | |
303 { | |
304 Node* arg = args.AtIndex(arg_index.value()); | |
305 assembler.GotoIfNumber(arg, &default_label); | |
306 Node* length = assembler.LoadJSArrayLength(receiver); | |
307 // TODO(danno): Use the KeyedStoreGeneric stub here when possible, | |
308 // calling into the runtime to do the elements transition is overkill. | |
309 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, | |
310 arg, assembler.SmiConstant(Smi::FromInt(STRICT))); | |
Jakob Kummerow
2016/11/23 17:17:05
nit: s/Smi::FromInt(STRICT)/STRICT/
danno
2016/11/29 14:39:59
Done.
| |
311 assembler.Increment(arg_index); | |
312 assembler.Goto(&object_push); | |
313 } | |
314 | |
315 // Fallback that stores un-processed arguments using the full, heavyweight | |
316 // SetProperty machinery. | |
317 assembler.Bind(&default_label); | |
318 { | |
319 args.ForEach( | |
320 [receiver, context, &arg_index](CodeStubAssembler* assembler, | |
321 Node* arg) { | |
322 Node* length = assembler->LoadJSArrayLength(receiver); | |
323 assembler->CallRuntime( | |
324 Runtime::kSetProperty, context, receiver, length, arg, | |
325 assembler->SmiConstant(Smi::FromInt(STRICT))); | |
Jakob Kummerow
2016/11/23 17:17:05
nit: s/Smi::FromInt(STRICT)/STRICT/
danno
2016/11/29 14:39:59
Done.
| |
326 }, | |
327 arg_index.value()); | |
328 args.PopAndReturn(assembler.LoadJSArrayLength(receiver)); | |
329 } | |
330 | |
331 assembler.Bind(&runtime); | |
332 { | |
333 Node* target = | |
334 assembler.LoadFromFrame(StandardFrameConstants::kFunctionOffset, | |
335 MachineType::TaggedPointer()); | |
336 assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), | |
337 context, target, new_target, argc); | |
338 } | |
339 } | |
190 } | 340 } |
191 | 341 |
192 BUILTIN(ArrayPop) { | 342 BUILTIN(ArrayPop) { |
193 HandleScope scope(isolate); | 343 HandleScope scope(isolate); |
194 Handle<Object> receiver = args.receiver(); | 344 Handle<Object> receiver = args.receiver(); |
195 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { | 345 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { |
196 return CallJsIntrinsic(isolate, isolate->array_pop(), args); | 346 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
197 } | 347 } |
198 | 348 |
199 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 349 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
(...skipping 1086 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1286 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), | 1436 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), |
1287 call_runtime(&assembler); | 1437 call_runtime(&assembler); |
1288 | 1438 |
1289 Label init_len(&assembler); | 1439 Label init_len(&assembler); |
1290 | 1440 |
1291 index_var.Bind(intptr_zero); | 1441 index_var.Bind(intptr_zero); |
1292 len_var.Bind(intptr_zero); | 1442 len_var.Bind(intptr_zero); |
1293 | 1443 |
1294 // Take slow path if not a JSArray, if retrieving elements requires | 1444 // Take slow path if not a JSArray, if retrieving elements requires |
1295 // traversing prototype, or if access checks are required. | 1445 // traversing prototype, or if access checks are required. |
1296 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); | 1446 assembler.BranchIfFastJSArray( |
1447 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
1448 &init_len, &call_runtime); | |
1297 | 1449 |
1298 assembler.Bind(&init_len); | 1450 assembler.Bind(&init_len); |
1299 { | 1451 { |
1300 // Handle case where JSArray length is not an Smi in the runtime | 1452 // Handle case where JSArray length is not an Smi in the runtime |
1301 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); | 1453 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); |
1302 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); | 1454 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); |
1303 | 1455 |
1304 len_var.Bind(assembler.SmiToWord(len)); | 1456 len_var.Bind(assembler.SmiToWord(len)); |
1305 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), | 1457 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), |
1306 &return_false, &init_k); | 1458 &return_false, &init_k); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1727 Label init_k(&assembler), return_found(&assembler), | 1879 Label init_k(&assembler), return_found(&assembler), |
1728 return_not_found(&assembler), call_runtime(&assembler); | 1880 return_not_found(&assembler), call_runtime(&assembler); |
1729 | 1881 |
1730 Label init_len(&assembler); | 1882 Label init_len(&assembler); |
1731 | 1883 |
1732 index_var.Bind(intptr_zero); | 1884 index_var.Bind(intptr_zero); |
1733 len_var.Bind(intptr_zero); | 1885 len_var.Bind(intptr_zero); |
1734 | 1886 |
1735 // Take slow path if not a JSArray, if retrieving elements requires | 1887 // Take slow path if not a JSArray, if retrieving elements requires |
1736 // traversing prototype, or if access checks are required. | 1888 // traversing prototype, or if access checks are required. |
1737 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); | 1889 assembler.BranchIfFastJSArray( |
1890 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
1891 &init_len, &call_runtime); | |
1738 | 1892 |
1739 assembler.Bind(&init_len); | 1893 assembler.Bind(&init_len); |
1740 { | 1894 { |
1741 // Handle case where JSArray length is not an Smi in the runtime | 1895 // Handle case where JSArray length is not an Smi in the runtime |
1742 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); | 1896 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); |
1743 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); | 1897 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); |
1744 | 1898 |
1745 len_var.Bind(assembler.SmiToWord(len)); | 1899 len_var.Bind(assembler.SmiToWord(len)); |
1746 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), | 1900 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), |
1747 &return_not_found, &init_k); | 1901 &return_not_found, &init_k); |
(...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2613 Runtime::kThrowIncompatibleMethodReceiver, context, | 2767 Runtime::kThrowIncompatibleMethodReceiver, context, |
2614 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( | 2768 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( |
2615 "Array Iterator.prototype.next", TENURED)), | 2769 "Array Iterator.prototype.next", TENURED)), |
2616 iterator); | 2770 iterator); |
2617 assembler.Return(result); | 2771 assembler.Return(result); |
2618 } | 2772 } |
2619 } | 2773 } |
2620 | 2774 |
2621 } // namespace internal | 2775 } // namespace internal |
2622 } // namespace v8 | 2776 } // namespace v8 |
OLD | NEW |