Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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())); |
|
srdjan
2012/05/16 20:16:15
Why not pass dynamic type (meaning unknown) instea
regis
2012/05/16 23:20:37
I want to catch cases where the static type is req
| |
| 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); |
|
srdjan
2012/05/16 20:16:15
Needs a type as well, I think.
regis
2012/05/16 23:20:37
No, the type of interest is the type of the assign
| |
| 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())); |
|
srdjan
2012/05/16 20:16:15
dynamic type instead of null?
regis
2012/05/16 23:20:37
Same as above.
| |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1837 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { | 1850 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { |
| 1838 return (node == owner()->parsed_function().node_sequence()) && | 1851 return (node == owner()->parsed_function().node_sequence()) && |
| 1839 (owner()->parsed_function().saved_context_var() != NULL); | 1852 (owner()->parsed_function().saved_context_var() != NULL); |
| 1840 } | 1853 } |
| 1841 | 1854 |
| 1842 | 1855 |
| 1843 void EffectGraphVisitor::UnchainContext() { | 1856 void EffectGraphVisitor::UnchainContext() { |
| 1844 BindInstr* context = new BindInstr(new CurrentContextComp()); | 1857 BindInstr* context = new BindInstr(new CurrentContextComp()); |
| 1845 AddInstruction(context); | 1858 AddInstruction(context); |
| 1846 BindInstr* parent = | 1859 BindInstr* parent = |
| 1847 new BindInstr(new NativeLoadFieldComp( | 1860 new BindInstr( |
| 1848 new UseVal(context), Context::parent_offset())); | 1861 new NativeLoadFieldComp( |
| 1862 new UseVal(context), | |
| 1863 Context::parent_offset(), | |
| 1864 Type::ZoneHandle())); // Not an instance, no type. | |
| 1849 AddInstruction(parent); | 1865 AddInstruction(parent); |
| 1850 AddInstruction(new DoInstr(new StoreContextComp(new UseVal(parent)))); | 1866 AddInstruction(new DoInstr(new StoreContextComp(new UseVal(parent)))); |
| 1851 } | 1867 } |
| 1852 | 1868 |
| 1853 | 1869 |
| 1854 // <Statement> ::= Sequence { scope: LocalScope | 1870 // <Statement> ::= Sequence { scope: LocalScope |
| 1855 // nodes: <Statement>* | 1871 // nodes: <Statement>* |
| 1856 // label: SourceLabel } | 1872 // label: SourceLabel } |
| 1857 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 1873 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
| 1858 LocalScope* scope = node->scope(); | 1874 LocalScope* scope = node->scope(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1929 Computation* clear_local = | 1945 Computation* clear_local = |
| 1930 BuildStoreLocal(*temp_local, new UseVal(null_constant)); | 1946 BuildStoreLocal(*temp_local, new UseVal(null_constant)); |
| 1931 AddInstruction(new DoInstr(clear_local)); | 1947 AddInstruction(new DoInstr(clear_local)); |
| 1932 } | 1948 } |
| 1933 } | 1949 } |
| 1934 } | 1950 } |
| 1935 } | 1951 } |
| 1936 | 1952 |
| 1937 if (FLAG_enable_type_checks && | 1953 if (FLAG_enable_type_checks && |
| 1938 (node == owner()->parsed_function().node_sequence())) { | 1954 (node == owner()->parsed_function().node_sequence())) { |
| 1939 const int num_params = | 1955 const Function& function = owner()->parsed_function().function(); |
| 1940 owner()->parsed_function().function().NumberOfParameters(); | 1956 const int num_params = function.NumberOfParameters(); |
| 1941 for (int pos = 0; pos < num_params; pos++) { | 1957 int pos = 0; |
| 1958 if (function.IsConstructor()) { | |
| 1959 // Skip type checking of receiver and phase for constructor functions. | |
| 1960 pos = 2; | |
| 1961 } else if (function.IsFactory() || function.IsDynamicFunction()) { | |
| 1962 // Skip type checking of type arguments for factory functions. | |
| 1963 // Skip type checking of receiver for instance functions. | |
| 1964 pos = 1; | |
| 1965 } | |
| 1966 while (pos < num_params) { | |
| 1942 const LocalVariable& parameter = *scope->VariableAt(pos); | 1967 const LocalVariable& parameter = *scope->VariableAt(pos); |
| 1943 ASSERT(parameter.owner() == scope); | 1968 ASSERT(parameter.owner() == scope); |
| 1944 if (!CanSkipTypeCheck(NULL, parameter.type())) { | 1969 if (!CanSkipTypeCheck(NULL, parameter.type())) { |
| 1945 BindInstr* load = new BindInstr(BuildLoadLocal(parameter)); | 1970 BindInstr* load = new BindInstr(BuildLoadLocal(parameter)); |
| 1946 AddInstruction(load); | 1971 AddInstruction(load); |
| 1947 BuildAssertAssignable(parameter.token_index(), | 1972 BuildAssertAssignable(parameter.token_index(), |
| 1948 new UseVal(load), | 1973 new UseVal(load), |
| 1949 parameter.type(), | 1974 parameter.type(), |
| 1950 parameter.name()); | 1975 parameter.name()); |
| 1951 } | 1976 } |
| 1977 pos++; | |
| 1952 } | 1978 } |
| 1953 } | 1979 } |
| 1954 | 1980 |
| 1955 intptr_t i = 0; | 1981 intptr_t i = 0; |
| 1956 while (is_open() && (i < node->length())) { | 1982 while (is_open() && (i < node->length())) { |
| 1957 EffectGraphVisitor for_effect(owner(), temp_index()); | 1983 EffectGraphVisitor for_effect(owner(), temp_index()); |
| 1958 node->NodeAt(i++)->Visit(&for_effect); | 1984 node->NodeAt(i++)->Visit(&for_effect); |
| 1959 Append(for_effect); | 1985 Append(for_effect); |
| 1960 if (!is_open()) { | 1986 if (!is_open()) { |
| 1961 // E.g., because of a JumpNode. | 1987 // E.g., because of a JumpNode. |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2286 char* chars = reinterpret_cast<char*>( | 2312 char* chars = reinterpret_cast<char*>( |
| 2287 Isolate::Current()->current_zone()->Allocate(len)); | 2313 Isolate::Current()->current_zone()->Allocate(len)); |
| 2288 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2314 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2289 const Error& error = Error::Handle( | 2315 const Error& error = Error::Handle( |
| 2290 LanguageError::New(String::Handle(String::New(chars)))); | 2316 LanguageError::New(String::Handle(String::New(chars)))); |
| 2291 Isolate::Current()->long_jump_base()->Jump(1, error); | 2317 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2292 } | 2318 } |
| 2293 | 2319 |
| 2294 | 2320 |
| 2295 } // namespace dart | 2321 } // namespace dart |
| OLD | NEW |