Chromium Code Reviews| 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/bailout-reason.h" | 7 #include "src/bailout-reason.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/field-index.h" | 9 #include "src/field-index.h" |
| 10 #include "src/hydrogen.h" | 10 #include "src/hydrogen.h" |
| 11 #include "src/ic/ic.h" | |
| 11 #include "src/lithium.h" | 12 #include "src/lithium.h" |
| 12 | 13 |
| 13 namespace v8 { | 14 namespace v8 { |
| 14 namespace internal { | 15 namespace internal { |
| 15 | 16 |
| 16 | 17 |
| 17 static LChunk* OptimizeGraph(HGraph* graph) { | 18 static LChunk* OptimizeGraph(HGraph* graph) { |
| 18 DisallowHeapAllocation no_allocation; | 19 DisallowHeapAllocation no_allocation; |
| 19 DisallowHandleAllocation no_handles; | 20 DisallowHandleAllocation no_handles; |
| 20 DisallowHandleDereference no_deref; | 21 DisallowHandleDereference no_deref; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 HValue* map_index); | 93 HValue* map_index); |
| 93 void BuildInstallCode(HValue* js_function, HValue* shared_info); | 94 void BuildInstallCode(HValue* js_function, HValue* shared_info); |
| 94 | 95 |
| 95 HInstruction* LoadFromOptimizedCodeMap(HValue* optimized_map, | 96 HInstruction* LoadFromOptimizedCodeMap(HValue* optimized_map, |
| 96 HValue* iterator, | 97 HValue* iterator, |
| 97 int field_offset); | 98 int field_offset); |
| 98 void BuildInstallFromOptimizedCodeMap(HValue* js_function, | 99 void BuildInstallFromOptimizedCodeMap(HValue* js_function, |
| 99 HValue* shared_info, | 100 HValue* shared_info, |
| 100 HValue* native_context); | 101 HValue* native_context); |
| 101 | 102 |
| 103 // Tail calls handler found at array[index]. | |
| 104 void TailCallHandler(HValue* receiver, HValue* name, HValue* array, | |
| 105 HValue* index, HValue* slot, HValue* vector); | |
| 106 | |
| 107 // Tail calls handler_code. | |
| 108 void TailCallHandler(HValue* receiver, HValue* name, HValue* slot, | |
| 109 HValue* vector, HValue* handler_code); | |
| 110 | |
| 111 void TailCallMiss(HValue* receiver, HValue* name, HValue* slot, | |
| 112 HValue* vector, bool keyed_load); | |
| 113 | |
| 114 // Handle MONOMORPHIC and POLYMORPHIC LoadIC and KeyedLoadIC cases. | |
| 115 void HandleArrayCases(HValue* array, HValue* receiver, HValue* name, | |
| 116 HValue* slot, HValue* vector, bool keyed_load); | |
| 117 | |
| 102 private: | 118 private: |
| 103 HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); | 119 HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder); |
| 104 HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, | 120 HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder, |
| 105 ElementsKind kind); | 121 ElementsKind kind); |
| 106 | 122 |
| 107 SmartArrayPointer<HParameter*> parameters_; | 123 SmartArrayPointer<HParameter*> parameters_; |
| 108 HValue* arguments_length_; | 124 HValue* arguments_length_; |
| 109 CompilationInfoWithZone info_; | 125 CompilationInfoWithZone info_; |
| 110 CodeStubDescriptor descriptor_; | 126 CodeStubDescriptor descriptor_; |
| 111 HContext* context_; | 127 HContext* context_; |
| (...skipping 1884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1996 | 2012 |
| 1997 return Pop(); | 2013 return Pop(); |
| 1998 } | 2014 } |
| 1999 | 2015 |
| 2000 | 2016 |
| 2001 Handle<Code> KeyedLoadGenericStub::GenerateCode() { | 2017 Handle<Code> KeyedLoadGenericStub::GenerateCode() { |
| 2002 return DoGenerateCode(this); | 2018 return DoGenerateCode(this); |
| 2003 } | 2019 } |
| 2004 | 2020 |
| 2005 | 2021 |
| 2022 void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name, | |
| 2023 HValue* array, HValue* index, | |
| 2024 HValue* slot, HValue* vector) { | |
| 2025 HValue* handler_code = | |
| 2026 Add<HLoadKeyed>(array, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2027 TailCallHandler(receiver, name, slot, vector, handler_code); | |
| 2028 } | |
| 2029 | |
| 2030 | |
| 2031 void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name, | |
| 2032 HValue* slot, HValue* vector, | |
| 2033 HValue* handler_code) { | |
| 2034 VectorLoadICDescriptor descriptor(isolate()); | |
| 2035 HValue* op_vals[] = {context(), receiver, name, slot, vector}; | |
| 2036 // We never return here, it is a tail call. | |
|
Jakob Kummerow
2014/12/02 08:43:06
nit: I'd move this comment after the Add<...>.
If
mvstanton
2014/12/03 11:48:30
Thanks, sounds like a good idea. I tried approxima
| |
| 2037 Add<HCallWithDescriptor>(handler_code, 0, descriptor, | |
| 2038 Vector<HValue*>(op_vals, 5), TAIL_CALL); | |
| 2039 } | |
| 2040 | |
| 2041 | |
| 2042 void CodeStubGraphBuilderBase::TailCallMiss(HValue* receiver, HValue* name, | |
| 2043 HValue* slot, HValue* vector, | |
| 2044 bool keyed_load) { | |
| 2045 DCHECK(FLAG_vector_ics); | |
| 2046 // We never return here, it is a tail call. | |
|
Jakob Kummerow
2014/12/02 08:43:06
same here
mvstanton
2014/12/03 11:48:30
Done.
| |
| 2047 Add<HTailCallThroughMegamorphicCache>( | |
| 2048 receiver, name, slot, vector, | |
| 2049 HTailCallThroughMegamorphicCache::ComputeFlags(keyed_load, true)); | |
| 2050 } | |
| 2051 | |
| 2052 | |
| 2053 void CodeStubGraphBuilderBase::HandleArrayCases(HValue* array, HValue* receiver, | |
| 2054 HValue* name, HValue* slot, | |
| 2055 HValue* vector, | |
| 2056 bool keyed_load) { | |
| 2057 HValue* length = AddLoadFixedArrayLength(array, static_cast<HValue*>(NULL)); | |
| 2058 HValue* receiver_map = AddLoadMap(receiver, static_cast<HValue*>(NULL)); | |
| 2059 IfBuilder mono_checker(this); | |
|
Jakob Kummerow
2014/12/02 08:43:06
Naming suggestion: if you name this guy "if_monomo
mvstanton
2014/12/03 11:48:30
Done.
| |
| 2060 HValue* mono_length = | |
| 2061 Add<HConstant>(static_cast<int32_t>(keyed_load ? 3 : 2)); | |
| 2062 mono_checker.If<HCompareNumericAndBranch>(length, mono_length, Token::EQ); | |
| 2063 mono_checker.Then(); | |
| 2064 { | |
| 2065 // Compare map. | |
| 2066 HValue* start = | |
| 2067 keyed_load ? graph()->GetConstant1() : graph()->GetConstant0(); | |
| 2068 HValue* array_map = Add<HLoadKeyed>( | |
| 2069 array, start, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2070 IfBuilder correct_map_checker(this); | |
| 2071 correct_map_checker.If<HCompareObjectEqAndBranch>(receiver_map, array_map); | |
| 2072 correct_map_checker.Then(); | |
| 2073 { | |
| 2074 HValue* handler_index = keyed_load | |
| 2075 ? Add<HConstant>(static_cast<int32_t>(2)) | |
|
Jakob Kummerow
2014/12/02 08:43:06
nit: Drop the static_cast, it's cleaner.
mvstanton
2014/12/03 11:48:29
Done.
mvstanton
2014/12/03 11:48:30
Done. I reformulated this code a bit too, noticing
| |
| 2076 : graph()->GetConstant1(); | |
| 2077 TailCallHandler(receiver, name, array, handler_index, slot, vector); | |
| 2078 } | |
| 2079 correct_map_checker.Else(); | |
| 2080 { TailCallMiss(receiver, name, slot, vector, keyed_load); } | |
| 2081 correct_map_checker.End(); | |
| 2082 } | |
| 2083 mono_checker.Else(); | |
| 2084 { | |
| 2085 // It is polymorphic. | |
| 2086 HValue* increment_amount = Add<HConstant>(2); | |
| 2087 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement, | |
| 2088 increment_amount); | |
| 2089 HValue* start = | |
| 2090 keyed_load ? graph()->GetConstant1() : graph()->GetConstant0(); | |
| 2091 HValue* key = builder.BeginBody(start, length, Token::LT); | |
| 2092 { | |
| 2093 HValue* array_map = Add<HLoadKeyed>( | |
| 2094 array, key, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2095 IfBuilder correct_map_checker(this); | |
| 2096 correct_map_checker.If<HCompareObjectEqAndBranch>(receiver_map, | |
| 2097 array_map); | |
| 2098 correct_map_checker.Then(); | |
| 2099 { | |
| 2100 HValue* one = graph()->GetConstant1(); | |
| 2101 HValue* index = AddUncasted<HAdd>(key, one); | |
| 2102 TailCallHandler(receiver, name, array, index, slot, vector); | |
| 2103 } | |
| 2104 } | |
| 2105 builder.EndBody(); | |
| 2106 | |
| 2107 TailCallMiss(receiver, name, slot, vector, keyed_load); | |
| 2108 } | |
| 2109 mono_checker.End(); | |
| 2110 } | |
| 2111 | |
| 2112 | |
| 2006 template <> | 2113 template <> |
| 2007 HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() { | 2114 HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() { |
| 2008 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); | 2115 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); |
| 2009 Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER); | 2116 HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex); |
| 2010 return receiver; | 2117 HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex); |
| 2118 HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex); | |
| 2119 | |
| 2120 // Are we monomorphic? | |
|
Jakob Kummerow
2014/12/02 08:43:06
nit: s/Are we foo/Is the IC in foo state/, and ple
mvstanton
2014/12/03 11:48:30
Done.
| |
| 2121 HValue* feedback = | |
| 2122 Add<HLoadKeyed>(vector, slot, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2123 IfBuilder array_checker(this); | |
| 2124 array_checker.If<HCompareMap>(feedback, | |
|
Jakob Kummerow
2014/12/02 08:43:06
This map check bakes in the assumption that the fe
mvstanton
2014/12/03 11:48:30
Yes indeed, that is why we have a pile of symbols
| |
| 2125 isolate()->factory()->fixed_array_map()); | |
| 2126 array_checker.Then(); | |
| 2127 { | |
| 2128 Add<HCheckHeapObject>(receiver); | |
|
Jakob Kummerow
2014/12/02 08:43:06
Ugh. Hydrogen's ugly warts. HCheckHeapObject shoul
mvstanton
2014/12/03 11:48:30
Oh yeah, creepy. Okay, I've turned the HCheckHeapO
Jakob Kummerow
2014/12/03 13:22:17
That's fine, but I didn't mean to imply you should
| |
| 2129 HandleArrayCases(feedback, receiver, name, slot, vector, false); | |
| 2130 } | |
| 2131 array_checker.Else(); | |
| 2132 { | |
| 2133 // Are we megamorphic? | |
| 2134 IfBuilder mega_checker(this); | |
| 2135 HConstant* megamorphic_symbol = | |
| 2136 Add<HConstant>(isolate()->factory()->megamorphic_symbol()); | |
| 2137 mega_checker.If<HCompareObjectEqAndBranch>(feedback, megamorphic_symbol); | |
| 2138 mega_checker.Then(); | |
| 2139 { | |
| 2140 // Probe the stub cache. | |
| 2141 Add<HTailCallThroughMegamorphicCache>( | |
| 2142 receiver, name, slot, vector, | |
| 2143 HTailCallThroughMegamorphicCache::ComputeFlags(false, false)); | |
| 2144 } | |
| 2145 mega_checker.End(); | |
| 2146 | |
| 2147 TailCallMiss(receiver, name, slot, vector, false); | |
| 2148 } | |
| 2149 array_checker.End(); | |
| 2150 | |
| 2151 // We never get here. | |
| 2152 return graph()->GetConstant0(); | |
| 2011 } | 2153 } |
| 2012 | 2154 |
| 2013 | 2155 |
| 2014 Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); } | 2156 Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); } |
| 2015 | 2157 |
| 2016 | 2158 |
| 2017 template <> | 2159 template <> |
| 2018 HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() { | 2160 HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() { |
| 2019 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); | 2161 HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex); |
| 2020 Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER); | 2162 HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex); |
| 2021 return receiver; | 2163 HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex); |
| 2164 HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex); | |
| 2165 HConstant* zero = graph()->GetConstant0(); | |
| 2166 | |
| 2167 // Are we monomorphic? | |
| 2168 HValue* feedback = | |
| 2169 Add<HLoadKeyed>(vector, slot, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2170 IfBuilder array_checker(this); | |
| 2171 array_checker.If<HCompareMap>(feedback, | |
| 2172 isolate()->factory()->fixed_array_map()); | |
| 2173 array_checker.Then(); | |
| 2174 { | |
| 2175 // Deal with the key. If feedback[0] is 0, then we are dealing with element | |
| 2176 // handlers. Otherwise, it's a string, verify that name matches. | |
| 2177 HValue* recorded_name = Add<HLoadKeyed>( | |
| 2178 feedback, zero, static_cast<HValue*>(NULL), FAST_ELEMENTS); | |
| 2179 | |
| 2180 IfBuilder recorded_name_is_zero(this); | |
| 2181 recorded_name_is_zero.If<HCompareNumericAndBranch>(recorded_name, zero, | |
| 2182 Token::EQ); | |
| 2183 recorded_name_is_zero.Then(); | |
| 2184 { | |
| 2185 // TODO(mvstanton): is this necessary? Anyway, I should call the | |
| 2186 // miss handler directly and not let the bailout mechanism run. | |
| 2187 Add<HCheckSmi>(name); | |
| 2188 } | |
| 2189 recorded_name_is_zero.Else(); | |
| 2190 { | |
| 2191 IfBuilder strings_match(this); | |
| 2192 strings_match.IfNot<HCompareObjectEqAndBranch>(name, recorded_name); | |
| 2193 strings_match.Then(); | |
| 2194 TailCallMiss(receiver, name, slot, vector, true); | |
| 2195 strings_match.End(); | |
| 2196 } | |
| 2197 recorded_name_is_zero.End(); | |
| 2198 | |
| 2199 Add<HCheckHeapObject>(receiver); | |
| 2200 HandleArrayCases(feedback, receiver, name, slot, vector, true); | |
| 2201 } | |
| 2202 array_checker.Else(); | |
| 2203 { | |
| 2204 // Are we megamorphic? | |
| 2205 IfBuilder mega_checker(this); | |
| 2206 HConstant* megamorphic_symbol = | |
| 2207 Add<HConstant>(isolate()->factory()->megamorphic_symbol()); | |
| 2208 mega_checker.If<HCompareObjectEqAndBranch>(feedback, megamorphic_symbol); | |
| 2209 mega_checker.Then(); | |
| 2210 { | |
| 2211 // HTailCallThroughMegamorphicCache expects name to be a string. | |
| 2212 // TODO(mvstanton): I don't understand why I need this check. How does it | |
| 2213 // work without --vector-ics on? Because there isn't a check on the name | |
| 2214 // in that case right? | |
|
Jakob Kummerow
2014/12/02 08:43:06
KeyedLoadIC currently doesn't support megamorphic
mvstanton
2014/12/03 11:48:30
Wow...the overloaded megamorphic_stub() method in
Jakob Kummerow
2014/12/03 13:22:17
Acknowledged.
| |
| 2215 Add<HCheckHeapObject>(name); | |
| 2216 // Probe the stub cache. | |
| 2217 Add<HTailCallThroughMegamorphicCache>( | |
| 2218 receiver, name, slot, vector, | |
| 2219 HTailCallThroughMegamorphicCache::ComputeFlags(true, false)); | |
| 2220 } | |
| 2221 mega_checker.End(); | |
| 2222 | |
| 2223 // Are we generic? | |
| 2224 IfBuilder generic_checker(this); | |
| 2225 HConstant* generic_symbol = | |
| 2226 Add<HConstant>(isolate()->factory()->generic_symbol()); | |
| 2227 generic_checker.If<HCompareObjectEqAndBranch>(feedback, generic_symbol); | |
| 2228 generic_checker.Then(); | |
| 2229 { | |
| 2230 // Tail-call to the generic KeyedLoadIC, treating it like a handler. | |
| 2231 Handle<Code> stub = KeyedLoadIC::generic_stub(isolate()); | |
| 2232 HValue* constant_stub = Add<HConstant>(stub); | |
| 2233 LoadDescriptor descriptor(isolate()); | |
| 2234 HValue* op_vals[] = {context(), receiver, name}; | |
| 2235 // We never return here, it is a tail call. | |
| 2236 Add<HCallWithDescriptor>(constant_stub, 0, descriptor, | |
| 2237 Vector<HValue*>(op_vals, 3), TAIL_CALL); | |
| 2238 } | |
| 2239 generic_checker.End(); | |
| 2240 | |
| 2241 TailCallMiss(receiver, name, slot, vector, true); | |
| 2242 } | |
| 2243 array_checker.End(); | |
| 2244 | |
| 2245 // We never get here. | |
| 2246 return zero; | |
| 2022 } | 2247 } |
| 2023 | 2248 |
| 2024 | 2249 |
| 2025 Handle<Code> VectorKeyedLoadStub::GenerateCode() { | 2250 Handle<Code> VectorKeyedLoadStub::GenerateCode() { |
| 2026 return DoGenerateCode(this); | 2251 return DoGenerateCode(this); |
| 2027 } | 2252 } |
| 2028 | 2253 |
| 2029 | 2254 |
| 2030 Handle<Code> MegamorphicLoadStub::GenerateCode() { | 2255 Handle<Code> MegamorphicLoadStub::GenerateCode() { |
| 2031 return DoGenerateCode(this); | 2256 return DoGenerateCode(this); |
| 2032 } | 2257 } |
| 2033 | 2258 |
| 2034 | 2259 |
| 2035 template <> | 2260 template <> |
| 2036 HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() { | 2261 HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() { |
| 2037 // The return address is on the stack. | |
| 2038 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); | 2262 HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); |
| 2039 HValue* name = GetParameter(LoadDescriptor::kNameIndex); | 2263 HValue* name = GetParameter(LoadDescriptor::kNameIndex); |
| 2040 | 2264 |
| 2265 // We shouldn't generate this when FLAG_vector_ics is true because the | |
| 2266 // megamorphic case is handled as part of the default stub. | |
| 2267 DCHECK(!FLAG_vector_ics); | |
| 2268 | |
| 2041 // Probe the stub cache. | 2269 // Probe the stub cache. |
| 2042 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 2270 Add<HTailCallThroughMegamorphicCache>(receiver, name); |
| 2043 Code::ComputeHandlerFlags(Code::LOAD_IC)); | |
| 2044 Add<HTailCallThroughMegamorphicCache>(receiver, name, flags); | |
| 2045 | 2271 |
| 2046 // We never continue. | 2272 // We never continue. |
| 2047 return graph()->GetConstant0(); | 2273 return graph()->GetConstant0(); |
| 2048 } | 2274 } |
| 2049 } } // namespace v8::internal | 2275 } } // namespace v8::internal |
| OLD | NEW |