| 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 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 } | 235 } |
| 236 | 236 |
| 237 // Set length and elements on the array. | 237 // Set length and elements on the array. |
| 238 array->set_elements(FixedArray::cast(obj)); | 238 array->set_elements(FixedArray::cast(obj)); |
| 239 array->set_length(len); | 239 array->set_length(len); |
| 240 | 240 |
| 241 return array; | 241 return array; |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 static Object* AllocateJSArray() { |
| 246 JSFunction* array_function = |
| 247 Top::context()->global_context()->array_function(); |
| 248 Object* result = Heap::AllocateJSObject(array_function); |
| 249 if (result->IsFailure()) return result; |
| 250 return result; |
| 251 } |
| 252 |
| 253 |
| 254 static Object* AllocateEmptyJSArray() { |
| 255 Object* result = AllocateJSArray(); |
| 256 if (result->IsFailure()) return result; |
| 257 JSArray* result_array = JSArray::cast(result); |
| 258 result_array->set_length(Smi::FromInt(0)); |
| 259 result_array->set_elements(Heap::empty_fixed_array()); |
| 260 return result_array; |
| 261 } |
| 262 |
| 263 |
| 264 static void CopyElements(AssertNoAllocation* no_gc, |
| 265 FixedArray* dst, |
| 266 int dst_index, |
| 267 FixedArray* src, |
| 268 int src_index, |
| 269 int len) { |
| 270 ASSERT(dst != src); // Use MoveElements instead. |
| 271 memcpy(dst->data_start() + dst_index, |
| 272 src->data_start() + src_index, |
| 273 len * kPointerSize); |
| 274 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); |
| 275 if (mode == UPDATE_WRITE_BARRIER) { |
| 276 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); |
| 277 } |
| 278 } |
| 279 |
| 280 |
| 281 static void MoveElements(AssertNoAllocation* no_gc, |
| 282 FixedArray* dst, |
| 283 int dst_index, |
| 284 FixedArray* src, |
| 285 int src_index, |
| 286 int len) { |
| 287 memmove(dst->data_start() + dst_index, |
| 288 src->data_start() + src_index, |
| 289 len * kPointerSize); |
| 290 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); |
| 291 if (mode == UPDATE_WRITE_BARRIER) { |
| 292 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); |
| 293 } |
| 294 } |
| 295 |
| 296 |
| 297 static void FillWithHoles(FixedArray* dst, int from, int to) { |
| 298 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from); |
| 299 } |
| 300 |
| 301 |
| 302 static bool ArrayPrototypeHasNoElements() { |
| 303 // This method depends on non writability of Object and Array prototype |
| 304 // fields. |
| 305 Context* global_context = Top::context()->global_context(); |
| 306 // Array.prototype |
| 307 JSObject* proto = |
| 308 JSObject::cast(global_context->array_function()->prototype()); |
| 309 if (proto->elements() != Heap::empty_fixed_array()) return false; |
| 310 // Hidden prototype |
| 311 proto = JSObject::cast(proto->GetPrototype()); |
| 312 ASSERT(proto->elements() == Heap::empty_fixed_array()); |
| 313 // Object.prototype |
| 314 proto = JSObject::cast(proto->GetPrototype()); |
| 315 if (proto != global_context->initial_object_prototype()) return false; |
| 316 if (proto->elements() != Heap::empty_fixed_array()) return false; |
| 317 ASSERT(proto->GetPrototype()->IsNull()); |
| 318 return true; |
| 319 } |
| 320 |
| 321 |
| 322 static Object* CallJsBuiltin(const char* name, |
| 323 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
| 324 HandleScope handleScope; |
| 325 |
| 326 Handle<Object> js_builtin = |
| 327 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), |
| 328 name); |
| 329 ASSERT(js_builtin->IsJSFunction()); |
| 330 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); |
| 331 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1)); |
| 332 int n_args = args.length() - 1; |
| 333 for (int i = 0; i < n_args; i++) { |
| 334 argv[i] = &args[i + 1]; |
| 335 } |
| 336 bool pending_exception = false; |
| 337 Handle<Object> result = Execution::Call(function, |
| 338 args.receiver(), |
| 339 n_args, |
| 340 argv.start(), |
| 341 &pending_exception); |
| 342 argv.Dispose(); |
| 343 if (pending_exception) return Failure::Exception(); |
| 344 return *result; |
| 345 } |
| 346 |
| 347 |
| 245 BUILTIN(ArrayPush) { | 348 BUILTIN(ArrayPush) { |
| 246 JSArray* array = JSArray::cast(*args.receiver()); | 349 JSArray* array = JSArray::cast(*args.receiver()); |
| 247 ASSERT(array->HasFastElements()); | 350 ASSERT(array->HasFastElements()); |
| 248 | 351 |
| 249 int len = Smi::cast(array->length())->value(); | 352 int len = Smi::cast(array->length())->value(); |
| 250 int to_add = args.length() - 1; | 353 int to_add = args.length() - 1; |
| 251 if (to_add == 0) { | 354 if (to_add == 0) { |
| 252 return Smi::FromInt(len); | 355 return Smi::FromInt(len); |
| 253 } | 356 } |
| 254 // Currently fixed arrays cannot grow too big, so | 357 // Currently fixed arrays cannot grow too big, so |
| 255 // we should never hit this case. | 358 // we should never hit this case. |
| 256 ASSERT(to_add <= (Smi::kMaxValue - len)); | 359 ASSERT(to_add <= (Smi::kMaxValue - len)); |
| 257 | 360 |
| 258 int new_length = len + to_add; | 361 int new_length = len + to_add; |
| 259 FixedArray* elms = FixedArray::cast(array->elements()); | 362 FixedArray* elms = FixedArray::cast(array->elements()); |
| 260 | 363 |
| 261 if (new_length > elms->length()) { | 364 if (new_length > elms->length()) { |
| 262 // New backing storage is needed. | 365 // New backing storage is needed. |
| 263 int capacity = new_length + (new_length >> 1) + 16; | 366 int capacity = new_length + (new_length >> 1) + 16; |
| 264 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | 367 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); |
| 265 if (obj->IsFailure()) return obj; | 368 if (obj->IsFailure()) return obj; |
| 369 FixedArray* new_elms = FixedArray::cast(obj); |
| 266 | 370 |
| 267 AssertNoAllocation no_gc; | 371 AssertNoAllocation no_gc; |
| 268 FixedArray* new_elms = FixedArray::cast(obj); | 372 CopyElements(&no_gc, new_elms, 0, elms, 0, len); |
| 269 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc); | 373 FillWithHoles(new_elms, new_length, capacity); |
| 270 // Fill out the new array with old elements. | 374 |
| 271 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode); | |
| 272 elms = new_elms; | 375 elms = new_elms; |
| 273 array->set_elements(elms); | 376 array->set_elements(elms); |
| 274 } | 377 } |
| 275 | 378 |
| 379 // Add the provided values. |
| 276 AssertNoAllocation no_gc; | 380 AssertNoAllocation no_gc; |
| 277 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | 381 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
| 278 | |
| 279 // Add the provided values. | |
| 280 for (int index = 0; index < to_add; index++) { | 382 for (int index = 0; index < to_add; index++) { |
| 281 elms->set(index + len, args[index + 1], mode); | 383 elms->set(index + len, args[index + 1], mode); |
| 282 } | 384 } |
| 283 | 385 |
| 284 // Set the length. | 386 // Set the length. |
| 285 array->set_length(Smi::FromInt(new_length)); | 387 array->set_length(Smi::FromInt(new_length)); |
| 286 return Smi::FromInt(new_length); | 388 return Smi::FromInt(new_length); |
| 287 } | 389 } |
| 288 | 390 |
| 289 | 391 |
| 290 BUILTIN(ArrayPop) { | 392 BUILTIN(ArrayPop) { |
| 291 JSArray* array = JSArray::cast(*args.receiver()); | 393 JSArray* array = JSArray::cast(*args.receiver()); |
| 292 ASSERT(array->HasFastElements()); | 394 ASSERT(array->HasFastElements()); |
| 293 Object* undefined = Heap::undefined_value(); | |
| 294 | 395 |
| 295 int len = Smi::cast(array->length())->value(); | 396 int len = Smi::cast(array->length())->value(); |
| 296 if (len == 0) return undefined; | 397 if (len == 0) return Heap::undefined_value(); |
| 297 | 398 |
| 298 // Get top element | 399 // Get top element |
| 299 FixedArray* elms = FixedArray::cast(array->elements()); | 400 FixedArray* elms = FixedArray::cast(array->elements()); |
| 300 Object* top = elms->get(len - 1); | 401 Object* top = elms->get(len - 1); |
| 301 | 402 |
| 302 // Set the length. | 403 // Set the length. |
| 303 array->set_length(Smi::FromInt(len - 1)); | 404 array->set_length(Smi::FromInt(len - 1)); |
| 304 | 405 |
| 305 if (!top->IsTheHole()) { | 406 if (!top->IsTheHole()) { |
| 306 // Delete the top element. | 407 // Delete the top element. |
| 307 elms->set_the_hole(len - 1); | 408 elms->set_the_hole(len - 1); |
| 308 return top; | 409 return top; |
| 309 } | 410 } |
| 310 | 411 |
| 311 // Remember to check the prototype chain. | 412 // Remember to check the prototype chain. |
| 312 JSFunction* array_function = | 413 JSFunction* array_function = |
| 313 Top::context()->global_context()->array_function(); | 414 Top::context()->global_context()->array_function(); |
| 314 JSObject* prototype = JSObject::cast(array_function->prototype()); | 415 JSObject* prototype = JSObject::cast(array_function->prototype()); |
| 315 top = prototype->GetElement(len - 1); | 416 top = prototype->GetElement(len - 1); |
| 316 | 417 |
| 317 return top; | 418 return top; |
| 318 } | 419 } |
| 319 | 420 |
| 320 | 421 |
| 321 static Object* GetElementToMove(uint32_t index, | |
| 322 FixedArray* elms, | |
| 323 JSObject* prototype) { | |
| 324 Object* e = elms->get(index); | |
| 325 if (e->IsTheHole() && prototype->HasElement(index)) { | |
| 326 e = prototype->GetElement(index); | |
| 327 } | |
| 328 return e; | |
| 329 } | |
| 330 | |
| 331 | |
| 332 BUILTIN(ArrayShift) { | 422 BUILTIN(ArrayShift) { |
| 423 if (!ArrayPrototypeHasNoElements()) { |
| 424 return CallJsBuiltin("ArrayShift", args); |
| 425 } |
| 426 |
| 333 JSArray* array = JSArray::cast(*args.receiver()); | 427 JSArray* array = JSArray::cast(*args.receiver()); |
| 334 ASSERT(array->HasFastElements()); | 428 ASSERT(array->HasFastElements()); |
| 335 | 429 |
| 336 int len = Smi::cast(array->length())->value(); | 430 int len = Smi::cast(array->length())->value(); |
| 337 if (len == 0) return Heap::undefined_value(); | 431 if (len == 0) return Heap::undefined_value(); |
| 338 | 432 |
| 339 // Fetch the prototype. | |
| 340 JSFunction* array_function = | |
| 341 Top::context()->global_context()->array_function(); | |
| 342 JSObject* prototype = JSObject::cast(array_function->prototype()); | |
| 343 | |
| 344 FixedArray* elms = FixedArray::cast(array->elements()); | 433 FixedArray* elms = FixedArray::cast(array->elements()); |
| 345 | 434 |
| 346 // Get first element | 435 // Get first element |
| 347 Object* first = elms->get(0); | 436 Object* first = elms->get(0); |
| 348 if (first->IsTheHole()) { | 437 if (first->IsTheHole()) { |
| 349 first = prototype->GetElement(0); | 438 first = Heap::undefined_value(); |
| 350 } | 439 } |
| 351 | 440 |
| 352 // Shift the elements. | 441 // Shift the elements. |
| 353 for (int i = 0; i < len - 1; i++) { | 442 AssertNoAllocation no_gc; |
| 354 elms->set(i, GetElementToMove(i + 1, elms, prototype)); | 443 MoveElements(&no_gc, elms, 0, elms, 1, len - 1); |
| 355 } | |
| 356 elms->set(len - 1, Heap::the_hole_value()); | 444 elms->set(len - 1, Heap::the_hole_value()); |
| 357 | 445 |
| 358 // Set the length. | 446 // Set the length. |
| 359 array->set_length(Smi::FromInt(len - 1)); | 447 array->set_length(Smi::FromInt(len - 1)); |
| 360 | 448 |
| 361 return first; | 449 return first; |
| 362 } | 450 } |
| 363 | 451 |
| 364 | 452 |
| 365 BUILTIN(ArrayUnshift) { | 453 BUILTIN(ArrayUnshift) { |
| 454 if (!ArrayPrototypeHasNoElements()) { |
| 455 return CallJsBuiltin("ArrayUnshift", args); |
| 456 } |
| 457 |
| 366 JSArray* array = JSArray::cast(*args.receiver()); | 458 JSArray* array = JSArray::cast(*args.receiver()); |
| 367 ASSERT(array->HasFastElements()); | 459 ASSERT(array->HasFastElements()); |
| 368 | 460 |
| 369 int len = Smi::cast(array->length())->value(); | 461 int len = Smi::cast(array->length())->value(); |
| 370 int to_add = args.length() - 1; | 462 int to_add = args.length() - 1; |
| 371 // Note that we cannot quit early if to_add == 0 as | 463 // Note that we cannot quit early if to_add == 0 as |
| 372 // values should be lifted from prototype into | 464 // values should be lifted from prototype into |
| 373 // the array. | 465 // the array. |
| 374 | 466 |
| 375 int new_length = len + to_add; | 467 int new_length = len + to_add; |
| 376 // Currently fixed arrays cannot grow too big, so | 468 // Currently fixed arrays cannot grow too big, so |
| 377 // we should never hit this case. | 469 // we should never hit this case. |
| 378 ASSERT(to_add <= (Smi::kMaxValue - len)); | 470 ASSERT(to_add <= (Smi::kMaxValue - len)); |
| 379 | 471 |
| 380 FixedArray* elms = FixedArray::cast(array->elements()); | 472 FixedArray* elms = FixedArray::cast(array->elements()); |
| 381 | 473 |
| 382 // Fetch the prototype. | |
| 383 JSFunction* array_function = | |
| 384 Top::context()->global_context()->array_function(); | |
| 385 JSObject* prototype = JSObject::cast(array_function->prototype()); | |
| 386 | |
| 387 if (new_length > elms->length()) { | 474 if (new_length > elms->length()) { |
| 388 // New backing storage is needed. | 475 // New backing storage is needed. |
| 389 int capacity = new_length + (new_length >> 1) + 16; | 476 int capacity = new_length + (new_length >> 1) + 16; |
| 390 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | 477 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); |
| 391 if (obj->IsFailure()) return obj; | 478 if (obj->IsFailure()) return obj; |
| 479 FixedArray* new_elms = FixedArray::cast(obj); |
| 392 | 480 |
| 393 AssertNoAllocation no_gc; | 481 AssertNoAllocation no_gc; |
| 394 FixedArray* new_elms = FixedArray::cast(obj); | 482 CopyElements(&no_gc, new_elms, to_add, elms, 0, len); |
| 395 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc); | 483 FillWithHoles(new_elms, new_length, capacity); |
| 396 // Fill out the new array with old elements. | |
| 397 for (int i = 0; i < len; i++) | |
| 398 new_elms->set(to_add + i, | |
| 399 GetElementToMove(i, elms, prototype), | |
| 400 mode); | |
| 401 | 484 |
| 402 elms = new_elms; | 485 elms = new_elms; |
| 403 array->set_elements(elms); | 486 array->set_elements(elms); |
| 404 } else { | 487 } else { |
| 405 AssertNoAllocation no_gc; | 488 AssertNoAllocation no_gc; |
| 406 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | 489 MoveElements(&no_gc, elms, to_add, elms, 0, len); |
| 407 | |
| 408 // Move elements to the right | |
| 409 for (int i = 0; i < len; i++) { | |
| 410 elms->set(new_length - i - 1, | |
| 411 GetElementToMove(len - i - 1, elms, prototype), | |
| 412 mode); | |
| 413 } | |
| 414 } | 490 } |
| 415 | 491 |
| 416 // Add the provided values. | 492 // Add the provided values. |
| 417 AssertNoAllocation no_gc; | 493 AssertNoAllocation no_gc; |
| 418 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); | 494 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
| 419 for (int i = 0; i < to_add; i++) { | 495 for (int i = 0; i < to_add; i++) { |
| 420 elms->set(i, args[i + 1], mode); | 496 elms->set(i, args[i + 1], mode); |
| 421 } | 497 } |
| 422 | 498 |
| 423 // Set the length. | 499 // Set the length. |
| 424 array->set_length(Smi::FromInt(new_length)); | 500 array->set_length(Smi::FromInt(new_length)); |
| 425 return Smi::FromInt(new_length); | 501 return Smi::FromInt(new_length); |
| 426 } | 502 } |
| 427 | 503 |
| 428 | 504 |
| 429 static Object* CallJsBuiltin(const char* name, | |
| 430 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | |
| 431 HandleScope handleScope; | |
| 432 | |
| 433 Handle<Object> js_builtin = | |
| 434 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), | |
| 435 name); | |
| 436 ASSERT(js_builtin->IsJSFunction()); | |
| 437 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); | |
| 438 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1)); | |
| 439 int n_args = args.length() - 1; | |
| 440 for (int i = 0; i < n_args; i++) { | |
| 441 argv[i] = &args[i + 1]; | |
| 442 } | |
| 443 bool pending_exception = false; | |
| 444 Handle<Object> result = Execution::Call(function, | |
| 445 args.receiver(), | |
| 446 n_args, | |
| 447 argv.start(), | |
| 448 &pending_exception); | |
| 449 if (pending_exception) return Failure::Exception(); | |
| 450 return *result; | |
| 451 } | |
| 452 | |
| 453 | |
| 454 BUILTIN(ArraySlice) { | 505 BUILTIN(ArraySlice) { |
| 506 if (!ArrayPrototypeHasNoElements()) { |
| 507 return CallJsBuiltin("ArraySlice", args); |
| 508 } |
| 509 |
| 455 JSArray* array = JSArray::cast(*args.receiver()); | 510 JSArray* array = JSArray::cast(*args.receiver()); |
| 456 ASSERT(array->HasFastElements()); | 511 ASSERT(array->HasFastElements()); |
| 457 | 512 |
| 458 int len = Smi::cast(array->length())->value(); | 513 int len = Smi::cast(array->length())->value(); |
| 459 | 514 |
| 460 int n_arguments = args.length() - 1; | 515 int n_arguments = args.length() - 1; |
| 461 | 516 |
| 462 // Note carefully choosen defaults---if argument is missing, | 517 // Note carefully choosen defaults---if argument is missing, |
| 463 // it's undefined which gets converted to 0 for relativeStart | 518 // it's undefined which gets converted to 0 for relative_start |
| 464 // and to len for relativeEnd. | 519 // and to len for relative_end. |
| 465 int relativeStart = 0; | 520 int relative_start = 0; |
| 466 int relativeEnd = len; | 521 int relative_end = len; |
| 467 if (n_arguments > 0) { | 522 if (n_arguments > 0) { |
| 468 Object* arg1 = args[1]; | 523 Object* arg1 = args[1]; |
| 469 if (arg1->IsSmi()) { | 524 if (arg1->IsSmi()) { |
| 470 relativeStart = Smi::cast(arg1)->value(); | 525 relative_start = Smi::cast(arg1)->value(); |
| 471 } else if (!arg1->IsUndefined()) { | 526 } else if (!arg1->IsUndefined()) { |
| 472 return CallJsBuiltin("ArraySlice", args); | 527 return CallJsBuiltin("ArraySlice", args); |
| 473 } | 528 } |
| 474 if (n_arguments > 1) { | 529 if (n_arguments > 1) { |
| 475 Object* arg2 = args[2]; | 530 Object* arg2 = args[2]; |
| 476 if (arg2->IsSmi()) { | 531 if (arg2->IsSmi()) { |
| 477 relativeEnd = Smi::cast(arg2)->value(); | 532 relative_end = Smi::cast(arg2)->value(); |
| 478 } else if (!arg2->IsUndefined()) { | 533 } else if (!arg2->IsUndefined()) { |
| 479 return CallJsBuiltin("ArraySlice", args); | 534 return CallJsBuiltin("ArraySlice", args); |
| 480 } | 535 } |
| 481 } | 536 } |
| 482 } | 537 } |
| 483 | 538 |
| 484 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. | 539 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
| 485 int k = (relativeStart < 0) ? Max(len + relativeStart, 0) | 540 int k = (relative_start < 0) ? Max(len + relative_start, 0) |
| 486 : Min(relativeStart, len); | 541 : Min(relative_start, len); |
| 487 | 542 |
| 488 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. | 543 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
| 489 int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0) | 544 int final = (relative_end < 0) ? Max(len + relative_end, 0) |
| 490 : Min(relativeEnd, len); | 545 : Min(relative_end, len); |
| 491 | 546 |
| 492 // Calculate the length of result array. | 547 // Calculate the length of result array. |
| 493 int result_len = final - k; | 548 int result_len = final - k; |
| 494 if (result_len < 0) { | 549 if (result_len <= 0) { |
| 495 result_len = 0; | 550 return AllocateEmptyJSArray(); |
| 496 } | 551 } |
| 497 | 552 |
| 498 JSFunction* array_function = | 553 Object* result = AllocateJSArray(); |
| 499 Top::context()->global_context()->array_function(); | |
| 500 Object* result = Heap::AllocateJSObject(array_function); | |
| 501 if (result->IsFailure()) return result; | 554 if (result->IsFailure()) return result; |
| 502 JSArray* result_array = JSArray::cast(result); | 555 JSArray* result_array = JSArray::cast(result); |
| 503 | 556 |
| 504 result = Heap::AllocateFixedArrayWithHoles(result_len); | 557 result = Heap::AllocateUninitializedFixedArray(result_len); |
| 505 if (result->IsFailure()) return result; | 558 if (result->IsFailure()) return result; |
| 506 FixedArray* result_elms = FixedArray::cast(result); | 559 FixedArray* result_elms = FixedArray::cast(result); |
| 507 | 560 |
| 508 FixedArray* elms = FixedArray::cast(array->elements()); | 561 FixedArray* elms = FixedArray::cast(array->elements()); |
| 509 | 562 |
| 510 // Fetch the prototype. | |
| 511 JSObject* prototype = JSObject::cast(array_function->prototype()); | |
| 512 | |
| 513 AssertNoAllocation no_gc; | 563 AssertNoAllocation no_gc; |
| 514 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc); | 564 CopyElements(&no_gc, result_elms, 0, elms, k, result_len); |
| 515 | |
| 516 // Fill newly created array. | |
| 517 for (int i = 0; i < result_len; i++) { | |
| 518 result_elms->set(i, | |
| 519 GetElementToMove(k + i, elms, prototype), | |
| 520 mode); | |
| 521 } | |
| 522 | 565 |
| 523 // Set elements. | 566 // Set elements. |
| 524 result_array->set_elements(result_elms); | 567 result_array->set_elements(result_elms); |
| 525 | 568 |
| 526 // Set the length. | 569 // Set the length. |
| 527 result_array->set_length(Smi::FromInt(result_len)); | 570 result_array->set_length(Smi::FromInt(result_len)); |
| 528 return result_array; | 571 return result_array; |
| 529 } | 572 } |
| 530 | 573 |
| 531 | 574 |
| 532 BUILTIN(ArraySplice) { | 575 BUILTIN(ArraySplice) { |
| 576 if (!ArrayPrototypeHasNoElements()) { |
| 577 return CallJsBuiltin("ArraySplice", args); |
| 578 } |
| 579 |
| 533 JSArray* array = JSArray::cast(*args.receiver()); | 580 JSArray* array = JSArray::cast(*args.receiver()); |
| 534 ASSERT(array->HasFastElements()); | 581 ASSERT(array->HasFastElements()); |
| 535 | 582 |
| 536 int len = Smi::cast(array->length())->value(); | 583 int len = Smi::cast(array->length())->value(); |
| 537 | 584 |
| 538 int n_arguments = args.length() - 1; | 585 int n_arguments = args.length() - 1; |
| 539 | 586 |
| 540 // SpiderMonkey and JSC return undefined in the case where no | 587 // SpiderMonkey and JSC return undefined in the case where no |
| 541 // arguments are given instead of using the implicit undefined | 588 // arguments are given instead of using the implicit undefined |
| 542 // arguments. This does not follow ECMA-262, but we do the same for | 589 // arguments. This does not follow ECMA-262, but we do the same for |
| 543 // compatibility. | 590 // compatibility. |
| 544 // TraceMonkey follows ECMA-262 though. | 591 // TraceMonkey follows ECMA-262 though. |
| 545 if (n_arguments == 0) { | 592 if (n_arguments == 0) { |
| 546 return Heap::undefined_value(); | 593 return Heap::undefined_value(); |
| 547 } | 594 } |
| 548 | 595 |
| 549 int relativeStart = 0; | 596 int relative_start = 0; |
| 550 Object* arg1 = args[1]; | 597 Object* arg1 = args[1]; |
| 551 if (arg1->IsSmi()) { | 598 if (arg1->IsSmi()) { |
| 552 relativeStart = Smi::cast(arg1)->value(); | 599 relative_start = Smi::cast(arg1)->value(); |
| 553 } else if (!arg1->IsUndefined()) { | 600 } else if (!arg1->IsUndefined()) { |
| 554 return CallJsBuiltin("ArraySplice", args); | 601 return CallJsBuiltin("ArraySplice", args); |
| 555 } | 602 } |
| 556 int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0) | 603 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
| 557 : Min(relativeStart, len); | 604 : Min(relative_start, len); |
| 558 | 605 |
| 559 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is | 606 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| 560 // given differently from when an undefined delete count is given. | 607 // given differently from when an undefined delete count is given. |
| 561 // This does not follow ECMA-262, but we do the same for | 608 // This does not follow ECMA-262, but we do the same for |
| 562 // compatibility. | 609 // compatibility. |
| 563 int deleteCount = len; | 610 int delete_count = len; |
| 564 if (n_arguments > 1) { | 611 if (n_arguments > 1) { |
| 565 Object* arg2 = args[2]; | 612 Object* arg2 = args[2]; |
| 566 if (arg2->IsSmi()) { | 613 if (arg2->IsSmi()) { |
| 567 deleteCount = Smi::cast(arg2)->value(); | 614 delete_count = Smi::cast(arg2)->value(); |
| 568 } else { | 615 } else { |
| 569 return CallJsBuiltin("ArraySplice", args); | 616 return CallJsBuiltin("ArraySplice", args); |
| 570 } | 617 } |
| 571 } | 618 } |
| 572 int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart); | 619 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start); |
| 573 | |
| 574 JSFunction* array_function = | |
| 575 Top::context()->global_context()->array_function(); | |
| 576 | |
| 577 // Allocate result array. | |
| 578 Object* result = Heap::AllocateJSObject(array_function); | |
| 579 if (result->IsFailure()) return result; | |
| 580 JSArray* result_array = JSArray::cast(result); | |
| 581 | |
| 582 result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount); | |
| 583 if (result->IsFailure()) return result; | |
| 584 FixedArray* result_elms = FixedArray::cast(result); | |
| 585 | 620 |
| 586 FixedArray* elms = FixedArray::cast(array->elements()); | 621 FixedArray* elms = FixedArray::cast(array->elements()); |
| 587 | 622 |
| 588 // Fetch the prototype. | 623 JSArray* result_array = NULL; |
| 589 JSObject* prototype = JSObject::cast(array_function->prototype()); | 624 if (actual_delete_count == 0) { |
| 625 Object* result = AllocateEmptyJSArray(); |
| 626 if (result->IsFailure()) return result; |
| 627 result_array = JSArray::cast(result); |
| 628 } else { |
| 629 // Allocate result array. |
| 630 Object* result = AllocateJSArray(); |
| 631 if (result->IsFailure()) return result; |
| 632 result_array = JSArray::cast(result); |
| 590 | 633 |
| 591 AssertNoAllocation no_gc; | 634 result = Heap::AllocateUninitializedFixedArray(actual_delete_count); |
| 592 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc); | 635 if (result->IsFailure()) return result; |
| 636 FixedArray* result_elms = FixedArray::cast(result); |
| 593 | 637 |
| 594 // Fill newly created array. | 638 AssertNoAllocation no_gc; |
| 595 for (int k = 0; k < actualDeleteCount; k++) { | 639 // Fill newly created array. |
| 596 result_elms->set(k, | 640 CopyElements(&no_gc, |
| 597 GetElementToMove(actualStart + k, elms, prototype), | 641 result_elms, 0, |
| 598 mode); | 642 elms, actual_start, |
| 643 actual_delete_count); |
| 644 |
| 645 // Set elements. |
| 646 result_array->set_elements(result_elms); |
| 647 |
| 648 // Set the length. |
| 649 result_array->set_length(Smi::FromInt(actual_delete_count)); |
| 599 } | 650 } |
| 600 | 651 |
| 601 // Set elements. | 652 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; |
| 602 result_array->set_elements(result_elms); | |
| 603 | 653 |
| 604 // Set the length. | 654 int new_length = len - actual_delete_count + item_count; |
| 605 result_array->set_length(Smi::FromInt(actualDeleteCount)); | |
| 606 | 655 |
| 607 int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0; | 656 if (item_count < actual_delete_count) { |
| 608 | |
| 609 int new_length = len - actualDeleteCount + itemCount; | |
| 610 | |
| 611 mode = elms->GetWriteBarrierMode(no_gc); | |
| 612 if (itemCount < actualDeleteCount) { | |
| 613 // Shrink the array. | 657 // Shrink the array. |
| 614 for (int k = actualStart; k < (len - actualDeleteCount); k++) { | 658 AssertNoAllocation no_gc; |
| 615 elms->set(k + itemCount, | 659 MoveElements(&no_gc, |
| 616 GetElementToMove(k + actualDeleteCount, elms, prototype), | 660 elms, actual_start + item_count, |
| 617 mode); | 661 elms, actual_start + actual_delete_count, |
| 618 } | 662 (len - actual_delete_count - actual_start)); |
| 619 | 663 FillWithHoles(elms, new_length, len); |
| 620 for (int k = len; k > new_length; k--) { | 664 } else if (item_count > actual_delete_count) { |
| 621 elms->set(k - 1, Heap::the_hole_value()); | |
| 622 } | |
| 623 } else if (itemCount > actualDeleteCount) { | |
| 624 // Currently fixed arrays cannot grow too big, so | 665 // Currently fixed arrays cannot grow too big, so |
| 625 // we should never hit this case. | 666 // we should never hit this case. |
| 626 ASSERT((itemCount - actualDeleteCount) <= (Smi::kMaxValue - len)); | 667 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); |
| 627 | |
| 628 FixedArray* source_elms = elms; | |
| 629 | 668 |
| 630 // Check if array need to grow. | 669 // Check if array need to grow. |
| 631 if (new_length > elms->length()) { | 670 if (new_length > elms->length()) { |
| 632 // New backing storage is needed. | 671 // New backing storage is needed. |
| 633 int capacity = new_length + (new_length >> 1) + 16; | 672 int capacity = new_length + (new_length >> 1) + 16; |
| 634 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | 673 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); |
| 635 if (obj->IsFailure()) return obj; | 674 if (obj->IsFailure()) return obj; |
| 675 FixedArray* new_elms = FixedArray::cast(obj); |
| 636 | 676 |
| 637 FixedArray* new_elms = FixedArray::cast(obj); | 677 AssertNoAllocation no_gc; |
| 638 mode = new_elms->GetWriteBarrierMode(no_gc); | 678 // Copy the part before actual_start as is. |
| 679 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start); |
| 680 CopyElements(&no_gc, |
| 681 new_elms, actual_start + item_count, |
| 682 elms, actual_start + actual_delete_count, |
| 683 (len - actual_delete_count - actual_start)); |
| 684 FillWithHoles(new_elms, new_length, capacity); |
| 639 | 685 |
| 640 // Copy the part before actualStart as is. | |
| 641 for (int k = 0; k < actualStart; k++) { | |
| 642 new_elms->set(k, elms->get(k), mode); | |
| 643 } | |
| 644 | |
| 645 source_elms = elms; | |
| 646 elms = new_elms; | 686 elms = new_elms; |
| 647 array->set_elements(elms); | 687 array->set_elements(elms); |
| 648 } | 688 } else { |
| 649 | 689 AssertNoAllocation no_gc; |
| 650 for (int k = len - actualDeleteCount; k > actualStart; k--) { | 690 MoveElements(&no_gc, |
| 651 elms->set(k + itemCount - 1, | 691 elms, actual_start + item_count, |
| 652 GetElementToMove(k + actualDeleteCount - 1, | 692 elms, actual_start + actual_delete_count, |
| 653 source_elms, | 693 (len - actual_delete_count - actual_start)); |
| 654 prototype), | |
| 655 mode); | |
| 656 } | 694 } |
| 657 } | 695 } |
| 658 | 696 |
| 659 for (int k = actualStart; k < actualStart + itemCount; k++) { | 697 AssertNoAllocation no_gc; |
| 660 elms->set(k, args[3 + k - actualStart], mode); | 698 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
| 699 for (int k = actual_start; k < actual_start + item_count; k++) { |
| 700 elms->set(k, args[3 + k - actual_start], mode); |
| 661 } | 701 } |
| 662 | 702 |
| 663 // Set the length. | 703 // Set the length. |
| 664 array->set_length(Smi::FromInt(new_length)); | 704 array->set_length(Smi::FromInt(new_length)); |
| 665 | 705 |
| 666 return result_array; | 706 return result_array; |
| 667 } | 707 } |
| 668 | 708 |
| 669 | 709 |
| 670 // ----------------------------------------------------------------------------- | 710 // ----------------------------------------------------------------------------- |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1311 if (entry->contains(pc)) { | 1351 if (entry->contains(pc)) { |
| 1312 return names_[i]; | 1352 return names_[i]; |
| 1313 } | 1353 } |
| 1314 } | 1354 } |
| 1315 } | 1355 } |
| 1316 return NULL; | 1356 return NULL; |
| 1317 } | 1357 } |
| 1318 | 1358 |
| 1319 | 1359 |
| 1320 } } // namespace v8::internal | 1360 } } // namespace v8::internal |
| OLD | NEW |