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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 // Arg0: uninstantiated type. | 197 // Arg0: uninstantiated type. |
198 // Arg1: instantiator type arguments. | 198 // Arg1: instantiator type arguments. |
199 // Return value: instantiated type. | 199 // Return value: instantiated type. |
200 DEFINE_RUNTIME_ENTRY(InstantiateType, 2) { | 200 DEFINE_RUNTIME_ENTRY(InstantiateType, 2) { |
201 AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(0)); | 201 AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(0)); |
202 const TypeArguments& instantiator = | 202 const TypeArguments& instantiator = |
203 TypeArguments::CheckedHandle(arguments.ArgAt(1)); | 203 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
204 ASSERT(!type.IsNull() && !type.IsInstantiated()); | 204 ASSERT(!type.IsNull() && !type.IsInstantiated()); |
205 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 205 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
206 Error& bound_error = Error::Handle(); | 206 Error& bound_error = Error::Handle(); |
207 type = type.InstantiateFrom(instantiator, &bound_error); | 207 type = type.InstantiateFrom(instantiator, &bound_error, NULL, Heap::kOld); |
208 if (!bound_error.IsNull()) { | 208 if (!bound_error.IsNull()) { |
209 // Throw a dynamic type error. | 209 // Throw a dynamic type error. |
210 const intptr_t location = GetCallerLocation(); | 210 const intptr_t location = GetCallerLocation(); |
211 String& bound_error_message = String::Handle( | 211 String& bound_error_message = String::Handle( |
212 String::New(bound_error.ToErrorCString())); | 212 String::New(bound_error.ToErrorCString())); |
213 Exceptions::CreateAndThrowTypeError( | 213 Exceptions::CreateAndThrowTypeError( |
214 location, Symbols::Empty(), Symbols::Empty(), | 214 location, Symbols::Empty(), Symbols::Empty(), |
215 Symbols::Empty(), bound_error_message); | 215 Symbols::Empty(), bound_error_message); |
216 UNREACHABLE(); | 216 UNREACHABLE(); |
217 } | 217 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 static void PrintTypeCheck( | 293 static void PrintTypeCheck( |
294 const char* message, | 294 const char* message, |
295 const Instance& instance, | 295 const Instance& instance, |
296 const AbstractType& type, | 296 const AbstractType& type, |
297 const TypeArguments& instantiator_type_arguments, | 297 const TypeArguments& instantiator_type_arguments, |
298 const Bool& result) { | 298 const Bool& result) { |
299 DartFrameIterator iterator; | 299 DartFrameIterator iterator; |
300 StackFrame* caller_frame = iterator.NextFrame(); | 300 StackFrame* caller_frame = iterator.NextFrame(); |
301 ASSERT(caller_frame != NULL); | 301 ASSERT(caller_frame != NULL); |
302 | 302 |
303 const Type& instance_type = Type::Handle(instance.GetType()); | 303 const AbstractType& instance_type = AbstractType::Handle(instance.GetType()); |
304 ASSERT(instance_type.IsInstantiated()); | 304 ASSERT(instance_type.IsInstantiated()); |
305 if (type.IsInstantiated()) { | 305 if (type.IsInstantiated()) { |
306 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", | 306 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", |
307 message, | 307 message, |
308 String::Handle(instance_type.Name()).ToCString(), | 308 String::Handle(instance_type.Name()).ToCString(), |
309 Class::Handle(instance_type.type_class()).id(), | 309 Class::Handle(instance_type.type_class()).id(), |
310 (result.raw() == Bool::True().raw()) ? "is" : "is !", | 310 (result.raw() == Bool::True().raw()) ? "is" : "is !", |
311 String::Handle(type.Name()).ToCString(), | 311 String::Handle(type.Name()).ToCString(), |
312 Class::Handle(type.type_class()).id(), | 312 Class::Handle(type.type_class()).id(), |
313 caller_frame->pc()); | 313 caller_frame->pc()); |
(...skipping 13 matching lines...) Expand all Loading... |
327 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); | 327 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); |
328 } | 328 } |
329 } | 329 } |
330 const Function& function = Function::Handle( | 330 const Function& function = Function::Handle( |
331 caller_frame->LookupDartFunction()); | 331 caller_frame->LookupDartFunction()); |
332 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); | 332 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); |
333 } | 333 } |
334 | 334 |
335 | 335 |
336 // This updates the type test cache, an array containing 4-value elements | 336 // This updates the type test cache, an array containing 4-value elements |
337 // (instance class, instance type arguments, instantiator type arguments and | 337 // (instance class (or function if the instance is a closure), instance type |
338 // test_result). It can be applied to classes with type arguments in which | 338 // arguments, instantiator type arguments and test_result). It can be applied to |
339 // case it contains just the result of the class subtype test, not including | 339 // classes with type arguments in which case it contains just the result of the |
340 // the evaluation of type arguments. | 340 // class subtype test, not including the evaluation of type arguments. |
341 // This operation is currently very slow (lookup of code is not efficient yet). | 341 // This operation is currently very slow (lookup of code is not efficient yet). |
342 static void UpdateTypeTestCache( | 342 static void UpdateTypeTestCache( |
343 const Instance& instance, | 343 const Instance& instance, |
344 const AbstractType& type, | 344 const AbstractType& type, |
345 const TypeArguments& instantiator_type_arguments, | 345 const TypeArguments& instantiator_type_arguments, |
346 const Bool& result, | 346 const Bool& result, |
347 const SubtypeTestCache& new_cache) { | 347 const SubtypeTestCache& new_cache) { |
348 // Since the test is expensive, don't do it unless necessary. | 348 // Since the test is expensive, don't do it unless necessary. |
349 // The list of disallowed cases will decrease as they are implemented in | 349 // The list of disallowed cases will decrease as they are implemented in |
350 // inlined assembly. | 350 // inlined assembly. |
351 if (new_cache.IsNull()) { | 351 if (new_cache.IsNull()) { |
352 if (FLAG_trace_type_checks) { | 352 if (FLAG_trace_type_checks) { |
353 OS::Print("UpdateTypeTestCache: cache is null\n"); | 353 OS::Print("UpdateTypeTestCache: cache is null\n"); |
354 } | 354 } |
355 return; | 355 return; |
356 } | 356 } |
357 if (instance.IsSmi()) { | 357 if (instance.IsSmi()) { |
358 if (FLAG_trace_type_checks) { | 358 if (FLAG_trace_type_checks) { |
359 OS::Print("UpdateTypeTestCache: instance is Smi\n"); | 359 OS::Print("UpdateTypeTestCache: instance is Smi\n"); |
360 } | 360 } |
361 return; | 361 return; |
362 } | 362 } |
363 TypeArguments& instance_type_arguments = | |
364 TypeArguments::Handle(); | |
365 const Class& instance_class = Class::Handle(instance.clazz()); | 363 const Class& instance_class = Class::Handle(instance.clazz()); |
366 | 364 Object& instance_class_id_or_function = Object::Handle(); |
367 if (instance_class.NumTypeArguments() > 0) { | 365 if (instance_class.IsClosureClass()) { |
| 366 instance_class_id_or_function = Closure::Cast(instance).function(); |
| 367 } else { |
| 368 instance_class_id_or_function = Smi::New(instance_class.id()); |
| 369 } |
| 370 TypeArguments& instance_type_arguments = TypeArguments::Handle(); |
| 371 if (instance_class.IsClosureClass() || |
| 372 (instance_class.NumTypeArguments() > 0)) { |
368 instance_type_arguments = instance.GetTypeArguments(); | 373 instance_type_arguments = instance.GetTypeArguments(); |
369 } | 374 } |
370 | 375 |
371 const intptr_t len = new_cache.NumberOfChecks(); | 376 const intptr_t len = new_cache.NumberOfChecks(); |
372 if (len >= FLAG_max_subtype_cache_entries) { | 377 if (len >= FLAG_max_subtype_cache_entries) { |
373 return; | 378 return; |
374 } | 379 } |
375 #if defined(DEBUG) | 380 #if defined(DEBUG) |
376 ASSERT(instance_type_arguments.IsNull() || | 381 ASSERT(instance_type_arguments.IsNull() || |
377 instance_type_arguments.IsCanonical()); | 382 instance_type_arguments.IsCanonical()); |
378 ASSERT(instantiator_type_arguments.IsNull() || | 383 ASSERT(instantiator_type_arguments.IsNull() || |
379 instantiator_type_arguments.IsCanonical()); | 384 instantiator_type_arguments.IsCanonical()); |
380 intptr_t last_instance_class_id = -1; | 385 Object& last_instance_class_id_or_function = Object::Handle(); |
381 TypeArguments& last_instance_type_arguments = | 386 TypeArguments& last_instance_type_arguments = TypeArguments::Handle(); |
382 TypeArguments::Handle(); | 387 TypeArguments& last_instantiator_type_arguments = TypeArguments::Handle(); |
383 TypeArguments& last_instantiator_type_arguments = | |
384 TypeArguments::Handle(); | |
385 Bool& last_result = Bool::Handle(); | 388 Bool& last_result = Bool::Handle(); |
386 for (intptr_t i = 0; i < len; ++i) { | 389 for (intptr_t i = 0; i < len; ++i) { |
387 new_cache.GetCheck( | 390 new_cache.GetCheck( |
388 i, | 391 i, |
389 &last_instance_class_id, | 392 &last_instance_class_id_or_function, |
390 &last_instance_type_arguments, | 393 &last_instance_type_arguments, |
391 &last_instantiator_type_arguments, | 394 &last_instantiator_type_arguments, |
392 &last_result); | 395 &last_result); |
393 if ((last_instance_class_id == instance_class.id()) && | 396 if ((last_instance_class_id_or_function.raw() == |
| 397 instance_class_id_or_function.raw()) && |
394 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && | 398 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && |
395 (last_instantiator_type_arguments.raw() == | 399 (last_instantiator_type_arguments.raw() == |
396 instantiator_type_arguments.raw())) { | 400 instantiator_type_arguments.raw())) { |
397 OS::PrintErr(" Error in test cache %p ix: %" Pd ",", new_cache.raw(), i); | 401 OS::PrintErr(" Error in test cache %p ix: %" Pd ",", new_cache.raw(), i); |
398 PrintTypeCheck(" duplicate cache entry", instance, type, | 402 PrintTypeCheck(" duplicate cache entry", instance, type, |
399 instantiator_type_arguments, result); | 403 instantiator_type_arguments, result); |
400 UNREACHABLE(); | 404 UNREACHABLE(); |
401 return; | 405 return; |
402 } | 406 } |
403 } | 407 } |
404 #endif | 408 #endif |
405 new_cache.AddCheck(instance_class.id(), | 409 new_cache.AddCheck(instance_class_id_or_function, |
406 instance_type_arguments, | 410 instance_type_arguments, |
407 instantiator_type_arguments, | 411 instantiator_type_arguments, |
408 result); | 412 result); |
409 if (FLAG_trace_type_checks) { | 413 if (FLAG_trace_type_checks) { |
410 AbstractType& test_type = AbstractType::Handle(type.raw()); | 414 AbstractType& test_type = AbstractType::Handle(type.raw()); |
411 if (!test_type.IsInstantiated()) { | 415 if (!test_type.IsInstantiated()) { |
412 Error& bound_error = Error::Handle(); | 416 Error& bound_error = Error::Handle(); |
413 test_type = type.InstantiateFrom(instantiator_type_arguments, | 417 test_type = type.InstantiateFrom(instantiator_type_arguments, |
414 &bound_error); | 418 &bound_error); |
415 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. | 419 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. |
416 } | 420 } |
417 OS::PrintErr(" Updated test cache %p ix: %" Pd " with " | 421 OS::PrintErr(" Updated test cache %p ix: %" Pd " with " |
418 "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n" | 422 "(cid-or-fun: %p, type-args: %p, instantiator: %p, result: %s)\n" |
419 " instance [class: (%p '%s' cid: %" Pd "), type-args: %p %s]\n" | 423 " instance [class: (%p '%s' cid: %" Pd "), type-args: %p %s]\n" |
420 " test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n", | 424 " test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n", |
421 new_cache.raw(), | 425 new_cache.raw(), |
422 len, | 426 len, |
423 | 427 |
424 instance_class.id(), | 428 instance_class_id_or_function.raw(), |
425 instance_type_arguments.raw(), | 429 instance_type_arguments.raw(), |
426 instantiator_type_arguments.raw(), | 430 instantiator_type_arguments.raw(), |
427 result.ToCString(), | 431 result.ToCString(), |
428 | 432 |
429 instance_class.raw(), | 433 instance_class.raw(), |
430 String::Handle(instance_class.Name()).ToCString(), | 434 String::Handle(instance_class.Name()).ToCString(), |
431 instance_class.id(), | 435 instance_class.id(), |
432 instance_type_arguments.raw(), | 436 instance_type_arguments.raw(), |
433 instance_type_arguments.ToCString(), | 437 instance_type_arguments.ToCString(), |
434 | 438 |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 const int kNumArguments = 1; | 742 const int kNumArguments = 1; |
739 ArgumentsDescriptor args_desc( | 743 ArgumentsDescriptor args_desc( |
740 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); | 744 Array::Handle(ArgumentsDescriptor::New(kNumArguments))); |
741 const Function& getter = Function::Handle( | 745 const Function& getter = Function::Handle( |
742 Resolver::ResolveDynamicForReceiverClass(receiver_class, | 746 Resolver::ResolveDynamicForReceiverClass(receiver_class, |
743 getter_name, | 747 getter_name, |
744 args_desc)); | 748 args_desc)); |
745 if (getter.IsNull() || getter.IsMethodExtractor()) { | 749 if (getter.IsNull() || getter.IsMethodExtractor()) { |
746 return false; | 750 return false; |
747 } | 751 } |
748 const Class& cache_class = Class::Handle(receiver_class.IsSignatureClass() | |
749 ? receiver_class.SuperClass() | |
750 : receiver_class.raw()); | |
751 ASSERT( | |
752 !receiver_class.IsSignatureClass() || | |
753 (receiver_class.SuperClass() == Type::Handle( | |
754 Isolate::Current()->object_store()->function_impl_type()).type_class())); | |
755 const Function& target_function = | 752 const Function& target_function = |
756 Function::Handle(cache_class.GetInvocationDispatcher( | 753 Function::Handle(receiver_class.GetInvocationDispatcher( |
757 target_name, | 754 target_name, |
758 arguments_descriptor, | 755 arguments_descriptor, |
759 RawFunction::kInvokeFieldDispatcher, | 756 RawFunction::kInvokeFieldDispatcher, |
760 FLAG_lazy_dispatchers)); | 757 FLAG_lazy_dispatchers)); |
761 ASSERT(!target_function.IsNull() || !FLAG_lazy_dispatchers); | 758 ASSERT(!target_function.IsNull() || !FLAG_lazy_dispatchers); |
762 if (FLAG_trace_ic) { | 759 if (FLAG_trace_ic) { |
763 OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", | 760 OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", |
764 Class::Handle(receiver.clazz()).ToCString(), | 761 Class::Handle(receiver.clazz()).ToCString(), |
765 receiver.GetClassId(), | 762 receiver.GetClassId(), |
766 target_function.IsNull() ? "null" : target_function.ToCString()); | 763 target_function.IsNull() ? "null" : target_function.ToCString()); |
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1216 #undef CLOSURIZE | 1213 #undef CLOSURIZE |
1217 } | 1214 } |
1218 | 1215 |
1219 | 1216 |
1220 | 1217 |
1221 // Invoke appropriate noSuchMethod function. | 1218 // Invoke appropriate noSuchMethod function. |
1222 // Arg0: receiver (closure object) | 1219 // Arg0: receiver (closure object) |
1223 // Arg1: arguments descriptor array. | 1220 // Arg1: arguments descriptor array. |
1224 // Arg2: arguments array. | 1221 // Arg2: arguments array. |
1225 DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) { | 1222 DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) { |
1226 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); | 1223 const Closure& receiver = Closure::CheckedHandle(arguments.ArgAt(0)); |
1227 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1)); | 1224 const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1)); |
1228 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2)); | 1225 const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2)); |
1229 | 1226 |
1230 // For closure the function name is always 'call'. Replace it with the | 1227 // For closure the function name is always 'call'. Replace it with the |
1231 // name of the closurized function so that exception contains more | 1228 // name of the closurized function so that exception contains more |
1232 // relevant information. | 1229 // relevant information. |
1233 ASSERT(receiver.IsClosure()); | 1230 const Function& function = Function::Handle(receiver.function()); |
1234 const Function& function = Function::Handle(Closure::function(receiver)); | |
1235 const String& original_function_name = | 1231 const String& original_function_name = |
1236 String::Handle(function.QualifiedUserVisibleName()); | 1232 String::Handle(function.QualifiedUserVisibleName()); |
1237 const Object& result = Object::Handle( | 1233 const Object& result = Object::Handle( |
1238 DartEntry::InvokeNoSuchMethod(receiver, | 1234 DartEntry::InvokeNoSuchMethod(receiver, |
1239 original_function_name, | 1235 original_function_name, |
1240 orig_arguments, | 1236 orig_arguments, |
1241 orig_arguments_desc)); | 1237 orig_arguments_desc)); |
1242 CheckResultError(result); | 1238 CheckResultError(result); |
1243 arguments.SetReturn(result); | 1239 arguments.SetReturn(result); |
1244 } | 1240 } |
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1891 const intptr_t elm_size = old_data.ElementSizeInBytes(); | 1887 const intptr_t elm_size = old_data.ElementSizeInBytes(); |
1892 const TypedData& new_data = | 1888 const TypedData& new_data = |
1893 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); | 1889 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); |
1894 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); | 1890 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); |
1895 typed_data_cell.SetAt(0, new_data); | 1891 typed_data_cell.SetAt(0, new_data); |
1896 arguments.SetReturn(new_data); | 1892 arguments.SetReturn(new_data); |
1897 } | 1893 } |
1898 | 1894 |
1899 | 1895 |
1900 } // namespace dart | 1896 } // namespace dart |
OLD | NEW |