Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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/precompiler.h" | 5 #include "vm/precompiler.h" |
| 6 | 6 |
| 7 #include "vm/compiler.h" | |
| 7 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
| 9 #include "vm/longjump.h" | |
| 8 #include "vm/object.h" | 10 #include "vm/object.h" |
| 9 #include "vm/object_store.h" | 11 #include "vm/object_store.h" |
| 10 #include "vm/compiler.h" | 12 #include "vm/resolver.h" |
| 11 #include "vm/longjump.h" | 13 #include "vm/symbols.h" |
| 12 | 14 |
| 13 namespace dart { | 15 namespace dart { |
| 14 | 16 |
| 15 | 17 |
| 18 #define I (isolate()) | |
| 19 #define Z (zone()) | |
| 20 | |
| 21 | |
| 16 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); | 22 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); |
| 17 | 23 |
| 18 | 24 |
| 19 static RawError* CompileFunction(const Function& func) { | 25 static void Jump(const Error& error) { |
| 20 Thread* thread = Thread::Current(); | 26 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 21 Error& error = Error::Handle(); | |
| 22 if (func.is_abstract() || func.IsRedirectingFactory()) { | |
| 23 return error.raw(); | |
| 24 } | |
| 25 | |
| 26 if (!func.HasCode()) { | |
| 27 if (FLAG_trace_precompiler) { | |
| 28 OS::Print(" Precompiling %s (%" Pd ")\n", | |
| 29 func.ToQualifiedCString(), | |
| 30 func.token_pos()); | |
| 31 } | |
| 32 error = Compiler::CompileFunction(thread, func); | |
| 33 if (!error.IsNull()) { | |
| 34 return error.raw(); | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 if ((func.kind() == RawFunction::kRegularFunction) && !func.is_static()) { | |
| 39 const String& name = String::Handle(func.name()); | |
| 40 if (!Field::IsGetterName(name) && !Field::IsSetterName(name)) { | |
| 41 const Function& closure_func = | |
| 42 Function::Handle(func.ImplicitClosureFunction()); | |
| 43 ASSERT(!closure_func.IsNull()); | |
| 44 error = CompileFunction(closure_func); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 return error.raw(); | |
| 49 } | |
| 50 | |
| 51 | |
| 52 static RawError* CompileClass(const Class& cls) { | |
| 53 if (FLAG_trace_precompiler) { | |
| 54 OS::Print(" Precompiling %s\n", cls.ToCString()); | |
| 55 } | |
| 56 | |
| 57 Error& error = Error::Handle(); | |
| 58 error = cls.EnsureIsFinalized(Isolate::Current()); | |
| 59 if (!error.IsNull()) { | |
| 60 return error.raw(); | |
| 61 } | |
| 62 | |
| 63 const Array& fields = Array::Handle(cls.fields()); | |
| 64 Field& field = Field::Handle(); | |
| 65 for (intptr_t i = 0; i < fields.Length(); i++) { | |
| 66 field ^= fields.At(i); | |
| 67 ASSERT(!field.IsNull()); | |
| 68 if (field.is_static() && field.has_initializer()) { | |
| 69 if (FLAG_trace_precompiler) { | |
| 70 OS::Print(" Precompiling initializer for %s\n", field.ToCString()); | |
| 71 } | |
| 72 Compiler::CompileStaticInitializer(field); | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 const Array& functions = Array::Handle(cls.functions()); | |
| 77 Function& func = Function::Handle(); | |
| 78 for (intptr_t i = 0; i < functions.Length(); i++) { | |
| 79 func ^= functions.At(i); | |
| 80 ASSERT(!func.IsNull()); | |
| 81 error = CompileFunction(func); | |
| 82 if (!error.IsNull()) { | |
| 83 return error.raw(); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 return error.raw(); | |
| 88 } | |
| 89 | |
| 90 | |
| 91 static RawError* CompileLibrary(const Library& lib) { | |
| 92 if (FLAG_trace_precompiler) { | |
| 93 OS::Print("Precompiling %s\n", lib.ToCString()); | |
| 94 } | |
| 95 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 96 Class& cls = Class::Handle(); | |
| 97 Error& error = Error::Handle(); | |
| 98 while (it.HasNext()) { | |
| 99 cls = it.GetNextClass(); | |
| 100 error = CompileClass(cls); | |
| 101 if (!error.IsNull()) { | |
| 102 return error.raw(); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 return error.raw(); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 static RawError* InnerCompileAll() { | |
| 111 Error& error = Error::Handle(); | |
| 112 const GrowableObjectArray& libs = GrowableObjectArray::Handle( | |
| 113 Isolate::Current()->object_store()->libraries()); | |
| 114 Library& lib = Library::Handle(); | |
| 115 for (int i = 0; i < libs.Length(); i++) { | |
| 116 lib ^= libs.At(i); | |
| 117 error = CompileLibrary(lib); | |
| 118 if (!error.IsNull()) { | |
| 119 return error.raw(); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 if (FLAG_trace_precompiler) { | |
| 124 OS::Print("** Precompiling collected closures **\n"); | |
| 125 } | |
| 126 | |
| 127 const GrowableObjectArray& closures = | |
| 128 GrowableObjectArray::Handle(Isolate::Current()->collected_closures()); | |
| 129 Function& func = Function::Handle(); | |
| 130 if (!closures.IsNull()) { | |
| 131 for (int i = 0; i < closures.Length(); i++) { | |
| 132 func ^= closures.At(i); | |
| 133 error = CompileFunction(func); | |
| 134 if (!error.IsNull()) { | |
| 135 return error.raw(); | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 Isolate::Current()->set_collected_closures(GrowableObjectArray::Handle()); | |
| 140 | |
| 141 if (FLAG_trace_precompiler) { | |
| 142 OS::Print("*** Done precompiling ***\n"); | |
| 143 } | |
| 144 Isolate::Current()->set_compilation_allowed(false); | |
| 145 return error.raw(); | |
| 146 } | 27 } |
| 147 | 28 |
| 148 | 29 |
| 149 RawError* Precompiler::CompileAll() { | 30 RawError* Precompiler::CompileAll() { |
| 150 LongJumpScope jump; | 31 LongJumpScope jump; |
| 151 if (setjmp(*jump.Set()) == 0) { | 32 if (setjmp(*jump.Set()) == 0) { |
| 152 return InnerCompileAll(); | 33 Precompiler precompiler(Thread::Current()); |
| 34 precompiler.DoCompileAll(); | |
| 35 return Error::null(); | |
| 153 } else { | 36 } else { |
| 154 Isolate* isolate = Isolate::Current(); | 37 Isolate* isolate = Isolate::Current(); |
| 155 const Error& error = Error::Handle(isolate, | 38 const Error& error = Error::Handle(isolate->object_store()->sticky_error()); |
| 156 isolate->object_store()->sticky_error()); | |
| 157 isolate->object_store()->clear_sticky_error(); | 39 isolate->object_store()->clear_sticky_error(); |
| 158 return error.raw(); | 40 return error.raw(); |
| 159 } | 41 } |
| 160 } | 42 } |
| 161 | 43 |
| 44 | |
| 45 Precompiler::Precompiler(Thread* thread) : | |
| 46 thread_(thread), | |
| 47 zone_(thread->zone()), | |
| 48 isolate_(thread->isolate()), | |
| 49 changed_(false), | |
| 50 function_count_(0), | |
| 51 class_count_(0), | |
| 52 libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())), | |
| 53 pending_functions_(GrowableObjectArray::Handle(Z, | |
| 54 GrowableObjectArray::New())), | |
| 55 collected_closures_(GrowableObjectArray::Handle(Z, I->collected_closures())), | |
| 56 sent_selectors_(GrowableObjectArray::Handle(Z, GrowableObjectArray::New())), | |
| 57 error_(Error::Handle(Z)) { | |
| 58 } | |
| 59 | |
| 60 | |
| 61 void Precompiler::DoCompileAll() { | |
| 62 // Drop all existing code so we can use the presence of code as an indicator | |
| 63 // that we have already looked for the function's callees. | |
| 64 ClearAllCode(); | |
| 65 | |
| 66 // Start with the allocations and invocations that happen from C++. | |
| 67 AddRoots(); | |
| 68 | |
| 69 // TODO(rmacnak): Eagerly add field-invocation functions to all signature | |
| 70 // classes so closure calls don't go through the runtime. | |
| 71 | |
| 72 // Compile newly found targets and add their callees until we reach a fixed | |
| 73 // point. | |
| 74 Iterate(); | |
| 75 | |
| 76 CleanUp(); | |
| 77 | |
| 78 if (FLAG_trace_precompiler) { | |
| 79 OS::Print("Precompiled %" Pd " functions, %" Pd " dynamic types," | |
| 80 " %" Pd " dynamic selectors\n", | |
| 81 function_count_, | |
| 82 class_count_, | |
| 83 sent_selectors_.Length()); | |
| 84 } | |
| 85 | |
| 86 I->set_compilation_allowed(false); | |
| 87 } | |
| 88 | |
| 89 | |
| 90 void Precompiler::ClearAllCode() { | |
| 91 Library& lib = Library::Handle(Z); | |
| 92 Class& cls = Class::Handle(Z); | |
| 93 Array& functions = Array::Handle(Z); | |
| 94 Function& function = Function::Handle(Z); | |
| 95 | |
| 96 for (intptr_t i = 0; i < libraries_.Length(); i++) { | |
| 97 lib ^= libraries_.At(i); | |
| 98 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 99 while (it.HasNext()) { | |
| 100 cls = it.GetNextClass(); | |
| 101 error_ = cls.EnsureIsFinalized(I); | |
| 102 if (!error_.IsNull()) { | |
| 103 Jump(error_); | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 for (intptr_t i = 0; i < libraries_.Length(); i++) { | |
| 109 lib ^= libraries_.At(i); | |
| 110 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 111 while (it.HasNext()) { | |
| 112 cls = it.GetNextClass(); | |
| 113 functions = cls.functions(); | |
| 114 for (intptr_t i = 0; i < functions.Length(); i++) { | |
| 115 function ^= functions.At(i); | |
| 116 function.ClearCode(); | |
| 117 } | |
| 118 } | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 | |
| 123 void Precompiler::AddRoots() { | |
| 124 // Note that <rootlibrary>.main is not a root. The appropriate main will be | |
| 125 // discovered through _getMainClosure. | |
| 126 | |
| 127 AddSelector(Symbols::NoSuchMethod()); | |
| 128 | |
| 129 AddSelector(Symbols::Call()); // For speed, not correctness. | |
| 130 | |
| 131 // Allocated from C++. | |
| 132 static const intptr_t kExternallyAllocatedCids[] = { | |
| 133 kBoolCid, | |
| 134 kNullCid, | |
| 135 | |
| 136 kSmiCid, | |
| 137 kMintCid, | |
| 138 kBigintCid, | |
| 139 kDoubleCid, | |
| 140 | |
| 141 kOneByteStringCid, | |
| 142 kTwoByteStringCid, | |
| 143 kExternalOneByteStringCid, | |
| 144 kExternalTwoByteStringCid, | |
| 145 | |
| 146 kArrayCid, | |
| 147 kImmutableArrayCid, | |
| 148 kGrowableObjectArrayCid, | |
| 149 kLinkedHashMapCid, | |
| 150 | |
| 151 kTypedDataUint8ClampedArrayCid, | |
| 152 kTypedDataUint8ArrayCid, | |
| 153 kTypedDataUint16ArrayCid, | |
| 154 kTypedDataUint32ArrayCid, | |
| 155 kTypedDataUint64ArrayCid, | |
| 156 | |
| 157 kTypedDataInt8ArrayCid, | |
| 158 kTypedDataInt16ArrayCid, | |
| 159 kTypedDataInt32ArrayCid, | |
| 160 kTypedDataInt64ArrayCid, | |
| 161 | |
| 162 kExternalTypedDataUint8ArrayCid, | |
| 163 | |
| 164 kTypedDataFloat32ArrayCid, | |
| 165 kTypedDataFloat64ArrayCid, | |
| 166 | |
| 167 kTypedDataFloat32x4ArrayCid, | |
| 168 kTypedDataInt32x4ArrayCid, | |
| 169 kTypedDataFloat64x2ArrayCid, | |
| 170 | |
| 171 kInt32x4Cid, | |
| 172 kFloat32x4Cid, | |
| 173 kFloat64x2Cid, | |
| 174 | |
| 175 kTypeCid, | |
| 176 kTypeRefCid, | |
| 177 kTypeParameterCid, | |
| 178 kBoundedTypeCid, | |
| 179 kLibraryPrefixCid, | |
| 180 | |
| 181 kJSRegExpCid, | |
| 182 kUserTagCid, | |
| 183 kStacktraceCid, | |
| 184 kWeakPropertyCid, | |
| 185 kCapabilityCid, | |
| 186 ReceivePort::kClassId, | |
| 187 SendPort::kClassId, | |
| 188 | |
| 189 kIllegalCid | |
| 190 }; | |
| 191 | |
| 192 Class& cls = Class::Handle(Z); | |
| 193 for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) { | |
| 194 cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]); | |
| 195 AddClass(cls); | |
| 196 } | |
| 197 | |
| 198 static const struct { | |
| 199 const char* library_; | |
| 200 const char* class_; | |
| 201 const char* function_; | |
| 202 } kExternallyCalled[] = { | |
| 203 { "dart:_builtin", "::", "_getMainClosure" }, | |
| 204 { "dart:_builtin", "::", "_getPrintClosure" }, | |
| 205 { "dart:_builtin", "::", "_getUriBaseClosure" }, | |
| 206 { "dart:_builtin", "::", "_resolveUri" }, | |
| 207 { "dart:_builtin", "::", "_setWorkingDirectory" }, | |
| 208 { "dart:async", "::", "_setScheduleImmediateClosure" }, | |
| 209 { "dart:core", "_InternalError", "_InternalError." }, | |
| 210 { "dart:core", "_InvocationMirror", "_allocateInvocationMirror" }, | |
| 211 { "dart:io", "::", "_makeUint8ListView" }, | |
| 212 { "dart:io", "::", "_makeDatagram" }, | |
| 213 { "dart:io", "CertificateException", "CertificateException." }, | |
| 214 { "dart:io", "HandshakeException", "HandshakeException." }, | |
| 215 { "dart:io", "TlsException", "TlsException." }, | |
| 216 { "dart:io", "X509Certificate", "X509Certificate." }, | |
| 217 { "dart:io", "_ExternalBuffer", "set:data" }, | |
| 218 { "dart:io", "_Platform", "set:_nativeScript" }, | |
| 219 { "dart:io", "_ProcessStartStatus", "set:_errorCode" }, | |
| 220 { "dart:io", "_ProcessStartStatus", "set:_errorMessage" }, | |
| 221 { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" }, | |
| 222 { "dart:io", "_SecureFilterImpl", "get:SIZE" }, | |
| 223 { "dart:isolate", "::", "_getIsolateScheduleImmediateClosure" }, | |
| 224 { "dart:isolate", "::", "_startMainIsolate" }, | |
| 225 { "dart:isolate", "_RawReceivePortImpl", "_handleMessage" }, | |
| 226 { "dart:isolate", "_RawReceivePortImpl", "_lookupHandler" }, | |
| 227 { "dart:vmservice", "::", "_registerIsolate" }, | |
| 228 { "dart:vmservice", "::", "boot" }, | |
| 229 { "dart:vmservice_io", "::", "_addResource" }, | |
| 230 { "dart:vmservice_io", "::", "main" }, | |
| 231 | |
| 232 // Cf. Exceptions::Create | |
| 233 { "dart:core", "RangeError", "RangeError." }, | |
| 234 { "dart:core", "RangeError", "RangeError.range" }, | |
| 235 { "dart:core", "ArgumentError", "ArgumentError." }, | |
| 236 { "dart:core", "NoSuchMethodError", "NoSuchMethodError._withType" }, | |
| 237 { "dart:core", "FormatException", "FormatException." }, | |
| 238 { "dart:core", "UnsupportedError", "UnsupportedError." }, | |
| 239 { "dart:core", "NullThrownError", "NullThrownError." }, | |
| 240 { "dart:isolate", "IsolateSpawnException", "IsolateSpawnException." }, | |
| 241 { "dart:isolate", "_IsolateUnhandledException", | |
| 242 "_IsolateUnhandledException." }, | |
| 243 { "dart:core", "_JavascriptIntegerOverflowError", | |
| 244 "_JavascriptIntegerOverflowError." }, | |
| 245 { "dart:core", "_JavascriptCompatibilityError", | |
| 246 "_JavascriptCompatibilityError." }, | |
| 247 { "dart:core", "AssertionError", "AssertionError." }, | |
| 248 { "dart:core", "_CastError", "_CastError._create" }, | |
| 249 { "dart:core", "_TypeError", "_TypeError._create" }, | |
| 250 { "dart:core", "FallThroughError", "FallThroughError._create" }, | |
| 251 { "dart:core", "AbstractClassInstantiationError", | |
| 252 "AbstractClassInstantiationError._create" }, | |
| 253 { "dart:core", "CyclicInitializationError", | |
| 254 "CyclicInitializationError." }, | |
| 255 { "dart:core", "StackOverflowError", "StackOverflowError." }, | |
| 256 { "dart:core", "OutOfMemoryError", "OutOfMemoryError." }, | |
| 257 { NULL, NULL, NULL } | |
| 258 }; | |
| 259 | |
| 260 Library& lib = Library::Handle(Z); | |
| 261 Function& func = Function::Handle(Z); | |
| 262 String& library_name = String::Handle(Z); | |
| 263 String& class_name = String::Handle(Z); | |
| 264 String& function_name = String::Handle(Z); | |
| 265 for (intptr_t i = 0; kExternallyCalled[i].library_ != NULL; i++) { | |
| 266 library_name = Symbols::New(kExternallyCalled[i].library_); | |
| 267 class_name = Symbols::New(kExternallyCalled[i].class_); | |
| 268 function_name = Symbols::New(kExternallyCalled[i].function_); | |
| 269 | |
| 270 lib = Library::LookupLibrary(library_name); | |
| 271 if (lib.IsNull()) { | |
| 272 if (FLAG_trace_precompiler) { | |
| 273 OS::Print("WARNING: Missing %s\n", kExternallyCalled[i].library_); | |
| 274 } | |
| 275 continue; | |
| 276 } | |
| 277 | |
| 278 if (class_name.raw() == Symbols::TopLevel().raw()) { | |
| 279 func = lib.LookupFunctionAllowPrivate(function_name); | |
| 280 } else { | |
| 281 cls = lib.LookupClassAllowPrivate(class_name); | |
| 282 if (cls.IsNull()) { | |
| 283 if (FLAG_trace_precompiler) { | |
| 284 OS::Print("WARNING: Missing %s %s\n", | |
| 285 kExternallyCalled[i].library_, | |
| 286 kExternallyCalled[i].class_); | |
| 287 } | |
| 288 continue; | |
| 289 } | |
| 290 | |
| 291 ASSERT(!cls.IsNull()); | |
| 292 func = cls.LookupFunctionAllowPrivate(function_name); | |
| 293 } | |
| 294 | |
| 295 if (func.IsNull()) { | |
| 296 if (FLAG_trace_precompiler) { | |
| 297 OS::Print("WARNING: Missing %s %s %s\n", | |
| 298 kExternallyCalled[i].library_, | |
| 299 kExternallyCalled[i].class_, | |
| 300 kExternallyCalled[i].function_); | |
| 301 } | |
| 302 continue; | |
| 303 } | |
| 304 | |
| 305 AddFunction(func); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 | |
| 310 void Precompiler::Iterate() { | |
| 311 Function& function = Function::Handle(Z); | |
| 312 | |
| 313 while (changed_) { | |
| 314 changed_ = false; | |
| 315 | |
| 316 while (pending_functions_.Length() > 0) { | |
| 317 function ^= pending_functions_.RemoveLast(); | |
| 318 ProcessFunction(function); | |
| 319 } | |
| 320 | |
| 321 CheckForNewDynamicFunctions(); | |
| 322 | |
| 323 // Drain collected_closures last because additions to this list come from | |
| 324 // outside the Precompiler and so do not flip our changed_ flag. | |
| 325 while (collected_closures_.Length() > 0) { | |
| 326 function ^= collected_closures_.RemoveLast(); | |
| 327 ProcessFunction(function); | |
| 328 } | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 | |
| 333 void Precompiler::CleanUp() { | |
| 334 I->set_collected_closures(GrowableObjectArray::Handle(Z)); | |
| 335 | |
| 336 // TODO(rmacnak): Drop functions without code, classes without functions, etc. | |
| 337 } | |
| 338 | |
| 339 | |
| 340 void Precompiler::ProcessFunction(const Function& function) { | |
| 341 if (!function.HasCode()) { | |
| 342 function_count_++; | |
| 343 | |
| 344 if (FLAG_trace_precompiler) { | |
| 345 OS::Print("Precompiling %" Pd " %s (%" Pd ", %s)\n", | |
| 346 function_count_, | |
| 347 function.ToLibNamePrefixedQualifiedCString(), | |
| 348 function.token_pos(), | |
| 349 Function::KindToCString(function.kind())); | |
| 350 } | |
| 351 | |
| 352 ASSERT(!function.is_abstract()); | |
| 353 ASSERT(!function.IsRedirectingFactory()); | |
| 354 | |
| 355 error_ = Compiler::CompileFunction(thread_, function); | |
| 356 if (!error_.IsNull()) { | |
| 357 Jump(error_); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 ASSERT(function.HasCode()); | |
| 362 AddCalleesOf(function); | |
| 363 } | |
| 364 | |
| 365 | |
| 366 void Precompiler::AddCalleesOf(const Function& function) { | |
| 367 ASSERT(function.HasCode()); | |
| 368 | |
| 369 const Code& code = Code::Handle(Z, function.CurrentCode()); | |
| 370 | |
| 371 const Array& table = Array::Handle(Z, code.static_calls_target_table()); | |
| 372 Object& entry = Object::Handle(Z); | |
| 373 Function& target = Function::Handle(Z); | |
| 374 for (intptr_t i = 0; i < table.Length(); i++) { | |
| 375 entry = table.At(i); | |
| 376 if (entry.IsFunction()) { | |
| 377 target ^= table.At(i); | |
| 378 AddFunction(target); | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 #if defined(TARGET_ARCH_IA32) | |
| 383 FATAL("Callee scanning unimplemented for IA32"); | |
| 384 #endif | |
| 385 | |
| 386 const ObjectPool& pool = ObjectPool::Handle(Z, code.GetObjectPool()); | |
| 387 ICData& call_site = ICData::Handle(Z); | |
| 388 String& selector = String::Handle(Z); | |
| 389 Field& field = Field::Handle(Z); | |
| 390 Class& cls = Class::Handle(Z); | |
| 391 for (intptr_t i = 0; i < pool.Length(); i++) { | |
| 392 if (pool.InfoAt(i) == ObjectPool::kTaggedObject) { | |
| 393 entry = pool.ObjectAt(i); | |
| 394 if (entry.IsICData()) { | |
| 395 call_site ^= entry.raw(); | |
| 396 if (call_site.NumberOfChecks() == 1) { | |
| 397 // Probably a static call. | |
| 398 target = call_site.GetTargetAt(0); | |
| 399 AddFunction(target); | |
| 400 if (!target.is_static()) { | |
| 401 // Super call (should not enqueue selector) or dynamic call with a | |
| 402 // CHA prediction (should enqueue selector). | |
| 403 selector = call_site.target_name(); | |
| 404 AddSelector(selector); | |
| 405 } | |
| 406 } else { | |
| 407 // A dynamic call. | |
| 408 selector = call_site.target_name(); | |
| 409 AddSelector(selector); | |
| 410 } | |
| 411 } else if (entry.IsField()) { | |
| 412 // Potential need for field initializer. | |
| 413 field ^= entry.raw(); | |
| 414 AddField(field); | |
| 415 } else if (entry.IsInstance()) { | |
| 416 // Potential const object. | |
| 417 cls = entry.clazz(); | |
| 418 AddClass(cls); | |
| 419 } | |
| 420 } | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 | |
| 425 void Precompiler::AddField(const Field& field) { | |
| 426 if (field.is_static()) { | |
| 427 // Potential const object. Uninitialized field will harmlessly do a redudant | |
|
Florian Schneider
2015/08/04 08:20:01
*redundant
rmacnak
2015/08/04 18:34:28
Done.
| |
| 428 // add of the Null class. | |
| 429 const Object& value = Object::Handle(Z, field.value()); | |
| 430 const Class& cls = Class::Handle(Z, value.clazz()); | |
| 431 AddClass(cls); | |
| 432 | |
| 433 if (field.has_initializer()) { | |
| 434 if (field.initializer() != Function::null()) return; | |
| 435 | |
| 436 if (FLAG_trace_precompiler) { | |
| 437 OS::Print("Precompiling initializer for %s\n", field.ToCString()); | |
| 438 } | |
| 439 Compiler::CompileStaticInitializer(field); | |
| 440 | |
| 441 const Function& function = Function::Handle(Z, field.initializer()); | |
| 442 AddCalleesOf(function); | |
| 443 } | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 | |
| 448 void Precompiler::AddFunction(const Function& function) { | |
| 449 if (function.HasCode()) return; | |
| 450 | |
| 451 pending_functions_.Add(function); | |
| 452 changed_ = true; | |
| 453 } | |
| 454 | |
| 455 | |
| 456 bool Precompiler::IsSent(const String& selector) { | |
| 457 ASSERT(selector.IsSymbol()); | |
| 458 | |
| 459 // TODO(rmacnak): Use a proper set. | |
|
Florian Schneider
2015/08/04 08:20:01
You could use the one from runtime/vm/hash_map.h,
rmacnak
2015/08/04 18:34:28
I'll do that in the next CL.
| |
| 460 for (intptr_t i = 0; i < sent_selectors_.Length(); i++) { | |
| 461 if (sent_selectors_.At(i) == selector.raw()) { | |
| 462 return true; | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 return false; | |
| 467 } | |
| 468 | |
| 469 | |
| 470 void Precompiler::AddSelector(const String& selector) { | |
| 471 if (!IsSent(selector)) { | |
| 472 if (FLAG_trace_precompiler) { | |
| 473 OS::Print("Enqueueing selector %" Pd " %s\n", | |
| 474 sent_selectors_.Length(), | |
| 475 selector.ToCString()); | |
| 476 } | |
| 477 | |
| 478 sent_selectors_.Add(selector); | |
| 479 changed_ = true; | |
| 480 | |
| 481 if (!Field::IsGetterName(selector) && | |
| 482 !Field::IsSetterName(selector)) { | |
| 483 // Regular method may be call-through-getter. | |
| 484 // TODO(rmacnak): Do not create the symbol if it does not already exist. | |
| 485 String& getter = String::Handle(Field::GetterName(selector)); | |
| 486 getter = Symbols::New(getter); | |
| 487 AddSelector(getter); | |
| 488 } | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 | |
| 493 void Precompiler::AddClass(const Class& cls) { | |
| 494 if (cls.is_allocated()) return; | |
| 495 | |
| 496 class_count_++; | |
| 497 cls.set_is_allocated(); | |
| 498 changed_ = true; | |
| 499 | |
| 500 if (FLAG_trace_precompiler) { | |
| 501 OS::Print("Allocation %ld %s\n", class_count_, cls.ToCString()); | |
| 502 } | |
| 503 | |
| 504 const Class& superclass = Class::Handle(cls.SuperClass()); | |
| 505 if (!superclass.IsNull()) { | |
| 506 AddClass(superclass); | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 | |
| 511 void Precompiler::CheckForNewDynamicFunctions() { | |
| 512 Library& lib = Library::Handle(Z); | |
| 513 Class& cls = Class::Handle(Z); | |
| 514 Array& functions = Array::Handle(Z); | |
| 515 Function& function = Function::Handle(Z); | |
| 516 String& selector = String::Handle(Z); | |
| 517 | |
| 518 for (intptr_t i = 0; i < libraries_.Length(); i++) { | |
| 519 lib ^= libraries_.At(i); | |
| 520 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 521 while (it.HasNext()) { | |
| 522 cls = it.GetNextClass(); | |
| 523 | |
| 524 if (!cls.is_allocated()) { | |
| 525 bool has_compiled_constructor = false; | |
| 526 if (cls.allocation_stub() != Code::null()) { | |
| 527 // Regular objects. | |
| 528 has_compiled_constructor = true; | |
| 529 } else if (cls.is_synthesized_class()) { | |
| 530 // Enums. | |
| 531 has_compiled_constructor = true; | |
| 532 } else { | |
| 533 // Objects only allocated via const constructors, and not stored in a | |
| 534 // static field or code. | |
| 535 // E.g. A in | |
| 536 // class A { | |
| 537 // const A(); | |
| 538 // toString() => "Don't drop me!"; | |
| 539 // } | |
| 540 // class B { | |
| 541 // const a = const A(); | |
| 542 // const B(); | |
| 543 // static const theB = const B(); | |
| 544 // } | |
| 545 // main() => print(B.theB.a); | |
| 546 functions = cls.functions(); | |
| 547 for (intptr_t k = 0; k < functions.Length(); k++) { | |
| 548 function ^= functions.At(k); | |
| 549 if (function.IsGenerativeConstructor() && | |
| 550 function.HasCode()) { | |
| 551 has_compiled_constructor = true; | |
| 552 break; | |
| 553 } | |
| 554 } | |
| 555 } | |
| 556 if (!has_compiled_constructor) { | |
| 557 continue; | |
| 558 } | |
| 559 AddClass(cls); | |
| 560 } | |
| 561 | |
| 562 functions = cls.functions(); | |
| 563 for (intptr_t k = 0; k < functions.Length(); k++) { | |
| 564 function ^= functions.At(k); | |
| 565 | |
| 566 if (function.is_static() || function.is_abstract()) continue; | |
| 567 | |
| 568 // Don't bail out early if there is already code because we may discover | |
| 569 // the corresponding getter selector is sent in some later iteration. | |
| 570 // if (function.HasCode()) continue; | |
| 571 | |
| 572 selector = function.name(); | |
| 573 if (IsSent(selector)) { | |
| 574 AddFunction(function); | |
| 575 } | |
| 576 | |
| 577 if (function.kind() == RawFunction::kRegularFunction && | |
| 578 !Field::IsGetterName(selector) && | |
| 579 !Field::IsSetterName(selector)) { | |
| 580 // TODO(rmacnak): Do not create the symbol if it does not already | |
| 581 // exist. | |
| 582 selector = Field::GetterName(selector); | |
| 583 selector = Symbols::New(selector); | |
| 584 if (IsSent(selector)) { | |
| 585 function = function.ImplicitClosureFunction(); | |
| 586 AddFunction(function); | |
| 587 } | |
| 588 } | |
| 589 } | |
| 590 } | |
| 591 } | |
| 592 } | |
| 593 | |
| 162 } // namespace dart | 594 } // namespace dart |
| OLD | NEW |