| 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 |