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

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

Issue 10080015: Implement checked mode in new compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 8 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/intermediate_language.h » ('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 "vm/ast_printer.h" 11 #include "vm/ast_printer.h"
11 #include "vm/code_descriptors.h" 12 #include "vm/code_descriptors.h"
12 #include "vm/code_generator.h" 13 #include "vm/code_generator.h"
13 #include "vm/disassembler.h" 14 #include "vm/disassembler.h"
14 #include "vm/longjump.h" 15 #include "vm/longjump.h"
15 #include "vm/object_store.h" 16 #include "vm/object_store.h"
16 #include "vm/parser.h" 17 #include "vm/parser.h"
17 #include "vm/stub_code.h" 18 #include "vm/stub_code.h"
18 19
19 namespace dart { 20 namespace dart {
20 21
22 DECLARE_FLAG(bool, enable_type_checks);
21 DECLARE_FLAG(bool, print_ast); 23 DECLARE_FLAG(bool, print_ast);
22 DECLARE_FLAG(bool, print_scopes); 24 DECLARE_FLAG(bool, print_scopes);
23 DECLARE_FLAG(bool, trace_functions); 25 DECLARE_FLAG(bool, trace_functions);
24 26
25 FlowGraphCompiler::FlowGraphCompiler( 27 FlowGraphCompiler::FlowGraphCompiler(
26 Assembler* assembler, 28 Assembler* assembler,
27 const ParsedFunction& parsed_function, 29 const ParsedFunction& parsed_function,
28 const GrowableArray<BlockEntryInstr*>& block_order) 30 const GrowableArray<BlockEntryInstr*>& block_order)
29 : FlowGraphVisitor(block_order), 31 : FlowGraphVisitor(block_order),
30 assembler_(assembler), 32 assembler_(assembler),
(...skipping 29 matching lines...) Expand all
60 const char* function_name = parsed_function_.function().ToCString(); 62 const char* function_name = parsed_function_.function().ToCString();
61 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 63 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
62 char* chars = reinterpret_cast<char*>( 64 char* chars = reinterpret_cast<char*>(
63 Isolate::Current()->current_zone()->Allocate(len)); 65 Isolate::Current()->current_zone()->Allocate(len));
64 OS::SNPrint(chars, len, kFormat, function_name, reason); 66 OS::SNPrint(chars, len, kFormat, function_name, reason);
65 const Error& error = Error::Handle( 67 const Error& error = Error::Handle(
66 LanguageError::New(String::Handle(String::New(chars)))); 68 LanguageError::New(String::Handle(String::New(chars))));
67 Isolate::Current()->long_jump_base()->Jump(1, error); 69 Isolate::Current()->long_jump_base()->Jump(1, error);
68 } 70 }
69 71
72
73 static const Class* CoreClass(const char* c_name) {
74 const String& class_name = String::Handle(String::NewSymbol(c_name));
75 const Class& cls = Class::ZoneHandle(Library::Handle(
76 Library::CoreImplLibrary()).LookupClass(class_name));
77 ASSERT(!cls.IsNull());
78 return &cls;
79 }
80
81
70 #define __ assembler_-> 82 #define __ assembler_->
71 83
72 84
85 // Inputs:
86 // - RAX: object (preserved).
87 // - RDX: optional instantiator type arguments (preserved).
88 // Destroys RCX.
89 // Returns:
90 // - unchanged object in RAX and optional instantiator type arguments in RDX.
91 // Note that this inlined code must be followed by the runtime_call code, as it
92 // may fall through to it.
srdjan 2012/04/13 21:47:34 Add comment that it can fall-through or jump to is
regis 2012/04/13 22:05:50 I expanded the comment just above.
93 void FlowGraphCompiler::GenerateInlineInstanceof(const AbstractType& type,
94 Label* is_instance,
95 Label* is_not_instance) {
96 Label runtime_call;
97 if (type.IsInstantiated()) {
98 const Class& type_class = Class::ZoneHandle(type.type_class());
99 const bool requires_type_arguments = type_class.HasTypeArguments();
100 // A Smi object cannot be the instance of a parameterized class.
101 // A class equality check is only applicable with a dst type of a
102 // non-parameterized class or with a raw dst type of a parameterized class.
103 if (requires_type_arguments) {
104 const AbstractTypeArguments& type_arguments =
105 AbstractTypeArguments::Handle(type.arguments());
106 const bool is_raw_type = type_arguments.IsNull() ||
107 type_arguments.IsRaw(type_arguments.Length());
108 __ testq(RAX, Immediate(kSmiTagMask));
109 __ j(ZERO, &runtime_call);
110 // Object not Smi.
111 if (is_raw_type) {
112 // Dynamic type argument, check only classes.
113 if (type.IsListInterface()) {
114 // TODO(srdjan) also accept List<Object>.
115 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
116 __ CompareObject(RCX, *CoreClass("ObjectArray"));
117 __ j(EQUAL, is_instance);
118 __ CompareObject(RCX, *CoreClass("GrowableObjectArray"));
119 __ j(EQUAL, is_instance);
120 } else if (!type_class.is_interface()) {
121 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
122 __ CompareObject(RCX, type_class);
123 __ j(EQUAL, is_instance);
124 }
125 // Fall through to runtime class.
126 }
127 } else { // type has NO type arguments.
128 Label compare_classes;
129 __ testq(RAX, Immediate(kSmiTagMask));
130 __ j(NOT_ZERO, &compare_classes);
131 // Object is Smi.
132 const Class& smi_class = Class::Handle(Smi::Class());
133 // TODO(regis): We should introduce a SmiType.
134 Error& malformed_error = Error::Handle();
135 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
136 type_class,
137 TypeArguments::Handle(),
138 &malformed_error)) {
139 // Successful assignable type check: return object in RAX.
140 __ jmp(is_instance);
141 } else {
142 // Failed assignable type check: call runtime to throw TypeError.
143 __ jmp(&runtime_call);
144 }
145 // Compare if the classes are equal.
146 __ Bind(&compare_classes);
147 // If type is an interface, we can skip the class equality check,
148 // because instances cannot be of an interface type.
149 if (!type_class.is_interface()) {
150 __ LoadObject(RCX, type_class);
151 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
152 __ cmpq(R10, RCX);
153 __ j(EQUAL, is_instance);
154 // RAX, RCX, and RDX are preserved in stub, result is in RBX.
155 __ call(&StubCode::IsRawSubTypeLabel());
156 // Result in RBX: 1 is raw subtype.
157 __ cmpq(RBX, Immediate(1));
158 __ j(EQUAL, is_instance);
159 // Otherwise fall through to runtime call.
160 } else {
161 // However, for specific core library interfaces, we can check for
162 // specific core library classes.
163 Error& malformed_error = Error::Handle();
164 if (type.IsBoolInterface()) {
165 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
166 const Class& bool_class = Class::ZoneHandle(
167 Isolate::Current()->object_store()->bool_class());
168 __ CompareObject(RCX, bool_class);
169 __ j(EQUAL, is_instance);
170 } else if (type.IsSubtypeOf(
171 Type::Handle(Type::NumberInterface()), &malformed_error)) {
172 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
173 if (type.IsIntInterface() || type.IsNumberInterface()) {
174 // We already checked for Smi above.
175 const Class& mint_class = Class::ZoneHandle(
176 Isolate::Current()->object_store()->mint_class());
177 __ CompareObject(RCX, mint_class);
178 __ j(EQUAL, is_instance);
179 const Class& bigint_class = Class::ZoneHandle(
180 Isolate::Current()->object_store()->bigint_class());
181 __ CompareObject(RCX, bigint_class);
182 __ j(EQUAL, is_instance);
183 }
184 if (type.IsDoubleInterface() || type.IsNumberInterface()) {
185 const Class& double_class = Class::ZoneHandle(
186 Isolate::Current()->object_store()->double_class());
187 __ CompareObject(RCX, double_class);
188 __ j(EQUAL, is_instance);
189 }
190 } else if (type.IsStringInterface()) {
191 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
192 const Class& one_byte_string_class = Class::ZoneHandle(
193 Isolate::Current()->object_store()->one_byte_string_class());
194 __ CompareObject(RCX, one_byte_string_class);
195 __ j(EQUAL, is_instance);
196 const Class& two_byte_string_class = Class::ZoneHandle(
197 Isolate::Current()->object_store()->two_byte_string_class());
198 __ CompareObject(RCX, two_byte_string_class);
199 __ j(EQUAL, is_instance);
200 const Class& four_byte_string_class = Class::ZoneHandle(
201 Isolate::Current()->object_store()->four_byte_string_class());
202 __ CompareObject(RCX, four_byte_string_class);
203 __ j(EQUAL, is_instance);
204 } else if (type.IsFunctionInterface()) {
205 const Immediate raw_null =
206 Immediate(reinterpret_cast<intptr_t>(Object::null()));
207 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
208 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset()));
209 __ cmpq(RCX, raw_null);
210 __ j(NOT_EQUAL, is_instance);
211 } else {
212 __ LoadObject(RCX, type_class);
213 // RAX: Instance (preserved).
214 // RCX: test class (preserved).
215 // RDX: instantiator type arguments (preserved).
216 __ call(&StubCode::IsRawSubTypeLabel());
217 // Result in RBX: 1 is raw subtype.
218 __ cmpq(RBX, Immediate(1));
219 __ j(EQUAL, is_instance);
220 // Otherwise fallthrough to runtime call.
221 }
222 }
223 }
224 } else {
225 ASSERT(!type.IsInstantiated());
226 // Skip check if destination is a dynamic type.
227 if (type.IsTypeParameter()) {
228 // Check if dynamic.
229 const Immediate raw_null =
230 Immediate(reinterpret_cast<intptr_t>(Object::null()));
231 // Instantiator type arguments are in RDX.
232 __ cmpq(RDX, raw_null);
233 __ j(EQUAL, is_instance);
234
235 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
236 __ movq(RCX, FieldAddress(RDX, Object::class_offset()));
237 __ CompareObject(RCX, Object::ZoneHandle(Object::type_arguments_class()));
238 __ j(NOT_EQUAL, &runtime_call);
239 __ movq(RCX,
240 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
241 // RCX: instantiated type parameter.
242 __ CompareObject(RCX, Type::ZoneHandle(Type::DynamicType()));
243 __ j(EQUAL, is_instance);
244 // Check if the type has type parameters, if not, do the class comparison.
245 Label not_smi;
246 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
247 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
248 __ CompareObject(RCX, Type::ZoneHandle(Type::IntInterface()));
249 __ j(EQUAL, is_instance);
250 __ CompareObject(RCX, Type::ZoneHandle(Type::NumberInterface()));
251 __ j(EQUAL, is_instance);
252 __ Bind(&not_smi);
253 // The instantiated type parameter RCX may not be a Type, but could be an
254 // InstantiatedType. It is therefore necessary to check its class.
255 __ movq(R10, FieldAddress(RCX, Object::class_offset()));
256 __ CompareObject(R10, Object::ZoneHandle(Object::type_class()));
257 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
258 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset()));
259 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset()));
260 // Check that class of type has no type parameters.
261 __ cmpq(R10, raw_null);
262 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
263 // We have a non-parameterized class in RCX, compare with class of
264 // value in RAX. RAX, RCX, and RDX are preserved in stub.
265 #if 1
srdjan 2012/04/13 21:47:34 remove #if 1
regis 2012/04/13 22:05:50 Oops. Searching for "if 0" is not good enough :-)
266 __ call(&StubCode::IsRawSubTypeLabel());
267 // Result in EBX: 1 is raw subtype.
268 __ cmpq(RBX, Immediate(1));
269 __ j(EQUAL, is_instance);
270 #endif
271 // Fall through to runtime call.
272 }
273 }
274 __ Bind(&runtime_call);
275 }
276
277
278 // If type check cannot be performed successfully at compile time and therefore
279 // eliminated, optimize it by adding inlined tests for:
srdjan 2012/04/13 21:47:34 Add TODO: move compile time tests to flow_graph_bu
regis 2012/04/13 22:05:50 The TODO is actually below on line 318. Edited the
280 // - NULL -> return NULL.
281 // - Smi -> compile time subtype check (only if dst class is not parameterized).
282 // - Class equality (only if class is not parameterized).
283 // Inputs:
284 // - RAX: object.
285 // - RDX: optional instantiator type arguments.
286 // Destroys RCX and RDX.
287 // Returns:
288 // - object in RAX for successful assignable check (or throws TypeError).
289 // Performance notes: positive checks must be quick, negative checks can be slow
290 // as they throw an exception.
73 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t node_id, 291 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t node_id,
74 intptr_t token_index, 292 intptr_t token_index,
293 intptr_t try_index,
294 Value* value,
75 const AbstractType& dst_type, 295 const AbstractType& dst_type,
76 const String& dst_name) { 296 const String& dst_name) {
77 Bailout("GenerateAssertAssignable"); 297 ASSERT(FLAG_enable_type_checks);
298 ASSERT(token_index >= 0);
299 ASSERT(!dst_type.IsNull());
300 ASSERT(dst_type.IsFinalized());
301
302 // Any expression is assignable to the Dynamic type and to the Object type.
303 // Skip the test.
304 if (!dst_type.IsMalformed() &&
305 (dst_type.IsDynamicType() || dst_type.IsObjectType())) {
306 return;
307 }
308
309 // It is a compile-time error to explicitly return a value (including null)
310 // from a void function. However, functions that do not explicitly return a
311 // value, implicitly return null. This includes void functions. Therefore, we
312 // skip the type test here and trust the parser to only return null in void
313 // function.
314 if (dst_type.IsVoidType()) {
315 return;
316 }
317
318 // TODO(regis): Move this compile time check to the graph builder.
319 // Eliminate the test if it can be performed successfully at compile time.
320 if ((value != NULL) && value->IsConstant()) {
321 Instance& literal_value = Instance::Handle();
322 literal_value ^= value->AsConstant()->value().raw();
323 const Class& cls = Class::Handle(literal_value.clazz());
324 if (cls.IsNullClass()) {
325 ASSERT(literal_value.IsNull() ||
326 (literal_value.raw() == Object::sentinel()) ||
327 (literal_value.raw() == Object::transition_sentinel()));
328 return;
329 }
330 Error& malformed_error = Error::Handle();
331 if (!dst_type.IsMalformed() &&
332 dst_type.IsInstantiated() &&
333 literal_value.IsInstanceOf(dst_type,
334 TypeArguments::Handle(),
335 &malformed_error)) {
336 return;
337 }
338 }
339
340 // A null object is always assignable and is returned as result.
341 const Immediate raw_null =
342 Immediate(reinterpret_cast<intptr_t>(Object::null()));
343 Label is_assignable, runtime_call;
344 __ cmpq(RAX, raw_null);
345 __ j(EQUAL, &is_assignable);
346
347 // Generate throw new TypeError() if the type is malformed.
348 if (dst_type.IsMalformed()) {
349 const Error& error = Error::Handle(dst_type.malformed_error());
350 const String& error_message = String::ZoneHandle(
351 String::NewSymbol(error.ToErrorCString()));
352 __ PushObject(Object::ZoneHandle()); // Make room for the result.
353 const Immediate location =
354 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
355 __ pushq(location); // Push the source location.
356 __ pushq(RAX); // Push the source object.
357 __ PushObject(dst_name); // Push the name of the destination.
358 __ PushObject(error_message);
359 GenerateCallRuntime(node_id,
360 token_index,
361 try_index,
362 kMalformedTypeErrorRuntimeEntry);
363 // We should never return here.
364 __ int3();
365
366 __ Bind(&is_assignable); // For a null object.
367 return;
368 }
369
370 // Generate inline type check, linking to runtime call if not assignable.
371 GenerateInlineInstanceof(dst_type, &is_assignable, &runtime_call);
372
373 __ Bind(&runtime_call);
374 __ PushObject(Object::ZoneHandle()); // Make room for the result.
375 const Immediate location =
376 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
377 __ pushq(location); // Push the source location.
378 __ pushq(RAX); // Push the source object.
379 __ PushObject(dst_type); // Push the type of the destination.
380 if (!dst_type.IsInstantiated()) {
381 __ pushq(RDX); // Instantiator type arguments.
382 } else {
383 __ pushq(raw_null); // Null instantiator.
384 }
385 __ PushObject(dst_name); // Push the name of the destination.
386 GenerateCallRuntime(node_id,
387 token_index,
388 try_index,
389 kTypeCheckRuntimeEntry);
390 // Pop the parameters supplied to the runtime entry. The result of the
391 // type check runtime call is the checked value.
392 __ addq(RSP, Immediate(5 * kWordSize));
393 __ popq(RAX);
394
395 __ Bind(&is_assignable);
78 } 396 }
79 397
80 398
81 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { 399 void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
82 if (value->IsConstant()) { 400 if (value->IsConstant()) {
83 ConstantVal* constant = value->AsConstant(); 401 ConstantVal* constant = value->AsConstant();
84 if (constant->value().IsSmi()) { 402 if (constant->value().IsSmi()) {
85 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); 403 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
86 __ movq(dst, Immediate(imm)); 404 __ movq(dst, Immediate(imm));
87 } else { 405 } else {
(...skipping 10 matching lines...) Expand all
98 LoadValue(RAX, val); 416 LoadValue(RAX, val);
99 } 417 }
100 418
101 419
102 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { 420 void FlowGraphCompiler::VisitConstant(ConstantVal* val) {
103 LoadValue(RAX, val); 421 LoadValue(RAX, val);
104 } 422 }
105 423
106 424
107 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { 425 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) {
108 Bailout("AssertAssignableComp"); 426 if (comp->type_arguments() != NULL) {
427 __ popq(RDX);
428 }
429 LoadValue(RAX, comp->value());
430 GenerateAssertAssignable(comp->node_id(),
431 comp->token_index(),
432 comp->try_index(),
433 comp->value(),
434 comp->dst_type(),
435 comp->dst_name());
436 }
437
438
439 void FlowGraphCompiler::VisitAssertBoolean(AssertBooleanComp* comp) {
440 LoadValue(RAX, comp->value());
441 // Check that the type of the value is allowed in conditional context.
442 // Call the runtime if the object is null or not of type bool.
srdjan 2012/04/13 21:47:34 A quicker comparison wold be to compare RAX with B
regis 2012/04/13 22:05:50 Good point. Done.
443 const Immediate raw_null =
444 Immediate(reinterpret_cast<intptr_t>(Object::null()));
445 Label runtime_call, done;
446 __ popq(RAX);
447 __ cmpq(RAX, raw_null);
448 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
449 __ testq(RAX, Immediate(kSmiTagMask));
450 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi.
451 // This check should pass if the receiver's class implements the interface
452 // 'bool'. Check only class 'Bool' since it is the only legal implementation
453 // of the interface 'bool'.
454 const Class& bool_class =
455 Class::ZoneHandle(Isolate::Current()->object_store()->bool_class());
456 __ movq(RDX, FieldAddress(RAX, Object::class_offset()));
457 __ CompareObject(RDX, bool_class);
458 __ j(EQUAL, &done, Assembler::kNearJump);
459
460 __ Bind(&runtime_call);
461 const Immediate location =
462 Immediate(reinterpret_cast<int64_t>(Smi::New(comp->token_index())));
463 __ pushq(location); // Push the source location.
464 __ pushq(RAX); // Push the source object.
465 GenerateCallRuntime(comp->node_id(),
466 comp->token_index(),
467 comp->try_index(),
468 kConditionTypeErrorRuntimeEntry);
469 // We should never return here.
470 __ int3();
471
472 __ Bind(&done);
109 } 473 }
110 474
111 475
112 // True iff. the arguments to a call will be properly pushed and can 476 // True iff. the arguments to a call will be properly pushed and can
113 // be popped after the call. 477 // be popped after the call.
114 template <typename T> static bool VerifyCallComputation(T* comp) { 478 template <typename T> static bool VerifyCallComputation(T* comp) {
115 // Argument values should be consecutive temps. 479 // Argument values should be consecutive temps.
116 // 480 //
117 // TODO(kmillikin): implement stack height tracking so we can also assert 481 // TODO(kmillikin): implement stack height tracking so we can also assert
118 // they are on top of the stack. 482 // they are on top of the stack.
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 Label done; 790 Label done;
427 LoadValue(RDX, comp->value()); 791 LoadValue(RDX, comp->value());
428 __ LoadObject(RAX, bool_true); 792 __ LoadObject(RAX, bool_true);
429 __ cmpq(RAX, RDX); 793 __ cmpq(RAX, RDX);
430 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 794 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
431 __ LoadObject(RAX, bool_false); 795 __ LoadObject(RAX, bool_false);
432 __ Bind(&done); 796 __ Bind(&done);
433 } 797 }
434 798
435 799
436 static const Class* CoreClass(const char* c_name) {
437 const String& class_name = String::Handle(String::NewSymbol(c_name));
438 const Class& cls = Class::ZoneHandle(Library::Handle(
439 Library::CoreImplLibrary()).LookupClass(class_name));
440 ASSERT(!cls.IsNull());
441 return &cls;
442 }
443
444
445 // Copied from CodeGenerator.
446 // If instanceof type test cannot be performed successfully at compile time and 800 // If instanceof type test cannot be performed successfully at compile time and
447 // therefore eliminated, optimize it by adding inlined tests for: 801 // therefore eliminated, optimize it by adding inlined tests for:
448 // - NULL -> return false. 802 // - NULL -> return false.
449 // - Smi -> compile time subtype check (only if dst class is not parameterized). 803 // - Smi -> compile time subtype check (only if dst class is not parameterized).
450 // - Class equality (only if class is not parameterized). 804 // - Class equality (only if class is not parameterized).
451 // Inputs: 805 // Inputs:
452 // - RAX: object. 806 // - RAX: object.
453 // - RDX: optional type-arguments. 807 // - RDX: optional instantiator type arguments.
454 // Destroys RCX. 808 // Destroys RCX and RDX.
455 // Returns: 809 // Returns:
456 // - true or false in RAX. 810 // - true or false in RAX.
457 void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id, 811 void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id,
458 intptr_t token_index, 812 intptr_t token_index,
459 intptr_t try_index, 813 intptr_t try_index,
460 Value* value, 814 Value* value,
461 const AbstractType& type, 815 const AbstractType& type,
462 bool negate_result) { 816 bool negate_result) {
463 ASSERT(type.IsFinalized() && !type.IsMalformed()); 817 ASSERT(type.IsFinalized() && !type.IsMalformed());
464 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 818 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
465 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 819 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
466 820
467 const Immediate raw_null = 821 const Immediate raw_null =
468 Immediate(reinterpret_cast<intptr_t>(Object::null())); 822 Immediate(reinterpret_cast<intptr_t>(Object::null()));
469 Label done; 823 Label is_instance, is_not_instance;
470 // If type is instantiated and non-parameterized, we can inline code 824 // If type is instantiated and non-parameterized, we can inline code
471 // checking whether the tested instance is a Smi. 825 // checking whether the tested instance is a Smi.
472 if (type.IsInstantiated()) { 826 if (type.IsInstantiated()) {
473 // A null object is only an instance of Object and Dynamic, which has 827 // A null object is only an instance of Object and Dynamic, which has
474 // already been checked above (if the type is instantiated). So we can 828 // already been checked above (if the type is instantiated). So we can
475 // return false here if the instance is null (and if the type is 829 // return false here if the instance is null (and if the type is
476 // instantiated). 830 // instantiated).
477 // We can only inline this null check if the type is instantiated at compile 831 // We can only inline this null check if the type is instantiated at compile
478 // time, since an uninstantiated type at compile time could be Object or 832 // time, since an uninstantiated type at compile time could be Object or
479 // Dynamic at run time. 833 // Dynamic at run time.
480 Label non_null;
481 __ cmpq(RAX, raw_null); 834 __ cmpq(RAX, raw_null);
482 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); 835 __ j(EQUAL, &is_not_instance);
483 __ PushObject(negate_result ? bool_true : bool_false); 836 }
484 __ jmp(&done);
485 837
486 __ Bind(&non_null); 838 // Generate inline instanceof test.
839 GenerateInlineInstanceof(type, &is_instance, &is_not_instance);
487 840
488 const Class& type_class = Class::ZoneHandle(type.type_class()); 841 // Generate runtime call.
489 const bool requires_type_arguments = type_class.HasTypeArguments();
490 // A Smi object cannot be the instance of a parameterized class.
491 // A class equality check is only applicable with a dst type of a
492 // non-parameterized class or with a raw dst type of a parameterized class.
493 if (requires_type_arguments) {
494 const AbstractTypeArguments& type_arguments =
495 AbstractTypeArguments::Handle(type.arguments());
496 const bool is_raw_type = type_arguments.IsNull() ||
497 type_arguments.IsRaw(type_arguments.Length());
498 Label runtime_call;
499 __ testq(RAX, Immediate(kSmiTagMask));
500 __ j(ZERO, &runtime_call, Assembler::kNearJump);
501 // Object not Smi.
502 if (is_raw_type) {
503 if (type.IsListInterface()) {
504 Label push_result;
505 // TODO(srdjan) also accept List<Object>.
506 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
507 __ CompareObject(RCX, *CoreClass("ObjectArray"));
508 __ j(EQUAL, &push_result, Assembler::kNearJump);
509 __ CompareObject(RCX, *CoreClass("GrowableObjectArray"));
510 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
511 __ Bind(&push_result);
512 __ PushObject(negate_result ? bool_false : bool_true);
513 __ jmp(&done);
514 } else if (!type_class.is_interface()) {
515 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
516 __ CompareObject(RCX, type_class);
517 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
518 __ PushObject(negate_result ? bool_false : bool_true);
519 __ jmp(&done);
520 }
521 }
522 __ Bind(&runtime_call);
523 // Fall through to runtime call.
524 } else {
525 ASSERT(!requires_type_arguments);
526 // Test if object is Smi and for a couple known test-classes.
527 Label compare_classes;
528 __ testq(RAX, Immediate(kSmiTagMask));
529 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
530 // Object is Smi.
531 const Class& smi_class = Class::Handle(Smi::Class());
532 // TODO(regis): We should introduce a SmiType.
533 Error& malformed_error = Error::Handle();
534 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
535 type_class,
536 TypeArguments::Handle(),
537 &malformed_error)) {
538 __ PushObject(negate_result ? bool_false : bool_true);
539 } else {
540 __ PushObject(negate_result ? bool_true : bool_false);
541 }
542 __ jmp(&done);
543
544 // Compare if the classes are equal.
545 __ Bind(&compare_classes);
546 const Class* compare_class = NULL;
547 if (type.IsStringInterface()) {
548 compare_class = &Class::ZoneHandle(
549 Isolate::Current()->object_store()->one_byte_string_class());
550 } else if (type.IsBoolInterface()) {
551 compare_class = &Class::ZoneHandle(
552 Isolate::Current()->object_store()->bool_class());
553 } else if (!type_class.is_interface()) {
554 compare_class = &type_class;
555 }
556 if (compare_class != NULL) {
557 Label runtime_call;
558 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
559 __ CompareObject(RCX, *compare_class);
560 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
561 __ PushObject(negate_result ? bool_false : bool_true);
562 __ jmp(&done, Assembler::kNearJump);
563 __ Bind(&runtime_call);
564 }
565 }
566 }
567 __ PushObject(Object::ZoneHandle()); // Make room for the result. 842 __ PushObject(Object::ZoneHandle()); // Make room for the result.
568 const Immediate location = 843 const Immediate location =
569 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); 844 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
570 const Immediate node_id_as_smi = 845 const Immediate node_id_as_smi =
571 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id))); 846 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id)));
572 __ pushq(location); // Push the source location. 847 __ pushq(location); // Push the source location.
573 __ pushq(node_id_as_smi); 848 __ pushq(node_id_as_smi);
574 __ pushq(RAX); // Push the instance. 849 __ pushq(RAX); // Push the instance.
575 __ PushObject(type); // Push the type. 850 __ PushObject(type); // Push the type.
576 if (!type.IsInstantiated()) { 851 if (!type.IsInstantiated()) {
577 __ pushq(RDX); // Type arguments. 852 __ pushq(RDX); // Instantiator type arguments.
578 } else { 853 } else {
579 __ pushq(raw_null); // Null instantiator. 854 __ pushq(raw_null); // Null instantiator.
580 } 855 }
581 GenerateCallRuntime(node_id, token_index, try_index, kInstanceofRuntimeEntry); 856 GenerateCallRuntime(node_id, token_index, try_index, kInstanceofRuntimeEntry);
582 // Pop the two parameters supplied to the runtime entry. The result of the 857 // Pop the two parameters supplied to the runtime entry. The result of the
583 // instanceof runtime call will be left as the result of the operation. 858 // instanceof runtime call will be left as the result of the operation.
584 __ addq(RSP, Immediate(5 * kWordSize)); 859 __ addq(RSP, Immediate(5 * kWordSize));
860 Label done;
585 if (negate_result) { 861 if (negate_result) {
586 Label negate_done;
587 __ popq(RDX); 862 __ popq(RDX);
588 __ LoadObject(RAX, bool_true); 863 __ LoadObject(RAX, bool_true);
589 __ cmpq(RDX, RAX); 864 __ cmpq(RDX, RAX);
590 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); 865 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
591 __ LoadObject(RAX, bool_false); 866 __ LoadObject(RAX, bool_false);
592 __ Bind(&negate_done); 867 } else {
593 __ pushq(RAX); 868 __ popq(RAX);
594 } 869 }
870 __ jmp(&done, Assembler::kNearJump);
871
872 __ Bind(&is_not_instance);
873 __ LoadObject(RAX, negate_result ? bool_true : bool_false);
874 __ jmp(&done, Assembler::kNearJump);
875
876 __ Bind(&is_instance);
877 __ LoadObject(RAX, negate_result ? bool_false : bool_true);
595 __ Bind(&done); 878 __ Bind(&done);
596 __ popq(RAX);
597 } 879 }
598 880
599 881
600 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { 882 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) {
601 if (comp->type_arguments() != NULL) { 883 if (comp->type_arguments() != NULL) {
602 __ popq(RDX); 884 __ popq(RDX);
603 } 885 }
604 __ popq(RAX); 886 LoadValue(RAX, comp->value());
605 GenerateInstanceOf(comp->node_id(), 887 GenerateInstanceOf(comp->node_id(),
606 comp->token_index(), 888 comp->token_index(),
607 comp->try_index(), 889 comp->try_index(),
608 comp->value(), 890 comp->value(),
609 comp->type(), 891 comp->type(),
610 comp->negate_result()); 892 comp->negate_result());
611 } 893 }
612 894
613 895
614 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) { 896 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) {
(...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after
1353 ASSERT(exception_handlers_list_ != NULL); 1635 ASSERT(exception_handlers_list_ != NULL);
1354 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( 1636 const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
1355 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint())); 1637 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
1356 code.set_exception_handlers(handlers); 1638 code.set_exception_handlers(handlers);
1357 } 1639 }
1358 1640
1359 1641
1360 } // namespace dart 1642 } // namespace dart
1361 1643
1362 #endif // defined TARGET_ARCH_X64 1644 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698