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 |