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

Side by Side Diff: src/builtins.cc

Issue 3144002: Copy-on-write arrays. (Closed)
Patch Set: Review fixes. Created 10 years, 4 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 | « src/arm/stub-cache-arm.cc ('k') | src/codegen.h » ('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 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 262 }
263 263
264 264
265 static void CopyElements(AssertNoAllocation* no_gc, 265 static void CopyElements(AssertNoAllocation* no_gc,
266 FixedArray* dst, 266 FixedArray* dst,
267 int dst_index, 267 int dst_index,
268 FixedArray* src, 268 FixedArray* src,
269 int src_index, 269 int src_index,
270 int len) { 270 int len) {
271 ASSERT(dst != src); // Use MoveElements instead. 271 ASSERT(dst != src); // Use MoveElements instead.
272 ASSERT(dst->map() != Heap::fixed_cow_array_map());
272 ASSERT(len > 0); 273 ASSERT(len > 0);
273 CopyWords(dst->data_start() + dst_index, 274 CopyWords(dst->data_start() + dst_index,
274 src->data_start() + src_index, 275 src->data_start() + src_index,
275 len); 276 len);
276 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); 277 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
277 if (mode == UPDATE_WRITE_BARRIER) { 278 if (mode == UPDATE_WRITE_BARRIER) {
278 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); 279 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
279 } 280 }
280 } 281 }
281 282
282 283
283 static void MoveElements(AssertNoAllocation* no_gc, 284 static void MoveElements(AssertNoAllocation* no_gc,
284 FixedArray* dst, 285 FixedArray* dst,
285 int dst_index, 286 int dst_index,
286 FixedArray* src, 287 FixedArray* src,
287 int src_index, 288 int src_index,
288 int len) { 289 int len) {
290 ASSERT(dst->map() != Heap::fixed_cow_array_map());
289 memmove(dst->data_start() + dst_index, 291 memmove(dst->data_start() + dst_index,
290 src->data_start() + src_index, 292 src->data_start() + src_index,
291 len * kPointerSize); 293 len * kPointerSize);
292 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); 294 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
293 if (mode == UPDATE_WRITE_BARRIER) { 295 if (mode == UPDATE_WRITE_BARRIER) {
294 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); 296 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
295 } 297 }
296 } 298 }
297 299
298 300
299 static void FillWithHoles(FixedArray* dst, int from, int to) { 301 static void FillWithHoles(FixedArray* dst, int from, int to) {
302 ASSERT(dst->map() != Heap::fixed_cow_array_map());
300 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from); 303 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
301 } 304 }
302 305
303 306
304 static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) { 307 static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
308 ASSERT(elms->map() != Heap::fixed_cow_array_map());
305 // For now this trick is only applied to fixed arrays in new space. 309 // For now this trick is only applied to fixed arrays in new space.
306 // In large object space the object's start must coincide with chunk 310 // In large object space the object's start must coincide with chunk
307 // and thus the trick is just not applicable. 311 // and thus the trick is just not applicable.
308 // In old space we do not use this trick to avoid dealing with 312 // In old space we do not use this trick to avoid dealing with
309 // region dirty marks. 313 // region dirty marks.
310 ASSERT(Heap::new_space()->Contains(elms)); 314 ASSERT(Heap::new_space()->Contains(elms));
311 315
312 STATIC_ASSERT(FixedArray::kMapOffset == 0); 316 STATIC_ASSERT(FixedArray::kMapOffset == 0);
313 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); 317 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
314 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); 318 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
(...skipping 26 matching lines...) Expand all
341 ASSERT(array_proto->elements() == Heap::empty_fixed_array()); 345 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
342 // Object.prototype 346 // Object.prototype
343 array_proto = JSObject::cast(array_proto->GetPrototype()); 347 array_proto = JSObject::cast(array_proto->GetPrototype());
344 if (array_proto != global_context->initial_object_prototype()) return false; 348 if (array_proto != global_context->initial_object_prototype()) return false;
345 if (array_proto->elements() != Heap::empty_fixed_array()) return false; 349 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
346 ASSERT(array_proto->GetPrototype()->IsNull()); 350 ASSERT(array_proto->GetPrototype()->IsNull());
347 return true; 351 return true;
348 } 352 }
349 353
350 354
351 static bool IsJSArrayWithFastElements(Object* receiver, 355 static Object* EnsureJSArrayWithWritableFastElements(Object* receiver) {
352 FixedArray** elements) { 356 if (!receiver->IsJSArray()) return NULL;
353 if (!receiver->IsJSArray()) { 357 JSArray* array = JSArray::cast(receiver);
354 return false; 358 HeapObject* elms = HeapObject::cast(array->elements());
359 if (elms->map() == Heap::fixed_array_map()) return elms;
360 if (elms->map() == Heap::fixed_cow_array_map()) {
361 return array->EnsureWritableFastElements();
355 } 362 }
356 363 return NULL;
357 JSArray* array = JSArray::cast(receiver);
358
359 HeapObject* elms = HeapObject::cast(array->elements());
360 if (elms->map() != Heap::fixed_array_map()) {
361 return false;
362 }
363
364 *elements = FixedArray::cast(elms);
365 return true;
366 } 364 }
367 365
368 366
369 static bool IsFastElementMovingAllowed(Object* receiver, 367 static bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
370 FixedArray** elements) {
371 if (!IsJSArrayWithFastElements(receiver, elements)) return false;
372
373 Context* global_context = Top::context()->global_context(); 368 Context* global_context = Top::context()->global_context();
374 JSObject* array_proto = 369 JSObject* array_proto =
375 JSObject::cast(global_context->array_function()->prototype()); 370 JSObject::cast(global_context->array_function()->prototype());
376 if (JSArray::cast(receiver)->GetPrototype() != array_proto) return false; 371 return receiver->GetPrototype() == array_proto &&
377 return ArrayPrototypeHasNoElements(global_context, array_proto); 372 ArrayPrototypeHasNoElements(global_context, array_proto);
378 } 373 }
379 374
380 375
381 static Object* CallJsBuiltin(const char* name, 376 static Object* CallJsBuiltin(const char* name,
382 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { 377 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
383 HandleScope handleScope; 378 HandleScope handleScope;
384 379
385 Handle<Object> js_builtin = 380 Handle<Object> js_builtin =
386 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), 381 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
387 name); 382 name);
(...skipping 10 matching lines...) Expand all
398 n_args, 393 n_args,
399 argv.start(), 394 argv.start(),
400 &pending_exception); 395 &pending_exception);
401 if (pending_exception) return Failure::Exception(); 396 if (pending_exception) return Failure::Exception();
402 return *result; 397 return *result;
403 } 398 }
404 399
405 400
406 BUILTIN(ArrayPush) { 401 BUILTIN(ArrayPush) {
407 Object* receiver = *args.receiver(); 402 Object* receiver = *args.receiver();
408 FixedArray* elms = NULL; 403 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
409 if (!IsJSArrayWithFastElements(receiver, &elms)) { 404 if (elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
410 return CallJsBuiltin("ArrayPush", args); 405 if (elms_obj->IsFailure()) return elms_obj;
411 } 406 FixedArray* elms = FixedArray::cast(elms_obj);
412 JSArray* array = JSArray::cast(receiver); 407 JSArray* array = JSArray::cast(receiver);
413 408
414 int len = Smi::cast(array->length())->value(); 409 int len = Smi::cast(array->length())->value();
415 int to_add = args.length() - 1; 410 int to_add = args.length() - 1;
416 if (to_add == 0) { 411 if (to_add == 0) {
417 return Smi::FromInt(len); 412 return Smi::FromInt(len);
418 } 413 }
419 // Currently fixed arrays cannot grow too big, so 414 // Currently fixed arrays cannot grow too big, so
420 // we should never hit this case. 415 // we should never hit this case.
421 ASSERT(to_add <= (Smi::kMaxValue - len)); 416 ASSERT(to_add <= (Smi::kMaxValue - len));
(...skipping 25 matching lines...) Expand all
447 } 442 }
448 443
449 // Set the length. 444 // Set the length.
450 array->set_length(Smi::FromInt(new_length)); 445 array->set_length(Smi::FromInt(new_length));
451 return Smi::FromInt(new_length); 446 return Smi::FromInt(new_length);
452 } 447 }
453 448
454 449
455 BUILTIN(ArrayPop) { 450 BUILTIN(ArrayPop) {
456 Object* receiver = *args.receiver(); 451 Object* receiver = *args.receiver();
457 FixedArray* elms = NULL; 452 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
458 if (!IsJSArrayWithFastElements(receiver, &elms)) { 453 if (elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
459 return CallJsBuiltin("ArrayPop", args); 454 if (elms_obj->IsFailure()) return elms_obj;
460 } 455 FixedArray* elms = FixedArray::cast(elms_obj);
461 JSArray* array = JSArray::cast(receiver); 456 JSArray* array = JSArray::cast(receiver);
462 457
463 int len = Smi::cast(array->length())->value(); 458 int len = Smi::cast(array->length())->value();
464 if (len == 0) return Heap::undefined_value(); 459 if (len == 0) return Heap::undefined_value();
465 460
466 // Get top element 461 // Get top element
467 Object* top = elms->get(len - 1); 462 Object* top = elms->get(len - 1);
468 463
469 // Set the length. 464 // Set the length.
470 array->set_length(Smi::FromInt(len - 1)); 465 array->set_length(Smi::FromInt(len - 1));
471 466
472 if (!top->IsTheHole()) { 467 if (!top->IsTheHole()) {
473 // Delete the top element. 468 // Delete the top element.
474 elms->set_the_hole(len - 1); 469 elms->set_the_hole(len - 1);
475 return top; 470 return top;
476 } 471 }
477 472
478 top = array->GetPrototype()->GetElement(len - 1); 473 top = array->GetPrototype()->GetElement(len - 1);
479 474
480 return top; 475 return top;
481 } 476 }
482 477
483 478
484 BUILTIN(ArrayShift) { 479 BUILTIN(ArrayShift) {
485 Object* receiver = *args.receiver(); 480 Object* receiver = *args.receiver();
486 FixedArray* elms = NULL; 481 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
487 if (!IsFastElementMovingAllowed(receiver, &elms)) { 482 if (elms_obj->IsFailure()) return elms_obj;
483 if (elms_obj == NULL ||
484 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
488 return CallJsBuiltin("ArrayShift", args); 485 return CallJsBuiltin("ArrayShift", args);
489 } 486 }
487 FixedArray* elms = FixedArray::cast(elms_obj);
490 JSArray* array = JSArray::cast(receiver); 488 JSArray* array = JSArray::cast(receiver);
491 ASSERT(array->HasFastElements()); 489 ASSERT(array->HasFastElements());
492 490
493 int len = Smi::cast(array->length())->value(); 491 int len = Smi::cast(array->length())->value();
494 if (len == 0) return Heap::undefined_value(); 492 if (len == 0) return Heap::undefined_value();
495 493
496 // Get first element 494 // Get first element
497 Object* first = elms->get(0); 495 Object* first = elms->get(0);
498 if (first->IsTheHole()) { 496 if (first->IsTheHole()) {
499 first = Heap::undefined_value(); 497 first = Heap::undefined_value();
(...skipping 12 matching lines...) Expand all
512 510
513 // Set the length. 511 // Set the length.
514 array->set_length(Smi::FromInt(len - 1)); 512 array->set_length(Smi::FromInt(len - 1));
515 513
516 return first; 514 return first;
517 } 515 }
518 516
519 517
520 BUILTIN(ArrayUnshift) { 518 BUILTIN(ArrayUnshift) {
521 Object* receiver = *args.receiver(); 519 Object* receiver = *args.receiver();
522 FixedArray* elms = NULL; 520 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
523 if (!IsFastElementMovingAllowed(receiver, &elms)) { 521 if (elms_obj->IsFailure()) return elms_obj;
522 if (elms_obj == NULL ||
523 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
524 return CallJsBuiltin("ArrayUnshift", args); 524 return CallJsBuiltin("ArrayUnshift", args);
525 } 525 }
526 FixedArray* elms = FixedArray::cast(elms_obj);
526 JSArray* array = JSArray::cast(receiver); 527 JSArray* array = JSArray::cast(receiver);
527 ASSERT(array->HasFastElements()); 528 ASSERT(array->HasFastElements());
528 529
529 int len = Smi::cast(array->length())->value(); 530 int len = Smi::cast(array->length())->value();
530 int to_add = args.length() - 1; 531 int to_add = args.length() - 1;
531 int new_length = len + to_add; 532 int new_length = len + to_add;
532 // Currently fixed arrays cannot grow too big, so 533 // Currently fixed arrays cannot grow too big, so
533 // we should never hit this case. 534 // we should never hit this case.
534 ASSERT(to_add <= (Smi::kMaxValue - len)); 535 ASSERT(to_add <= (Smi::kMaxValue - len));
535 536
(...skipping 25 matching lines...) Expand all
561 } 562 }
562 563
563 // Set the length. 564 // Set the length.
564 array->set_length(Smi::FromInt(new_length)); 565 array->set_length(Smi::FromInt(new_length));
565 return Smi::FromInt(new_length); 566 return Smi::FromInt(new_length);
566 } 567 }
567 568
568 569
569 BUILTIN(ArraySlice) { 570 BUILTIN(ArraySlice) {
570 Object* receiver = *args.receiver(); 571 Object* receiver = *args.receiver();
571 FixedArray* elms = NULL; 572 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
572 if (!IsFastElementMovingAllowed(receiver, &elms)) { 573 if (elms_obj->IsFailure()) return elms_obj;
574 if (elms_obj == NULL ||
575 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
573 return CallJsBuiltin("ArraySlice", args); 576 return CallJsBuiltin("ArraySlice", args);
574 } 577 }
578 FixedArray* elms = FixedArray::cast(elms_obj);
575 JSArray* array = JSArray::cast(receiver); 579 JSArray* array = JSArray::cast(receiver);
576 ASSERT(array->HasFastElements()); 580 ASSERT(array->HasFastElements());
577 581
578 int len = Smi::cast(array->length())->value(); 582 int len = Smi::cast(array->length())->value();
579 583
580 int n_arguments = args.length() - 1; 584 int n_arguments = args.length() - 1;
581 585
582 // Note carefully choosen defaults---if argument is missing, 586 // Note carefully choosen defaults---if argument is missing,
583 // it's undefined which gets converted to 0 for relative_start 587 // it's undefined which gets converted to 0 for relative_start
584 // and to len for relative_end. 588 // and to len for relative_end.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 result_array->set_elements(result_elms); 634 result_array->set_elements(result_elms);
631 635
632 // Set the length. 636 // Set the length.
633 result_array->set_length(Smi::FromInt(result_len)); 637 result_array->set_length(Smi::FromInt(result_len));
634 return result_array; 638 return result_array;
635 } 639 }
636 640
637 641
638 BUILTIN(ArraySplice) { 642 BUILTIN(ArraySplice) {
639 Object* receiver = *args.receiver(); 643 Object* receiver = *args.receiver();
640 FixedArray* elms = NULL; 644 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
641 if (!IsFastElementMovingAllowed(receiver, &elms)) { 645 if (elms_obj->IsFailure()) return elms_obj;
646 if (elms_obj == NULL ||
647 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
642 return CallJsBuiltin("ArraySplice", args); 648 return CallJsBuiltin("ArraySplice", args);
643 } 649 }
650 FixedArray* elms = FixedArray::cast(elms_obj);
644 JSArray* array = JSArray::cast(receiver); 651 JSArray* array = JSArray::cast(receiver);
645 ASSERT(array->HasFastElements()); 652 ASSERT(array->HasFastElements());
646 653
647 int len = Smi::cast(array->length())->value(); 654 int len = Smi::cast(array->length())->value();
648 655
649 int n_arguments = args.length() - 1; 656 int n_arguments = args.length() - 1;
650 657
651 // SpiderMonkey and JSC return undefined in the case where no 658 // SpiderMonkey and JSC return undefined in the case where no
652 // arguments are given instead of using the implicit undefined 659 // arguments are given instead of using the implicit undefined
653 // arguments. This does not follow ECMA-262, but we do the same for 660 // arguments. This does not follow ECMA-262, but we do the same for
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after
1520 if (entry->contains(pc)) { 1527 if (entry->contains(pc)) {
1521 return names_[i]; 1528 return names_[i];
1522 } 1529 }
1523 } 1530 }
1524 } 1531 }
1525 return NULL; 1532 return NULL;
1526 } 1533 }
1527 1534
1528 1535
1529 } } // namespace v8::internal 1536 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/codegen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698