Chromium Code Reviews| 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/bigint_operations.h" | 9 #include "vm/bigint_operations.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 // Allocation of a fixed length array of given element type. | 84 // Allocation of a fixed length array of given element type. |
| 85 // This runtime entry is never called for allocating a List of a generic type, | 85 // This runtime entry is never called for allocating a List of a generic type, |
| 86 // because a prior run time call instantiates the element type if necessary. | 86 // because a prior run time call instantiates the element type if necessary. |
| 87 // Arg0: array length. | 87 // Arg0: array length. |
| 88 // Arg1: array type arguments, i.e. vector of 1 type, the element type. | 88 // Arg1: array type arguments, i.e. vector of 1 type, the element type. |
| 89 // Return value: newly allocated array of length arg0. | 89 // Return value: newly allocated array of length arg0. |
| 90 DEFINE_RUNTIME_ENTRY(AllocateArray, 2) { | 90 DEFINE_RUNTIME_ENTRY(AllocateArray, 2) { |
| 91 const Smi& length = Smi::CheckedHandle(arguments.ArgAt(0)); | 91 const Smi& length = Smi::CheckedHandle(arguments.ArgAt(0)); |
| 92 const Array& array = Array::Handle(Array::New(length.Value())); | 92 const Array& array = Array::Handle(Array::New(length.Value())); |
| 93 arguments.SetReturn(array); | 93 arguments.SetReturn(array); |
| 94 AbstractTypeArguments& element_type = | 94 TypeArguments& element_type = |
| 95 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | 95 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
| 96 // An Array is raw or takes one type argument. However, its type argument | 96 // An Array is raw or takes one type argument. However, its type argument |
| 97 // vector may be longer than 1 due to a type optimization reusing the type | 97 // vector may be longer than 1 due to a type optimization reusing the type |
| 98 // argument vector of the instantiator. | 98 // argument vector of the instantiator. |
| 99 ASSERT(element_type.IsNull() || | 99 ASSERT(element_type.IsNull() || |
| 100 ((element_type.Length() >= 1) && element_type.IsInstantiated())); | 100 ((element_type.Length() >= 1) && element_type.IsInstantiated())); |
| 101 array.SetTypeArguments(element_type); // May be null. | 101 array.SetTypeArguments(element_type); // May be null. |
| 102 } | 102 } |
| 103 | 103 |
| 104 | 104 |
| 105 // Helper returning the token position of the Dart caller. | |
| 106 static intptr_t GetCallerLocation() { | |
| 107 DartFrameIterator iterator; | |
| 108 StackFrame* caller_frame = iterator.NextFrame(); | |
| 109 ASSERT(caller_frame != NULL); | |
| 110 return caller_frame->GetTokenPos(); | |
| 111 } | |
| 112 | |
| 113 | |
| 105 // Allocate a new object. | 114 // Allocate a new object. |
| 106 // Arg0: class of the object that needs to be allocated. | 115 // Arg0: class of the object that needs to be allocated. |
| 107 // Arg1: type arguments of the object that needs to be allocated. | 116 // Arg1: type arguments of the object that needs to be allocated. |
| 108 // Arg2: type arguments of the instantiator or kNoInstantiator. | 117 // Arg2: type arguments of the instantiator or kNoInstantiator. |
| 109 // Return value: newly allocated object. | 118 // Return value: newly allocated object. |
| 110 DEFINE_RUNTIME_ENTRY(AllocateObject, 3) { | 119 DEFINE_RUNTIME_ENTRY(AllocateObject, 3) { |
| 111 const Class& cls = Class::CheckedHandle(arguments.ArgAt(0)); | 120 const Class& cls = Class::CheckedHandle(arguments.ArgAt(0)); |
| 112 const Instance& instance = Instance::Handle(Instance::New(cls)); | 121 const Instance& instance = Instance::Handle(Instance::New(cls)); |
| 113 arguments.SetReturn(instance); | 122 arguments.SetReturn(instance); |
| 114 if (cls.NumTypeArguments() == 0) { | 123 if (cls.NumTypeArguments() == 0) { |
| 115 // No type arguments required for a non-parameterized type. | 124 // No type arguments required for a non-parameterized type. |
| 116 ASSERT(Instance::CheckedHandle(arguments.ArgAt(1)).IsNull()); | 125 ASSERT(Instance::CheckedHandle(arguments.ArgAt(1)).IsNull()); |
| 117 return; | 126 return; |
| 118 } | 127 } |
| 119 AbstractTypeArguments& type_arguments = | 128 TypeArguments& type_arguments = |
| 120 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | 129 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
| 121 // If no instantiator is provided, set the type arguments and return. | 130 // If no instantiator is provided, set the type arguments and return. |
| 122 if (Object::Handle(arguments.ArgAt(2)).IsSmi()) { | 131 if (Object::Handle(arguments.ArgAt(2)).IsSmi()) { |
| 123 ASSERT(Smi::CheckedHandle(arguments.ArgAt(2)).Value() == | 132 ASSERT(Smi::CheckedHandle(arguments.ArgAt(2)).Value() == |
| 124 StubCode::kNoInstantiator); | 133 StubCode::kNoInstantiator); |
| 125 // Unless null (for a raw type), the type argument vector may be longer than | 134 // Unless null (for a raw type), the type argument vector may be longer than |
| 126 // necessary due to a type optimization reusing the type argument vector of | 135 // necessary due to a type optimization reusing the type argument vector of |
| 127 // the instantiator. | 136 // the instantiator. |
| 128 ASSERT(type_arguments.IsNull() || | 137 ASSERT(type_arguments.IsNull() || |
| 129 (type_arguments.IsInstantiated() && | 138 (type_arguments.IsInstantiated() && |
| 130 (type_arguments.Length() >= cls.NumTypeArguments()))); | 139 (type_arguments.Length() >= cls.NumTypeArguments()))); |
| 131 instance.SetTypeArguments(type_arguments); // May be null. | 140 instance.SetTypeArguments(type_arguments); // May be null. |
| 132 return; | 141 return; |
| 133 } | 142 } |
| 134 // A still uninstantiated type argument vector must have the correct length. | 143 // A still uninstantiated type argument vector must have the correct length. |
| 135 ASSERT(!type_arguments.IsInstantiated() && | 144 ASSERT(!type_arguments.IsInstantiated() && |
| 136 (type_arguments.Length() == cls.NumTypeArguments())); | 145 (type_arguments.Length() == cls.NumTypeArguments())); |
| 137 const AbstractTypeArguments& instantiator = | 146 const TypeArguments& instantiator = |
| 138 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(2)); | 147 TypeArguments::CheckedHandle(arguments.ArgAt(2)); |
| 139 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 148 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
| 140 // Code inlined in the caller should have optimized the case where the | 149 // Code inlined in the caller should have optimized the case where the |
| 141 // instantiator can be reused as type argument vector. | 150 // instantiator can be reused as type argument vector. |
| 142 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); | 151 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); |
| 143 type_arguments = InstantiatedTypeArguments::New(type_arguments, instantiator); | 152 if (FLAG_enable_type_checks) { |
| 144 instance.SetTypeArguments(type_arguments); | |
| 145 } | |
| 146 | |
| 147 | |
| 148 // Helper returning the token position of the Dart caller. | |
| 149 static intptr_t GetCallerLocation() { | |
| 150 DartFrameIterator iterator; | |
| 151 StackFrame* caller_frame = iterator.NextFrame(); | |
| 152 ASSERT(caller_frame != NULL); | |
| 153 return caller_frame->GetTokenPos(); | |
| 154 } | |
| 155 | |
| 156 | |
| 157 // Allocate a new object of a generic type and check that the instantiated type | |
| 158 // arguments are within the declared bounds or throw a dynamic type error. | |
| 159 // Arg0: class of the object that needs to be allocated. | |
| 160 // Arg1: type arguments of the object that needs to be allocated. | |
| 161 // Arg2: type arguments of the instantiator or kNoInstantiator. | |
| 162 // Return value: newly allocated object. | |
| 163 DEFINE_RUNTIME_ENTRY(AllocateObjectWithBoundsCheck, 3) { | |
| 164 ASSERT(FLAG_enable_type_checks); | |
| 165 const Class& cls = Class::CheckedHandle(arguments.ArgAt(0)); | |
| 166 const Instance& instance = Instance::Handle(Instance::New(cls)); | |
| 167 arguments.SetReturn(instance); | |
| 168 ASSERT(cls.NumTypeArguments() > 0); | |
| 169 AbstractTypeArguments& type_arguments = | |
| 170 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | |
| 171 if (Object::Handle(arguments.ArgAt(2)).IsSmi()) { | |
| 172 ASSERT(Smi::CheckedHandle(arguments.ArgAt(2)).Value() == | |
| 173 StubCode::kNoInstantiator); | |
| 174 // Unless null (for a raw type), the type argument vector may be longer than | |
| 175 // necessary due to a type optimization reusing the type argument vector of | |
| 176 // the instantiator. | |
| 177 ASSERT(type_arguments.IsNull() || | |
| 178 (type_arguments.IsInstantiated() && | |
| 179 (type_arguments.Length() >= cls.NumTypeArguments()))); | |
| 180 } else { | |
| 181 // A still uninstantiated type argument vector must have the correct length. | |
| 182 ASSERT(!type_arguments.IsInstantiated() && | |
| 183 (type_arguments.Length() == cls.NumTypeArguments())); | |
| 184 const AbstractTypeArguments& instantiator = | |
| 185 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(2)); | |
| 186 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | |
| 187 Error& bound_error = Error::Handle(); | 153 Error& bound_error = Error::Handle(); |
| 188 // Code inlined in the caller should have optimized the case where the | 154 type_arguments = |
| 189 // instantiator can be reused as type argument vector. | 155 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, |
| 190 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); | 156 &bound_error); |
| 191 type_arguments = type_arguments.InstantiateFrom(instantiator, &bound_error); | |
| 192 if (!bound_error.IsNull()) { | 157 if (!bound_error.IsNull()) { |
| 193 // Throw a dynamic type error. | 158 // Throw a dynamic type error. |
| 194 const intptr_t location = GetCallerLocation(); | 159 const intptr_t location = GetCallerLocation(); |
| 195 String& bound_error_message = String::Handle( | 160 String& bound_error_message = String::Handle( |
| 196 String::New(bound_error.ToErrorCString())); | 161 String::New(bound_error.ToErrorCString())); |
| 197 Exceptions::CreateAndThrowTypeError( | 162 Exceptions::CreateAndThrowTypeError( |
| 198 location, Symbols::Empty(), Symbols::Empty(), | 163 location, Symbols::Empty(), Symbols::Empty(), |
| 199 Symbols::Empty(), bound_error_message); | 164 Symbols::Empty(), bound_error_message); |
| 200 UNREACHABLE(); | 165 UNREACHABLE(); |
| 201 } | 166 } |
| 167 } else { | |
| 168 type_arguments = | |
| 169 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, NULL); | |
| 202 } | 170 } |
| 203 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); | 171 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); |
| 204 instance.SetTypeArguments(type_arguments); | 172 instance.SetTypeArguments(type_arguments); |
| 205 } | 173 } |
| 206 | 174 |
| 207 | 175 |
| 208 // Instantiate type. | 176 // Instantiate type. |
| 209 // Arg0: uninstantiated type. | 177 // Arg0: uninstantiated type. |
| 210 // Arg1: instantiator type arguments. | 178 // Arg1: instantiator type arguments. |
| 211 // Return value: instantiated type. | 179 // Return value: instantiated type. |
| 212 DEFINE_RUNTIME_ENTRY(InstantiateType, 2) { | 180 DEFINE_RUNTIME_ENTRY(InstantiateType, 2) { |
| 213 AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(0)); | 181 AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(0)); |
| 214 const AbstractTypeArguments& instantiator = | 182 const TypeArguments& instantiator = |
| 215 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | 183 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
| 216 ASSERT(!type.IsNull() && !type.IsInstantiated()); | 184 ASSERT(!type.IsNull() && !type.IsInstantiated()); |
| 217 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 185 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
| 218 Error& bound_error = Error::Handle(); | 186 Error& bound_error = Error::Handle(); |
| 219 type = type.InstantiateFrom(instantiator, &bound_error); | 187 type = type.InstantiateFrom(instantiator, &bound_error); |
| 220 if (!bound_error.IsNull()) { | 188 if (!bound_error.IsNull()) { |
| 221 // Throw a dynamic type error. | 189 // Throw a dynamic type error. |
| 222 const intptr_t location = GetCallerLocation(); | 190 const intptr_t location = GetCallerLocation(); |
| 223 String& bound_error_message = String::Handle( | 191 String& bound_error_message = String::Handle( |
| 224 String::New(bound_error.ToErrorCString())); | 192 String::New(bound_error.ToErrorCString())); |
| 225 Exceptions::CreateAndThrowTypeError( | 193 Exceptions::CreateAndThrowTypeError( |
| 226 location, Symbols::Empty(), Symbols::Empty(), | 194 location, Symbols::Empty(), Symbols::Empty(), |
| 227 Symbols::Empty(), bound_error_message); | 195 Symbols::Empty(), bound_error_message); |
| 228 UNREACHABLE(); | 196 UNREACHABLE(); |
| 229 } | 197 } |
| 230 if (type.IsTypeRef()) { | 198 if (type.IsTypeRef()) { |
| 231 type = TypeRef::Cast(type).type(); | 199 type = TypeRef::Cast(type).type(); |
| 232 ASSERT(!type.IsTypeRef()); | 200 ASSERT(!type.IsTypeRef()); |
| 233 ASSERT(type.IsCanonical()); | 201 ASSERT(type.IsCanonical()); |
| 234 } | 202 } |
| 235 ASSERT(!type.IsNull() && type.IsInstantiated()); | 203 ASSERT(!type.IsNull() && type.IsInstantiated()); |
| 236 arguments.SetReturn(type); | 204 arguments.SetReturn(type); |
| 237 } | 205 } |
| 238 | 206 |
| 239 | 207 |
| 240 // Instantiate type arguments. | 208 // Instantiate type arguments. |
| 241 // Arg0: uninstantiated type arguments. | 209 // Arg0: uninstantiated type arguments. |
| 242 // Arg1: instantiator type arguments. | 210 // Arg1: instantiator type arguments. |
| 243 // Return value: instantiated type arguments. | 211 // Return value: instantiated type arguments. |
| 244 DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) { | 212 DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) { |
| 245 AbstractTypeArguments& type_arguments = | 213 TypeArguments& type_arguments = |
| 246 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(0)); | 214 TypeArguments::CheckedHandle(arguments.ArgAt(0)); |
| 247 const AbstractTypeArguments& instantiator = | 215 const TypeArguments& instantiator = |
| 248 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | 216 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
| 249 ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated()); | 217 ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated()); |
| 250 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); | 218 ASSERT(instantiator.IsNull() || instantiator.IsInstantiated()); |
| 251 // Code inlined in the caller should have optimized the case where the | 219 // Code inlined in the caller should have optimized the case where the |
| 252 // instantiator can be reused as type argument vector. | 220 // instantiator can be reused as type argument vector. |
| 253 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); | 221 ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity()); |
| 254 type_arguments = InstantiatedTypeArguments::New(type_arguments, instantiator); | 222 type_arguments = |
| 223 type_arguments.InstantiateAndCanonicalizeFrom(instantiator, NULL); | |
| 255 ASSERT(type_arguments.IsInstantiated()); | 224 ASSERT(type_arguments.IsInstantiated()); |
| 256 arguments.SetReturn(type_arguments); | 225 arguments.SetReturn(type_arguments); |
| 257 } | 226 } |
| 258 | 227 |
| 259 | 228 |
| 260 // Allocate a new closure. | 229 // Allocate a new closure. |
| 261 // The type argument vector of a closure is always the vector of type parameters | 230 // The type argument vector of a closure is always the vector of type parameters |
| 262 // of its signature class, i.e. an uninstantiated identity vector. Therefore, | 231 // of its signature class, i.e. an uninstantiated identity vector. Therefore, |
| 263 // the instantiator type arguments can be used as the instantiated closure type | 232 // the instantiator type arguments can be used as the instantiated closure type |
| 264 // arguments and is passed here as the type arguments. | 233 // arguments and is passed here as the type arguments. |
| 265 // Arg0: local function. | 234 // Arg0: local function. |
| 266 // Arg1: type arguments of the closure (i.e. instantiator). | 235 // Arg1: type arguments of the closure (i.e. instantiator). |
| 267 // Return value: newly allocated closure. | 236 // Return value: newly allocated closure. |
| 268 DEFINE_RUNTIME_ENTRY(AllocateClosure, 2) { | 237 DEFINE_RUNTIME_ENTRY(AllocateClosure, 2) { |
| 269 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 238 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
| 270 ASSERT(function.IsClosureFunction() && !function.IsImplicitClosureFunction()); | 239 ASSERT(function.IsClosureFunction() && !function.IsImplicitClosureFunction()); |
| 271 const AbstractTypeArguments& type_arguments = | 240 const TypeArguments& type_arguments = |
| 272 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1)); | 241 TypeArguments::CheckedHandle(arguments.ArgAt(1)); |
| 273 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); | 242 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); |
| 274 // The current context was saved in the Isolate structure when entering the | 243 // The current context was saved in the Isolate structure when entering the |
| 275 // runtime. | 244 // runtime. |
| 276 const Context& context = Context::Handle(isolate->top_context()); | 245 const Context& context = Context::Handle(isolate->top_context()); |
| 277 ASSERT(!context.IsNull()); | 246 ASSERT(!context.IsNull()); |
| 278 const Instance& closure = Instance::Handle(Closure::New(function, context)); | 247 const Instance& closure = Instance::Handle(Closure::New(function, context)); |
| 279 Closure::SetTypeArguments(closure, type_arguments); | 248 Closure::SetTypeArguments(closure, type_arguments); |
| 280 arguments.SetReturn(closure); | 249 arguments.SetReturn(closure); |
| 281 } | 250 } |
| 282 | 251 |
| 283 | 252 |
| 284 // Allocate a new implicit instance closure. | 253 // Allocate a new implicit instance closure. |
| 285 // Arg0: local function. | 254 // Arg0: local function. |
| 286 // Arg1: receiver object. | 255 // Arg1: receiver object. |
| 287 // Arg2: type arguments of the closure. | 256 // Arg2: type arguments of the closure. |
| 288 // Return value: newly allocated closure. | 257 // Return value: newly allocated closure. |
| 289 DEFINE_RUNTIME_ENTRY(AllocateImplicitInstanceClosure, 3) { | 258 DEFINE_RUNTIME_ENTRY(AllocateImplicitInstanceClosure, 3) { |
| 290 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); | 259 const Function& function = Function::CheckedHandle(arguments.ArgAt(0)); |
| 291 ASSERT(function.IsImplicitInstanceClosureFunction()); | 260 ASSERT(function.IsImplicitInstanceClosureFunction()); |
| 292 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(1)); | 261 const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(1)); |
| 293 const AbstractTypeArguments& type_arguments = | 262 const TypeArguments& type_arguments = |
| 294 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(2)); | 263 TypeArguments::CheckedHandle(arguments.ArgAt(2)); |
| 295 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); | 264 ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated()); |
| 296 Context& context = Context::Handle(); | 265 Context& context = Context::Handle(); |
| 297 context = Context::New(1); | 266 context = Context::New(1); |
| 298 context.SetAt(0, receiver); | 267 context.SetAt(0, receiver); |
| 299 const Instance& closure = Instance::Handle(Closure::New(function, context)); | 268 const Instance& closure = Instance::Handle(Closure::New(function, context)); |
| 300 Closure::SetTypeArguments(closure, type_arguments); | 269 Closure::SetTypeArguments(closure, type_arguments); |
| 301 arguments.SetReturn(closure); | 270 arguments.SetReturn(closure); |
| 302 } | 271 } |
| 303 | 272 |
| 304 | 273 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 324 } | 293 } |
| 325 arguments.SetReturn(cloned_ctx); | 294 arguments.SetReturn(cloned_ctx); |
| 326 } | 295 } |
| 327 | 296 |
| 328 | 297 |
| 329 // Helper routine for tracing a type check. | 298 // Helper routine for tracing a type check. |
| 330 static void PrintTypeCheck( | 299 static void PrintTypeCheck( |
| 331 const char* message, | 300 const char* message, |
| 332 const Instance& instance, | 301 const Instance& instance, |
| 333 const AbstractType& type, | 302 const AbstractType& type, |
| 334 const AbstractTypeArguments& instantiator_type_arguments, | 303 const TypeArguments& instantiator_type_arguments, |
| 335 const Bool& result) { | 304 const Bool& result) { |
| 336 DartFrameIterator iterator; | 305 DartFrameIterator iterator; |
| 337 StackFrame* caller_frame = iterator.NextFrame(); | 306 StackFrame* caller_frame = iterator.NextFrame(); |
| 338 ASSERT(caller_frame != NULL); | 307 ASSERT(caller_frame != NULL); |
| 339 | 308 |
| 340 const Type& instance_type = Type::Handle(instance.GetType()); | 309 const Type& instance_type = Type::Handle(instance.GetType()); |
| 341 ASSERT(instance_type.IsInstantiated()); | 310 ASSERT(instance_type.IsInstantiated()); |
| 342 if (type.IsInstantiated()) { | 311 if (type.IsInstantiated()) { |
| 343 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", | 312 OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", |
| 344 message, | 313 message, |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 363 if (!bound_error.IsNull()) { | 332 if (!bound_error.IsNull()) { |
| 364 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); | 333 OS::Print(" bound error: %s\n", bound_error.ToErrorCString()); |
| 365 } | 334 } |
| 366 } | 335 } |
| 367 const Function& function = Function::Handle( | 336 const Function& function = Function::Handle( |
| 368 caller_frame->LookupDartFunction()); | 337 caller_frame->LookupDartFunction()); |
| 369 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); | 338 OS::PrintErr(" -> Function %s\n", function.ToFullyQualifiedCString()); |
| 370 } | 339 } |
| 371 | 340 |
| 372 | 341 |
| 373 // Converts InstantiatedTypeArguments to TypeArguments and stores it | |
| 374 // into the instance. The assembly code can handle only type arguments of | |
| 375 // class TypeArguments. Because of the overhead, do it only when needed. | |
| 376 // Return true if type arguments have been replaced, false otherwise. | |
| 377 static bool OptimizeTypeArguments(const Instance& instance) { | |
| 378 const Class& type_class = Class::ZoneHandle(instance.clazz()); | |
| 379 if (type_class.NumTypeArguments() == 0) { | |
| 380 return false; | |
| 381 } | |
| 382 AbstractTypeArguments& type_arguments = | |
| 383 AbstractTypeArguments::Handle(instance.GetTypeArguments()); | |
| 384 if (type_arguments.IsNull()) { | |
| 385 return false; | |
| 386 } | |
| 387 bool replaced = false; | |
| 388 if (type_arguments.IsInstantiatedTypeArguments()) { | |
| 389 AbstractTypeArguments& uninstantiated = AbstractTypeArguments::Handle(); | |
| 390 AbstractTypeArguments& instantiator = AbstractTypeArguments::Handle(); | |
| 391 do { | |
| 392 const InstantiatedTypeArguments& instantiated_type_arguments = | |
| 393 InstantiatedTypeArguments::Cast(type_arguments); | |
| 394 uninstantiated = | |
| 395 instantiated_type_arguments.uninstantiated_type_arguments(); | |
| 396 instantiator = instantiated_type_arguments.instantiator_type_arguments(); | |
| 397 Error& bound_error = Error::Handle(); | |
| 398 type_arguments = uninstantiated.InstantiateFrom(instantiator, | |
| 399 &bound_error); | |
| 400 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. | |
| 401 } while (type_arguments.IsInstantiatedTypeArguments()); | |
| 402 AbstractTypeArguments& new_type_arguments = AbstractTypeArguments::Handle(); | |
| 403 new_type_arguments = type_arguments.Canonicalize(); | |
| 404 instance.SetTypeArguments(new_type_arguments); | |
| 405 replaced = true; | |
| 406 } else if (!type_arguments.IsCanonical()) { | |
| 407 AbstractTypeArguments& new_type_arguments = AbstractTypeArguments::Handle(); | |
| 408 new_type_arguments = type_arguments.Canonicalize(); | |
| 409 instance.SetTypeArguments(new_type_arguments); | |
| 410 replaced = true; | |
| 411 } | |
| 412 ASSERT(AbstractTypeArguments::Handle( | |
| 413 instance.GetTypeArguments()).IsTypeArguments()); | |
| 414 return replaced; | |
| 415 } | |
| 416 | |
| 417 | |
| 418 // This updates the type test cache, an array containing 4-value elements | 342 // This updates the type test cache, an array containing 4-value elements |
| 419 // (instance class, instance type arguments, instantiator type arguments and | 343 // (instance class, instance type arguments, instantiator type arguments and |
| 420 // test_result). It can be applied to classes with type arguments in which | 344 // test_result). It can be applied to classes with type arguments in which |
| 421 // case it contains just the result of the class subtype test, not including | 345 // case it contains just the result of the class subtype test, not including |
| 422 // the evaluation of type arguments. | 346 // the evaluation of type arguments. |
| 423 // This operation is currently very slow (lookup of code is not efficient yet). | 347 // This operation is currently very slow (lookup of code is not efficient yet). |
| 424 // 'instantiator' can be null, in which case inst_targ | 348 // 'instantiator' can be null, in which case inst_targ |
| 425 static void UpdateTypeTestCache( | 349 static void UpdateTypeTestCache( |
| 426 const Instance& instance, | 350 const Instance& instance, |
| 427 const AbstractType& type, | 351 const AbstractType& type, |
| 428 const Instance& instantiator, | 352 const Instance& instantiator, |
| 429 const AbstractTypeArguments& incoming_instantiator_type_arguments, | 353 const TypeArguments& instantiator_type_arguments, |
| 430 const Bool& result, | 354 const Bool& result, |
| 431 const SubtypeTestCache& new_cache) { | 355 const SubtypeTestCache& new_cache) { |
| 432 // Since the test is expensive, don't do it unless necessary. | 356 // Since the test is expensive, don't do it unless necessary. |
| 433 // The list of disallowed cases will decrease as they are implemented in | 357 // The list of disallowed cases will decrease as they are implemented in |
| 434 // inlined assembly. | 358 // inlined assembly. |
| 435 if (new_cache.IsNull()) { | 359 if (new_cache.IsNull()) { |
| 436 if (FLAG_trace_type_checks) { | 360 if (FLAG_trace_type_checks) { |
| 437 OS::Print("UpdateTypeTestCache: cache is null\n"); | 361 OS::Print("UpdateTypeTestCache: cache is null\n"); |
| 438 } | 362 } |
| 439 return; | 363 return; |
| 440 } | 364 } |
| 441 // Instantiator type arguments may be canonicalized later. | 365 if (instance.IsSmi()) { |
| 442 AbstractTypeArguments& instantiator_type_arguments = | 366 if (FLAG_trace_type_checks) { |
| 443 AbstractTypeArguments::Handle(incoming_instantiator_type_arguments.raw()); | 367 OS::Print("UpdateTypeTestCache: instance is Smi\n"); |
| 444 AbstractTypeArguments& instance_type_arguments = | 368 } |
| 445 AbstractTypeArguments::Handle(); | 369 return; |
| 370 } | |
| 371 TypeArguments& instance_type_arguments = | |
| 372 TypeArguments::Handle(); | |
|
srdjan
2014/02/07 21:59:47
This should fit on one line.
| |
| 446 const Class& instance_class = Class::Handle(instance.clazz()); | 373 const Class& instance_class = Class::Handle(instance.clazz()); |
| 447 | 374 |
| 448 // Canonicalize type arguments. | |
| 449 bool type_arguments_replaced = false; | |
| 450 if (instance_class.NumTypeArguments() > 0) { | 375 if (instance_class.NumTypeArguments() > 0) { |
| 451 // Canonicalize type arguments. | |
| 452 type_arguments_replaced = OptimizeTypeArguments(instance); | |
| 453 instance_type_arguments = instance.GetTypeArguments(); | 376 instance_type_arguments = instance.GetTypeArguments(); |
| 454 } | 377 } |
| 455 if (!instantiator.IsNull()) { | |
| 456 if (OptimizeTypeArguments(instantiator)) { | |
| 457 type_arguments_replaced = true; | |
| 458 } | |
| 459 instantiator_type_arguments = instantiator.GetTypeArguments(); | |
| 460 } | |
| 461 | 378 |
| 462 intptr_t last_instance_class_id = -1; | |
| 463 AbstractTypeArguments& last_instance_type_arguments = | |
| 464 AbstractTypeArguments::Handle(); | |
| 465 AbstractTypeArguments& last_instantiator_type_arguments = | |
| 466 AbstractTypeArguments::Handle(); | |
| 467 Bool& last_result = Bool::Handle(); | |
| 468 const intptr_t len = new_cache.NumberOfChecks(); | 379 const intptr_t len = new_cache.NumberOfChecks(); |
| 469 if (len >= FLAG_max_subtype_cache_entries) { | 380 if (len >= FLAG_max_subtype_cache_entries) { |
| 470 return; | 381 return; |
| 471 } | 382 } |
| 383 #if defined(DEBUG) | |
| 384 ASSERT(instance_type_arguments.IsNull() || | |
| 385 instance_type_arguments.IsCanonical()); | |
| 386 ASSERT(instantiator_type_arguments.IsNull() || | |
| 387 instantiator_type_arguments.IsCanonical()); | |
| 388 intptr_t last_instance_class_id = -1; | |
| 389 TypeArguments& last_instance_type_arguments = | |
| 390 TypeArguments::Handle(); | |
| 391 TypeArguments& last_instantiator_type_arguments = | |
| 392 TypeArguments::Handle(); | |
| 393 Bool& last_result = Bool::Handle(); | |
| 472 for (intptr_t i = 0; i < len; ++i) { | 394 for (intptr_t i = 0; i < len; ++i) { |
| 473 new_cache.GetCheck( | 395 new_cache.GetCheck( |
| 474 i, | 396 i, |
| 475 &last_instance_class_id, | 397 &last_instance_class_id, |
| 476 &last_instance_type_arguments, | 398 &last_instance_type_arguments, |
| 477 &last_instantiator_type_arguments, | 399 &last_instantiator_type_arguments, |
| 478 &last_result); | 400 &last_result); |
| 479 if ((last_instance_class_id == instance_class.id()) && | 401 if ((last_instance_class_id == instance_class.id()) && |
| 480 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && | 402 (last_instance_type_arguments.raw() == instance_type_arguments.raw()) && |
| 481 (last_instantiator_type_arguments.raw() == | 403 (last_instantiator_type_arguments.raw() == |
| 482 instantiator_type_arguments.raw())) { | 404 instantiator_type_arguments.raw())) { |
| 483 if (FLAG_trace_type_checks) { | 405 OS::PrintErr(" Error in test cache %p ix: %" Pd ",", new_cache.raw(), i); |
| 484 OS::PrintErr("%" Pd " ", i); | 406 PrintTypeCheck(" duplicate cache entry", instance, type, |
| 485 if (type_arguments_replaced) { | 407 instantiator_type_arguments, result); |
| 486 PrintTypeCheck("Duplicate cache entry (canonical.)", instance, type, | 408 UNREACHABLE(); |
| 487 instantiator_type_arguments, result); | |
| 488 } else { | |
| 489 PrintTypeCheck("WARNING Duplicate cache entry", instance, type, | |
| 490 instantiator_type_arguments, result); | |
| 491 } | |
| 492 } | |
| 493 // Can occur if we have canonicalized arguments. | |
| 494 // TODO(srdjan): Investigate why this assert can fail. | |
| 495 // ASSERT(type_arguments_replaced); | |
| 496 return; | 409 return; |
| 497 } | 410 } |
| 498 } | 411 } |
| 499 if (!instantiator_type_arguments.IsInstantiatedTypeArguments()) { | 412 #endif |
| 500 new_cache.AddCheck(instance_class.id(), | 413 new_cache.AddCheck(instance_class.id(), |
| 501 instance_type_arguments, | 414 instance_type_arguments, |
| 502 instantiator_type_arguments, | 415 instantiator_type_arguments, |
| 503 result); | 416 result); |
| 504 } | |
| 505 if (FLAG_trace_type_checks) { | 417 if (FLAG_trace_type_checks) { |
| 506 AbstractType& test_type = AbstractType::Handle(type.raw()); | 418 AbstractType& test_type = AbstractType::Handle(type.raw()); |
| 507 if (!test_type.IsInstantiated()) { | 419 if (!test_type.IsInstantiated()) { |
| 508 Error& bound_error = Error::Handle(); | 420 Error& bound_error = Error::Handle(); |
| 509 test_type = type.InstantiateFrom(instantiator_type_arguments, | 421 test_type = type.InstantiateFrom(instantiator_type_arguments, |
| 510 &bound_error); | 422 &bound_error); |
| 511 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. | 423 ASSERT(bound_error.IsNull()); // Malbounded types are not optimized. |
| 512 } | 424 } |
| 513 OS::PrintErr(" Updated test cache %p ix: %" Pd " with " | 425 OS::PrintErr(" Updated test cache %p ix: %" Pd " with " |
| 514 "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n" | 426 "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 543 // Arg0: instance being checked. | 455 // Arg0: instance being checked. |
| 544 // Arg1: type. | 456 // Arg1: type. |
| 545 // Arg2: instantiator (or null). | 457 // Arg2: instantiator (or null). |
| 546 // Arg3: type arguments of the instantiator of the type. | 458 // Arg3: type arguments of the instantiator of the type. |
| 547 // Arg4: SubtypeTestCache. | 459 // Arg4: SubtypeTestCache. |
| 548 // Return value: true or false, or may throw a type error in checked mode. | 460 // Return value: true or false, or may throw a type error in checked mode. |
| 549 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { | 461 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { |
| 550 const Instance& instance = Instance::CheckedHandle(arguments.ArgAt(0)); | 462 const Instance& instance = Instance::CheckedHandle(arguments.ArgAt(0)); |
| 551 const AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(1)); | 463 const AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(1)); |
| 552 const Instance& instantiator = Instance::CheckedHandle(arguments.ArgAt(2)); | 464 const Instance& instantiator = Instance::CheckedHandle(arguments.ArgAt(2)); |
| 553 const AbstractTypeArguments& instantiator_type_arguments = | 465 const TypeArguments& instantiator_type_arguments = |
| 554 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(3)); | 466 TypeArguments::CheckedHandle(arguments.ArgAt(3)); |
| 555 const SubtypeTestCache& cache = | 467 const SubtypeTestCache& cache = |
| 556 SubtypeTestCache::CheckedHandle(arguments.ArgAt(4)); | 468 SubtypeTestCache::CheckedHandle(arguments.ArgAt(4)); |
| 557 ASSERT(type.IsFinalized()); | 469 ASSERT(type.IsFinalized()); |
| 558 ASSERT(!type.IsDynamicType()); // No need to check assignment. | 470 ASSERT(!type.IsDynamicType()); // No need to check assignment. |
| 559 ASSERT(!type.IsMalformed()); // Already checked in code generator. | 471 ASSERT(!type.IsMalformed()); // Already checked in code generator. |
| 560 ASSERT(!type.IsMalbounded()); // Already checked in code generator. | 472 ASSERT(!type.IsMalbounded()); // Already checked in code generator. |
| 561 Error& bound_error = Error::Handle(); | 473 Error& bound_error = Error::Handle(); |
| 562 const Bool& result = | 474 const Bool& result = |
| 563 Bool::Get(instance.IsInstanceOf(type, | 475 Bool::Get(instance.IsInstanceOf(type, |
| 564 instantiator_type_arguments, | 476 instantiator_type_arguments, |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 591 // Arg3: type arguments of the instantiator of the type being assigned to. | 503 // Arg3: type arguments of the instantiator of the type being assigned to. |
| 592 // Arg4: name of variable being assigned to. | 504 // Arg4: name of variable being assigned to. |
| 593 // Arg5: SubtypeTestCache. | 505 // Arg5: SubtypeTestCache. |
| 594 // Return value: instance if a subtype, otherwise throw a TypeError. | 506 // Return value: instance if a subtype, otherwise throw a TypeError. |
| 595 DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { | 507 DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { |
| 596 const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0)); | 508 const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0)); |
| 597 const AbstractType& dst_type = | 509 const AbstractType& dst_type = |
| 598 AbstractType::CheckedHandle(arguments.ArgAt(1)); | 510 AbstractType::CheckedHandle(arguments.ArgAt(1)); |
| 599 const Instance& dst_instantiator = | 511 const Instance& dst_instantiator = |
| 600 Instance::CheckedHandle(arguments.ArgAt(2)); | 512 Instance::CheckedHandle(arguments.ArgAt(2)); |
| 601 const AbstractTypeArguments& instantiator_type_arguments = | 513 const TypeArguments& instantiator_type_arguments = |
| 602 AbstractTypeArguments::CheckedHandle(arguments.ArgAt(3)); | 514 TypeArguments::CheckedHandle(arguments.ArgAt(3)); |
| 603 const String& dst_name = String::CheckedHandle(arguments.ArgAt(4)); | 515 const String& dst_name = String::CheckedHandle(arguments.ArgAt(4)); |
| 604 const SubtypeTestCache& cache = | 516 const SubtypeTestCache& cache = |
| 605 SubtypeTestCache::CheckedHandle(arguments.ArgAt(5)); | 517 SubtypeTestCache::CheckedHandle(arguments.ArgAt(5)); |
| 606 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. | 518 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. |
| 607 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. | 519 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. |
| 608 ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator. | 520 ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator. |
| 609 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. | 521 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. |
| 610 | 522 |
| 611 Error& bound_error = Error::Handle(); | 523 Error& bound_error = Error::Handle(); |
| 612 const bool is_instance_of = src_instance.IsInstanceOf( | 524 const bool is_instance_of = src_instance.IsInstanceOf( |
| (...skipping 1074 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1687 // of the given value. | 1599 // of the given value. |
| 1688 // Arg0: Field object; | 1600 // Arg0: Field object; |
| 1689 // Arg1: Value that is being stored. | 1601 // Arg1: Value that is being stored. |
| 1690 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) { | 1602 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) { |
| 1691 const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); | 1603 const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); |
| 1692 const Object& value = Object::Handle(arguments.ArgAt(1)); | 1604 const Object& value = Object::Handle(arguments.ArgAt(1)); |
| 1693 field.UpdateGuardedCidAndLength(value); | 1605 field.UpdateGuardedCidAndLength(value); |
| 1694 } | 1606 } |
| 1695 | 1607 |
| 1696 } // namespace dart | 1608 } // namespace dart |
| OLD | NEW |