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

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

Issue 10545186: Improve equality operation (inline, direct calls). (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
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/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 // We should never return here. 192 // We should never return here.
193 __ int3(); 193 __ int3();
194 194
195 __ Bind(&done); 195 __ Bind(&done);
196 ASSERT(obj == result); 196 ASSERT(obj == result);
197 } 197 }
198 198
199 199
200 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { 200 LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
201 const intptr_t kNumInputs = 2; 201 const intptr_t kNumInputs = 2;
202 if (operands_class_id() == kSmi) { 202 if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) {
203 const intptr_t kNumTemps = 1; 203 const intptr_t kNumTemps = 1;
204 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); 204 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
205 locs->set_in(0, Location::RequiresRegister()); 205 locs->set_in(0, Location::RequiresRegister());
206 locs->set_in(1, Location::RequiresRegister()); 206 locs->set_in(1, Location::RequiresRegister());
207 locs->set_temp(0, Location::RequiresRegister()); 207 locs->set_temp(0, Location::RequiresRegister());
208 if (!is_fused_with_branch()) { 208 if (!is_fused_with_branch()) {
209 locs->set_out(Location::RequiresRegister()); 209 locs->set_out(Location::RequiresRegister());
210 } 210 }
211 return locs; 211 return locs;
212 } 212 }
213 if (operands_class_id() == kObject) { 213 if (NumTargets() > 0) {
214 const intptr_t kNumTemps = 0; 214 const intptr_t kNumTemps = 1;
215 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); 215 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
216 locs->set_in(0, Location::RequiresRegister()); 216 locs->set_in(0, Location::RequiresRegister());
217 locs->set_in(1, Location::RequiresRegister()); 217 locs->set_in(1, Location::RequiresRegister());
218 locs->set_temp(0, Location::RequiresRegister());
218 if (!is_fused_with_branch()) { 219 if (!is_fused_with_branch()) {
219 locs->set_out(Location::RegisterLocation(RAX)); 220 locs->set_out(Location::RegisterLocation(RAX));
220 } 221 }
221 return locs; 222 return locs;
222 } 223 }
223 UNREACHABLE(); 224 const intptr_t kNumTemps = 0;
224 return NULL; 225 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps);
226 locs->set_in(0, Location::RequiresRegister());
227 locs->set_in(1, Location::RequiresRegister());
228 if (!is_fused_with_branch()) {
229 locs->set_out(Location::RegisterLocation(RAX));
230 }
231 return locs;
225 } 232 }
226 233
227 234
228 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler, 235 static void EmitSmiEqualityCompare(FlowGraphCompiler* compiler,
229 EqualityCompareComp* comp) { 236 EqualityCompareComp* comp) {
230 Register left = comp->locs()->in(0).reg(); 237 Register left = comp->locs()->in(0).reg();
231 Register right = comp->locs()->in(1).reg(); 238 Register right = comp->locs()->in(1).reg();
232 Register temp = comp->locs()->temp(0).reg(); 239 Register temp = comp->locs()->temp(0).reg();
233 Label* deopt = compiler->AddDeoptStub(comp->cid(), 240 Label* deopt = compiler->AddDeoptStub(comp->cid(),
234 comp->token_index(), 241 comp->token_index(),
(...skipping 15 matching lines...) Expand all
250 __ j(EQUAL, &load_true, Assembler::kNearJump); 257 __ j(EQUAL, &load_true, Assembler::kNearJump);
251 __ LoadObject(result, compiler->bool_false()); 258 __ LoadObject(result, compiler->bool_false());
252 __ jmp(&done, Assembler::kNearJump); 259 __ jmp(&done, Assembler::kNearJump);
253 __ Bind(&load_true); 260 __ Bind(&load_true);
254 __ LoadObject(result, compiler->bool_true()); 261 __ LoadObject(result, compiler->bool_true());
255 __ Bind(&done); 262 __ Bind(&done);
256 } 263 }
257 } 264 }
258 265
259 266
267 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
268 EqualityCompareComp* comp) {
269 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
270 comp->cid(),
271 comp->token_index(),
272 comp->try_index());
273 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
274 const int kNumberOfArguments = 2;
275 const Array& kNoArgumentNames = Array::Handle();
276 const int kNumArgumentsChecked = 2;
277
278 compiler->GenerateInstanceCall(comp->cid(),
279 comp->token_index(),
280 comp->try_index(),
281 operator_name,
282 kNumberOfArguments,
283 kNoArgumentNames,
284 kNumArgumentsChecked);
285 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == RAX));
286
287 if (comp->is_fused_with_branch()) {
288 __ CompareObject(RAX, compiler->bool_true());
289 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
290 }
291 }
292
293
294 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
295 EqualityCompareComp* comp,
296 Register left,
297 Register right) {
298 ASSERT(comp->NumTargets() > 0);
299 Label* deopt = compiler->AddDeoptStub(comp->cid(),
300 comp->token_index(),
301 comp->try_index(),
302 kDeoptEquality);
303 __ testq(left, Immediate(kSmiTagMask));
304 Register temp = comp->locs()->temp(0).reg();
305 if (comp->ClassIdAt(0) == kSmi) {
306 Label done, load_class_id;
307 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
308 __ movq(temp, Immediate(kSmi));
309 __ jmp(&done, Assembler::kNearJump);
310 __ Bind(&load_class_id);
311 __ LoadClassId(temp, left);
312 __ Bind(&done);
313 } else {
314 __ j(ZERO, deopt); // Smi deopts.
315 __ LoadClassId(temp, left);
316 }
317 Label done;
318 for (intptr_t i = 0; i < comp->NumTargets(); i++) {
319 ASSERT(comp->ClassIdAt(i) != kSmi || i == 0);
regis 2012/06/14 23:59:41 ditto
srdjan 2012/06/15 00:27:19 Done.
320 Label next_test;
321 __ cmpq(temp, Immediate(comp->ClassIdAt(i)));
322 __ j(NOT_EQUAL, &next_test, Assembler::kNearJump);
323 const Function& target = *comp->TargetAt(i);
324 ObjectStore* object_store = Isolate::Current()->object_store();
325 if (target.owner() == object_store->object_class()) {
326 // Object.== is same as ===.
327 __ Drop(2);
328 __ cmpq(left, right);
329 if (comp->is_fused_with_branch()) {
330 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
331 } else {
332 // This case should be rare.
333 Register result = comp->locs()->out().reg();
334 Label load_true;
335 __ j(EQUAL, &load_true, Assembler::kNearJump);
336 __ LoadObject(result, compiler->bool_false());
337 __ jmp(&done);
338 __ Bind(&load_true);
339 __ LoadObject(result, compiler->bool_true());
340 }
341 } else {
342 const int kNumberOfArguments = 2;
343 const Array& kNoArgumentNames = Array::Handle();
344 compiler->GenerateStaticCall(comp->cid(),
345 comp->token_index(),
346 comp->try_index(),
347 target,
348 kNumberOfArguments,
349 kNoArgumentNames);
350 ASSERT(comp->is_fused_with_branch() ||
351 (comp->locs()->out().reg() == RAX));
352 if (comp->is_fused_with_branch()) {
353 __ CompareObject(RAX, compiler->bool_true());
354 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
355 }
356 }
357 __ jmp(&done);
358 __ Bind(&next_test);
359 }
360 // Fall through leads to deoptimization
361 __ jmp(deopt);
362 __ Bind(&done);
363 }
364
365
366
367 // First test if receiver is NULL, in which case === is applied.
368 // If type feedback was provided (lists of <class-id, target>), do a
369 // type by type check (either === or static call to the operator.
260 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, 370 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
261 EqualityCompareComp* comp) { 371 EqualityCompareComp* comp) {
262 const Immediate raw_null = 372 const Immediate raw_null =
263 Immediate(reinterpret_cast<intptr_t>(Object::null())); 373 Immediate(reinterpret_cast<intptr_t>(Object::null()));
264 Register left = comp->locs()->in(0).reg(); 374 Register left = comp->locs()->in(0).reg();
265 Register right = comp->locs()->in(1).reg(); 375 Register right = comp->locs()->in(1).reg();
266 Label done, non_null_compare; 376 Label done, non_null_compare;
267 __ cmpq(left, raw_null); 377 __ cmpq(left, raw_null);
268 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); 378 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
269 // Comparison with NULL is "===". 379 // Comparison with NULL is "===".
270 __ cmpq(left, right); 380 __ cmpq(left, right);
271 if (comp->is_fused_with_branch()) { 381 if (comp->is_fused_with_branch()) {
272 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); 382 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
273 } else { 383 } else {
274 Register result = comp->locs()->out().reg(); 384 Register result = comp->locs()->out().reg();
275 Label load_true; 385 Label load_true;
276 __ j(EQUAL, &load_true, Assembler::kNearJump); 386 __ j(EQUAL, &load_true, Assembler::kNearJump);
277 __ LoadObject(result, compiler->bool_false()); 387 __ LoadObject(result, compiler->bool_false());
278 __ jmp(&done, Assembler::kNearJump); 388 __ jmp(&done);
279 __ Bind(&load_true); 389 __ Bind(&load_true);
280 __ LoadObject(result, compiler->bool_true()); 390 __ LoadObject(result, compiler->bool_true());
281 } 391 }
282 __ jmp(&done); 392 __ jmp(&done);
283 393
284 __ Bind(&non_null_compare); 394 __ Bind(&non_null_compare); // Receiver is not null.
285 __ pushq(left); 395 __ pushq(left);
286 __ pushq(right); 396 __ pushq(right);
287 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, 397 if (comp->NumTargets() > 0) {
288 comp->cid(), 398 EmitEqualityAsPolymorphicCall(compiler, comp, left, right);
289 comp->token_index(), 399 } else {
290 comp->try_index()); 400 EmitEqualityAsInstanceCall(compiler, comp);
291 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
292 const int kNumberOfArguments = 2;
293 const Array& kNoArgumentNames = Array::Handle();
294 const int kNumArgumentsChecked = 2;
295
296 compiler->GenerateInstanceCall(comp->cid(),
297 comp->token_index(),
298 comp->try_index(),
299 operator_name,
300 kNumberOfArguments,
301 kNoArgumentNames,
302 kNumArgumentsChecked);
303 ASSERT(comp->is_fused_with_branch() || (comp->locs()->out().reg() == RAX));
304
305 if (comp->is_fused_with_branch()) {
306 __ CompareObject(RAX, compiler->bool_true());
307 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL);
308 } 401 }
309 __ Bind(&done); 402 __ Bind(&done);
310 } 403 }
311 404
312 405
313 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { 406 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
314 if (operands_class_id() == kSmi) { 407 if ((NumTargets() == 1) && (ClassIdAt(0) == kSmi)) {
315 EmitSmiEqualityCompare(compiler, this); 408 EmitSmiEqualityCompare(compiler, this);
316 return; 409 return;
317 } 410 }
318 if (operands_class_id() == kObject) { 411 EmitGenericEqualityCompare(compiler, this);
319 EmitGenericEqualityCompare(compiler, this);
320 return;
321 }
322 UNREACHABLE();
323 } 412 }
324 413
325 414
326 LocationSummary* RelationalOpComp::MakeLocationSummary() const { 415 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
327 if (operands_class_id() == kSmi || operands_class_id() == kDouble) { 416 if (operands_class_id() == kSmi || operands_class_id() == kDouble) {
328 const intptr_t kNumInputs = 2; 417 const intptr_t kNumInputs = 2;
329 const intptr_t kNumTemps = 1; 418 const intptr_t kNumTemps = 1;
330 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); 419 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
331 summary->set_in(0, Location::RequiresRegister()); 420 summary->set_in(0, Location::RequiresRegister());
332 summary->set_in(1, Location::RequiresRegister()); 421 summary->set_in(1, Location::RequiresRegister());
(...skipping 1313 matching lines...) Expand 10 before | Expand all | Expand 10 after
1646 instance_call()->argument_names()); 1735 instance_call()->argument_names());
1647 } 1736 }
1648 __ Bind(&done); 1737 __ Bind(&done);
1649 } 1738 }
1650 1739
1651 } // namespace dart 1740 } // namespace dart
1652 1741
1653 #undef __ 1742 #undef __
1654 1743
1655 #endif // defined TARGET_ARCH_X64 1744 #endif // defined TARGET_ARCH_X64
OLDNEW
« runtime/vm/intermediate_language_ia32.cc ('K') | « runtime/vm/intermediate_language_ia32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698