| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/builtins.h" | 5 #include "src/builtins.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" |
| 9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
| 10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 } | 276 } |
| 277 } | 277 } |
| 278 if (target_kind != origin_kind) { | 278 if (target_kind != origin_kind) { |
| 279 JSObject::TransitionElementsKind(array, target_kind); | 279 JSObject::TransitionElementsKind(array, target_kind); |
| 280 return handle(array->elements(), isolate); | 280 return handle(array->elements(), isolate); |
| 281 } | 281 } |
| 282 return elms; | 282 return elms; |
| 283 } | 283 } |
| 284 | 284 |
| 285 | 285 |
| 286 MUST_USE_RESULT static Object* CallJsBuiltin( | 286 MUST_USE_RESULT static Object* CallJsIntrinsic( |
| 287 Isolate* isolate, | 287 Isolate* isolate, Handle<JSFunction> function, |
| 288 const char* name, | |
| 289 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | 288 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
| 290 HandleScope handleScope(isolate); | 289 HandleScope handleScope(isolate); |
| 291 | |
| 292 Handle<Object> js_builtin = Object::GetProperty( | |
| 293 isolate, | |
| 294 handle(isolate->native_context()->builtins(), isolate), | |
| 295 name).ToHandleChecked(); | |
| 296 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin); | |
| 297 int argc = args.length() - 1; | 290 int argc = args.length() - 1; |
| 298 ScopedVector<Handle<Object> > argv(argc); | 291 ScopedVector<Handle<Object> > argv(argc); |
| 299 for (int i = 0; i < argc; ++i) { | 292 for (int i = 0; i < argc; ++i) { |
| 300 argv[i] = args.at<Object>(i + 1); | 293 argv[i] = args.at<Object>(i + 1); |
| 301 } | 294 } |
| 302 Handle<Object> result; | 295 Handle<Object> result; |
| 303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 296 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 304 isolate, result, | 297 isolate, result, |
| 305 Execution::Call(isolate, | 298 Execution::Call(isolate, |
| 306 function, | 299 function, |
| 307 args.receiver(), | 300 args.receiver(), |
| 308 argc, | 301 argc, |
| 309 argv.start())); | 302 argv.start())); |
| 310 return *result; | 303 return *result; |
| 311 } | 304 } |
| 312 | 305 |
| 313 | 306 |
| 314 BUILTIN(ArrayPush) { | 307 BUILTIN(ArrayPush) { |
| 315 HandleScope scope(isolate); | 308 HandleScope scope(isolate); |
| 316 Handle<Object> receiver = args.receiver(); | 309 Handle<Object> receiver = args.receiver(); |
| 317 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 310 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 318 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); | 311 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
| 319 Handle<FixedArrayBase> elms_obj; | 312 Handle<FixedArrayBase> elms_obj; |
| 320 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 313 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
| 321 return CallJsBuiltin(isolate, "$arrayPush", args); | 314 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
| 322 } | 315 } |
| 323 // Fast Elements Path | 316 // Fast Elements Path |
| 324 int push_size = args.length() - 1; | 317 int push_size = args.length() - 1; |
| 325 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 318 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 326 int len = Smi::cast(array->length())->value(); | 319 int len = Smi::cast(array->length())->value(); |
| 327 if (push_size == 0) { | 320 if (push_size == 0) { |
| 328 return Smi::FromInt(len); | 321 return Smi::FromInt(len); |
| 329 } | 322 } |
| 330 if (push_size > 0 && | 323 if (push_size > 0 && |
| 331 JSArray::WouldChangeReadOnlyLength(array, len + push_size)) { | 324 JSArray::WouldChangeReadOnlyLength(array, len + push_size)) { |
| 332 return CallJsBuiltin(isolate, "$arrayPush", args); | 325 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
| 333 } | 326 } |
| 334 DCHECK(!array->map()->is_observed()); | 327 DCHECK(!array->map()->is_observed()); |
| 335 ElementsAccessor* accessor = array->GetElementsAccessor(); | 328 ElementsAccessor* accessor = array->GetElementsAccessor(); |
| 336 int new_length = accessor->Push(array, elms_obj, &args[1], push_size, | 329 int new_length = accessor->Push(array, elms_obj, &args[1], push_size, |
| 337 ElementsAccessor::kDirectionReverse); | 330 ElementsAccessor::kDirectionReverse); |
| 338 return Smi::FromInt(new_length); | 331 return Smi::FromInt(new_length); |
| 339 } | 332 } |
| 340 | 333 |
| 341 | 334 |
| 342 BUILTIN(ArrayPop) { | 335 BUILTIN(ArrayPop) { |
| 343 HandleScope scope(isolate); | 336 HandleScope scope(isolate); |
| 344 Handle<Object> receiver = args.receiver(); | 337 Handle<Object> receiver = args.receiver(); |
| 345 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 338 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 346 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 339 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); |
| 347 Handle<FixedArrayBase> elms_obj; | 340 Handle<FixedArrayBase> elms_obj; |
| 348 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 341 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
| 349 return CallJsBuiltin(isolate, "$arrayPop", args); | 342 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
| 350 } | 343 } |
| 351 | 344 |
| 352 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 345 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 353 DCHECK(!array->map()->is_observed()); | 346 DCHECK(!array->map()->is_observed()); |
| 354 | 347 |
| 355 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); | 348 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); |
| 356 if (len == 0) return isolate->heap()->undefined_value(); | 349 if (len == 0) return isolate->heap()->undefined_value(); |
| 357 | 350 |
| 358 if (JSArray::HasReadOnlyLength(array)) { | 351 if (JSArray::HasReadOnlyLength(array)) { |
| 359 return CallJsBuiltin(isolate, "$arrayPop", args); | 352 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
| 360 } | 353 } |
| 361 | 354 |
| 362 uint32_t new_length = len - 1; | 355 uint32_t new_length = len - 1; |
| 363 Handle<Object> element; | 356 Handle<Object> element; |
| 364 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 357 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 365 isolate, element, Object::GetElement(isolate, array, new_length)); | 358 isolate, element, Object::GetElement(isolate, array, new_length)); |
| 366 | 359 |
| 367 JSArray::SetLength(array, new_length); | 360 JSArray::SetLength(array, new_length); |
| 368 return *element; | 361 return *element; |
| 369 } | 362 } |
| 370 | 363 |
| 371 | 364 |
| 372 BUILTIN(ArrayShift) { | 365 BUILTIN(ArrayShift) { |
| 373 HandleScope scope(isolate); | 366 HandleScope scope(isolate); |
| 374 Heap* heap = isolate->heap(); | 367 Heap* heap = isolate->heap(); |
| 375 Handle<Object> receiver = args.receiver(); | 368 Handle<Object> receiver = args.receiver(); |
| 376 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 369 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 377 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 370 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); |
| 378 Handle<FixedArrayBase> elms_obj; | 371 Handle<FixedArrayBase> elms_obj; |
| 379 if (!maybe_elms_obj.ToHandle(&elms_obj) || | 372 if (!maybe_elms_obj.ToHandle(&elms_obj) || |
| 380 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { | 373 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { |
| 381 return CallJsBuiltin(isolate, "$arrayShift", args); | 374 return CallJsIntrinsic(isolate, isolate->array_shift(), args); |
| 382 } | 375 } |
| 383 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 376 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 384 DCHECK(!array->map()->is_observed()); | 377 DCHECK(!array->map()->is_observed()); |
| 385 | 378 |
| 386 int len = Smi::cast(array->length())->value(); | 379 int len = Smi::cast(array->length())->value(); |
| 387 if (len == 0) return heap->undefined_value(); | 380 if (len == 0) return heap->undefined_value(); |
| 388 | 381 |
| 389 if (JSArray::HasReadOnlyLength(array)) { | 382 if (JSArray::HasReadOnlyLength(array)) { |
| 390 return CallJsBuiltin(isolate, "$arrayShift", args); | 383 return CallJsIntrinsic(isolate, isolate->array_shift(), args); |
| 391 } | 384 } |
| 392 | 385 |
| 393 // Get first element | 386 // Get first element |
| 394 Handle<Object> first; | 387 Handle<Object> first; |
| 395 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first, | 388 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first, |
| 396 Object::GetElement(isolate, array, 0)); | 389 Object::GetElement(isolate, array, 0)); |
| 397 | 390 |
| 398 if (heap->CanMoveObjectStart(*elms_obj)) { | 391 if (heap->CanMoveObjectStart(*elms_obj)) { |
| 399 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1)); | 392 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1)); |
| 400 } else { | 393 } else { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 418 } | 411 } |
| 419 | 412 |
| 420 | 413 |
| 421 BUILTIN(ArrayUnshift) { | 414 BUILTIN(ArrayUnshift) { |
| 422 HandleScope scope(isolate); | 415 HandleScope scope(isolate); |
| 423 Handle<Object> receiver = args.receiver(); | 416 Handle<Object> receiver = args.receiver(); |
| 424 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 417 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 425 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); | 418 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
| 426 Handle<FixedArrayBase> elms_obj; | 419 Handle<FixedArrayBase> elms_obj; |
| 427 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 420 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
| 428 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 421 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
| 429 } | 422 } |
| 430 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 423 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 431 DCHECK(!array->map()->is_observed()); | 424 DCHECK(!array->map()->is_observed()); |
| 432 if (!array->HasFastSmiOrObjectElements()) { | 425 if (!array->HasFastSmiOrObjectElements()) { |
| 433 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 426 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
| 434 } | 427 } |
| 435 int len = Smi::cast(array->length())->value(); | 428 int len = Smi::cast(array->length())->value(); |
| 436 int to_add = args.length() - 1; | 429 int to_add = args.length() - 1; |
| 437 int new_length = len + to_add; | 430 int new_length = len + to_add; |
| 438 // Currently fixed arrays cannot grow too big, so | 431 // Currently fixed arrays cannot grow too big, so |
| 439 // we should never hit this case. | 432 // we should never hit this case. |
| 440 DCHECK(to_add <= (Smi::kMaxValue - len)); | 433 DCHECK(to_add <= (Smi::kMaxValue - len)); |
| 441 | 434 |
| 442 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { | 435 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { |
| 443 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 436 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
| 444 } | 437 } |
| 445 | 438 |
| 446 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | 439 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| 447 | 440 |
| 448 if (new_length > elms->length()) { | 441 if (new_length > elms->length()) { |
| 449 // New backing storage is needed. | 442 // New backing storage is needed. |
| 450 int capacity = new_length + (new_length >> 1) + 16; | 443 int capacity = new_length + (new_length >> 1) + 16; |
| 451 Handle<FixedArray> new_elms = | 444 Handle<FixedArray> new_elms = |
| 452 isolate->factory()->NewUninitializedFixedArray(capacity); | 445 isolate->factory()->NewUninitializedFixedArray(capacity); |
| 453 | 446 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 483 Handle<Object> receiver = args.receiver(); | 476 Handle<Object> receiver = args.receiver(); |
| 484 int len = -1; | 477 int len = -1; |
| 485 int relative_start = 0; | 478 int relative_start = 0; |
| 486 int relative_end = 0; | 479 int relative_end = 0; |
| 487 { | 480 { |
| 488 DisallowHeapAllocation no_gc; | 481 DisallowHeapAllocation no_gc; |
| 489 if (receiver->IsJSArray()) { | 482 if (receiver->IsJSArray()) { |
| 490 JSArray* array = JSArray::cast(*receiver); | 483 JSArray* array = JSArray::cast(*receiver); |
| 491 if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { | 484 if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { |
| 492 AllowHeapAllocation allow_allocation; | 485 AllowHeapAllocation allow_allocation; |
| 493 return CallJsBuiltin(isolate, "$arraySlice", args); | 486 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 494 } | 487 } |
| 495 | 488 |
| 496 if (!array->HasFastElements()) { | 489 if (!array->HasFastElements()) { |
| 497 AllowHeapAllocation allow_allocation; | 490 AllowHeapAllocation allow_allocation; |
| 498 return CallJsBuiltin(isolate, "$arraySlice", args); | 491 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 499 } | 492 } |
| 500 | 493 |
| 501 len = Smi::cast(array->length())->value(); | 494 len = Smi::cast(array->length())->value(); |
| 502 } else { | 495 } else { |
| 503 // Array.slice(arguments, ...) is quite a common idiom (notably more | 496 // Array.slice(arguments, ...) is quite a common idiom (notably more |
| 504 // than 50% of invocations in Web apps). Treat it in C++ as well. | 497 // than 50% of invocations in Web apps). Treat it in C++ as well. |
| 505 Map* arguments_map = | 498 Map* arguments_map = |
| 506 isolate->context()->native_context()->sloppy_arguments_map(); | 499 isolate->context()->native_context()->sloppy_arguments_map(); |
| 507 | 500 |
| 508 bool is_arguments_object_with_fast_elements = | 501 bool is_arguments_object_with_fast_elements = |
| 509 receiver->IsJSObject() && | 502 receiver->IsJSObject() && |
| 510 JSObject::cast(*receiver)->map() == arguments_map; | 503 JSObject::cast(*receiver)->map() == arguments_map; |
| 511 if (!is_arguments_object_with_fast_elements) { | 504 if (!is_arguments_object_with_fast_elements) { |
| 512 AllowHeapAllocation allow_allocation; | 505 AllowHeapAllocation allow_allocation; |
| 513 return CallJsBuiltin(isolate, "$arraySlice", args); | 506 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 514 } | 507 } |
| 515 JSObject* object = JSObject::cast(*receiver); | 508 JSObject* object = JSObject::cast(*receiver); |
| 516 | 509 |
| 517 if (!object->HasFastElements()) { | 510 if (!object->HasFastElements()) { |
| 518 AllowHeapAllocation allow_allocation; | 511 AllowHeapAllocation allow_allocation; |
| 519 return CallJsBuiltin(isolate, "$arraySlice", args); | 512 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 520 } | 513 } |
| 521 | 514 |
| 522 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); | 515 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); |
| 523 if (!len_obj->IsSmi()) { | 516 if (!len_obj->IsSmi()) { |
| 524 AllowHeapAllocation allow_allocation; | 517 AllowHeapAllocation allow_allocation; |
| 525 return CallJsBuiltin(isolate, "$arraySlice", args); | 518 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 526 } | 519 } |
| 527 len = Smi::cast(len_obj)->value(); | 520 len = Smi::cast(len_obj)->value(); |
| 528 if (len > object->elements()->length()) { | 521 if (len > object->elements()->length()) { |
| 529 AllowHeapAllocation allow_allocation; | 522 AllowHeapAllocation allow_allocation; |
| 530 return CallJsBuiltin(isolate, "$arraySlice", args); | 523 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 531 } | 524 } |
| 532 } | 525 } |
| 533 | 526 |
| 534 DCHECK(len >= 0); | 527 DCHECK(len >= 0); |
| 535 int n_arguments = args.length() - 1; | 528 int n_arguments = args.length() - 1; |
| 536 | 529 |
| 537 // Note carefully choosen defaults---if argument is missing, | 530 // Note carefully choosen defaults---if argument is missing, |
| 538 // it's undefined which gets converted to 0 for relative_start | 531 // it's undefined which gets converted to 0 for relative_start |
| 539 // and to len for relative_end. | 532 // and to len for relative_end. |
| 540 relative_start = 0; | 533 relative_start = 0; |
| 541 relative_end = len; | 534 relative_end = len; |
| 542 if (n_arguments > 0) { | 535 if (n_arguments > 0) { |
| 543 Object* arg1 = args[1]; | 536 Object* arg1 = args[1]; |
| 544 if (arg1->IsSmi()) { | 537 if (arg1->IsSmi()) { |
| 545 relative_start = Smi::cast(arg1)->value(); | 538 relative_start = Smi::cast(arg1)->value(); |
| 546 } else if (arg1->IsHeapNumber()) { | 539 } else if (arg1->IsHeapNumber()) { |
| 547 double start = HeapNumber::cast(arg1)->value(); | 540 double start = HeapNumber::cast(arg1)->value(); |
| 548 if (start < kMinInt || start > kMaxInt) { | 541 if (start < kMinInt || start > kMaxInt) { |
| 549 AllowHeapAllocation allow_allocation; | 542 AllowHeapAllocation allow_allocation; |
| 550 return CallJsBuiltin(isolate, "$arraySlice", args); | 543 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 551 } | 544 } |
| 552 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | 545 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
| 553 } else if (!arg1->IsUndefined()) { | 546 } else if (!arg1->IsUndefined()) { |
| 554 AllowHeapAllocation allow_allocation; | 547 AllowHeapAllocation allow_allocation; |
| 555 return CallJsBuiltin(isolate, "$arraySlice", args); | 548 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 556 } | 549 } |
| 557 if (n_arguments > 1) { | 550 if (n_arguments > 1) { |
| 558 Object* arg2 = args[2]; | 551 Object* arg2 = args[2]; |
| 559 if (arg2->IsSmi()) { | 552 if (arg2->IsSmi()) { |
| 560 relative_end = Smi::cast(arg2)->value(); | 553 relative_end = Smi::cast(arg2)->value(); |
| 561 } else if (arg2->IsHeapNumber()) { | 554 } else if (arg2->IsHeapNumber()) { |
| 562 double end = HeapNumber::cast(arg2)->value(); | 555 double end = HeapNumber::cast(arg2)->value(); |
| 563 if (end < kMinInt || end > kMaxInt) { | 556 if (end < kMinInt || end > kMaxInt) { |
| 564 AllowHeapAllocation allow_allocation; | 557 AllowHeapAllocation allow_allocation; |
| 565 return CallJsBuiltin(isolate, "$arraySlice", args); | 558 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 566 } | 559 } |
| 567 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); | 560 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); |
| 568 } else if (!arg2->IsUndefined()) { | 561 } else if (!arg2->IsUndefined()) { |
| 569 AllowHeapAllocation allow_allocation; | 562 AllowHeapAllocation allow_allocation; |
| 570 return CallJsBuiltin(isolate, "$arraySlice", args); | 563 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 571 } | 564 } |
| 572 } | 565 } |
| 573 } | 566 } |
| 574 } | 567 } |
| 575 | 568 |
| 576 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. | 569 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
| 577 int k = (relative_start < 0) ? Max(len + relative_start, 0) | 570 int k = (relative_start < 0) ? Max(len + relative_start, 0) |
| 578 : Min(relative_start, len); | 571 : Min(relative_start, len); |
| 579 | 572 |
| 580 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. | 573 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 595 for (int i = k; i < final; i++) { | 588 for (int i = k; i < final; i++) { |
| 596 if (!accessor->HasElement(object, i, elms)) { | 589 if (!accessor->HasElement(object, i, elms)) { |
| 597 packed = false; | 590 packed = false; |
| 598 break; | 591 break; |
| 599 } | 592 } |
| 600 } | 593 } |
| 601 if (packed) { | 594 if (packed) { |
| 602 kind = GetPackedElementsKind(kind); | 595 kind = GetPackedElementsKind(kind); |
| 603 } else if (!receiver->IsJSArray()) { | 596 } else if (!receiver->IsJSArray()) { |
| 604 AllowHeapAllocation allow_allocation; | 597 AllowHeapAllocation allow_allocation; |
| 605 return CallJsBuiltin(isolate, "$arraySlice", args); | 598 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 606 } | 599 } |
| 607 } | 600 } |
| 608 | 601 |
| 609 Handle<JSArray> result_array = | 602 Handle<JSArray> result_array = |
| 610 isolate->factory()->NewJSArray(kind, result_len, result_len); | 603 isolate->factory()->NewJSArray(kind, result_len, result_len); |
| 611 | 604 |
| 612 DisallowHeapAllocation no_gc; | 605 DisallowHeapAllocation no_gc; |
| 613 if (result_len == 0) return *result_array; | 606 if (result_len == 0) return *result_array; |
| 614 | 607 |
| 615 ElementsAccessor* accessor = object->GetElementsAccessor(); | 608 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 616 accessor->CopyElements( | 609 accessor->CopyElements( |
| 617 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); | 610 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); |
| 618 return *result_array; | 611 return *result_array; |
| 619 } | 612 } |
| 620 | 613 |
| 621 | 614 |
| 622 BUILTIN(ArraySplice) { | 615 BUILTIN(ArraySplice) { |
| 623 HandleScope scope(isolate); | 616 HandleScope scope(isolate); |
| 624 Heap* heap = isolate->heap(); | 617 Heap* heap = isolate->heap(); |
| 625 Handle<Object> receiver = args.receiver(); | 618 Handle<Object> receiver = args.receiver(); |
| 626 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 619 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 627 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 620 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
| 628 Handle<FixedArrayBase> elms_obj; | 621 Handle<FixedArrayBase> elms_obj; |
| 629 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 622 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
| 630 return CallJsBuiltin(isolate, "$arraySplice", args); | 623 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 631 } | 624 } |
| 632 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 625 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 633 DCHECK(!array->map()->is_observed()); | 626 DCHECK(!array->map()->is_observed()); |
| 634 | 627 |
| 635 int len = Smi::cast(array->length())->value(); | 628 int len = Smi::cast(array->length())->value(); |
| 636 | 629 |
| 637 int n_arguments = args.length() - 1; | 630 int n_arguments = args.length() - 1; |
| 638 | 631 |
| 639 int relative_start = 0; | 632 int relative_start = 0; |
| 640 if (n_arguments > 0) { | 633 if (n_arguments > 0) { |
| 641 DisallowHeapAllocation no_gc; | 634 DisallowHeapAllocation no_gc; |
| 642 Object* arg1 = args[1]; | 635 Object* arg1 = args[1]; |
| 643 if (arg1->IsSmi()) { | 636 if (arg1->IsSmi()) { |
| 644 relative_start = Smi::cast(arg1)->value(); | 637 relative_start = Smi::cast(arg1)->value(); |
| 645 } else if (arg1->IsHeapNumber()) { | 638 } else if (arg1->IsHeapNumber()) { |
| 646 double start = HeapNumber::cast(arg1)->value(); | 639 double start = HeapNumber::cast(arg1)->value(); |
| 647 if (start < kMinInt || start > kMaxInt) { | 640 if (start < kMinInt || start > kMaxInt) { |
| 648 AllowHeapAllocation allow_allocation; | 641 AllowHeapAllocation allow_allocation; |
| 649 return CallJsBuiltin(isolate, "$arraySplice", args); | 642 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 650 } | 643 } |
| 651 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | 644 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
| 652 } else if (!arg1->IsUndefined()) { | 645 } else if (!arg1->IsUndefined()) { |
| 653 AllowHeapAllocation allow_allocation; | 646 AllowHeapAllocation allow_allocation; |
| 654 return CallJsBuiltin(isolate, "$arraySplice", args); | 647 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 655 } | 648 } |
| 656 } | 649 } |
| 657 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) | 650 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
| 658 : Min(relative_start, len); | 651 : Min(relative_start, len); |
| 659 | 652 |
| 660 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is | 653 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| 661 // given as a request to delete all the elements from the start. | 654 // given as a request to delete all the elements from the start. |
| 662 // And it differs from the case of undefined delete count. | 655 // And it differs from the case of undefined delete count. |
| 663 // This does not follow ECMA-262, but we do the same for | 656 // This does not follow ECMA-262, but we do the same for |
| 664 // compatibility. | 657 // compatibility. |
| 665 int actual_delete_count; | 658 int actual_delete_count; |
| 666 if (n_arguments == 1) { | 659 if (n_arguments == 1) { |
| 667 DCHECK(len - actual_start >= 0); | 660 DCHECK(len - actual_start >= 0); |
| 668 actual_delete_count = len - actual_start; | 661 actual_delete_count = len - actual_start; |
| 669 } else { | 662 } else { |
| 670 int value = 0; // ToInteger(undefined) == 0 | 663 int value = 0; // ToInteger(undefined) == 0 |
| 671 if (n_arguments > 1) { | 664 if (n_arguments > 1) { |
| 672 DisallowHeapAllocation no_gc; | 665 DisallowHeapAllocation no_gc; |
| 673 Object* arg2 = args[2]; | 666 Object* arg2 = args[2]; |
| 674 if (arg2->IsSmi()) { | 667 if (arg2->IsSmi()) { |
| 675 value = Smi::cast(arg2)->value(); | 668 value = Smi::cast(arg2)->value(); |
| 676 } else { | 669 } else { |
| 677 AllowHeapAllocation allow_allocation; | 670 AllowHeapAllocation allow_allocation; |
| 678 return CallJsBuiltin(isolate, "$arraySplice", args); | 671 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 679 } | 672 } |
| 680 } | 673 } |
| 681 actual_delete_count = Min(Max(value, 0), len - actual_start); | 674 actual_delete_count = Min(Max(value, 0), len - actual_start); |
| 682 } | 675 } |
| 683 | 676 |
| 684 ElementsKind elements_kind = array->GetElementsKind(); | 677 ElementsKind elements_kind = array->GetElementsKind(); |
| 685 | 678 |
| 686 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; | 679 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; |
| 687 int new_length = len - actual_delete_count + item_count; | 680 int new_length = len - actual_delete_count + item_count; |
| 688 | 681 |
| 689 // For double mode we do not support changing the length. | 682 // For double mode we do not support changing the length. |
| 690 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { | 683 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { |
| 691 return CallJsBuiltin(isolate, "$arraySplice", args); | 684 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 692 } | 685 } |
| 693 | 686 |
| 694 if (new_length != len && JSArray::HasReadOnlyLength(array)) { | 687 if (new_length != len && JSArray::HasReadOnlyLength(array)) { |
| 695 AllowHeapAllocation allow_allocation; | 688 AllowHeapAllocation allow_allocation; |
| 696 return CallJsBuiltin(isolate, "$arraySplice", args); | 689 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 697 } | 690 } |
| 698 | 691 |
| 699 if (new_length == 0) { | 692 if (new_length == 0) { |
| 700 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( | 693 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( |
| 701 elms_obj, elements_kind, actual_delete_count); | 694 elms_obj, elements_kind, actual_delete_count); |
| 702 array->set_elements(heap->empty_fixed_array()); | 695 array->set_elements(heap->empty_fixed_array()); |
| 703 array->set_length(Smi::FromInt(0)); | 696 array->set_length(Smi::FromInt(0)); |
| 704 return *result; | 697 return *result; |
| 705 } | 698 } |
| 706 | 699 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 ElementsKind elements_kind = GetInitialFastElementsKind(); | 839 ElementsKind elements_kind = GetInitialFastElementsKind(); |
| 847 bool has_double = false; | 840 bool has_double = false; |
| 848 { | 841 { |
| 849 DisallowHeapAllocation no_gc; | 842 DisallowHeapAllocation no_gc; |
| 850 Context* native_context = isolate->context()->native_context(); | 843 Context* native_context = isolate->context()->native_context(); |
| 851 Object* array_proto = native_context->array_function()->prototype(); | 844 Object* array_proto = native_context->array_function()->prototype(); |
| 852 PrototypeIterator iter(isolate, array_proto, | 845 PrototypeIterator iter(isolate, array_proto, |
| 853 PrototypeIterator::START_AT_RECEIVER); | 846 PrototypeIterator::START_AT_RECEIVER); |
| 854 if (!ArrayPrototypeHasNoElements(&iter)) { | 847 if (!ArrayPrototypeHasNoElements(&iter)) { |
| 855 AllowHeapAllocation allow_allocation; | 848 AllowHeapAllocation allow_allocation; |
| 856 return CallJsBuiltin(isolate, "$arrayConcat", args); | 849 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
| 857 } | 850 } |
| 858 | 851 |
| 859 // Iterate through all the arguments performing checks | 852 // Iterate through all the arguments performing checks |
| 860 // and calculating total length. | 853 // and calculating total length. |
| 861 bool is_holey = false; | 854 bool is_holey = false; |
| 862 for (int i = 0; i < n_arguments; i++) { | 855 for (int i = 0; i < n_arguments; i++) { |
| 863 Object* arg = args[i]; | 856 Object* arg = args[i]; |
| 864 PrototypeIterator iter(isolate, arg); | 857 PrototypeIterator iter(isolate, arg); |
| 865 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || | 858 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || |
| 866 iter.GetCurrent() != array_proto) { | 859 iter.GetCurrent() != array_proto) { |
| 867 AllowHeapAllocation allow_allocation; | 860 AllowHeapAllocation allow_allocation; |
| 868 return CallJsBuiltin(isolate, "$arrayConcat", args); | 861 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
| 869 } | 862 } |
| 870 int len = Smi::cast(JSArray::cast(arg)->length())->value(); | 863 int len = Smi::cast(JSArray::cast(arg)->length())->value(); |
| 871 | 864 |
| 872 // We shouldn't overflow when adding another len. | 865 // We shouldn't overflow when adding another len. |
| 873 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 866 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
| 874 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 867 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
| 875 USE(kHalfOfMaxInt); | 868 USE(kHalfOfMaxInt); |
| 876 result_len += len; | 869 result_len += len; |
| 877 DCHECK(result_len >= 0); | 870 DCHECK(result_len >= 0); |
| 878 | 871 |
| 879 if (result_len > FixedDoubleArray::kMaxLength) { | 872 if (result_len > FixedDoubleArray::kMaxLength) { |
| 880 AllowHeapAllocation allow_allocation; | 873 AllowHeapAllocation allow_allocation; |
| 881 return CallJsBuiltin(isolate, "$arrayConcat", args); | 874 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
| 882 } | 875 } |
| 883 | 876 |
| 884 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); | 877 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); |
| 885 has_double = has_double || IsFastDoubleElementsKind(arg_kind); | 878 has_double = has_double || IsFastDoubleElementsKind(arg_kind); |
| 886 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); | 879 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); |
| 887 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { | 880 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { |
| 888 elements_kind = arg_kind; | 881 elements_kind = arg_kind; |
| 889 } | 882 } |
| 890 } | 883 } |
| 891 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); | 884 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1534 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1527 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
| 1535 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1528 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 1536 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1529 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
| 1537 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1530 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 1538 #undef DEFINE_BUILTIN_ACCESSOR_C | 1531 #undef DEFINE_BUILTIN_ACCESSOR_C |
| 1539 #undef DEFINE_BUILTIN_ACCESSOR_A | 1532 #undef DEFINE_BUILTIN_ACCESSOR_A |
| 1540 | 1533 |
| 1541 | 1534 |
| 1542 } // namespace internal | 1535 } // namespace internal |
| 1543 } // namespace v8 | 1536 } // namespace v8 |
| OLD | NEW |