Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 10399051: First shot at static type propagation and type test elimination. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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_builder.h" 5 #include "vm/flow_graph_builder.h"
6 6
7 #include "vm/ast_printer.h" 7 #include "vm/ast_printer.h"
8 #include "vm/bit_vector.h" 8 #include "vm/bit_vector.h"
9 #include "vm/code_descriptors.h" 9 #include "vm/code_descriptors.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 const LocalVariable& local, Value* value) { 149 const LocalVariable& local, Value* value) {
150 if (local.is_captured()) { 150 if (local.is_captured()) {
151 intptr_t delta = owner()->context_level() - 151 intptr_t delta = owner()->context_level() -
152 local.owner()->context_level(); 152 local.owner()->context_level();
153 ASSERT(delta >= 0); 153 ASSERT(delta >= 0);
154 BindInstr* context = new BindInstr(new CurrentContextComp()); 154 BindInstr* context = new BindInstr(new CurrentContextComp());
155 AddInstruction(context); 155 AddInstruction(context);
156 Value* context_value = new UseVal(context); 156 Value* context_value = new UseVal(context);
157 while (delta-- > 0) { 157 while (delta-- > 0) {
158 BindInstr* load = new BindInstr(new NativeLoadFieldComp( 158 BindInstr* load = new BindInstr(new NativeLoadFieldComp(
159 context_value, Context::parent_offset())); 159 context_value, Context::parent_offset(), Type::ZoneHandle()));
160 AddInstruction(load); 160 AddInstruction(load);
161 context_value = new UseVal(load); 161 context_value = new UseVal(load);
162 } 162 }
163 Computation* store = new NativeStoreFieldComp( 163 Computation* store = new NativeStoreFieldComp(
164 context_value, Context::variable_offset(local.index()), value); 164 context_value, Context::variable_offset(local.index()), value);
165 return store; 165 return store;
166 } else { 166 } else {
167 return new StoreLocalComp(local, value, owner()->context_level()); 167 return new StoreLocalComp(local, value, owner()->context_level());
168 } 168 }
169 } 169 }
170 170
171 171
172 Computation* EffectGraphVisitor::BuildLoadLocal(const LocalVariable& local) { 172 Computation* EffectGraphVisitor::BuildLoadLocal(const LocalVariable& local) {
173 if (local.is_captured()) { 173 if (local.is_captured()) {
174 intptr_t delta = owner()->context_level() - 174 intptr_t delta = owner()->context_level() -
175 local.owner()->context_level(); 175 local.owner()->context_level();
176 ASSERT(delta >= 0); 176 ASSERT(delta >= 0);
177 BindInstr* context = new BindInstr(new CurrentContextComp()); 177 BindInstr* context = new BindInstr(new CurrentContextComp());
178 AddInstruction(context); 178 AddInstruction(context);
179 Value* context_value = new UseVal(context); 179 Value* context_value = new UseVal(context);
180 while (delta-- > 0) { 180 while (delta-- > 0) {
181 BindInstr* load = new BindInstr(new NativeLoadFieldComp( 181 BindInstr* load = new BindInstr(new NativeLoadFieldComp(
182 context_value, Context::parent_offset())); 182 context_value, Context::parent_offset(), Type::ZoneHandle()));
183 AddInstruction(load); 183 AddInstruction(load);
184 context_value = new UseVal(load); 184 context_value = new UseVal(load);
185 } 185 }
186 Computation* store = new NativeLoadFieldComp( 186 Computation* store = new NativeLoadFieldComp(
187 context_value, Context::variable_offset(local.index())); 187 context_value, Context::variable_offset(local.index()), local.type());
188 return store; 188 return store;
189 } else { 189 } else {
190 return new LoadLocalComp(local, owner()->context_level()); 190 return new LoadLocalComp(local, owner()->context_level());
191 } 191 }
192 } 192 }
193 193
194 194
195 // Stores current context into the 'variable' 195 // Stores current context into the 'variable'
196 void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable) { 196 void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable) {
197 BindInstr* context = new BindInstr(new CurrentContextComp()); 197 BindInstr* context = new BindInstr(new CurrentContextComp());
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 294
295 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { 295 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) {
296 ReturnComputation(new ConstantVal(node->literal())); 296 ReturnComputation(new ConstantVal(node->literal()));
297 } 297 }
298 298
299 // Type nodes only occur as the right-hand side of instanceof comparisons, 299 // Type nodes only occur as the right-hand side of instanceof comparisons,
300 // and they are handled specially in that context. 300 // and they are handled specially in that context.
301 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } 301 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); }
302 302
303 303
304 // Returns true if the type check can be skipped, for example, if the type is 304 // Returns true if the type check can be skipped, for example, if the
305 // Dynamic or if the value is a compile time constant and an instance of type. 305 // destination type is Dynamic or if the static type of the value is a subtype
306 static bool CanSkipTypeCheck(AstNode* value, const AbstractType& dst_type) { 306 // of the destination type.
307 static bool CanSkipTypeCheck(Value* value, const AbstractType& dst_type) {
307 ASSERT(FLAG_enable_type_checks); 308 ASSERT(FLAG_enable_type_checks);
308 ASSERT(!dst_type.IsNull()); 309 ASSERT(!dst_type.IsNull());
309 ASSERT(dst_type.IsFinalized()); 310 ASSERT(dst_type.IsFinalized());
310 311
311 // Any expression is assignable to the Dynamic type and to the Object type. 312 // Any expression is assignable to the Dynamic type and to the Object type.
312 // Skip the test. 313 // Skip the test.
313 if (!dst_type.IsMalformed() && 314 if (!dst_type.IsMalformed() &&
314 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { 315 (dst_type.IsDynamicType() || dst_type.IsObjectType())) {
315 return true; 316 return true;
316 } 317 }
317 318
318 // It is a compile-time error to explicitly return a value (including null) 319 // It is a compile-time error to explicitly return a value (including null)
319 // from a void function. However, functions that do not explicitly return a 320 // from a void function. However, functions that do not explicitly return a
320 // value, implicitly return null. This includes void functions. Therefore, we 321 // value, implicitly return null. This includes void functions. Therefore, we
321 // skip the type test here and trust the parser to only return null in void 322 // skip the type test here and trust the parser to only return null in void
322 // function. 323 // function.
323 if (dst_type.IsVoidType()) { 324 if (dst_type.IsVoidType()) {
324 return true; 325 return true;
325 } 326 }
326 327
328 // If nothing is known about the value, as is the case for passed-in
329 // parameters, the test cannot be eliminated.
330 if (value == NULL) {
331 return false;
332 }
333
334 // If nothing is known about the static type of the value, the test cannot be
335 // eliminated.
336 const AbstractType& static_type = AbstractType::Handle(value->StaticType());
337 ASSERT(!static_type.IsMalformed());
338 if (static_type.IsDynamicType()) {
339 return false;
340 }
341
342 // If the static type of the value is void, the only allowed value is null,
343 // which must be verified by the type test.
344 if (static_type.IsVoidType()) {
345 // TODO(regis): Eliminate the test if the value is constant null.
346 return false;
347 }
348
327 // Eliminate the test if it can be performed successfully at compile time. 349 // Eliminate the test if it can be performed successfully at compile time.
328 if ((value != NULL) && value->IsLiteralNode()) { 350 if (static_type.IsNullType()) {
329 const Instance& literal_value = value->AsLiteralNode()->literal(); 351 // There are only three instances that can be of Class Null:
330 const Class& cls = Class::Handle(literal_value.clazz()); 352 // Object::null(), Object::sentinel(), and Object::transition_sentinel().
331 if (cls.IsNullClass()) { 353 // The inline code and run time code performing the type check will never
332 // There are only three instances that can be of Class Null: 354 // encounter the 2 sentinel values. The type check of a sentinel value
333 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). 355 // will always be eliminated here, because these sentinel values can only
334 // The inline code and run time code performing the type check will never 356 // be encountered as constants, never as actual value of a heap object
335 // encounter the 2 sentinel values. The type check of a sentinel value 357 // being type checked.
336 // will always be eliminated here, because these sentinel values can only 358 return true;
337 // be encountered as constants, never as actual value of an heap object 359 }
338 // being type checked. 360 Error& malformed_error = Error::Handle();
339 ASSERT(literal_value.IsNull() || 361 if (!dst_type.IsMalformed() &&
340 (literal_value.raw() == Object::sentinel()) || 362 static_type.IsSubtypeOf(dst_type, &malformed_error)) {
341 (literal_value.raw() == Object::transition_sentinel())); 363 return true;
342 return true;
343 }
344 Error& malformed_error = Error::Handle();
345 if (!dst_type.IsMalformed() &&
346 dst_type.IsInstantiated() &&
347 literal_value.IsInstanceOf(dst_type,
348 TypeArguments::Handle(),
349 &malformed_error)) {
350 return true;
351 }
352 } 364 }
353 365
354 return false; 366 return false;
355 } 367 }
356 368
357 369
358 // <Expression> :: Assignable { expr: <Expression> 370 // <Expression> :: Assignable { expr: <Expression>
359 // type: AbstractType 371 // type: AbstractType
360 // dst_name: String } 372 // dst_name: String }
361 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { 373 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) {
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 dst_type, 591 dst_type,
580 dst_name); 592 dst_name);
581 AddInstruction(new DoInstr(assert_assignable)); 593 AddInstruction(new DoInstr(assert_assignable));
582 } 594 }
583 595
584 596
585 Value* EffectGraphVisitor::BuildAssignableValue(AstNode* value_node, 597 Value* EffectGraphVisitor::BuildAssignableValue(AstNode* value_node,
586 Value* value, 598 Value* value,
587 const AbstractType& dst_type, 599 const AbstractType& dst_type,
588 const String& dst_name) { 600 const String& dst_name) {
589 if (CanSkipTypeCheck(value_node, dst_type)) { 601 if (CanSkipTypeCheck(value, dst_type)) {
590 return value; 602 return value;
591 } 603 }
592 604
593 // Build the type check computation. 605 // Build the type check computation.
594 Value* instantiator_type_arguments = NULL; 606 Value* instantiator_type_arguments = NULL;
595 if (!dst_type.IsInstantiated()) { 607 if (!dst_type.IsInstantiated()) {
596 instantiator_type_arguments = 608 instantiator_type_arguments =
597 BuildInstantiatorTypeArguments(value_node->token_index()); 609 BuildInstantiatorTypeArguments(value_node->token_index());
598 } 610 }
599 BindInstr* assert_assignable = 611 BindInstr* assert_assignable =
(...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after
1487 // The receiver cannot be null; extract its AbstractTypeArguments object. 1499 // The receiver cannot be null; extract its AbstractTypeArguments object.
1488 // Note that in the factory case, the instantiator is the first parameter 1500 // Note that in the factory case, the instantiator is the first parameter
1489 // of the factory, i.e. already an AbstractTypeArguments object. 1501 // of the factory, i.e. already an AbstractTypeArguments object.
1490 intptr_t type_arguments_instance_field_offset = 1502 intptr_t type_arguments_instance_field_offset =
1491 instantiator_class.type_arguments_instance_field_offset(); 1503 instantiator_class.type_arguments_instance_field_offset();
1492 ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); 1504 ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments);
1493 1505
1494 BindInstr* load = 1506 BindInstr* load =
1495 new BindInstr(new NativeLoadFieldComp( 1507 new BindInstr(new NativeLoadFieldComp(
1496 for_instantiator.value(), 1508 for_instantiator.value(),
1497 type_arguments_instance_field_offset)); 1509 type_arguments_instance_field_offset,
1510 Type::ZoneHandle())); // Not an instance, no type.
1498 AddInstruction(load); 1511 AddInstruction(load);
1499 return new UseVal(load); 1512 return new UseVal(load);
1500 } 1513 }
1501 1514
1502 1515
1503 Definition* EffectGraphVisitor::BuildInstantiatedTypeArguments( 1516 Definition* EffectGraphVisitor::BuildInstantiatedTypeArguments(
1504 intptr_t token_index, 1517 intptr_t token_index,
1505 const AbstractTypeArguments& type_arguments) { 1518 const AbstractTypeArguments& type_arguments) {
1506 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) { 1519 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
1507 BindInstr* type_args = 1520 BindInstr* type_args =
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
1834 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { 1847 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const {
1835 return (node == owner()->parsed_function().node_sequence()) && 1848 return (node == owner()->parsed_function().node_sequence()) &&
1836 (owner()->parsed_function().saved_context_var() != NULL); 1849 (owner()->parsed_function().saved_context_var() != NULL);
1837 } 1850 }
1838 1851
1839 1852
1840 void EffectGraphVisitor::UnchainContext() { 1853 void EffectGraphVisitor::UnchainContext() {
1841 BindInstr* context = new BindInstr(new CurrentContextComp()); 1854 BindInstr* context = new BindInstr(new CurrentContextComp());
1842 AddInstruction(context); 1855 AddInstruction(context);
1843 BindInstr* parent = 1856 BindInstr* parent =
1844 new BindInstr(new NativeLoadFieldComp( 1857 new BindInstr(
1845 new UseVal(context), Context::parent_offset())); 1858 new NativeLoadFieldComp(
1859 new UseVal(context),
1860 Context::parent_offset(),
1861 Type::ZoneHandle())); // Not an instance, no type.
1846 AddInstruction(parent); 1862 AddInstruction(parent);
1847 AddInstruction(new DoInstr(new StoreContextComp(new UseVal(parent)))); 1863 AddInstruction(new DoInstr(new StoreContextComp(new UseVal(parent))));
1848 } 1864 }
1849 1865
1850 1866
1851 // <Statement> ::= Sequence { scope: LocalScope 1867 // <Statement> ::= Sequence { scope: LocalScope
1852 // nodes: <Statement>* 1868 // nodes: <Statement>*
1853 // label: SourceLabel } 1869 // label: SourceLabel }
1854 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { 1870 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
1855 LocalScope* scope = node->scope(); 1871 LocalScope* scope = node->scope();
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1926 Computation* clear_local = 1942 Computation* clear_local =
1927 BuildStoreLocal(*temp_local, new UseVal(null_constant)); 1943 BuildStoreLocal(*temp_local, new UseVal(null_constant));
1928 AddInstruction(new DoInstr(clear_local)); 1944 AddInstruction(new DoInstr(clear_local));
1929 } 1945 }
1930 } 1946 }
1931 } 1947 }
1932 } 1948 }
1933 1949
1934 if (FLAG_enable_type_checks && 1950 if (FLAG_enable_type_checks &&
1935 (node == owner()->parsed_function().node_sequence())) { 1951 (node == owner()->parsed_function().node_sequence())) {
1936 const int num_params = 1952 const Function& function = owner()->parsed_function().function();
1937 owner()->parsed_function().function().NumberOfParameters(); 1953 const int num_params = function.NumberOfParameters();
1938 for (int pos = 0; pos < num_params; pos++) { 1954 int pos = 0;
1955 if (function.IsConstructor()) {
1956 // Skip type checking of receiver and phase for constructor functions.
1957 pos = 2;
1958 } else if (function.IsFactory() || function.IsDynamicFunction()) {
1959 // Skip type checking of type arguments for factory functions.
1960 // Skip type checking of receiver for instance functions.
1961 pos = 1;
1962 }
1963 while (pos < num_params) {
1939 const LocalVariable& parameter = *scope->VariableAt(pos); 1964 const LocalVariable& parameter = *scope->VariableAt(pos);
1940 ASSERT(parameter.owner() == scope); 1965 ASSERT(parameter.owner() == scope);
1941 if (!CanSkipTypeCheck(NULL, parameter.type())) { 1966 if (!CanSkipTypeCheck(NULL, parameter.type())) {
1942 BindInstr* load = new BindInstr(BuildLoadLocal(parameter)); 1967 BindInstr* load = new BindInstr(BuildLoadLocal(parameter));
1943 AddInstruction(load); 1968 AddInstruction(load);
1944 BuildAssertAssignable(parameter.token_index(), 1969 BuildAssertAssignable(parameter.token_index(),
1945 new UseVal(load), 1970 new UseVal(load),
1946 parameter.type(), 1971 parameter.type(),
1947 parameter.name()); 1972 parameter.name());
1948 } 1973 }
1974 pos++;
1949 } 1975 }
1950 } 1976 }
1951 1977
1952 intptr_t i = 0; 1978 intptr_t i = 0;
1953 while (is_open() && (i < node->length())) { 1979 while (is_open() && (i < node->length())) {
1954 EffectGraphVisitor for_effect(owner(), temp_index()); 1980 EffectGraphVisitor for_effect(owner(), temp_index());
1955 node->NodeAt(i++)->Visit(&for_effect); 1981 node->NodeAt(i++)->Visit(&for_effect);
1956 Append(for_effect); 1982 Append(for_effect);
1957 if (!is_open()) { 1983 if (!is_open()) {
1958 // E.g., because of a JumpNode. 1984 // E.g., because of a JumpNode.
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
2283 char* chars = reinterpret_cast<char*>( 2309 char* chars = reinterpret_cast<char*>(
2284 Isolate::Current()->current_zone()->Allocate(len)); 2310 Isolate::Current()->current_zone()->Allocate(len));
2285 OS::SNPrint(chars, len, kFormat, function_name, reason); 2311 OS::SNPrint(chars, len, kFormat, function_name, reason);
2286 const Error& error = Error::Handle( 2312 const Error& error = Error::Handle(
2287 LanguageError::New(String::Handle(String::New(chars)))); 2313 LanguageError::New(String::Handle(String::New(chars))));
2288 Isolate::Current()->long_jump_base()->Jump(1, error); 2314 Isolate::Current()->long_jump_base()->Jump(1, error);
2289 } 2315 }
2290 2316
2291 2317
2292 } // namespace dart 2318 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698