OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
9 #include "src/base/once.h" | 9 #include "src/base/once.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
195 return false; | 195 return false; |
196 } | 196 } |
197 array_proto = JSObject::cast(iter.GetCurrent()); | 197 array_proto = JSObject::cast(iter.GetCurrent()); |
198 if (array_proto != native_context->initial_object_prototype()) return false; | 198 if (array_proto != native_context->initial_object_prototype()) return false; |
199 if (array_proto->elements() != heap->empty_fixed_array()) return false; | 199 if (array_proto->elements() != heap->empty_fixed_array()) return false; |
200 iter.Advance(); | 200 iter.Advance(); |
201 return iter.IsAtEnd(); | 201 return iter.IsAtEnd(); |
202 } | 202 } |
203 | 203 |
204 | 204 |
205 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, | |
206 JSArray* receiver) { | |
207 if (!FLAG_clever_optimizations) return false; | |
208 DisallowHeapAllocation no_gc; | |
209 Context* native_context = heap->isolate()->context()->native_context(); | |
210 JSObject* array_proto = | |
211 JSObject::cast(native_context->array_function()->prototype()); | |
212 PrototypeIterator iter(heap->isolate(), receiver); | |
213 return iter.GetCurrent() == array_proto && | |
214 ArrayPrototypeHasNoElements(heap, native_context, array_proto); | |
215 } | |
216 | |
217 | |
205 // Returns empty handle if not applicable. | 218 // Returns empty handle if not applicable. |
206 MUST_USE_RESULT | 219 MUST_USE_RESULT |
207 static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( | 220 static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( |
208 Isolate* isolate, | 221 Isolate* isolate, |
209 Handle<Object> receiver, | 222 Handle<Object> receiver, |
210 Arguments* args, | 223 Arguments* args, |
211 int first_added_arg) { | 224 int first_added_arg) { |
212 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>(); | 225 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>(); |
213 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 226 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
214 // If there may be elements accessors in the prototype chain, the fast path | 227 // If there may be elements accessors in the prototype chain, the fast path |
215 // cannot be used if there arguments to add to the array. | 228 // cannot be used if there arguments to add to the array. |
216 if (args != NULL && array->map()->DictionaryElementsInPrototypeChainOnly()) { | 229 Heap* heap = isolate->heap(); |
230 if (args != NULL && !IsJSArrayFastElementMovingAllowed(heap, *array)) { | |
217 return MaybeHandle<FixedArrayBase>(); | 231 return MaybeHandle<FixedArrayBase>(); |
218 } | 232 } |
219 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>(); | 233 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>(); |
220 if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>(); | 234 if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>(); |
221 Handle<FixedArrayBase> elms(array->elements(), isolate); | 235 Handle<FixedArrayBase> elms(array->elements(), isolate); |
222 Heap* heap = isolate->heap(); | |
223 Map* map = elms->map(); | 236 Map* map = elms->map(); |
224 if (map == heap->fixed_array_map()) { | 237 if (map == heap->fixed_array_map()) { |
225 if (args == NULL || array->HasFastObjectElements()) return elms; | 238 if (args == NULL || array->HasFastObjectElements()) return elms; |
226 } else if (map == heap->fixed_cow_array_map()) { | 239 } else if (map == heap->fixed_cow_array_map()) { |
227 elms = JSObject::EnsureWritableFastElements(array); | 240 elms = JSObject::EnsureWritableFastElements(array); |
228 if (args == NULL || array->HasFastObjectElements()) return elms; | 241 if (args == NULL || array->HasFastObjectElements()) return elms; |
229 } else if (map == heap->fixed_double_array_map()) { | 242 } else if (map == heap->fixed_double_array_map()) { |
230 if (args == NULL) return elms; | 243 if (args == NULL) return elms; |
231 } else { | 244 } else { |
232 return MaybeHandle<FixedArrayBase>(); | 245 return MaybeHandle<FixedArrayBase>(); |
(...skipping 24 matching lines...) Expand all Loading... | |
257 } | 270 } |
258 } | 271 } |
259 if (target_kind != origin_kind) { | 272 if (target_kind != origin_kind) { |
260 JSObject::TransitionElementsKind(array, target_kind); | 273 JSObject::TransitionElementsKind(array, target_kind); |
261 return handle(array->elements(), isolate); | 274 return handle(array->elements(), isolate); |
262 } | 275 } |
263 return elms; | 276 return elms; |
264 } | 277 } |
265 | 278 |
266 | 279 |
267 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, | |
268 JSArray* receiver) { | |
269 if (!FLAG_clever_optimizations) return false; | |
270 DisallowHeapAllocation no_gc; | |
271 Context* native_context = heap->isolate()->context()->native_context(); | |
272 JSObject* array_proto = | |
273 JSObject::cast(native_context->array_function()->prototype()); | |
274 PrototypeIterator iter(heap->isolate(), receiver); | |
275 return iter.GetCurrent() == array_proto && | |
276 ArrayPrototypeHasNoElements(heap, native_context, array_proto); | |
277 } | |
278 | |
279 | |
280 MUST_USE_RESULT static Object* CallJsBuiltin( | 280 MUST_USE_RESULT static Object* CallJsBuiltin( |
281 Isolate* isolate, | 281 Isolate* isolate, |
282 const char* name, | 282 const char* name, |
283 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | 283 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
284 HandleScope handleScope(isolate); | 284 HandleScope handleScope(isolate); |
285 | 285 |
286 Handle<Object> js_builtin = Object::GetProperty( | 286 Handle<Object> js_builtin = Object::GetProperty( |
287 isolate, | 287 isolate, |
288 handle(isolate->native_context()->builtins(), isolate), | 288 handle(isolate->native_context()->builtins(), isolate), |
289 name).ToHandleChecked(); | 289 name).ToHandleChecked(); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
446 | 446 |
447 | 447 |
448 BUILTIN(ArrayShift) { | 448 BUILTIN(ArrayShift) { |
449 HandleScope scope(isolate); | 449 HandleScope scope(isolate); |
450 Heap* heap = isolate->heap(); | 450 Heap* heap = isolate->heap(); |
451 Handle<Object> receiver = args.receiver(); | 451 Handle<Object> receiver = args.receiver(); |
452 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 452 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
453 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 453 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); |
454 Handle<FixedArrayBase> elms_obj; | 454 Handle<FixedArrayBase> elms_obj; |
455 if (!maybe_elms_obj.ToHandle(&elms_obj) || | 455 if (!maybe_elms_obj.ToHandle(&elms_obj) || |
456 !IsJSArrayFastElementMovingAllowed(heap, | 456 !IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(*receiver))) { |
457 *Handle<JSArray>::cast(receiver))) { | |
458 return CallJsBuiltin(isolate, "ArrayShift", args); | 457 return CallJsBuiltin(isolate, "ArrayShift", args); |
459 } | 458 } |
460 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 459 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
461 DCHECK(!array->map()->is_observed()); | 460 DCHECK(!array->map()->is_observed()); |
462 | 461 |
463 int len = Smi::cast(array->length())->value(); | 462 int len = Smi::cast(array->length())->value(); |
464 if (len == 0) return heap->undefined_value(); | 463 if (len == 0) return heap->undefined_value(); |
465 | 464 |
466 // Get first element | 465 // Get first element |
467 ElementsAccessor* accessor = array->GetElementsAccessor(); | 466 ElementsAccessor* accessor = array->GetElementsAccessor(); |
(...skipping 24 matching lines...) Expand all Loading... | |
492 | 491 |
493 return *first; | 492 return *first; |
494 } | 493 } |
495 | 494 |
496 | 495 |
497 BUILTIN(ArrayUnshift) { | 496 BUILTIN(ArrayUnshift) { |
498 HandleScope scope(isolate); | 497 HandleScope scope(isolate); |
499 Heap* heap = isolate->heap(); | 498 Heap* heap = isolate->heap(); |
500 Handle<Object> receiver = args.receiver(); | 499 Handle<Object> receiver = args.receiver(); |
501 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 500 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
502 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 501 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
503 Handle<FixedArrayBase> elms_obj; | 502 Handle<FixedArrayBase> elms_obj; |
504 if (!maybe_elms_obj.ToHandle(&elms_obj) || | 503 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
505 !IsJSArrayFastElementMovingAllowed(heap, | |
506 *Handle<JSArray>::cast(receiver))) { | |
507 return CallJsBuiltin(isolate, "ArrayUnshift", args); | 504 return CallJsBuiltin(isolate, "ArrayUnshift", args); |
508 } | 505 } |
509 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 506 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
510 DCHECK(!array->map()->is_observed()); | 507 DCHECK(!array->map()->is_observed()); |
511 if (!array->HasFastSmiOrObjectElements()) { | 508 if (!array->HasFastSmiOrObjectElements()) { |
512 return CallJsBuiltin(isolate, "ArrayUnshift", args); | 509 return CallJsBuiltin(isolate, "ArrayUnshift", args); |
513 } | 510 } |
514 int len = Smi::cast(array->length())->value(); | 511 int len = Smi::cast(array->length())->value(); |
515 int to_add = args.length() - 1; | 512 int to_add = args.length() - 1; |
516 int new_length = len + to_add; | 513 int new_length = len + to_add; |
517 // Currently fixed arrays cannot grow too big, so | 514 // Currently fixed arrays cannot grow too big, so |
518 // we should never hit this case. | 515 // we should never hit this case. |
519 DCHECK(to_add <= (Smi::kMaxValue - len)); | 516 DCHECK(to_add <= (Smi::kMaxValue - len)); |
520 | 517 |
521 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { | 518 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { |
522 return CallJsBuiltin(isolate, "ArrayUnshift", args); | 519 return CallJsBuiltin(isolate, "ArrayUnshift", args); |
523 } | 520 } |
524 | 521 |
525 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | 522 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
526 | 523 |
527 JSObject::EnsureCanContainElements(array, &args, 1, to_add, | |
528 DONT_ALLOW_DOUBLE_ELEMENTS); | |
mvstanton
2014/11/03 12:59:13
nit: should prolly be in another CL but up to you.
| |
529 | |
530 if (new_length > elms->length()) { | 524 if (new_length > elms->length()) { |
531 // New backing storage is needed. | 525 // New backing storage is needed. |
532 int capacity = new_length + (new_length >> 1) + 16; | 526 int capacity = new_length + (new_length >> 1) + 16; |
533 Handle<FixedArray> new_elms = | 527 Handle<FixedArray> new_elms = |
534 isolate->factory()->NewUninitializedFixedArray(capacity); | 528 isolate->factory()->NewUninitializedFixedArray(capacity); |
535 | 529 |
536 ElementsKind kind = array->GetElementsKind(); | 530 ElementsKind kind = array->GetElementsKind(); |
537 ElementsAccessor* accessor = array->GetElementsAccessor(); | 531 ElementsAccessor* accessor = array->GetElementsAccessor(); |
538 accessor->CopyElements( | 532 accessor->CopyElements( |
539 elms, 0, kind, new_elms, to_add, | 533 elms, 0, kind, new_elms, to_add, |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 } | 695 } |
702 | 696 |
703 | 697 |
704 BUILTIN(ArraySplice) { | 698 BUILTIN(ArraySplice) { |
705 HandleScope scope(isolate); | 699 HandleScope scope(isolate); |
706 Heap* heap = isolate->heap(); | 700 Heap* heap = isolate->heap(); |
707 Handle<Object> receiver = args.receiver(); | 701 Handle<Object> receiver = args.receiver(); |
708 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 702 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
709 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 703 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
710 Handle<FixedArrayBase> elms_obj; | 704 Handle<FixedArrayBase> elms_obj; |
711 if (!maybe_elms_obj.ToHandle(&elms_obj) || | 705 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
712 !IsJSArrayFastElementMovingAllowed(heap, | |
713 *Handle<JSArray>::cast(receiver))) { | |
714 return CallJsBuiltin(isolate, "ArraySplice", args); | 706 return CallJsBuiltin(isolate, "ArraySplice", args); |
715 } | 707 } |
716 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 708 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
717 DCHECK(!array->map()->is_observed()); | 709 DCHECK(!array->map()->is_observed()); |
718 | 710 |
719 int len = Smi::cast(array->length())->value(); | 711 int len = Smi::cast(array->length())->value(); |
720 | 712 |
721 int n_arguments = args.length() - 1; | 713 int n_arguments = args.length() - 1; |
722 | 714 |
723 int relative_start = 0; | 715 int relative_start = 0; |
(...skipping 926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1650 } | 1642 } |
1651 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1643 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
1652 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1644 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
1653 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1645 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
1654 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1646 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
1655 #undef DEFINE_BUILTIN_ACCESSOR_C | 1647 #undef DEFINE_BUILTIN_ACCESSOR_C |
1656 #undef DEFINE_BUILTIN_ACCESSOR_A | 1648 #undef DEFINE_BUILTIN_ACCESSOR_A |
1657 | 1649 |
1658 | 1650 |
1659 } } // namespace v8::internal | 1651 } } // namespace v8::internal |
OLD | NEW |