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

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

Issue 10636038: Minimize differences between ia32 and x64 sources to facilitate maintenance. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 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') | no next file » | 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"
11 #include "vm/ast_printer.h" 11 #include "vm/ast_printer.h"
12 #include "vm/code_descriptors.h"
13 #include "vm/code_generator.h"
14 #include "vm/disassembler.h"
15 #include "vm/il_printer.h" 12 #include "vm/il_printer.h"
16 #include "vm/locations.h" 13 #include "vm/locations.h"
17 #include "vm/object_store.h" 14 #include "vm/object_store.h"
18 #include "vm/parser.h" 15 #include "vm/parser.h"
19 #include "vm/stub_code.h" 16 #include "vm/stub_code.h"
20 17
21 namespace dart { 18 namespace dart {
22 19
23 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables.");
24 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function.");
25 DECLARE_FLAG(bool, enable_type_checks); 20 DECLARE_FLAG(bool, enable_type_checks);
26 DECLARE_FLAG(bool, print_ast); 21 DECLARE_FLAG(bool, print_ast);
22 DECLARE_FLAG(bool, print_scopes);
23 DECLARE_FLAG(bool, trace_functions);
27 24
28 25
29 void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) { 26 void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) {
30 Assembler* assem = compiler->assembler(); 27 Assembler* assem = compiler->assembler();
31 #define __ assem-> 28 #define __ assem->
32 __ Comment("Deopt stub for id %d", deopt_id_); 29 __ Comment("Deopt stub for id %d", deopt_id_);
33 __ Bind(entry_label()); 30 __ Bind(entry_label());
34 for (intptr_t i = 0; i < registers_.length(); i++) { 31 for (intptr_t i = 0; i < registers_.length(); i++) {
35 if (registers_[i] != kNoRegister) { 32 if (registers_[i] != kNoRegister) {
36 __ pushq(registers_[i]); 33 __ pushq(registers_[i]);
37 } 34 }
38 } 35 }
39 __ movq(RAX, Immediate(Smi::RawValue(reason_))); 36 __ movq(RAX, Immediate(Smi::RawValue(reason_)));
40 __ call(&StubCode::DeoptimizeLabel()); 37 __ call(&StubCode::DeoptimizeLabel());
41 compiler->AddCurrentDescriptor(PcDescriptors::kOther, 38 compiler->AddCurrentDescriptor(PcDescriptors::kOther,
42 deopt_id_, 39 deopt_id_,
43 deopt_token_pos_, 40 deopt_token_pos_,
44 try_index_); 41 try_index_);
45 #undef __ 42 #undef __
46 } 43 }
47 44
48 45
49 #define __ assembler()-> 46 #define __ assembler()->
50 47
51 48
52
53 // Fall through if bool_register contains null. 49 // Fall through if bool_register contains null.
54 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, 50 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
55 Label* is_true, 51 Label* is_true,
56 Label* is_false) { 52 Label* is_false) {
57 const Immediate raw_null = 53 const Immediate raw_null =
58 Immediate(reinterpret_cast<intptr_t>(Object::null())); 54 Immediate(reinterpret_cast<intptr_t>(Object::null()));
59 Label fall_through; 55 Label fall_through;
60 __ cmpq(bool_register, raw_null); 56 __ cmpq(bool_register, raw_null);
61 __ j(EQUAL, &fall_through, Assembler::kNearJump); 57 __ j(EQUAL, &fall_through, Assembler::kNearJump);
62 __ CompareObject(bool_register, bool_true()); 58 __ CompareObject(bool_register, bool_true());
63 __ j(EQUAL, is_true); 59 __ j(EQUAL, is_true);
64 __ jmp(is_false); 60 __ jmp(is_false);
65 __ Bind(&fall_through); 61 __ Bind(&fall_through);
66 } 62 }
67 63
68 64
65 // Clobbers RCX.
69 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( 66 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
70 TypeTestStubKind test_kind, 67 TypeTestStubKind test_kind,
71 Register instance_reg, 68 Register instance_reg,
72 Register type_arguments_reg, 69 Register type_arguments_reg,
73 Register temp_reg, 70 Register temp_reg,
74 Label* is_instance_lbl, 71 Label* is_instance_lbl,
75 Label* is_not_instance_lbl) { 72 Label* is_not_instance_lbl) {
76 const SubtypeTestCache& type_test_cache = 73 const SubtypeTestCache& type_test_cache =
77 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 74 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
78 const Immediate raw_null = 75 const Immediate raw_null =
79 Immediate(reinterpret_cast<intptr_t>(Object::null())); 76 Immediate(reinterpret_cast<intptr_t>(Object::null()));
80 __ LoadObject(temp_reg, type_test_cache); 77 __ LoadObject(temp_reg, type_test_cache);
81 __ pushq(temp_reg); // Subtype test cache. 78 __ pushq(temp_reg); // Subtype test cache.
82 __ pushq(instance_reg); // Instance. 79 __ pushq(instance_reg); // Instance.
83 if (test_kind == kTestTypeOneArg) { 80 if (test_kind == kTestTypeOneArg) {
84 ASSERT(type_arguments_reg == kNoRegister); 81 ASSERT(type_arguments_reg == kNoRegister);
85 __ pushq(raw_null); 82 __ pushq(raw_null);
86 __ call(&StubCode::Subtype1TestCacheLabel()); 83 __ call(&StubCode::Subtype1TestCacheLabel());
87 } else if (test_kind == kTestTypeTwoArgs) { 84 } else if (test_kind == kTestTypeTwoArgs) {
88 ASSERT(type_arguments_reg == kNoRegister); 85 ASSERT(type_arguments_reg == kNoRegister);
89 __ pushq(raw_null); 86 __ pushq(raw_null);
90 __ call(&StubCode::Subtype2TestCacheLabel()); 87 __ call(&StubCode::Subtype2TestCacheLabel());
91 } else if (test_kind == kTestTypeThreeArgs) { 88 } else if (test_kind == kTestTypeThreeArgs) {
92 __ pushq(type_arguments_reg); 89 __ pushq(type_arguments_reg);
93 __ call(&StubCode::Subtype3TestCacheLabel()); 90 __ call(&StubCode::Subtype3TestCacheLabel());
94 } else { 91 } else {
95 UNREACHABLE(); 92 UNREACHABLE();
96 } 93 }
97 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. 94 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
95 ASSERT(instance_reg != RCX);
96 ASSERT(temp_reg != RCX);
98 __ popq(instance_reg); // Discard. 97 __ popq(instance_reg); // Discard.
99 __ popq(instance_reg); // Restore receiver. 98 __ popq(instance_reg); // Restore receiver.
100 __ popq(temp_reg); // Discard. 99 __ popq(temp_reg); // Discard.
101 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); 100 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl);
102 return type_test_cache.raw(); 101 return type_test_cache.raw();
103 } 102 }
104 103
104
105 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 105 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
106 // type test is conclusive, otherwise fallthrough if a type test could not 106 // type test is conclusive, otherwise fallthrough if a type test could not
107 // be completed. 107 // be completed.
108 // RAX: instance (must survive), 108 // RAX: instance (must survive).
109 // Clobbers R10.
109 RawSubtypeTestCache* 110 RawSubtypeTestCache*
110 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 111 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
111 intptr_t cid, 112 intptr_t cid,
112 intptr_t token_pos, 113 intptr_t token_pos,
113 const AbstractType& type, 114 const AbstractType& type,
114 Label* is_instance_lbl, 115 Label* is_instance_lbl,
115 Label* is_not_instance_lbl) { 116 Label* is_not_instance_lbl) {
116 ASSERT(type.IsInstantiated()); 117 ASSERT(type.IsInstantiated());
117 const Class& type_class = Class::ZoneHandle(type.type_class()); 118 const Class& type_class = Class::ZoneHandle(type.type_class());
118 ASSERT(type_class.HasTypeArguments()); 119 ASSERT(type_class.HasTypeArguments());
(...skipping 30 matching lines...) Expand all
149 // Check if type argument is dynamic or Object. 150 // Check if type argument is dynamic or Object.
150 const Type& object_type = Type::Handle(Type::ObjectType()); 151 const Type& object_type = Type::Handle(Type::ObjectType());
151 Error& malformed_error = Error::Handle(); 152 Error& malformed_error = Error::Handle();
152 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { 153 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) {
153 // Instance class test only necessary. 154 // Instance class test only necessary.
154 return GenerateSubtype1TestCacheLookup( 155 return GenerateSubtype1TestCacheLookup(
155 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 156 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
156 } 157 }
157 } 158 }
158 } 159 }
159
160 // Regular subtype test cache involving instance's type arguments. 160 // Regular subtype test cache involving instance's type arguments.
161 const Register kTypeArgumentsReg = kNoRegister; 161 const Register kTypeArgumentsReg = kNoRegister;
162 const Register kTempReg = R10; 162 const Register kTempReg = R10;
163 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, 163 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
164 kInstanceReg, 164 kInstanceReg,
165 kTypeArgumentsReg, 165 kTypeArgumentsReg,
166 kTempReg, 166 kTempReg,
167 is_instance_lbl, 167 is_instance_lbl,
168 is_not_instance_lbl); 168 is_not_instance_lbl);
169 } 169 }
170 170
171 171
172 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, 172 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
173 const GrowableArray<intptr_t>& class_ids, 173 const GrowableArray<intptr_t>& class_ids,
174 Label* is_equal_lbl, 174 Label* is_equal_lbl,
175 Label* is_not_equal_lbl) { 175 Label* is_not_equal_lbl) {
176 for (intptr_t i = 0; i < class_ids.length(); i++) { 176 for (intptr_t i = 0; i < class_ids.length(); i++) {
177 __ cmpl(class_id_reg, Immediate(class_ids[i])); 177 __ cmpl(class_id_reg, Immediate(class_ids[i]));
178 __ j(EQUAL, is_equal_lbl); 178 __ j(EQUAL, is_equal_lbl);
179 } 179 }
180 __ jmp(is_not_equal_lbl); 180 __ jmp(is_not_equal_lbl);
181 } 181 }
182 182
183 183
184
185 // Testing against an instantiated type with no arguments, without 184 // Testing against an instantiated type with no arguments, without
186 // SubtypeTestCache. 185 // SubtypeTestCache.
187 // RAX: instance to test against (preserved). 186 // RAX: instance to test against (preserved).
187 // Clobbers R10, R13.
188 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 188 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
189 intptr_t cid, 189 intptr_t cid,
190 intptr_t token_pos, 190 intptr_t token_pos,
191 const AbstractType& type, 191 const AbstractType& type,
192 Label* is_instance_lbl, 192 Label* is_instance_lbl,
193 Label* is_not_instance_lbl) { 193 Label* is_not_instance_lbl) {
194 ASSERT(type.IsInstantiated()); 194 ASSERT(type.IsInstantiated());
195 const Class& type_class = Class::ZoneHandle(type.type_class()); 195 const Class& type_class = Class::Handle(type.type_class());
196 ASSERT(!type_class.HasTypeArguments()); 196 ASSERT(!type_class.HasTypeArguments());
197 197
198 const Register kInstanceReg = RAX;
198 Label compare_classes; 199 Label compare_classes;
199 __ testq(RAX, Immediate(kSmiTagMask)); 200 __ testq(kInstanceReg, Immediate(kSmiTagMask));
200 __ j(NOT_ZERO, &compare_classes); 201 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
201 // Instance is Smi, check directly. 202 // Instance is Smi, check directly.
202 const Class& smi_class = Class::Handle(Smi::Class()); 203 const Class& smi_class = Class::Handle(Smi::Class());
203 // TODO(regis): We should introduce a SmiType. 204 // TODO(regis): We should introduce a SmiType.
204 Error& malformed_error = Error::Handle(); 205 Error& malformed_error = Error::Handle();
205 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), 206 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
206 type_class, 207 type_class,
207 TypeArguments::Handle(), 208 TypeArguments::Handle(),
208 &malformed_error)) { 209 &malformed_error)) {
209 __ jmp(is_instance_lbl); 210 __ jmp(is_instance_lbl);
210 } else { 211 } else {
211 __ jmp(is_not_instance_lbl); 212 __ jmp(is_not_instance_lbl);
212 } 213 }
213 214 // Compare if the classes are equal.
214 // Compare if the classes are equal. Instance is not Smi.
215 __ Bind(&compare_classes); 215 __ Bind(&compare_classes);
216 const Register kClassIdReg = R10; 216 const Register kClassIdReg = R10;
217 __ LoadClassId(kClassIdReg, RAX); 217 __ LoadClassId(kClassIdReg, kInstanceReg);
218 // If type is an interface, we can skip the class equality check. 218 // If type is an interface, we can skip the class equality check.
219 if (!type_class.is_interface()) { 219 if (!type_class.is_interface()) {
220 __ cmpl(kClassIdReg, Immediate(type_class.id())); 220 __ cmpl(kClassIdReg, Immediate(type_class.id()));
221 __ j(EQUAL, is_instance_lbl); 221 __ j(EQUAL, is_instance_lbl);
222 } 222 }
223 // Check for interfaces that cannot be implemented by user. 223 // Bool interface can be implemented only by core class Bool.
224 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). 224 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
225 // Bool interface can be implemented only by core class Bool.
226 if (type.IsBoolInterface()) { 225 if (type.IsBoolInterface()) {
227 __ cmpl(kClassIdReg, Immediate(kBool)); 226 __ cmpl(kClassIdReg, Immediate(kBool));
228 __ j(EQUAL, is_instance_lbl); 227 __ j(EQUAL, is_instance_lbl);
229 __ jmp(is_not_instance_lbl); 228 __ jmp(is_not_instance_lbl);
230 return; 229 return;
231 } 230 }
232 if (type.IsFunctionInterface()) { 231 if (type.IsFunctionInterface()) {
233 // Check if instance is a closure. 232 // Check if instance is a closure.
234 const Immediate raw_null = 233 const Immediate raw_null =
235 Immediate(reinterpret_cast<intptr_t>(Object::null())); 234 Immediate(reinterpret_cast<intptr_t>(Object::null()));
(...skipping 15 matching lines...) Expand all
251 if (type.IsStringInterface()) { 250 if (type.IsStringInterface()) {
252 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); 251 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
253 return; 252 return;
254 } 253 }
255 // Otherwise fallthrough. 254 // Otherwise fallthrough.
256 } 255 }
257 256
258 257
259 // Uses SubtypeTestCache to store instance class and result. 258 // Uses SubtypeTestCache to store instance class and result.
260 // RAX: instance to test. 259 // RAX: instance to test.
260 // Clobbers R10, R13.
261 // Immediate class test already done. 261 // Immediate class test already done.
262 // TODO(srdjan): Implement a quicker subtype check, as type test
263 // arrays can grow too high, but they may be useful when optimizing
264 // code (type-feedback).
262 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 265 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
263 intptr_t cid, 266 intptr_t cid,
264 intptr_t token_pos, 267 intptr_t token_pos,
265 const Class& type_class, 268 const Class& type_class,
266 Label* is_instance_lbl, 269 Label* is_instance_lbl,
267 Label* is_not_instance_lbl) { 270 Label* is_not_instance_lbl) {
268 const Register kInstanceReg = RAX; 271 const Register kInstanceReg = RAX;
269 __ LoadClass(R10, kInstanceReg); 272 __ LoadClass(R10, kInstanceReg);
273 // R10: instance class.
270 // Check immediate superclass equality. 274 // Check immediate superclass equality.
271 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); 275 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
272 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); 276 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
273 __ CompareObject(R13, type_class); 277 __ CompareObject(R13, type_class);
274 __ j(EQUAL, is_instance_lbl); 278 __ j(EQUAL, is_instance_lbl);
275 279
276 const Register kTypeArgumentsReg = kNoRegister; 280 const Register kTypeArgumentsReg = kNoRegister;
277 const Register kTempReg = R10; 281 const Register kTempReg = R10;
278 return GenerateCallSubtypeTestStub(kTestTypeOneArg, 282 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
279 kInstanceReg, 283 kInstanceReg,
280 kTypeArgumentsReg, 284 kTypeArgumentsReg,
281 kTempReg, 285 kTempReg,
282 is_instance_lbl, 286 is_instance_lbl,
283 is_not_instance_lbl); 287 is_not_instance_lbl);
284 } 288 }
285 289
286 290
287 // Generates inlined check if 'type' is a type parameter or type itsef 291 // Generates inlined check if 'type' is a type parameter or type itsef
288 // RAX: instance (preserved). 292 // RAX: instance (preserved).
293 // Clobbers RDI, RDX, R10.
289 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 294 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
290 intptr_t cid, 295 intptr_t cid,
291 intptr_t token_pos, 296 intptr_t token_pos,
292 const AbstractType& type, 297 const AbstractType& type,
293 Label* is_instance_lbl, 298 Label* is_instance_lbl,
294 Label* is_not_instance_lbl) { 299 Label* is_not_instance_lbl) {
295 ASSERT(!type.IsInstantiated()); 300 ASSERT(!type.IsInstantiated());
301 // Skip check if destination is a dynamic type.
296 const Immediate raw_null = 302 const Immediate raw_null =
297 Immediate(reinterpret_cast<intptr_t>(Object::null())); 303 Immediate(reinterpret_cast<intptr_t>(Object::null()));
298 if (type.IsTypeParameter()) { 304 if (type.IsTypeParameter()) {
299 // Load instantiator (or null) and instantiator type arguments on stack. 305 // Load instantiator (or null) and instantiator type arguments on stack.
300 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 306 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
301 // RDX: instantiator type arguments. 307 // RDX: instantiator type arguments.
302 // Check if type argument is Dynamic. 308 // Check if type argument is Dynamic.
303 __ cmpq(RDX, raw_null); 309 __ cmpq(RDX, raw_null);
304 __ j(EQUAL, is_instance_lbl); 310 __ j(EQUAL, is_instance_lbl);
305 // Can handle only type arguments that are instances of TypeArguments. 311 // Can handle only type arguments that are instances of TypeArguments.
306 // (runtime checks canonicalize type arguments). 312 // (runtime checks canonicalize type arguments).
307 Label fall_through; 313 Label fall_through;
308 __ CompareClassId(RDX, kTypeArguments); 314 __ CompareClassId(RDX, kTypeArguments);
309 __ j(NOT_EQUAL, &fall_through); 315 __ j(NOT_EQUAL, &fall_through);
310 __ movq(RDI, 316 __ movq(RDI,
311 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index()))); 317 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
312 // RDI: Concrete type. 318 // RDI: Concrete type of type.
313 // Check if it is Dynamic, 319 // Check if type argument is dynamic.
314 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); 320 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
315 __ j(EQUAL, is_instance_lbl); 321 __ j(EQUAL, is_instance_lbl);
316 __ cmpq(RDI, raw_null); 322 __ cmpq(RDI, raw_null);
317 __ j(EQUAL, is_instance_lbl); 323 __ j(EQUAL, is_instance_lbl);
318 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); 324 const Type& object_type = Type::ZoneHandle(Type::ObjectType());
319 __ CompareObject(RDI, object_type); 325 __ CompareObject(RDI, object_type);
320 __ j(EQUAL, is_instance_lbl); 326 __ j(EQUAL, is_instance_lbl);
321 327
322 // For Smi check quickly against int and num interface types. 328 // For Smi check quickly against int and num interfaces.
323 Label not_smi; 329 Label not_smi;
324 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? 330 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
325 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump); 331 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
326 __ CompareObject(RDI, Type::ZoneHandle(Type::IntInterface())); 332 __ CompareObject(RDI, Type::ZoneHandle(Type::IntInterface()));
327 __ j(EQUAL, is_instance_lbl); 333 __ j(EQUAL, is_instance_lbl);
328 __ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface())); 334 __ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface()));
329 __ j(EQUAL, is_instance_lbl); 335 __ j(EQUAL, is_instance_lbl);
330 // Smi must be handled in runtime. 336 // Smi must be handled in runtime.
331 __ jmp(&fall_through); 337 __ jmp(&fall_through);
332 338
333 __ Bind(&not_smi); 339 __ Bind(&not_smi);
334 // RDX: instantiator type arguments. 340 // RDX: instantiator type arguments.
335 // RAX: instance. 341 // RAX: instance.
336 const Register kInstanceReg = RAX; 342 const Register kInstanceReg = RAX;
337 const Register kTypeArgumentsReg = RDX; 343 const Register kTypeArgumentsReg = RDX;
338 const Register kTempReg = R10; 344 const Register kTempReg = R10;
339 const SubtypeTestCache& type_test_cache = 345 const SubtypeTestCache& type_test_cache =
340 SubtypeTestCache::ZoneHandle( 346 SubtypeTestCache::ZoneHandle(
341 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, 347 GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
342 kInstanceReg, 348 kInstanceReg,
343 kTypeArgumentsReg, 349 kTypeArgumentsReg,
344 kTempReg, 350 kTempReg,
345 is_instance_lbl, 351 is_instance_lbl,
346 is_not_instance_lbl)); 352 is_not_instance_lbl));
347
348 __ Bind(&fall_through); 353 __ Bind(&fall_through);
349 return type_test_cache.raw(); 354 return type_test_cache.raw();
350 } 355 }
351 if (type.IsType()) { 356 if (type.IsType()) {
352 const Register kInstanceReg = RAX; 357 const Register kInstanceReg = RAX;
353 const Register kTypeArgumentsReg = RDX; 358 const Register kTypeArgumentsReg = RDX;
354 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? 359 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
355 __ j(ZERO, is_not_instance_lbl); 360 __ j(ZERO, is_not_instance_lbl);
356 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args. 361 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args.
357 // Uninstantiated type class is known at compile time, but the type 362 // Uninstantiated type class is known at compile time, but the type
358 // arguments are determined at runtime by the instantiator. 363 // arguments are determined at runtime by the instantiator.
359 const Register kTempReg = R10; 364 const Register kTempReg = R10;
360 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, 365 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
361 kInstanceReg, 366 kInstanceReg,
362 kTypeArgumentsReg, 367 kTypeArgumentsReg,
363 kTempReg, 368 kTempReg,
364 is_instance_lbl, 369 is_instance_lbl,
365 is_not_instance_lbl); 370 is_not_instance_lbl);
366 } 371 }
367 return SubtypeTestCache::null(); 372 return SubtypeTestCache::null();
368 } 373 }
369 374
370 375
371 // Inputs: 376 // Inputs:
372 // - RAX: instance to test against (preserved). 377 // - RAX: instance to test against (preserved).
373 // - RDX: optional instantiator type arguments (preserved). 378 // - RDX: optional instantiator type arguments (preserved).
374 // Destroys RCX. 379 // Clobbers R10, R13.
375 // Returns: 380 // Returns:
376 // - unchanged object in RAX and optional instantiator type arguments in RDX. 381 // - preserved instance in RAX and optional instantiator type arguments in RDX.
377 // Note that this inlined code must be followed by the runtime_call code, as it 382 // Note that this inlined code must be followed by the runtime_call code, as it
378 // may fall through to it. Otherwise, this inline code will jump to the label 383 // may fall through to it. Otherwise, this inline code will jump to the label
379 // is_instance or to the label is_not_instance. 384 // is_instance or to the label is_not_instance.
380 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 385 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
381 intptr_t cid, 386 intptr_t cid,
382 intptr_t token_pos, 387 intptr_t token_pos,
383 const AbstractType& type, 388 const AbstractType& type,
384 Label* is_instance_lbl, 389 Label* is_instance_lbl,
385 Label* is_not_instance_lbl) { 390 Label* is_not_instance_lbl) {
386 if (type.IsInstantiated()) { 391 if (type.IsInstantiated()) {
(...skipping 24 matching lines...) Expand all
411 return GenerateUninstantiatedTypeTest(cid, 416 return GenerateUninstantiatedTypeTest(cid,
412 token_pos, 417 token_pos,
413 type, 418 type,
414 is_instance_lbl, 419 is_instance_lbl,
415 is_not_instance_lbl); 420 is_not_instance_lbl);
416 } 421 }
417 return SubtypeTestCache::null(); 422 return SubtypeTestCache::null();
418 } 423 }
419 424
420 425
426 // If instanceof type test cannot be performed successfully at compile time and
427 // therefore eliminated, optimize it by adding inlined tests for:
428 // - NULL -> return false.
429 // - Smi -> compile time subtype check (only if dst class is not parameterized).
430 // - Class equality (only if class is not parameterized).
431 // Inputs:
432 // - RAX: object.
433 // - RDX: instantiator type arguments or raw_null.
434 // - RCX: instantiator or raw_null.
435 // Clobbers RCX and RDX.
436 // Returns:
437 // - true or false in RAX.
438 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
439 intptr_t token_pos,
440 intptr_t try_index,
441 const AbstractType& type,
442 bool negate_result) {
443 ASSERT(type.IsFinalized() && !type.IsMalformed());
444
445 const Immediate raw_null =
446 Immediate(reinterpret_cast<intptr_t>(Object::null()));
447 Label is_instance, is_not_instance;
448 __ pushq(RCX); // Store instantiator on stack.
449 __ pushq(RDX); // Store instantiator type arguments.
450 // If type is instantiated and non-parameterized, we can inline code
451 // checking whether the tested instance is a Smi.
452 if (type.IsInstantiated()) {
453 // A null object is only an instance of Object and Dynamic, which has
454 // already been checked above (if the type is instantiated). So we can
455 // return false here if the instance is null (and if the type is
456 // instantiated).
457 // We can only inline this null check if the type is instantiated at compile
458 // time, since an uninstantiated type at compile time could be Object or
459 // Dynamic at run time.
460 __ cmpq(RAX, raw_null);
461 __ j(EQUAL, &is_not_instance);
462 }
463
464 // Generate inline instanceof test.
465 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
466 test_cache = GenerateInlineInstanceof(cid, token_pos, type,
467 &is_instance, &is_not_instance);
468
469 // Generate runtime call.
470 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
471 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
472 __ PushObject(Object::ZoneHandle()); // Make room for the result.
473 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
474 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
475 __ pushq(RAX); // Push the instance.
476 __ PushObject(type); // Push the type.
477 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
478 __ pushq(RDX); // Instantiator type arguments.
479 __ LoadObject(RAX, test_cache);
480 __ pushq(RAX);
481 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry);
482 // Pop the two parameters supplied to the runtime entry. The result of the
483 // instanceof runtime call will be left as the result of the operation.
484 __ Drop(7);
485 Label done;
486 if (negate_result) {
487 __ popq(RDX);
488 __ LoadObject(RAX, bool_true());
489 __ cmpq(RDX, RAX);
490 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
491 __ LoadObject(RAX, bool_false());
492 } else {
493 __ popq(RAX);
494 }
495 __ jmp(&done, Assembler::kNearJump);
496
497 __ Bind(&is_not_instance);
498 __ LoadObject(RAX, negate_result ? bool_true() : bool_false());
499 __ jmp(&done, Assembler::kNearJump);
500
501 __ Bind(&is_instance);
502 __ LoadObject(RAX, negate_result ? bool_false() : bool_true());
503 __ Bind(&done);
504 __ popq(RDX); // Remove pushed instantiator type arguments.
505 __ popq(RCX); // Remove pushed instantiator.
506 }
507
508
421 // Optimize assignable type check by adding inlined tests for: 509 // Optimize assignable type check by adding inlined tests for:
422 // - NULL -> return NULL. 510 // - NULL -> return NULL.
423 // - Smi -> compile time subtype check (only if dst class is not parameterized). 511 // - Smi -> compile time subtype check (only if dst class is not parameterized).
424 // - Class equality (only if class is not parameterized). 512 // - Class equality (only if class is not parameterized).
425 // Inputs: 513 // Inputs:
426 // - RAX: object. 514 // - RAX: object.
427 // - RDX: instantiator type arguments or raw_null. 515 // - RDX: instantiator type arguments or raw_null.
428 // - RCX: instantiator or raw_null. 516 // - RCX: instantiator or raw_null.
429 // Returns: 517 // Returns:
430 // - object in RAX for successful assignable check (or throws TypeError). 518 // - object in RAX for successful assignable check (or throws TypeError).
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 __ int3(); 557 __ int3();
470 558
471 __ Bind(&is_assignable); // For a null object. 559 __ Bind(&is_assignable); // For a null object.
472 return; 560 return;
473 } 561 }
474 562
475 // Generate inline type check, linking to runtime call if not assignable. 563 // Generate inline type check, linking to runtime call if not assignable.
476 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 564 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
477 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type, 565 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type,
478 &is_assignable, &runtime_call); 566 &is_assignable, &runtime_call);
567
479 __ Bind(&runtime_call); 568 __ Bind(&runtime_call);
480 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 569 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
481 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. 570 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
482 __ PushObject(Object::ZoneHandle()); // Make room for the result. 571 __ PushObject(Object::ZoneHandle()); // Make room for the result.
483 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location. 572 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
484 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 573 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
485 __ pushq(RAX); // Push the source object. 574 __ pushq(RAX); // Push the source object.
486 __ PushObject(dst_type); // Push the type of the destination. 575 __ PushObject(dst_type); // Push the type of the destination.
487 __ pushq(RCX); // Instantiator. 576 __ pushq(RCX); // Instantiator.
488 __ pushq(RDX); // Instantiator type arguments. 577 __ pushq(RDX); // Instantiator type arguments.
489 __ PushObject(dst_name); // Push the name of the destination. 578 __ PushObject(dst_name); // Push the name of the destination.
490 __ LoadObject(RAX, test_cache); 579 __ LoadObject(RAX, test_cache);
491 __ pushq(RAX); 580 __ pushq(RAX);
492 GenerateCallRuntime(cid, 581 GenerateCallRuntime(cid,
493 token_pos, 582 token_pos,
494 try_index, 583 try_index,
495 kTypeCheckRuntimeEntry); 584 kTypeCheckRuntimeEntry);
496 // Pop the parameters supplied to the runtime entry. The result of the 585 // Pop the parameters supplied to the runtime entry. The result of the
497 // type check runtime call is the checked value. 586 // type check runtime call is the checked value.
498 __ Drop(8); 587 __ Drop(8);
499 __ popq(RAX); 588 __ popq(RAX);
500 589
501 __ Bind(&is_assignable); 590 __ Bind(&is_assignable);
502 __ popq(RDX); // Remove pushed instantiator type arguments.. 591 __ popq(RDX); // Remove pushed instantiator type arguments..
503 __ popq(RCX); // Remove pushed instantiator. 592 __ popq(RCX); // Remove pushed instantiator.
504 } 593 }
505 594
506 595
507 void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
508 if (value->IsConstant()) {
509 ConstantVal* constant = value->AsConstant();
510 if (constant->value().IsSmi()) {
511 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
512 __ movq(dst, Immediate(imm));
513 } else {
514 __ LoadObject(dst, value->AsConstant()->value());
515 }
516 } else {
517 ASSERT(value->IsUse());
518 __ popq(dst);
519 }
520 }
521
522
523 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
524 const ICData& ic_data,
525 const Array& arguments_descriptor,
526 intptr_t argument_count) {
527 __ LoadObject(RBX, ic_data);
528 __ LoadObject(R10, arguments_descriptor);
529
530 __ call(target_label);
531 const intptr_t descr_offset = assembler()->CodeSize();
532 __ Drop(argument_count);
533 return descr_offset;
534 }
535
536 intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function,
537 const Array& arguments_descriptor,
538 intptr_t argument_count) {
539 __ LoadObject(RBX, function);
540 __ LoadObject(R10, arguments_descriptor);
541 __ call(&StubCode::CallStaticFunctionLabel());
542 const intptr_t descr_offset = assembler()->CodeSize();
543 __ Drop(argument_count);
544 return descr_offset;
545 }
546
547
548 // Optimize instanceof type test by adding inlined tests for:
549 // - NULL -> return false.
550 // - Smi -> compile time subtype check (only if dst class is not parameterized).
551 // - Class equality (only if class is not parameterized).
552 // Inputs:
553 // - RAX: object.
554 // - RDX: instantiator type arguments or raw_null.
555 // - RCX: instantiator or raw_null.
556 // Destroys RCX and RDX.
557 // Returns:
558 // - true or false in RAX.
559 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
560 intptr_t token_pos,
561 intptr_t try_index,
562 const AbstractType& type,
563 bool negate_result) {
564 ASSERT(type.IsFinalized() && !type.IsMalformed());
565
566 const Immediate raw_null =
567 Immediate(reinterpret_cast<intptr_t>(Object::null()));
568 Label is_instance, is_not_instance;
569 __ pushq(RCX); // Store instantiator on stack.
570 __ pushq(RDX); // Store instantiator type arguments.
571 // If type is instantiated and non-parameterized, we can inline code
572 // checking whether the tested instance is a Smi.
573 if (type.IsInstantiated()) {
574 // A null object is only an instance of Object and Dynamic, which has
575 // already been checked above (if the type is instantiated). So we can
576 // return false here if the instance is null (and if the type is
577 // instantiated).
578 // We can only inline this null check if the type is instantiated at compile
579 // time, since an uninstantiated type at compile time could be Object or
580 // Dynamic at run time.
581 __ cmpq(RAX, raw_null);
582 __ j(EQUAL, &is_not_instance);
583 }
584
585 // Generate inline instanceof test.
586 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
587 test_cache = GenerateInlineInstanceof(cid, token_pos, type,
588 &is_instance, &is_not_instance);
589
590 // Generate runtime call.
591 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
592 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
593 __ PushObject(Object::ZoneHandle()); // Make room for the result.
594 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
595 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
596 __ pushq(RAX); // Push the instance.
597 __ PushObject(type); // Push the type.
598 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
599 __ pushq(RDX); // Instantiator type arguments.
600 __ LoadObject(RAX, test_cache);
601 __ pushq(RAX);
602 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry);
603 // Pop the two parameters supplied to the runtime entry. The result of the
604 // instanceof runtime call will be left as the result of the operation.
605 __ Drop(7);
606 Label done;
607 if (negate_result) {
608 __ popq(RDX);
609 __ LoadObject(RAX, bool_true());
610 __ cmpq(RDX, RAX);
611 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
612 __ LoadObject(RAX, bool_false());
613 } else {
614 __ popq(RAX);
615 }
616 __ jmp(&done, Assembler::kNearJump);
617
618 __ Bind(&is_not_instance);
619 __ LoadObject(RAX, negate_result ? bool_true() : bool_false());
620 __ jmp(&done, Assembler::kNearJump);
621
622 __ Bind(&is_instance);
623 __ LoadObject(RAX, negate_result ? bool_false() : bool_true());
624 __ Bind(&done);
625 __ popq(RDX); // Remove pushed instantiator type arguments.
626 __ popq(RCX); // Remove pushed instantiator.
627 }
628
629
630 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { 596 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
631 LocationSummary* locs = instr->locs(); 597 LocationSummary* locs = instr->locs();
632 ASSERT(locs != NULL); 598 ASSERT(locs != NULL);
633 599
634 frame_register_allocator()->AllocateRegisters(instr); 600 frame_register_allocator()->AllocateRegisters(instr);
635 601
636 // TODO(vegorov): adjust assertion when we start removing comparison from the 602 // TODO(vegorov): adjust assertion when we start removing comparison from the
637 // graph when it is merged with a branch. 603 // graph when it is merged with a branch.
638 ASSERT(locs->is_call() || 604 ASSERT(locs->is_call() ||
639 (instr->IsBranch() && instr->AsBranch()->is_fused_with_comparison()) || 605 (instr->IsBranch() && instr->AsBranch()->is_fused_with_comparison()) ||
640 (locs->input_count() == instr->InputCount())); 606 (locs->input_count() == instr->InputCount()));
641 } 607 }
642 608
643 609
644 // Copied from CodeGenerator::CopyParameters (CodeGenerator will be deprecated).
645 void FlowGraphCompiler::CopyParameters() { 610 void FlowGraphCompiler::CopyParameters() {
646 const Function& function = parsed_function().function(); 611 const Function& function = parsed_function().function();
647 const bool is_native_instance_closure = 612 const bool is_native_instance_closure =
648 function.is_native() && function.IsImplicitInstanceClosureFunction(); 613 function.is_native() && function.IsImplicitInstanceClosureFunction();
649 LocalScope* scope = parsed_function().node_sequence()->scope(); 614 LocalScope* scope = parsed_function().node_sequence()->scope();
650 const int num_fixed_params = function.num_fixed_parameters(); 615 const int num_fixed_params = function.num_fixed_parameters();
651 const int num_opt_params = function.num_optional_parameters(); 616 const int num_opt_params = function.num_optional_parameters();
652 int implicit_this_param_pos = is_native_instance_closure ? -1 : 0; 617 int implicit_this_param_pos = is_native_instance_closure ? -1 : 0;
653 ASSERT(parsed_function().first_parameter_index() == 618 ASSERT(parsed_function().first_parameter_index() ==
654 ParsedFunction::kFirstLocalSlotIndex + implicit_this_param_pos); 619 ParsedFunction::kFirstLocalSlotIndex + implicit_this_param_pos);
(...skipping 14 matching lines...) Expand all
669 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); 634 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
670 // Check that num_pos_args >= num_fixed_params. 635 // Check that num_pos_args >= num_fixed_params.
671 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params))); 636 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params)));
672 __ j(LESS, &wrong_num_arguments); 637 __ j(LESS, &wrong_num_arguments);
673 638
674 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. 639 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8.
675 // Let RBX point to the last passed positional argument, i.e. to 640 // Let RBX point to the last passed positional argument, i.e. to
676 // fp[1 + num_args - (num_pos_args - 1)]. 641 // fp[1 + num_args - (num_pos_args - 1)].
677 __ subq(RBX, RCX); 642 __ subq(RBX, RCX);
678 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize)); 643 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize));
644
679 // Let RDI point to the last copied positional argument, i.e. to 645 // Let RDI point to the last copied positional argument, i.e. to
680 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. 646 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)].
681 const int index = 647 const int index =
682 ParsedFunction::kFirstLocalSlotIndex + 1 + implicit_this_param_pos; 648 ParsedFunction::kFirstLocalSlotIndex + 1 + implicit_this_param_pos;
683 // First copy captured receiver if function is an implicit native closure. 649 // First copy captured receiver if function is an implicit native closure.
684 if (is_native_instance_closure) { 650 if (is_native_instance_closure) {
685 __ movq(RAX, FieldAddress(CTX, Context::variable_offset(0))); 651 __ movq(RAX, FieldAddress(CTX, Context::variable_offset(0)));
686 __ movq(Address(RBP, (index * kWordSize)), RAX); 652 __ movq(Address(RBP, (index * kWordSize)), RAX);
687 } 653 }
688 __ SmiUntag(RCX); 654 __ SmiUntag(RCX);
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 __ SmiUntag(RAX); 864 __ SmiUntag(RAX);
899 __ cvtsi2sd(XMM1, RAX); 865 __ cvtsi2sd(XMM1, RAX);
900 __ jmp(&double_op); 866 __ jmp(&double_op);
901 __ Bind(&call_method); 867 __ Bind(&call_method);
902 } 868 }
903 869
904 870
905 void FlowGraphCompiler::CompileGraph() { 871 void FlowGraphCompiler::CompileGraph() {
906 InitCompiler(); 872 InitCompiler();
907 if (TryIntrinsify()) { 873 if (TryIntrinsify()) {
908 // Make it patchable: code must have a minimum code size, nop(2) increases 874 // Although this intrinsified code will never be patched, it must satisfy
909 // the minimum code size appropriately. 875 // CodePatcher::CodeIsPatchable, which verifies that this code has a minimum
876 // code size, and nop(2) increases the minimum code size appropriately.
910 __ nop(2); 877 __ nop(2);
911 __ int3(); 878 __ int3();
912 __ jmp(&StubCode::FixCallersTargetLabel()); 879 __ jmp(&StubCode::FixCallersTargetLabel());
913 return; 880 return;
914 } 881 }
915 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. 882 // Specialized version of entry code from CodeGenerator::GenerateEntryCode.
916 const Function& function = parsed_function().function(); 883 const Function& function = parsed_function().function();
917 884
918 const int parameter_count = function.num_fixed_parameters(); 885 const int parameter_count = function.num_fixed_parameters();
919 const int num_copied_params = parsed_function().copied_parameter_count(); 886 const int num_copied_params = parsed_function().copied_parameter_count();
920 const int local_count = parsed_function().stack_local_count(); 887 const int local_count = parsed_function().stack_local_count();
921 AssemblerMacros::EnterDartFrame(assembler(), (StackSize() * kWordSize)); 888 AssemblerMacros::EnterDartFrame(assembler(), (StackSize() * kWordSize));
922
923 // We check the number of passed arguments when we have to copy them due to 889 // We check the number of passed arguments when we have to copy them due to
924 // the presence of optional named parameters. 890 // the presence of optional named parameters.
925 // No such checking code is generated if only fixed parameters are declared, 891 // No such checking code is generated if only fixed parameters are declared,
926 // unless we are debug mode or unless we are compiling a closure. 892 // unless we are debug mode or unless we are compiling a closure.
927 if (num_copied_params == 0) { 893 if (num_copied_params == 0) {
928 #ifdef DEBUG 894 #ifdef DEBUG
929 const bool check_arguments = true; 895 const bool check_arguments = true;
930 #else 896 #else
931 const bool check_arguments = function.IsClosureFunction(); 897 const bool check_arguments = function.IsClosureFunction();
932 #endif 898 #endif
(...skipping 10 matching lines...) Expand all
943 CatchClauseNode::kInvalidTryIndex, 909 CatchClauseNode::kInvalidTryIndex,
944 kClosureArgumentMismatchRuntimeEntry); 910 kClosureArgumentMismatchRuntimeEntry);
945 } else { 911 } else {
946 __ Stop("Wrong number of arguments"); 912 __ Stop("Wrong number of arguments");
947 } 913 }
948 __ Bind(&argc_in_range); 914 __ Bind(&argc_in_range);
949 } 915 }
950 } else { 916 } else {
951 CopyParameters(); 917 CopyParameters();
952 } 918 }
953 919 // Initialize (non-argument) stack allocated locals to null.
954 // Initialize locals to null.
955 if (local_count > 0) { 920 if (local_count > 0) {
956 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); 921 const Immediate raw_null =
922 Immediate(reinterpret_cast<intptr_t>(Object::null()));
923 __ movq(RAX, raw_null);
957 const int base = parsed_function().first_stack_local_index(); 924 const int base = parsed_function().first_stack_local_index();
958 for (int i = 0; i < local_count; ++i) { 925 for (int i = 0; i < local_count; ++i) {
959 // Subtract index i (locals lie at lower addresses than RBP). 926 // Subtract index i (locals lie at lower addresses than RBP).
960 __ movq(Address(RBP, (base - i) * kWordSize), RAX); 927 __ movq(Address(RBP, (base - i) * kWordSize), RAX);
961 } 928 }
962 } 929 }
963 930
964 // Generate stack overflow check. 931 // Generate stack overflow check.
965 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address())); 932 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address()));
966 __ cmpq(RSP, Address(RDI, 0)); 933 __ cmpq(RSP, Address(RDI, 0));
(...skipping 23 matching lines...) Expand all
990 // at entry point. 957 // at entry point.
991 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, 958 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode,
992 assembler()->CodeSize(), 959 assembler()->CodeSize(),
993 AstNode::kNoId, 960 AstNode::kNoId,
994 0, 961 0,
995 -1); 962 -1);
996 __ jmp(&StubCode::FixCallersTargetLabel()); 963 __ jmp(&StubCode::FixCallersTargetLabel());
997 } 964 }
998 965
999 966
1000 // Infrastructure copied from class CodeGenerator.
1001 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, 967 void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
1002 intptr_t try_index, 968 intptr_t try_index,
1003 const ExternalLabel* label, 969 const ExternalLabel* label,
1004 PcDescriptors::Kind kind) { 970 PcDescriptors::Kind kind) {
1005 ASSERT(frame_register_allocator()->IsSpilled()); 971 ASSERT(frame_register_allocator()->IsSpilled());
1006 __ call(label); 972 __ call(label);
1007 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index); 973 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index);
1008 } 974 }
1009 975
1010 976
1011 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, 977 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid,
1012 intptr_t token_pos, 978 intptr_t token_pos,
1013 intptr_t try_index, 979 intptr_t try_index,
1014 const RuntimeEntry& entry) { 980 const RuntimeEntry& entry) {
1015 ASSERT(frame_register_allocator()->IsSpilled()); 981 ASSERT(frame_register_allocator()->IsSpilled());
1016 __ CallRuntime(entry); 982 __ CallRuntime(entry);
1017 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index); 983 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index);
1018 } 984 }
1019 985
1020 986
987 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
988 const ICData& ic_data,
989 const Array& arguments_descriptor,
990 intptr_t argument_count) {
991 __ LoadObject(RBX, ic_data);
992 __ LoadObject(R10, arguments_descriptor);
993
994 __ call(target_label);
995 const intptr_t descr_offset = assembler()->CodeSize();
996 __ Drop(argument_count);
997 return descr_offset;
998 }
999
1000
1001 intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function,
1002 const Array& arguments_descriptor,
1003 intptr_t argument_count) {
1004 __ LoadObject(RBX, function);
1005 __ LoadObject(R10, arguments_descriptor);
1006 __ call(&StubCode::CallStaticFunctionLabel());
1007 const intptr_t descr_offset = assembler()->CodeSize();
1008 __ Drop(argument_count);
1009 return descr_offset;
1010 }
1011
1012
1021 // Checks class id of instance against all 'class_ids'. Jump to 'deopt' label 1013 // Checks class id of instance against all 'class_ids'. Jump to 'deopt' label
1022 // if no match or instance is Smi. 1014 // if no match or instance is Smi.
1023 void FlowGraphCompiler::EmitClassChecksNoSmi(const ICData& ic_data, 1015 void FlowGraphCompiler::EmitClassChecksNoSmi(const ICData& ic_data,
1024 Register instance_reg, 1016 Register instance_reg,
1025 Register temp_reg, 1017 Register temp_reg,
1026 Label* deopt) { 1018 Label* deopt) {
1027 Label ok; 1019 Label ok;
1028 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi); 1020 ASSERT(ic_data.GetReceiverClassIdAt(0) != kSmi);
1029 __ testq(instance_reg, Immediate(kSmiTagMask)); 1021 __ testq(instance_reg, Immediate(kSmiTagMask));
1030 __ j(ZERO, deopt); 1022 __ j(ZERO, deopt);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 __ cvtsi2sd(result, temp); 1057 __ cvtsi2sd(result, temp);
1066 __ Bind(&done); 1058 __ Bind(&done);
1067 } 1059 }
1068 1060
1069 1061
1070 #undef __ 1062 #undef __
1071 1063
1072 } // namespace dart 1064 } // namespace dart
1073 1065
1074 #endif // defined TARGET_ARCH_X64 1066 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698