OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |