OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 new_elms->address(), | 271 new_elms->address(), |
272 new_elms->Size()); | 272 new_elms->Size()); |
273 } | 273 } |
274 return new_elms; | 274 return new_elms; |
275 } | 275 } |
276 | 276 |
277 | 277 |
278 static bool ArrayPrototypeHasNoElements(Heap* heap, | 278 static bool ArrayPrototypeHasNoElements(Heap* heap, |
279 Context* native_context, | 279 Context* native_context, |
280 JSObject* array_proto) { | 280 JSObject* array_proto) { |
| 281 DisallowHeapAllocation no_gc; |
281 // This method depends on non writability of Object and Array prototype | 282 // This method depends on non writability of Object and Array prototype |
282 // fields. | 283 // fields. |
283 if (array_proto->elements() != heap->empty_fixed_array()) return false; | 284 if (array_proto->elements() != heap->empty_fixed_array()) return false; |
284 // Object.prototype | 285 // Object.prototype |
285 Object* proto = array_proto->GetPrototype(); | 286 Object* proto = array_proto->GetPrototype(); |
286 if (proto == heap->null_value()) return false; | 287 if (proto == heap->null_value()) return false; |
287 array_proto = JSObject::cast(proto); | 288 array_proto = JSObject::cast(proto); |
288 if (array_proto != native_context->initial_object_prototype()) return false; | 289 if (array_proto != native_context->initial_object_prototype()) return false; |
289 if (array_proto->elements() != heap->empty_fixed_array()) return false; | 290 if (array_proto->elements() != heap->empty_fixed_array()) return false; |
290 return array_proto->GetPrototype()->IsNull(); | 291 return array_proto->GetPrototype()->IsNull(); |
(...skipping 26 matching lines...) Expand all Loading... |
317 } | 318 } |
318 | 319 |
319 // Need to ensure that the arguments passed in args can be contained in | 320 // Need to ensure that the arguments passed in args can be contained in |
320 // the array. | 321 // the array. |
321 int args_length = args->length(); | 322 int args_length = args->length(); |
322 if (first_added_arg >= args_length) return handle(array->elements(), isolate); | 323 if (first_added_arg >= args_length) return handle(array->elements(), isolate); |
323 | 324 |
324 ElementsKind origin_kind = array->map()->elements_kind(); | 325 ElementsKind origin_kind = array->map()->elements_kind(); |
325 ASSERT(!IsFastObjectElementsKind(origin_kind)); | 326 ASSERT(!IsFastObjectElementsKind(origin_kind)); |
326 ElementsKind target_kind = origin_kind; | 327 ElementsKind target_kind = origin_kind; |
327 int arg_count = args->length() - first_added_arg; | 328 { |
328 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); | 329 DisallowHeapAllocation no_gc; |
329 for (int i = 0; i < arg_count; i++) { | 330 int arg_count = args->length() - first_added_arg; |
330 Object* arg = arguments[i]; | 331 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); |
331 if (arg->IsHeapObject()) { | 332 for (int i = 0; i < arg_count; i++) { |
332 if (arg->IsHeapNumber()) { | 333 Object* arg = arguments[i]; |
333 target_kind = FAST_DOUBLE_ELEMENTS; | 334 if (arg->IsHeapObject()) { |
334 } else { | 335 if (arg->IsHeapNumber()) { |
335 target_kind = FAST_ELEMENTS; | 336 target_kind = FAST_DOUBLE_ELEMENTS; |
336 break; | 337 } else { |
| 338 target_kind = FAST_ELEMENTS; |
| 339 break; |
| 340 } |
337 } | 341 } |
338 } | 342 } |
339 } | 343 } |
340 if (target_kind != origin_kind) { | 344 if (target_kind != origin_kind) { |
341 JSObject::TransitionElementsKind(array, target_kind); | 345 JSObject::TransitionElementsKind(array, target_kind); |
342 return handle(array->elements(), isolate); | 346 return handle(array->elements(), isolate); |
343 } | 347 } |
344 return elms; | 348 return elms; |
345 } | 349 } |
346 | 350 |
347 | 351 |
348 // TODO(ishell): Handlify when all Array* builtins are handlified. | |
349 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, | 352 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, |
350 JSArray* receiver) { | 353 JSArray* receiver) { |
351 if (!FLAG_clever_optimizations) return false; | 354 if (!FLAG_clever_optimizations) return false; |
| 355 DisallowHeapAllocation no_gc; |
352 Context* native_context = heap->isolate()->context()->native_context(); | 356 Context* native_context = heap->isolate()->context()->native_context(); |
353 JSObject* array_proto = | 357 JSObject* array_proto = |
354 JSObject::cast(native_context->array_function()->prototype()); | 358 JSObject::cast(native_context->array_function()->prototype()); |
355 return receiver->GetPrototype() == array_proto && | 359 return receiver->GetPrototype() == array_proto && |
356 ArrayPrototypeHasNoElements(heap, native_context, array_proto); | 360 ArrayPrototypeHasNoElements(heap, native_context, array_proto); |
357 } | 361 } |
358 | 362 |
359 | 363 |
360 MUST_USE_RESULT static MaybeObject* CallJsBuiltin( | 364 MUST_USE_RESULT static MaybeObject* CallJsBuiltin( |
361 Isolate* isolate, | 365 Isolate* isolate, |
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 } | 984 } |
981 // Set the length. | 985 // Set the length. |
982 array->set_length(Smi::FromInt(new_length)); | 986 array->set_length(Smi::FromInt(new_length)); |
983 | 987 |
984 return *result_array; | 988 return *result_array; |
985 } | 989 } |
986 | 990 |
987 | 991 |
988 BUILTIN(ArrayConcat) { | 992 BUILTIN(ArrayConcat) { |
989 HandleScope scope(isolate); | 993 HandleScope scope(isolate); |
990 Heap* heap = isolate->heap(); | |
991 Handle<Context> native_context(isolate->context()->native_context(), isolate); | |
992 Handle<JSObject> array_proto( | |
993 JSObject::cast(native_context->array_function()->prototype()), isolate); | |
994 if (!ArrayPrototypeHasNoElements(heap, *native_context, *array_proto)) { | |
995 return CallJsBuiltin(isolate, "ArrayConcat", args); | |
996 } | |
997 | 994 |
998 // Iterate through all the arguments performing checks | |
999 // and calculating total length. | |
1000 int n_arguments = args.length(); | 995 int n_arguments = args.length(); |
1001 int result_len = 0; | 996 int result_len = 0; |
1002 ElementsKind elements_kind = GetInitialFastElementsKind(); | 997 ElementsKind elements_kind = GetInitialFastElementsKind(); |
1003 bool has_double = false; | 998 bool has_double = false; |
1004 bool is_holey = false; | 999 { |
1005 for (int i = 0; i < n_arguments; i++) { | |
1006 DisallowHeapAllocation no_gc; | 1000 DisallowHeapAllocation no_gc; |
1007 Object* arg = args[i]; | 1001 Heap* heap = isolate->heap(); |
1008 if (!arg->IsJSArray() || | 1002 Context* native_context = isolate->context()->native_context(); |
1009 !JSArray::cast(arg)->HasFastElements() || | 1003 JSObject* array_proto = |
1010 JSArray::cast(arg)->GetPrototype() != *array_proto) { | 1004 JSObject::cast(native_context->array_function()->prototype()); |
1011 AllowHeapAllocation allow_allocation; | 1005 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) { |
1012 return CallJsBuiltin(isolate, "ArrayConcat", args); | |
1013 } | |
1014 int len = Smi::cast(JSArray::cast(arg)->length())->value(); | |
1015 | |
1016 // We shouldn't overflow when adding another len. | |
1017 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | |
1018 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | |
1019 USE(kHalfOfMaxInt); | |
1020 result_len += len; | |
1021 ASSERT(result_len >= 0); | |
1022 | |
1023 if (result_len > FixedDoubleArray::kMaxLength) { | |
1024 AllowHeapAllocation allow_allocation; | 1006 AllowHeapAllocation allow_allocation; |
1025 return CallJsBuiltin(isolate, "ArrayConcat", args); | 1007 return CallJsBuiltin(isolate, "ArrayConcat", args); |
1026 } | 1008 } |
1027 | 1009 |
1028 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); | 1010 // Iterate through all the arguments performing checks |
1029 has_double = has_double || IsFastDoubleElementsKind(arg_kind); | 1011 // and calculating total length. |
1030 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); | 1012 bool is_holey = false; |
1031 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { | 1013 for (int i = 0; i < n_arguments; i++) { |
1032 elements_kind = arg_kind; | 1014 Object* arg = args[i]; |
| 1015 if (!arg->IsJSArray() || |
| 1016 !JSArray::cast(arg)->HasFastElements() || |
| 1017 JSArray::cast(arg)->GetPrototype() != array_proto) { |
| 1018 AllowHeapAllocation allow_allocation; |
| 1019 return CallJsBuiltin(isolate, "ArrayConcat", args); |
| 1020 } |
| 1021 int len = Smi::cast(JSArray::cast(arg)->length())->value(); |
| 1022 |
| 1023 // We shouldn't overflow when adding another len. |
| 1024 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
| 1025 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
| 1026 USE(kHalfOfMaxInt); |
| 1027 result_len += len; |
| 1028 ASSERT(result_len >= 0); |
| 1029 |
| 1030 if (result_len > FixedDoubleArray::kMaxLength) { |
| 1031 AllowHeapAllocation allow_allocation; |
| 1032 return CallJsBuiltin(isolate, "ArrayConcat", args); |
| 1033 } |
| 1034 |
| 1035 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); |
| 1036 has_double = has_double || IsFastDoubleElementsKind(arg_kind); |
| 1037 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); |
| 1038 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { |
| 1039 elements_kind = arg_kind; |
| 1040 } |
1033 } | 1041 } |
| 1042 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); |
1034 } | 1043 } |
1035 | 1044 |
1036 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); | |
1037 | |
1038 // If a double array is concatted into a fast elements array, the fast | 1045 // If a double array is concatted into a fast elements array, the fast |
1039 // elements array needs to be initialized to contain proper holes, since | 1046 // elements array needs to be initialized to contain proper holes, since |
1040 // boxing doubles may cause incremental marking. | 1047 // boxing doubles may cause incremental marking. |
1041 ArrayStorageAllocationMode mode = | 1048 ArrayStorageAllocationMode mode = |
1042 has_double && IsFastObjectElementsKind(elements_kind) | 1049 has_double && IsFastObjectElementsKind(elements_kind) |
1043 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS; | 1050 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS; |
1044 Handle<JSArray> result_array = | 1051 Handle<JSArray> result_array = |
1045 isolate->factory()->NewJSArray(elements_kind, | 1052 isolate->factory()->NewJSArray(elements_kind, |
1046 result_len, | 1053 result_len, |
1047 result_len, | 1054 result_len, |
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1728 } | 1735 } |
1729 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1736 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
1730 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1737 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
1731 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1738 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
1732 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1739 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
1733 #undef DEFINE_BUILTIN_ACCESSOR_C | 1740 #undef DEFINE_BUILTIN_ACCESSOR_C |
1734 #undef DEFINE_BUILTIN_ACCESSOR_A | 1741 #undef DEFINE_BUILTIN_ACCESSOR_A |
1735 | 1742 |
1736 | 1743 |
1737 } } // namespace v8::internal | 1744 } } // namespace v8::internal |
OLD | NEW |