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

Side by Side Diff: src/builtins.cc

Issue 844006: Merge changes up to V8 version 2.1.3 into the partial snapshots (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/bootstrapper.cc ('k') | src/code-stubs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
OLDNEW
« no previous file with comments | « src/bootstrapper.cc ('k') | src/code-stubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698