| 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/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "vm/resolver.h" | 21 #include "vm/resolver.h" |
| 22 #include "vm/runtime_entry.h" | 22 #include "vm/runtime_entry.h" |
| 23 #include "vm/service_isolate.h" | 23 #include "vm/service_isolate.h" |
| 24 #include "vm/stack_frame.h" | 24 #include "vm/stack_frame.h" |
| 25 #include "vm/symbols.h" | 25 #include "vm/symbols.h" |
| 26 #include "vm/thread_registry.h" | 26 #include "vm/thread_registry.h" |
| 27 #include "vm/verifier.h" | 27 #include "vm/verifier.h" |
| 28 | 28 |
| 29 namespace dart { | 29 namespace dart { |
| 30 | 30 |
| 31 DEFINE_FLAG(int, max_subtype_cache_entries, 100, | 31 DEFINE_FLAG( |
| 32 int, |
| 33 max_subtype_cache_entries, |
| 34 100, |
| 32 "Maximum number of subtype cache entries (number of checks cached)."); | 35 "Maximum number of subtype cache entries (number of checks cached)."); |
| 33 DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000, | 36 DEFINE_FLAG( |
| 37 int, |
| 38 regexp_optimization_counter_threshold, |
| 39 1000, |
| 34 "RegExp's usage-counter value before it is optimized, -1 means never"); | 40 "RegExp's usage-counter value before it is optimized, -1 means never"); |
| 35 DEFINE_FLAG(int, reoptimization_counter_threshold, 4000, | 41 DEFINE_FLAG(int, |
| 36 "Counter threshold before a function gets reoptimized."); | 42 reoptimization_counter_threshold, |
| 43 4000, |
| 44 "Counter threshold before a function gets reoptimized."); |
| 37 DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization"); | 45 DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization"); |
| 38 DEFINE_FLAG(bool, trace_deoptimization_verbose, false, | 46 DEFINE_FLAG(bool, |
| 39 "Trace deoptimization verbose"); | 47 trace_deoptimization_verbose, |
| 48 false, |
| 49 "Trace deoptimization verbose"); |
| 40 DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling"); | 50 DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling"); |
| 41 DEFINE_FLAG(bool, trace_ic_miss_in_optimized, false, | 51 DEFINE_FLAG(bool, |
| 42 "Trace IC miss in optimized code"); | 52 trace_ic_miss_in_optimized, |
| 43 DEFINE_FLAG(bool, trace_optimized_ic_calls, false, | 53 false, |
| 44 "Trace IC calls in optimized code."); | 54 "Trace IC miss in optimized code"); |
| 55 DEFINE_FLAG(bool, |
| 56 trace_optimized_ic_calls, |
| 57 false, |
| 58 "Trace IC calls in optimized code."); |
| 45 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code."); | 59 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code."); |
| 46 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls"); | 60 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls"); |
| 47 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); | 61 DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); |
| 48 | 62 |
| 49 DECLARE_FLAG(int, max_deoptimization_counter_threshold); | 63 DECLARE_FLAG(int, max_deoptimization_counter_threshold); |
| 50 DECLARE_FLAG(bool, enable_inlining_annotations); | 64 DECLARE_FLAG(bool, enable_inlining_annotations); |
| 51 DECLARE_FLAG(bool, trace_compiler); | 65 DECLARE_FLAG(bool, trace_compiler); |
| 52 DECLARE_FLAG(bool, trace_optimizing_compiler); | 66 DECLARE_FLAG(bool, trace_optimizing_compiler); |
| 53 DECLARE_FLAG(int, max_polymorphic_checks); | 67 DECLARE_FLAG(int, max_polymorphic_checks); |
| 54 | 68 |
| 55 DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement."); | 69 DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement."); |
| 56 | 70 |
| 57 DEFINE_FLAG(int, stacktrace_every, 0, | 71 DEFINE_FLAG(int, |
| 72 stacktrace_every, |
| 73 0, |
| 58 "Compute debugger stacktrace on every N stack overflow checks"); | 74 "Compute debugger stacktrace on every N stack overflow checks"); |
| 59 DEFINE_FLAG(charp, stacktrace_filter, NULL, | 75 DEFINE_FLAG(charp, |
| 76 stacktrace_filter, |
| 77 NULL, |
| 60 "Compute stacktrace in named function on stack overflow checks"); | 78 "Compute stacktrace in named function on stack overflow checks"); |
| 61 DEFINE_FLAG(charp, deoptimize_filter, NULL, | 79 DEFINE_FLAG(charp, |
| 80 deoptimize_filter, |
| 81 NULL, |
| 62 "Deoptimize in named function on stack overflow checks"); | 82 "Deoptimize in named function on stack overflow checks"); |
| 63 | 83 |
| 64 DECLARE_FLAG(int, reload_every); | 84 DECLARE_FLAG(int, reload_every); |
| 65 DECLARE_FLAG(bool, reload_every_optimized); | 85 DECLARE_FLAG(bool, reload_every_optimized); |
| 66 DECLARE_FLAG(bool, reload_every_back_off); | 86 DECLARE_FLAG(bool, reload_every_back_off); |
| 67 | 87 |
| 68 #ifdef DEBUG | 88 #ifdef DEBUG |
| 69 DEFINE_FLAG(charp, gc_at_instance_allocation, NULL, | 89 DEFINE_FLAG(charp, |
| 90 gc_at_instance_allocation, |
| 91 NULL, |
| 70 "Perform a GC before allocation of instances of " | 92 "Perform a GC before allocation of instances of " |
| 71 "the specified class"); | 93 "the specified class"); |
| 72 #endif | 94 #endif |
| 73 | 95 |
| 74 DEFINE_RUNTIME_ENTRY(TraceFunctionEntry, 1) { | 96 DEFINE_RUNTIME_ENTRY(TraceFunctionEntry, 1) { |
| 75 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 97 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
| 76 const String& function_name = String::Handle(function.name()); | 98 const String& function_name = String::Handle(function.name()); |
| 77 const String& class_name = | 99 const String& class_name = |
| 78 String::Handle(Class::Handle(function.Owner()).Name()); | 100 String::Handle(Class::Handle(function.Owner()).Name()); |
| 79 OS::PrintErr("> Entering '%s.%s'\n", | 101 OS::PrintErr("> Entering '%s.%s'\n", class_name.ToCString(), |
| 80 class_name.ToCString(), function_name.ToCString()); | 102 function_name.ToCString()); |
| 81 } | 103 } |
| 82 | 104 |
| 83 | 105 |
| 84 DEFINE_RUNTIME_ENTRY(TraceFunctionExit, 1) { | 106 DEFINE_RUNTIME_ENTRY(TraceFunctionExit, 1) { |
| 85 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 107 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
| 86 const String& function_name = String::Handle(function.name()); | 108 const String& function_name = String::Handle(function.name()); |
| 87 const String& class_name = | 109 const String& class_name = |
| 88 String::Handle(Class::Handle(function.Owner()).Name()); | 110 String::Handle(Class::Handle(function.Owner()).Name()); |
| 89 OS::PrintErr("< Exiting '%s.%s'\n", | 111 OS::PrintErr("< Exiting '%s.%s'\n", class_name.ToCString(), |
| 90 class_name.ToCString(), function_name.ToCString()); | 112 function_name.ToCString()); |
| 91 } | 113 } |
| 92 | 114 |
| 93 | 115 |
| 94 DEFINE_RUNTIME_ENTRY(RangeError, 2) { | 116 DEFINE_RUNTIME_ENTRY(RangeError, 2) { |
| 95 const Instance& length = Instance::CheckedHandle(arguments.ArgAt(0)); | 117 const Instance& length = Instance::CheckedHandle(arguments.ArgAt(0)); |
| 96 const Instance& index = Instance::CheckedHandle(arguments.ArgAt(1)); | 118 const Instance& index = Instance::CheckedHandle(arguments.ArgAt(1)); |
| 97 if (!length.IsInteger()) { | 119 if (!length.IsInteger()) { |
| 98 // Throw: new ArgumentError.value(length, "length", "is not an integer"); | 120 // Throw: new ArgumentError.value(length, "length", "is not an integer"); |
| 99 const Array& args = Array::Handle(Array::New(3)); | 121 const Array& args = Array::Handle(Array::New(3)); |
| 100 args.SetAt(0, length); | 122 args.SetAt(0, length); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 const TypeArguments& instantiator = | 240 const TypeArguments& instantiator = |
| 219 TypeArguments::CheckedHandle(zone, arguments.ArgAt(1)); | 241 TypeArguments::CheckedHandle(zone, arguments.ArgAt(1)); |
| 220 ASSERT(!type.IsNull() && !type.IsInstantiated()); | 242 ASSERT(!type.IsNull() && !type.IsInstantiated()); |
| 221 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 243 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
| 222 Error& bound_error = Error::Handle(zone); | 244 Error& bound_error = Error::Handle(zone); |
| 223 type = | 245 type = |
| 224 type.InstantiateFrom(instantiator, &bound_error, NULL, NULL, Heap::kOld); | 246 type.InstantiateFrom(instantiator, &bound_error, NULL, NULL, Heap::kOld); |
| 225 if (!bound_error.IsNull()) { | 247 if (!bound_error.IsNull()) { |
| 226 // Throw a dynamic type error. | 248 // Throw a dynamic type error. |
| 227 const TokenPosition location = GetCallerLocation(); | 249 const TokenPosition location = GetCallerLocation(); |
| 228 String& bound_error_message = String::Handle( | 250 String& bound_error_message = |
| 229 zone, String::New(bound_error.ToErrorCString())); | 251 String::Handle(zone, String::New(bound_error.ToErrorCString())); |
| 230 Exceptions::CreateAndThrowTypeError( | 252 Exceptions::CreateAndThrowTypeError(location, AbstractType::Handle(zone), |
| 231 location, AbstractType::Handle(zone), AbstractType::Handle(zone), | 253 AbstractType::Handle(zone), |
| 232 Symbols::Empty(), bound_error_message); | 254 Symbols::Empty(), bound_error_message); |
| 233 UNREACHABLE(); | 255 UNREACHABLE(); |
| 234 } | 256 } |
| 235 if (type.IsTypeRef()) { | 257 if (type.IsTypeRef()) { |
| 236 type = TypeRef::Cast(type).type(); | 258 type = TypeRef::Cast(type).type(); |
| 237 ASSERT(!type.IsTypeRef()); | 259 ASSERT(!type.IsTypeRef()); |
| 238 ASSERT(type.IsCanonical()); | 260 ASSERT(type.IsCanonical()); |
| 239 } | 261 } |
| 240 ASSERT(!type.IsNull() && type.IsInstantiated()); | 262 ASSERT(!type.IsNull() && type.IsInstantiated()); |
| 241 arguments.SetReturn(type); | 263 arguments.SetReturn(type); |
| 242 } | 264 } |
| 243 | 265 |
| 244 | 266 |
| 245 // Instantiate type arguments. | 267 // Instantiate type arguments. |
| 246 // Arg0: uninstantiated type arguments. | 268 // Arg0: uninstantiated type arguments. |
| 247 // Arg1: instantiator type arguments. | 269 // Arg1: instantiator type arguments. |
| 248 // Return value: instantiated type arguments. | 270 // Return value: instantiated type arguments. |
| 249 DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) { | 271 DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) { |
| 250 TypeArguments& type_arguments = | 272 TypeArguments& type_arguments = |
| 251 TypeArguments::CheckedHandle(zone, arguments.ArgAt(0)); | 273 TypeArguments::CheckedHandle(zone, arguments.ArgAt(0)); |
| 252 const TypeArguments& instantiator = | 274 const TypeArguments& instantiator = |
| 253 TypeArguments::CheckedHandle(zone, arguments.ArgAt(1)); | 275 TypeArguments::CheckedHandle(zone, arguments.ArgAt(1)); |
| 254 ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated()); | 276 ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated()); |
| 255 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 277 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
| 256 // Code inlined in the caller should have optimized the case where the | 278 // Code inlined in the caller should have optimized the case where the |
| 257 // instantiator can be reused as type argument vector. | 279 // instantiator can be reused as type argument vector. |
| 258 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); | 280 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); |
| 259 if (isolate->type_checks()) { | 281 if (isolate->type_checks()) { |
| 260 Error& bound_error = Error::Handle(zone); | 282 Error& bound_error = Error::Handle(zone); |
| 261 type_arguments = | 283 type_arguments = type_arguments.InstantiateAndCanonicalizeFrom( |
| 262 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, | 284 instantiator, &bound_error); |
| 263 &bound_error); | |
| 264 if (!bound_error.IsNull()) { | 285 if (!bound_error.IsNull()) { |
| 265 // Throw a dynamic type error. | 286 // Throw a dynamic type error. |
| 266 const TokenPosition location = GetCallerLocation(); | 287 const TokenPosition location = GetCallerLocation(); |
| 267 String& bound_error_message = String::Handle( | 288 String& bound_error_message = |
| 268 zone, String::New(bound_error.ToErrorCString())); | 289 String::Handle(zone, String::New(bound_error.ToErrorCString())); |
| 269 Exceptions::CreateAndThrowTypeError( | 290 Exceptions::CreateAndThrowTypeError( |
| 270 location, AbstractType::Handle(zone), AbstractType::Handle(zone), | 291 location, AbstractType::Handle(zone), AbstractType::Handle(zone), |
| 271 Symbols::Empty(), bound_error_message); | 292 Symbols::Empty(), bound_error_message); |
| 272 UNREACHABLE(); | 293 UNREACHABLE(); |
| 273 } | 294 } |
| 274 } else { | 295 } else { |
| 275 type_arguments = | 296 type_arguments = |
| 276 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, NULL); | 297 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, NULL); |
| 277 } | 298 } |
| 278 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); | 299 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 301 Object& inst = Object::Handle(zone); | 322 Object& inst = Object::Handle(zone); |
| 302 for (int i = 0; i < ctx.num_variables(); i++) { | 323 for (int i = 0; i < ctx.num_variables(); i++) { |
| 303 inst = ctx.At(i); | 324 inst = ctx.At(i); |
| 304 cloned_ctx.SetAt(i, inst); | 325 cloned_ctx.SetAt(i, inst); |
| 305 } | 326 } |
| 306 arguments.SetReturn(cloned_ctx); | 327 arguments.SetReturn(cloned_ctx); |
| 307 } | 328 } |
| 308 | 329 |
| 309 | 330 |
| 310 // Helper routine for tracing a type check. | 331 // Helper routine for tracing a type check. |
| 311 static void PrintTypeCheck( | 332 static void PrintTypeCheck(const char* message, |
| 312 const char* message, | 333 const Instance& instance, |
| 313 const Instance& instance, | 334 const AbstractType& type, |
| 314 const AbstractType& type, | 335 const TypeArguments& instantiator_type_arguments, |
| 315 const TypeArguments& instantiator_type_arguments, | 336 const Bool& result) { |
| 316 const Bool& result) { | |
| 317 DartFrameIterator iterator; | 337 DartFrameIterator iterator; |
| 318 StackFrame* caller_frame = iterator.NextFrame(); | 338 StackFrame* caller_frame = iterator.NextFrame(); |
| 319 ASSERT(caller_frame != NULL); | 339 ASSERT(caller_frame != NULL); |
| 320 | 340 |
| 321 const AbstractType& instance_type = AbstractType::Handle(instance.GetType()); | 341 const AbstractType& instance_type = AbstractType::Handle(instance.GetType()); |
| 322 ASSERT(instance_type.IsInstantiated()); | 342 ASSERT(instance_type.IsInstantiated()); |
| 323 if (type.IsInstantiated()) { | 343 if (type.IsInstantiated()) { |
| 324 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", | 344 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", message, |
| 325 message, | |
| 326 String::Handle(instance_type.Name()).ToCString(), | 345 String::Handle(instance_type.Name()).ToCString(), |
| 327 Class::Handle(instance_type.type_class()).id(), | 346 Class::Handle(instance_type.type_class()).id(), |
| 328 (result.raw() == Bool::True().raw()) ? "is" : "is !", | 347 (result.raw() == Bool::True().raw()) ? "is" : "is !", |
| 329 String::Handle(type.Name()).ToCString(), | 348 String::Handle(type.Name()).ToCString(), |
| 330 Class::Handle(type.type_class()).id(), | 349 Class::Handle(type.type_class()).id(), caller_frame->pc()); |
| 331 caller_frame->pc()); | |
| 332 } else { | 350 } else { |
| 333 // Instantiate type before printing. | 351 // Instantiate type before printing. |
| 334 Error& bound_error = Error::Handle(); | 352 Error& bound_error = Error::Handle(); |
| 335 const AbstractType& instantiated_type = AbstractType::Handle( | 353 const AbstractType& instantiated_type = |
| 336 type.InstantiateFrom(instantiator_type_arguments, &bound_error, | 354 AbstractType::Handle(type.InstantiateFrom( |
| 337 NULL, NULL, Heap::kOld)); | 355 instantiator_type_arguments, &bound_error, NULL, NULL, Heap::kOld)); |
| 338 OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#" Px ").\n", | 356 OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#" Px ").\n", |
| 339 message, | 357 message, String::Handle(instance_type.Name()).ToCString(), |
| 340 String::Handle(instance_type.Name()).ToCString(), | |
| 341 (result.raw() == Bool::True().raw()) ? "is" : "is !", | 358 (result.raw() == Bool::True().raw()) ? "is" : "is !", |
| 342 String::Handle(instantiated_type.Name()).ToCString(), | 359 String::Handle(instantiated_type.Name()).ToCString(), |
| 343 String::Handle(type.Name()).ToCString(), | 360 String::Handle(type.Name()).ToCString(), caller_frame->pc()); |
| 344 caller_frame->pc()); | |
| 345 if (!bound_error.IsNull()) { | 361 if (!bound_error.IsNull()) { |
| 346 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); | 362 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); |
| 347 } | 363 } |
| 348 } | 364 } |
| 349 const Function& function = Function::Handle( | 365 const Function& function = |
| 350 caller_frame->LookupDartFunction()); | 366 Function::Handle(caller_frame->LookupDartFunction()); |
| 351 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); | 367 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); |
| 352 } | 368 } |
| 353 | 369 |
| 354 | 370 |
| 355 // This updates the type test cache, an array containing 4-value elements | 371 // This updates the type test cache, an array containing 4-value elements |
| 356 // (instance class (or function if the instance is a closure), instance type | 372 // (instance class (or function if the instance is a closure), instance type |
| 357 // arguments, instantiator type arguments and test_result). It can be applied to | 373 // arguments, instantiator type arguments and test_result). It can be applied to |
| 358 // classes with type arguments in which case it contains just the result of the | 374 // classes with type arguments in which case it contains just the result of the |
| 359 // class subtype test, not including the evaluation of type arguments. | 375 // class subtype test, not including the evaluation of type arguments. |
| 360 // This operation is currently very slow (lookup of code is not efficient yet). | 376 // This operation is currently very slow (lookup of code is not efficient yet). |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 #if defined(DEBUG) | 415 #if defined(DEBUG) |
| 400 ASSERT(instance_type_arguments.IsNull() || | 416 ASSERT(instance_type_arguments.IsNull() || |
| 401 instance_type_arguments.IsCanonical()); | 417 instance_type_arguments.IsCanonical()); |
| 402 ASSERT(instantiator_type_arguments.IsNull() || | 418 ASSERT(instantiator_type_arguments.IsNull() || |
| 403 instantiator_type_arguments.IsCanonical()); | 419 instantiator_type_arguments.IsCanonical()); |
| 404 Object& last_instance_class_id_or_function = Object::Handle(); | 420 Object& last_instance_class_id_or_function = Object::Handle(); |
| 405 TypeArguments& last_instance_type_arguments = TypeArguments::Handle(); | 421 TypeArguments& last_instance_type_arguments = TypeArguments::Handle(); |
| 406 TypeArguments& last_instantiator_type_arguments = TypeArguments::Handle(); | 422 TypeArguments& last_instantiator_type_arguments = TypeArguments::Handle(); |
| 407 Bool& last_result = Bool::Handle(); | 423 Bool& last_result = Bool::Handle(); |
| 408 for (intptr_t i = 0; i < len; ++i) { | 424 for (intptr_t i = 0; i < len; ++i) { |
| 409 new_cache.GetCheck( | 425 new_cache.GetCheck(i, &last_instance_class_id_or_function, |
| 410 i, | 426 &last_instance_type_arguments, |
| 411 &last_instance_class_id_or_function, | 427 &last_instantiator_type_arguments, &last_result); |
| 412 &last_instance_type_arguments, | |
| 413 &last_instantiator_type_arguments, | |
| 414 &last_result); | |
| 415 if ((last_instance_class_id_or_function.raw() == | 428 if ((last_instance_class_id_or_function.raw() == |
| 416 instance_class_id_or_function.raw()) && | 429 instance_class_id_or_function.raw()) && |
| 417 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && | 430 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && |
| 418 (last_instantiator_type_arguments.raw() == | 431 (last_instantiator_type_arguments.raw() == |
| 419 instantiator_type_arguments.raw())) { | 432 instantiator_type_arguments.raw())) { |
| 420 OS::PrintErr(" Error in test cache %p ix: %" Pd ",", new_cache.raw(), i); | 433 OS::PrintErr(" Error in test cache %p ix: %" Pd ",", new_cache.raw(), i); |
| 421 PrintTypeCheck(" duplicate cache entry", instance, type, | 434 PrintTypeCheck(" duplicate cache entry", instance, type, |
| 422 instantiator_type_arguments, result); | 435 instantiator_type_arguments, result); |
| 423 UNREACHABLE(); | 436 UNREACHABLE(); |
| 424 return; | 437 return; |
| 425 } | 438 } |
| 426 } | 439 } |
| 427 #endif | 440 #endif |
| 428 new_cache.AddCheck(instance_class_id_or_function, | 441 new_cache.AddCheck(instance_class_id_or_function, instance_type_arguments, |
| 429 instance_type_arguments, | 442 instantiator_type_arguments, result); |
| 430 instantiator_type_arguments, | |
| 431 result); | |
| 432 if (FLAG_trace_type_checks) { | 443 if (FLAG_trace_type_checks) { |
| 433 AbstractType& test_type = AbstractType::Handle(type.raw()); | 444 AbstractType& test_type = AbstractType::Handle(type.raw()); |
| 434 if (!test_type.IsInstantiated()) { | 445 if (!test_type.IsInstantiated()) { |
| 435 Error& bound_error = Error::Handle(); | 446 Error& bound_error = Error::Handle(); |
| 436 test_type = type.InstantiateFrom(instantiator_type_arguments, | 447 test_type = type.InstantiateFrom(instantiator_type_arguments, |
| 437 &bound_error, | 448 &bound_error, NULL, NULL, Heap::kNew); |
| 438 NULL, NULL, Heap::kNew); | |
| 439 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. | 449 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. |
| 440 } | 450 } |
| 441 OS::PrintErr(" Updated test cache %p ix: %" Pd " with " | 451 OS::PrintErr( |
| 452 " Updated test cache %p ix: %" Pd |
| 453 " with " |
| 442 "(cid-or-fun: %p, type-args: %p, instantiator: %p, result: %s)\n" | 454 "(cid-or-fun: %p, type-args: %p, instantiator: %p, result: %s)\n" |
| 443 " instance [class: (%p '%s' cid: %" Pd "), type-args: %p %s]\n" | 455 " instance [class: (%p '%s' cid: %" Pd |
| 456 "), type-args: %p %s]\n" |
| 444 " test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n", | 457 " test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n", |
| 445 new_cache.raw(), | 458 new_cache.raw(), len, |
| 446 len, | |
| 447 | 459 |
| 448 instance_class_id_or_function.raw(), | 460 instance_class_id_or_function.raw(), instance_type_arguments.raw(), |
| 449 instance_type_arguments.raw(), | 461 instantiator_type_arguments.raw(), result.ToCString(), |
| 450 instantiator_type_arguments.raw(), | |
| 451 result.ToCString(), | |
| 452 | 462 |
| 453 instance_class.raw(), | 463 instance_class.raw(), String::Handle(instance_class.Name()).ToCString(), |
| 454 String::Handle(instance_class.Name()).ToCString(), | 464 instance_class.id(), instance_type_arguments.raw(), |
| 455 instance_class.id(), | |
| 456 instance_type_arguments.raw(), | |
| 457 instance_type_arguments.ToCString(), | 465 instance_type_arguments.ToCString(), |
| 458 | 466 |
| 459 test_type.type_class(), | 467 test_type.type_class(), |
| 460 String::Handle(Class::Handle(test_type.type_class()).Name()). | 468 String::Handle(Class::Handle(test_type.type_class()).Name()) |
| 461 ToCString(), | 469 .ToCString(), |
| 462 Class::Handle(test_type.type_class()).id(), | 470 Class::Handle(test_type.type_class()).id(), |
| 463 instantiator_type_arguments.raw(), | 471 instantiator_type_arguments.raw(), |
| 464 instantiator_type_arguments.ToCString()); | 472 instantiator_type_arguments.ToCString()); |
| 465 } | 473 } |
| 466 } | 474 } |
| 467 | 475 |
| 468 | 476 |
| 469 // Check that the given instance is an instance of the given type. | 477 // Check that the given instance is an instance of the given type. |
| 470 // Tested instance may not be null, because the null test is inlined. | 478 // Tested instance may not be null, because the null test is inlined. |
| 471 // Arg0: instance being checked. | 479 // Arg0: instance being checked. |
| 472 // Arg1: type. | 480 // Arg1: type. |
| 473 // Arg2: type arguments of the instantiator of the type. | 481 // Arg2: type arguments of the instantiator of the type. |
| 474 // Arg3: SubtypeTestCache. | 482 // Arg3: SubtypeTestCache. |
| 475 // Return value: true or false, or may throw a type error in checked mode. | 483 // Return value: true or false, or may throw a type error in checked mode. |
| 476 DEFINE_RUNTIME_ENTRY(Instanceof, 4) { | 484 DEFINE_RUNTIME_ENTRY(Instanceof, 4) { |
| 477 const Instance& instance = Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 485 const Instance& instance = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 478 const AbstractType& type = | 486 const AbstractType& type = |
| 479 AbstractType::CheckedHandle(zone, arguments.ArgAt(1)); | 487 AbstractType::CheckedHandle(zone, arguments.ArgAt(1)); |
| 480 const TypeArguments& instantiator_type_arguments = | 488 const TypeArguments& instantiator_type_arguments = |
| 481 TypeArguments::CheckedHandle(zone, arguments.ArgAt(2)); | 489 TypeArguments::CheckedHandle(zone, arguments.ArgAt(2)); |
| 482 const SubtypeTestCache& cache = | 490 const SubtypeTestCache& cache = |
| 483 SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(3)); | 491 SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(3)); |
| 484 ASSERT(type.IsFinalized()); | 492 ASSERT(type.IsFinalized()); |
| 485 ASSERT(!type.IsMalformed()); // Already checked in code generator. | 493 ASSERT(!type.IsMalformed()); // Already checked in code generator. |
| 486 ASSERT(!type.IsMalbounded()); // Already checked in code generator. | 494 ASSERT(!type.IsMalbounded()); // Already checked in code generator. |
| 487 ASSERT(!type.IsDynamicType()); // No need to check assignment. | 495 ASSERT(!type.IsDynamicType()); // No need to check assignment. |
| 488 Error& bound_error = Error::Handle(zone); | 496 Error& bound_error = Error::Handle(zone); |
| 489 const Bool& result = | 497 const Bool& result = Bool::Get( |
| 490 Bool::Get(instance.IsInstanceOf(type, | 498 instance.IsInstanceOf(type, instantiator_type_arguments, &bound_error)); |
| 491 instantiator_type_arguments, | |
| 492 &bound_error)); | |
| 493 if (FLAG_trace_type_checks) { | 499 if (FLAG_trace_type_checks) { |
| 494 PrintTypeCheck("InstanceOf", | 500 PrintTypeCheck("InstanceOf", instance, type, instantiator_type_arguments, |
| 495 instance, type, instantiator_type_arguments, result); | 501 result); |
| 496 } | 502 } |
| 497 if (!result.value() && !bound_error.IsNull()) { | 503 if (!result.value() && !bound_error.IsNull()) { |
| 498 // Throw a dynamic type error only if the instanceof test fails. | 504 // Throw a dynamic type error only if the instanceof test fails. |
| 499 const TokenPosition location = GetCallerLocation(); | 505 const TokenPosition location = GetCallerLocation(); |
| 500 String& bound_error_message = String::Handle( | 506 String& bound_error_message = |
| 501 zone, String::New(bound_error.ToErrorCString())); | 507 String::Handle(zone, String::New(bound_error.ToErrorCString())); |
| 502 Exceptions::CreateAndThrowTypeError( | 508 Exceptions::CreateAndThrowTypeError(location, AbstractType::Handle(zone), |
| 503 location, AbstractType::Handle(zone), AbstractType::Handle(zone), | 509 AbstractType::Handle(zone), |
| 504 Symbols::Empty(), bound_error_message); | 510 Symbols::Empty(), bound_error_message); |
| 505 UNREACHABLE(); | 511 UNREACHABLE(); |
| 506 } | 512 } |
| 507 UpdateTypeTestCache( | 513 UpdateTypeTestCache(instance, type, instantiator_type_arguments, result, |
| 508 instance, type, instantiator_type_arguments, result, cache); | 514 cache); |
| 509 arguments.SetReturn(result); | 515 arguments.SetReturn(result); |
| 510 } | 516 } |
| 511 | 517 |
| 512 | 518 |
| 513 // Check that the type of the given instance is a subtype of the given type and | 519 // Check that the type of the given instance is a subtype of the given type and |
| 514 // can therefore be assigned. | 520 // can therefore be assigned. |
| 515 // Arg0: instance being assigned. | 521 // Arg0: instance being assigned. |
| 516 // Arg1: type being assigned to. | 522 // Arg1: type being assigned to. |
| 517 // Arg2: type arguments of the instantiator of the type being assigned to. | 523 // Arg2: type arguments of the instantiator of the type being assigned to. |
| 518 // Arg3: name of variable being assigned to. | 524 // Arg3: name of variable being assigned to. |
| 519 // Arg4: SubtypeTestCache. | 525 // Arg4: SubtypeTestCache. |
| 520 // Return value: instance if a subtype, otherwise throw a TypeError. | 526 // Return value: instance if a subtype, otherwise throw a TypeError. |
| 521 DEFINE_RUNTIME_ENTRY(TypeCheck, 5) { | 527 DEFINE_RUNTIME_ENTRY(TypeCheck, 5) { |
| 522 const Instance& src_instance = | 528 const Instance& src_instance = |
| 523 Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 529 Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 524 AbstractType& dst_type = | 530 AbstractType& dst_type = |
| 525 AbstractType::CheckedHandle(zone, arguments.ArgAt(1)); | 531 AbstractType::CheckedHandle(zone, arguments.ArgAt(1)); |
| 526 const TypeArguments& instantiator_type_arguments = | 532 const TypeArguments& instantiator_type_arguments = |
| 527 TypeArguments::CheckedHandle(zone, arguments.ArgAt(2)); | 533 TypeArguments::CheckedHandle(zone, arguments.ArgAt(2)); |
| 528 const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(3)); | 534 const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(3)); |
| 529 const SubtypeTestCache& cache = | 535 const SubtypeTestCache& cache = |
| 530 SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(4)); | 536 SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(4)); |
| 531 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. | 537 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. |
| 532 ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator. | 538 ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator. |
| 533 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. | 539 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. |
| 534 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. | 540 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. |
| 535 | 541 |
| 536 Error& bound_error = Error::Handle(zone); | 542 Error& bound_error = Error::Handle(zone); |
| 537 const bool is_instance_of = src_instance.IsInstanceOf( | 543 const bool is_instance_of = src_instance.IsInstanceOf( |
| 538 dst_type, instantiator_type_arguments, &bound_error); | 544 dst_type, instantiator_type_arguments, &bound_error); |
| 539 | 545 |
| 540 if (FLAG_trace_type_checks) { | 546 if (FLAG_trace_type_checks) { |
| 541 PrintTypeCheck("TypeCheck", | 547 PrintTypeCheck("TypeCheck", src_instance, dst_type, |
| 542 src_instance, dst_type, instantiator_type_arguments, | 548 instantiator_type_arguments, Bool::Get(is_instance_of)); |
| 543 Bool::Get(is_instance_of)); | |
| 544 } | 549 } |
| 545 if (!is_instance_of) { | 550 if (!is_instance_of) { |
| 546 // Throw a dynamic type error. | 551 // Throw a dynamic type error. |
| 547 const TokenPosition location = GetCallerLocation(); | 552 const TokenPosition location = GetCallerLocation(); |
| 548 const AbstractType& src_type = | 553 const AbstractType& src_type = |
| 549 AbstractType::Handle(zone, src_instance.GetType()); | 554 AbstractType::Handle(zone, src_instance.GetType()); |
| 550 if (!dst_type.IsInstantiated()) { | 555 if (!dst_type.IsInstantiated()) { |
| 551 // Instantiate dst_type before reporting the error. | 556 // Instantiate dst_type before reporting the error. |
| 552 dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL, | 557 dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL, |
| 553 NULL, NULL, Heap::kNew); | 558 NULL, NULL, Heap::kNew); |
| 554 // Note that instantiated dst_type may be malbounded. | 559 // Note that instantiated dst_type may be malbounded. |
| 555 } | 560 } |
| 556 String& bound_error_message = String::Handle(zone); | 561 String& bound_error_message = String::Handle(zone); |
| 557 if (!bound_error.IsNull()) { | 562 if (!bound_error.IsNull()) { |
| 558 ASSERT(isolate->type_checks()); | 563 ASSERT(isolate->type_checks()); |
| 559 bound_error_message = String::New(bound_error.ToErrorCString()); | 564 bound_error_message = String::New(bound_error.ToErrorCString()); |
| 560 } | 565 } |
| 561 Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, | 566 Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, dst_name, |
| 562 dst_name, bound_error_message); | 567 bound_error_message); |
| 563 UNREACHABLE(); | 568 UNREACHABLE(); |
| 564 } | 569 } |
| 565 UpdateTypeTestCache( | 570 UpdateTypeTestCache(src_instance, dst_type, instantiator_type_arguments, |
| 566 src_instance, dst_type, instantiator_type_arguments, Bool::True(), cache); | 571 Bool::True(), cache); |
| 567 arguments.SetReturn(src_instance); | 572 arguments.SetReturn(src_instance); |
| 568 } | 573 } |
| 569 | 574 |
| 570 | 575 |
| 571 // Report that the type of the given object is not bool in conditional context. | 576 // Report that the type of the given object is not bool in conditional context. |
| 572 // Throw assertion error if the object is null. (cf. Boolean Conversion | 577 // Throw assertion error if the object is null. (cf. Boolean Conversion |
| 573 // in language Spec.) | 578 // in language Spec.) |
| 574 // Arg0: bad object. | 579 // Arg0: bad object. |
| 575 // Return value: none, throws TypeError or AssertionError. | 580 // Return value: none, throws TypeError or AssertionError. |
| 576 DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) { | 581 DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) { |
| 577 const TokenPosition location = GetCallerLocation(); | 582 const TokenPosition location = GetCallerLocation(); |
| 578 const Instance& src_instance = | 583 const Instance& src_instance = |
| 579 Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 584 Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 580 | 585 |
| 581 if (src_instance.IsNull()) { | 586 if (src_instance.IsNull()) { |
| 582 const Array& args = Array::Handle(zone, Array::New(4)); | 587 const Array& args = Array::Handle(zone, Array::New(4)); |
| 583 args.SetAt(0, String::Handle(zone, | 588 args.SetAt( |
| 584 String::New("Failed assertion: boolean expression must not be null"))); | 589 0, String::Handle( |
| 590 zone, |
| 591 String::New( |
| 592 "Failed assertion: boolean expression must not be null"))); |
| 585 | 593 |
| 586 // No source code for this assertion, set url to null. | 594 // No source code for this assertion, set url to null. |
| 587 args.SetAt(1, String::Handle(zone, String::null())); | 595 args.SetAt(1, String::Handle(zone, String::null())); |
| 588 args.SetAt(2, Smi::Handle(zone, Smi::New(0))); | 596 args.SetAt(2, Smi::Handle(zone, Smi::New(0))); |
| 589 args.SetAt(3, Smi::Handle(zone, Smi::New(0))); | 597 args.SetAt(3, Smi::Handle(zone, Smi::New(0))); |
| 590 | 598 |
| 591 Exceptions::ThrowByType(Exceptions::kAssertion, args); | 599 Exceptions::ThrowByType(Exceptions::kAssertion, args); |
| 592 UNREACHABLE(); | 600 UNREACHABLE(); |
| 593 } | 601 } |
| 594 | 602 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 610 // Arg2: type of destination being assigned to. | 618 // Arg2: type of destination being assigned to. |
| 611 // Return value: none, throws an exception. | 619 // Return value: none, throws an exception. |
| 612 DEFINE_RUNTIME_ENTRY(BadTypeError, 3) { | 620 DEFINE_RUNTIME_ENTRY(BadTypeError, 3) { |
| 613 const TokenPosition location = GetCallerLocation(); | 621 const TokenPosition location = GetCallerLocation(); |
| 614 const Instance& src_value = Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 622 const Instance& src_value = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 615 const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(1)); | 623 const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(1)); |
| 616 const AbstractType& dst_type = | 624 const AbstractType& dst_type = |
| 617 AbstractType::CheckedHandle(zone, arguments.ArgAt(2)); | 625 AbstractType::CheckedHandle(zone, arguments.ArgAt(2)); |
| 618 const AbstractType& src_type = | 626 const AbstractType& src_type = |
| 619 AbstractType::Handle(zone, src_value.GetType()); | 627 AbstractType::Handle(zone, src_value.GetType()); |
| 620 Exceptions::CreateAndThrowTypeError( | 628 Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, dst_name, |
| 621 location, src_type, dst_type, dst_name, String::Handle(zone)); | 629 String::Handle(zone)); |
| 622 UNREACHABLE(); | 630 UNREACHABLE(); |
| 623 } | 631 } |
| 624 | 632 |
| 625 | 633 |
| 626 DEFINE_RUNTIME_ENTRY(Throw, 1) { | 634 DEFINE_RUNTIME_ENTRY(Throw, 1) { |
| 627 const Instance& exception = | 635 const Instance& exception = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 628 Instance::CheckedHandle(zone, arguments.ArgAt(0)); | |
| 629 Exceptions::Throw(thread, exception); | 636 Exceptions::Throw(thread, exception); |
| 630 } | 637 } |
| 631 | 638 |
| 632 | 639 |
| 633 DEFINE_RUNTIME_ENTRY(ReThrow, 2) { | 640 DEFINE_RUNTIME_ENTRY(ReThrow, 2) { |
| 634 const Instance& exception = | 641 const Instance& exception = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 635 Instance::CheckedHandle(zone, arguments.ArgAt(0)); | |
| 636 const Instance& stacktrace = | 642 const Instance& stacktrace = |
| 637 Instance::CheckedHandle(zone, arguments.ArgAt(1)); | 643 Instance::CheckedHandle(zone, arguments.ArgAt(1)); |
| 638 Exceptions::ReThrow(thread, exception, stacktrace); | 644 Exceptions::ReThrow(thread, exception, stacktrace); |
| 639 } | 645 } |
| 640 | 646 |
| 641 | 647 |
| 642 // Patches static call in optimized code with the target's entry point. | 648 // Patches static call in optimized code with the target's entry point. |
| 643 // Compiles target if necessary. | 649 // Compiles target if necessary. |
| 644 DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) { | 650 DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) { |
| 645 DartFrameIterator iterator; | 651 DartFrameIterator iterator; |
| 646 StackFrame* caller_frame = iterator.NextFrame(); | 652 StackFrame* caller_frame = iterator.NextFrame(); |
| 647 ASSERT(caller_frame != NULL); | 653 ASSERT(caller_frame != NULL); |
| 648 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); | 654 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| 649 ASSERT(!caller_code.IsNull()); | 655 ASSERT(!caller_code.IsNull()); |
| 650 ASSERT(caller_code.is_optimized()); | 656 ASSERT(caller_code.is_optimized()); |
| 651 const Function& target_function = Function::Handle( | 657 const Function& target_function = Function::Handle( |
| 652 zone, caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc())); | 658 zone, caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc())); |
| 653 if (!target_function.HasCode()) { | 659 if (!target_function.HasCode()) { |
| 654 const Error& error = | 660 const Error& error = |
| 655 Error::Handle(zone, Compiler::CompileFunction(thread, target_function)); | 661 Error::Handle(zone, Compiler::CompileFunction(thread, target_function)); |
| 656 if (!error.IsNull()) { | 662 if (!error.IsNull()) { |
| 657 Exceptions::PropagateError(error); | 663 Exceptions::PropagateError(error); |
| 658 } | 664 } |
| 659 } | 665 } |
| 660 const Code& target_code = Code::Handle(zone, target_function.CurrentCode()); | 666 const Code& target_code = Code::Handle(zone, target_function.CurrentCode()); |
| 661 // Before patching verify that we are not repeatedly patching to the same | 667 // Before patching verify that we are not repeatedly patching to the same |
| 662 // target. | 668 // target. |
| 663 ASSERT(target_code.raw() != | 669 ASSERT(target_code.raw() != |
| 664 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)); | 670 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)); |
| 665 CodePatcher::PatchStaticCallAt(caller_frame->pc(), | 671 CodePatcher::PatchStaticCallAt(caller_frame->pc(), caller_code, target_code); |
| 666 caller_code, | |
| 667 target_code); | |
| 668 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code); | 672 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code); |
| 669 if (FLAG_trace_patching) { | 673 if (FLAG_trace_patching) { |
| 670 THR_Print("PatchStaticCall: patching caller pc %#" Px "" | 674 THR_Print("PatchStaticCall: patching caller pc %#" Px |
| 671 " to '%s' new entry point %#" Px " (%s)\n", | 675 "" |
| 672 caller_frame->pc(), | 676 " to '%s' new entry point %#" Px " (%s)\n", |
| 673 target_function.ToFullyQualifiedCString(), | 677 caller_frame->pc(), target_function.ToFullyQualifiedCString(), |
| 674 target_code.UncheckedEntryPoint(), | 678 target_code.UncheckedEntryPoint(), |
| 675 target_code.is_optimized() ? "optimized" : "unoptimized"); | 679 target_code.is_optimized() ? "optimized" : "unoptimized"); |
| 676 } | 680 } |
| 677 arguments.SetReturn(target_code); | 681 arguments.SetReturn(target_code); |
| 678 } | 682 } |
| 679 | 683 |
| 680 | 684 |
| 681 // Result of an invoke may be an unhandled exception, in which case we | 685 // Result of an invoke may be an unhandled exception, in which case we |
| 682 // rethrow it. | 686 // rethrow it. |
| 683 static void CheckResultError(const Object& result) { | 687 static void CheckResultError(const Object& result) { |
| 684 if (result.IsError()) { | 688 if (result.IsError()) { |
| 685 Exceptions::PropagateError(Error::Cast(result)); | 689 Exceptions::PropagateError(Error::Cast(result)); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 static bool ResolveCallThroughGetter(const Instance& receiver, | 749 static bool ResolveCallThroughGetter(const Instance& receiver, |
| 746 const Class& receiver_class, | 750 const Class& receiver_class, |
| 747 const String& target_name, | 751 const String& target_name, |
| 748 const Array& arguments_descriptor, | 752 const Array& arguments_descriptor, |
| 749 Function* result) { | 753 Function* result) { |
| 750 // 1. Check if there is a getter with the same name. | 754 // 1. Check if there is a getter with the same name. |
| 751 const String& getter_name = String::Handle(Field::GetterName(target_name)); | 755 const String& getter_name = String::Handle(Field::GetterName(target_name)); |
| 752 const int kNumArguments = 1; | 756 const int kNumArguments = 1; |
| 753 ArgumentsDescriptor args_desc( | 757 ArgumentsDescriptor args_desc( |
| 754 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); | 758 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); |
| 755 const Function& getter = Function::Handle( | 759 const Function& getter = |
| 756 Resolver::ResolveDynamicForReceiverClass(receiver_class, | 760 Function::Handle(Resolver::ResolveDynamicForReceiverClass( |
| 757 getter_name, | 761 receiver_class, getter_name, args_desc)); |
| 758 args_desc)); | |
| 759 if (getter.IsNull() || getter.IsMethodExtractor()) { | 762 if (getter.IsNull() || getter.IsMethodExtractor()) { |
| 760 return false; | 763 return false; |
| 761 } | 764 } |
| 762 const Function& target_function = | 765 const Function& target_function = |
| 763 Function::Handle(receiver_class.GetInvocationDispatcher( | 766 Function::Handle(receiver_class.GetInvocationDispatcher( |
| 764 target_name, | 767 target_name, arguments_descriptor, |
| 765 arguments_descriptor, | 768 RawFunction::kInvokeFieldDispatcher, FLAG_lazy_dispatchers)); |
| 766 RawFunction::kInvokeFieldDispatcher, | |
| 767 FLAG_lazy_dispatchers)); | |
| 768 ASSERT(!target_function.IsNull() || !FLAG_lazy_dispatchers); | 769 ASSERT(!target_function.IsNull() || !FLAG_lazy_dispatchers); |
| 769 if (FLAG_trace_ic) { | 770 if (FLAG_trace_ic) { |
| 770 OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", | 771 OS::PrintErr( |
| 771 Class::Handle(receiver.clazz()).ToCString(), | 772 "InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", |
| 772 receiver.GetClassId(), | 773 Class::Handle(receiver.clazz()).ToCString(), receiver.GetClassId(), |
| 773 target_function.IsNull() ? "null" : target_function.ToCString()); | 774 target_function.IsNull() ? "null" : target_function.ToCString()); |
| 774 } | 775 } |
| 775 *result = target_function.raw(); | 776 *result = target_function.raw(); |
| 776 return true; | 777 return true; |
| 777 } | 778 } |
| 778 | 779 |
| 779 | 780 |
| 780 // Handle other invocations (implicit closures, noSuchMethod). | 781 // Handle other invocations (implicit closures, noSuchMethod). |
| 781 RawFunction* InlineCacheMissHelper( | 782 RawFunction* InlineCacheMissHelper(const Instance& receiver, |
| 782 const Instance& receiver, | 783 const Array& args_descriptor, |
| 783 const Array& args_descriptor, | 784 const String& target_name) { |
| 784 const String& target_name) { | |
| 785 const Class& receiver_class = Class::Handle(receiver.clazz()); | 785 const Class& receiver_class = Class::Handle(receiver.clazz()); |
| 786 | 786 |
| 787 Function& result = Function::Handle(); | 787 Function& result = Function::Handle(); |
| 788 if (!ResolveCallThroughGetter(receiver, | 788 if (!ResolveCallThroughGetter(receiver, receiver_class, target_name, |
| 789 receiver_class, | 789 args_descriptor, &result)) { |
| 790 target_name, | |
| 791 args_descriptor, | |
| 792 &result)) { | |
| 793 ArgumentsDescriptor desc(args_descriptor); | 790 ArgumentsDescriptor desc(args_descriptor); |
| 794 const Function& target_function = | 791 const Function& target_function = |
| 795 Function::Handle(receiver_class.GetInvocationDispatcher( | 792 Function::Handle(receiver_class.GetInvocationDispatcher( |
| 796 target_name, | 793 target_name, args_descriptor, RawFunction::kNoSuchMethodDispatcher, |
| 797 args_descriptor, | |
| 798 RawFunction::kNoSuchMethodDispatcher, | |
| 799 FLAG_lazy_dispatchers)); | 794 FLAG_lazy_dispatchers)); |
| 800 if (FLAG_trace_ic) { | 795 if (FLAG_trace_ic) { |
| 801 OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", | 796 OS::PrintErr( |
| 802 Class::Handle(receiver.clazz()).ToCString(), | 797 "NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", |
| 803 receiver.GetClassId(), | 798 Class::Handle(receiver.clazz()).ToCString(), receiver.GetClassId(), |
| 804 target_function.IsNull() ? "null" : target_function.ToCString()); | 799 target_function.IsNull() ? "null" : target_function.ToCString()); |
| 805 } | 800 } |
| 806 result = target_function.raw(); | 801 result = target_function.raw(); |
| 807 } | 802 } |
| 808 // May be null if --no-lazy-dispatchers, in which case dispatch will be | 803 // May be null if --no-lazy-dispatchers, in which case dispatch will be |
| 809 // handled by InvokeNoSuchMethodDispatcher. | 804 // handled by InvokeNoSuchMethodDispatcher. |
| 810 ASSERT(!result.IsNull() || !FLAG_lazy_dispatchers); | 805 ASSERT(!result.IsNull() || !FLAG_lazy_dispatchers); |
| 811 return result.raw(); | 806 return result.raw(); |
| 812 } | 807 } |
| 813 | 808 |
| 814 | 809 |
| 815 // Perform the subtype and return constant function based on the result. | 810 // Perform the subtype and return constant function based on the result. |
| 816 static RawFunction* ComputeTypeCheckTarget(const Instance& receiver, | 811 static RawFunction* ComputeTypeCheckTarget(const Instance& receiver, |
| 817 const AbstractType& type, | 812 const AbstractType& type, |
| 818 const ArgumentsDescriptor& desc) { | 813 const ArgumentsDescriptor& desc) { |
| 819 const TypeArguments& checked_type_arguments = TypeArguments::Handle(); | 814 const TypeArguments& checked_type_arguments = TypeArguments::Handle(); |
| 820 Error& error = Error::Handle(); | 815 Error& error = Error::Handle(); |
| 821 bool result = receiver.IsInstanceOf(type, checked_type_arguments, &error); | 816 bool result = receiver.IsInstanceOf(type, checked_type_arguments, &error); |
| 822 ASSERT(error.IsNull()); | 817 ASSERT(error.IsNull()); |
| 823 ObjectStore* store = Isolate::Current()->object_store(); | 818 ObjectStore* store = Isolate::Current()->object_store(); |
| 824 const Function& target | 819 const Function& target = |
| 825 = Function::Handle(result | 820 Function::Handle(result ? store->simple_instance_of_true_function() |
| 826 ? store->simple_instance_of_true_function() | 821 : store->simple_instance_of_false_function()); |
| 827 : store->simple_instance_of_false_function()); | |
| 828 ASSERT(!target.IsNull()); | 822 ASSERT(!target.IsNull()); |
| 829 return target.raw(); | 823 return target.raw(); |
| 830 } | 824 } |
| 831 | 825 |
| 832 | 826 |
| 833 static RawFunction* InlineCacheMissHandler( | 827 static RawFunction* InlineCacheMissHandler( |
| 834 const GrowableArray<const Instance*>& args, | 828 const GrowableArray<const Instance*>& args, |
| 835 const ICData& ic_data) { | 829 const ICData& ic_data) { |
| 836 const Instance& receiver = *args[0]; | 830 const Instance& receiver = *args[0]; |
| 837 ArgumentsDescriptor | 831 ArgumentsDescriptor arguments_descriptor( |
| 838 arguments_descriptor(Array::Handle(ic_data.arguments_descriptor())); | 832 Array::Handle(ic_data.arguments_descriptor())); |
| 839 String& function_name = String::Handle(ic_data.target_name()); | 833 String& function_name = String::Handle(ic_data.target_name()); |
| 840 ASSERT(function_name.IsSymbol()); | 834 ASSERT(function_name.IsSymbol()); |
| 841 | 835 |
| 842 Function& target_function = Function::Handle( | 836 Function& target_function = Function::Handle( |
| 843 Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor)); | 837 Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor)); |
| 844 | 838 |
| 845 ObjectStore* store = Isolate::Current()->object_store(); | 839 ObjectStore* store = Isolate::Current()->object_store(); |
| 846 if (target_function.raw() == store->simple_instance_of_function()) { | 840 if (target_function.raw() == store->simple_instance_of_function()) { |
| 847 // Replace the target function with constant function. | 841 // Replace the target function with constant function. |
| 848 const AbstractType& type = AbstractType::Cast(*args[1]); | 842 const AbstractType& type = AbstractType::Cast(*args[1]); |
| 849 target_function | 843 target_function = |
| 850 = ComputeTypeCheckTarget(receiver, type, arguments_descriptor); | 844 ComputeTypeCheckTarget(receiver, type, arguments_descriptor); |
| 851 } | 845 } |
| 852 if (target_function.IsNull()) { | 846 if (target_function.IsNull()) { |
| 853 if (FLAG_trace_ic) { | 847 if (FLAG_trace_ic) { |
| 854 OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n", | 848 OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n", |
| 855 String::Handle(ic_data.target_name()).ToCString(), | 849 String::Handle(ic_data.target_name()).ToCString(), |
| 856 receiver.ToCString()); | 850 receiver.ToCString()); |
| 857 } | 851 } |
| 858 const Array& args_descriptor = | 852 const Array& args_descriptor = |
| 859 Array::Handle(ic_data.arguments_descriptor()); | 853 Array::Handle(ic_data.arguments_descriptor()); |
| 860 const String& target_name = String::Handle(ic_data.target_name()); | 854 const String& target_name = String::Handle(ic_data.target_name()); |
| 861 target_function = InlineCacheMissHelper(receiver, | 855 target_function = |
| 862 args_descriptor, | 856 InlineCacheMissHelper(receiver, args_descriptor, target_name); |
| 863 target_name); | |
| 864 } | 857 } |
| 865 if (target_function.IsNull()) { | 858 if (target_function.IsNull()) { |
| 866 ASSERT(!FLAG_lazy_dispatchers); | 859 ASSERT(!FLAG_lazy_dispatchers); |
| 867 return target_function.raw(); | 860 return target_function.raw(); |
| 868 } | 861 } |
| 869 if (args.length() == 1) { | 862 if (args.length() == 1) { |
| 870 ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function); | 863 ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function); |
| 871 } else { | 864 } else { |
| 872 GrowableArray<intptr_t> class_ids(args.length()); | 865 GrowableArray<intptr_t> class_ids(args.length()); |
| 873 ASSERT(ic_data.NumArgsTested() == args.length()); | 866 ASSERT(ic_data.NumArgsTested() == args.length()); |
| 874 for (intptr_t i = 0; i < args.length(); i++) { | 867 for (intptr_t i = 0; i < args.length(); i++) { |
| 875 class_ids.Add(args[i]->GetClassId()); | 868 class_ids.Add(args[i]->GetClassId()); |
| 876 } | 869 } |
| 877 ic_data.AddCheck(class_ids, target_function); | 870 ic_data.AddCheck(class_ids, target_function); |
| 878 } | 871 } |
| 879 if (FLAG_trace_ic_miss_in_optimized || FLAG_trace_ic) { | 872 if (FLAG_trace_ic_miss_in_optimized || FLAG_trace_ic) { |
| 880 DartFrameIterator iterator; | 873 DartFrameIterator iterator; |
| 881 StackFrame* caller_frame = iterator.NextFrame(); | 874 StackFrame* caller_frame = iterator.NextFrame(); |
| 882 ASSERT(caller_frame != NULL); | 875 ASSERT(caller_frame != NULL); |
| 883 if (FLAG_trace_ic_miss_in_optimized) { | 876 if (FLAG_trace_ic_miss_in_optimized) { |
| 884 const Code& caller = Code::Handle(Code::LookupCode(caller_frame->pc())); | 877 const Code& caller = Code::Handle(Code::LookupCode(caller_frame->pc())); |
| 885 if (caller.is_optimized()) { | 878 if (caller.is_optimized()) { |
| 886 OS::PrintErr("IC miss in optimized code; call %s -> %s\n", | 879 OS::PrintErr("IC miss in optimized code; call %s -> %s\n", |
| 887 Function::Handle(caller.function()).ToCString(), | 880 Function::Handle(caller.function()).ToCString(), |
| 888 target_function.ToCString()); | 881 target_function.ToCString()); |
| 889 } | 882 } |
| 890 } | 883 } |
| 891 if (FLAG_trace_ic) { | 884 if (FLAG_trace_ic) { |
| 892 OS::PrintErr("InlineCacheMissHandler %" Pd " call at %#" Px "' " | 885 OS::PrintErr("InlineCacheMissHandler %" Pd " call at %#" Px |
| 886 "' " |
| 893 "adding <%s> id:%" Pd " -> <%s>\n", | 887 "adding <%s> id:%" Pd " -> <%s>\n", |
| 894 args.length(), | 888 args.length(), caller_frame->pc(), |
| 895 caller_frame->pc(), | 889 Class::Handle(receiver.clazz()).ToCString(), |
| 896 Class::Handle(receiver.clazz()).ToCString(), | 890 receiver.GetClassId(), target_function.ToCString()); |
| 897 receiver.GetClassId(), | |
| 898 target_function.ToCString()); | |
| 899 } | 891 } |
| 900 } | 892 } |
| 901 return target_function.raw(); | 893 return target_function.raw(); |
| 902 } | 894 } |
| 903 | 895 |
| 904 | 896 |
| 905 // Handles inline cache misses by updating the IC data array of the call site. | 897 // Handles inline cache misses by updating the IC data array of the call site. |
| 906 // Arg0: Receiver object. | 898 // Arg0: Receiver object. |
| 907 // Arg1: IC data object. | 899 // Arg1: IC data object. |
| 908 // Returns: target function with compiled code or null. | 900 // Returns: target function with compiled code or null. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 // seen before. Compile the target if necessary and update the ICData. | 955 // seen before. Compile the target if necessary and update the ICData. |
| 964 // Arg0: argument. | 956 // Arg0: argument. |
| 965 // Arg1: IC data object. | 957 // Arg1: IC data object. |
| 966 DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerOneArg, 2) { | 958 DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerOneArg, 2) { |
| 967 const Instance& arg = Instance::CheckedHandle(arguments.ArgAt(0)); | 959 const Instance& arg = Instance::CheckedHandle(arguments.ArgAt(0)); |
| 968 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); | 960 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); |
| 969 // IC data for static call is prepopulated with the statically known target. | 961 // IC data for static call is prepopulated with the statically known target. |
| 970 ASSERT(ic_data.NumberOfChecks() == 1); | 962 ASSERT(ic_data.NumberOfChecks() == 1); |
| 971 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 963 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 972 if (!target.HasCode()) { | 964 if (!target.HasCode()) { |
| 973 const Error& error = Error::Handle(Compiler::CompileFunction(thread, | 965 const Error& error = |
| 974 target)); | 966 Error::Handle(Compiler::CompileFunction(thread, target)); |
| 975 if (!error.IsNull()) { | 967 if (!error.IsNull()) { |
| 976 Exceptions::PropagateError(error); | 968 Exceptions::PropagateError(error); |
| 977 } | 969 } |
| 978 } | 970 } |
| 979 ASSERT(!target.IsNull() && target.HasCode()); | 971 ASSERT(!target.IsNull() && target.HasCode()); |
| 980 ic_data.AddReceiverCheck(arg.GetClassId(), target, 1); | 972 ic_data.AddReceiverCheck(arg.GetClassId(), target, 1); |
| 981 if (FLAG_trace_ic) { | 973 if (FLAG_trace_ic) { |
| 982 DartFrameIterator iterator; | 974 DartFrameIterator iterator; |
| 983 StackFrame* caller_frame = iterator.NextFrame(); | 975 StackFrame* caller_frame = iterator.NextFrame(); |
| 984 ASSERT(caller_frame != NULL); | 976 ASSERT(caller_frame != NULL); |
| 985 OS::PrintErr("StaticCallMissHandler at %#" Px | 977 OS::PrintErr("StaticCallMissHandler at %#" Px " target %s (%" Pd ")\n", |
| 986 " target %s (%" Pd ")\n", | |
| 987 caller_frame->pc(), target.ToCString(), arg.GetClassId()); | 978 caller_frame->pc(), target.ToCString(), arg.GetClassId()); |
| 988 } | 979 } |
| 989 arguments.SetReturn(target); | 980 arguments.SetReturn(target); |
| 990 } | 981 } |
| 991 | 982 |
| 992 | 983 |
| 993 // Handles a static call in unoptimized code that has two argument types not | 984 // Handles a static call in unoptimized code that has two argument types not |
| 994 // seen before. Compile the target if necessary and update the ICData. | 985 // seen before. Compile the target if necessary and update the ICData. |
| 995 // Arg0: argument 0. | 986 // Arg0: argument 0. |
| 996 // Arg1: argument 1. | 987 // Arg1: argument 1. |
| 997 // Arg2: IC data object. | 988 // Arg2: IC data object. |
| 998 DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { | 989 DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { |
| 999 const Instance& arg0 = Instance::CheckedHandle(arguments.ArgAt(0)); | 990 const Instance& arg0 = Instance::CheckedHandle(arguments.ArgAt(0)); |
| 1000 const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1)); | 991 const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1)); |
| 1001 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(2)); | 992 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(2)); |
| 1002 // IC data for static call is prepopulated with the statically known target. | 993 // IC data for static call is prepopulated with the statically known target. |
| 1003 ASSERT(ic_data.NumberOfChecks() > 0); | 994 ASSERT(ic_data.NumberOfChecks() > 0); |
| 1004 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 995 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 1005 if (!target.HasCode()) { | 996 if (!target.HasCode()) { |
| 1006 const Error& error = Error::Handle(Compiler::CompileFunction(thread, | 997 const Error& error = |
| 1007 target)); | 998 Error::Handle(Compiler::CompileFunction(thread, target)); |
| 1008 if (!error.IsNull()) { | 999 if (!error.IsNull()) { |
| 1009 Exceptions::PropagateError(error); | 1000 Exceptions::PropagateError(error); |
| 1010 } | 1001 } |
| 1011 } | 1002 } |
| 1012 ASSERT(!target.IsNull() && target.HasCode()); | 1003 ASSERT(!target.IsNull() && target.HasCode()); |
| 1013 GrowableArray<intptr_t> cids(2); | 1004 GrowableArray<intptr_t> cids(2); |
| 1014 cids.Add(arg0.GetClassId()); | 1005 cids.Add(arg0.GetClassId()); |
| 1015 cids.Add(arg1.GetClassId()); | 1006 cids.Add(arg1.GetClassId()); |
| 1016 ic_data.AddCheck(cids, target); | 1007 ic_data.AddCheck(cids, target); |
| 1017 if (FLAG_trace_ic) { | 1008 if (FLAG_trace_ic) { |
| 1018 DartFrameIterator iterator; | 1009 DartFrameIterator iterator; |
| 1019 StackFrame* caller_frame = iterator.NextFrame(); | 1010 StackFrame* caller_frame = iterator.NextFrame(); |
| 1020 ASSERT(caller_frame != NULL); | 1011 ASSERT(caller_frame != NULL); |
| 1021 OS::PrintErr("StaticCallMissHandler at %#" Px | 1012 OS::PrintErr("StaticCallMissHandler at %#" Px " target %s (%" Pd ", %" Pd |
| 1022 " target %s (%" Pd ", %" Pd ")\n", | 1013 ")\n", |
| 1023 caller_frame->pc(), target.ToCString(), cids[0], cids[1]); | 1014 caller_frame->pc(), target.ToCString(), cids[0], cids[1]); |
| 1024 } | 1015 } |
| 1025 arguments.SetReturn(target); | 1016 arguments.SetReturn(target); |
| 1026 } | 1017 } |
| 1027 | 1018 |
| 1028 | 1019 |
| 1029 #if !defined(TARGET_ARCH_DBC) | 1020 #if !defined(TARGET_ARCH_DBC) |
| 1030 static bool IsSingleTarget(Isolate* isolate, | 1021 static bool IsSingleTarget(Isolate* isolate, |
| 1031 Zone* zone, | 1022 Zone* zone, |
| 1032 intptr_t lower_cid, | 1023 intptr_t lower_cid, |
| 1033 intptr_t upper_cid, | 1024 intptr_t upper_cid, |
| 1034 const Function& target, | 1025 const Function& target, |
| 1035 const String& name) { | 1026 const String& name) { |
| 1036 Class& cls = Class::Handle(zone); | 1027 Class& cls = Class::Handle(zone); |
| 1037 ClassTable* table = isolate->class_table(); | 1028 ClassTable* table = isolate->class_table(); |
| 1038 Function& other_target = Function::Handle(zone); | 1029 Function& other_target = Function::Handle(zone); |
| 1039 for (intptr_t cid = lower_cid; cid <= upper_cid; cid++) { | 1030 for (intptr_t cid = lower_cid; cid <= upper_cid; cid++) { |
| 1040 if (!table->HasValidClassAt(cid)) continue; | 1031 if (!table->HasValidClassAt(cid)) continue; |
| 1041 cls = table->At(cid); | 1032 cls = table->At(cid); |
| 1042 if (cls.is_abstract()) continue; | 1033 if (cls.is_abstract()) continue; |
| 1043 if (!cls.is_allocated()) continue; | 1034 if (!cls.is_allocated()) continue; |
| 1044 other_target = Resolver::ResolveDynamicAnyArgs(zone, cls, name, | 1035 other_target = |
| 1045 false /* allow_add */); | 1036 Resolver::ResolveDynamicAnyArgs(zone, cls, name, false /* allow_add */); |
| 1046 if (other_target.raw() != target.raw()) { | 1037 if (other_target.raw() != target.raw()) { |
| 1047 return false; | 1038 return false; |
| 1048 } | 1039 } |
| 1049 } | 1040 } |
| 1050 return true; | 1041 return true; |
| 1051 } | 1042 } |
| 1052 #endif | 1043 #endif |
| 1053 | 1044 |
| 1054 | 1045 |
| 1055 // Handle a miss of a single target cache. | 1046 // Handle a miss of a single target cache. |
| 1056 // Arg0: Receiver. | 1047 // Arg0: Receiver. |
| 1057 // Returns: the ICData used to continue with a polymorphic call. | 1048 // Returns: the ICData used to continue with a polymorphic call. |
| 1058 DEFINE_RUNTIME_ENTRY(SingleTargetMiss, 1) { | 1049 DEFINE_RUNTIME_ENTRY(SingleTargetMiss, 1) { |
| 1059 #if defined(TARGET_ARCH_DBC) | 1050 #if defined(TARGET_ARCH_DBC) |
| 1060 // DBC does not use switchable calls. | 1051 // DBC does not use switchable calls. |
| 1061 UNREACHABLE(); | 1052 UNREACHABLE(); |
| 1062 #else | 1053 #else |
| 1063 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 1054 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 1064 | 1055 |
| 1065 DartFrameIterator iterator; | 1056 DartFrameIterator iterator; |
| 1066 StackFrame* caller_frame = iterator.NextFrame(); | 1057 StackFrame* caller_frame = iterator.NextFrame(); |
| 1067 ASSERT(caller_frame->IsDartFrame()); | 1058 ASSERT(caller_frame->IsDartFrame()); |
| 1068 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); | 1059 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| 1069 const Function& caller_function = | 1060 const Function& caller_function = |
| 1070 Function::Handle(zone, caller_frame->LookupDartFunction()); | 1061 Function::Handle(zone, caller_frame->LookupDartFunction()); |
| 1071 | 1062 |
| 1072 SingleTargetCache& cache = SingleTargetCache::Handle(zone); | 1063 SingleTargetCache& cache = SingleTargetCache::Handle(zone); |
| 1073 cache ^= CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(), | 1064 cache ^= |
| 1074 caller_code); | 1065 CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(), caller_code); |
| 1075 Code& old_target_code = Code::Handle(zone, cache.target()); | 1066 Code& old_target_code = Code::Handle(zone, cache.target()); |
| 1076 Function& old_target = Function::Handle(zone); | 1067 Function& old_target = Function::Handle(zone); |
| 1077 old_target ^= old_target_code.owner(); | 1068 old_target ^= old_target_code.owner(); |
| 1078 | 1069 |
| 1079 // We lost the original ICData when we patched to the monomorphic case. | 1070 // We lost the original ICData when we patched to the monomorphic case. |
| 1080 const String& name = String::Handle(zone, old_target.name()); | 1071 const String& name = String::Handle(zone, old_target.name()); |
| 1081 ASSERT(!old_target.HasOptionalParameters()); | 1072 ASSERT(!old_target.HasOptionalParameters()); |
| 1082 const Array& descriptor = Array::Handle(zone, | 1073 const Array& descriptor = Array::Handle( |
| 1083 ArgumentsDescriptor::New(old_target.num_fixed_parameters())); | 1074 zone, ArgumentsDescriptor::New(old_target.num_fixed_parameters())); |
| 1084 const ICData& ic_data = | 1075 const ICData& ic_data = |
| 1085 ICData::Handle(zone, ICData::New(caller_function, | 1076 ICData::Handle(zone, ICData::New(caller_function, name, descriptor, |
| 1086 name, | 1077 Thread::kNoDeoptId, 1, /* args_tested */ |
| 1087 descriptor, | |
| 1088 Thread::kNoDeoptId, | |
| 1089 1, /* args_tested */ | |
| 1090 false /* static_call */)); | 1078 false /* static_call */)); |
| 1091 | 1079 |
| 1092 // Maybe add the new target. | 1080 // Maybe add the new target. |
| 1093 Class& cls = Class::Handle(zone, receiver.clazz()); | 1081 Class& cls = Class::Handle(zone, receiver.clazz()); |
| 1094 ArgumentsDescriptor args_desc(descriptor); | 1082 ArgumentsDescriptor args_desc(descriptor); |
| 1095 Function& target_function = Function::Handle(zone, | 1083 Function& target_function = Function::Handle( |
| 1096 Resolver::ResolveDynamicForReceiverClass(cls, | 1084 zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc)); |
| 1097 name, | |
| 1098 args_desc)); | |
| 1099 if (target_function.IsNull()) { | 1085 if (target_function.IsNull()) { |
| 1100 target_function = InlineCacheMissHelper(receiver, descriptor, name); | 1086 target_function = InlineCacheMissHelper(receiver, descriptor, name); |
| 1101 } | 1087 } |
| 1102 if (target_function.IsNull()) { | 1088 if (target_function.IsNull()) { |
| 1103 ASSERT(!FLAG_lazy_dispatchers); | 1089 ASSERT(!FLAG_lazy_dispatchers); |
| 1104 } else { | 1090 } else { |
| 1105 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); | 1091 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| 1106 } | 1092 } |
| 1107 | 1093 |
| 1108 if (old_target.raw() == target_function.raw()) { | 1094 if (old_target.raw() == target_function.raw()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1127 // IC call stub. | 1113 // IC call stub. |
| 1128 arguments.SetReturn(ic_data); | 1114 arguments.SetReturn(ic_data); |
| 1129 return; | 1115 return; |
| 1130 } | 1116 } |
| 1131 } | 1117 } |
| 1132 | 1118 |
| 1133 // Call site is not single target, switch to call using ICData. | 1119 // Call site is not single target, switch to call using ICData. |
| 1134 const Code& stub = | 1120 const Code& stub = |
| 1135 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); | 1121 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); |
| 1136 ASSERT(!Isolate::Current()->compilation_allowed()); | 1122 ASSERT(!Isolate::Current()->compilation_allowed()); |
| 1137 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), | 1123 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data, |
| 1138 caller_code, | |
| 1139 ic_data, | |
| 1140 stub); | 1124 stub); |
| 1141 | 1125 |
| 1142 // Return the ICData. The single target stub will jump to continue in the | 1126 // Return the ICData. The single target stub will jump to continue in the |
| 1143 // IC call stub. | 1127 // IC call stub. |
| 1144 arguments.SetReturn(ic_data); | 1128 arguments.SetReturn(ic_data); |
| 1145 #endif | 1129 #endif |
| 1146 } | 1130 } |
| 1147 | 1131 |
| 1148 | 1132 |
| 1149 DEFINE_RUNTIME_ENTRY(UnlinkedCall, 2) { | 1133 DEFINE_RUNTIME_ENTRY(UnlinkedCall, 2) { |
| 1150 #if defined(TARGET_ARCH_DBC) | 1134 #if defined(TARGET_ARCH_DBC) |
| 1151 // DBC does not use switchable calls. | 1135 // DBC does not use switchable calls. |
| 1152 UNREACHABLE(); | 1136 UNREACHABLE(); |
| 1153 #else | 1137 #else |
| 1154 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 1138 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 1155 const UnlinkedCall& unlinked = | 1139 const UnlinkedCall& unlinked = |
| 1156 UnlinkedCall::CheckedHandle(zone, arguments.ArgAt(1)); | 1140 UnlinkedCall::CheckedHandle(zone, arguments.ArgAt(1)); |
| 1157 | 1141 |
| 1158 DartFrameIterator iterator; | 1142 DartFrameIterator iterator; |
| 1159 StackFrame* caller_frame = iterator.NextFrame(); | 1143 StackFrame* caller_frame = iterator.NextFrame(); |
| 1160 ASSERT(caller_frame->IsDartFrame()); | 1144 ASSERT(caller_frame->IsDartFrame()); |
| 1161 const Code& caller_code = | 1145 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| 1162 Code::Handle(zone, caller_frame->LookupDartCode()); | |
| 1163 const Function& caller_function = | 1146 const Function& caller_function = |
| 1164 Function::Handle(zone, caller_frame->LookupDartFunction()); | 1147 Function::Handle(zone, caller_frame->LookupDartFunction()); |
| 1165 | 1148 |
| 1166 const String& name = String::Handle(zone, unlinked.target_name()); | 1149 const String& name = String::Handle(zone, unlinked.target_name()); |
| 1167 const Array& descriptor = Array::Handle(zone, unlinked.args_descriptor()); | 1150 const Array& descriptor = Array::Handle(zone, unlinked.args_descriptor()); |
| 1168 const ICData& ic_data = | 1151 const ICData& ic_data = |
| 1169 ICData::Handle(zone, ICData::New(caller_function, | 1152 ICData::Handle(zone, ICData::New(caller_function, name, descriptor, |
| 1170 name, | 1153 Thread::kNoDeoptId, 1, /* args_tested */ |
| 1171 descriptor, | |
| 1172 Thread::kNoDeoptId, | |
| 1173 1, /* args_tested */ | |
| 1174 false /* static_call */)); | 1154 false /* static_call */)); |
| 1175 | 1155 |
| 1176 Class& cls = Class::Handle(zone, receiver.clazz()); | 1156 Class& cls = Class::Handle(zone, receiver.clazz()); |
| 1177 ArgumentsDescriptor args_desc(descriptor); | 1157 ArgumentsDescriptor args_desc(descriptor); |
| 1178 Function& target_function = Function::Handle(zone, | 1158 Function& target_function = Function::Handle( |
| 1179 Resolver::ResolveDynamicForReceiverClass(cls, | 1159 zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc)); |
| 1180 name, | |
| 1181 args_desc)); | |
| 1182 if (target_function.IsNull()) { | 1160 if (target_function.IsNull()) { |
| 1183 target_function = InlineCacheMissHelper(receiver, descriptor, name); | 1161 target_function = InlineCacheMissHelper(receiver, descriptor, name); |
| 1184 } | 1162 } |
| 1185 if (target_function.IsNull()) { | 1163 if (target_function.IsNull()) { |
| 1186 ASSERT(!FLAG_lazy_dispatchers); | 1164 ASSERT(!FLAG_lazy_dispatchers); |
| 1187 } else { | 1165 } else { |
| 1188 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); | 1166 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| 1189 } | 1167 } |
| 1190 | 1168 |
| 1191 if (!target_function.IsNull() && | 1169 if (!target_function.IsNull() && !target_function.HasOptionalParameters()) { |
| 1192 !target_function.HasOptionalParameters()) { | |
| 1193 // Patch to monomorphic call. | 1170 // Patch to monomorphic call. |
| 1194 ASSERT(target_function.HasCode()); | 1171 ASSERT(target_function.HasCode()); |
| 1195 const Code& target_code = | 1172 const Code& target_code = Code::Handle(zone, target_function.CurrentCode()); |
| 1196 Code::Handle(zone, target_function.CurrentCode()); | |
| 1197 const Smi& expected_cid = | 1173 const Smi& expected_cid = |
| 1198 Smi::Handle(zone, Smi::New(receiver.GetClassId())); | 1174 Smi::Handle(zone, Smi::New(receiver.GetClassId())); |
| 1199 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, | 1175 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, |
| 1200 expected_cid, target_code); | 1176 expected_cid, target_code); |
| 1201 | 1177 |
| 1202 // Return the ICData. The miss stub will jump to continue in the IC call | 1178 // Return the ICData. The miss stub will jump to continue in the IC call |
| 1203 // stub. | 1179 // stub. |
| 1204 arguments.SetReturn(ic_data); | 1180 arguments.SetReturn(ic_data); |
| 1205 return; | 1181 return; |
| 1206 } | 1182 } |
| 1207 | 1183 |
| 1208 // Patch to call through stub. | 1184 // Patch to call through stub. |
| 1209 const Code& stub = | 1185 const Code& stub = |
| 1210 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); | 1186 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); |
| 1211 ASSERT(!Isolate::Current()->compilation_allowed()); | 1187 ASSERT(!Isolate::Current()->compilation_allowed()); |
| 1212 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), | 1188 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data, |
| 1213 caller_code, | |
| 1214 ic_data, | |
| 1215 stub); | 1189 stub); |
| 1216 | 1190 |
| 1217 // Return the ICData. The miss stub will jump to continue in the IC lookup | 1191 // Return the ICData. The miss stub will jump to continue in the IC lookup |
| 1218 // stub. | 1192 // stub. |
| 1219 arguments.SetReturn(ic_data); | 1193 arguments.SetReturn(ic_data); |
| 1220 #endif // !DBC | 1194 #endif // !DBC |
| 1221 } | 1195 } |
| 1222 | 1196 |
| 1223 | 1197 |
| 1224 // Handle a miss of a megamorphic cache. | 1198 // Handle a miss of a megamorphic cache. |
| 1225 // Arg0: Receiver. | 1199 // Arg0: Receiver. |
| 1226 // Returns: the ICData used to continue with a polymorphic call. | 1200 // Returns: the ICData used to continue with a polymorphic call. |
| 1227 DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) { | 1201 DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) { |
| 1228 #if defined(TARGET_ARCH_DBC) | 1202 #if defined(TARGET_ARCH_DBC) |
| 1229 // DBC does not use switchable calls. | 1203 // DBC does not use switchable calls. |
| 1230 UNREACHABLE(); | 1204 UNREACHABLE(); |
| 1231 #else | 1205 #else |
| 1232 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); | 1206 const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| 1233 | 1207 |
| 1234 DartFrameIterator iterator; | 1208 DartFrameIterator iterator; |
| 1235 StackFrame* caller_frame = iterator.NextFrame(); | 1209 StackFrame* caller_frame = iterator.NextFrame(); |
| 1236 ASSERT(caller_frame->IsDartFrame()); | 1210 ASSERT(caller_frame->IsDartFrame()); |
| 1237 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); | 1211 const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| 1238 const Function& caller_function = | 1212 const Function& caller_function = |
| 1239 Function::Handle(zone, caller_frame->LookupDartFunction()); | 1213 Function::Handle(zone, caller_frame->LookupDartFunction()); |
| 1240 | 1214 |
| 1241 Smi& old_expected_cid = Smi::Handle(zone); | 1215 Smi& old_expected_cid = Smi::Handle(zone); |
| 1242 old_expected_cid ^= CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(), | 1216 old_expected_cid ^= |
| 1243 caller_code); | 1217 CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(), caller_code); |
| 1244 const Code& old_target_code = | 1218 const Code& old_target_code = Code::Handle( |
| 1245 Code::Handle(CodePatcher::GetSwitchableCallTargetAt(caller_frame->pc(), | 1219 CodePatcher::GetSwitchableCallTargetAt(caller_frame->pc(), caller_code)); |
| 1246 caller_code)); | |
| 1247 Function& old_target = Function::Handle(zone); | 1220 Function& old_target = Function::Handle(zone); |
| 1248 old_target ^= old_target_code.owner(); | 1221 old_target ^= old_target_code.owner(); |
| 1249 | 1222 |
| 1250 // We lost the original ICData when we patched to the monomorphic case. | 1223 // We lost the original ICData when we patched to the monomorphic case. |
| 1251 const String& name = String::Handle(zone, old_target.name()); | 1224 const String& name = String::Handle(zone, old_target.name()); |
| 1252 ASSERT(!old_target.HasOptionalParameters()); | 1225 ASSERT(!old_target.HasOptionalParameters()); |
| 1253 const Array& descriptor = Array::Handle(zone, | 1226 const Array& descriptor = Array::Handle( |
| 1254 ArgumentsDescriptor::New(old_target.num_fixed_parameters())); | 1227 zone, ArgumentsDescriptor::New(old_target.num_fixed_parameters())); |
| 1255 const ICData& ic_data = | 1228 const ICData& ic_data = |
| 1256 ICData::Handle(zone, ICData::New(caller_function, | 1229 ICData::Handle(zone, ICData::New(caller_function, name, descriptor, |
| 1257 name, | 1230 Thread::kNoDeoptId, 1, /* args_tested */ |
| 1258 descriptor, | |
| 1259 Thread::kNoDeoptId, | |
| 1260 1, /* args_tested */ | |
| 1261 false /* static_call */)); | 1231 false /* static_call */)); |
| 1262 | 1232 |
| 1263 // Add the first target. | 1233 // Add the first target. |
| 1264 ic_data.AddReceiverCheck(old_expected_cid.Value(), old_target); | 1234 ic_data.AddReceiverCheck(old_expected_cid.Value(), old_target); |
| 1265 | 1235 |
| 1266 // Maybe add the new target. | 1236 // Maybe add the new target. |
| 1267 Class& cls = Class::Handle(zone, receiver.clazz()); | 1237 Class& cls = Class::Handle(zone, receiver.clazz()); |
| 1268 ArgumentsDescriptor args_desc(descriptor); | 1238 ArgumentsDescriptor args_desc(descriptor); |
| 1269 Function& target_function = Function::Handle(zone, | 1239 Function& target_function = Function::Handle( |
| 1270 Resolver::ResolveDynamicForReceiverClass(cls, | 1240 zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc)); |
| 1271 name, | |
| 1272 args_desc)); | |
| 1273 if (target_function.IsNull()) { | 1241 if (target_function.IsNull()) { |
| 1274 target_function = InlineCacheMissHelper(receiver, descriptor, name); | 1242 target_function = InlineCacheMissHelper(receiver, descriptor, name); |
| 1275 } | 1243 } |
| 1276 if (target_function.IsNull()) { | 1244 if (target_function.IsNull()) { |
| 1277 ASSERT(!FLAG_lazy_dispatchers); | 1245 ASSERT(!FLAG_lazy_dispatchers); |
| 1278 } else { | 1246 } else { |
| 1279 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); | 1247 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| 1280 } | 1248 } |
| 1281 | 1249 |
| 1282 if (old_target.raw() == target_function.raw()) { | 1250 if (old_target.raw() == target_function.raw()) { |
| 1283 intptr_t lower, upper; | 1251 intptr_t lower, upper; |
| 1284 if (old_expected_cid.Value() < receiver.GetClassId()) { | 1252 if (old_expected_cid.Value() < receiver.GetClassId()) { |
| 1285 lower = old_expected_cid.Value(); | 1253 lower = old_expected_cid.Value(); |
| 1286 upper = receiver.GetClassId(); | 1254 upper = receiver.GetClassId(); |
| 1287 } else { | 1255 } else { |
| 1288 lower = receiver.GetClassId(); | 1256 lower = receiver.GetClassId(); |
| 1289 upper = old_expected_cid.Value(); | 1257 upper = old_expected_cid.Value(); |
| 1290 } | 1258 } |
| 1291 | 1259 |
| 1292 if (IsSingleTarget(isolate, zone, lower, upper, target_function, name)) { | 1260 if (IsSingleTarget(isolate, zone, lower, upper, target_function, name)) { |
| 1293 const SingleTargetCache& cache = | 1261 const SingleTargetCache& cache = |
| 1294 SingleTargetCache::Handle(SingleTargetCache::New()); | 1262 SingleTargetCache::Handle(SingleTargetCache::New()); |
| 1295 const Code& code = Code::Handle(target_function.CurrentCode()); | 1263 const Code& code = Code::Handle(target_function.CurrentCode()); |
| 1296 cache.set_target(code); | 1264 cache.set_target(code); |
| 1297 cache.set_entry_point(code.UncheckedEntryPoint()); | 1265 cache.set_entry_point(code.UncheckedEntryPoint()); |
| 1298 cache.set_lower_limit(lower); | 1266 cache.set_lower_limit(lower); |
| 1299 cache.set_upper_limit(upper); | 1267 cache.set_upper_limit(upper); |
| 1300 const Code& stub = Code::Handle(zone, | 1268 const Code& stub = |
| 1301 StubCode::SingleTargetCall_entry()->code()); | 1269 Code::Handle(zone, StubCode::SingleTargetCall_entry()->code()); |
| 1302 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), | 1270 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, cache, |
| 1303 caller_code, | |
| 1304 cache, | |
| 1305 stub); | 1271 stub); |
| 1306 // Return the ICData. The miss stub will jump to continue in the IC call | 1272 // Return the ICData. The miss stub will jump to continue in the IC call |
| 1307 // stub. | 1273 // stub. |
| 1308 arguments.SetReturn(ic_data); | 1274 arguments.SetReturn(ic_data); |
| 1309 return; | 1275 return; |
| 1310 } | 1276 } |
| 1311 } | 1277 } |
| 1312 | 1278 |
| 1313 // Patch to call through stub. | 1279 // Patch to call through stub. |
| 1314 const Code& stub = | 1280 const Code& stub = |
| 1315 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); | 1281 Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code()); |
| 1316 ASSERT(!Isolate::Current()->compilation_allowed()); | 1282 ASSERT(!Isolate::Current()->compilation_allowed()); |
| 1317 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), | 1283 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data, |
| 1318 caller_code, | |
| 1319 ic_data, | |
| 1320 stub); | 1284 stub); |
| 1321 | 1285 |
| 1322 // Return the ICData. The miss stub will jump to continue in the IC lookup | 1286 // Return the ICData. The miss stub will jump to continue in the IC lookup |
| 1323 // stub. | 1287 // stub. |
| 1324 arguments.SetReturn(ic_data); | 1288 arguments.SetReturn(ic_data); |
| 1325 #endif // !defined(TARGET_ARCH_DBC) | 1289 #endif // !defined(TARGET_ARCH_DBC) |
| 1326 } | 1290 } |
| 1327 | 1291 |
| 1328 | 1292 |
| 1329 // Handle a miss of a megamorphic cache. | 1293 // Handle a miss of a megamorphic cache. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1347 name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); | 1311 name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); |
| 1348 } | 1312 } |
| 1349 Class& cls = Class::Handle(zone, receiver.clazz()); | 1313 Class& cls = Class::Handle(zone, receiver.clazz()); |
| 1350 ASSERT(!cls.IsNull()); | 1314 ASSERT(!cls.IsNull()); |
| 1351 if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) { | 1315 if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) { |
| 1352 OS::PrintErr("Megamorphic IC miss, class=%s, function=%s\n", | 1316 OS::PrintErr("Megamorphic IC miss, class=%s, function=%s\n", |
| 1353 cls.ToCString(), name.ToCString()); | 1317 cls.ToCString(), name.ToCString()); |
| 1354 } | 1318 } |
| 1355 | 1319 |
| 1356 ArgumentsDescriptor args_desc(descriptor); | 1320 ArgumentsDescriptor args_desc(descriptor); |
| 1357 Function& target_function = Function::Handle(zone, | 1321 Function& target_function = Function::Handle( |
| 1358 Resolver::ResolveDynamicForReceiverClass(cls, | 1322 zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc)); |
| 1359 name, | |
| 1360 args_desc)); | |
| 1361 if (target_function.IsNull()) { | 1323 if (target_function.IsNull()) { |
| 1362 target_function = InlineCacheMissHelper(receiver, descriptor, name); | 1324 target_function = InlineCacheMissHelper(receiver, descriptor, name); |
| 1363 } | 1325 } |
| 1364 if (target_function.IsNull()) { | 1326 if (target_function.IsNull()) { |
| 1365 ASSERT(!FLAG_lazy_dispatchers); | 1327 ASSERT(!FLAG_lazy_dispatchers); |
| 1366 arguments.SetReturn(target_function); | 1328 arguments.SetReturn(target_function); |
| 1367 return; | 1329 return; |
| 1368 } | 1330 } |
| 1369 | 1331 |
| 1370 if (ic_data_or_cache.IsICData()) { | 1332 if (ic_data_or_cache.IsICData()) { |
| 1371 const ICData& ic_data = ICData::Cast(ic_data_or_cache); | 1333 const ICData& ic_data = ICData::Cast(ic_data_or_cache); |
| 1372 | 1334 |
| 1373 if ((ic_data.NumberOfChecks() == 0) && | 1335 if ((ic_data.NumberOfChecks() == 0) && |
| 1374 !target_function.HasOptionalParameters() && | 1336 !target_function.HasOptionalParameters() && |
| 1375 !Isolate::Current()->compilation_allowed()) { | 1337 !Isolate::Current()->compilation_allowed()) { |
| 1376 // This call site is unlinked: transition to a monomorphic direct call. | 1338 // This call site is unlinked: transition to a monomorphic direct call. |
| 1377 // Note we cannot do this if the target has optional parameters because | 1339 // Note we cannot do this if the target has optional parameters because |
| 1378 // the monomorphic direct call does not load the arguments descriptor. | 1340 // the monomorphic direct call does not load the arguments descriptor. |
| 1379 // We cannot do this if we are still in the middle of precompiling because | 1341 // We cannot do this if we are still in the middle of precompiling because |
| 1380 // the monomorphic case hides an live instance selector from the | 1342 // the monomorphic case hides an live instance selector from the |
| 1381 // treeshaker. | 1343 // treeshaker. |
| 1382 | 1344 |
| 1383 if (!target_function.HasCode()) { | 1345 if (!target_function.HasCode()) { |
| 1384 const Error& error = | 1346 const Error& error = |
| 1385 Error::Handle(Compiler::CompileFunction(thread, target_function)); | 1347 Error::Handle(Compiler::CompileFunction(thread, target_function)); |
| 1386 if (!error.IsNull()) { | 1348 if (!error.IsNull()) { |
| 1387 Exceptions::PropagateError(error); | 1349 Exceptions::PropagateError(error); |
| 1388 } | 1350 } |
| 1389 } | 1351 } |
| 1390 | 1352 |
| 1391 DartFrameIterator iterator; | 1353 DartFrameIterator iterator; |
| 1392 StackFrame* miss_function_frame = iterator.NextFrame(); | 1354 StackFrame* miss_function_frame = iterator.NextFrame(); |
| 1393 ASSERT(miss_function_frame->IsDartFrame()); | 1355 ASSERT(miss_function_frame->IsDartFrame()); |
| 1394 StackFrame* caller_frame = iterator.NextFrame(); | 1356 StackFrame* caller_frame = iterator.NextFrame(); |
| 1395 ASSERT(caller_frame->IsDartFrame()); | 1357 ASSERT(caller_frame->IsDartFrame()); |
| 1396 const Code& caller_code = | 1358 const Code& caller_code = |
| 1397 Code::Handle(zone, caller_frame->LookupDartCode()); | 1359 Code::Handle(zone, caller_frame->LookupDartCode()); |
| 1398 const Code& target_code = | 1360 const Code& target_code = |
| 1399 Code::Handle(zone, target_function.CurrentCode()); | 1361 Code::Handle(zone, target_function.CurrentCode()); |
| 1400 const Smi& expected_cid = | 1362 const Smi& expected_cid = |
| 1401 Smi::Handle(zone, Smi::New(receiver.GetClassId())); | 1363 Smi::Handle(zone, Smi::New(receiver.GetClassId())); |
| 1402 | 1364 |
| 1403 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, | 1365 CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, |
| 1404 expected_cid, target_code); | 1366 expected_cid, target_code); |
| 1405 } else { | 1367 } else { |
| 1406 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); | 1368 ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| 1407 if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { | 1369 if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { |
| 1408 // Switch to megamorphic call. | 1370 // Switch to megamorphic call. |
| 1409 const MegamorphicCache& cache = MegamorphicCache::Handle(zone, | 1371 const MegamorphicCache& cache = MegamorphicCache::Handle( |
| 1410 MegamorphicCacheTable::Lookup(isolate, name, descriptor)); | 1372 zone, MegamorphicCacheTable::Lookup(isolate, name, descriptor)); |
| 1411 DartFrameIterator iterator; | 1373 DartFrameIterator iterator; |
| 1412 StackFrame* miss_function_frame = iterator.NextFrame(); | 1374 StackFrame* miss_function_frame = iterator.NextFrame(); |
| 1413 ASSERT(miss_function_frame->IsDartFrame()); | 1375 ASSERT(miss_function_frame->IsDartFrame()); |
| 1414 StackFrame* caller_frame = iterator.NextFrame(); | 1376 StackFrame* caller_frame = iterator.NextFrame(); |
| 1415 ASSERT(caller_frame->IsDartFrame()); | 1377 ASSERT(caller_frame->IsDartFrame()); |
| 1416 const Code& caller_code = | 1378 const Code& caller_code = |
| 1417 Code::Handle(zone, caller_frame->LookupDartCode()); | 1379 Code::Handle(zone, caller_frame->LookupDartCode()); |
| 1418 const Code& stub = | 1380 const Code& stub = |
| 1419 Code::Handle(zone, StubCode::MegamorphicCall_entry()->code()); | 1381 Code::Handle(zone, StubCode::MegamorphicCall_entry()->code()); |
| 1420 | 1382 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1450 if (ic_data_or_cache.IsICData()) { | 1412 if (ic_data_or_cache.IsICData()) { |
| 1451 target_name = ICData::Cast(ic_data_or_cache).target_name(); | 1413 target_name = ICData::Cast(ic_data_or_cache).target_name(); |
| 1452 } else { | 1414 } else { |
| 1453 ASSERT(ic_data_or_cache.IsMegamorphicCache()); | 1415 ASSERT(ic_data_or_cache.IsMegamorphicCache()); |
| 1454 target_name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); | 1416 target_name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); |
| 1455 } | 1417 } |
| 1456 | 1418 |
| 1457 Class& cls = Class::Handle(zone, receiver.clazz()); | 1419 Class& cls = Class::Handle(zone, receiver.clazz()); |
| 1458 Function& function = Function::Handle(zone); | 1420 Function& function = Function::Handle(zone); |
| 1459 | 1421 |
| 1460 // Dart distinguishes getters and regular methods and allows their calls | 1422 // Dart distinguishes getters and regular methods and allows their calls |
| 1461 // to mix with conversions, and its selectors are independent of arity. So do | 1423 // to mix with conversions, and its selectors are independent of arity. So do |
| 1462 // a zigzagged lookup to see if this call failed because of an arity mismatch, | 1424 // a zigzagged lookup to see if this call failed because of an arity mismatch, |
| 1463 // need for conversion, or there really is no such method. | 1425 // need for conversion, or there really is no such method. |
| 1464 | 1426 |
| 1465 #define NO_SUCH_METHOD() \ | 1427 #define NO_SUCH_METHOD() \ |
| 1466 const Object& result = Object::Handle(zone, \ | 1428 const Object& result = Object::Handle( \ |
| 1467 DartEntry::InvokeNoSuchMethod(receiver, \ | 1429 zone, DartEntry::InvokeNoSuchMethod( \ |
| 1468 target_name, \ | 1430 receiver, target_name, orig_arguments, orig_arguments_desc)); \ |
| 1469 orig_arguments, \ | |
| 1470 orig_arguments_desc)); \ | |
| 1471 CheckResultError(result); \ | 1431 CheckResultError(result); \ |
| 1472 arguments.SetReturn(result); \ | 1432 arguments.SetReturn(result); |
| 1473 | 1433 |
| 1474 #define CLOSURIZE(some_function) \ | 1434 #define CLOSURIZE(some_function) \ |
| 1475 const Function& closure_function = \ | 1435 const Function& closure_function = \ |
| 1476 Function::Handle(zone, some_function.ImplicitClosureFunction()); \ | 1436 Function::Handle(zone, some_function.ImplicitClosureFunction()); \ |
| 1477 const Object& result = \ | 1437 const Object& result = Object::Handle( \ |
| 1478 Object::Handle(zone, closure_function.ImplicitInstanceClosure(receiver));\ | 1438 zone, closure_function.ImplicitInstanceClosure(receiver)); \ |
| 1479 arguments.SetReturn(result); \ | 1439 arguments.SetReturn(result); |
| 1480 | 1440 |
| 1481 const bool is_getter = Field::IsGetterName(target_name); | 1441 const bool is_getter = Field::IsGetterName(target_name); |
| 1482 if (is_getter) { | 1442 if (is_getter) { |
| 1483 // o.foo (o.get:foo) failed, closurize o.foo() if it exists. Or, | 1443 // o.foo (o.get:foo) failed, closurize o.foo() if it exists. Or, |
| 1484 // o#foo (o.get:#foo) failed, closurizee o.foo or o.foo(), whichever is | 1444 // o#foo (o.get:#foo) failed, closurizee o.foo or o.foo(), whichever is |
| 1485 // encountered first on the inheritance chain. Or, | 1445 // encountered first on the inheritance chain. Or, |
| 1486 // o#foo= (o.get:#set:foo) failed, closurize o.foo= if it exists. | 1446 // o#foo= (o.get:#set:foo) failed, closurize o.foo= if it exists. |
| 1487 String& field_name = | 1447 String& field_name = |
| 1488 String::Handle(zone, Field::NameFromGetter(target_name)); | 1448 String::Handle(zone, Field::NameFromGetter(target_name)); |
| 1489 | 1449 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1529 | 1489 |
| 1530 // Fall through for noSuchMethod | 1490 // Fall through for noSuchMethod |
| 1531 } else { | 1491 } else { |
| 1532 // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong | 1492 // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong |
| 1533 // number of arguments, or try (o.foo).call(...) | 1493 // number of arguments, or try (o.foo).call(...) |
| 1534 | 1494 |
| 1535 if ((target_name.raw() == Symbols::Call().raw()) && receiver.IsClosure()) { | 1495 if ((target_name.raw() == Symbols::Call().raw()) && receiver.IsClosure()) { |
| 1536 // Special case: closures are implemented with a call getter instead of a | 1496 // Special case: closures are implemented with a call getter instead of a |
| 1537 // call method and with lazy dispatchers the field-invocation-dispatcher | 1497 // call method and with lazy dispatchers the field-invocation-dispatcher |
| 1538 // would perform the closure call. | 1498 // would perform the closure call. |
| 1539 const Object& result = | 1499 const Object& result = Object::Handle( |
| 1540 Object::Handle(zone, DartEntry::InvokeClosure(orig_arguments, | 1500 zone, DartEntry::InvokeClosure(orig_arguments, orig_arguments_desc)); |
| 1541 orig_arguments_desc)); | |
| 1542 CheckResultError(result); | 1501 CheckResultError(result); |
| 1543 arguments.SetReturn(result); | 1502 arguments.SetReturn(result); |
| 1544 return; | 1503 return; |
| 1545 } | 1504 } |
| 1546 | 1505 |
| 1547 const String& getter_name = | 1506 const String& getter_name = |
| 1548 String::Handle(zone, Field::GetterName(target_name)); | 1507 String::Handle(zone, Field::GetterName(target_name)); |
| 1549 while (!cls.IsNull()) { | 1508 while (!cls.IsNull()) { |
| 1550 function ^= cls.LookupDynamicFunction(target_name); | 1509 function ^= cls.LookupDynamicFunction(target_name); |
| 1551 if (!function.IsNull()) { | 1510 if (!function.IsNull()) { |
| 1552 ArgumentsDescriptor args_desc(orig_arguments_desc); | 1511 ArgumentsDescriptor args_desc(orig_arguments_desc); |
| 1553 ASSERT(!function.AreValidArguments(args_desc, NULL)); | 1512 ASSERT(!function.AreValidArguments(args_desc, NULL)); |
| 1554 break; // mismatch, invoke noSuchMethod | 1513 break; // mismatch, invoke noSuchMethod |
| 1555 } | 1514 } |
| 1556 function ^= cls.LookupDynamicFunction(getter_name); | 1515 function ^= cls.LookupDynamicFunction(getter_name); |
| 1557 if (!function.IsNull()) { | 1516 if (!function.IsNull()) { |
| 1558 const Array& getter_arguments = Array::Handle(Array::New(1)); | 1517 const Array& getter_arguments = Array::Handle(Array::New(1)); |
| 1559 getter_arguments.SetAt(0, receiver); | 1518 getter_arguments.SetAt(0, receiver); |
| 1560 const Object& getter_result = | 1519 const Object& getter_result = Object::Handle( |
| 1561 Object::Handle(zone, DartEntry::InvokeFunction(function, | 1520 zone, DartEntry::InvokeFunction(function, getter_arguments)); |
| 1562 getter_arguments)); | |
| 1563 CheckResultError(getter_result); | 1521 CheckResultError(getter_result); |
| 1564 ASSERT(getter_result.IsNull() || getter_result.IsInstance()); | 1522 ASSERT(getter_result.IsNull() || getter_result.IsInstance()); |
| 1565 | 1523 |
| 1566 orig_arguments.SetAt(0, getter_result); | 1524 orig_arguments.SetAt(0, getter_result); |
| 1567 const Object& call_result = | 1525 const Object& call_result = Object::Handle( |
| 1568 Object::Handle(zone, DartEntry::InvokeClosure(orig_arguments, | 1526 zone, |
| 1569 orig_arguments_desc)); | 1527 DartEntry::InvokeClosure(orig_arguments, orig_arguments_desc)); |
| 1570 CheckResultError(call_result); | 1528 CheckResultError(call_result); |
| 1571 arguments.SetReturn(call_result); | 1529 arguments.SetReturn(call_result); |
| 1572 return; | 1530 return; |
| 1573 } | 1531 } |
| 1574 cls = cls.SuperClass(); | 1532 cls = cls.SuperClass(); |
| 1575 } | 1533 } |
| 1576 } | 1534 } |
| 1577 | 1535 |
| 1578 NO_SUCH_METHOD(); | 1536 NO_SUCH_METHOD(); |
| 1579 | 1537 |
| 1580 #undef NO_SUCH_METHOD | 1538 #undef NO_SUCH_METHOD |
| 1581 #undef CLOSURIZE | 1539 #undef CLOSURIZE |
| 1582 } | 1540 } |
| 1583 | 1541 |
| 1584 | 1542 |
| 1585 | |
| 1586 // Invoke appropriate noSuchMethod function. | 1543 // Invoke appropriate noSuchMethod function. |
| 1587 // Arg0: receiver (closure object) | 1544 // Arg0: receiver (closure object) |
| 1588 // Arg1: arguments descriptor array. | 1545 // Arg1: arguments descriptor array. |
| 1589 // Arg2: arguments array. | 1546 // Arg2: arguments array. |
| 1590 DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) { | 1547 DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) { |
| 1591 const Closure& receiver = Closure::CheckedHandle(arguments.ArgAt(0)); | 1548 const Closure& receiver = Closure::CheckedHandle(arguments.ArgAt(0)); |
| 1592 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1)); | 1549 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1)); |
| 1593 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2)); | 1550 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2)); |
| 1594 | 1551 |
| 1595 // For closure the function name is always 'call'. Replace it with the | 1552 // For closure the function name is always 'call'. Replace it with the |
| 1596 // name of the closurized function so that exception contains more | 1553 // name of the closurized function so that exception contains more |
| 1597 // relevant information. | 1554 // relevant information. |
| 1598 const Function& function = Function::Handle(receiver.function()); | 1555 const Function& function = Function::Handle(receiver.function()); |
| 1599 const String& original_function_name = | 1556 const String& original_function_name = |
| 1600 String::Handle(function.QualifiedUserVisibleName()); | 1557 String::Handle(function.QualifiedUserVisibleName()); |
| 1601 const Object& result = Object::Handle( | 1558 const Object& result = Object::Handle(DartEntry::InvokeNoSuchMethod( |
| 1602 DartEntry::InvokeNoSuchMethod(receiver, | 1559 receiver, original_function_name, orig_arguments, orig_arguments_desc)); |
| 1603 original_function_name, | |
| 1604 orig_arguments, | |
| 1605 orig_arguments_desc)); | |
| 1606 CheckResultError(result); | 1560 CheckResultError(result); |
| 1607 arguments.SetReturn(result); | 1561 arguments.SetReturn(result); |
| 1608 } | 1562 } |
| 1609 | 1563 |
| 1610 | 1564 |
| 1611 DEFINE_RUNTIME_ENTRY(StackOverflow, 0) { | 1565 DEFINE_RUNTIME_ENTRY(StackOverflow, 0) { |
| 1612 #if defined(USING_SIMULATOR) | 1566 #if defined(USING_SIMULATOR) |
| 1613 uword stack_pos = Simulator::Current()->get_sp(); | 1567 uword stack_pos = Simulator::Current()->get_sp(); |
| 1614 #else | 1568 #else |
| 1615 uword stack_pos = Thread::GetCurrentStackPointer(); | 1569 uword stack_pos = Thread::GetCurrentStackPointer(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1631 UNREACHABLE(); | 1585 UNREACHABLE(); |
| 1632 } | 1586 } |
| 1633 | 1587 |
| 1634 // The following code is used to stress test deoptimization and | 1588 // The following code is used to stress test deoptimization and |
| 1635 // debugger stack tracing. | 1589 // debugger stack tracing. |
| 1636 bool do_deopt = false; | 1590 bool do_deopt = false; |
| 1637 bool do_stacktrace = false; | 1591 bool do_stacktrace = false; |
| 1638 bool do_reload = false; | 1592 bool do_reload = false; |
| 1639 const intptr_t isolate_reload_every = | 1593 const intptr_t isolate_reload_every = |
| 1640 isolate->reload_every_n_stack_overflow_checks(); | 1594 isolate->reload_every_n_stack_overflow_checks(); |
| 1641 if ((FLAG_deoptimize_every > 0) || | 1595 if ((FLAG_deoptimize_every > 0) || (FLAG_stacktrace_every > 0) || |
| 1642 (FLAG_stacktrace_every > 0) || | |
| 1643 (isolate_reload_every > 0)) { | 1596 (isolate_reload_every > 0)) { |
| 1644 // TODO(turnidge): To make --deoptimize_every and | 1597 // TODO(turnidge): To make --deoptimize_every and |
| 1645 // --stacktrace-every faster we could move this increment/test to | 1598 // --stacktrace-every faster we could move this increment/test to |
| 1646 // the generated code. | 1599 // the generated code. |
| 1647 int32_t count = thread->IncrementAndGetStackOverflowCount(); | 1600 int32_t count = thread->IncrementAndGetStackOverflowCount(); |
| 1648 if (FLAG_deoptimize_every > 0 && | 1601 if (FLAG_deoptimize_every > 0 && (count % FLAG_deoptimize_every) == 0) { |
| 1649 (count % FLAG_deoptimize_every) == 0) { | |
| 1650 do_deopt = true; | 1602 do_deopt = true; |
| 1651 } | 1603 } |
| 1652 if (FLAG_stacktrace_every > 0 && | 1604 if (FLAG_stacktrace_every > 0 && (count % FLAG_stacktrace_every) == 0) { |
| 1653 (count % FLAG_stacktrace_every) == 0) { | |
| 1654 do_stacktrace = true; | 1605 do_stacktrace = true; |
| 1655 } | 1606 } |
| 1656 if ((isolate_reload_every > 0) && | 1607 if ((isolate_reload_every > 0) && (count % isolate_reload_every) == 0) { |
| 1657 (count % isolate_reload_every) == 0) { | |
| 1658 do_reload = isolate->CanReload(); | 1608 do_reload = isolate->CanReload(); |
| 1659 } | 1609 } |
| 1660 } | 1610 } |
| 1661 if ((FLAG_deoptimize_filter != NULL) || | 1611 if ((FLAG_deoptimize_filter != NULL) || (FLAG_stacktrace_filter != NULL) || |
| 1662 (FLAG_stacktrace_filter != NULL) || | 1612 FLAG_reload_every_optimized) { |
| 1663 FLAG_reload_every_optimized) { | |
| 1664 DartFrameIterator iterator; | 1613 DartFrameIterator iterator; |
| 1665 StackFrame* frame = iterator.NextFrame(); | 1614 StackFrame* frame = iterator.NextFrame(); |
| 1666 ASSERT(frame != NULL); | 1615 ASSERT(frame != NULL); |
| 1667 const Code& code = Code::Handle(frame->LookupDartCode()); | 1616 const Code& code = Code::Handle(frame->LookupDartCode()); |
| 1668 ASSERT(!code.IsNull()); | 1617 ASSERT(!code.IsNull()); |
| 1669 const Function& function = Function::Handle(code.function()); | 1618 const Function& function = Function::Handle(code.function()); |
| 1670 ASSERT(!function.IsNull()); | 1619 ASSERT(!function.IsNull()); |
| 1671 const char* function_name = function.ToFullyQualifiedCString(); | 1620 const char* function_name = function.ToFullyQualifiedCString(); |
| 1672 ASSERT(function_name != NULL); | 1621 ASSERT(function_name != NULL); |
| 1673 if (!code.is_optimized() && FLAG_reload_every_optimized) { | 1622 if (!code.is_optimized() && FLAG_reload_every_optimized) { |
| 1674 // Don't do the reload if we aren't inside optimized code. | 1623 // Don't do the reload if we aren't inside optimized code. |
| 1675 do_reload = false; | 1624 do_reload = false; |
| 1676 } | 1625 } |
| 1677 if (code.is_optimized() && | 1626 if (code.is_optimized() && FLAG_deoptimize_filter != NULL && |
| 1678 FLAG_deoptimize_filter != NULL && | |
| 1679 strstr(function_name, FLAG_deoptimize_filter) != NULL) { | 1627 strstr(function_name, FLAG_deoptimize_filter) != NULL) { |
| 1680 OS::PrintErr("*** Forcing deoptimization (%s)\n", | 1628 OS::PrintErr("*** Forcing deoptimization (%s)\n", |
| 1681 function.ToFullyQualifiedCString()); | 1629 function.ToFullyQualifiedCString()); |
| 1682 do_deopt = true; | 1630 do_deopt = true; |
| 1683 } | 1631 } |
| 1684 if (FLAG_stacktrace_filter != NULL && | 1632 if (FLAG_stacktrace_filter != NULL && |
| 1685 strstr(function_name, FLAG_stacktrace_filter) != NULL) { | 1633 strstr(function_name, FLAG_stacktrace_filter) != NULL) { |
| 1686 OS::PrintErr("*** Computing stacktrace (%s)\n", | 1634 OS::PrintErr("*** Computing stacktrace (%s)\n", |
| 1687 function.ToFullyQualifiedCString()); | 1635 function.ToFullyQualifiedCString()); |
| 1688 do_stacktrace = true; | 1636 do_stacktrace = true; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1718 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); | 1666 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); |
| 1719 intptr_t num_frames = stack->Length(); | 1667 intptr_t num_frames = stack->Length(); |
| 1720 for (intptr_t i = 0; i < num_frames; i++) { | 1668 for (intptr_t i = 0; i < num_frames; i++) { |
| 1721 ActivationFrame* frame = stack->FrameAt(i); | 1669 ActivationFrame* frame = stack->FrameAt(i); |
| 1722 #ifndef DART_PRECOMPILED_RUNTIME | 1670 #ifndef DART_PRECOMPILED_RUNTIME |
| 1723 // Ensure that we have unoptimized code. | 1671 // Ensure that we have unoptimized code. |
| 1724 frame->function().EnsureHasCompiledUnoptimizedCode(); | 1672 frame->function().EnsureHasCompiledUnoptimizedCode(); |
| 1725 #endif | 1673 #endif |
| 1726 // Variable locations and number are unknown when precompiling. | 1674 // Variable locations and number are unknown when precompiling. |
| 1727 const int num_vars = | 1675 const int num_vars = |
| 1728 FLAG_precompiled_runtime ? 0 : frame->NumLocalVariables(); | 1676 FLAG_precompiled_runtime ? 0 : frame->NumLocalVariables(); |
| 1729 TokenPosition unused = TokenPosition::kNoSource; | 1677 TokenPosition unused = TokenPosition::kNoSource; |
| 1730 for (intptr_t v = 0; v < num_vars; v++) { | 1678 for (intptr_t v = 0; v < num_vars; v++) { |
| 1731 frame->VariableAt(v, &var_name, &unused, &unused, &unused, &var_value); | 1679 frame->VariableAt(v, &var_name, &unused, &unused, &unused, &var_value); |
| 1732 } | 1680 } |
| 1733 } | 1681 } |
| 1734 FLAG_stacktrace_every = saved_stacktrace_every; | 1682 FLAG_stacktrace_every = saved_stacktrace_every; |
| 1735 } | 1683 } |
| 1736 | 1684 |
| 1737 const Error& error = Error::Handle(thread->HandleInterrupts()); | 1685 const Error& error = Error::Handle(thread->HandleInterrupts()); |
| 1738 if (!error.IsNull()) { | 1686 if (!error.IsNull()) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1768 } | 1716 } |
| 1769 | 1717 |
| 1770 // The unoptimized code is on the stack and should never be detached from | 1718 // The unoptimized code is on the stack and should never be detached from |
| 1771 // the function at this point. | 1719 // the function at this point. |
| 1772 ASSERT(function.unoptimized_code() != Object::null()); | 1720 ASSERT(function.unoptimized_code() != Object::null()); |
| 1773 intptr_t osr_id = | 1721 intptr_t osr_id = |
| 1774 Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc()); | 1722 Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc()); |
| 1775 ASSERT(osr_id != Compiler::kNoOSRDeoptId); | 1723 ASSERT(osr_id != Compiler::kNoOSRDeoptId); |
| 1776 if (FLAG_trace_osr) { | 1724 if (FLAG_trace_osr) { |
| 1777 OS::Print("Attempting OSR for %s at id=%" Pd ", count=%" Pd "\n", | 1725 OS::Print("Attempting OSR for %s at id=%" Pd ", count=%" Pd "\n", |
| 1778 function.ToFullyQualifiedCString(), | 1726 function.ToFullyQualifiedCString(), osr_id, |
| 1779 osr_id, | |
| 1780 function.usage_counter()); | 1727 function.usage_counter()); |
| 1781 } | 1728 } |
| 1782 | 1729 |
| 1783 const Code& original_code = Code::Handle(function.CurrentCode()); | 1730 const Code& original_code = Code::Handle(function.CurrentCode()); |
| 1784 // Since the code is referenced from the frame and the ZoneHandle, | 1731 // Since the code is referenced from the frame and the ZoneHandle, |
| 1785 // it cannot have been removed from the function. | 1732 // it cannot have been removed from the function. |
| 1786 ASSERT(!original_code.IsNull()); | 1733 ASSERT(!original_code.IsNull()); |
| 1787 const Error& error = Error::Handle(Compiler::CompileOptimizedFunction( | 1734 const Error& error = Error::Handle( |
| 1788 thread, function, osr_id)); | 1735 Compiler::CompileOptimizedFunction(thread, function, osr_id)); |
| 1789 if (!error.IsNull()) { | 1736 if (!error.IsNull()) { |
| 1790 Exceptions::PropagateError(error); | 1737 Exceptions::PropagateError(error); |
| 1791 } | 1738 } |
| 1792 | 1739 |
| 1793 const Code& optimized_code = Code::Handle(function.CurrentCode()); | 1740 const Code& optimized_code = Code::Handle(function.CurrentCode()); |
| 1794 // The current code will not be changed in the case that the compiler | 1741 // The current code will not be changed in the case that the compiler |
| 1795 // bailed out during OSR compilation. | 1742 // bailed out during OSR compilation. |
| 1796 if (optimized_code.raw() != original_code.raw()) { | 1743 if (optimized_code.raw() != original_code.raw()) { |
| 1797 // The OSR code does not work for calling the function, so restore the | 1744 // The OSR code does not work for calling the function, so restore the |
| 1798 // unoptimized code. Patch the stack frame to return into the OSR | 1745 // unoptimized code. Patch the stack frame to return into the OSR |
| 1799 // code. | 1746 // code. |
| 1800 uword optimized_entry = | 1747 uword optimized_entry = |
| 1801 Instructions::UncheckedEntryPoint(optimized_code.instructions()); | 1748 Instructions::UncheckedEntryPoint(optimized_code.instructions()); |
| 1802 function.AttachCode(original_code); | 1749 function.AttachCode(original_code); |
| 1803 frame->set_pc(optimized_entry); | 1750 frame->set_pc(optimized_entry); |
| 1804 frame->set_pc_marker(optimized_code.raw()); | 1751 frame->set_pc_marker(optimized_code.raw()); |
| 1805 } | 1752 } |
| 1806 } | 1753 } |
| 1807 } | 1754 } |
| 1808 | 1755 |
| 1809 | 1756 |
| 1810 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) { | 1757 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) { |
| 1811 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0)); | 1758 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0)); |
| 1812 const Function& function = Function::CheckedHandle(arguments.ArgAt(1)); | 1759 const Function& function = Function::CheckedHandle(arguments.ArgAt(1)); |
| 1813 DartFrameIterator iterator; | 1760 DartFrameIterator iterator; |
| 1814 StackFrame* frame = iterator.NextFrame(); | 1761 StackFrame* frame = iterator.NextFrame(); |
| 1815 ASSERT(frame != NULL); | 1762 ASSERT(frame != NULL); |
| 1816 OS::PrintErr("IC call @%#" Px ": ICData: %p cnt:%" Pd " nchecks: %" Pd | 1763 OS::PrintErr("IC call @%#" Px ": ICData: %p cnt:%" Pd " nchecks: %" Pd |
| 1817 " %s\n", | 1764 " %s\n", |
| 1818 frame->pc(), | 1765 frame->pc(), ic_data.raw(), function.usage_counter(), |
| 1819 ic_data.raw(), | 1766 ic_data.NumberOfChecks(), function.ToFullyQualifiedCString()); |
| 1820 function.usage_counter(), | |
| 1821 ic_data.NumberOfChecks(), | |
| 1822 function.ToFullyQualifiedCString()); | |
| 1823 } | 1767 } |
| 1824 | 1768 |
| 1825 | 1769 |
| 1826 // This is called from function that needs to be optimized. | 1770 // This is called from function that needs to be optimized. |
| 1827 // The requesting function can be already optimized (reoptimization). | 1771 // The requesting function can be already optimized (reoptimization). |
| 1828 // Returns the Code object where to continue execution. | 1772 // Returns the Code object where to continue execution. |
| 1829 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { | 1773 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { |
| 1830 #if !defined(DART_PRECOMPILED_RUNTIME) | 1774 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 1831 const Function& function = Function::CheckedHandle(zone, | 1775 const Function& function = Function::CheckedHandle(zone, arguments.ArgAt(0)); |
| 1832 arguments.ArgAt(0)); | |
| 1833 ASSERT(!function.IsNull()); | 1776 ASSERT(!function.IsNull()); |
| 1834 ASSERT(function.HasCode()); | 1777 ASSERT(function.HasCode()); |
| 1835 | 1778 |
| 1836 if (Compiler::CanOptimizeFunction(thread, function)) { | 1779 if (Compiler::CanOptimizeFunction(thread, function)) { |
| 1837 if (FLAG_background_compilation) { | 1780 if (FLAG_background_compilation) { |
| 1838 Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField()); | 1781 Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField()); |
| 1839 while (!field.IsNull()) { | 1782 while (!field.IsNull()) { |
| 1840 if (FLAG_trace_optimization || FLAG_trace_field_guards) { | 1783 if (FLAG_trace_optimization || FLAG_trace_field_guards) { |
| 1841 THR_Print("Lazy disabling unboxing of %s\n", field.ToCString()); | 1784 THR_Print("Lazy disabling unboxing of %s\n", field.ToCString()); |
| 1842 } | 1785 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1907 // Since function's current code is always unpatched, the entry frame always | 1850 // Since function's current code is always unpatched, the entry frame always |
| 1908 // calls to unpatched code. | 1851 // calls to unpatched code. |
| 1909 UNREACHABLE(); | 1852 UNREACHABLE(); |
| 1910 } | 1853 } |
| 1911 ASSERT(frame->IsDartFrame()); | 1854 ASSERT(frame->IsDartFrame()); |
| 1912 const Code& caller_code = Code::Handle(zone, frame->LookupDartCode()); | 1855 const Code& caller_code = Code::Handle(zone, frame->LookupDartCode()); |
| 1913 ASSERT(caller_code.is_optimized()); | 1856 ASSERT(caller_code.is_optimized()); |
| 1914 const Function& target_function = Function::Handle( | 1857 const Function& target_function = Function::Handle( |
| 1915 zone, caller_code.GetStaticCallTargetFunctionAt(frame->pc())); | 1858 zone, caller_code.GetStaticCallTargetFunctionAt(frame->pc())); |
| 1916 if (!target_function.HasCode()) { | 1859 if (!target_function.HasCode()) { |
| 1917 const Error& error = Error::Handle( | 1860 const Error& error = |
| 1918 zone, Compiler::CompileFunction(thread, target_function)); | 1861 Error::Handle(zone, Compiler::CompileFunction(thread, target_function)); |
| 1919 if (!error.IsNull()) { | 1862 if (!error.IsNull()) { |
| 1920 Exceptions::PropagateError(error); | 1863 Exceptions::PropagateError(error); |
| 1921 } | 1864 } |
| 1922 } | 1865 } |
| 1923 ASSERT(target_function.HasCode()); | 1866 ASSERT(target_function.HasCode()); |
| 1924 | 1867 |
| 1925 const Code& current_target_code = Code::Handle( | 1868 const Code& current_target_code = |
| 1926 zone, target_function.CurrentCode()); | 1869 Code::Handle(zone, target_function.CurrentCode()); |
| 1927 CodePatcher::PatchStaticCallAt(frame->pc(), | 1870 CodePatcher::PatchStaticCallAt(frame->pc(), caller_code, current_target_code); |
| 1928 caller_code, | |
| 1929 current_target_code); | |
| 1930 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code); | 1871 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code); |
| 1931 if (FLAG_trace_patching) { | 1872 if (FLAG_trace_patching) { |
| 1932 OS::PrintErr("FixCallersTarget: caller %#" Px " " | 1873 OS::PrintErr("FixCallersTarget: caller %#" Px |
| 1874 " " |
| 1933 "target '%s' -> %#" Px "\n", | 1875 "target '%s' -> %#" Px "\n", |
| 1934 frame->pc(), | 1876 frame->pc(), target_function.ToFullyQualifiedCString(), |
| 1935 target_function.ToFullyQualifiedCString(), | |
| 1936 current_target_code.UncheckedEntryPoint()); | 1877 current_target_code.UncheckedEntryPoint()); |
| 1937 } | 1878 } |
| 1938 ASSERT(!current_target_code.IsDisabled()); | 1879 ASSERT(!current_target_code.IsDisabled()); |
| 1939 arguments.SetReturn(current_target_code); | 1880 arguments.SetReturn(current_target_code); |
| 1940 } | 1881 } |
| 1941 | 1882 |
| 1942 | 1883 |
| 1943 // The caller tried to allocate an instance via an invalidated allocation | 1884 // The caller tried to allocate an instance via an invalidated allocation |
| 1944 // stub. | 1885 // stub. |
| 1945 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { | 1886 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1960 ASSERT(!caller_code.IsNull()); | 1901 ASSERT(!caller_code.IsNull()); |
| 1961 const Code& stub = Code::Handle( | 1902 const Code& stub = Code::Handle( |
| 1962 CodePatcher::GetStaticCallTargetAt(frame->pc(), caller_code)); | 1903 CodePatcher::GetStaticCallTargetAt(frame->pc(), caller_code)); |
| 1963 Class& alloc_class = Class::ZoneHandle(zone); | 1904 Class& alloc_class = Class::ZoneHandle(zone); |
| 1964 alloc_class ^= stub.owner(); | 1905 alloc_class ^= stub.owner(); |
| 1965 Code& alloc_stub = Code::Handle(zone, alloc_class.allocation_stub()); | 1906 Code& alloc_stub = Code::Handle(zone, alloc_class.allocation_stub()); |
| 1966 if (alloc_stub.IsNull()) { | 1907 if (alloc_stub.IsNull()) { |
| 1967 alloc_stub = StubCode::GetAllocationStubForClass(alloc_class); | 1908 alloc_stub = StubCode::GetAllocationStubForClass(alloc_class); |
| 1968 ASSERT(!alloc_stub.IsDisabled()); | 1909 ASSERT(!alloc_stub.IsDisabled()); |
| 1969 } | 1910 } |
| 1970 CodePatcher::PatchStaticCallAt(frame->pc(), | 1911 CodePatcher::PatchStaticCallAt(frame->pc(), caller_code, alloc_stub); |
| 1971 caller_code, | |
| 1972 alloc_stub); | |
| 1973 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub); | 1912 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub); |
| 1974 if (FLAG_trace_patching) { | 1913 if (FLAG_trace_patching) { |
| 1975 OS::PrintErr("FixAllocationStubTarget: caller %#" Px " alloc-class %s " | 1914 OS::PrintErr("FixAllocationStubTarget: caller %#" Px |
| 1976 " -> %#" Px "\n", | 1915 " alloc-class %s " |
| 1977 frame->pc(), | 1916 " -> %#" Px "\n", |
| 1978 alloc_class.ToCString(), | 1917 frame->pc(), alloc_class.ToCString(), |
| 1979 alloc_stub.UncheckedEntryPoint()); | 1918 alloc_stub.UncheckedEntryPoint()); |
| 1980 } | 1919 } |
| 1981 arguments.SetReturn(alloc_stub); | 1920 arguments.SetReturn(alloc_stub); |
| 1982 #else | 1921 #else |
| 1983 UNREACHABLE(); | 1922 UNREACHABLE(); |
| 1984 #endif | 1923 #endif |
| 1985 } | 1924 } |
| 1986 | 1925 |
| 1987 | 1926 |
| 1988 const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason) { | 1927 const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason) { |
| 1989 switch (deopt_reason) { | 1928 switch (deopt_reason) { |
| 1990 #define DEOPT_REASON_TO_TEXT(name) case ICData::kDeopt##name: return #name; | 1929 #define DEOPT_REASON_TO_TEXT(name) \ |
| 1991 DEOPT_REASONS(DEOPT_REASON_TO_TEXT) | 1930 case ICData::kDeopt##name: \ |
| 1931 return #name; |
| 1932 DEOPT_REASONS(DEOPT_REASON_TO_TEXT) |
| 1992 #undef DEOPT_REASON_TO_TEXT | 1933 #undef DEOPT_REASON_TO_TEXT |
| 1993 default: | 1934 default: |
| 1994 UNREACHABLE(); | 1935 UNREACHABLE(); |
| 1995 return ""; | 1936 return ""; |
| 1996 } | 1937 } |
| 1997 } | 1938 } |
| 1998 | 1939 |
| 1999 | 1940 |
| 2000 void DeoptimizeAt(const Code& optimized_code, StackFrame* frame) { | 1941 void DeoptimizeAt(const Code& optimized_code, StackFrame* frame) { |
| 2001 ASSERT(optimized_code.is_optimized()); | 1942 ASSERT(optimized_code.is_optimized()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2016 } | 1957 } |
| 2017 | 1958 |
| 2018 #if defined(TARGET_ARCH_DBC) | 1959 #if defined(TARGET_ARCH_DBC) |
| 2019 const Instructions& instrs = | 1960 const Instructions& instrs = |
| 2020 Instructions::Handle(zone, optimized_code.instructions()); | 1961 Instructions::Handle(zone, optimized_code.instructions()); |
| 2021 { | 1962 { |
| 2022 WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size()); | 1963 WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size()); |
| 2023 CodePatcher::InsertDeoptimizationCallAt(frame->pc()); | 1964 CodePatcher::InsertDeoptimizationCallAt(frame->pc()); |
| 2024 if (FLAG_trace_patching) { | 1965 if (FLAG_trace_patching) { |
| 2025 const String& name = String::Handle(function.name()); | 1966 const String& name = String::Handle(function.name()); |
| 2026 OS::PrintErr( | 1967 OS::PrintErr("InsertDeoptimizationCallAt: 0x%" Px " for %s\n", |
| 2027 "InsertDeoptimizationCallAt: 0x%" Px " for %s\n", | 1968 frame->pc(), name.ToCString()); |
| 2028 frame->pc(), name.ToCString()); | |
| 2029 } | 1969 } |
| 2030 const ExceptionHandlers& handlers = | 1970 const ExceptionHandlers& handlers = |
| 2031 ExceptionHandlers::Handle(zone, optimized_code.exception_handlers()); | 1971 ExceptionHandlers::Handle(zone, optimized_code.exception_handlers()); |
| 2032 RawExceptionHandlers::HandlerInfo info; | 1972 RawExceptionHandlers::HandlerInfo info; |
| 2033 for (intptr_t i = 0; i < handlers.num_entries(); ++i) { | 1973 for (intptr_t i = 0; i < handlers.num_entries(); ++i) { |
| 2034 handlers.GetHandlerInfo(i, &info); | 1974 handlers.GetHandlerInfo(i, &info); |
| 2035 const uword patch_pc = instrs.PayloadStart() + info.handler_pc_offset; | 1975 const uword patch_pc = instrs.PayloadStart() + info.handler_pc_offset; |
| 2036 CodePatcher::InsertDeoptimizationCallAt(patch_pc); | 1976 CodePatcher::InsertDeoptimizationCallAt(patch_pc); |
| 2037 if (FLAG_trace_patching) { | 1977 if (FLAG_trace_patching) { |
| 2038 OS::PrintErr(" at handler 0x%" Px "\n", patch_pc); | 1978 OS::PrintErr(" at handler 0x%" Px "\n", patch_pc); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2119 *cpu_registers = cpu_registers_copy; | 2059 *cpu_registers = cpu_registers_copy; |
| 2120 } | 2060 } |
| 2121 #endif | 2061 #endif |
| 2122 | 2062 |
| 2123 | 2063 |
| 2124 // Copies saved registers and caller's frame into temporary buffers. | 2064 // Copies saved registers and caller's frame into temporary buffers. |
| 2125 // Returns the stack size of unoptimized frame. | 2065 // Returns the stack size of unoptimized frame. |
| 2126 // The calling code must be optimized, but its function may not have | 2066 // The calling code must be optimized, but its function may not have |
| 2127 // have optimized code if the code is OSR code, or if the code was invalidated | 2067 // have optimized code if the code is OSR code, or if the code was invalidated |
| 2128 // through class loading/finalization or field guard. | 2068 // through class loading/finalization or field guard. |
| 2129 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 2069 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, |
| 2070 DeoptimizeCopyFrame, |
| 2130 2, | 2071 2, |
| 2131 uword saved_registers_address, | 2072 uword saved_registers_address, |
| 2132 uword is_lazy_deopt) { | 2073 uword is_lazy_deopt) { |
| 2133 #if !defined(DART_PRECOMPILED_RUNTIME) | 2074 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 2134 Thread* thread = Thread::Current(); | 2075 Thread* thread = Thread::Current(); |
| 2135 Isolate* isolate = thread->isolate(); | 2076 Isolate* isolate = thread->isolate(); |
| 2136 StackZone zone(thread); | 2077 StackZone zone(thread); |
| 2137 HANDLESCOPE(thread); | 2078 HANDLESCOPE(thread); |
| 2138 | 2079 |
| 2139 // All registers have been saved below last-fp as if they were locals. | 2080 // All registers have been saved below last-fp as if they were locals. |
| 2140 const uword last_fp = saved_registers_address | 2081 const uword last_fp = saved_registers_address + |
| 2141 + (kNumberOfSavedCpuRegisters * kWordSize) | 2082 (kNumberOfSavedCpuRegisters * kWordSize) + |
| 2142 + (kNumberOfSavedFpuRegisters * kFpuRegisterSize) | 2083 (kNumberOfSavedFpuRegisters * kFpuRegisterSize) - |
| 2143 - ((kFirstLocalSlotFromFp + 1) * kWordSize); | 2084 ((kFirstLocalSlotFromFp + 1) * kWordSize); |
| 2144 | 2085 |
| 2145 // Get optimized code and frame that need to be deoptimized. | 2086 // Get optimized code and frame that need to be deoptimized. |
| 2146 DartFrameIterator iterator(last_fp); | 2087 DartFrameIterator iterator(last_fp); |
| 2147 | 2088 |
| 2148 StackFrame* caller_frame = iterator.NextFrame(); | 2089 StackFrame* caller_frame = iterator.NextFrame(); |
| 2149 ASSERT(caller_frame != NULL); | 2090 ASSERT(caller_frame != NULL); |
| 2150 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 2091 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
| 2151 ASSERT(optimized_code.is_optimized()); | 2092 ASSERT(optimized_code.is_optimized()); |
| 2152 const Function& top_function = | 2093 const Function& top_function = |
| 2153 Function::Handle(thread->zone(), optimized_code.function()); | 2094 Function::Handle(thread->zone(), optimized_code.function()); |
| 2154 const bool deoptimizing_code = top_function.HasOptimizedCode(); | 2095 const bool deoptimizing_code = top_function.HasOptimizedCode(); |
| 2155 if (FLAG_trace_deoptimization) { | 2096 if (FLAG_trace_deoptimization) { |
| 2156 const Function& function = Function::Handle(optimized_code.function()); | 2097 const Function& function = Function::Handle(optimized_code.function()); |
| 2157 THR_Print("== Deoptimizing code for '%s', %s, %s\n", | 2098 THR_Print("== Deoptimizing code for '%s', %s, %s\n", |
| 2158 function.ToFullyQualifiedCString(), | 2099 function.ToFullyQualifiedCString(), |
| 2159 deoptimizing_code ? "code & frame" : "frame", | 2100 deoptimizing_code ? "code & frame" : "frame", |
| 2160 is_lazy_deopt ? "lazy-deopt" : ""); | 2101 is_lazy_deopt ? "lazy-deopt" : ""); |
| 2161 } | 2102 } |
| 2162 | 2103 |
| 2163 #if !defined(TARGET_ARCH_DBC) | 2104 #if !defined(TARGET_ARCH_DBC) |
| 2164 if (is_lazy_deopt) { | 2105 if (is_lazy_deopt) { |
| 2165 uword deopt_pc = isolate->FindPendingDeopt(caller_frame->fp()); | 2106 uword deopt_pc = isolate->FindPendingDeopt(caller_frame->fp()); |
| 2166 if (FLAG_trace_deoptimization) { | 2107 if (FLAG_trace_deoptimization) { |
| 2167 THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n", | 2108 THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n", caller_frame->fp(), |
| 2168 caller_frame->fp(), deopt_pc); | 2109 deopt_pc); |
| 2169 } | 2110 } |
| 2170 | 2111 |
| 2171 // N.B.: Update frame before updating pending deopt table. The profiler | 2112 // N.B.: Update frame before updating pending deopt table. The profiler |
| 2172 // may attempt a stack walk in between. | 2113 // may attempt a stack walk in between. |
| 2173 caller_frame->set_pc(deopt_pc); | 2114 caller_frame->set_pc(deopt_pc); |
| 2174 ASSERT(caller_frame->pc() == deopt_pc); | 2115 ASSERT(caller_frame->pc() == deopt_pc); |
| 2175 ASSERT(optimized_code.ContainsInstructionAt(caller_frame->pc())); | 2116 ASSERT(optimized_code.ContainsInstructionAt(caller_frame->pc())); |
| 2176 isolate->ClearPendingDeoptsAtOrBelow(caller_frame->fp()); | 2117 isolate->ClearPendingDeoptsAtOrBelow(caller_frame->fp()); |
| 2177 } else { | 2118 } else { |
| 2178 if (FLAG_trace_deoptimization) { | 2119 if (FLAG_trace_deoptimization) { |
| 2179 THR_Print("Eager deopt fp=%" Pp " pc=%" Pp "\n", | 2120 THR_Print("Eager deopt fp=%" Pp " pc=%" Pp "\n", caller_frame->fp(), |
| 2180 caller_frame->fp(), caller_frame->pc()); | 2121 caller_frame->pc()); |
| 2181 } | 2122 } |
| 2182 } | 2123 } |
| 2183 #endif // !DBC | 2124 #endif // !DBC |
| 2184 | 2125 |
| 2185 // Copy the saved registers from the stack. | 2126 // Copy the saved registers from the stack. |
| 2186 fpu_register_t* fpu_registers; | 2127 fpu_register_t* fpu_registers; |
| 2187 intptr_t* cpu_registers; | 2128 intptr_t* cpu_registers; |
| 2188 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); | 2129 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); |
| 2189 | 2130 |
| 2190 // Create the DeoptContext. | 2131 // Create the DeoptContext. |
| 2191 DeoptContext* deopt_context = | 2132 DeoptContext* deopt_context = new DeoptContext( |
| 2192 new DeoptContext(caller_frame, | 2133 caller_frame, optimized_code, DeoptContext::kDestIsOriginalFrame, |
| 2193 optimized_code, | 2134 fpu_registers, cpu_registers, is_lazy_deopt != 0, deoptimizing_code); |
| 2194 DeoptContext::kDestIsOriginalFrame, | |
| 2195 fpu_registers, | |
| 2196 cpu_registers, | |
| 2197 is_lazy_deopt != 0, | |
| 2198 deoptimizing_code); | |
| 2199 isolate->set_deopt_context(deopt_context); | 2135 isolate->set_deopt_context(deopt_context); |
| 2200 | 2136 |
| 2201 // Stack size (FP - SP) in bytes. | 2137 // Stack size (FP - SP) in bytes. |
| 2202 return deopt_context->DestStackAdjustment() * kWordSize; | 2138 return deopt_context->DestStackAdjustment() * kWordSize; |
| 2203 #else | 2139 #else |
| 2204 UNREACHABLE(); | 2140 UNREACHABLE(); |
| 2205 return 0; | 2141 return 0; |
| 2206 #endif // !DART_PRECOMPILED_RUNTIME | 2142 #endif // !DART_PRECOMPILED_RUNTIME |
| 2207 } | 2143 } |
| 2208 END_LEAF_RUNTIME_ENTRY | 2144 END_LEAF_RUNTIME_ENTRY |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2345 const intptr_t elm_size = old_data.ElementSizeInBytes(); | 2281 const intptr_t elm_size = old_data.ElementSizeInBytes(); |
| 2346 const TypedData& new_data = | 2282 const TypedData& new_data = |
| 2347 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); | 2283 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); |
| 2348 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); | 2284 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); |
| 2349 typed_data_cell.SetAt(0, new_data); | 2285 typed_data_cell.SetAt(0, new_data); |
| 2350 arguments.SetReturn(new_data); | 2286 arguments.SetReturn(new_data); |
| 2351 } | 2287 } |
| 2352 | 2288 |
| 2353 | 2289 |
| 2354 } // namespace dart | 2290 } // namespace dart |
| OLD | NEW |