| 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/class_finalizer.h" | 5 #include "vm/class_finalizer.h" |
| 6 | 6 |
| 7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
| 8 #include "vm/heap.h" | 8 #include "vm/heap.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 // Collect superclasses that were already finalized before this run of | 131 // Collect superclasses that were already finalized before this run of |
| 132 // finalization. | 132 // finalization. |
| 133 CollectFinalizedSuperClasses(class_array, &added_subclasses_to_cids); | 133 CollectFinalizedSuperClasses(class_array, &added_subclasses_to_cids); |
| 134 Class& cls = Class::Handle(); | 134 Class& cls = Class::Handle(); |
| 135 // First resolve all superclasses. | 135 // First resolve all superclasses. |
| 136 for (intptr_t i = 0; i < class_array.Length(); i++) { | 136 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 137 cls ^= class_array.At(i); | 137 cls ^= class_array.At(i); |
| 138 if (FLAG_trace_class_finalization) { | 138 if (FLAG_trace_class_finalization) { |
| 139 OS::Print("Resolving super and interfaces: %s\n", cls.ToCString()); | 139 OS::Print("Resolving super and interfaces: %s\n", cls.ToCString()); |
| 140 } | 140 } |
| 141 ResolveSuperType(cls); | |
| 142 GrowableArray<intptr_t> visited_interfaces; | 141 GrowableArray<intptr_t> visited_interfaces; |
| 143 ResolveInterfaces(cls, &visited_interfaces); | 142 ResolveSuperTypeAndInterfaces(cls, &visited_interfaces); |
| 144 } | 143 } |
| 145 // Finalize all classes. | 144 // Finalize all classes. |
| 146 for (intptr_t i = 0; i < class_array.Length(); i++) { | 145 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 147 cls ^= class_array.At(i); | 146 cls ^= class_array.At(i); |
| 148 FinalizeClass(cls); | 147 FinalizeClass(cls); |
| 149 } | 148 } |
| 150 if (FLAG_print_classes) { | 149 if (FLAG_print_classes) { |
| 151 for (intptr_t i = 0; i < class_array.Length(); i++) { | 150 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 152 cls ^= class_array.At(i); | 151 cls ^= class_array.At(i); |
| 153 PrintClassInformation(cls); | 152 PrintClassInformation(cls); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 } else { | 301 } else { |
| 303 LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); | 302 LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
| 304 lib_prefix = unresolved_class.library_prefix(); | 303 lib_prefix = unresolved_class.library_prefix(); |
| 305 ASSERT(!lib_prefix.IsNull()); | 304 ASSERT(!lib_prefix.IsNull()); |
| 306 resolved_class = lib_prefix.LookupLocalClass(class_name); | 305 resolved_class = lib_prefix.LookupLocalClass(class_name); |
| 307 } | 306 } |
| 308 return resolved_class.raw(); | 307 return resolved_class.raw(); |
| 309 } | 308 } |
| 310 | 309 |
| 311 | 310 |
| 312 // Resolve unresolved supertype (String -> Class). | |
| 313 void ClassFinalizer::ResolveSuperType(const Class& cls) { | |
| 314 if (cls.is_finalized()) { | |
| 315 return; | |
| 316 } | |
| 317 Type& super_type = Type::Handle(cls.super_type()); | |
| 318 if (super_type.IsNull()) { | |
| 319 return; | |
| 320 } | |
| 321 // Resolve failures lead to a longjmp. | |
| 322 ResolveType(cls, super_type, kCanonicalizeWellFormed); | |
| 323 const Class& super_class = Class::Handle(super_type.type_class()); | |
| 324 // If cls belongs to core lib or to core lib's implementation, restrictions | |
| 325 // about allowed interfaces are lifted. | |
| 326 if (cls.library() != Library::CoreLibrary()) { | |
| 327 // Prevent extending core implementation classes. | |
| 328 bool is_error = false; | |
| 329 switch (super_class.id()) { | |
| 330 case kNumberCid: | |
| 331 case kIntegerCid: | |
| 332 case kSmiCid: | |
| 333 case kMintCid: | |
| 334 case kBigintCid: | |
| 335 case kDoubleCid: | |
| 336 case kOneByteStringCid: | |
| 337 case kTwoByteStringCid: | |
| 338 case kExternalOneByteStringCid: | |
| 339 case kExternalTwoByteStringCid: | |
| 340 case kBoolCid: | |
| 341 case kArrayCid: | |
| 342 case kImmutableArrayCid: | |
| 343 case kGrowableObjectArrayCid: | |
| 344 case kInt8ArrayCid: | |
| 345 case kExternalInt8ArrayCid: | |
| 346 case kUint8ArrayCid: | |
| 347 case kUint8ClampedArrayCid: | |
| 348 case kExternalUint8ArrayCid: | |
| 349 case kExternalUint8ClampedArrayCid: | |
| 350 case kInt16ArrayCid: | |
| 351 case kExternalInt16ArrayCid: | |
| 352 case kUint16ArrayCid: | |
| 353 case kExternalUint16ArrayCid: | |
| 354 case kInt32ArrayCid: | |
| 355 case kExternalInt32ArrayCid: | |
| 356 case kUint32ArrayCid: | |
| 357 case kExternalUint32ArrayCid: | |
| 358 case kInt64ArrayCid: | |
| 359 case kExternalInt64ArrayCid: | |
| 360 case kUint64ArrayCid: | |
| 361 case kExternalUint64ArrayCid: | |
| 362 case kFloat32ArrayCid: | |
| 363 case kExternalFloat32ArrayCid: | |
| 364 case kFloat64ArrayCid: | |
| 365 case kExternalFloat64ArrayCid: | |
| 366 case kDartFunctionCid: | |
| 367 case kWeakPropertyCid: | |
| 368 is_error = true; | |
| 369 break; | |
| 370 default: { | |
| 371 // Special case: classes for which we don't have a known class id. | |
| 372 // TODO(regis): Why isn't comparing to kIntegerCid enough? | |
| 373 if (Type::Handle(Type::Double()).type_class() == super_class.raw() || | |
| 374 Type::Handle(Type::IntType()).type_class() == super_class.raw() || | |
| 375 Type::Handle( | |
| 376 Type::StringType()).type_class() == super_class.raw()) { | |
| 377 is_error = true; | |
| 378 } | |
| 379 break; | |
| 380 } | |
| 381 } | |
| 382 if (is_error) { | |
| 383 const Script& script = Script::Handle(cls.script()); | |
| 384 ReportError(script, cls.token_pos(), | |
| 385 "'%s' is not allowed to extend '%s'", | |
| 386 String::Handle(cls.Name()).ToCString(), | |
| 387 String::Handle(super_class.Name()).ToCString()); | |
| 388 } | |
| 389 } | |
| 390 return; | |
| 391 } | |
| 392 | |
| 393 | |
| 394 void ClassFinalizer::ResolveRedirectingFactoryTarget( | 311 void ClassFinalizer::ResolveRedirectingFactoryTarget( |
| 395 const Class& cls, | 312 const Class& cls, |
| 396 const Function& factory, | 313 const Function& factory, |
| 397 const GrowableObjectArray& visited_factories) { | 314 const GrowableObjectArray& visited_factories) { |
| 398 ASSERT(factory.IsRedirectingFactory()); | 315 ASSERT(factory.IsRedirectingFactory()); |
| 399 | 316 |
| 400 // Check for redirection cycle. | 317 // Check for redirection cycle. |
| 401 for (int i = 0; i < visited_factories.Length(); i++) { | 318 for (int i = 0; i < visited_factories.Length(); i++) { |
| 402 if (visited_factories.At(i) == factory.raw()) { | 319 if (visited_factories.At(i) == factory.raw()) { |
| 403 // A redirection cycle is reported as a compile-time error. | 320 // A redirection cycle is reported as a compile-time error. |
| (...skipping 915 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 return false; | 1236 return false; |
| 1320 } | 1237 } |
| 1321 } | 1238 } |
| 1322 } | 1239 } |
| 1323 } | 1240 } |
| 1324 visited->RemoveLast(); | 1241 visited->RemoveLast(); |
| 1325 return true; | 1242 return true; |
| 1326 } | 1243 } |
| 1327 | 1244 |
| 1328 | 1245 |
| 1329 // Walks the graph of explicitly declared interfaces of classes and | 1246 // Recursively walks the graph of explicitly declared super type and |
| 1330 // interfaces recursively. Resolves unresolved interfaces. | 1247 // interfaces, resolving unresolved super types and interfaces. |
| 1331 // Returns false if there is an interface reference that cannot be | 1248 // Reports an error if there is an interface reference that cannot be |
| 1332 // resolved, or if there is a cycle in the graph. We detect cycles by | 1249 // resolved, or if there is a cycle in the graph. We detect cycles by |
| 1333 // remembering interfaces we've visited in each path through the | 1250 // remembering interfaces we've visited in each path through the |
| 1334 // graph. If we visit an interface a second time on a given path, | 1251 // graph. If we visit an interface a second time on a given path, |
| 1335 // we found a loop. | 1252 // we found a loop. |
| 1336 void ClassFinalizer::ResolveInterfaces(const Class& cls, | 1253 void ClassFinalizer::ResolveSuperTypeAndInterfaces( |
| 1337 GrowableArray<intptr_t>* visited) { | 1254 const Class& cls, GrowableArray<intptr_t>* visited) { |
| 1338 ASSERT(visited != NULL); | 1255 ASSERT(visited != NULL); |
| 1339 const intptr_t cls_index = cls.id(); | 1256 const intptr_t cls_index = cls.id(); |
| 1340 for (int i = 0; i < visited->length(); i++) { | 1257 for (int i = 0; i < visited->length(); i++) { |
| 1341 if ((*visited)[i] == cls_index) { | 1258 if ((*visited)[i] == cls_index) { |
| 1342 // We have already visited interface class 'cls'. We found a cycle. | 1259 // We have already visited class 'cls'. We found a cycle. |
| 1343 const String& interface_name = String::Handle(cls.Name()); | 1260 const String& class_name = String::Handle(cls.Name()); |
| 1344 const Script& script = Script::Handle(cls.script()); | 1261 const Script& script = Script::Handle(cls.script()); |
| 1345 ReportError(script, cls.token_pos(), | 1262 ReportError(script, cls.token_pos(), |
| 1346 "cyclic reference found for interface '%s'", | 1263 "cyclic reference found for class '%s'", |
| 1347 interface_name.ToCString()); | 1264 class_name.ToCString()); |
| 1348 } | 1265 } |
| 1349 } | 1266 } |
| 1350 | 1267 |
| 1351 // If the class/interface has no explicit interfaces, we are done. | 1268 // If the class/interface has no explicit super class/interfaces, we are done. |
| 1269 Type& super_type = Type::Handle(cls.super_type()); |
| 1352 Array& super_interfaces = Array::Handle(cls.interfaces()); | 1270 Array& super_interfaces = Array::Handle(cls.interfaces()); |
| 1353 if (super_interfaces.Length() == 0) { | 1271 if ((super_type.IsNull() || super_type.IsObjectType()) && |
| 1272 (super_interfaces.Length() == 0)) { |
| 1354 return; | 1273 return; |
| 1355 } | 1274 } |
| 1356 | 1275 |
| 1357 // If cls belongs to core lib or to core lib's implementation, restrictions | 1276 // If cls belongs to core lib or to core lib's implementation, restrictions |
| 1358 // about allowed interfaces are lifted. | 1277 // about allowed interfaces are lifted. |
| 1359 const bool cls_belongs_to_core_lib = cls.library() == Library::CoreLibrary(); | 1278 const bool cls_belongs_to_core_lib = cls.library() == Library::CoreLibrary(); |
| 1360 | 1279 |
| 1361 // Resolve and check the interfaces of cls. | 1280 // Resolve and check the super type and interfaces of cls. |
| 1362 visited->Add(cls_index); | 1281 visited->Add(cls_index); |
| 1363 AbstractType& interface = AbstractType::Handle(); | 1282 AbstractType& interface = AbstractType::Handle(); |
| 1364 Class& interface_class = Class::Handle(); | 1283 Class& interface_class = Class::Handle(); |
| 1284 |
| 1285 // Resolve super type. Failures lead to a longjmp. |
| 1286 ResolveType(cls, super_type, kCanonicalizeWellFormed); |
| 1287 |
| 1288 // If cls belongs to core lib or to core lib's implementation, restrictions |
| 1289 interface_class = super_type.type_class(); |
| 1290 // If cls belongs to core lib or to core lib's implementation, restrictions |
| 1291 // about allowed interfaces are lifted. |
| 1292 if (!cls_belongs_to_core_lib) { |
| 1293 // Prevent extending core implementation classes. |
| 1294 bool is_error = false; |
| 1295 switch (interface_class.id()) { |
| 1296 case kNumberCid: |
| 1297 case kIntegerCid: // Class Integer, not int. |
| 1298 case kSmiCid: |
| 1299 case kMintCid: |
| 1300 case kBigintCid: |
| 1301 case kDoubleCid: // Class Double, not double. |
| 1302 case kOneByteStringCid: |
| 1303 case kTwoByteStringCid: |
| 1304 case kExternalOneByteStringCid: |
| 1305 case kExternalTwoByteStringCid: |
| 1306 case kBoolCid: |
| 1307 case kArrayCid: |
| 1308 case kImmutableArrayCid: |
| 1309 case kGrowableObjectArrayCid: |
| 1310 case kInt8ArrayCid: |
| 1311 case kExternalInt8ArrayCid: |
| 1312 case kUint8ArrayCid: |
| 1313 case kUint8ClampedArrayCid: |
| 1314 case kExternalUint8ArrayCid: |
| 1315 case kExternalUint8ClampedArrayCid: |
| 1316 case kInt16ArrayCid: |
| 1317 case kExternalInt16ArrayCid: |
| 1318 case kUint16ArrayCid: |
| 1319 case kExternalUint16ArrayCid: |
| 1320 case kInt32ArrayCid: |
| 1321 case kExternalInt32ArrayCid: |
| 1322 case kUint32ArrayCid: |
| 1323 case kExternalUint32ArrayCid: |
| 1324 case kInt64ArrayCid: |
| 1325 case kExternalInt64ArrayCid: |
| 1326 case kUint64ArrayCid: |
| 1327 case kExternalUint64ArrayCid: |
| 1328 case kFloat32ArrayCid: |
| 1329 case kExternalFloat32ArrayCid: |
| 1330 case kFloat64ArrayCid: |
| 1331 case kExternalFloat64ArrayCid: |
| 1332 case kDartFunctionCid: |
| 1333 case kWeakPropertyCid: |
| 1334 is_error = true; |
| 1335 break; |
| 1336 default: { |
| 1337 // Special case: classes for which we don't have a known class id. |
| 1338 if (super_type.IsDoubleType() || |
| 1339 super_type.IsIntType() || |
| 1340 super_type.IsStringType()) { |
| 1341 is_error = true; |
| 1342 } |
| 1343 break; |
| 1344 } |
| 1345 } |
| 1346 if (is_error) { |
| 1347 const Script& script = Script::Handle(cls.script()); |
| 1348 ReportError(script, cls.token_pos(), |
| 1349 "'%s' is not allowed to extend '%s'", |
| 1350 String::Handle(cls.Name()).ToCString(), |
| 1351 String::Handle(interface_class.Name()).ToCString()); |
| 1352 } |
| 1353 } |
| 1354 // Now resolve the super interfaces of the super type. |
| 1355 ResolveSuperTypeAndInterfaces(interface_class, visited); |
| 1356 |
| 1357 // Resolve interfaces. Failures lead to a longjmp. |
| 1365 for (intptr_t i = 0; i < super_interfaces.Length(); i++) { | 1358 for (intptr_t i = 0; i < super_interfaces.Length(); i++) { |
| 1366 interface ^= super_interfaces.At(i); | 1359 interface ^= super_interfaces.At(i); |
| 1367 ResolveType(cls, interface, kCanonicalizeWellFormed); | 1360 ResolveType(cls, interface, kCanonicalizeWellFormed); |
| 1368 if (interface.IsTypeParameter()) { | 1361 if (interface.IsTypeParameter()) { |
| 1369 const Script& script = Script::Handle(cls.script()); | 1362 const Script& script = Script::Handle(cls.script()); |
| 1370 ReportError(script, cls.token_pos(), | 1363 ReportError(script, cls.token_pos(), |
| 1371 "type parameter '%s' cannot be used as interface", | 1364 "type parameter '%s' cannot be used as interface", |
| 1372 String::Handle(interface.Name()).ToCString()); | 1365 String::Handle(interface.Name()).ToCString()); |
| 1373 } | 1366 } |
| 1374 interface_class = interface.type_class(); | 1367 interface_class = interface.type_class(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1392 interface.IsDynamicType()) { | 1385 interface.IsDynamicType()) { |
| 1393 const Script& script = Script::Handle(cls.script()); | 1386 const Script& script = Script::Handle(cls.script()); |
| 1394 ReportError(script, cls.token_pos(), | 1387 ReportError(script, cls.token_pos(), |
| 1395 "'%s' is not allowed to extend or implement '%s'", | 1388 "'%s' is not allowed to extend or implement '%s'", |
| 1396 String::Handle(cls.Name()).ToCString(), | 1389 String::Handle(cls.Name()).ToCString(), |
| 1397 String::Handle(interface_class.Name()).ToCString()); | 1390 String::Handle(interface_class.Name()).ToCString()); |
| 1398 } | 1391 } |
| 1399 } | 1392 } |
| 1400 interface_class.set_is_implemented(); | 1393 interface_class.set_is_implemented(); |
| 1401 // Now resolve the super interfaces. | 1394 // Now resolve the super interfaces. |
| 1402 ResolveInterfaces(interface_class, visited); | 1395 ResolveSuperTypeAndInterfaces(interface_class, visited); |
| 1403 } | 1396 } |
| 1404 visited->RemoveLast(); | 1397 visited->RemoveLast(); |
| 1405 } | 1398 } |
| 1406 | 1399 |
| 1407 | 1400 |
| 1408 // A class is marked as constant if it has one constant constructor. | 1401 // A class is marked as constant if it has one constant constructor. |
| 1409 // A constant class: | 1402 // A constant class: |
| 1410 // - may extend only const classes. | 1403 // - may extend only const classes. |
| 1411 // - has only const instance fields. | 1404 // - has only const instance fields. |
| 1412 // Note: we must check for cycles before checking for const properties. | 1405 // Note: we must check for cycles before checking for const properties. |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1582 void ClassFinalizer::ReportError(const char* format, ...) { | 1575 void ClassFinalizer::ReportError(const char* format, ...) { |
| 1583 va_list args; | 1576 va_list args; |
| 1584 va_start(args, format); | 1577 va_start(args, format); |
| 1585 const Error& error = Error::Handle( | 1578 const Error& error = Error::Handle( |
| 1586 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); | 1579 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); |
| 1587 va_end(args); | 1580 va_end(args); |
| 1588 ReportError(error); | 1581 ReportError(error); |
| 1589 } | 1582 } |
| 1590 | 1583 |
| 1591 } // namespace dart | 1584 } // namespace dart |
| OLD | NEW |