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

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. Otherwise, this inline code will jump to the label
93 // is_instance or to the label is_not_instance.
94 void FlowGraphCompiler::GenerateInlineInstanceof(const AbstractType& type,
95 Label* is_instance,
96 Label* is_not_instance) {
97 Label runtime_call;
98 if (type.IsInstantiated()) {
99 const Class& type_class = Class::ZoneHandle(type.type_class());
100 const bool requires_type_arguments = type_class.HasTypeArguments();
101 // A Smi object cannot be the instance of a parameterized class.
102 // A class equality check is only applicable with a dst type of a
103 // non-parameterized class or with a raw dst type of a parameterized class.
104 if (requires_type_arguments) {
105 const AbstractTypeArguments& type_arguments =
106 AbstractTypeArguments::Handle(type.arguments());
107 const bool is_raw_type = type_arguments.IsNull() ||
108 type_arguments.IsRaw(type_arguments.Length());
109 __ testq(RAX, Immediate(kSmiTagMask));
110 __ j(ZERO, &runtime_call);
111 // Object not Smi.
112 if (is_raw_type) {
113 // Dynamic type argument, check only classes.
114 if (type.IsListInterface()) {
115 // TODO(srdjan) also accept List<Object>.
116 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
117 __ CompareObject(RCX, *CoreClass("ObjectArray"));
118 __ j(EQUAL, is_instance);
119 __ CompareObject(RCX, *CoreClass("GrowableObjectArray"));
120 __ j(EQUAL, is_instance);
121 } else if (!type_class.is_interface()) {
122 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
123 __ CompareObject(RCX, type_class);
124 __ j(EQUAL, is_instance);
125 }
126 // Fall through to runtime class.
127 }
128 } else { // type has NO type arguments.
129 Label compare_classes;
130 __ testq(RAX, Immediate(kSmiTagMask));
131 __ j(NOT_ZERO, &compare_classes);
132 // Object is Smi.
133 const Class& smi_class = Class::Handle(Smi::Class());
134 // TODO(regis): We should introduce a SmiType.
135 Error& malformed_error = Error::Handle();
136 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
137 type_class,
138 TypeArguments::Handle(),
139 &malformed_error)) {
140 // Successful assignable type check: return object in RAX.
141 __ jmp(is_instance);
142 } else {
143 // Failed assignable type check: call runtime to throw TypeError.
144 __ jmp(&runtime_call);
145 }
146 // Compare if the classes are equal.
147 __ Bind(&compare_classes);
148 // If type is an interface, we can skip the class equality check,
149 // because instances cannot be of an interface type.
150 if (!type_class.is_interface()) {
151 __ LoadObject(RCX, type_class);
152 __ movq(R10, FieldAddress(RAX, Object::class_offset()));
153 __ cmpq(R10, RCX);
154 __ j(EQUAL, is_instance);
155 // RAX, RCX, and RDX are preserved in stub, result is in RBX.
156 __ call(&StubCode::IsRawSubTypeLabel());
157 // Result in RBX: 1 is raw subtype.
158 __ cmpq(RBX, Immediate(1));
159 __ j(EQUAL, is_instance);
160 // Otherwise fall through to runtime call.
161 } else {
162 // However, for specific core library interfaces, we can check for
163 // specific core library classes.
164 Error& malformed_error = Error::Handle();
165 if (type.IsBoolInterface()) {
166 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
167 const Class& bool_class = Class::ZoneHandle(
168 Isolate::Current()->object_store()->bool_class());
169 __ CompareObject(RCX, bool_class);
170 __ j(EQUAL, is_instance);
171 } else if (type.IsSubtypeOf(
172 Type::Handle(Type::NumberInterface()), &malformed_error)) {
173 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
174 if (type.IsIntInterface() || type.IsNumberInterface()) {
175 // We already checked for Smi above.
176 const Class& mint_class = Class::ZoneHandle(
177 Isolate::Current()->object_store()->mint_class());
178 __ CompareObject(RCX, mint_class);
179 __ j(EQUAL, is_instance);
180 const Class& bigint_class = Class::ZoneHandle(
181 Isolate::Current()->object_store()->bigint_class());
182 __ CompareObject(RCX, bigint_class);
183 __ j(EQUAL, is_instance);
184 }
185 if (type.IsDoubleInterface() || type.IsNumberInterface()) {
186 const Class& double_class = Class::ZoneHandle(
187 Isolate::Current()->object_store()->double_class());
188 __ CompareObject(RCX, double_class);
189 __ j(EQUAL, is_instance);
190 }
191 } else if (type.IsStringInterface()) {
192 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
193 const Class& one_byte_string_class = Class::ZoneHandle(
194 Isolate::Current()->object_store()->one_byte_string_class());
195 __ CompareObject(RCX, one_byte_string_class);
196 __ j(EQUAL, is_instance);
197 const Class& two_byte_string_class = Class::ZoneHandle(
198 Isolate::Current()->object_store()->two_byte_string_class());
199 __ CompareObject(RCX, two_byte_string_class);
200 __ j(EQUAL, is_instance);
201 const Class& four_byte_string_class = Class::ZoneHandle(
202 Isolate::Current()->object_store()->four_byte_string_class());
203 __ CompareObject(RCX, four_byte_string_class);
204 __ j(EQUAL, is_instance);
205 } else if (type.IsFunctionInterface()) {
206 const Immediate raw_null =
207 Immediate(reinterpret_cast<intptr_t>(Object::null()));
208 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
209 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset()));
210 __ cmpq(RCX, raw_null);
211 __ j(NOT_EQUAL, is_instance);
212 } else {
213 __ LoadObject(RCX, type_class);
214 // RAX: Instance (preserved).
215 // RCX: test class (preserved).
216 // RDX: instantiator type arguments (preserved).
217 __ call(&StubCode::IsRawSubTypeLabel());
218 // Result in RBX: 1 is raw subtype.
219 __ cmpq(RBX, Immediate(1));
220 __ j(EQUAL, is_instance);
221 // Otherwise fallthrough to runtime call.
222 }
223 }
224 }
225 } else {
226 ASSERT(!type.IsInstantiated());
227 // Skip check if destination is a dynamic type.
228 if (type.IsTypeParameter()) {
229 // Check if dynamic.
230 const Immediate raw_null =
231 Immediate(reinterpret_cast<intptr_t>(Object::null()));
232 // Instantiator type arguments are in RDX.
233 __ cmpq(RDX, raw_null);
234 __ j(EQUAL, is_instance);
235
236 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
237 __ movq(RCX, FieldAddress(RDX, Object::class_offset()));
238 __ CompareObject(RCX, Object::ZoneHandle(Object::type_arguments_class()));
239 __ j(NOT_EQUAL, &runtime_call);
240 __ movq(RCX,
241 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
242 // RCX: instantiated type parameter.
243 __ CompareObject(RCX, Type::ZoneHandle(Type::DynamicType()));
244 __ j(EQUAL, is_instance);
245 // Check if the type has type parameters, if not, do the class comparison.
246 Label not_smi;
247 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
248 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
249 __ CompareObject(RCX, Type::ZoneHandle(Type::IntInterface()));
250 __ j(EQUAL, is_instance);
251 __ CompareObject(RCX, Type::ZoneHandle(Type::NumberInterface()));
252 __ j(EQUAL, is_instance);
253 __ Bind(&not_smi);
254 // The instantiated type parameter RCX may not be a Type, but could be an
255 // InstantiatedType. It is therefore necessary to check its class.
256 __ movq(R10, FieldAddress(RCX, Object::class_offset()));
257 __ CompareObject(R10, Object::ZoneHandle(Object::type_class()));
258 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
259 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset()));
260 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset()));
261 // Check that class of type has no type parameters.
262 __ cmpq(R10, raw_null);
263 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
264 // We have a non-parameterized class in RCX, compare with class of
265 // value in RAX. RAX, RCX, and RDX are preserved in stub.
266 __ call(&StubCode::IsRawSubTypeLabel());
267 // Result in EBX: 1 is raw subtype.
268 __ cmpq(RBX, Immediate(1));
269 __ j(EQUAL, is_instance);
270 // Fall through to runtime call.
271 }
272 }
273 __ Bind(&runtime_call);
274 }
275
276
277 // Optimize assignable type check by adding inlined tests for:
278 // - NULL -> return NULL.
279 // - Smi -> compile time subtype check (only if dst class is not parameterized).
280 // - Class equality (only if class is not parameterized).
281 // Inputs:
282 // - RAX: object.
283 // - RDX: optional instantiator type arguments.
284 // Destroys RCX and RDX.
285 // Returns:
286 // - object in RAX for successful assignable check (or throws TypeError).
287 // Performance notes: positive checks must be quick, negative checks can be slow
288 // as they throw an exception.
73 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t node_id, 289 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t node_id,
74 intptr_t token_index, 290 intptr_t token_index,
291 intptr_t try_index,
292 Value* value,
75 const AbstractType& dst_type, 293 const AbstractType& dst_type,
76 const String& dst_name) { 294 const String& dst_name) {
77 Bailout("GenerateAssertAssignable"); 295 ASSERT(FLAG_enable_type_checks);
296 ASSERT(token_index >= 0);
297 ASSERT(!dst_type.IsNull());
298 ASSERT(dst_type.IsFinalized());
299
300 // Any expression is assignable to the Dynamic type and to the Object type.
301 // Skip the test.
302 if (!dst_type.IsMalformed() &&
303 (dst_type.IsDynamicType() || dst_type.IsObjectType())) {
304 return;
305 }
306
307 // It is a compile-time error to explicitly return a value (including null)
308 // from a void function. However, functions that do not explicitly return a
309 // value, implicitly return null. This includes void functions. Therefore, we
310 // skip the type test here and trust the parser to only return null in void
311 // function.
312 if (dst_type.IsVoidType()) {
313 return;
314 }
315
316 // TODO(regis): Move this compile time check to the graph builder.
317 // Eliminate the test if it can be performed successfully at compile time.
318 if ((value != NULL) && value->IsConstant()) {
319 Instance& literal_value = Instance::Handle();
320 literal_value ^= value->AsConstant()->value().raw();
321 const Class& cls = Class::Handle(literal_value.clazz());
322 if (cls.IsNullClass()) {
323 ASSERT(literal_value.IsNull() ||
324 (literal_value.raw() == Object::sentinel()) ||
325 (literal_value.raw() == Object::transition_sentinel()));
326 return;
327 }
328 Error& malformed_error = Error::Handle();
329 if (!dst_type.IsMalformed() &&
330 dst_type.IsInstantiated() &&
331 literal_value.IsInstanceOf(dst_type,
332 TypeArguments::Handle(),
333 &malformed_error)) {
334 return;
335 }
336 }
337
338 // A null object is always assignable and is returned as result.
339 const Immediate raw_null =
340 Immediate(reinterpret_cast<intptr_t>(Object::null()));
341 Label is_assignable, runtime_call;
342 __ cmpq(RAX, raw_null);
343 __ j(EQUAL, &is_assignable);
344
345 // Generate throw new TypeError() if the type is malformed.
346 if (dst_type.IsMalformed()) {
347 const Error& error = Error::Handle(dst_type.malformed_error());
348 const String& error_message = String::ZoneHandle(
349 String::NewSymbol(error.ToErrorCString()));
350 __ PushObject(Object::ZoneHandle()); // Make room for the result.
351 const Immediate location =
352 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
353 __ pushq(location); // Push the source location.
354 __ pushq(RAX); // Push the source object.
355 __ PushObject(dst_name); // Push the name of the destination.
356 __ PushObject(error_message);
357 GenerateCallRuntime(node_id,
358 token_index,
359 try_index,
360 kMalformedTypeErrorRuntimeEntry);
361 // We should never return here.
362 __ int3();
363
364 __ Bind(&is_assignable); // For a null object.
365 return;
366 }
367
368 // Generate inline type check, linking to runtime call if not assignable.
369 GenerateInlineInstanceof(dst_type, &is_assignable, &runtime_call);
370
371 __ Bind(&runtime_call);
372 __ PushObject(Object::ZoneHandle()); // Make room for the result.
373 const Immediate location =
374 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
375 __ pushq(location); // Push the source location.
376 __ pushq(RAX); // Push the source object.
377 __ PushObject(dst_type); // Push the type of the destination.
378 if (!dst_type.IsInstantiated()) {
379 __ pushq(RDX); // Instantiator type arguments.
380 } else {
381 __ pushq(raw_null); // Null instantiator.
382 }
383 __ PushObject(dst_name); // Push the name of the destination.
384 GenerateCallRuntime(node_id,
385 token_index,
386 try_index,
387 kTypeCheckRuntimeEntry);
388 // Pop the parameters supplied to the runtime entry. The result of the
389 // type check runtime call is the checked value.
390 __ addq(RSP, Immediate(5 * kWordSize));
391 __ popq(RAX);
392
393 __ Bind(&is_assignable);
78 } 394 }
79 395
80 396
81 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { 397 void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
82 if (value->IsConstant()) { 398 if (value->IsConstant()) {
83 ConstantVal* constant = value->AsConstant(); 399 ConstantVal* constant = value->AsConstant();
84 if (constant->value().IsSmi()) { 400 if (constant->value().IsSmi()) {
85 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); 401 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
86 __ movq(dst, Immediate(imm)); 402 __ movq(dst, Immediate(imm));
87 } else { 403 } else {
(...skipping 10 matching lines...) Expand all
98 LoadValue(RAX, val); 414 LoadValue(RAX, val);
99 } 415 }
100 416
101 417
102 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { 418 void FlowGraphCompiler::VisitConstant(ConstantVal* val) {
103 LoadValue(RAX, val); 419 LoadValue(RAX, val);
104 } 420 }
105 421
106 422
107 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { 423 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) {
108 Bailout("AssertAssignableComp"); 424 if (comp->type_arguments() != NULL) {
425 __ popq(RDX);
426 }
427 LoadValue(RAX, comp->value());
428 GenerateAssertAssignable(comp->node_id(),
429 comp->token_index(),
430 comp->try_index(),
431 comp->value(),
432 comp->dst_type(),
433 comp->dst_name());
434 }
435
436
437 void FlowGraphCompiler::VisitAssertBoolean(AssertBooleanComp* comp) {
438 LoadValue(RAX, comp->value());
439 // Check that the type of the value is allowed in conditional context.
440 // Call the runtime if the object is not bool::true or bool::false.
441 Label done;
442 __ popq(RAX);
443 __ CompareObject(RAX, Bool::ZoneHandle(Bool::True()));
444 __ j(EQUAL, &done, Assembler::kNearJump);
445 __ CompareObject(RAX, Bool::ZoneHandle(Bool::False()));
446 __ j(EQUAL, &done, Assembler::kNearJump);
447
448 const Immediate location =
449 Immediate(reinterpret_cast<int64_t>(Smi::New(comp->token_index())));
450 __ pushq(location); // Push the source location.
451 __ pushq(RAX); // Push the source object.
452 GenerateCallRuntime(comp->node_id(),
453 comp->token_index(),
454 comp->try_index(),
455 kConditionTypeErrorRuntimeEntry);
456 // We should never return here.
457 __ int3();
458
459 __ Bind(&done);
109 } 460 }
110 461
111 462
112 // True iff. the arguments to a call will be properly pushed and can 463 // True iff. the arguments to a call will be properly pushed and can
113 // be popped after the call. 464 // be popped after the call.
114 template <typename T> static bool VerifyCallComputation(T* comp) { 465 template <typename T> static bool VerifyCallComputation(T* comp) {
115 // Argument values should be consecutive temps. 466 // Argument values should be consecutive temps.
116 // 467 //
117 // TODO(kmillikin): implement stack height tracking so we can also assert 468 // TODO(kmillikin): implement stack height tracking so we can also assert
118 // they are on top of the stack. 469 // they are on top of the stack.
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 Label done; 777 Label done;
427 LoadValue(RDX, comp->value()); 778 LoadValue(RDX, comp->value());
428 __ LoadObject(RAX, bool_true); 779 __ LoadObject(RAX, bool_true);
429 __ cmpq(RAX, RDX); 780 __ cmpq(RAX, RDX);
430 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 781 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
431 __ LoadObject(RAX, bool_false); 782 __ LoadObject(RAX, bool_false);
432 __ Bind(&done); 783 __ Bind(&done);
433 } 784 }
434 785
435 786
436 static const Class* CoreClass(const char* c_name) { 787 // Optimize instanceof type test by adding inlined tests for:
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
447 // therefore eliminated, optimize it by adding inlined tests for:
448 // - NULL -> return false. 788 // - NULL -> return false.
449 // - Smi -> compile time subtype check (only if dst class is not parameterized). 789 // - Smi -> compile time subtype check (only if dst class is not parameterized).
450 // - Class equality (only if class is not parameterized). 790 // - Class equality (only if class is not parameterized).
451 // Inputs: 791 // Inputs:
452 // - RAX: object. 792 // - RAX: object.
453 // - RDX: optional type-arguments. 793 // - RDX: optional instantiator type arguments.
454 // Destroys RCX. 794 // Destroys RCX and RDX.
455 // Returns: 795 // Returns:
456 // - true or false in RAX. 796 // - true or false in RAX.
457 void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id, 797 void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id,
458 intptr_t token_index, 798 intptr_t token_index,
459 intptr_t try_index, 799 intptr_t try_index,
460 Value* value, 800 Value* value,
461 const AbstractType& type, 801 const AbstractType& type,
462 bool negate_result) { 802 bool negate_result) {
463 ASSERT(type.IsFinalized() && !type.IsMalformed()); 803 ASSERT(type.IsFinalized() && !type.IsMalformed());
464 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 804 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
465 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 805 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
466 806
467 const Immediate raw_null = 807 const Immediate raw_null =
468 Immediate(reinterpret_cast<intptr_t>(Object::null())); 808 Immediate(reinterpret_cast<intptr_t>(Object::null()));
469 Label done; 809 Label is_instance, is_not_instance;
470 // If type is instantiated and non-parameterized, we can inline code 810 // If type is instantiated and non-parameterized, we can inline code
471 // checking whether the tested instance is a Smi. 811 // checking whether the tested instance is a Smi.
472 if (type.IsInstantiated()) { 812 if (type.IsInstantiated()) {
473 // A null object is only an instance of Object and Dynamic, which has 813 // 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 814 // 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 815 // return false here if the instance is null (and if the type is
476 // instantiated). 816 // instantiated).
477 // We can only inline this null check if the type is instantiated at compile 817 // 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 818 // time, since an uninstantiated type at compile time could be Object or
479 // Dynamic at run time. 819 // Dynamic at run time.
480 Label non_null;
481 __ cmpq(RAX, raw_null); 820 __ cmpq(RAX, raw_null);
482 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); 821 __ j(EQUAL, &is_not_instance);
483 __ PushObject(negate_result ? bool_true : bool_false); 822 }
484 __ jmp(&done);
485 823
486 __ Bind(&non_null); 824 // Generate inline instanceof test.
825 GenerateInlineInstanceof(type, &is_instance, &is_not_instance);
487 826
488 const Class& type_class = Class::ZoneHandle(type.type_class()); 827 // 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. 828 __ PushObject(Object::ZoneHandle()); // Make room for the result.
568 const Immediate location = 829 const Immediate location =
569 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); 830 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index)));
570 const Immediate node_id_as_smi = 831 const Immediate node_id_as_smi =
571 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id))); 832 Immediate(reinterpret_cast<int64_t>(Smi::New(node_id)));
572 __ pushq(location); // Push the source location. 833 __ pushq(location); // Push the source location.
573 __ pushq(node_id_as_smi); 834 __ pushq(node_id_as_smi);
574 __ pushq(RAX); // Push the instance. 835 __ pushq(RAX); // Push the instance.
575 __ PushObject(type); // Push the type. 836 __ PushObject(type); // Push the type.
576 if (!type.IsInstantiated()) { 837 if (!type.IsInstantiated()) {
577 __ pushq(RDX); // Type arguments. 838 __ pushq(RDX); // Instantiator type arguments.
578 } else { 839 } else {
579 __ pushq(raw_null); // Null instantiator. 840 __ pushq(raw_null); // Null instantiator.
580 } 841 }
581 GenerateCallRuntime(node_id, token_index, try_index, kInstanceofRuntimeEntry); 842 GenerateCallRuntime(node_id, token_index, try_index, kInstanceofRuntimeEntry);
582 // Pop the two parameters supplied to the runtime entry. The result of the 843 // 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. 844 // instanceof runtime call will be left as the result of the operation.
584 __ addq(RSP, Immediate(5 * kWordSize)); 845 __ addq(RSP, Immediate(5 * kWordSize));
846 Label done;
585 if (negate_result) { 847 if (negate_result) {
586 Label negate_done;
587 __ popq(RDX); 848 __ popq(RDX);
588 __ LoadObject(RAX, bool_true); 849 __ LoadObject(RAX, bool_true);
589 __ cmpq(RDX, RAX); 850 __ cmpq(RDX, RAX);
590 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); 851 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
591 __ LoadObject(RAX, bool_false); 852 __ LoadObject(RAX, bool_false);
592 __ Bind(&negate_done); 853 } else {
593 __ pushq(RAX); 854 __ popq(RAX);
594 } 855 }
856 __ jmp(&done, Assembler::kNearJump);
857
858 __ Bind(&is_not_instance);
859 __ LoadObject(RAX, negate_result ? bool_true : bool_false);
860 __ jmp(&done, Assembler::kNearJump);
861
862 __ Bind(&is_instance);
863 __ LoadObject(RAX, negate_result ? bool_false : bool_true);
595 __ Bind(&done); 864 __ Bind(&done);
596 __ popq(RAX);
597 } 865 }
598 866
599 867
600 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { 868 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) {
601 if (comp->type_arguments() != NULL) { 869 if (comp->type_arguments() != NULL) {
602 __ popq(RDX); 870 __ popq(RDX);
603 } 871 }
604 __ popq(RAX); 872 LoadValue(RAX, comp->value());
605 GenerateInstanceOf(comp->node_id(), 873 GenerateInstanceOf(comp->node_id(),
606 comp->token_index(), 874 comp->token_index(),
607 comp->try_index(), 875 comp->try_index(),
608 comp->value(), 876 comp->value(),
609 comp->type(), 877 comp->type(),
610 comp->negate_result()); 878 comp->negate_result());
611 } 879 }
612 880
613 881
614 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) { 882 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) {
(...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after
1353 ASSERT(exception_handlers_list_ != NULL); 1621 ASSERT(exception_handlers_list_ != NULL);
1354 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( 1622 const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
1355 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint())); 1623 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
1356 code.set_exception_handlers(handlers); 1624 code.set_exception_handlers(handlers);
1357 } 1625 }
1358 1626
1359 1627
1360 } // namespace dart 1628 } // namespace dart
1361 1629
1362 #endif // defined TARGET_ARCH_X64 1630 #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