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

Side by Side Diff: src/x64/lithium-codegen-x64.cc

Issue 6597029: [Isolates] Merge r 6300:6500 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: Created 9 years, 10 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 | « src/x64/lithium-codegen-x64.h ('k') | src/x64/lithium-gap-resolver-x64.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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 va_start(arguments, format); 66 va_start(arguments, format);
67 OS::VPrint(format, arguments); 67 OS::VPrint(format, arguments);
68 va_end(arguments); 68 va_end(arguments);
69 PrintF("\n"); 69 PrintF("\n");
70 } 70 }
71 status_ = ABORTED; 71 status_ = ABORTED;
72 } 72 }
73 73
74 74
75 void LCodeGen::Comment(const char* format, ...) { 75 void LCodeGen::Comment(const char* format, ...) {
76 Abort("Unimplemented: %s", "Comment"); 76 if (!FLAG_code_comments) return;
77 char buffer[4 * KB];
78 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
79 va_list arguments;
80 va_start(arguments, format);
81 builder.AddFormattedList(format, arguments);
82 va_end(arguments);
83
84 // Copy the string before recording it in the assembler to avoid
85 // issues when the stack allocated buffer goes out of scope.
86 int length = builder.position();
87 Vector<char> copy = Vector<char>::New(length + 1);
88 memcpy(copy.start(), builder.Finalize(), copy.length());
89 masm()->RecordComment(copy.start());
77 } 90 }
78 91
79 92
80 bool LCodeGen::GeneratePrologue() { 93 bool LCodeGen::GeneratePrologue() {
81 Abort("Unimplemented: %s", "GeneratePrologue"); 94 ASSERT(is_generating());
95
96 #ifdef DEBUG
97 if (strlen(FLAG_stop_at) > 0 &&
98 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
99 __ int3();
100 }
101 #endif
102
103 __ push(rbp); // Caller's frame pointer.
104 __ movq(rbp, rsp);
105 __ push(rsi); // Callee's context.
106 __ push(rdi); // Callee's JS function.
107
108 // Reserve space for the stack slots needed by the code.
109 int slots = StackSlotCount();
110 if (slots > 0) {
111 if (FLAG_debug_code) {
112 __ movl(rax, Immediate(slots));
113 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE);
114 Label loop;
115 __ bind(&loop);
116 __ push(kScratchRegister);
117 __ decl(rax);
118 __ j(not_zero, &loop);
119 } else {
120 __ subq(rsp, Immediate(slots * kPointerSize));
121 #ifdef _MSC_VER
122 // On windows, you may not access the stack more than one page below
123 // the most recently mapped page. To make the allocated area randomly
124 // accessible, we write to each page in turn (the value is irrelevant).
125 const int kPageSize = 4 * KB;
126 for (int offset = slots * kPointerSize - kPageSize;
127 offset > 0;
128 offset -= kPageSize) {
129 __ movq(Operand(rsp, offset), rax);
130 }
131 #endif
132 }
133 }
134
135 // Trace the call.
136 if (FLAG_trace) {
137 __ CallRuntime(Runtime::kTraceEnter, 0);
138 }
82 return !is_aborted(); 139 return !is_aborted();
83 } 140 }
84 141
85 142
86 bool LCodeGen::GenerateBody() { 143 bool LCodeGen::GenerateBody() {
87 ASSERT(is_generating()); 144 ASSERT(is_generating());
88 bool emit_instructions = true; 145 bool emit_instructions = true;
89 for (current_instruction_ = 0; 146 for (current_instruction_ = 0;
90 !is_aborted() && current_instruction_ < instructions_->length(); 147 !is_aborted() && current_instruction_ < instructions_->length();
91 current_instruction_++) { 148 current_instruction_++) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 } 180 }
124 181
125 // Deferred code is the last part of the instruction sequence. Mark 182 // Deferred code is the last part of the instruction sequence. Mark
126 // the generated code as done unless we bailed out. 183 // the generated code as done unless we bailed out.
127 if (!is_aborted()) status_ = DONE; 184 if (!is_aborted()) status_ = DONE;
128 return !is_aborted(); 185 return !is_aborted();
129 } 186 }
130 187
131 188
132 bool LCodeGen::GenerateSafepointTable() { 189 bool LCodeGen::GenerateSafepointTable() {
133 Abort("Unimplemented: %s", "GeneratePrologue"); 190 ASSERT(is_done());
191 safepoints_.Emit(masm(), StackSlotCount());
134 return !is_aborted(); 192 return !is_aborted();
135 } 193 }
136 194
137 195
138 Register LCodeGen::ToRegister(int index) const { 196 Register LCodeGen::ToRegister(int index) const {
139 return Register::FromAllocationIndex(index); 197 return Register::FromAllocationIndex(index);
140 } 198 }
141 199
142 200
143 XMMRegister LCodeGen::ToDoubleRegister(int index) const { 201 XMMRegister LCodeGen::ToDoubleRegister(int index) const {
144 return XMMRegister::FromAllocationIndex(index); 202 return XMMRegister::FromAllocationIndex(index);
145 } 203 }
146 204
147 205
148 Register LCodeGen::ToRegister(LOperand* op) const { 206 Register LCodeGen::ToRegister(LOperand* op) const {
149 ASSERT(op->IsRegister()); 207 ASSERT(op->IsRegister());
150 return ToRegister(op->index()); 208 return ToRegister(op->index());
151 } 209 }
152 210
153 211
154 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { 212 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
155 ASSERT(op->IsDoubleRegister()); 213 ASSERT(op->IsDoubleRegister());
156 return ToDoubleRegister(op->index()); 214 return ToDoubleRegister(op->index());
157 } 215 }
158 216
159 217
218 bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
219 return op->IsConstantOperand() &&
220 chunk_->LookupLiteralRepresentation(op).IsInteger32();
221 }
222
223
224 bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
225 return op->IsConstantOperand() &&
226 chunk_->LookupLiteralRepresentation(op).IsTagged();
227 }
228
229
160 int LCodeGen::ToInteger32(LConstantOperand* op) const { 230 int LCodeGen::ToInteger32(LConstantOperand* op) const {
161 Handle<Object> value = chunk_->LookupLiteral(op); 231 Handle<Object> value = chunk_->LookupLiteral(op);
162 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); 232 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
163 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == 233 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
164 value->Number()); 234 value->Number());
165 return static_cast<int32_t>(value->Number()); 235 return static_cast<int32_t>(value->Number());
166 } 236 }
167 237
168 238
239 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
240 Handle<Object> literal = chunk_->LookupLiteral(op);
241 Representation r = chunk_->LookupLiteralRepresentation(op);
242 ASSERT(r.IsTagged());
243 return literal;
244 }
245
246
169 Operand LCodeGen::ToOperand(LOperand* op) const { 247 Operand LCodeGen::ToOperand(LOperand* op) const {
170 // Does not handle registers. In X64 assembler, plain registers are not 248 // Does not handle registers. In X64 assembler, plain registers are not
171 // representable as an Operand. 249 // representable as an Operand.
172 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); 250 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
173 int index = op->index(); 251 int index = op->index();
174 if (index >= 0) { 252 if (index >= 0) {
175 // Local or spill slot. Skip the frame pointer, function, and 253 // Local or spill slot. Skip the frame pointer, function, and
176 // context in the fixed part of the frame. 254 // context in the fixed part of the frame.
177 return Operand(rbp, -(index + 3) * kPointerSize); 255 return Operand(rbp, -(index + 3) * kPointerSize);
178 } else { 256 } else {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 translation->StoreLiteral(src_index); 335 translation->StoreLiteral(src_index);
258 } else { 336 } else {
259 UNREACHABLE(); 337 UNREACHABLE();
260 } 338 }
261 } 339 }
262 340
263 341
264 void LCodeGen::CallCode(Handle<Code> code, 342 void LCodeGen::CallCode(Handle<Code> code,
265 RelocInfo::Mode mode, 343 RelocInfo::Mode mode,
266 LInstruction* instr) { 344 LInstruction* instr) {
267 Abort("Unimplemented: %s", "CallCode"); 345 if (instr != NULL) {
346 LPointerMap* pointers = instr->pointer_map();
347 RecordPosition(pointers->position());
348 __ call(code, mode);
349 RegisterLazyDeoptimization(instr);
350 } else {
351 LPointerMap no_pointers(0);
352 RecordPosition(no_pointers.position());
353 __ call(code, mode);
354 RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
355 }
356
357 // Signal that we don't inline smi code before these stubs in the
358 // optimizing code generator.
359 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
360 code->kind() == Code::COMPARE_IC) {
361 __ nop();
362 }
268 } 363 }
269 364
270 365
271 void LCodeGen::CallRuntime(const Runtime::Function* function, 366 void LCodeGen::CallRuntime(const Runtime::Function* function,
272 int num_arguments, 367 int num_arguments,
273 LInstruction* instr) { 368 LInstruction* instr) {
274 Abort("Unimplemented: %s", "CallRuntime"); 369 Abort("Unimplemented: %s", "CallRuntime");
275 } 370 }
276 371
277 372
278 void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { 373 void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
279 // Create the environment to bailout to. If the call has side effects 374 // Create the environment to bailout to. If the call has side effects
280 // execution has to continue after the call otherwise execution can continue 375 // execution has to continue after the call otherwise execution can continue
281 // from a previous bailout point repeating the call. 376 // from a previous bailout point repeating the call.
282 LEnvironment* deoptimization_environment; 377 LEnvironment* deoptimization_environment;
283 if (instr->HasDeoptimizationEnvironment()) { 378 if (instr->HasDeoptimizationEnvironment()) {
284 deoptimization_environment = instr->deoptimization_environment(); 379 deoptimization_environment = instr->deoptimization_environment();
285 } else { 380 } else {
286 deoptimization_environment = instr->environment(); 381 deoptimization_environment = instr->environment();
287 } 382 }
288 383
289 RegisterEnvironmentForDeoptimization(deoptimization_environment); 384 RegisterEnvironmentForDeoptimization(deoptimization_environment);
290 RecordSafepoint(instr->pointer_map(), 385 RecordSafepoint(instr->pointer_map(),
291 deoptimization_environment->deoptimization_index()); 386 deoptimization_environment->deoptimization_index());
292 } 387 }
293 388
294 389
295 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { 390 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
296 Abort("Unimplemented: %s", "RegisterEnvironmentForDeoptimization"); 391 if (!environment->HasBeenRegistered()) {
392 // Physical stack frame layout:
393 // -x ............. -4 0 ..................................... y
394 // [incoming arguments] [spill slots] [pushed outgoing arguments]
395
396 // Layout of the environment:
397 // 0 ..................................................... size-1
398 // [parameters] [locals] [expression stack including arguments]
399
400 // Layout of the translation:
401 // 0 ........................................................ size - 1 + 4
402 // [expression stack including arguments] [locals] [4 words] [parameters]
403 // |>------------ translation_size ------------<|
404
405 int frame_count = 0;
406 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
407 ++frame_count;
408 }
409 Translation translation(&translations_, frame_count);
410 WriteTranslation(environment, &translation);
411 int deoptimization_index = deoptimizations_.length();
412 environment->Register(deoptimization_index, translation.index());
413 deoptimizations_.Add(environment);
414 }
297 } 415 }
298 416
299 417
300 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { 418 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
301 Abort("Unimplemented: %s", "Deoptimiz"); 419 RegisterEnvironmentForDeoptimization(environment);
420 ASSERT(environment->HasBeenRegistered());
421 int id = environment->deoptimization_index();
422 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
423 ASSERT(entry != NULL);
424 if (entry == NULL) {
425 Abort("bailout was not prepared");
426 return;
427 }
428
429 if (cc == no_condition) {
430 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
431 } else {
432 NearLabel done;
433 __ j(NegateCondition(cc), &done);
434 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
435 __ bind(&done);
436 }
302 } 437 }
303 438
304 439
305 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { 440 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
306 int length = deoptimizations_.length(); 441 int length = deoptimizations_.length();
307 if (length == 0) return; 442 if (length == 0) return;
308 ASSERT(FLAG_deopt); 443 ASSERT(FLAG_deopt);
309 Handle<DeoptimizationInputData> data = 444 Handle<DeoptimizationInputData> data =
310 FACTORY->NewDeoptimizationInputData(length, TENURED); 445 FACTORY->NewDeoptimizationInputData(length, TENURED);
311 446
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 } else { 541 } else {
407 Comment(";;; B%d", label->block_id()); 542 Comment(";;; B%d", label->block_id());
408 } 543 }
409 __ bind(label->label()); 544 __ bind(label->label());
410 current_block_ = label->block_id(); 545 current_block_ = label->block_id();
411 LCodeGen::DoGap(label); 546 LCodeGen::DoGap(label);
412 } 547 }
413 548
414 549
415 void LCodeGen::DoParallelMove(LParallelMove* move) { 550 void LCodeGen::DoParallelMove(LParallelMove* move) {
416 Abort("Unimplemented: %s", "DoParallelMove"); 551 resolver_.Resolve(move);
417 } 552 }
418 553
419 554
420 void LCodeGen::DoGap(LGap* gap) { 555 void LCodeGen::DoGap(LGap* gap) {
421 for (int i = LGap::FIRST_INNER_POSITION; 556 for (int i = LGap::FIRST_INNER_POSITION;
422 i <= LGap::LAST_INNER_POSITION; 557 i <= LGap::LAST_INNER_POSITION;
423 i++) { 558 i++) {
424 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); 559 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
425 LParallelMove* move = gap->GetParallelMove(inner_pos); 560 LParallelMove* move = gap->GetParallelMove(inner_pos);
426 if (move != NULL) DoParallelMove(move); 561 if (move != NULL) DoParallelMove(move);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 void LCodeGen::DoBitI(LBitI* instr) { 600 void LCodeGen::DoBitI(LBitI* instr) {
466 Abort("Unimplemented: %s", "DoBitI");} 601 Abort("Unimplemented: %s", "DoBitI");}
467 602
468 603
469 void LCodeGen::DoShiftI(LShiftI* instr) { 604 void LCodeGen::DoShiftI(LShiftI* instr) {
470 Abort("Unimplemented: %s", "DoShiftI"); 605 Abort("Unimplemented: %s", "DoShiftI");
471 } 606 }
472 607
473 608
474 void LCodeGen::DoSubI(LSubI* instr) { 609 void LCodeGen::DoSubI(LSubI* instr) {
475 Abort("Unimplemented: %s", "DoSubI"); 610 LOperand* left = instr->InputAt(0);
611 LOperand* right = instr->InputAt(1);
612 ASSERT(left->Equals(instr->result()));
613
614 if (right->IsConstantOperand()) {
615 __ subl(ToRegister(left),
616 Immediate(ToInteger32(LConstantOperand::cast(right))));
617 } else if (right->IsRegister()) {
618 __ subl(ToRegister(left), ToRegister(right));
619 } else {
620 __ subl(ToRegister(left), ToOperand(right));
621 }
622
623 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
624 DeoptimizeIf(overflow, instr->environment());
625 }
476 } 626 }
477 627
478 628
479 void LCodeGen::DoConstantI(LConstantI* instr) { 629 void LCodeGen::DoConstantI(LConstantI* instr) {
480 Abort("Unimplemented: %s", "DoConstantI"); 630 ASSERT(instr->result()->IsRegister());
631 __ movl(ToRegister(instr->result()), Immediate(instr->value()));
481 } 632 }
482 633
483 634
484 void LCodeGen::DoConstantD(LConstantD* instr) { 635 void LCodeGen::DoConstantD(LConstantD* instr) {
485 Abort("Unimplemented: %s", "DoConstantI"); 636 ASSERT(instr->result()->IsDoubleRegister());
637 XMMRegister res = ToDoubleRegister(instr->result());
638 double v = instr->value();
639 // Use xor to produce +0.0 in a fast and compact way, but avoid to
640 // do so if the constant is -0.0.
641 if (BitCast<uint64_t, double>(v) == 0) {
642 __ xorpd(res, res);
643 } else {
644 Register tmp = ToRegister(instr->TempAt(0));
645 int32_t v_int32 = static_cast<int32_t>(v);
646 if (static_cast<double>(v_int32) == v) {
647 __ movl(tmp, Immediate(v_int32));
648 __ cvtlsi2sd(res, tmp);
649 } else {
650 uint64_t int_val = BitCast<uint64_t, double>(v);
651 __ Set(tmp, int_val);
652 __ movd(res, tmp);
653 }
654 }
486 } 655 }
487 656
488 657
489 void LCodeGen::DoConstantT(LConstantT* instr) { 658 void LCodeGen::DoConstantT(LConstantT* instr) {
490 Abort("Unimplemented: %s", "DoConstantT"); 659 ASSERT(instr->result()->IsRegister());
660 __ Move(ToRegister(instr->result()), instr->value());
491 } 661 }
492 662
493 663
494 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { 664 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
495 Abort("Unimplemented: %s", "DoJSArrayLength"); 665 Abort("Unimplemented: %s", "DoJSArrayLength");
496 } 666 }
497 667
498 668
499 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { 669 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
500 Abort("Unimplemented: %s", "DoFixedArrayLength"); 670 Abort("Unimplemented: %s", "DoFixedArrayLength");
501 } 671 }
502 672
503 673
504 void LCodeGen::DoValueOf(LValueOf* instr) { 674 void LCodeGen::DoValueOf(LValueOf* instr) {
505 Abort("Unimplemented: %s", "DoValueOf"); 675 Abort("Unimplemented: %s", "DoValueOf");
506 } 676 }
507 677
508 678
509 void LCodeGen::DoBitNotI(LBitNotI* instr) { 679 void LCodeGen::DoBitNotI(LBitNotI* instr) {
510 Abort("Unimplemented: %s", "DoBitNotI"); 680 Abort("Unimplemented: %s", "DoBitNotI");
511 } 681 }
512 682
513 683
514 void LCodeGen::DoThrow(LThrow* instr) { 684 void LCodeGen::DoThrow(LThrow* instr) {
515 Abort("Unimplemented: %s", "DoThrow"); 685 Abort("Unimplemented: %s", "DoThrow");
516 } 686 }
517 687
518 688
519 void LCodeGen::DoAddI(LAddI* instr) { 689 void LCodeGen::DoAddI(LAddI* instr) {
520 Abort("Unimplemented: %s", "DoAddI"); 690 LOperand* left = instr->InputAt(0);
691 LOperand* right = instr->InputAt(1);
692 ASSERT(left->Equals(instr->result()));
693
694 if (right->IsConstantOperand()) {
695 __ addl(ToRegister(left),
696 Immediate(ToInteger32(LConstantOperand::cast(right))));
697 } else if (right->IsRegister()) {
698 __ addl(ToRegister(left), ToRegister(right));
699 } else {
700 __ addl(ToRegister(left), ToOperand(right));
701 }
702
703 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
704 DeoptimizeIf(overflow, instr->environment());
705 }
521 } 706 }
522 707
523 708
524 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { 709 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
525 Abort("Unimplemented: %s", "DoArithmeticD"); 710 Abort("Unimplemented: %s", "DoArithmeticD");
526 } 711 }
527 712
528 713
529 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { 714 void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
530 Abort("Unimplemented: %s", "DoArithmeticT"); 715 ASSERT(ToRegister(instr->InputAt(0)).is(rdx));
716 ASSERT(ToRegister(instr->InputAt(1)).is(rax));
717 ASSERT(ToRegister(instr->result()).is(rax));
718
719 GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, NO_GENERIC_BINARY_FLAGS);
720 stub.SetArgsInRegisters();
721 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
531 } 722 }
532 723
533 724
534 int LCodeGen::GetNextEmittedBlock(int block) { 725 int LCodeGen::GetNextEmittedBlock(int block) {
535 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { 726 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
536 LLabel* label = chunk_->GetLabel(i); 727 LLabel* label = chunk_->GetLabel(i);
537 if (!label->HasReplacement()) return i; 728 if (!label->HasReplacement()) return i;
538 } 729 }
539 return -1; 730 return -1;
540 } 731 }
541 732
542 733
543 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { 734 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
544 Abort("Unimplemented: %s", "EmitBranch"); 735 int next_block = GetNextEmittedBlock(current_block_);
736 right_block = chunk_->LookupDestination(right_block);
737 left_block = chunk_->LookupDestination(left_block);
738
739 if (right_block == left_block) {
740 EmitGoto(left_block);
741 } else if (left_block == next_block) {
742 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
743 } else if (right_block == next_block) {
744 __ j(cc, chunk_->GetAssemblyLabel(left_block));
745 } else {
746 __ j(cc, chunk_->GetAssemblyLabel(left_block));
747 if (cc != always) {
748 __ jmp(chunk_->GetAssemblyLabel(right_block));
749 }
750 }
545 } 751 }
546 752
547 753
548 void LCodeGen::DoBranch(LBranch* instr) { 754 void LCodeGen::DoBranch(LBranch* instr) {
549 Abort("Unimplemented: %s", "DoBranch"); 755 int true_block = chunk_->LookupDestination(instr->true_block_id());
756 int false_block = chunk_->LookupDestination(instr->false_block_id());
757
758 Representation r = instr->hydrogen()->representation();
759 if (r.IsInteger32()) {
760 Register reg = ToRegister(instr->InputAt(0));
761 __ testl(reg, reg);
762 EmitBranch(true_block, false_block, not_zero);
763 } else if (r.IsDouble()) {
764 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
765 __ xorpd(xmm0, xmm0);
766 __ ucomisd(reg, xmm0);
767 EmitBranch(true_block, false_block, not_equal);
768 } else {
769 ASSERT(r.IsTagged());
770 Register reg = ToRegister(instr->InputAt(0));
771 HType type = instr->hydrogen()->type();
772 if (type.IsBoolean()) {
773 __ Cmp(reg, FACTORY->true_value());
774 EmitBranch(true_block, false_block, equal);
775 } else if (type.IsSmi()) {
776 __ SmiCompare(reg, Smi::FromInt(0));
777 EmitBranch(true_block, false_block, not_equal);
778 } else {
779 Label* true_label = chunk_->GetAssemblyLabel(true_block);
780 Label* false_label = chunk_->GetAssemblyLabel(false_block);
781
782 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
783 __ j(equal, false_label);
784 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
785 __ j(equal, true_label);
786 __ CompareRoot(reg, Heap::kFalseValueRootIndex);
787 __ j(equal, false_label);
788 __ SmiCompare(reg, Smi::FromInt(0));
789 __ j(equal, false_label);
790 __ JumpIfSmi(reg, true_label);
791
792 // Test for double values. Plus/minus zero and NaN are false.
793 NearLabel call_stub;
794 __ CompareRoot(FieldOperand(reg, HeapObject::kMapOffset),
795 Heap::kHeapNumberMapRootIndex);
796 __ j(not_equal, &call_stub);
797
798 // HeapNumber => false iff +0, -0, or NaN. These three cases set the
799 // zero flag when compared to zero using ucomisd.
800 __ xorpd(xmm0, xmm0);
801 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
802 __ j(zero, false_label);
803 __ jmp(true_label);
804
805 // The conversion stub doesn't cause garbage collections so it's
806 // safe to not record a safepoint after the call.
807 __ bind(&call_stub);
808 ToBooleanStub stub;
809 __ Pushad();
810 __ push(reg);
811 __ CallStub(&stub);
812 __ testq(rax, rax);
813 __ Popad();
814 EmitBranch(true_block, false_block, not_zero);
815 }
816 }
550 } 817 }
551 818
552 819
553 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { 820 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
554 Abort("Unimplemented: %s", "EmitGoto"); 821 block = chunk_->LookupDestination(block);
822 int next_block = GetNextEmittedBlock(current_block_);
823 if (block != next_block) {
824 // Perform stack overflow check if this goto needs it before jumping.
825 if (deferred_stack_check != NULL) {
826 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
827 __ j(above_equal, chunk_->GetAssemblyLabel(block));
828 __ jmp(deferred_stack_check->entry());
829 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
830 } else {
831 __ jmp(chunk_->GetAssemblyLabel(block));
832 }
833 }
555 } 834 }
556 835
557 836
558 void LCodeGen::DoDeferredStackCheck(LGoto* instr) { 837 void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
559 Abort("Unimplemented: %s", "DoDeferredStackCheck"); 838 Abort("Unimplemented: %s", "DoDeferredStackCheck");
560 } 839 }
561 840
562 841
563 void LCodeGen::DoGoto(LGoto* instr) { 842 void LCodeGen::DoGoto(LGoto* instr) {
564 Abort("Unimplemented: %s", "DoGoto"); 843 class DeferredStackCheck: public LDeferredCode {
844 public:
845 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
846 : LDeferredCode(codegen), instr_(instr) { }
847 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
848 private:
849 LGoto* instr_;
850 };
851
852 DeferredStackCheck* deferred = NULL;
853 if (instr->include_stack_check()) {
854 deferred = new DeferredStackCheck(this, instr);
855 }
856 EmitGoto(instr->block_id(), deferred);
565 } 857 }
566 858
567 859
568 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { 860 inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
569 Condition cond = no_condition; 861 Condition cond = no_condition;
570 switch (op) { 862 switch (op) {
571 case Token::EQ: 863 case Token::EQ:
572 case Token::EQ_STRICT: 864 case Token::EQ_STRICT:
573 cond = equal; 865 cond = equal;
574 break; 866 break;
575 case Token::LT: 867 case Token::LT:
576 cond = is_unsigned ? below : less; 868 cond = is_unsigned ? below : less;
577 break; 869 break;
578 case Token::GT: 870 case Token::GT:
579 cond = is_unsigned ? above : greater; 871 cond = is_unsigned ? above : greater;
580 break; 872 break;
581 case Token::LTE: 873 case Token::LTE:
582 cond = is_unsigned ? below_equal : less_equal; 874 cond = is_unsigned ? below_equal : less_equal;
583 break; 875 break;
584 case Token::GTE: 876 case Token::GTE:
585 cond = is_unsigned ? above_equal : greater_equal; 877 cond = is_unsigned ? above_equal : greater_equal;
586 break; 878 break;
587 case Token::IN: 879 case Token::IN:
588 case Token::INSTANCEOF: 880 case Token::INSTANCEOF:
589 default: 881 default:
590 UNREACHABLE(); 882 UNREACHABLE();
591 } 883 }
592 return cond; 884 return cond;
593 } 885 }
594 886
595 887
596 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { 888 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
597 Abort("Unimplemented: %s", "EmitCmpI"); 889 if (right->IsConstantOperand()) {
890 int32_t value = ToInteger32(LConstantOperand::cast(right));
891 if (left->IsRegister()) {
892 __ cmpl(ToRegister(left), Immediate(value));
893 } else {
894 __ cmpl(ToOperand(left), Immediate(value));
895 }
896 } else if (right->IsRegister()) {
897 __ cmpq(ToRegister(left), ToRegister(right));
898 } else {
899 __ cmpq(ToRegister(left), ToOperand(right));
900 }
598 } 901 }
599 902
600 903
601 void LCodeGen::DoCmpID(LCmpID* instr) { 904 void LCodeGen::DoCmpID(LCmpID* instr) {
602 Abort("Unimplemented: %s", "DoCmpID"); 905 LOperand* left = instr->InputAt(0);
906 LOperand* right = instr->InputAt(1);
907 LOperand* result = instr->result();
908
909 NearLabel unordered;
910 if (instr->is_double()) {
911 // Don't base result on EFLAGS when a NaN is involved. Instead
912 // jump to the unordered case, which produces a false value.
913 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
914 __ j(parity_even, &unordered);
915 } else {
916 EmitCmpI(left, right);
917 }
918
919 NearLabel done;
920 Condition cc = TokenToCondition(instr->op(), instr->is_double());
921 __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
922 __ j(cc, &done);
923
924 __ bind(&unordered);
925 __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
926 __ bind(&done);
603 } 927 }
604 928
605 929
606 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { 930 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
607 Abort("Unimplemented: %s", "DoCmpIDAndBranch"); 931 LOperand* left = instr->InputAt(0);
932 LOperand* right = instr->InputAt(1);
933 int false_block = chunk_->LookupDestination(instr->false_block_id());
934 int true_block = chunk_->LookupDestination(instr->true_block_id());
935
936 if (instr->is_double()) {
937 // Don't base result on EFLAGS when a NaN is involved. Instead
938 // jump to the false block.
939 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
940 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
941 } else {
942 EmitCmpI(left, right);
943 }
944
945 Condition cc = TokenToCondition(instr->op(), instr->is_double());
946 EmitBranch(true_block, false_block, cc);
608 } 947 }
609 948
610 949
611 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { 950 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
612 Abort("Unimplemented: %s", "DoCmpJSObjectEq"); 951 Register left = ToRegister(instr->InputAt(0));
952 Register right = ToRegister(instr->InputAt(1));
953 Register result = ToRegister(instr->result());
954
955 NearLabel different, done;
956 __ cmpq(left, right);
957 __ j(not_equal, &different);
958 __ LoadRoot(result, Heap::kTrueValueRootIndex);
959 __ jmp(&done);
960 __ bind(&different);
961 __ LoadRoot(result, Heap::kFalseValueRootIndex);
962 __ bind(&done);
613 } 963 }
614 964
615 965
616 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { 966 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
617 Abort("Unimplemented: %s", "DoCmpJSObjectAndBranch"); 967 Register left = ToRegister(instr->InputAt(0));
968 Register right = ToRegister(instr->InputAt(1));
969 int false_block = chunk_->LookupDestination(instr->false_block_id());
970 int true_block = chunk_->LookupDestination(instr->true_block_id());
971
972 __ cmpq(left, right);
973 EmitBranch(true_block, false_block, equal);
618 } 974 }
619 975
620 976
621 void LCodeGen::DoIsNull(LIsNull* instr) { 977 void LCodeGen::DoIsNull(LIsNull* instr) {
622 Abort("Unimplemented: %s", "DoIsNull"); 978 Register reg = ToRegister(instr->InputAt(0));
979 Register result = ToRegister(instr->result());
980
981 // If the expression is known to be a smi, then it's
982 // definitely not null. Materialize false.
983 // Consider adding other type and representation tests too.
984 if (instr->hydrogen()->value()->type().IsSmi()) {
985 __ LoadRoot(result, Heap::kFalseValueRootIndex);
986 return;
987 }
988
989 __ CompareRoot(reg, Heap::kNullValueRootIndex);
990 if (instr->is_strict()) {
991 __ movl(result, Immediate(Heap::kTrueValueRootIndex));
992 NearLabel load;
993 __ j(equal, &load);
994 __ movl(result, Immediate(Heap::kFalseValueRootIndex));
995 __ bind(&load);
996 __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0));
997 } else {
998 NearLabel true_value, false_value, done;
999 __ j(equal, &true_value);
1000 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
1001 __ j(equal, &true_value);
1002 __ JumpIfSmi(reg, &false_value);
1003 // Check for undetectable objects by looking in the bit field in
1004 // the map. The object has already been smi checked.
1005 Register scratch = result;
1006 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1007 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
1008 Immediate(1 << Map::kIsUndetectable));
1009 __ j(not_zero, &true_value);
1010 __ bind(&false_value);
1011 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1012 __ jmp(&done);
1013 __ bind(&true_value);
1014 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1015 __ bind(&done);
1016 }
623 } 1017 }
624 1018
625 1019
626 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { 1020 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
627 Abort("Unimplemented: %s", "DoIsNullAndBranch"); 1021 Register reg = ToRegister(instr->InputAt(0));
1022
1023 int false_block = chunk_->LookupDestination(instr->false_block_id());
1024
1025 if (instr->hydrogen()->representation().IsSpecialization() ||
1026 instr->hydrogen()->type().IsSmi()) {
1027 // If the expression is known to untagged or smi, then it's definitely
1028 // not null, and it can't be a an undetectable object.
1029 // Jump directly to the false block.
1030 EmitGoto(false_block);
1031 return;
1032 }
1033
1034 int true_block = chunk_->LookupDestination(instr->true_block_id());
1035
1036 __ Cmp(reg, FACTORY->null_value());
1037 if (instr->is_strict()) {
1038 EmitBranch(true_block, false_block, equal);
1039 } else {
1040 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1041 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1042 __ j(equal, true_label);
1043 __ Cmp(reg, FACTORY->undefined_value());
1044 __ j(equal, true_label);
1045 __ JumpIfSmi(reg, false_label);
1046 // Check for undetectable objects by looking in the bit field in
1047 // the map. The object has already been smi checked.
1048 Register scratch = ToRegister(instr->TempAt(0));
1049 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1050 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
1051 Immediate(1 << Map::kIsUndetectable));
1052 EmitBranch(true_block, false_block, not_zero);
1053 }
628 } 1054 }
629 1055
630 1056
631 Condition LCodeGen::EmitIsObject(Register input, 1057 Condition LCodeGen::EmitIsObject(Register input,
632 Register temp1,
633 Register temp2,
634 Label* is_not_object, 1058 Label* is_not_object,
635 Label* is_object) { 1059 Label* is_object) {
636 Abort("Unimplemented: %s", "EmitIsObject"); 1060 ASSERT(!input.is(kScratchRegister));
1061
1062 __ JumpIfSmi(input, is_not_object);
1063
1064 __ CompareRoot(input, Heap::kNullValueRootIndex);
1065 __ j(equal, is_object);
1066
1067 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
1068 // Undetectable objects behave like undefined.
1069 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
1070 Immediate(1 << Map::kIsUndetectable));
1071 __ j(not_zero, is_not_object);
1072
1073 __ movzxbl(kScratchRegister,
1074 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
1075 __ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE));
1076 __ j(below, is_not_object);
1077 __ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE));
637 return below_equal; 1078 return below_equal;
638 } 1079 }
639 1080
640 1081
641 void LCodeGen::DoIsObject(LIsObject* instr) { 1082 void LCodeGen::DoIsObject(LIsObject* instr) {
642 Abort("Unimplemented: %s", "DoIsObject"); 1083 Register reg = ToRegister(instr->InputAt(0));
1084 Register result = ToRegister(instr->result());
1085 Label is_false, is_true, done;
1086
1087 Condition true_cond = EmitIsObject(reg, &is_false, &is_true);
1088 __ j(true_cond, &is_true);
1089
1090 __ bind(&is_false);
1091 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1092 __ jmp(&done);
1093
1094 __ bind(&is_true);
1095 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1096
1097 __ bind(&done);
643 } 1098 }
644 1099
645 1100
646 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { 1101 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
647 Abort("Unimplemented: %s", "DoIsObjectAndBranch"); 1102 Register reg = ToRegister(instr->InputAt(0));
1103
1104 int true_block = chunk_->LookupDestination(instr->true_block_id());
1105 int false_block = chunk_->LookupDestination(instr->false_block_id());
1106 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1107 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1108
1109 Condition true_cond = EmitIsObject(reg, false_label, true_label);
1110
1111 EmitBranch(true_block, false_block, true_cond);
648 } 1112 }
649 1113
650 1114
651 void LCodeGen::DoIsSmi(LIsSmi* instr) { 1115 void LCodeGen::DoIsSmi(LIsSmi* instr) {
652 Abort("Unimplemented: %s", "DoIsSmi"); 1116 LOperand* input_operand = instr->InputAt(0);
1117 Register result = ToRegister(instr->result());
1118 if (input_operand->IsRegister()) {
1119 Register input = ToRegister(input_operand);
1120 __ CheckSmiToIndicator(result, input);
1121 } else {
1122 Operand input = ToOperand(instr->InputAt(0));
1123 __ CheckSmiToIndicator(result, input);
1124 }
1125 // result is zero if input is a smi, and one otherwise.
1126 ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1);
1127 __ movq(result, Operand(kRootRegister, result, times_pointer_size,
1128 Heap::kTrueValueRootIndex * kPointerSize));
653 } 1129 }
654 1130
655 1131
656 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { 1132 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
657 Abort("Unimplemented: %s", "DoIsSmiAndBranch"); 1133 int true_block = chunk_->LookupDestination(instr->true_block_id());
658 } 1134 int false_block = chunk_->LookupDestination(instr->false_block_id());
659 1135
660 1136 Condition is_smi;
661 InstanceType LHasInstanceType::TestType() { 1137 if (instr->InputAt(0)->IsRegister()) {
662 InstanceType from = hydrogen()->from(); 1138 Register input = ToRegister(instr->InputAt(0));
663 InstanceType to = hydrogen()->to(); 1139 is_smi = masm()->CheckSmi(input);
1140 } else {
1141 Operand input = ToOperand(instr->InputAt(0));
1142 is_smi = masm()->CheckSmi(input);
1143 }
1144 EmitBranch(true_block, false_block, is_smi);
1145 }
1146
1147
1148 static InstanceType TestType(HHasInstanceType* instr) {
1149 InstanceType from = instr->from();
1150 InstanceType to = instr->to();
664 if (from == FIRST_TYPE) return to; 1151 if (from == FIRST_TYPE) return to;
665 ASSERT(from == to || to == LAST_TYPE); 1152 ASSERT(from == to || to == LAST_TYPE);
666 return from; 1153 return from;
667 } 1154 }
668 1155
669 1156
670 1157 static Condition BranchCondition(HHasInstanceType* instr) {
671 Condition LHasInstanceType::BranchCondition() { 1158 InstanceType from = instr->from();
672 InstanceType from = hydrogen()->from(); 1159 InstanceType to = instr->to();
673 InstanceType to = hydrogen()->to();
674 if (from == to) return equal; 1160 if (from == to) return equal;
675 if (to == LAST_TYPE) return above_equal; 1161 if (to == LAST_TYPE) return above_equal;
676 if (from == FIRST_TYPE) return below_equal; 1162 if (from == FIRST_TYPE) return below_equal;
677 UNREACHABLE(); 1163 UNREACHABLE();
678 return equal; 1164 return equal;
679 } 1165 }
680 1166
681 1167
682 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { 1168 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
683 Abort("Unimplemented: %s", "DoHasInstanceType"); 1169 Abort("Unimplemented: %s", "DoHasInstanceType");
684 } 1170 }
685 1171
686 1172
687 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { 1173 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
688 Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch"); 1174 Register input = ToRegister(instr->InputAt(0));
1175
1176 int true_block = chunk_->LookupDestination(instr->true_block_id());
1177 int false_block = chunk_->LookupDestination(instr->false_block_id());
1178
1179 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1180
1181 __ JumpIfSmi(input, false_label);
1182
1183 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
1184 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
689 } 1185 }
690 1186
691 1187
692 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { 1188 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
693 Abort("Unimplemented: %s", "DoHasCachedArrayIndex"); 1189 Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
694 } 1190 }
695 1191
696 1192
697 void LCodeGen::DoHasCachedArrayIndexAndBranch( 1193 void LCodeGen::DoHasCachedArrayIndexAndBranch(
698 LHasCachedArrayIndexAndBranch* instr) { 1194 LHasCachedArrayIndexAndBranch* instr) {
699 Abort("Unimplemented: %s", "DoHasCachedArrayIndexAndBranch"); 1195 Register input = ToRegister(instr->InputAt(0));
1196
1197 int true_block = chunk_->LookupDestination(instr->true_block_id());
1198 int false_block = chunk_->LookupDestination(instr->false_block_id());
1199
1200 __ testl(FieldOperand(input, String::kHashFieldOffset),
1201 Immediate(String::kContainsCachedArrayIndexMask));
1202 EmitBranch(true_block, false_block, not_equal);
700 } 1203 }
701 1204
702 1205
703 // Branches to a label or falls through with the answer in the z flag. Trashes 1206 // Branches to a label or falls through with the answer in the z flag.
704 // the temp registers, but not the input. Only input and temp2 may alias. 1207 // Trashes the temp register and possibly input (if it and temp are aliased).
705 void LCodeGen::EmitClassOfTest(Label* is_true, 1208 void LCodeGen::EmitClassOfTest(Label* is_true,
706 Label* is_false, 1209 Label* is_false,
707 Handle<String>class_name, 1210 Handle<String> class_name,
708 Register input, 1211 Register input,
709 Register temp, 1212 Register temp) {
710 Register temp2) { 1213 __ JumpIfSmi(input, is_false);
711 Abort("Unimplemented: %s", "EmitClassOfTest"); 1214 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
1215 __ j(below, is_false);
1216
1217 // Map is now in temp.
1218 // Functions have class 'Function'.
1219 __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
1220 if (class_name->IsEqualTo(CStrVector("Function"))) {
1221 __ j(equal, is_true);
1222 } else {
1223 __ j(equal, is_false);
1224 }
1225
1226 // Check if the constructor in the map is a function.
1227 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset));
1228
1229 // As long as JS_FUNCTION_TYPE is the last instance type and it is
1230 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1231 // LAST_JS_OBJECT_TYPE.
1232 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1233 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
1234
1235 // Objects with a non-function constructor have class 'Object'.
1236 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
1237 if (class_name->IsEqualTo(CStrVector("Object"))) {
1238 __ j(not_equal, is_true);
1239 } else {
1240 __ j(not_equal, is_false);
1241 }
1242
1243 // temp now contains the constructor function. Grab the
1244 // instance class name from there.
1245 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1246 __ movq(temp, FieldOperand(temp,
1247 SharedFunctionInfo::kInstanceClassNameOffset));
1248 // The class name we are testing against is a symbol because it's a literal.
1249 // The name in the constructor is a symbol because of the way the context is
1250 // booted. This routine isn't expected to work for random API-created
1251 // classes and it doesn't have to because you can't access it with natives
1252 // syntax. Since both sides are symbols it is sufficient to use an identity
1253 // comparison.
1254 ASSERT(class_name->IsSymbol());
1255 __ Cmp(temp, class_name);
1256 // End with the answer in the z flag.
712 } 1257 }
713 1258
714 1259
715 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { 1260 void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
716 Abort("Unimplemented: %s", "DoClassOfTest"); 1261 Register input = ToRegister(instr->InputAt(0));
1262 Register result = ToRegister(instr->result());
1263 ASSERT(input.is(result));
1264 Register temp = ToRegister(instr->TempAt(0));
1265 Handle<String> class_name = instr->hydrogen()->class_name();
1266 NearLabel done;
1267 Label is_true, is_false;
1268
1269 EmitClassOfTest(&is_true, &is_false, class_name, input, temp);
1270
1271 __ j(not_equal, &is_false);
1272
1273 __ bind(&is_true);
1274 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1275 __ jmp(&done);
1276
1277 __ bind(&is_false);
1278 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1279 __ bind(&done);
717 } 1280 }
718 1281
719 1282
720 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { 1283 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
721 Abort("Unimplemented: %s", "DoClassOfTestAndBranch"); 1284 Register input = ToRegister(instr->InputAt(0));
1285 Register temp = ToRegister(instr->TempAt(0));
1286 Handle<String> class_name = instr->hydrogen()->class_name();
1287
1288 int true_block = chunk_->LookupDestination(instr->true_block_id());
1289 int false_block = chunk_->LookupDestination(instr->false_block_id());
1290
1291 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1292 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1293
1294 EmitClassOfTest(true_label, false_label, class_name, input, temp);
1295
1296 EmitBranch(true_block, false_block, equal);
722 } 1297 }
723 1298
724 1299
725 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { 1300 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
726 Abort("Unimplemented: %s", "DoCmpMapAndBranch"); 1301 Register reg = ToRegister(instr->InputAt(0));
1302 int true_block = instr->true_block_id();
1303 int false_block = instr->false_block_id();
1304
1305 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1306 EmitBranch(true_block, false_block, equal);
727 } 1307 }
728 1308
729 1309
730 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { 1310 void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
731 Abort("Unimplemented: %s", "DoInstanceOf"); 1311 Abort("Unimplemented: %s", "DoInstanceOf");
732 } 1312 }
733 1313
734 1314
735 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { 1315 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
736 Abort("Unimplemented: %s", "DoInstanceOfAndBranch"); 1316 int true_block = chunk_->LookupDestination(instr->true_block_id());
1317 int false_block = chunk_->LookupDestination(instr->false_block_id());
1318
1319 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
1320 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1321 __ testq(rax, rax);
1322 EmitBranch(true_block, false_block, zero);
737 } 1323 }
738 1324
739 1325
740 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { 1326 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
741 Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal"); 1327 Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal");
742 } 1328 }
743 1329
744 1330
745 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 1331 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
746 Label* map_check) { 1332 Label* map_check) {
747 Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl"); 1333 Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl");
748 } 1334 }
749 1335
750 1336
751 void LCodeGen::DoCmpT(LCmpT* instr) { 1337 void LCodeGen::DoCmpT(LCmpT* instr) {
752 Abort("Unimplemented: %s", "DoCmpT"); 1338 Token::Value op = instr->op();
1339
1340 Handle<Code> ic = CompareIC::GetUninitialized(op);
1341 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1342
1343 Condition condition = TokenToCondition(op, false);
1344 if (op == Token::GT || op == Token::LTE) {
1345 condition = ReverseCondition(condition);
1346 }
1347 NearLabel true_value, done;
1348 __ testq(rax, rax);
1349 __ j(condition, &true_value);
1350 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
1351 __ jmp(&done);
1352 __ bind(&true_value);
1353 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
1354 __ bind(&done);
753 } 1355 }
754 1356
755 1357
756 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { 1358 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
757 Abort("Unimplemented: %s", "DoCmpTAndBranch"); 1359 Token::Value op = instr->op();
1360 int true_block = chunk_->LookupDestination(instr->true_block_id());
1361 int false_block = chunk_->LookupDestination(instr->false_block_id());
1362
1363 Handle<Code> ic = CompareIC::GetUninitialized(op);
1364 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1365
1366 // The compare stub expects compare condition and the input operands
1367 // reversed for GT and LTE.
1368 Condition condition = TokenToCondition(op, false);
1369 if (op == Token::GT || op == Token::LTE) {
1370 condition = ReverseCondition(condition);
1371 }
1372 __ testq(rax, rax);
1373 EmitBranch(true_block, false_block, condition);
758 } 1374 }
759 1375
760 1376
761 void LCodeGen::DoReturn(LReturn* instr) { 1377 void LCodeGen::DoReturn(LReturn* instr) {
762 Abort("Unimplemented: %s", "DoReturn"); 1378 if (FLAG_trace) {
1379 // Preserve the return value on the stack and rely on the runtime
1380 // call to return the value in the same register.
1381 __ push(rax);
1382 __ CallRuntime(Runtime::kTraceExit, 1);
1383 }
1384 __ movq(rsp, rbp);
1385 __ pop(rbp);
1386 __ ret((ParameterCount() + 1) * kPointerSize);
763 } 1387 }
764 1388
765 1389
766 void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { 1390 void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
767 Abort("Unimplemented: %s", "DoLoadGlobal"); 1391 Abort("Unimplemented: %s", "DoLoadGlobal");
768 } 1392 }
769 1393
770 1394
771 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { 1395 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
772 Abort("Unimplemented: %s", "DoStoreGlobal"); 1396 Abort("Unimplemented: %s", "DoStoreGlobal");
773 } 1397 }
774 1398
775 1399
1400 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
1401 Abort("Unimplemented: %s", "DoLoadContextSlot");
1402 }
1403
1404
776 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { 1405 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
777 Abort("Unimplemented: %s", "DoLoadNamedField"); 1406 Abort("Unimplemented: %s", "DoLoadNamedField");
778 } 1407 }
779 1408
780 1409
781 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { 1410 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
782 Abort("Unimplemented: %s", "DoLoadNamedGeneric"); 1411 Abort("Unimplemented: %s", "DoLoadNamedGeneric");
783 } 1412 }
784 1413
785 1414
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 Abort("Unimplemented: %s", "DoApplyArguments"); 1451 Abort("Unimplemented: %s", "DoApplyArguments");
823 } 1452 }
824 1453
825 1454
826 void LCodeGen::DoPushArgument(LPushArgument* instr) { 1455 void LCodeGen::DoPushArgument(LPushArgument* instr) {
827 Abort("Unimplemented: %s", "DoPushArgument"); 1456 Abort("Unimplemented: %s", "DoPushArgument");
828 } 1457 }
829 1458
830 1459
831 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { 1460 void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
832 Abort("Unimplemented: %s", "DoGlobalObject"); 1461 Register result = ToRegister(instr->result());
1462 __ movq(result, GlobalObjectOperand());
833 } 1463 }
834 1464
835 1465
836 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { 1466 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
837 Abort("Unimplemented: %s", "DoGlobalReceiver"); 1467 Abort("Unimplemented: %s", "DoGlobalReceiver");
838 } 1468 }
839 1469
840 1470
841 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 1471 void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
842 int arity, 1472 int arity,
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 Abort("Unimplemented: %s", "DoStoreKeyedFastElement"); 1589 Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
960 } 1590 }
961 1591
962 1592
963 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { 1593 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
964 Abort("Unimplemented: %s", "DoStoreKeyedGeneric"); 1594 Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
965 } 1595 }
966 1596
967 1597
968 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { 1598 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
969 Abort("Unimplemented: %s", "DoInteger32ToDouble"); 1599 LOperand* input = instr->InputAt(0);
1600 ASSERT(input->IsRegister() || input->IsStackSlot());
1601 LOperand* output = instr->result();
1602 ASSERT(output->IsDoubleRegister());
1603 __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
970 } 1604 }
971 1605
972 1606
973 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { 1607 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
974 Abort("Unimplemented: %s", "DoNumberTagI"); 1608 LOperand* input = instr->InputAt(0);
975 } 1609 ASSERT(input->IsRegister() && input->Equals(instr->result()));
1610 Register reg = ToRegister(input);
976 1611
977 1612 __ Integer32ToSmi(reg, reg);
978 void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
979 Abort("Unimplemented: %s", "DoDeferredNumberTagI");
980 } 1613 }
981 1614
982 1615
983 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { 1616 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
984 Abort("Unimplemented: %s", "DoNumberTagD"); 1617 class DeferredNumberTagD: public LDeferredCode {
1618 public:
1619 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
1620 : LDeferredCode(codegen), instr_(instr) { }
1621 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
1622 private:
1623 LNumberTagD* instr_;
1624 };
1625
1626 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
1627 Register reg = ToRegister(instr->result());
1628 Register tmp = ToRegister(instr->TempAt(0));
1629
1630 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
1631 if (FLAG_inline_new) {
1632 __ AllocateHeapNumber(reg, tmp, deferred->entry());
1633 } else {
1634 __ jmp(deferred->entry());
1635 }
1636 __ bind(deferred->exit());
1637 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
985 } 1638 }
986 1639
987 1640
988 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { 1641 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
989 Abort("Unimplemented: %s", "DoDeferredNumberTagD"); 1642 // TODO(3095996): Get rid of this. For now, we need to make the
1643 // result register contain a valid pointer because it is already
1644 // contained in the register pointer map.
1645 Register reg = ToRegister(instr->result());
1646 __ Move(reg, Smi::FromInt(0));
1647
1648 __ PushSafepointRegisters();
1649 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
1650 RecordSafepointWithRegisters(
1651 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1652 // Ensure that value in rax survives popping registers.
1653 __ movq(kScratchRegister, rax);
1654 __ PopSafepointRegisters();
1655 __ movq(reg, kScratchRegister);
990 } 1656 }
991 1657
992 1658
993 void LCodeGen::DoSmiTag(LSmiTag* instr) { 1659 void LCodeGen::DoSmiTag(LSmiTag* instr) {
994 Abort("Unimplemented: %s", "DoSmiTag"); 1660 Abort("Unimplemented: %s", "DoSmiTag");
995 } 1661 }
996 1662
997 1663
998 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 1664 void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
999 Abort("Unimplemented: %s", "DoSmiUntag"); 1665 Abort("Unimplemented: %s", "DoSmiUntag");
1000 } 1666 }
1001 1667
1002 1668
1003 void LCodeGen::EmitNumberUntagD(Register input_reg, 1669 void LCodeGen::EmitNumberUntagD(Register input_reg,
1004 XMMRegister result_reg, 1670 XMMRegister result_reg,
1005 LEnvironment* env) { 1671 LEnvironment* env) {
1006 Abort("Unimplemented: %s", "EmitNumberUntagD"); 1672 NearLabel load_smi, heap_number, done;
1673
1674 // Smi check.
1675 __ JumpIfSmi(input_reg, &load_smi);
1676
1677 // Heap number map check.
1678 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
1679 Heap::kHeapNumberMapRootIndex);
1680 __ j(equal, &heap_number);
1681
1682 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
1683 DeoptimizeIf(not_equal, env);
1684
1685 // Convert undefined to NaN. Compute NaN as 0/0.
1686 __ xorpd(result_reg, result_reg);
1687 __ divsd(result_reg, result_reg);
1688 __ jmp(&done);
1689
1690 // Heap number to XMM conversion.
1691 __ bind(&heap_number);
1692 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
1693 __ jmp(&done);
1694
1695 // Smi to XMM conversion
1696 __ bind(&load_smi);
1697 __ SmiToInteger32(kScratchRegister, input_reg); // Untag smi first.
1698 __ cvtlsi2sd(result_reg, kScratchRegister);
1699 __ bind(&done);
1007 } 1700 }
1008 1701
1009 1702
1010 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { 1703 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
1011 Abort("Unimplemented: %s", "DoDeferredTaggedToI"); 1704 Abort("Unimplemented: %s", "DoDeferredTaggedToI");
1012 } 1705 }
1013 1706
1014 1707
1015 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { 1708 void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
1016 Abort("Unimplemented: %s", "DoTaggedToI"); 1709 Abort("Unimplemented: %s", "DoTaggedToI");
(...skipping 23 matching lines...) Expand all
1040 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { 1733 void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
1041 Abort("Unimplemented: %s", "DoCheckFunction"); 1734 Abort("Unimplemented: %s", "DoCheckFunction");
1042 } 1735 }
1043 1736
1044 1737
1045 void LCodeGen::DoCheckMap(LCheckMap* instr) { 1738 void LCodeGen::DoCheckMap(LCheckMap* instr) {
1046 Abort("Unimplemented: %s", "DoCheckMap"); 1739 Abort("Unimplemented: %s", "DoCheckMap");
1047 } 1740 }
1048 1741
1049 1742
1050 void LCodeGen::LoadPrototype(Register result, Handle<JSObject> prototype) { 1743 void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
1051 Abort("Unimplemented: %s", "LoadPrototype"); 1744 Abort("Unimplemented: %s", "LoadHeapObject");
1052 } 1745 }
1053 1746
1054 1747
1055 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { 1748 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
1056 Abort("Unimplemented: %s", "DoCheckPrototypeMaps"); 1749 Abort("Unimplemented: %s", "DoCheckPrototypeMaps");
1057 } 1750 }
1058 1751
1059 1752
1060 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { 1753 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
1061 Abort("Unimplemented: %s", "DoArrayLiteral"); 1754 Abort("Unimplemented: %s", "DoArrayLiteral");
(...skipping 19 matching lines...) Expand all
1081 Abort("Unimplemented: %s", "DoTypeof"); 1774 Abort("Unimplemented: %s", "DoTypeof");
1082 } 1775 }
1083 1776
1084 1777
1085 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { 1778 void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
1086 Abort("Unimplemented: %s", "DoTypeofIs"); 1779 Abort("Unimplemented: %s", "DoTypeofIs");
1087 } 1780 }
1088 1781
1089 1782
1090 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { 1783 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
1091 Abort("Unimplemented: %s", "DoTypeofIsAndBranch"); 1784 Register input = ToRegister(instr->InputAt(0));
1785 int true_block = chunk_->LookupDestination(instr->true_block_id());
1786 int false_block = chunk_->LookupDestination(instr->false_block_id());
1787 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1788 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1789
1790 Condition final_branch_condition = EmitTypeofIs(true_label,
1791 false_label,
1792 input,
1793 instr->type_literal());
1794
1795 EmitBranch(true_block, false_block, final_branch_condition);
1092 } 1796 }
1093 1797
1094 1798
1095 Condition LCodeGen::EmitTypeofIs(Label* true_label, 1799 Condition LCodeGen::EmitTypeofIs(Label* true_label,
1096 Label* false_label, 1800 Label* false_label,
1097 Register input, 1801 Register input,
1098 Handle<String> type_name) { 1802 Handle<String> type_name) {
1099 Abort("Unimplemented: %s", "EmitTypeofIs"); 1803 Condition final_branch_condition = no_condition;
1100 return no_condition; 1804 if (type_name->Equals(HEAP->number_symbol())) {
1805 __ JumpIfSmi(input, true_label);
1806 __ Cmp(FieldOperand(input, HeapObject::kMapOffset),
1807 FACTORY->heap_number_map());
1808 final_branch_condition = equal;
1809
1810 } else if (type_name->Equals(HEAP->string_symbol())) {
1811 __ JumpIfSmi(input, false_label);
1812 __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
1813 __ testb(FieldOperand(input, Map::kBitFieldOffset),
1814 Immediate(1 << Map::kIsUndetectable));
1815 __ j(not_zero, false_label);
1816 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
1817 final_branch_condition = below;
1818
1819 } else if (type_name->Equals(HEAP->boolean_symbol())) {
1820 __ CompareRoot(input, Heap::kTrueValueRootIndex);
1821 __ j(equal, true_label);
1822 __ CompareRoot(input, Heap::kFalseValueRootIndex);
1823 final_branch_condition = equal;
1824
1825 } else if (type_name->Equals(HEAP->undefined_symbol())) {
1826 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
1827 __ j(equal, true_label);
1828 __ JumpIfSmi(input, false_label);
1829 // Check for undetectable objects => true.
1830 __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
1831 __ testb(FieldOperand(input, Map::kBitFieldOffset),
1832 Immediate(1 << Map::kIsUndetectable));
1833 final_branch_condition = not_zero;
1834
1835 } else if (type_name->Equals(HEAP->function_symbol())) {
1836 __ JumpIfSmi(input, false_label);
1837 __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input);
1838 final_branch_condition = above_equal;
1839
1840 } else if (type_name->Equals(HEAP->object_symbol())) {
1841 __ JumpIfSmi(input, false_label);
1842 __ Cmp(input, FACTORY->null_value());
1843 __ j(equal, true_label);
1844 // Check for undetectable objects => false.
1845 __ testb(FieldOperand(input, Map::kBitFieldOffset),
1846 Immediate(1 << Map::kIsUndetectable));
1847 __ j(not_zero, false_label);
1848 // Check for JS objects that are not RegExp or Function => true.
1849 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
1850 __ j(below, false_label);
1851 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
1852 final_branch_condition = below_equal;
1853
1854 } else {
1855 final_branch_condition = never;
1856 __ jmp(false_label);
1857 }
1858
1859 return final_branch_condition;
1101 } 1860 }
1102 1861
1103 1862
1104 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { 1863 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
1105 // No code for lazy bailout instruction. Used to capture environment after a 1864 // No code for lazy bailout instruction. Used to capture environment after a
1106 // call for populating the safepoint data with deoptimization data. 1865 // call for populating the safepoint data with deoptimization data.
1107 } 1866 }
1108 1867
1109 1868
1110 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { 1869 void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
1111 DeoptimizeIf(no_condition, instr->environment()); 1870 DeoptimizeIf(no_condition, instr->environment());
1112 } 1871 }
1113 1872
1114 1873
1115 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { 1874 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
1116 Abort("Unimplemented: %s", "DoDeleteProperty"); 1875 Abort("Unimplemented: %s", "DoDeleteProperty");
1117 } 1876 }
1118 1877
1119 1878
1120 void LCodeGen::DoStackCheck(LStackCheck* instr) { 1879 void LCodeGen::DoStackCheck(LStackCheck* instr) {
1121 Abort("Unimplemented: %s", "DoStackCheck"); 1880 // Perform stack overflow check.
1881 NearLabel done;
1882 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
1883 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
1884 __ j(above_equal, &done);
1885
1886 StackCheckStub stub;
1887 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1888 __ bind(&done);
1122 } 1889 }
1123 1890
1124 1891
1125 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { 1892 void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
1126 Abort("Unimplemented: %s", "DoOsrEntry"); 1893 Abort("Unimplemented: %s", "DoOsrEntry");
1127 } 1894 }
1128 1895
1129 #undef __ 1896 #undef __
1130 1897
1131 } } // namespace v8::internal 1898 } } // namespace v8::internal
1132 1899
1133 #endif // V8_TARGET_ARCH_X64 1900 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/lithium-codegen-x64.h ('k') | src/x64/lithium-gap-resolver-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698