Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(676)

Side by Side Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 10414026: Started porting inlined type checks to x64 (will be the future pattern for other architectures). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/stub_code_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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/globals.h" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 const Class& cls = Class::ZoneHandle(Library::Handle( 93 const Class& cls = Class::ZoneHandle(Library::Handle(
94 Library::CoreImplLibrary()).LookupClass(class_name)); 94 Library::CoreImplLibrary()).LookupClass(class_name));
95 ASSERT(!cls.IsNull()); 95 ASSERT(!cls.IsNull());
96 return &cls; 96 return &cls;
97 } 97 }
98 98
99 99
100 #define __ assembler_-> 100 #define __ assembler_->
101 101
102 102
103 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
104 // type test is conclusive, otherwise fallthrough if a type test could not
105 // be completed.
106 // RAX: instance (must survive),
107 RawSubtypeTestCache*
108 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
109 intptr_t cid,
110 intptr_t token_index,
111 const AbstractType& type,
112 Label* is_instance_lbl,
113 Label* is_not_instance_lbl) {
114 ASSERT(type.IsInstantiated());
115 const Class& type_class = Class::ZoneHandle(type.type_class());
116 ASSERT(type_class.HasTypeArguments());
117 // A Smi object cannot be the instance of a parameterized class.
118 __ testq(RAX, Immediate(kSmiTagMask));
119 __ j(ZERO, is_not_instance_lbl);
120 const AbstractTypeArguments& type_arguments =
121 AbstractTypeArguments::ZoneHandle(type.arguments());
122 const bool is_raw_type = type_arguments.IsNull() ||
123 type_arguments.IsRaw(type_arguments.Length());
124 if (is_raw_type) {
125 // Dynamic type argument, check only classes.
126 // List is a very common case.
127 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
128 if (!type_class.is_interface()) {
129 __ CompareObject(R10, type_class);
130 __ j(EQUAL, is_instance_lbl);
131 }
132 if (type.IsListInterface()) {
133 Label unknown;
134 GrowableArray<const Class*> args;
135 args.Add(CoreClass("ObjectArray"));
136 args.Add(CoreClass("GrowableObjectArray"));
137 args.Add(CoreClass("ImmutableArray"));
138 CheckClasses(args, is_instance_lbl, &unknown);
139 __ Bind(&unknown);
140 }
141 return GenerateSubtype1TestCacheLookup(
142 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl);
143 }
144 return SubtypeTestCache::null();
145 }
146
147
148 // R10: instance class to check.
149 void FlowGraphCompiler::CheckClasses(const GrowableArray<const Class*>& classes,
150 Label* is_instance_lbl,
151 Label* is_not_instance_lbl) {
152 for (intptr_t i = 0; i < classes.length(); i++) {
153 __ CompareObject(R10, *classes[i]);
154 __ j(EQUAL, is_instance_lbl);
155 }
156 __ jmp(is_not_instance_lbl);
157 }
158
159
160
161 // Testing against an instantiated type with no arguments, without
162 // SubtypeTestCache.
163 // RAX: instance to test against (preserved).
164 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
165 intptr_t cid,
166 intptr_t token_index,
167 const AbstractType& type,
168 Label* is_instance_lbl,
169 Label* is_not_instance_lbl) {
170 ASSERT(type.IsInstantiated());
171 const Class& type_class = Class::ZoneHandle(type.type_class());
172 ASSERT(!type_class.HasTypeArguments());
173
174 Label compare_classes;
175 __ testq(RAX, Immediate(kSmiTagMask));
176 __ j(NOT_ZERO, &compare_classes);
177 // Instance is Smi, check directly.
178 const Class& smi_class = Class::Handle(Smi::Class());
179 // TODO(regis): We should introduce a SmiType.
180 Error& malformed_error = Error::Handle();
181 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
182 type_class,
183 TypeArguments::Handle(),
184 &malformed_error)) {
185 __ jmp(is_instance_lbl);
186 } else {
187 __ jmp(is_not_instance_lbl);
188 }
189
190 ObjectStore* object_store = Isolate::Current()->object_store();
191 // Compare if the classes are equal. Instance is not Smi.
192 __ Bind(&compare_classes);
193 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
194 // If type is an interface, we can skip the class equality check.
195 if (!type_class.is_interface()) {
196 __ CompareObject(R10, type_class);
197 __ j(EQUAL, is_instance_lbl);
198 }
199 // Check for interfaces that cannot be implemented by user.
200 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
201 // Bool interface can be implemented only by core class Bool.
202 if (type.IsBoolInterface()) {
203 const Class& bool_class = Class::ZoneHandle(object_store->bool_class());
204 __ CompareObject(R10, bool_class);
205 __ j(EQUAL, is_instance_lbl);
206 __ jmp(is_not_instance_lbl);
207 return;
208 }
209 if (type.IsFunctionInterface()) {
210 // Check if instance is a closure.
211 const Immediate raw_null =
212 Immediate(reinterpret_cast<intptr_t>(Object::null()));
213 __ movq(R10, FieldAddress(R10, Class::signature_function_offset()));
214 __ cmpq(R10, raw_null);
215 __ j(NOT_EQUAL, is_instance_lbl);
216 __ jmp(is_not_instance_lbl);
217 return;
218 }
219 // Custom checking for numbers (Smi, Mint, Bigint and Double).
220 // Note that instance is not Smi(checked above).
221 if (type.IsSubtypeOf(
222 Type::Handle(Type::NumberInterface()), &malformed_error)) {
223 const Class& mint_class = Class::ZoneHandle(object_store->mint_class());
224 const Class& bigint_class = Class::ZoneHandle(object_store->bigint_class());
225 const Class& double_class = Class::ZoneHandle(object_store->double_class());
226 GrowableArray<const Class*> args;
227 if (type.IsNumberInterface()) {
228 args.Add(&double_class);
229 args.Add(&mint_class);
230 args.Add(&bigint_class);
231 } else if (type.IsIntInterface()) {
232 args.Add(&mint_class);
233 args.Add(&bigint_class);
234 } else if (type.IsDoubleInterface()) {
235 args.Add(&double_class);
236 }
237 CheckClasses(args, is_instance_lbl, is_not_instance_lbl);
238 return;
239 }
240 if (type.IsStringInterface()) {
241 const Class& one_byte_string_class =
242 Class::ZoneHandle(object_store->one_byte_string_class());
243 const Class& two_byte_string_class =
244 Class::ZoneHandle(object_store->two_byte_string_class());
245 const Class& four_byte_string_class =
246 Class::ZoneHandle(object_store->four_byte_string_class());
247 const Class& external_one_byte_string_class =
248 Class::ZoneHandle(object_store->external_one_byte_string_class());
249 const Class& external_two_byte_string_class =
250 Class::ZoneHandle(object_store->external_two_byte_string_class());
251 const Class& external_four_byte_string_class =
252 Class::ZoneHandle(object_store->external_four_byte_string_class());
253 GrowableArray<const Class*> args;
254 args.Add(&one_byte_string_class);
255 args.Add(&two_byte_string_class);
256 args.Add(&four_byte_string_class);
257 args.Add(&external_one_byte_string_class);
258 args.Add(&external_two_byte_string_class);
259 args.Add(&external_four_byte_string_class);
260 CheckClasses(args, is_instance_lbl, is_not_instance_lbl);
261 return;
262 }
263 // Otherwise fallthrough.
264 }
265
266
267 // Uses SubtypeTestCache to store instance class and result.
268 // RAX: instance to test.
269 // Immediate class test already done.
270 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
271 intptr_t cid,
272 intptr_t token_index,
273 const Class& type_class,
274 Label* is_instance_lbl,
275 Label* is_not_instance_lbl) {
276 const SubtypeTestCache& type_test_cache =
277 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
278 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
279 const Immediate raw_null =
280 Immediate(reinterpret_cast<intptr_t>(Object::null()));
281 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
282 // Check immediate superclass equality.
283 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
284 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
285 __ CompareObject(R13, type_class);
286 __ j(EQUAL, is_instance_lbl);
287
288 __ LoadObject(R10, type_test_cache);
289 __ pushq(R10); // Cache array.
290 __ pushq(RAX); // Instance.
291 __ pushq(raw_null); // Unused
292 __ call(&StubCode::Subtype1TestCacheLabel());
293 __ popq(RAX); // Discard.
294 __ popq(RAX); // Restore receiver.
295 __ popq(RDX); // Discard.
296 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
297
298 Label runtime_call;
299 __ cmpq(RCX, raw_null);
300 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
301 __ CompareObject(RCX, bool_true);
302 __ j(EQUAL, is_instance_lbl);
303 __ jmp(is_not_instance_lbl);
304 __ Bind(&runtime_call);
305 return type_test_cache.raw();
306 }
307
308
309 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
310 const AbstractType& type,
311 intptr_t cid,
312 intptr_t token_index,
313 Label* is_instance_lbl,
314 Label* is_not_instance_lbl) {
315 return SubtypeTestCache::null();
316 }
317
318
103 // Inputs: 319 // Inputs:
104 // - RAX: object (preserved). 320 // - RAX: instance to test against (preserved).
105 // - RDX: optional instantiator type arguments (preserved). 321 // - RDX: optional instantiator type arguments (preserved).
106 // Destroys RCX. 322 // Destroys RCX.
107 // Returns: 323 // Returns:
108 // - unchanged object in RAX and optional instantiator type arguments in RDX. 324 // - unchanged object in RAX and optional instantiator type arguments in RDX.
109 // Note that this inlined code must be followed by the runtime_call code, as it 325 // Note that this inlined code must be followed by the runtime_call code, as it
110 // may fall through to it. Otherwise, this inline code will jump to the label 326 // may fall through to it. Otherwise, this inline code will jump to the label
111 // is_instance or to the label is_not_instance. 327 // is_instance or to the label is_not_instance.
112 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 328 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
113 intptr_t cid, 329 intptr_t cid,
114 intptr_t token_index, 330 intptr_t token_index,
115 const AbstractType& type, 331 const AbstractType& type,
116 Label* is_instance, 332 Label* is_instance_lbl,
117 Label* is_not_instance) { 333 Label* is_not_instance_lbl) {
118 Label runtime_call;
119 if (type.IsInstantiated()) { 334 if (type.IsInstantiated()) {
120 const Class& type_class = Class::ZoneHandle(type.type_class()); 335 const Class& type_class = Class::ZoneHandle(type.type_class());
121 const bool requires_type_arguments = type_class.HasTypeArguments();
122 // A Smi object cannot be the instance of a parameterized class. 336 // A Smi object cannot be the instance of a parameterized class.
123 // A class equality check is only applicable with a dst type of a 337 // A class equality check is only applicable with a dst type of a
124 // non-parameterized class or with a raw dst type of a parameterized class. 338 // non-parameterized class or with a raw dst type of a parameterized class.
125 if (requires_type_arguments) { 339 if (type_class.HasTypeArguments()) {
126 const AbstractTypeArguments& type_arguments = 340 return GenerateInstantiatedTypeWithArgumentsTest(cid,
127 AbstractTypeArguments::Handle(type.arguments()); 341 token_index,
128 const bool is_raw_type = type_arguments.IsNull() || 342 type,
129 type_arguments.IsRaw(type_arguments.Length()); 343 is_instance_lbl,
130 __ testq(RAX, Immediate(kSmiTagMask)); 344 is_not_instance_lbl);
131 __ j(ZERO, &runtime_call); 345 // Fall through to runtime call.
132 // Object not Smi. 346 } else {
133 if (is_raw_type) { 347 GenerateInstantiatedTypeNoArgumentsTest(cid,
134 // Dynamic type argument, check only classes. 348 token_index,
135 if (type.IsListInterface()) { 349 type,
136 // TODO(srdjan) also accept List<Object>. 350 is_instance_lbl,
137 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); 351 is_not_instance_lbl);
138 __ CompareObject(RCX, *CoreClass("ObjectArray")); 352 // If test non-conclusive so far, try the inlined type-test cache.
139 __ j(EQUAL, is_instance); 353 // 'type' is known at compile time.
140 __ CompareObject(RCX, *CoreClass("GrowableObjectArray")); 354 return GenerateSubtype1TestCacheLookup(
141 __ j(EQUAL, is_instance); 355 cid, token_index, type_class,
142 } else if (!type_class.is_interface()) { 356 is_instance_lbl, is_not_instance_lbl);
143 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
144 __ CompareObject(RCX, type_class);
145 __ j(EQUAL, is_instance);
146 }
147 // Fall through to runtime call.
148 }
149 } else { // type has NO type arguments.
150 Label compare_classes;
151 __ testq(RAX, Immediate(kSmiTagMask));
152 __ j(NOT_ZERO, &compare_classes);
153 // Object is Smi.
154 const Class& smi_class = Class::Handle(Smi::Class());
155 // TODO(regis): We should introduce a SmiType.
156 Error& malformed_error = Error::Handle();
157 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
158 type_class,
159 TypeArguments::Handle(),
160 &malformed_error)) {
161 // Successful assignable type check: return object in RAX.
162 __ jmp(is_instance);
163 } else {
164 // Failed assignable type check: call runtime to throw TypeError.
165 __ jmp(&runtime_call);
166 }
167 // Compare if the classes are equal.
168 __ Bind(&compare_classes);
169 // If type is an interface, we can skip the class equality check,
170 // because instances cannot be of an interface type.
171 if (!type_class.is_interface()) {
172 __ LoadObject(RCX, type_class);
173 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
174 __ cmpq(R10, RCX);
175 __ j(EQUAL, is_instance);
176 // TODO(srdjan): Finish implementation.
177 // Otherwise fall through to runtime call.
178 } else {
179 // However, for specific core library interfaces, we can check for
180 // specific core library classes.
181 Error& malformed_error = Error::Handle();
182 if (type.IsBoolInterface()) {
183 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
184 const Class& bool_class = Class::ZoneHandle(
185 Isolate::Current()->object_store()->bool_class());
186 __ CompareObject(RCX, bool_class);
187 __ j(EQUAL, is_instance);
188 } else if (type.IsSubtypeOf(
189 Type::Handle(Type::NumberInterface()), &malformed_error)) {
190 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
191 if (type.IsIntInterface() || type.IsNumberInterface()) {
192 // We already checked for Smi above.
193 const Class& mint_class = Class::ZoneHandle(
194 Isolate::Current()->object_store()->mint_class());
195 __ CompareObject(RCX, mint_class);
196 __ j(EQUAL, is_instance);
197 const Class& bigint_class = Class::ZoneHandle(
198 Isolate::Current()->object_store()->bigint_class());
199 __ CompareObject(RCX, bigint_class);
200 __ j(EQUAL, is_instance);
201 }
202 if (type.IsDoubleInterface() || type.IsNumberInterface()) {
203 const Class& double_class = Class::ZoneHandle(
204 Isolate::Current()->object_store()->double_class());
205 __ CompareObject(RCX, double_class);
206 __ j(EQUAL, is_instance);
207 }
208 } else if (type.IsStringInterface()) {
209 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
210 const Class& one_byte_string_class = Class::ZoneHandle(
211 Isolate::Current()->object_store()->one_byte_string_class());
212 __ CompareObject(RCX, one_byte_string_class);
213 __ j(EQUAL, is_instance);
214 const Class& two_byte_string_class = Class::ZoneHandle(
215 Isolate::Current()->object_store()->two_byte_string_class());
216 __ CompareObject(RCX, two_byte_string_class);
217 __ j(EQUAL, is_instance);
218 const Class& four_byte_string_class = Class::ZoneHandle(
219 Isolate::Current()->object_store()->four_byte_string_class());
220 __ CompareObject(RCX, four_byte_string_class);
221 __ j(EQUAL, is_instance);
222 } else if (type.IsFunctionInterface()) {
223 const Immediate raw_null =
224 Immediate(reinterpret_cast<intptr_t>(Object::null()));
225 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
226 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset()));
227 __ cmpq(RCX, raw_null);
228 __ j(NOT_EQUAL, is_instance);
229 } else {
230 // TODO(srdjan): Finish implementation.
231 }
232 }
233 } 357 }
234 } else { 358 } else {
235 ASSERT(!type.IsInstantiated()); 359 return GenerateUninstantiatedTypeTest(type,
236 // Skip check if destination is a dynamic type. 360 cid,
237 if (type.IsTypeParameter()) { 361 token_index,
238 // Check if dynamic. 362 is_instance_lbl,
239 const Immediate raw_null = 363 is_not_instance_lbl);
240 Immediate(reinterpret_cast<intptr_t>(Object::null()));
241 // Instantiator type arguments are in RDX.
242 __ cmpq(RDX, raw_null);
243 __ j(EQUAL, is_instance);
244
245 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
246 __ movq(RCX, FieldAddress(RDX, Object::class_offset()));
247 __ CompareObject(RCX, Object::ZoneHandle(Object::type_arguments_class()));
248 __ j(NOT_EQUAL, &runtime_call);
249 __ movq(RCX,
250 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
251 // RCX: instantiated type parameter.
252 __ CompareObject(RCX, Type::ZoneHandle(Type::DynamicType()));
253 __ j(EQUAL, is_instance);
254 // Check if the type has type parameters, if not, do the class comparison.
255 Label not_smi;
256 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
257 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
258 __ CompareObject(RCX, Type::ZoneHandle(Type::IntInterface()));
259 __ j(EQUAL, is_instance);
260 __ CompareObject(RCX, Type::ZoneHandle(Type::NumberInterface()));
261 __ j(EQUAL, is_instance);
262 __ Bind(&not_smi);
263 // The instantiated type parameter RCX may not be a Type, but could be an
264 // InstantiatedType. It is therefore necessary to check its class.
265 __ movq(R10, FieldAddress(RCX, Object::class_offset()));
266 __ CompareObject(R10, Object::ZoneHandle(Object::type_class()));
267 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
268 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset()));
269 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset()));
270 // Check that class of type has no type parameters.
271 __ cmpq(R10, raw_null);
272 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
273 // TODO(srdjan): Implement subtype test cache.
274 // Fall through to runtime call.
275 }
276 } 364 }
277 __ Bind(&runtime_call);
278 return SubtypeTestCache::null(); 365 return SubtypeTestCache::null();
279 } 366 }
280 367
281 368
282 // Optimize assignable type check by adding inlined tests for: 369 // Optimize assignable type check by adding inlined tests for:
283 // - NULL -> return NULL. 370 // - NULL -> return NULL.
284 // - Smi -> compile time subtype check (only if dst class is not parameterized). 371 // - Smi -> compile time subtype check (only if dst class is not parameterized).
285 // - Class equality (only if class is not parameterized). 372 // - Class equality (only if class is not parameterized).
286 // Inputs: 373 // Inputs:
287 // - RAX: object. 374 // - RAX: object.
(...skipping 10 matching lines...) Expand all
298 const AbstractType& dst_type, 385 const AbstractType& dst_type,
299 const String& dst_name) { 386 const String& dst_name) {
300 ASSERT(FLAG_enable_type_checks); 387 ASSERT(FLAG_enable_type_checks);
301 ASSERT(token_index >= 0); 388 ASSERT(token_index >= 0);
302 ASSERT(!dst_type.IsNull()); 389 ASSERT(!dst_type.IsNull());
303 ASSERT(dst_type.IsFinalized()); 390 ASSERT(dst_type.IsFinalized());
304 // Assignable check is skipped in FlowGraphBuilder, not here. 391 // Assignable check is skipped in FlowGraphBuilder, not here.
305 ASSERT(dst_type.IsMalformed() || 392 ASSERT(dst_type.IsMalformed() ||
306 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 393 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
307 ASSERT(!dst_type.IsVoidType()); 394 ASSERT(!dst_type.IsVoidType());
308 __ pushq(RCX); // Temporary store instantiator on stack. 395 __ pushq(RCX); // Store instantiator.
396 __ pushq(RDX); // Store instantiator type arguments.
309 // A null object is always assignable and is returned as result. 397 // A null object is always assignable and is returned as result.
310 const Immediate raw_null = 398 const Immediate raw_null =
311 Immediate(reinterpret_cast<intptr_t>(Object::null())); 399 Immediate(reinterpret_cast<intptr_t>(Object::null()));
312 Label is_assignable, runtime_call; 400 Label is_assignable, runtime_call;
313 __ cmpq(RAX, raw_null); 401 __ cmpq(RAX, raw_null);
314 __ j(EQUAL, &is_assignable); 402 __ j(EQUAL, &is_assignable);
315 403
316 // Generate throw new TypeError() if the type is malformed. 404 // Generate throw new TypeError() if the type is malformed.
317 if (dst_type.IsMalformed()) { 405 if (dst_type.IsMalformed()) {
318 const Error& error = Error::Handle(dst_type.malformed_error()); 406 const Error& error = Error::Handle(dst_type.malformed_error());
(...skipping 13 matching lines...) Expand all
332 420
333 __ Bind(&is_assignable); // For a null object. 421 __ Bind(&is_assignable); // For a null object.
334 return; 422 return;
335 } 423 }
336 424
337 // Generate inline type check, linking to runtime call if not assignable. 425 // Generate inline type check, linking to runtime call if not assignable.
338 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 426 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
339 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, 427 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type,
340 &is_assignable, &runtime_call); 428 &is_assignable, &runtime_call);
341 __ Bind(&runtime_call); 429 __ Bind(&runtime_call);
342 __ movq(RCX, Address(RSP, 0)); // Get instantiator. 430 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
431 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
343 __ PushObject(Object::ZoneHandle()); // Make room for the result. 432 __ PushObject(Object::ZoneHandle()); // Make room for the result.
344 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 433 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
345 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 434 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
346 __ pushq(RAX); // Push the source object. 435 __ pushq(RAX); // Push the source object.
347 __ PushObject(dst_type); // Push the type of the destination. 436 __ PushObject(dst_type); // Push the type of the destination.
348 __ pushq(RCX); // Instantiator. 437 __ pushq(RCX); // Instantiator.
349 __ pushq(RDX); // Instantiator type arguments. 438 __ pushq(RDX); // Instantiator type arguments.
350 __ PushObject(dst_name); // Push the name of the destination. 439 __ PushObject(dst_name); // Push the name of the destination.
351 __ LoadObject(RAX, test_cache); 440 __ LoadObject(RAX, test_cache);
352 __ pushq(RAX); 441 __ pushq(RAX);
353 GenerateCallRuntime(cid, 442 GenerateCallRuntime(cid,
354 token_index, 443 token_index,
355 try_index, 444 try_index,
356 kTypeCheckRuntimeEntry); 445 kTypeCheckRuntimeEntry);
357 // Pop the parameters supplied to the runtime entry. The result of the 446 // Pop the parameters supplied to the runtime entry. The result of the
358 // type check runtime call is the checked value. 447 // type check runtime call is the checked value.
359 __ Drop(8); 448 __ Drop(8);
360 __ popq(RAX); 449 __ popq(RAX);
361 450
362 __ Bind(&is_assignable); 451 __ Bind(&is_assignable);
452 __ popq(RDX); // Remove pushed instantiator type arguments..
363 __ popq(RCX); // Remove pushed instantiator. 453 __ popq(RCX); // Remove pushed instantiator.
364 } 454 }
365 455
366 456
367 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { 457 void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
368 if (value->IsConstant()) { 458 if (value->IsConstant()) {
369 ConstantVal* constant = value->AsConstant(); 459 ConstantVal* constant = value->AsConstant();
370 if (constant->value().IsSmi()) { 460 if (constant->value().IsSmi()) {
371 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); 461 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
372 __ movq(dst, Immediate(imm)); 462 __ movq(dst, Immediate(imm));
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 890 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
801 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 891 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
802 __ pushq(RAX); // Push the instance. 892 __ pushq(RAX); // Push the instance.
803 __ PushObject(type); // Push the type. 893 __ PushObject(type); // Push the type.
804 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null. 894 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null.
805 if (type.IsInstantiated()) { 895 if (type.IsInstantiated()) {
806 __ pushq(raw_null); // Null instantiator type arguments. 896 __ pushq(raw_null); // Null instantiator type arguments.
807 } else { 897 } else {
808 __ pushq(RDX); // Instantiator type arguments. 898 __ pushq(RDX); // Instantiator type arguments.
809 } 899 }
810 __ pushq(raw_null); // SubtypeTestCache not yet supported. 900 __ LoadObject(RAX, test_cache);
901 __ pushq(RAX);
811 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); 902 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry);
812 // Pop the two parameters supplied to the runtime entry. The result of the 903 // Pop the two parameters supplied to the runtime entry. The result of the
813 // instanceof runtime call will be left as the result of the operation. 904 // instanceof runtime call will be left as the result of the operation.
814 __ Drop(7); 905 __ Drop(7);
815 Label done; 906 Label done;
816 if (negate_result) { 907 if (negate_result) {
817 __ popq(RDX); 908 __ popq(RDX);
818 __ LoadObject(RAX, bool_true); 909 __ LoadObject(RAX, bool_true);
819 __ cmpq(RDX, RAX); 910 __ cmpq(RDX, RAX);
820 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 911 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after
1755 1846
1756 1847
1757 void FlowGraphCompiler::FinalizeComments(const Code& code) { 1848 void FlowGraphCompiler::FinalizeComments(const Code& code) {
1758 code.set_comments(assembler_->GetCodeComments()); 1849 code.set_comments(assembler_->GetCodeComments());
1759 } 1850 }
1760 1851
1761 1852
1762 } // namespace dart 1853 } // namespace dart
1763 1854
1764 #endif // defined TARGET_ARCH_X64 1855 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/stub_code_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698