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

Side by Side Diff: src/builtins.cc

Issue 2037008: Properly process arrays with overridden prototype in various Array's functions. (Closed)
Patch Set: Addressing Mads' comments Created 10 years, 7 months 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
« no previous file with comments | « no previous file | test/mjsunit/array-concat.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 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 323
324 former_start[to_trim] = Heap::fixed_array_map(); 324 former_start[to_trim] = Heap::fixed_array_map();
325 former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim); 325 former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim);
326 326
327 ASSERT_EQ(elms->address() + to_trim * kPointerSize, 327 ASSERT_EQ(elms->address() + to_trim * kPointerSize,
328 (elms + to_trim * kPointerSize)->address()); 328 (elms + to_trim * kPointerSize)->address());
329 return elms + to_trim * kPointerSize; 329 return elms + to_trim * kPointerSize;
330 } 330 }
331 331
332 332
333 static bool ArrayPrototypeHasNoElements() { 333 static bool ArrayPrototypeHasNoElements(Context* global_context,
334 JSObject* array_proto) {
334 // This method depends on non writability of Object and Array prototype 335 // This method depends on non writability of Object and Array prototype
335 // fields. 336 // fields.
336 Context* global_context = Top::context()->global_context(); 337 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
337 // Array.prototype
338 JSObject* proto =
339 JSObject::cast(global_context->array_function()->prototype());
340 if (proto->elements() != Heap::empty_fixed_array()) return false;
341 // Hidden prototype 338 // Hidden prototype
342 proto = JSObject::cast(proto->GetPrototype()); 339 array_proto = JSObject::cast(array_proto->GetPrototype());
343 ASSERT(proto->elements() == Heap::empty_fixed_array()); 340 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
344 // Object.prototype 341 // Object.prototype
345 proto = JSObject::cast(proto->GetPrototype()); 342 array_proto = JSObject::cast(array_proto->GetPrototype());
346 if (proto != global_context->initial_object_prototype()) return false; 343 if (array_proto != global_context->initial_object_prototype()) return false;
347 if (proto->elements() != Heap::empty_fixed_array()) return false; 344 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
348 ASSERT(proto->GetPrototype()->IsNull()); 345 ASSERT(array_proto->GetPrototype()->IsNull());
349 return true; 346 return true;
350 } 347 }
351 348
352 349
353 static bool IsJSArrayWithFastElements(Object* receiver, 350 static bool IsJSArrayWithFastElements(Object* receiver,
354 FixedArray** elements) { 351 FixedArray** elements) {
355 if (!receiver->IsJSArray()) { 352 if (!receiver->IsJSArray()) {
356 return false; 353 return false;
357 } 354 }
358 355
359 JSArray* array = JSArray::cast(receiver); 356 JSArray* array = JSArray::cast(receiver);
360 357
361 HeapObject* elms = HeapObject::cast(array->elements()); 358 HeapObject* elms = HeapObject::cast(array->elements());
362 if (elms->map() != Heap::fixed_array_map()) { 359 if (elms->map() != Heap::fixed_array_map()) {
363 return false; 360 return false;
364 } 361 }
365 362
366 *elements = FixedArray::cast(elms); 363 *elements = FixedArray::cast(elms);
367 return true; 364 return true;
368 } 365 }
369 366
370 367
368 static bool IsFastElementMovingAllowed(Object* receiver,
369 FixedArray** elements) {
370 if (!IsJSArrayWithFastElements(receiver, elements)) return false;
371
372 Context* global_context = Top::context()->global_context();
373 JSObject* array_proto =
374 JSObject::cast(global_context->array_function()->prototype());
375 if (JSArray::cast(receiver)->GetPrototype() != array_proto) return false;
376 return ArrayPrototypeHasNoElements(global_context, array_proto);
377 }
378
379
371 static Object* CallJsBuiltin(const char* name, 380 static Object* CallJsBuiltin(const char* name,
372 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { 381 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
373 HandleScope handleScope; 382 HandleScope handleScope;
374 383
375 Handle<Object> js_builtin = 384 Handle<Object> js_builtin =
376 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), 385 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
377 name); 386 name);
378 ASSERT(js_builtin->IsJSFunction()); 387 ASSERT(js_builtin->IsJSFunction());
379 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); 388 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
380 ScopedVector<Object**> argv(args.length() - 1); 389 ScopedVector<Object**> argv(args.length() - 1);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 467
459 // Set the length. 468 // Set the length.
460 array->set_length(Smi::FromInt(len - 1)); 469 array->set_length(Smi::FromInt(len - 1));
461 470
462 if (!top->IsTheHole()) { 471 if (!top->IsTheHole()) {
463 // Delete the top element. 472 // Delete the top element.
464 elms->set_the_hole(len - 1); 473 elms->set_the_hole(len - 1);
465 return top; 474 return top;
466 } 475 }
467 476
468 // Remember to check the prototype chain. 477 top = array->GetPrototype()->GetElement(len - 1);
469 JSFunction* array_function =
470 Top::context()->global_context()->array_function();
471 JSObject* prototype = JSObject::cast(array_function->prototype());
472 top = prototype->GetElement(len - 1);
473 478
474 return top; 479 return top;
475 } 480 }
476 481
477 482
478 BUILTIN(ArrayShift) { 483 BUILTIN(ArrayShift) {
479 Object* receiver = *args.receiver(); 484 Object* receiver = *args.receiver();
480 FixedArray* elms = NULL; 485 FixedArray* elms = NULL;
481 if (!IsJSArrayWithFastElements(receiver, &elms) 486 if (!IsFastElementMovingAllowed(receiver, &elms)) {
482 || !ArrayPrototypeHasNoElements()) {
483 return CallJsBuiltin("ArrayShift", args); 487 return CallJsBuiltin("ArrayShift", args);
484 } 488 }
485 JSArray* array = JSArray::cast(receiver); 489 JSArray* array = JSArray::cast(receiver);
486 ASSERT(array->HasFastElements()); 490 ASSERT(array->HasFastElements());
487 491
488 int len = Smi::cast(array->length())->value(); 492 int len = Smi::cast(array->length())->value();
489 if (len == 0) return Heap::undefined_value(); 493 if (len == 0) return Heap::undefined_value();
490 494
491 // Get first element 495 // Get first element
492 Object* first = elms->get(0); 496 Object* first = elms->get(0);
(...skipping 15 matching lines...) Expand all
508 // Set the length. 512 // Set the length.
509 array->set_length(Smi::FromInt(len - 1)); 513 array->set_length(Smi::FromInt(len - 1));
510 514
511 return first; 515 return first;
512 } 516 }
513 517
514 518
515 BUILTIN(ArrayUnshift) { 519 BUILTIN(ArrayUnshift) {
516 Object* receiver = *args.receiver(); 520 Object* receiver = *args.receiver();
517 FixedArray* elms = NULL; 521 FixedArray* elms = NULL;
518 if (!IsJSArrayWithFastElements(receiver, &elms) 522 if (!IsFastElementMovingAllowed(receiver, &elms)) {
519 || !ArrayPrototypeHasNoElements()) {
520 return CallJsBuiltin("ArrayUnshift", args); 523 return CallJsBuiltin("ArrayUnshift", args);
521 } 524 }
522 JSArray* array = JSArray::cast(receiver); 525 JSArray* array = JSArray::cast(receiver);
523 ASSERT(array->HasFastElements()); 526 ASSERT(array->HasFastElements());
524 527
525 int len = Smi::cast(array->length())->value(); 528 int len = Smi::cast(array->length())->value();
526 int to_add = args.length() - 1; 529 int to_add = args.length() - 1;
527 int new_length = len + to_add; 530 int new_length = len + to_add;
528 // Currently fixed arrays cannot grow too big, so 531 // Currently fixed arrays cannot grow too big, so
529 // we should never hit this case. 532 // we should never hit this case.
(...skipping 28 matching lines...) Expand all
558 561
559 // Set the length. 562 // Set the length.
560 array->set_length(Smi::FromInt(new_length)); 563 array->set_length(Smi::FromInt(new_length));
561 return Smi::FromInt(new_length); 564 return Smi::FromInt(new_length);
562 } 565 }
563 566
564 567
565 BUILTIN(ArraySlice) { 568 BUILTIN(ArraySlice) {
566 Object* receiver = *args.receiver(); 569 Object* receiver = *args.receiver();
567 FixedArray* elms = NULL; 570 FixedArray* elms = NULL;
568 if (!IsJSArrayWithFastElements(receiver, &elms) 571 if (!IsFastElementMovingAllowed(receiver, &elms)) {
569 || !ArrayPrototypeHasNoElements()) {
570 return CallJsBuiltin("ArraySlice", args); 572 return CallJsBuiltin("ArraySlice", args);
571 } 573 }
572 JSArray* array = JSArray::cast(receiver); 574 JSArray* array = JSArray::cast(receiver);
573 ASSERT(array->HasFastElements()); 575 ASSERT(array->HasFastElements());
574 576
575 int len = Smi::cast(array->length())->value(); 577 int len = Smi::cast(array->length())->value();
576 578
577 int n_arguments = args.length() - 1; 579 int n_arguments = args.length() - 1;
578 580
579 // Note carefully choosen defaults---if argument is missing, 581 // Note carefully choosen defaults---if argument is missing,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 630
629 // Set the length. 631 // Set the length.
630 result_array->set_length(Smi::FromInt(result_len)); 632 result_array->set_length(Smi::FromInt(result_len));
631 return result_array; 633 return result_array;
632 } 634 }
633 635
634 636
635 BUILTIN(ArraySplice) { 637 BUILTIN(ArraySplice) {
636 Object* receiver = *args.receiver(); 638 Object* receiver = *args.receiver();
637 FixedArray* elms = NULL; 639 FixedArray* elms = NULL;
638 if (!IsJSArrayWithFastElements(receiver, &elms) 640 if (!IsFastElementMovingAllowed(receiver, &elms)) {
639 || !ArrayPrototypeHasNoElements()) {
640 return CallJsBuiltin("ArraySplice", args); 641 return CallJsBuiltin("ArraySplice", args);
641 } 642 }
642 JSArray* array = JSArray::cast(receiver); 643 JSArray* array = JSArray::cast(receiver);
643 ASSERT(array->HasFastElements()); 644 ASSERT(array->HasFastElements());
644 645
645 int len = Smi::cast(array->length())->value(); 646 int len = Smi::cast(array->length())->value();
646 647
647 int n_arguments = args.length() - 1; 648 int n_arguments = args.length() - 1;
648 649
649 // SpiderMonkey and JSC return undefined in the case where no 650 // SpiderMonkey and JSC return undefined in the case where no
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 } 782 }
782 783
783 // Set the length. 784 // Set the length.
784 array->set_length(Smi::FromInt(new_length)); 785 array->set_length(Smi::FromInt(new_length));
785 786
786 return result_array; 787 return result_array;
787 } 788 }
788 789
789 790
790 BUILTIN(ArrayConcat) { 791 BUILTIN(ArrayConcat) {
791 if (!ArrayPrototypeHasNoElements()) { 792 Context* global_context = Top::context()->global_context();
793 JSObject* array_proto =
794 JSObject::cast(global_context->array_function()->prototype());
795 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
792 return CallJsBuiltin("ArrayConcat", args); 796 return CallJsBuiltin("ArrayConcat", args);
793 } 797 }
794 798
795 // Iterate through all the arguments performing checks 799 // Iterate through all the arguments performing checks
796 // and calculating total length. 800 // and calculating total length.
797 int n_arguments = args.length(); 801 int n_arguments = args.length();
798 int result_len = 0; 802 int result_len = 0;
799 for (int i = 0; i < n_arguments; i++) { 803 for (int i = 0; i < n_arguments; i++) {
800 Object* arg = args[i]; 804 Object* arg = args[i];
801 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()) { 805 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
806 || JSArray::cast(arg)->GetPrototype() != array_proto) {
802 return CallJsBuiltin("ArrayConcat", args); 807 return CallJsBuiltin("ArrayConcat", args);
803 } 808 }
804 809
805 int len = Smi::cast(JSArray::cast(arg)->length())->value(); 810 int len = Smi::cast(JSArray::cast(arg)->length())->value();
806 811
807 // We shouldn't overflow when adding another len. 812 // We shouldn't overflow when adding another len.
808 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 813 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
809 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 814 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
810 USE(kHalfOfMaxInt); 815 USE(kHalfOfMaxInt);
811 result_len += len; 816 result_len += len;
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after
1502 if (entry->contains(pc)) { 1507 if (entry->contains(pc)) {
1503 return names_[i]; 1508 return names_[i];
1504 } 1509 }
1505 } 1510 }
1506 } 1511 }
1507 return NULL; 1512 return NULL;
1508 } 1513 }
1509 1514
1510 1515
1511 } } // namespace v8::internal 1516 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | test/mjsunit/array-concat.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698