| 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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 int args_length, Object** args_object, Isolate* isolate) { \ | 127 int args_length, Object** args_object, Isolate* isolate) { \ |
| 128 name##ArgumentsType args(args_length, args_object); \ | 128 name##ArgumentsType args(args_length, args_object); \ |
| 129 return Builtin_impl##name(args, isolate); \ | 129 return Builtin_impl##name(args, isolate); \ |
| 130 } \ | 130 } \ |
| 131 static Object* Builtin_impl##name( \ | 131 static Object* Builtin_impl##name( \ |
| 132 name##ArgumentsType args, Isolate* isolate) | 132 name##ArgumentsType args, Isolate* isolate) |
| 133 #endif | 133 #endif |
| 134 | 134 |
| 135 | 135 |
| 136 #ifdef DEBUG | 136 #ifdef DEBUG |
| 137 static inline bool CalledAsConstructor(Isolate* isolate) { | 137 inline bool CalledAsConstructor(Isolate* isolate) { |
| 138 // Calculate the result using a full stack frame iterator and check | 138 // Calculate the result using a full stack frame iterator and check |
| 139 // that the state of the stack is as we assume it to be in the | 139 // that the state of the stack is as we assume it to be in the |
| 140 // code below. | 140 // code below. |
| 141 StackFrameIterator it(isolate); | 141 StackFrameIterator it(isolate); |
| 142 DCHECK(it.frame()->is_exit()); | 142 DCHECK(it.frame()->is_exit()); |
| 143 it.Advance(); | 143 it.Advance(); |
| 144 StackFrame* frame = it.frame(); | 144 StackFrame* frame = it.frame(); |
| 145 bool reference_result = frame->is_construct(); | 145 bool reference_result = frame->is_construct(); |
| 146 Address fp = Isolate::c_entry_fp(isolate->thread_local_top()); | 146 Address fp = Isolate::c_entry_fp(isolate->thread_local_top()); |
| 147 // Because we know fp points to an exit frame we can use the relevant | 147 // Because we know fp points to an exit frame we can use the relevant |
| (...skipping 10 matching lines...) Expand all Loading... |
| 158 bool result = (marker == kConstructMarker); | 158 bool result = (marker == kConstructMarker); |
| 159 DCHECK_EQ(result, reference_result); | 159 DCHECK_EQ(result, reference_result); |
| 160 return result; | 160 return result; |
| 161 } | 161 } |
| 162 #endif | 162 #endif |
| 163 | 163 |
| 164 | 164 |
| 165 // ---------------------------------------------------------------------------- | 165 // ---------------------------------------------------------------------------- |
| 166 | 166 |
| 167 | 167 |
| 168 bool ClampedToInteger(Object* object, int* out) { | 168 inline bool ClampedToInteger(Object* object, int* out) { |
| 169 // This is an extended version of ECMA-262 7.1.11 handling signed values | 169 // This is an extended version of ECMA-262 7.1.11 handling signed values |
| 170 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] | 170 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] |
| 171 if (object->IsSmi()) { | 171 if (object->IsSmi()) { |
| 172 *out = Smi::cast(object)->value(); | 172 *out = Smi::cast(object)->value(); |
| 173 return true; | 173 return true; |
| 174 } else if (object->IsHeapNumber()) { | 174 } else if (object->IsHeapNumber()) { |
| 175 *out = FastD2IChecked(HeapNumber::cast(object)->value()); | 175 double value = HeapNumber::cast(object)->value(); |
| 176 if (std::isnan(value)) { |
| 177 *out = 0; |
| 178 } else if (value > kMaxInt) { |
| 179 *out = kMaxInt; |
| 180 } else if (value < kMinInt) { |
| 181 *out = kMinInt; |
| 182 } else { |
| 183 *out = static_cast<int>(value); |
| 184 } |
| 176 return true; | 185 return true; |
| 177 } else if (object->IsUndefined()) { | 186 } else if (object->IsUndefined() || object->IsNull()) { |
| 178 *out = 0; | 187 *out = 0; |
| 179 return true; | 188 return true; |
| 180 } else if (object->IsBoolean()) { | 189 } else if (object->IsBoolean()) { |
| 181 *out = object->IsTrue(); | 190 *out = object->IsTrue(); |
| 182 return true; | 191 return true; |
| 183 } | 192 } |
| 184 return false; | 193 return false; |
| 185 } | 194 } |
| 186 | 195 |
| 187 | 196 |
| 188 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, | 197 void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, |
| 189 FixedDoubleArray* src, int src_index, int len) { | 198 FixedDoubleArray* src, int src_index, int len) { |
| 190 if (len == 0) return; | 199 if (len == 0) return; |
| 191 MemMove(dst->data_start() + dst_index, src->data_start() + src_index, | 200 MemMove(dst->data_start() + dst_index, src->data_start() + src_index, |
| 192 len * kDoubleSize); | 201 len * kDoubleSize); |
| 193 } | 202 } |
| 194 | 203 |
| 195 | 204 |
| 196 static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { | 205 inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object, |
| 206 int* out) { |
| 207 Map* arguments_map = |
| 208 isolate->context()->native_context()->sloppy_arguments_map(); |
| 209 if (object->map() != arguments_map || !object->HasFastElements()) { |
| 210 return false; |
| 211 } |
| 212 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); |
| 213 if (!len_obj->IsSmi()) { |
| 214 return false; |
| 215 } |
| 216 *out = Smi::cast(len_obj)->value(); |
| 217 return *out <= object->elements()->length(); |
| 218 } |
| 219 |
| 220 |
| 221 bool PrototypeHasNoElements(PrototypeIterator* iter) { |
| 197 DisallowHeapAllocation no_gc; | 222 DisallowHeapAllocation no_gc; |
| 198 for (; !iter->IsAtEnd(); iter->Advance()) { | 223 for (; !iter->IsAtEnd(); iter->Advance()) { |
| 199 if (iter->GetCurrent()->IsJSProxy()) return false; | 224 if (iter->GetCurrent()->IsJSProxy()) return false; |
| 200 JSObject* current = JSObject::cast(iter->GetCurrent()); | 225 JSObject* current = JSObject::cast(iter->GetCurrent()); |
| 201 if (current->IsAccessCheckNeeded()) return false; | 226 if (current->IsAccessCheckNeeded()) return false; |
| 202 if (current->HasIndexedInterceptor()) return false; | 227 if (current->HasIndexedInterceptor()) return false; |
| 203 if (current->elements()->length() != 0) return false; | 228 if (current->elements()->length() != 0) return false; |
| 204 } | 229 } |
| 205 return true; | 230 return true; |
| 206 } | 231 } |
| 207 | 232 |
| 208 | 233 |
| 209 static inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, | 234 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
| 210 JSArray* receiver) { | 235 JSArray* receiver) { |
| 211 DisallowHeapAllocation no_gc; | 236 DisallowHeapAllocation no_gc; |
| 212 // If the array prototype chain is intact (and free of elements), and if the | 237 // If the array prototype chain is intact (and free of elements), and if the |
| 213 // receiver's prototype is the array prototype, then we are done. | 238 // receiver's prototype is the array prototype, then we are done. |
| 214 Object* prototype = receiver->map()->prototype(); | 239 Object* prototype = receiver->map()->prototype(); |
| 215 if (prototype->IsJSArray() && | 240 if (prototype->IsJSArray() && |
| 216 isolate->is_initial_array_prototype(JSArray::cast(prototype)) && | 241 isolate->is_initial_array_prototype(JSArray::cast(prototype)) && |
| 217 isolate->IsFastArrayConstructorPrototypeChainIntact()) { | 242 isolate->IsFastArrayConstructorPrototypeChainIntact()) { |
| 218 return true; | 243 return true; |
| 219 } | 244 } |
| 220 | 245 |
| 221 // Slow case. | 246 // Slow case. |
| 222 PrototypeIterator iter(isolate, receiver); | 247 PrototypeIterator iter(isolate, receiver); |
| 223 return ArrayPrototypeHasNoElements(&iter); | 248 return PrototypeHasNoElements(&iter); |
| 224 } | 249 } |
| 225 | 250 |
| 226 | 251 |
| 227 // Returns empty handle if not applicable. | 252 // Returns empty handle if not applicable. |
| 228 MUST_USE_RESULT | 253 MUST_USE_RESULT |
| 229 static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( | 254 inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( |
| 230 Isolate* isolate, | 255 Isolate* isolate, Handle<Object> receiver, Arguments* args, |
| 231 Handle<Object> receiver, | |
| 232 Arguments* args, | |
| 233 int first_added_arg) { | 256 int first_added_arg) { |
| 234 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>(); | 257 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>(); |
| 235 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 258 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 236 // If there may be elements accessors in the prototype chain, the fast path | 259 // If there may be elements accessors in the prototype chain, the fast path |
| 237 // cannot be used if there arguments to add to the array. | 260 // cannot be used if there arguments to add to the array. |
| 238 Heap* heap = isolate->heap(); | 261 Heap* heap = isolate->heap(); |
| 239 if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { | 262 if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { |
| 240 return MaybeHandle<FixedArrayBase>(); | 263 return MaybeHandle<FixedArrayBase>(); |
| 241 } | 264 } |
| 242 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>(); | 265 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>(); |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 | 511 |
| 489 // Set the length. | 512 // Set the length. |
| 490 array->set_length(Smi::FromInt(new_length)); | 513 array->set_length(Smi::FromInt(new_length)); |
| 491 return Smi::FromInt(new_length); | 514 return Smi::FromInt(new_length); |
| 492 } | 515 } |
| 493 | 516 |
| 494 | 517 |
| 495 BUILTIN(ArraySlice) { | 518 BUILTIN(ArraySlice) { |
| 496 HandleScope scope(isolate); | 519 HandleScope scope(isolate); |
| 497 Handle<Object> receiver = args.receiver(); | 520 Handle<Object> receiver = args.receiver(); |
| 521 Handle<JSObject> object; |
| 522 Handle<FixedArrayBase> elms_obj; |
| 498 int len = -1; | 523 int len = -1; |
| 499 int relative_start = 0; | 524 int relative_start = 0; |
| 500 int relative_end = 0; | 525 int relative_end = 0; |
| 501 { | 526 bool is_sloppy_arguments = false; |
| 527 |
| 528 if (receiver->IsJSArray()) { |
| 502 DisallowHeapAllocation no_gc; | 529 DisallowHeapAllocation no_gc; |
| 503 if (receiver->IsJSArray()) { | 530 JSArray* array = JSArray::cast(*receiver); |
| 504 JSArray* array = JSArray::cast(*receiver); | 531 if (!array->HasFastElements() || |
| 505 if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { | 532 !IsJSArrayFastElementMovingAllowed(isolate, array)) { |
| 533 AllowHeapAllocation allow_allocation; |
| 534 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 535 } |
| 536 len = Smi::cast(array->length())->value(); |
| 537 object = Handle<JSObject>::cast(receiver); |
| 538 elms_obj = handle(array->elements(), isolate); |
| 539 } else if (receiver->IsJSObject() && |
| 540 GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver), |
| 541 &len)) { |
| 542 // Array.prototype.slice(arguments, ...) is quite a common idiom |
| 543 // (notably more than 50% of invocations in Web apps). |
| 544 // Treat it in C++ as well. |
| 545 is_sloppy_arguments = true; |
| 546 object = Handle<JSObject>::cast(receiver); |
| 547 elms_obj = handle(object->elements(), isolate); |
| 548 } else { |
| 549 AllowHeapAllocation allow_allocation; |
| 550 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 551 } |
| 552 DCHECK(len >= 0); |
| 553 int argument_count = args.length() - 1; |
| 554 // Note carefully chosen defaults---if argument is missing, |
| 555 // it's undefined which gets converted to 0 for relative_start |
| 556 // and to len for relative_end. |
| 557 relative_start = 0; |
| 558 relative_end = len; |
| 559 if (argument_count > 0) { |
| 560 DisallowHeapAllocation no_gc; |
| 561 if (!ClampedToInteger(args[1], &relative_start)) { |
| 562 AllowHeapAllocation allow_allocation; |
| 563 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 564 } |
| 565 if (argument_count > 1) { |
| 566 Object* end_arg = args[2]; |
| 567 // slice handles the end_arg specially |
| 568 if (end_arg->IsUndefined()) { |
| 569 relative_end = len; |
| 570 } else if (!ClampedToInteger(end_arg, &relative_end)) { |
| 506 AllowHeapAllocation allow_allocation; | 571 AllowHeapAllocation allow_allocation; |
| 507 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | 572 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 508 } | 573 } |
| 509 | |
| 510 if (!array->HasFastElements()) { | |
| 511 AllowHeapAllocation allow_allocation; | |
| 512 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 513 } | |
| 514 | |
| 515 len = Smi::cast(array->length())->value(); | |
| 516 } else { | |
| 517 // Array.slice(arguments, ...) is quite a common idiom (notably more | |
| 518 // than 50% of invocations in Web apps). Treat it in C++ as well. | |
| 519 Map* arguments_map = | |
| 520 isolate->context()->native_context()->sloppy_arguments_map(); | |
| 521 | |
| 522 bool is_arguments_object_with_fast_elements = | |
| 523 receiver->IsJSObject() && | |
| 524 JSObject::cast(*receiver)->map() == arguments_map; | |
| 525 if (!is_arguments_object_with_fast_elements) { | |
| 526 AllowHeapAllocation allow_allocation; | |
| 527 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 528 } | |
| 529 JSObject* object = JSObject::cast(*receiver); | |
| 530 | |
| 531 if (!object->HasFastElements()) { | |
| 532 AllowHeapAllocation allow_allocation; | |
| 533 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 534 } | |
| 535 | |
| 536 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); | |
| 537 if (!len_obj->IsSmi()) { | |
| 538 AllowHeapAllocation allow_allocation; | |
| 539 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 540 } | |
| 541 len = Smi::cast(len_obj)->value(); | |
| 542 if (len > object->elements()->length()) { | |
| 543 AllowHeapAllocation allow_allocation; | |
| 544 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 545 } | |
| 546 } | |
| 547 | |
| 548 DCHECK(len >= 0); | |
| 549 int n_arguments = args.length() - 1; | |
| 550 | |
| 551 // Note carefully choosen defaults---if argument is missing, | |
| 552 // it's undefined which gets converted to 0 for relative_start | |
| 553 // and to len for relative_end. | |
| 554 relative_start = 0; | |
| 555 relative_end = len; | |
| 556 if (n_arguments > 0) { | |
| 557 Object* arg1 = args[1]; | |
| 558 if (arg1->IsSmi()) { | |
| 559 relative_start = Smi::cast(arg1)->value(); | |
| 560 } else if (arg1->IsHeapNumber()) { | |
| 561 double start = HeapNumber::cast(arg1)->value(); | |
| 562 if (start < kMinInt || start > kMaxInt) { | |
| 563 AllowHeapAllocation allow_allocation; | |
| 564 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 565 } | |
| 566 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | |
| 567 } else if (!arg1->IsUndefined()) { | |
| 568 AllowHeapAllocation allow_allocation; | |
| 569 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 570 } | |
| 571 if (n_arguments > 1) { | |
| 572 Object* arg2 = args[2]; | |
| 573 if (arg2->IsSmi()) { | |
| 574 relative_end = Smi::cast(arg2)->value(); | |
| 575 } else if (arg2->IsHeapNumber()) { | |
| 576 double end = HeapNumber::cast(arg2)->value(); | |
| 577 if (end < kMinInt || end > kMaxInt) { | |
| 578 AllowHeapAllocation allow_allocation; | |
| 579 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 580 } | |
| 581 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); | |
| 582 } else if (!arg2->IsUndefined()) { | |
| 583 AllowHeapAllocation allow_allocation; | |
| 584 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 585 } | |
| 586 } | |
| 587 } | 574 } |
| 588 } | 575 } |
| 589 | 576 |
| 590 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. | 577 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
| 591 int k = (relative_start < 0) ? Max(len + relative_start, 0) | 578 uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
| 592 : Min(relative_start, len); | 579 : Min(relative_start, len); |
| 593 | 580 |
| 594 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. | 581 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
| 595 int final = (relative_end < 0) ? Max(len + relative_end, 0) | 582 uint32_t actual_end = |
| 596 : Min(relative_end, len); | 583 (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); |
| 597 | |
| 598 // Calculate the length of result array. | |
| 599 int result_len = Max(final - k, 0); | |
| 600 | |
| 601 Handle<JSObject> object = Handle<JSObject>::cast(receiver); | |
| 602 Handle<FixedArrayBase> elms(object->elements(), isolate); | |
| 603 | |
| 604 ElementsKind kind = object->GetElementsKind(); | |
| 605 if (IsHoleyElementsKind(kind)) { | |
| 606 DisallowHeapAllocation no_gc; | |
| 607 bool packed = true; | |
| 608 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); | |
| 609 for (int i = k; i < final; i++) { | |
| 610 if (!accessor->HasElement(object, i, elms)) { | |
| 611 packed = false; | |
| 612 break; | |
| 613 } | |
| 614 } | |
| 615 if (packed) { | |
| 616 kind = GetPackedElementsKind(kind); | |
| 617 } else if (!receiver->IsJSArray()) { | |
| 618 AllowHeapAllocation allow_allocation; | |
| 619 return CallJsIntrinsic(isolate, isolate->array_slice(), args); | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 Handle<JSArray> result_array = | |
| 624 isolate->factory()->NewJSArray(kind, result_len, result_len); | |
| 625 | |
| 626 DisallowHeapAllocation no_gc; | |
| 627 if (result_len == 0) return *result_array; | |
| 628 | 584 |
| 629 ElementsAccessor* accessor = object->GetElementsAccessor(); | 585 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 630 accessor->CopyElements( | 586 if (is_sloppy_arguments && |
| 631 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); | 587 !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) { |
| 588 // Don't deal with arguments with holes in C++ |
| 589 AllowHeapAllocation allow_allocation; |
| 590 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
| 591 } |
| 592 Handle<JSArray> result_array = |
| 593 accessor->Slice(object, elms_obj, actual_start, actual_end); |
| 632 return *result_array; | 594 return *result_array; |
| 633 } | 595 } |
| 634 | 596 |
| 635 | 597 |
| 636 BUILTIN(ArraySplice) { | 598 BUILTIN(ArraySplice) { |
| 637 HandleScope scope(isolate); | 599 HandleScope scope(isolate); |
| 638 Handle<Object> receiver = args.receiver(); | 600 Handle<Object> receiver = args.receiver(); |
| 639 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 601 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| 640 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 602 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
| 641 Handle<FixedArrayBase> elms_obj; | 603 Handle<FixedArrayBase> elms_obj; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 } | 642 } |
| 681 | 643 |
| 682 int add_count = (argument_count > 1) ? (argument_count - 2) : 0; | 644 int add_count = (argument_count > 1) ? (argument_count - 2) : 0; |
| 683 int new_length = len - actual_delete_count + add_count; | 645 int new_length = len - actual_delete_count + add_count; |
| 684 | 646 |
| 685 if (new_length != len && JSArray::HasReadOnlyLength(array)) { | 647 if (new_length != len && JSArray::HasReadOnlyLength(array)) { |
| 686 AllowHeapAllocation allow_allocation; | 648 AllowHeapAllocation allow_allocation; |
| 687 return CallJsIntrinsic(isolate, isolate->array_splice(), args); | 649 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
| 688 } | 650 } |
| 689 ElementsAccessor* accessor = array->GetElementsAccessor(); | 651 ElementsAccessor* accessor = array->GetElementsAccessor(); |
| 690 Handle<JSArray> result = accessor->Splice( | 652 Handle<JSArray> result_array = accessor->Splice( |
| 691 array, elms_obj, actual_start, actual_delete_count, args, add_count); | 653 array, elms_obj, actual_start, actual_delete_count, args, add_count); |
| 692 return *result; | 654 return *result_array; |
| 693 } | 655 } |
| 694 | 656 |
| 695 | 657 |
| 696 BUILTIN(ArrayConcat) { | 658 BUILTIN(ArrayConcat) { |
| 697 HandleScope scope(isolate); | 659 HandleScope scope(isolate); |
| 698 | 660 |
| 699 int n_arguments = args.length(); | 661 int n_arguments = args.length(); |
| 700 int result_len = 0; | 662 int result_len = 0; |
| 701 ElementsKind elements_kind = GetInitialFastElementsKind(); | 663 ElementsKind elements_kind = GetInitialFastElementsKind(); |
| 702 bool has_double = false; | 664 bool has_double = false; |
| 703 { | 665 { |
| 704 DisallowHeapAllocation no_gc; | 666 DisallowHeapAllocation no_gc; |
| 705 Context* native_context = isolate->context()->native_context(); | 667 Context* native_context = isolate->context()->native_context(); |
| 706 Object* array_proto = native_context->array_function()->prototype(); | 668 Object* array_proto = native_context->array_function()->prototype(); |
| 707 PrototypeIterator iter(isolate, array_proto, | 669 PrototypeIterator iter(isolate, array_proto, |
| 708 PrototypeIterator::START_AT_RECEIVER); | 670 PrototypeIterator::START_AT_RECEIVER); |
| 709 if (!ArrayPrototypeHasNoElements(&iter)) { | 671 if (!PrototypeHasNoElements(&iter)) { |
| 710 AllowHeapAllocation allow_allocation; | 672 AllowHeapAllocation allow_allocation; |
| 711 return CallJsIntrinsic(isolate, isolate->array_concat(), args); | 673 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
| 712 } | 674 } |
| 713 | 675 |
| 714 // Iterate through all the arguments performing checks | 676 // Iterate through all the arguments performing checks |
| 715 // and calculating total length. | 677 // and calculating total length. |
| 716 bool is_holey = false; | 678 bool is_holey = false; |
| 717 for (int i = 0; i < n_arguments; i++) { | 679 for (int i = 0; i < n_arguments; i++) { |
| 718 Object* arg = args[i]; | 680 Object* arg = args[i]; |
| 719 PrototypeIterator iter(isolate, arg); | 681 PrototypeIterator iter(isolate, arg); |
| (...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1389 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1351 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
| 1390 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1352 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 1391 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1353 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
| 1392 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1354 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 1393 #undef DEFINE_BUILTIN_ACCESSOR_C | 1355 #undef DEFINE_BUILTIN_ACCESSOR_C |
| 1394 #undef DEFINE_BUILTIN_ACCESSOR_A | 1356 #undef DEFINE_BUILTIN_ACCESSOR_A |
| 1395 | 1357 |
| 1396 | 1358 |
| 1397 } // namespace internal | 1359 } // namespace internal |
| 1398 } // namespace v8 | 1360 } // namespace v8 |
| OLD | NEW |