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

Side by Side Diff: src/builtins.cc

Issue 701513002: Don't double-check elements in the prototype chain in array builtins (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | test/mjsunit/array-natives-elements.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/array-natives-elements.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698