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