| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 1891 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1902 elements, isolate()->factory()->fixed_array_map(), top_info()); | 1902 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 1903 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 1903 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1904 } | 1904 } |
| 1905 } | 1905 } |
| 1906 } | 1906 } |
| 1907 return AddElementAccess(elements, checked_key, val, checked_object, | 1907 return AddElementAccess(elements, checked_key, val, checked_object, |
| 1908 elements_kind, is_store, load_mode); | 1908 elements_kind, is_store, load_mode); |
| 1909 } | 1909 } |
| 1910 | 1910 |
| 1911 | 1911 |
| 1912 |
| 1913 HValue* HGraphBuilder::BuildAllocateArrayFromLength( |
| 1914 JSArrayBuilder* array_builder, |
| 1915 HValue* length_argument) { |
| 1916 if (length_argument->IsConstant() && |
| 1917 HConstant::cast(length_argument)->HasSmiValue()) { |
| 1918 int array_length = HConstant::cast(length_argument)->Integer32Value(); |
| 1919 HValue* new_object = array_length == 0 |
| 1920 ? array_builder->AllocateEmptyArray() |
| 1921 : array_builder->AllocateArray(length_argument, length_argument); |
| 1922 return new_object; |
| 1923 } |
| 1924 |
| 1925 HValue* constant_zero = graph()->GetConstant0(); |
| 1926 HConstant* max_alloc_length = |
| 1927 Add<HConstant>(JSObject::kInitialMaxFastElementArray); |
| 1928 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, |
| 1929 max_alloc_length); |
| 1930 IfBuilder if_builder(this); |
| 1931 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, |
| 1932 Token::EQ); |
| 1933 if_builder.Then(); |
| 1934 const int initial_capacity = JSArray::kPreallocatedArrayElements; |
| 1935 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); |
| 1936 Push(initial_capacity_node); // capacity |
| 1937 Push(constant_zero); // length |
| 1938 if_builder.Else(); |
| 1939 if (!(top_info()->IsStub()) && |
| 1940 IsFastPackedElementsKind(array_builder->kind())) { |
| 1941 // We'll come back later with better (holey) feedback. |
| 1942 if_builder.Deopt("Holey array despite packed elements_kind feedback"); |
| 1943 } |
| 1944 Push(checked_length); // capacity |
| 1945 Push(checked_length); // length |
| 1946 if_builder.End(); |
| 1947 |
| 1948 // Figure out total size |
| 1949 HValue* length = Pop(); |
| 1950 HValue* capacity = Pop(); |
| 1951 return array_builder->AllocateArray(capacity, length); |
| 1952 } |
| 1953 |
| 1912 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, | 1954 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, |
| 1913 HValue* capacity) { | 1955 HValue* capacity) { |
| 1914 int elements_size; | 1956 int elements_size; |
| 1915 InstanceType instance_type; | 1957 InstanceType instance_type; |
| 1916 | 1958 |
| 1917 if (IsFastDoubleElementsKind(kind)) { | 1959 if (IsFastDoubleElementsKind(kind)) { |
| 1918 elements_size = kDoubleSize; | 1960 elements_size = kDoubleSize; |
| 1919 instance_type = FIXED_DOUBLE_ARRAY_TYPE; | 1961 instance_type = FIXED_DOUBLE_ARRAY_TYPE; |
| 1920 } else { | 1962 } else { |
| 1921 elements_size = kPointerSize; | 1963 elements_size = kPointerSize; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 // Fast elements kinds need to be initialized in case statements below cause | 2132 // Fast elements kinds need to be initialized in case statements below cause |
| 2091 // a garbage collection. | 2133 // a garbage collection. |
| 2092 Factory* factory = isolate()->factory(); | 2134 Factory* factory = isolate()->factory(); |
| 2093 | 2135 |
| 2094 double nan_double = FixedDoubleArray::hole_nan_as_double(); | 2136 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 2095 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | 2137 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 2096 ? Add<HConstant>(factory->the_hole_value()) | 2138 ? Add<HConstant>(factory->the_hole_value()) |
| 2097 : Add<HConstant>(nan_double); | 2139 : Add<HConstant>(nan_double); |
| 2098 | 2140 |
| 2099 // Special loop unfolding case | 2141 // Special loop unfolding case |
| 2100 static const int kLoopUnfoldLimit = 4; | 2142 static const int kLoopUnfoldLimit = 8; |
| 2101 bool unfold_loop = false; | 2143 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
| 2102 int initial_capacity = JSArray::kPreallocatedArrayElements; | 2144 int initial_capacity = -1; |
| 2103 if (from->ActualValue()->IsConstant() && to->ActualValue()->IsConstant() && | 2145 if (from->ActualValue()->IsConstant() && to->ActualValue()->IsConstant()) { |
| 2104 initial_capacity <= kLoopUnfoldLimit) { | |
| 2105 HConstant* constant_from = HConstant::cast(from->ActualValue()); | 2146 HConstant* constant_from = HConstant::cast(from->ActualValue()); |
| 2106 HConstant* constant_to = HConstant::cast(to->ActualValue()); | 2147 HConstant* constant_to = HConstant::cast(to->ActualValue()); |
| 2107 | 2148 |
| 2108 if (constant_from->HasInteger32Value() && | 2149 if (constant_from->HasInteger32Value() && |
| 2109 constant_from->Integer32Value() == 0 && | 2150 constant_from->Integer32Value() == 0 && |
| 2110 constant_to->HasInteger32Value() && | 2151 constant_to->HasInteger32Value() && |
| 2111 constant_to->Integer32Value() == initial_capacity) { | 2152 constant_to->Integer32Value() <= kLoopUnfoldLimit) { |
| 2112 unfold_loop = true; | 2153 initial_capacity = constant_to->Integer32Value(); |
| 2113 } | 2154 } |
| 2114 } | 2155 } |
| 2115 | 2156 |
| 2116 // Since we're about to store a hole value, the store instruction below must | 2157 // Since we're about to store a hole value, the store instruction below must |
| 2117 // assume an elements kind that supports heap object values. | 2158 // assume an elements kind that supports heap object values. |
| 2118 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 2159 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 2119 elements_kind = FAST_HOLEY_ELEMENTS; | 2160 elements_kind = FAST_HOLEY_ELEMENTS; |
| 2120 } | 2161 } |
| 2121 | 2162 |
| 2122 if (unfold_loop) { | 2163 if (initial_capacity >= 0) { |
| 2123 for (int i = 0; i < initial_capacity; i++) { | 2164 for (int i = 0; i < initial_capacity; i++) { |
| 2124 HInstruction* key = Add<HConstant>(i); | 2165 HInstruction* key = Add<HConstant>(i); |
| 2125 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2166 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| 2126 } | 2167 } |
| 2127 } else { | 2168 } else { |
| 2128 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); | 2169 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); |
| 2129 | 2170 |
| 2130 HValue* key = builder.BeginBody(from, to, Token::LT); | 2171 HValue* key = builder.BeginBody(from, to, Token::LT); |
| 2131 | 2172 |
| 2132 Add<HStoreKeyed>(elements, key, hole, elements_kind); | 2173 Add<HStoreKeyed>(elements, key, hole, elements_kind); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2371 HValue* constructor_function) : | 2412 HValue* constructor_function) : |
| 2372 builder_(builder), | 2413 builder_(builder), |
| 2373 kind_(kind), | 2414 kind_(kind), |
| 2374 mode_(DONT_TRACK_ALLOCATION_SITE), | 2415 mode_(DONT_TRACK_ALLOCATION_SITE), |
| 2375 allocation_site_payload_(NULL), | 2416 allocation_site_payload_(NULL), |
| 2376 constructor_function_(constructor_function) { | 2417 constructor_function_(constructor_function) { |
| 2377 } | 2418 } |
| 2378 | 2419 |
| 2379 | 2420 |
| 2380 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { | 2421 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { |
| 2422 if (!builder()->top_info()->IsStub()) { |
| 2423 // A constant map is fine. |
| 2424 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), |
| 2425 builder()->isolate()); |
| 2426 return builder()->Add<HConstant>(map); |
| 2427 } |
| 2428 |
| 2381 if (kind_ == GetInitialFastElementsKind()) { | 2429 if (kind_ == GetInitialFastElementsKind()) { |
| 2382 // No need for a context lookup if the kind_ matches the initial | 2430 // No need for a context lookup if the kind_ matches the initial |
| 2383 // map, because we can just load the map in that case. | 2431 // map, because we can just load the map in that case. |
| 2384 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2432 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2385 return builder()->AddLoadNamedField(constructor_function_, access); | 2433 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2386 } | 2434 } |
| 2387 | 2435 |
| 2388 HInstruction* native_context = builder()->BuildGetNativeContext(); | 2436 HInstruction* native_context = builder()->BuildGetNativeContext(); |
| 2389 HInstruction* index = builder()->Add<HConstant>( | 2437 HInstruction* index = builder()->Add<HConstant>( |
| 2390 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2438 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2413 int base_size = JSArray::kSize; | 2461 int base_size = JSArray::kSize; |
| 2414 if (mode_ == TRACK_ALLOCATION_SITE) { | 2462 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2415 base_size += AllocationMemento::kSize; | 2463 base_size += AllocationMemento::kSize; |
| 2416 } | 2464 } |
| 2417 | 2465 |
| 2418 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); | 2466 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
| 2419 base_size += FixedArray::kHeaderSize; | 2467 base_size += FixedArray::kHeaderSize; |
| 2420 | 2468 |
| 2421 HInstruction* elements_size_value = | 2469 HInstruction* elements_size_value = |
| 2422 builder()->Add<HConstant>(elements_size()); | 2470 builder()->Add<HConstant>(elements_size()); |
| 2423 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); | 2471 HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(), |
| 2424 mul->ClearFlag(HValue::kCanOverflow); | 2472 length_node, elements_size_value); |
| 2425 | 2473 builder()->AddInstruction(mul); |
| 2426 HInstruction* base = builder()->Add<HConstant>(base_size); | 2474 HInstruction* base = builder()->Add<HConstant>(base_size); |
| 2427 HInstruction* total_size = builder()->Add<HAdd>(base, mul); | 2475 HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(), |
| 2476 base, mul); |
| 2428 total_size->ClearFlag(HValue::kCanOverflow); | 2477 total_size->ClearFlag(HValue::kCanOverflow); |
| 2478 builder()->AddInstruction(total_size); |
| 2429 return total_size; | 2479 return total_size; |
| 2430 } | 2480 } |
| 2431 | 2481 |
| 2432 | 2482 |
| 2433 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { | 2483 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() { |
| 2434 int base_size = JSArray::kSize; | 2484 int base_size = JSArray::kSize; |
| 2435 if (mode_ == TRACK_ALLOCATION_SITE) { | 2485 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2436 base_size += AllocationMemento::kSize; | 2486 base_size += AllocationMemento::kSize; |
| 2437 } | 2487 } |
| 2438 | 2488 |
| 2439 base_size += IsFastDoubleElementsKind(kind_) | 2489 base_size += IsFastDoubleElementsKind(kind_) |
| 2440 ? FixedDoubleArray::SizeFor(initial_capacity()) | 2490 ? FixedDoubleArray::SizeFor(initial_capacity()) |
| 2441 : FixedArray::SizeFor(initial_capacity()); | 2491 : FixedArray::SizeFor(initial_capacity()); |
| 2442 | 2492 |
| 2443 return builder()->Add<HConstant>(base_size); | 2493 return builder()->Add<HConstant>(base_size); |
| 2444 } | 2494 } |
| 2445 | 2495 |
| 2446 | 2496 |
| 2447 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { | 2497 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { |
| 2448 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); | 2498 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); |
| 2449 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); | 2499 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); |
| 2450 return AllocateArray(size_in_bytes, | 2500 return AllocateArray(size_in_bytes, |
| 2451 capacity, | 2501 capacity, |
| 2452 builder()->graph()->GetConstant0(), | 2502 builder()->graph()->GetConstant0()); |
| 2453 true); | |
| 2454 } | 2503 } |
| 2455 | 2504 |
| 2456 | 2505 |
| 2457 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, | 2506 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, |
| 2458 HValue* length_field, | 2507 HValue* length_field, |
| 2459 bool fill_with_hole) { | 2508 FillMode fill_mode) { |
| 2460 HValue* size_in_bytes = EstablishAllocationSize(capacity); | 2509 HValue* size_in_bytes = EstablishAllocationSize(capacity); |
| 2461 return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); | 2510 return AllocateArray(size_in_bytes, capacity, length_field, fill_mode); |
| 2462 } | 2511 } |
| 2463 | 2512 |
| 2464 | 2513 |
| 2465 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, | 2514 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
| 2466 HValue* capacity, | 2515 HValue* capacity, |
| 2467 HValue* length_field, | 2516 HValue* length_field, |
| 2468 bool fill_with_hole) { | 2517 FillMode fill_mode) { |
| 2469 // These HForceRepresentations are because we store these as fields in the | 2518 // These HForceRepresentations are because we store these as fields in the |
| 2470 // objects we construct, and an int32-to-smi HChange could deopt. Accept | 2519 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 2471 // the deopt possibility now, before allocation occurs. | 2520 // the deopt possibility now, before allocation occurs. |
| 2472 capacity = builder()->Add<HForceRepresentation>(capacity, | 2521 capacity = builder()->Add<HForceRepresentation>(capacity, |
| 2473 Representation::Smi()); | 2522 Representation::Smi()); |
| 2474 length_field = builder()->Add<HForceRepresentation>(length_field, | 2523 length_field = builder()->Add<HForceRepresentation>(length_field, |
| 2475 Representation::Smi()); | 2524 Representation::Smi()); |
| 2476 // Allocate (dealing with failure appropriately) | 2525 // Allocate (dealing with failure appropriately) |
| 2477 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, | 2526 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, |
| 2478 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); | 2527 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2492 elements_location_ = builder()->BuildJSArrayHeader(new_object, | 2541 elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| 2493 map, | 2542 map, |
| 2494 mode_, | 2543 mode_, |
| 2495 kind_, | 2544 kind_, |
| 2496 allocation_site_payload_, | 2545 allocation_site_payload_, |
| 2497 length_field); | 2546 length_field); |
| 2498 | 2547 |
| 2499 // Initialize the elements | 2548 // Initialize the elements |
| 2500 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); | 2549 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); |
| 2501 | 2550 |
| 2502 if (fill_with_hole) { | 2551 if (fill_mode == FILL_WITH_HOLE) { |
| 2503 builder()->BuildFillElementsWithHole(elements_location_, kind_, | 2552 builder()->BuildFillElementsWithHole(elements_location_, kind_, |
| 2504 graph()->GetConstant0(), capacity); | 2553 graph()->GetConstant0(), capacity); |
| 2505 } | 2554 } |
| 2506 | 2555 |
| 2507 return new_object; | 2556 return new_object; |
| 2508 } | 2557 } |
| 2509 | 2558 |
| 2510 | 2559 |
| 2511 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, | 2560 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, |
| 2512 Handle<Map> map) { | 2561 Handle<Map> map) { |
| (...skipping 5015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7528 | 7577 |
| 7529 call = New<HCallFunction>(function, argument_count); | 7578 call = New<HCallFunction>(function, argument_count); |
| 7530 Drop(argument_count + 1); | 7579 Drop(argument_count + 1); |
| 7531 } | 7580 } |
| 7532 } | 7581 } |
| 7533 | 7582 |
| 7534 return ast_context()->ReturnInstruction(call, expr->id()); | 7583 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7535 } | 7584 } |
| 7536 | 7585 |
| 7537 | 7586 |
| 7587 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
| 7588 NoObservableSideEffectsScope no_effects(this); |
| 7589 |
| 7590 int argument_count = expr->arguments()->length(); |
| 7591 // We should at least have the constructor on the expression stack. |
| 7592 HValue* constructor = environment()->ExpressionStackAt(argument_count); |
| 7593 |
| 7594 ElementsKind kind = expr->elements_kind(); |
| 7595 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7596 AllocationSite* site = AllocationSite::cast(cell->value()); |
| 7597 |
| 7598 // Register on the site for deoptimization if the cell value changes. |
| 7599 site->AddDependentCompilationInfo(AllocationSite::TRANSITIONS, top_info()); |
| 7600 HInstruction* cell_instruction = Add<HConstant>(cell); |
| 7601 |
| 7602 // In the single constant argument case, we may have to adjust elements kind |
| 7603 // to avoid creating a packed non-empty array. |
| 7604 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { |
| 7605 HValue* argument = environment()->Top(); |
| 7606 if (argument->IsConstant()) { |
| 7607 HConstant* constant_argument = HConstant::cast(argument); |
| 7608 ASSERT(constant_argument->HasSmiValue()); |
| 7609 int constant_array_size = constant_argument->Integer32Value(); |
| 7610 if (constant_array_size != 0) { |
| 7611 kind = GetHoleyElementsKind(kind); |
| 7612 } |
| 7613 } |
| 7614 } |
| 7615 |
| 7616 // Build the array. |
| 7617 JSArrayBuilder array_builder(this, |
| 7618 kind, |
| 7619 cell_instruction, |
| 7620 constructor, |
| 7621 DISABLE_ALLOCATION_SITES); |
| 7622 HValue* new_object; |
| 7623 if (argument_count == 0) { |
| 7624 new_object = array_builder.AllocateEmptyArray(); |
| 7625 } else if (argument_count == 1) { |
| 7626 HValue* argument = environment()->Top(); |
| 7627 new_object = BuildAllocateArrayFromLength(&array_builder, argument); |
| 7628 } else { |
| 7629 HValue* length = Add<HConstant>(argument_count); |
| 7630 // Smi arrays need to initialize array elements with the hole because |
| 7631 // bailout could occur if the arguments don't fit in a smi. |
| 7632 // |
| 7633 // TODO(mvstanton): If all the arguments are constants in smi range, then |
| 7634 // we could set fill_with_hole to false and save a few instructions. |
| 7635 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) |
| 7636 ? JSArrayBuilder::FILL_WITH_HOLE |
| 7637 : JSArrayBuilder::DONT_FILL_WITH_HOLE; |
| 7638 new_object = array_builder.AllocateArray(length, length, fill_mode); |
| 7639 HValue* elements = array_builder.GetElementsLocation(); |
| 7640 for (int i = 0; i < argument_count; i++) { |
| 7641 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1); |
| 7642 HValue* constant_i = Add<HConstant>(i); |
| 7643 Add<HStoreKeyed>(elements, constant_i, value, kind); |
| 7644 } |
| 7645 } |
| 7646 |
| 7647 Drop(argument_count + 1); // drop constructor and args. |
| 7648 ast_context()->ReturnValue(new_object); |
| 7649 } |
| 7650 |
| 7651 |
| 7538 // Checks whether allocation using the given constructor can be inlined. | 7652 // Checks whether allocation using the given constructor can be inlined. |
| 7539 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7653 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 7540 return constructor->has_initial_map() && | 7654 return constructor->has_initial_map() && |
| 7541 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7655 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 7542 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 7656 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 7543 constructor->initial_map()->InitialPropertiesLength() == 0; | 7657 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 7544 } | 7658 } |
| 7545 | 7659 |
| 7546 | 7660 |
| 7661 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
| 7662 bool inline_ok = false; |
| 7663 Handle<JSFunction> caller = current_info()->closure(); |
| 7664 Handle<JSFunction> target(isolate()->global_context()->array_function(), |
| 7665 isolate()); |
| 7666 int argument_count = expr->arguments()->length(); |
| 7667 // We should have the function plus array arguments on the environment stack. |
| 7668 ASSERT(environment()->length() >= (argument_count + 1)); |
| 7669 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7670 AllocationSite* site = AllocationSite::cast(cell->value()); |
| 7671 if (site->CanInlineCall()) { |
| 7672 // We also want to avoid inlining in certain 1 argument scenarios. |
| 7673 if (argument_count == 1) { |
| 7674 HValue* argument = Top(); |
| 7675 if (argument->IsConstant()) { |
| 7676 // Do not inline if the constant length argument is not a smi or |
| 7677 // outside the valid range for a fast array. |
| 7678 HConstant* constant_argument = HConstant::cast(argument); |
| 7679 if (constant_argument->HasSmiValue()) { |
| 7680 int value = constant_argument->Integer32Value(); |
| 7681 inline_ok = value >= 0 && |
| 7682 value < JSObject::kInitialMaxFastElementArray; |
| 7683 if (!inline_ok) { |
| 7684 TraceInline(target, caller, |
| 7685 "Length outside of valid array range"); |
| 7686 } |
| 7687 } |
| 7688 } else { |
| 7689 inline_ok = true; |
| 7690 } |
| 7691 } else { |
| 7692 inline_ok = true; |
| 7693 } |
| 7694 } else { |
| 7695 TraceInline(target, caller, "AllocationSite requested no inlining."); |
| 7696 } |
| 7697 |
| 7698 if (inline_ok) { |
| 7699 TraceInline(target, caller, NULL); |
| 7700 } |
| 7701 return inline_ok; |
| 7702 } |
| 7703 |
| 7704 |
| 7547 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7705 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 7548 ASSERT(!HasStackOverflow()); | 7706 ASSERT(!HasStackOverflow()); |
| 7549 ASSERT(current_block() != NULL); | 7707 ASSERT(current_block() != NULL); |
| 7550 ASSERT(current_block()->HasPredecessor()); | 7708 ASSERT(current_block()->HasPredecessor()); |
| 7551 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 7709 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 7552 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7710 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 7553 Factory* factory = isolate()->factory(); | 7711 Factory* factory = isolate()->factory(); |
| 7554 | 7712 |
| 7713 // The constructor function is on the stack in the unoptimized code |
| 7714 // during evaluation of the arguments. |
| 7715 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7716 HValue* function = Top(); |
| 7717 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7718 |
| 7555 if (FLAG_inline_construct && | 7719 if (FLAG_inline_construct && |
| 7556 expr->IsMonomorphic() && | 7720 expr->IsMonomorphic() && |
| 7557 IsAllocationInlineable(expr->target())) { | 7721 IsAllocationInlineable(expr->target())) { |
| 7558 // The constructor function is on the stack in the unoptimized code | |
| 7559 // during evaluation of the arguments. | |
| 7560 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7561 HValue* function = Top(); | |
| 7562 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7563 Handle<JSFunction> constructor = expr->target(); | 7722 Handle<JSFunction> constructor = expr->target(); |
| 7564 HValue* check = Add<HCheckValue>(function, constructor); | 7723 HValue* check = Add<HCheckValue>(function, constructor); |
| 7565 | 7724 |
| 7566 // Force completion of inobject slack tracking before generating | 7725 // Force completion of inobject slack tracking before generating |
| 7567 // allocation code to finalize instance size. | 7726 // allocation code to finalize instance size. |
| 7568 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7727 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
| 7569 constructor->shared()->CompleteInobjectSlackTracking(); | 7728 constructor->shared()->CompleteInobjectSlackTracking(); |
| 7570 } | 7729 } |
| 7571 | 7730 |
| 7572 // Calculate instance size from initial map of constructor. | 7731 // Calculate instance size from initial map of constructor. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7639 check->DeleteAndReplaceWith(NULL); | 7798 check->DeleteAndReplaceWith(NULL); |
| 7640 environment()->SetExpressionStackAt(receiver_index, function); | 7799 environment()->SetExpressionStackAt(receiver_index, function); |
| 7641 HInstruction* call = | 7800 HInstruction* call = |
| 7642 PreProcessCall(New<HCallNew>(function, argument_count)); | 7801 PreProcessCall(New<HCallNew>(function, argument_count)); |
| 7643 return ast_context()->ReturnInstruction(call, expr->id()); | 7802 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7644 } else { | 7803 } else { |
| 7645 // The constructor function is both an operand to the instruction and an | 7804 // The constructor function is both an operand to the instruction and an |
| 7646 // argument to the construct call. | 7805 // argument to the construct call. |
| 7647 Handle<JSFunction> array_function( | 7806 Handle<JSFunction> array_function( |
| 7648 isolate()->global_context()->array_function(), isolate()); | 7807 isolate()->global_context()->array_function(), isolate()); |
| 7649 CHECK_ALIVE(VisitArgument(expr->expression())); | 7808 bool use_call_new_array = expr->target().is_identical_to(array_function); |
| 7650 HValue* constructor = HPushArgument::cast(Top())->argument(); | 7809 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7651 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7810 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
| 7811 // Verify we are still calling the array function for our native context. |
| 7812 Add<HCheckValue>(function, array_function); |
| 7813 BuildInlinedCallNewArray(expr); |
| 7814 return; |
| 7815 } |
| 7816 |
| 7652 HBinaryCall* call; | 7817 HBinaryCall* call; |
| 7653 if (expr->target().is_identical_to(array_function)) { | 7818 if (use_call_new_array) { |
| 7654 Handle<Cell> cell = expr->allocation_info_cell(); | 7819 Add<HCheckValue>(function, array_function); |
| 7655 Add<HCheckValue>(constructor, array_function); | 7820 call = New<HCallNewArray>(function, argument_count, cell, |
| 7656 call = New<HCallNewArray>(constructor, argument_count, | 7821 expr->elements_kind()); |
| 7657 cell, expr->elements_kind()); | |
| 7658 } else { | 7822 } else { |
| 7659 call = New<HCallNew>(constructor, argument_count); | 7823 call = New<HCallNew>(function, argument_count); |
| 7660 } | 7824 } |
| 7661 Drop(argument_count); | 7825 PreProcessCall(call); |
| 7662 return ast_context()->ReturnInstruction(call, expr->id()); | 7826 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7663 } | 7827 } |
| 7664 } | 7828 } |
| 7665 | 7829 |
| 7666 | 7830 |
| 7667 // Support for generating inlined runtime functions. | 7831 // Support for generating inlined runtime functions. |
| 7668 | 7832 |
| 7669 // Lookup table for generators for runtime calls that are generated inline. | 7833 // Lookup table for generators for runtime calls that are generated inline. |
| 7670 // Elements of the table are member pointers to functions of | 7834 // Elements of the table are member pointers to functions of |
| 7671 // HOptimizedGraphBuilder. | 7835 // HOptimizedGraphBuilder. |
| (...skipping 2496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10168 if (ShouldProduceTraceOutput()) { | 10332 if (ShouldProduceTraceOutput()) { |
| 10169 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10333 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10170 } | 10334 } |
| 10171 | 10335 |
| 10172 #ifdef DEBUG | 10336 #ifdef DEBUG |
| 10173 graph_->Verify(false); // No full verify. | 10337 graph_->Verify(false); // No full verify. |
| 10174 #endif | 10338 #endif |
| 10175 } | 10339 } |
| 10176 | 10340 |
| 10177 } } // namespace v8::internal | 10341 } } // namespace v8::internal |
| OLD | NEW |