| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/exceptions.h" | 13 #include "vm/exceptions.h" |
| 14 #include "vm/flow_graph_builder.h" | 14 #include "vm/flow_graph_builder.h" |
| 15 #include "vm/flow_graph_compiler.h" | 15 #include "vm/flow_graph_compiler.h" |
| 16 #include "vm/flow_graph_inliner.h" | 16 #include "vm/flow_graph_inliner.h" |
| 17 #include "vm/flow_graph_range_analysis.h" | 17 #include "vm/flow_graph_range_analysis.h" |
| 18 #include "vm/hash_map.h" | 18 #include "vm/hash_map.h" |
| 19 #include "vm/il_printer.h" | 19 #include "vm/il_printer.h" |
| 20 #include "vm/intermediate_language.h" | 20 #include "vm/intermediate_language.h" |
| 21 #include "vm/object_store.h" | 21 #include "vm/object_store.h" |
| 22 #include "vm/parser.h" | 22 #include "vm/parser.h" |
| 23 #include "vm/precompiler.h" | |
| 24 #include "vm/resolver.h" | 23 #include "vm/resolver.h" |
| 25 #include "vm/scopes.h" | 24 #include "vm/scopes.h" |
| 26 #include "vm/stack_frame.h" | 25 #include "vm/stack_frame.h" |
| 27 #include "vm/symbols.h" | 26 #include "vm/symbols.h" |
| 28 | 27 |
| 29 namespace dart { | 28 namespace dart { |
| 30 | 29 |
| 31 DEFINE_FLAG(int, getter_setter_ratio, 13, | 30 DEFINE_FLAG(int, getter_setter_ratio, 13, |
| 32 "Ratio of getter/setter usage used for double field unboxing heuristics"); | 31 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
| 33 DEFINE_FLAG(bool, guess_icdata_cid, true, | 32 DEFINE_FLAG(bool, guess_icdata_cid, true, |
| 34 "Artificially create type feedback for arithmetic etc. operations" | 33 "Artificially create type feedback for arithmetic etc. operations" |
| 35 " by guessing the other unknown argument cid"); | 34 " by guessing the other unknown argument cid"); |
| 36 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 35 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 37 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 36 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | 37 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
| 39 "Maximum number of polymorphic checks in equality operator," | 38 "Maximum number of polymorphic checks in equality operator," |
| 40 " otherwise use megamorphic dispatch."); | 39 " otherwise use megamorphic dispatch."); |
| 41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); | 40 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); |
| 42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 43 DEFINE_FLAG(bool, truncating_left_shift, true, | 42 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 44 "Optimize left shift to truncate if possible"); | 43 "Optimize left shift to truncate if possible"); |
| 45 DEFINE_FLAG(bool, use_cha_deopt, true, | 44 DEFINE_FLAG(bool, use_cha_deopt, true, |
| 46 "Use class hierarchy analysis even if it can cause deoptimization."); | 45 "Use class hierarchy analysis even if it can cause deoptimization."); |
| 47 | 46 |
| 48 DECLARE_FLAG(bool, precompilation); | |
| 49 DECLARE_FLAG(bool, polymorphic_with_deopt); | 47 DECLARE_FLAG(bool, polymorphic_with_deopt); |
| 50 DECLARE_FLAG(bool, trace_cha); | 48 DECLARE_FLAG(bool, trace_cha); |
| 51 DECLARE_FLAG(bool, trace_field_guards); | 49 DECLARE_FLAG(bool, trace_field_guards); |
| 52 | 50 |
| 53 // Quick access to the current isolate and zone. | 51 // Quick access to the current isolate and zone. |
| 54 #define I (isolate()) | 52 #define I (isolate()) |
| 55 #define Z (zone()) | 53 #define Z (zone()) |
| 56 | 54 |
| 57 static bool ShouldInlineSimd() { | 55 static bool ShouldInlineSimd() { |
| 58 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 56 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 59 } | 57 } |
| 60 | 58 |
| 61 | 59 |
| 62 static bool CanUnboxDouble() { | 60 static bool CanUnboxDouble() { |
| 63 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 61 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 64 } | 62 } |
| 65 | 63 |
| 66 | 64 |
| 67 static bool CanConvertUnboxedMintToDouble() { | 65 static bool CanConvertUnboxedMintToDouble() { |
| 68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 66 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
| 69 } | 67 } |
| 70 | 68 |
| 71 | 69 |
| 72 // Optimize instance calls using ICData. | 70 // Optimize instance calls using ICData. |
| 73 void FlowGraphOptimizer::ApplyICData() { | 71 void FlowGraphOptimizer::ApplyICData() { |
| 74 VisitBlocks(); | 72 VisitBlocks(); |
| 75 } | 73 } |
| 76 | 74 |
| 77 | 75 |
| 78 void FlowGraphOptimizer::PopulateWithICData() { | |
| 79 ASSERT(current_iterator_ == NULL); | |
| 80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | |
| 81 !block_it.Done(); | |
| 82 block_it.Advance()) { | |
| 83 ForwardInstructionIterator it(block_it.Current()); | |
| 84 for (; !it.Done(); it.Advance()) { | |
| 85 Instruction* instr = it.Current(); | |
| 86 if (instr->IsInstanceCall()) { | |
| 87 InstanceCallInstr* call = instr->AsInstanceCall(); | |
| 88 if (!call->HasICData()) { | |
| 89 const Array& arguments_descriptor = | |
| 90 Array::Handle(zone(), | |
| 91 ArgumentsDescriptor::New(call->ArgumentCount(), | |
| 92 call->argument_names())); | |
| 93 const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New( | |
| 94 function(), call->function_name(), | |
| 95 arguments_descriptor, call->deopt_id(), | |
| 96 call->checked_argument_count())); | |
| 97 call->set_ic_data(&ic_data); | |
| 98 } | |
| 99 } | |
| 100 } | |
| 101 current_iterator_ = NULL; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 | |
| 106 // Optimize instance calls using cid. This is called after optimizer | 76 // Optimize instance calls using cid. This is called after optimizer |
| 107 // converted instance calls to instructions. Any remaining | 77 // converted instance calls to instructions. Any remaining |
| 108 // instance calls are either megamorphic calls, cannot be optimized or | 78 // instance calls are either megamorphic calls, cannot be optimized or |
| 109 // have no runtime type feedback collected. | 79 // have no runtime type feedback collected. |
| 110 // Attempts to convert an instance call (IC call) using propagated class-ids, | 80 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 111 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 81 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
| 112 void FlowGraphOptimizer::ApplyClassIds() { | 82 void FlowGraphOptimizer::ApplyClassIds() { |
| 113 ASSERT(current_iterator_ == NULL); | 83 ASSERT(current_iterator_ == NULL); |
| 114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 84 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 115 !block_it.Done(); | 85 !block_it.Done(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 if (class_ids.length() > 1) { | 180 if (class_ids.length() > 1) { |
| 211 ic_data.AddCheck(class_ids, function); | 181 ic_data.AddCheck(class_ids, function); |
| 212 } else { | 182 } else { |
| 213 ASSERT(class_ids.length() == 1); | 183 ASSERT(class_ids.length() == 1); |
| 214 ic_data.AddReceiverCheck(class_ids[0], function); | 184 ic_data.AddReceiverCheck(class_ids[0], function); |
| 215 } | 185 } |
| 216 call->set_ic_data(&ic_data); | 186 call->set_ic_data(&ic_data); |
| 217 return true; | 187 return true; |
| 218 } | 188 } |
| 219 | 189 |
| 220 #ifdef DART_PRECOMPILER | |
| 221 if (FLAG_precompilation && | |
| 222 (isolate()->object_store()->unique_dynamic_targets() != Array::null())) { | |
| 223 // Check if the target is unique. | |
| 224 Function& target_function = Function::Handle(Z); | |
| 225 Precompiler::GetUniqueDynamicTarget( | |
| 226 isolate(), call->function_name(), &target_function); | |
| 227 // Calls with named arguments must be resolved/checked at runtime. | |
| 228 String& error_message = String::Handle(Z); | |
| 229 if (!target_function.IsNull() && | |
| 230 !target_function.HasOptionalNamedParameters() && | |
| 231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | |
| 232 &error_message)) { | |
| 233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | |
| 234 const ICData& ic_data = ICData::ZoneHandle(Z, | |
| 235 ICData::NewFrom(*call->ic_data(), 1)); | |
| 236 ic_data.AddReceiverCheck(cid, target_function); | |
| 237 call->set_ic_data(&ic_data); | |
| 238 return true; | |
| 239 } | |
| 240 } | |
| 241 #endif | |
| 242 | |
| 243 // Check if getter or setter in function's class and class is currently leaf. | 190 // Check if getter or setter in function's class and class is currently leaf. |
| 244 if (FLAG_guess_icdata_cid && | 191 if (FLAG_guess_icdata_cid && |
| 245 ((call->token_kind() == Token::kGET) || | 192 ((call->token_kind() == Token::kGET) || |
| 246 (call->token_kind() == Token::kSET))) { | 193 (call->token_kind() == Token::kSET))) { |
| 247 const Class& owner_class = Class::Handle(Z, function().Owner()); | 194 const Class& owner_class = Class::Handle(Z, function().Owner()); |
| 248 if (!owner_class.is_abstract() && | 195 if (!owner_class.is_abstract() && |
| 249 !CHA::HasSubclasses(owner_class) && | 196 !CHA::HasSubclasses(owner_class) && |
| 250 !CHA::IsImplemented(owner_class)) { | 197 !CHA::IsImplemented(owner_class)) { |
| 251 const Array& args_desc_array = Array::Handle(Z, | 198 const Array& args_desc_array = Array::Handle(Z, |
| 252 ArgumentsDescriptor::New(call->ArgumentCount(), | 199 ArgumentsDescriptor::New(call->ArgumentCount(), |
| (...skipping 1796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2049 return true; | 1996 return true; |
| 2050 } | 1997 } |
| 2051 } | 1998 } |
| 2052 return false; | 1999 return false; |
| 2053 } | 2000 } |
| 2054 | 2001 |
| 2055 | 2002 |
| 2056 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | 2003 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( |
| 2057 StaticCallInstr* call, | 2004 StaticCallInstr* call, |
| 2058 MethodRecognizer::Kind recognized_kind) { | 2005 MethodRecognizer::Kind recognized_kind) { |
| 2059 if (FLAG_precompilation) { | |
| 2060 // Cannot handle unboxed instructions. | |
| 2061 return false; | |
| 2062 } | |
| 2063 if (!ShouldInlineSimd()) { | 2006 if (!ShouldInlineSimd()) { |
| 2064 return false; | 2007 return false; |
| 2065 } | 2008 } |
| 2066 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | 2009 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { |
| 2067 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); | 2010 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); |
| 2068 ReplaceCall(call, zero); | 2011 ReplaceCall(call, zero); |
| 2069 return true; | 2012 return true; |
| 2070 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | 2013 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { |
| 2071 Float32x4SplatInstr* splat = | 2014 Float32x4SplatInstr* splat = |
| 2072 new(Z) Float32x4SplatInstr( | 2015 new(Z) Float32x4SplatInstr( |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2096 ReplaceCall(call, cast); | 2039 ReplaceCall(call, cast); |
| 2097 return true; | 2040 return true; |
| 2098 } | 2041 } |
| 2099 return false; | 2042 return false; |
| 2100 } | 2043 } |
| 2101 | 2044 |
| 2102 | 2045 |
| 2103 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( | 2046 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( |
| 2104 StaticCallInstr* call, | 2047 StaticCallInstr* call, |
| 2105 MethodRecognizer::Kind recognized_kind) { | 2048 MethodRecognizer::Kind recognized_kind) { |
| 2106 if (FLAG_precompilation) { | |
| 2107 // Cannot handle unboxed instructions. | |
| 2108 return false; | |
| 2109 } | |
| 2110 if (!ShouldInlineSimd()) { | 2049 if (!ShouldInlineSimd()) { |
| 2111 return false; | 2050 return false; |
| 2112 } | 2051 } |
| 2113 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { | 2052 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { |
| 2114 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); | 2053 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); |
| 2115 ReplaceCall(call, zero); | 2054 ReplaceCall(call, zero); |
| 2116 return true; | 2055 return true; |
| 2117 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { | 2056 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { |
| 2118 Float64x2SplatInstr* splat = | 2057 Float64x2SplatInstr* splat = |
| 2119 new(Z) Float64x2SplatInstr( | 2058 new(Z) Float64x2SplatInstr( |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2135 ReplaceCall(call, cast); | 2074 ReplaceCall(call, cast); |
| 2136 return true; | 2075 return true; |
| 2137 } | 2076 } |
| 2138 return false; | 2077 return false; |
| 2139 } | 2078 } |
| 2140 | 2079 |
| 2141 | 2080 |
| 2142 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( | 2081 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( |
| 2143 StaticCallInstr* call, | 2082 StaticCallInstr* call, |
| 2144 MethodRecognizer::Kind recognized_kind) { | 2083 MethodRecognizer::Kind recognized_kind) { |
| 2145 if (FLAG_precompilation) { | |
| 2146 // Cannot handle unboxed instructions. | |
| 2147 return false; | |
| 2148 } | |
| 2149 if (!ShouldInlineSimd()) { | 2084 if (!ShouldInlineSimd()) { |
| 2150 return false; | 2085 return false; |
| 2151 } | 2086 } |
| 2152 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { | 2087 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { |
| 2153 Int32x4BoolConstructorInstr* con = | 2088 Int32x4BoolConstructorInstr* con = |
| 2154 new(Z) Int32x4BoolConstructorInstr( | 2089 new(Z) Int32x4BoolConstructorInstr( |
| 2155 new(Z) Value(call->ArgumentAt(1)), | 2090 new(Z) Value(call->ArgumentAt(1)), |
| 2156 new(Z) Value(call->ArgumentAt(2)), | 2091 new(Z) Value(call->ArgumentAt(2)), |
| 2157 new(Z) Value(call->ArgumentAt(3)), | 2092 new(Z) Value(call->ArgumentAt(3)), |
| 2158 new(Z) Value(call->ArgumentAt(4)), | 2093 new(Z) Value(call->ArgumentAt(4)), |
| (...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2929 /* with_checks = */ false); | 2864 /* with_checks = */ false); |
| 2930 instr->ReplaceWith(call, current_iterator()); | 2865 instr->ReplaceWith(call, current_iterator()); |
| 2931 return; | 2866 return; |
| 2932 } | 2867 } |
| 2933 } | 2868 } |
| 2934 | 2869 |
| 2935 | 2870 |
| 2936 // Tries to optimize instance call by replacing it with a faster instruction | 2871 // Tries to optimize instance call by replacing it with a faster instruction |
| 2937 // (e.g, binary op, field load, ..). | 2872 // (e.g, binary op, field load, ..). |
| 2938 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2873 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2939 if (FLAG_precompilation) { | |
| 2940 InstanceCallNoopt(instr); | |
| 2941 return; | |
| 2942 } | |
| 2943 | |
| 2944 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 2874 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
| 2945 return; | 2875 return; |
| 2946 } | 2876 } |
| 2947 const Token::Kind op_kind = instr->token_kind(); | 2877 const Token::Kind op_kind = instr->token_kind(); |
| 2948 | 2878 |
| 2949 // Type test is special as it always gets converted into inlined code. | 2879 // Type test is special as it always gets converted into inlined code. |
| 2950 if (Token::IsTypeTestOperator(op_kind)) { | 2880 if (Token::IsTypeTestOperator(op_kind)) { |
| 2951 ReplaceWithInstanceOf(instr); | 2881 ReplaceWithInstanceOf(instr); |
| 2952 return; | 2882 return; |
| 2953 } | 2883 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3061 unary_kind = MathUnaryInstr::kSin; | 2991 unary_kind = MathUnaryInstr::kSin; |
| 3062 break; | 2992 break; |
| 3063 case MethodRecognizer::kMathCos: | 2993 case MethodRecognizer::kMathCos: |
| 3064 unary_kind = MathUnaryInstr::kCos; | 2994 unary_kind = MathUnaryInstr::kCos; |
| 3065 break; | 2995 break; |
| 3066 default: | 2996 default: |
| 3067 unary_kind = MathUnaryInstr::kIllegal; | 2997 unary_kind = MathUnaryInstr::kIllegal; |
| 3068 break; | 2998 break; |
| 3069 } | 2999 } |
| 3070 if (unary_kind != MathUnaryInstr::kIllegal) { | 3000 if (unary_kind != MathUnaryInstr::kIllegal) { |
| 3071 if (FLAG_precompilation) { | |
| 3072 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | |
| 3073 return; | |
| 3074 } | |
| 3075 MathUnaryInstr* math_unary = | 3001 MathUnaryInstr* math_unary = |
| 3076 new(Z) MathUnaryInstr(unary_kind, | 3002 new(Z) MathUnaryInstr(unary_kind, |
| 3077 new(Z) Value(call->ArgumentAt(0)), | 3003 new(Z) Value(call->ArgumentAt(0)), |
| 3078 call->deopt_id()); | 3004 call->deopt_id()); |
| 3079 ReplaceCall(call, math_unary); | 3005 ReplaceCall(call, math_unary); |
| 3080 return; | 3006 return; |
| 3081 } | 3007 } |
| 3082 switch (recognized_kind) { | 3008 switch (recognized_kind) { |
| 3083 case MethodRecognizer::kFloat32x4Zero: | 3009 case MethodRecognizer::kFloat32x4Zero: |
| 3084 case MethodRecognizer::kFloat32x4Splat: | 3010 case MethodRecognizer::kFloat32x4Splat: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3147 } | 3073 } |
| 3148 } | 3074 } |
| 3149 break; | 3075 break; |
| 3150 } | 3076 } |
| 3151 case MethodRecognizer::kMathDoublePow: | 3077 case MethodRecognizer::kMathDoublePow: |
| 3152 case MethodRecognizer::kMathTan: | 3078 case MethodRecognizer::kMathTan: |
| 3153 case MethodRecognizer::kMathAsin: | 3079 case MethodRecognizer::kMathAsin: |
| 3154 case MethodRecognizer::kMathAcos: | 3080 case MethodRecognizer::kMathAcos: |
| 3155 case MethodRecognizer::kMathAtan: | 3081 case MethodRecognizer::kMathAtan: |
| 3156 case MethodRecognizer::kMathAtan2: { | 3082 case MethodRecognizer::kMathAtan2: { |
| 3157 if (FLAG_precompilation) { | |
| 3158 // No UnboxDouble instructons allowed. | |
| 3159 return; | |
| 3160 } | |
| 3161 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | 3083 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble |
| 3162 // instructions contain type checks and conversions to double. | 3084 // instructions contain type checks and conversions to double. |
| 3163 ZoneGrowableArray<Value*>* args = | 3085 ZoneGrowableArray<Value*>* args = |
| 3164 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 3086 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 3165 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 3087 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 3166 args->Add(new(Z) Value(call->ArgumentAt(i))); | 3088 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 3167 } | 3089 } |
| 3168 InvokeMathCFunctionInstr* invoke = | 3090 InvokeMathCFunctionInstr* invoke = |
| 3169 new(Z) InvokeMathCFunctionInstr(args, | 3091 new(Z) InvokeMathCFunctionInstr(args, |
| 3170 call->deopt_id(), | 3092 call->deopt_id(), |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3406 | 3328 |
| 3407 // Discard the environment from the original instruction because the store | 3329 // Discard the environment from the original instruction because the store |
| 3408 // can't deoptimize. | 3330 // can't deoptimize. |
| 3409 instr->RemoveEnvironment(); | 3331 instr->RemoveEnvironment(); |
| 3410 ReplaceCall(instr, store); | 3332 ReplaceCall(instr, store); |
| 3411 return true; | 3333 return true; |
| 3412 } | 3334 } |
| 3413 | 3335 |
| 3414 | 3336 |
| 3415 } // namespace dart | 3337 } // namespace dart |
| OLD | NEW |