7 #if V8_TARGET_ARCH_IA32
24 class SafepointGenerator
FINAL :
public CallWrapper {
26 SafepointGenerator(LCodeGen* codegen,
27 LPointerMap* pointers,
28 Safepoint::DeoptMode
mode)
32 virtual ~SafepointGenerator() {}
34 virtual void BeforeCall(
int call_size)
const OVERRIDE {}
36 virtual void AfterCall() const
OVERRIDE {
37 codegen_->RecordSafepoint(pointers_, deopt_mode_);
42 LPointerMap* pointers_;
43 Safepoint::DeoptMode deopt_mode_;
50 LPhase phase(
"Z_Code generation",
chunk());
57 FrameScope frame_scope(masm_, StackFrame::MANUAL);
62 ((
chunk()->num_double_slots() > 2 &&
63 !
chunk()->graph()->is_recursive()) ||
64 !info()->osr_ast_id().IsNone());
77 code->set_safepoint_table_offset(
safepoints_.GetCodeOffset());
78 if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
80 if (!info()->IsStub()) {
87 void LCodeGen::MakeSureStackPagesMapped(
int offset) {
88 const int kPageSize = 4 *
KB;
89 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
97 DCHECK(info()->saves_caller_doubles());
99 Comment(
";;; Save clobbered callee double registers");
101 BitVector* doubles =
chunk()->allocated_double_registers();
102 BitVector::Iterator save_iterator(doubles);
103 while (!save_iterator.Done()) {
106 save_iterator.Advance();
113 DCHECK(info()->saves_caller_doubles());
115 Comment(
";;; Restore clobbered callee double registers");
116 BitVector* doubles =
chunk()->allocated_double_registers();
117 BitVector::Iterator save_iterator(doubles);
119 while (!save_iterator.Done()) {
122 save_iterator.Advance();
131 if (info()->IsOptimizing()) {
135 if (strlen(FLAG_stop_at) > 0 &&
136 info_->function()->name()->IsUtf8EqualTo(
CStrVector(FLAG_stop_at))) {
144 if (info_->this_has_uses() &&
145 info_->strict_mode() ==
SLOPPY &&
146 !info_->is_native()) {
150 __ mov(
ecx, Operand(
esp, receiver_offset));
152 __ cmp(
ecx, isolate()->factory()->undefined_value());
158 __ mov(Operand(
esp, receiver_offset),
ecx);
167 Label do_not_pad, align_loop;
172 __ push(Immediate(0));
176 __ mov(
ecx, Immediate(
scope()->num_parameters() + 2));
178 __ bind(&align_loop);
185 __ bind(&do_not_pad);
189 info()->set_prologue_offset(masm_->pc_offset());
193 if (info()->IsStub()) {
196 __ Prologue(info()->IsCodePreAgingActive());
198 info()->AddNoFrameRange(0, masm_->pc_offset());
201 if (info()->IsOptimizing() &&
205 __ Assert(
zero, kFrameIsExpectedToBeAligned);
210 DCHECK(slots != 0 || !info()->IsOptimizing());
219 if (FLAG_debug_code) {
225 __ mov(Operand(
eax), Immediate(slots));
241 Comment(
";;; Store dynamic frame alignment tag for spilled doubles");
257 if (heap_slots > 0) {
258 Comment(
";;; Allocate local context");
259 bool need_write_barrier =
true;
261 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
262 FastNewContextStub stub(isolate(), heap_slots);
265 need_write_barrier =
false;
278 for (
int i = 0;
i < num_parameters;
i++) {
280 if (var->IsContextSlot()) {
284 __ mov(
eax, Operand(
ebp, parameter_offset));
287 __ mov(Operand(
esi, context_offset),
eax);
289 if (need_write_barrier) {
290 __ RecordWriteContextSlot(
esi,
295 }
else if (FLAG_debug_code) {
297 __ JumpIfInNewSpace(
esi,
eax, &done, Label::kNear);
298 __ Abort(kExpectedNewSpaceObject);
303 Comment(
";;; End allocate local context");
307 if (FLAG_trace && info()->IsOptimizing()) {
312 return !is_aborted();
327 Label do_not_pad, align_loop;
330 __ j(
zero, &do_not_pad, Label::kNear);
331 __ push(Immediate(0));
338 __ mov(
ecx, Immediate(
scope()->num_parameters() +
339 5 +
graph()->osr()->UnoptimizedFrameSlots()));
341 __ bind(&align_loop);
349 __ bind(&do_not_pad);
354 __ push(alignment_loc);
357 __ mov(alignment_loc,
edx);
368 if (instr->IsCall()) {
371 if (!instr->IsLazyBailout() && !instr->IsGap()) {
383 Comment(
";;; -------------------- Jump table --------------------");
386 Deoptimizer::JumpTableEntry* table_entry = &
jump_table_[
i];
387 __ bind(&table_entry->label);
388 Address entry = table_entry->address;
389 DeoptComment(table_entry->reason);
390 if (table_entry->needs_frame) {
391 DCHECK(!info()->saves_caller_doubles());
392 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
393 if (needs_frame.is_bound()) {
394 __ jmp(&needs_frame);
396 __ bind(&needs_frame);
407 Label push_approx_pc;
408 __ call(&push_approx_pc);
409 __ bind(&push_approx_pc);
422 return !is_aborted();
429 for (
int i = 0; !is_aborted() &&
i <
deferred_.length();
i++) {
433 instructions_->at(code->instruction_index())->hydrogen_value();
435 chunk()->
graph()->SourcePositionToScriptPosition(value->position()));
437 Comment(
";;; <@%d,#%d> "
438 "-------------------- Deferred %s --------------------",
439 code->instruction_index(),
440 code->instr()->hydrogen_value()->id(),
441 code->instr()->Mnemonic());
442 __ bind(code->entry());
444 Comment(
";;; Build frame");
453 Comment(
";;; Deferred code");
457 __ bind(code->done());
458 Comment(
";;; Destroy frame");
464 __ jmp(code->exit());
470 if (!is_aborted()) status_ =
DONE;
471 return !is_aborted();
477 if (!info()->IsStub()) {
482 while (masm()->pc_offset() < target_offset) {
487 return !is_aborted();
508 DCHECK(op->IsDoubleRegister());
519 const Representation& r)
const {
520 HConstant* constant = chunk_->LookupConstant(op);
521 int32_t value = constant->Integer32Value();
522 if (r.IsInteger32())
return value;
523 DCHECK(r.IsSmiOrTagged());
529 HConstant* constant = chunk_->LookupConstant(op);
530 DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
531 return constant->handle(isolate());
536 HConstant* constant = chunk_->LookupConstant(op);
537 DCHECK(constant->HasDoubleValue());
538 return constant->DoubleValue();
543 HConstant* constant = chunk_->LookupConstant(op);
544 DCHECK(constant->HasExternalReferenceValue());
545 return constant->ExternalReferenceValue();
550 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
555 return chunk_->LookupLiteralRepresentation(op).IsSmi();
566 if (op->IsRegister())
return Operand(
ToRegister(op));
568 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
580 DCHECK(op->IsDoubleStackSlot());
593 Translation* translation) {
594 if (environment ==
NULL)
return;
597 int translation_size = environment->translation_size();
599 int height = translation_size - environment->parameter_count();
602 bool has_closure_id = !info()->closure().is_null() &&
603 !info()->closure().is_identical_to(environment->closure());
604 int closure_id = has_closure_id
606 : Translation::kSelfLiteralId;
607 switch (environment->frame_type()) {
609 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
612 translation->BeginConstructStubFrame(closure_id, translation_size);
615 DCHECK(translation_size == 1);
617 translation->BeginGetterStubFrame(closure_id);
620 DCHECK(translation_size == 2);
622 translation->BeginSetterStubFrame(closure_id);
625 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
628 translation->BeginCompiledStubFrame();
634 int object_index = 0;
635 int dematerialized_index = 0;
636 for (
int i = 0;
i < translation_size; ++
i) {
637 LOperand* value = environment->values()->at(
i);
641 environment->HasTaggedValueAt(
i),
642 environment->HasUint32ValueAt(
i),
644 &dematerialized_index);
650 Translation* translation,
654 int* object_index_pointer,
655 int* dematerialized_index_pointer) {
656 if (op == LEnvironment::materialization_marker()) {
657 int object_index = (*object_index_pointer)++;
658 if (environment->ObjectIsDuplicateAt(object_index)) {
659 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
660 translation->DuplicateObject(dupe_of);
663 int object_length = environment->ObjectLengthAt(object_index);
664 if (environment->ObjectIsArgumentsAt(object_index)) {
665 translation->BeginArgumentsObject(object_length);
667 translation->BeginCapturedObject(object_length);
669 int dematerialized_index = *dematerialized_index_pointer;
670 int env_offset = environment->translation_size() + dematerialized_index;
671 *dematerialized_index_pointer += object_length;
672 for (
int i = 0;
i < object_length; ++
i) {
673 LOperand* value = environment->values()->at(env_offset +
i);
677 environment->HasTaggedValueAt(env_offset +
i),
678 environment->HasUint32ValueAt(env_offset +
i),
679 object_index_pointer,
680 dematerialized_index_pointer);
685 if (op->IsStackSlot()) {
687 translation->StoreStackSlot(op->index());
688 }
else if (is_uint32) {
689 translation->StoreUint32StackSlot(op->index());
691 translation->StoreInt32StackSlot(op->index());
693 }
else if (op->IsDoubleStackSlot()) {
694 translation->StoreDoubleStackSlot(op->index());
695 }
else if (op->IsRegister()) {
698 translation->StoreRegister(reg);
699 }
else if (is_uint32) {
700 translation->StoreUint32Register(reg);
702 translation->StoreInt32Register(reg);
704 }
else if (op->IsDoubleRegister()) {
706 translation->StoreDoubleRegister(reg);
707 }
else if (op->IsConstantOperand()) {
708 HConstant* constant =
chunk()->LookupConstant(LConstantOperand::cast(op));
710 translation->StoreLiteral(src_index);
720 SafepointMode safepoint_mode) {
727 if (code->kind() == Code::BINARY_OP_IC ||
728 code->kind() == Code::COMPARE_IC) {
736 LInstruction* instr) {
746 DCHECK(instr->HasPointerMap());
752 DCHECK(info()->is_calling());
757 if (context->IsRegister()) {
761 }
else if (context->IsStackSlot()) {
763 }
else if (context->IsConstantOperand()) {
764 HConstant* constant =
765 chunk_->LookupConstant(LConstantOperand::cast(context));
778 __ CallRuntimeSaveDoubles(
id);
780 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
782 DCHECK(info()->is_calling());
787 LEnvironment* environment, Safepoint::DeoptMode
mode) {
788 environment->set_has_been_used();
789 if (!environment->HasBeenRegistered()) {
804 int jsframe_count = 0;
811 Translation translation(&
translations_, frame_count, jsframe_count, zone());
814 int pc_offset = masm()->pc_offset();
815 environment->Register(deoptimization_index,
817 (
mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
828 DCHECK(environment->HasBeenRegistered());
829 int id = environment->deoptimization_index();
830 DCHECK(info()->IsOptimizing() || info()->IsStub());
834 Abort(kBailoutWasNotPrepared);
839 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
843 __ mov(
eax, Operand::StaticVariable(count));
844 __ sub(
eax, Immediate(1));
846 if (FLAG_trap_on_deopt)
__ int3();
847 __ mov(
eax, Immediate(FLAG_deopt_every_n_times));
848 __ mov(Operand::StaticVariable(count),
eax);
854 __ mov(Operand::StaticVariable(count),
eax);
859 if (info()->ShouldTrapOnDeopt()) {
866 Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
867 instr->Mnemonic(), detail);
870 DeoptComment(reason);
873 Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
891 const char* detail) {
901 if (length == 0)
return;
902 Handle<DeoptimizationInputData> data =
905 Handle<ByteArray> translations =
907 data->SetTranslationByteArray(*translations);
909 data->SetOptimizationId(
Smi::FromInt(info_->optimization_id()));
910 if (info_->IsOptimizing()) {
913 data->SetSharedFunctionInfo(*info_->shared_info());
927 data->SetOsrAstId(
Smi::FromInt(info_->osr_ast_id().ToInt()));
931 for (
int i = 0;
i < length;
i++) {
933 data->SetAstId(
i, env->ast_id());
934 data->SetTranslationIndex(
i,
Smi::FromInt(env->translation_index()));
935 data->SetArgumentsStackHeight(
i,
939 code->set_deoptimization_data(*data);
956 const ZoneList<Handle<JSFunction> >* inlined_closures =
957 chunk()->inlined_closures();
959 for (
int i = 0, length = inlined_closures->length();
970 LInstruction* instr, SafepointMode safepoint_mode) {
976 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
982 LPointerMap* pointers,
983 Safepoint::Kind kind,
985 Safepoint::DeoptMode deopt_mode) {
987 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
988 Safepoint safepoint =
989 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
990 for (
int i = 0;
i < operands->length();
i++) {
991 LOperand* pointer = operands->at(
i);
992 if (pointer->IsStackSlot()) {
993 safepoint.DefinePointerSlot(pointer->index(), zone());
994 }
else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
995 safepoint.DefinePointerRegister(
ToRegister(pointer), zone());
1002 Safepoint::DeoptMode
mode) {
1008 LPointerMap empty_pointers(zone());
1015 Safepoint::DeoptMode
mode) {
1022 masm()->positions_recorder()->RecordPosition(position);
1023 masm()->positions_recorder()->WriteRecordedPositions();
1027 static const char*
LabelType(LLabel* label) {
1028 if (label->is_loop_header())
return " (loop header)";
1029 if (label->is_osr_entry())
return " (OSR entry)";
1034 void LCodeGen::DoLabel(LLabel* label) {
1035 Comment(
";;; <@%d,#%d> -------------------- B%d%s --------------------",
1036 current_instruction_,
1037 label->hydrogen_value()->id(),
1040 __ bind(label->label());
1041 current_block_ = label->block_id();
1056 LParallelMove* move = gap->GetParallelMove(inner_pos);
1062 void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1067 void LCodeGen::DoParameter(LParameter* instr) {
1072 void LCodeGen::DoCallStub(LCallStub* instr) {
1075 switch (instr->hydrogen()->major_key()) {
1076 case CodeStub::RegExpExec: {
1077 RegExpExecStub stub(isolate());
1081 case CodeStub::SubString: {
1082 SubStringStub stub(isolate());
1086 case CodeStub::StringCompare: {
1087 StringCompareStub stub(isolate());
1097 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1102 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
1103 Register dividend =
ToRegister(instr->dividend());
1104 int32_t divisor = instr->divisor();
1113 HMod* hmod = instr->hydrogen();
1114 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1115 Label dividend_is_not_negative, done;
1117 __ test(dividend, dividend);
1118 __ j(
not_sign, ÷nd_is_not_negative, Label::kNear);
1121 __ and_(dividend, mask);
1126 __ jmp(&done, Label::kNear);
1129 __ bind(÷nd_is_not_negative);
1130 __ and_(dividend, mask);
1135 void LCodeGen::DoModByConstI(LModByConstI* instr) {
1136 Register dividend =
ToRegister(instr->dividend());
1137 int32_t divisor = instr->divisor();
1145 __ TruncatingDiv(dividend,
Abs(divisor));
1147 __ mov(
eax, dividend);
1151 HMod* hmod = instr->hydrogen();
1153 Label remainder_not_zero;
1154 __ j(
not_zero, &remainder_not_zero, Label::kNear);
1155 __ cmp(dividend, Immediate(0));
1157 __ bind(&remainder_not_zero);
1162 void LCodeGen::DoModI(LModI* instr) {
1163 HMod* hmod = instr->hydrogen();
1165 Register left_reg =
ToRegister(instr->left());
1167 Register right_reg =
ToRegister(instr->right());
1170 Register result_reg =
ToRegister(instr->result());
1177 __ test(right_reg, Operand(right_reg));
1184 Label no_overflow_possible;
1186 __ j(
not_equal, &no_overflow_possible, Label::kNear);
1187 __ cmp(right_reg, -1);
1191 __ j(
not_equal, &no_overflow_possible, Label::kNear);
1192 __ Move(result_reg, Immediate(0));
1193 __ jmp(&done, Label::kNear);
1195 __ bind(&no_overflow_possible);
1203 Label positive_left;
1204 __ test(left_reg, Operand(left_reg));
1205 __ j(
not_sign, &positive_left, Label::kNear);
1207 __ test(result_reg, Operand(result_reg));
1209 __ jmp(&done, Label::kNear);
1210 __ bind(&positive_left);
1217 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
1218 Register dividend =
ToRegister(instr->dividend());
1219 int32_t divisor = instr->divisor();
1220 Register result =
ToRegister(instr->result());
1222 DCHECK(!result.is(dividend));
1225 HDiv* hdiv = instr->hydrogen();
1227 __ test(dividend, dividend);
1237 divisor != 1 && divisor != -1) {
1238 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1239 __ test(dividend, Immediate(mask));
1242 __ Move(result, dividend);
1246 if (
shift > 1)
__ sar(result, 31);
1248 __ add(result, dividend);
1251 if (divisor < 0)
__ neg(result);
1255 void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
1256 Register dividend =
ToRegister(instr->dividend());
1257 int32_t divisor = instr->divisor();
1266 HDiv* hdiv = instr->hydrogen();
1268 __ test(dividend, dividend);
1272 __ TruncatingDiv(dividend,
Abs(divisor));
1273 if (divisor < 0)
__ neg(
edx);
1278 __ sub(
eax, dividend);
1285 void LCodeGen::DoDivI(LDivI* instr) {
1286 HBinaryOperation* hdiv = instr->hydrogen();
1287 Register dividend =
ToRegister(instr->dividend());
1288 Register divisor =
ToRegister(instr->divisor());
1289 Register remainder =
ToRegister(instr->temp());
1298 __ test(divisor, divisor);
1304 Label dividend_not_zero;
1305 __ test(dividend, dividend);
1306 __ j(
not_zero, ÷nd_not_zero, Label::kNear);
1307 __ test(divisor, divisor);
1309 __ bind(÷nd_not_zero);
1314 Label dividend_not_min_int;
1316 __ j(
not_zero, ÷nd_not_min_int, Label::kNear);
1317 __ cmp(divisor, -1);
1319 __ bind(÷nd_not_min_int);
1328 __ test(remainder, remainder);
1334 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
1335 Register dividend =
ToRegister(instr->dividend());
1336 int32_t divisor = instr->divisor();
1341 if (divisor == 1)
return;
1355 if (divisor == -1) {
1368 Label not_kmin_int, done;
1370 __ mov(dividend, Immediate(
kMinInt / divisor));
1371 __ jmp(&done, Label::kNear);
1372 __ bind(¬_kmin_int);
1378 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
1379 Register dividend =
ToRegister(instr->dividend());
1380 int32_t divisor = instr->divisor();
1389 HMathFloorOfDiv* hdiv = instr->hydrogen();
1391 __ test(dividend, dividend);
1399 __ TruncatingDiv(dividend,
Abs(divisor));
1400 if (divisor < 0)
__ neg(
edx);
1407 DCHECK(!temp.is(dividend) && !temp.is(
eax) && !temp.is(
edx));
1408 Label needs_adjustment, done;
1409 __ cmp(dividend, Immediate(0));
1410 __ j(divisor > 0 ?
less :
greater, &needs_adjustment, Label::kNear);
1411 __ TruncatingDiv(dividend,
Abs(divisor));
1412 if (divisor < 0)
__ neg(
edx);
1413 __ jmp(&done, Label::kNear);
1414 __ bind(&needs_adjustment);
1415 __ lea(temp, Operand(dividend, divisor > 0 ? 1 : -1));
1416 __ TruncatingDiv(temp,
Abs(divisor));
1417 if (divisor < 0)
__ neg(
edx);
1424 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
1425 HBinaryOperation* hdiv = instr->hydrogen();
1426 Register dividend =
ToRegister(instr->dividend());
1427 Register divisor =
ToRegister(instr->divisor());
1428 Register remainder =
ToRegister(instr->temp());
1429 Register result =
ToRegister(instr->result());
1438 __ test(divisor, divisor);
1444 Label dividend_not_zero;
1445 __ test(dividend, dividend);
1446 __ j(
not_zero, ÷nd_not_zero, Label::kNear);
1447 __ test(divisor, divisor);
1449 __ bind(÷nd_not_zero);
1454 Label dividend_not_min_int;
1456 __ j(
not_zero, ÷nd_not_min_int, Label::kNear);
1457 __ cmp(divisor, -1);
1459 __ bind(÷nd_not_min_int);
1467 __ test(remainder, remainder);
1468 __ j(
zero, &done, Label::kNear);
1469 __ xor_(remainder, divisor);
1470 __ sar(remainder, 31);
1471 __ add(result, remainder);
1476 void LCodeGen::DoMulI(LMulI* instr) {
1478 LOperand* right = instr->right();
1484 if (right->IsConstantOperand()) {
1488 int constant =
ToInteger32(LConstantOperand::cast(right));
1489 if (constant == -1) {
1491 }
else if (constant == 0) {
1492 __ xor_(left, Operand(left));
1493 }
else if (constant == 2) {
1494 __ add(left, Operand(left));
1504 __ lea(left, Operand(left, left,
times_2, 0));
1510 __ lea(left, Operand(left, left,
times_4, 0));
1516 __ lea(left, Operand(left, left,
times_8, 0));
1522 __ imul(left, left, constant);
1526 __ imul(left, left, constant);
1529 if (instr->hydrogen()->representation().IsSmi()) {
1542 __ test(left, Operand(left));
1544 if (right->IsConstantOperand()) {
1545 if (
ToInteger32(LConstantOperand::cast(right)) < 0) {
1547 }
else if (
ToInteger32(LConstantOperand::cast(right)) == 0) {
1561 void LCodeGen::DoBitI(LBitI* instr) {
1562 LOperand* left = instr->left();
1563 LOperand* right = instr->right();
1564 DCHECK(left->Equals(instr->result()));
1565 DCHECK(left->IsRegister());
1567 if (right->IsConstantOperand()) {
1570 instr->hydrogen()->representation());
1571 switch (instr->op()) {
1572 case Token::BIT_AND:
1578 case Token::BIT_XOR:
1579 if (right_operand ==
int32_t(~0)) {
1590 switch (instr->op()) {
1591 case Token::BIT_AND:
1597 case Token::BIT_XOR:
1608 void LCodeGen::DoShiftI(LShiftI* instr) {
1609 LOperand* left = instr->left();
1610 LOperand* right = instr->right();
1611 DCHECK(left->Equals(instr->result()));
1612 DCHECK(left->IsRegister());
1613 if (right->IsRegister()) {
1616 switch (instr->op()) {
1625 if (instr->can_deopt()) {
1638 int value =
ToInteger32(LConstantOperand::cast(right));
1639 uint8_t shift_count =
static_cast<uint8_t
>(value & 0x1F);
1640 switch (instr->op()) {
1642 if (shift_count == 0 && instr->can_deopt()) {
1650 if (shift_count != 0) {
1655 if (shift_count != 0) {
1657 }
else if (instr->can_deopt()) {
1663 if (shift_count != 0) {
1664 if (instr->hydrogen_value()->representation().IsSmi() &&
1665 instr->can_deopt()) {
1666 if (shift_count != 1) {
1684 void LCodeGen::DoSubI(LSubI* instr) {
1685 LOperand* left = instr->left();
1686 LOperand* right = instr->right();
1687 DCHECK(left->Equals(instr->result()));
1689 if (right->IsConstantOperand()) {
1691 ToImmediate(right, instr->hydrogen()->representation()));
1701 void LCodeGen::DoConstantI(LConstantI* instr) {
1702 __ Move(
ToRegister(instr->result()), Immediate(instr->value()));
1706 void LCodeGen::DoConstantS(LConstantS* instr) {
1707 __ Move(
ToRegister(instr->result()), Immediate(instr->value()));
1711 void LCodeGen::DoConstantD(LConstantD* instr) {
1712 double v = instr->value();
1713 uint64_t int_val = bit_cast<uint64_t, double>(v);
1716 DCHECK(instr->result()->IsDoubleRegister());
1724 CpuFeatureScope scope2(masm(),
SSE4_1);
1726 __ Move(temp, Immediate(lower));
1727 __ movd(res, Operand(temp));
1728 __ Move(temp, Immediate(upper));
1729 __ pinsrd(res, Operand(temp), 1);
1732 __ Move(temp, Immediate(upper));
1733 __ pinsrd(res, Operand(temp), 1);
1736 __ Move(temp, Immediate(upper));
1737 __ movd(res, Operand(temp));
1741 __ Move(temp, Immediate(lower));
1742 __ movd(xmm_scratch, Operand(temp));
1743 __ orps(res, xmm_scratch);
1750 void LCodeGen::DoConstantE(LConstantE* instr) {
1751 __ lea(
ToRegister(instr->result()), Operand::StaticVariable(instr->value()));
1755 void LCodeGen::DoConstantT(LConstantT* instr) {
1757 Handle<Object>
object = instr->value(isolate());
1759 __ LoadObject(reg,
object);
1763 void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1764 Register result =
ToRegister(instr->result());
1766 __ EnumLength(result,
map);
1770 void LCodeGen::DoDateField(LDateField* instr) {
1772 Register result =
ToRegister(instr->result());
1773 Register scratch =
ToRegister(instr->temp());
1774 Smi* index = instr->index();
1775 Label runtime, done;
1776 DCHECK(
object.is(result));
1784 if (index->value() == 0) {
1788 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1789 __ mov(scratch, Operand::StaticVariable(stamp));
1794 __ jmp(&done, Label::kNear);
1797 __ PrepareCallCFunction(2, scratch);
1798 __ mov(Operand(
esp, 0),
object);
1800 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1809 if (index->IsConstantOperand()) {
1825 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1827 Register result =
ToRegister(instr->result());
1828 Register
string =
ToRegister(instr->string());
1830 if (FLAG_debug_code) {
1839 ? one_byte_seq_type : two_byte_seq_type));
1840 __ Check(
equal, kUnexpectedStringType);
1846 __ movzx_b(result, operand);
1848 __ movzx_w(result, operand);
1853 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1855 Register
string =
ToRegister(instr->string());
1857 if (FLAG_debug_code) {
1864 ? one_byte_seq_type : two_byte_seq_type;
1865 __ EmitSeqStringSetCharCheck(
string, index, value, encoding_mask);
1869 if (instr->value()->IsConstantOperand()) {
1875 __ mov_b(operand,
static_cast<int8_t
>(value));
1878 __ mov_w(operand,
static_cast<int16_t>(value));
1883 __ mov_b(operand, value);
1885 __ mov_w(operand, value);
1891 void LCodeGen::DoAddI(LAddI* instr) {
1892 LOperand* left = instr->left();
1893 LOperand* right = instr->right();
1895 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1896 if (right->IsConstantOperand()) {
1898 instr->hydrogen()->representation());
1905 if (right->IsConstantOperand()) {
1907 ToImmediate(right, instr->hydrogen()->representation()));
1918 void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
1919 LOperand* left = instr->left();
1920 LOperand* right = instr->right();
1921 DCHECK(left->Equals(instr->result()));
1922 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1923 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
1925 Condition condition = (operation == HMathMinMax::kMathMin)
1928 if (right->IsConstantOperand()) {
1930 Immediate immediate =
ToImmediate(LConstantOperand::cast(instr->right()),
1931 instr->hydrogen()->representation());
1932 __ cmp(left_op, immediate);
1933 __ j(condition, &return_left, Label::kNear);
1934 __ mov(left_op, immediate);
1938 __ cmp(left_reg, right_op);
1939 __ j(condition, &return_left, Label::kNear);
1940 __ mov(left_reg, right_op);
1942 __ bind(&return_left);
1944 DCHECK(instr->hydrogen()->representation().IsDouble());
1945 Label check_nan_left, check_zero, return_left, return_right;
1949 __ ucomisd(left_reg, right_reg);
1951 __ j(
equal, &check_zero, Label::kNear);
1952 __ j(condition, &return_left, Label::kNear);
1953 __ jmp(&return_right, Label::kNear);
1955 __ bind(&check_zero);
1957 __ xorps(xmm_scratch, xmm_scratch);
1958 __ ucomisd(left_reg, xmm_scratch);
1961 if (operation == HMathMinMax::kMathMin) {
1962 __ orpd(left_reg, right_reg);
1965 __ addsd(left_reg, right_reg);
1967 __ jmp(&return_left, Label::kNear);
1969 __ bind(&check_nan_left);
1970 __ ucomisd(left_reg, left_reg);
1972 __ bind(&return_right);
1973 __ movaps(left_reg, right_reg);
1975 __ bind(&return_left);
1980 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
1984 switch (instr->op()) {
1986 __ addsd(left, right);
1989 __ subsd(left, right);
1992 __ mulsd(left, right);
1995 __ divsd(left, right);
1998 __ movaps(left, left);
2002 __ PrepareCallCFunction(4,
eax);
2006 ExternalReference::mod_two_doubles_operation(isolate()),
2012 __ fstp_d(Operand(
esp, 0));
2013 __ movsd(result, Operand(
esp, 0));
2024 void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
2031 CodeFactory::BinaryOpIC(isolate(), instr->op(),
NO_OVERWRITE).code();
2036 template<
class InstrType>
2038 int left_block = instr->TrueDestination(chunk_);
2039 int right_block = instr->FalseDestination(chunk_);
2041 int next_block = GetNextEmittedBlock();
2045 }
else if (left_block == next_block) {
2047 }
else if (right_block == next_block) {
2048 __ j(
cc, chunk_->GetAssemblyLabel(left_block));
2050 __ j(
cc, chunk_->GetAssemblyLabel(left_block));
2051 __ jmp(chunk_->GetAssemblyLabel(right_block));
2056 template<
class InstrType>
2058 int false_block = instr->FalseDestination(chunk_);
2060 __ jmp(chunk_->GetAssemblyLabel(false_block));
2062 __ j(
cc, chunk_->GetAssemblyLabel(false_block));
2067 void LCodeGen::DoBranch(LBranch* instr) {
2068 Representation r = instr->hydrogen()->value()->representation();
2069 if (r.IsSmiOrInteger32()) {
2071 __ test(reg, Operand(reg));
2073 }
else if (r.IsDouble()) {
2074 DCHECK(!info()->IsStub());
2077 __ xorps(xmm_scratch, xmm_scratch);
2078 __ ucomisd(reg, xmm_scratch);
2083 HType type = instr->hydrogen()->value()->type();
2084 if (type.IsBoolean()) {
2085 DCHECK(!info()->IsStub());
2086 __ cmp(reg, factory()->true_value());
2088 }
else if (type.IsSmi()) {
2089 DCHECK(!info()->IsStub());
2090 __ test(reg, Operand(reg));
2092 }
else if (type.IsJSArray()) {
2093 DCHECK(!info()->IsStub());
2095 }
else if (type.IsHeapNumber()) {
2096 DCHECK(!info()->IsStub());
2098 __ xorps(xmm_scratch, xmm_scratch);
2101 }
else if (type.IsString()) {
2102 DCHECK(!info()->IsStub());
2106 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2111 __ cmp(reg, factory()->undefined_value());
2112 __ j(
equal, instr->FalseLabel(chunk_));
2116 __ cmp(reg, factory()->true_value());
2117 __ j(
equal, instr->TrueLabel(chunk_));
2119 __ cmp(reg, factory()->false_value());
2120 __ j(
equal, instr->FalseLabel(chunk_));
2124 __ cmp(reg, factory()->null_value());
2125 __ j(
equal, instr->FalseLabel(chunk_));
2130 __ test(reg, Operand(reg));
2131 __ j(
equal, instr->FalseLabel(chunk_));
2132 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
2133 }
else if (expected.NeedsMap()) {
2140 if (expected.NeedsMap()) {
2145 if (expected.CanBeUndetectable()) {
2166 __ jmp(instr->FalseLabel(chunk_));
2167 __ bind(¬_string);
2173 __ j(
equal, instr->TrueLabel(chunk_));
2178 Label not_heap_number;
2180 factory()->heap_number_map());
2183 __ xorps(xmm_scratch, xmm_scratch);
2185 __ j(
zero, instr->FalseLabel(chunk_));
2186 __ jmp(instr->TrueLabel(chunk_));
2187 __ bind(¬_heap_number);
2190 if (!expected.IsGeneric()) {
2207 void LCodeGen::DoGoto(LGoto* instr) {
2216 case Token::EQ_STRICT:
2220 case Token::NE_STRICT:
2236 case Token::INSTANCEOF:
2244 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
2245 LOperand* left = instr->left();
2246 LOperand* right = instr->right();
2248 instr->is_double() ||
2253 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2255 double left_val =
ToDouble(LConstantOperand::cast(left));
2256 double right_val =
ToDouble(LConstantOperand::cast(right));
2257 int next_block =
EvalComparison(instr->op(), left_val, right_val) ?
2258 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
2261 if (instr->is_double()) {
2267 if (right->IsConstantOperand()) {
2269 ToImmediate(right, instr->hydrogen()->representation()));
2270 }
else if (left->IsConstantOperand()) {
2272 ToImmediate(left, instr->hydrogen()->representation()));
2284 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
2287 if (instr->right()->IsConstantOperand()) {
2288 Handle<Object> right =
ToHandle(LConstantOperand::cast(instr->right()));
2289 __ CmpObject(left, right);
2291 Operand right =
ToOperand(instr->right());
2292 __ cmp(left, right);
2298 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2299 if (instr->hydrogen()->representation().IsTagged()) {
2300 Register input_reg =
ToRegister(instr->object());
2301 __ cmp(input_reg, factory()->the_hole_value());
2307 __ ucomisd(input_reg, input_reg);
2320 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2321 Representation rep = instr->hydrogen()->value()->representation();
2322 DCHECK(!rep.IsInteger32());
2323 Register scratch =
ToRegister(instr->temp());
2325 if (rep.IsDouble()) {
2328 __ xorps(xmm_scratch, xmm_scratch);
2329 __ ucomisd(xmm_scratch, value);
2331 __ movmskpd(scratch, value);
2332 __ test(scratch, Immediate(1));
2336 Handle<Map>
map = masm()->isolate()->factory()->heap_number_map();
2342 Immediate(0x00000000));
2350 Label* is_not_object,
2352 __ JumpIfSmi(input, is_not_object);
2354 __ cmp(input, isolate()->factory()->null_value());
2371 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
2376 reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
2384 Label* is_not_string,
2387 __ JumpIfSmi(input, is_not_string);
2390 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2396 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
2401 instr->hydrogen()->value()->type().IsHeapObject()
2405 reg, temp, instr->FalseLabel(chunk_), check_needed);
2411 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
2412 Operand input =
ToOperand(instr->value());
2419 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
2423 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2425 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2436 case Token::EQ_STRICT:
2454 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2457 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2487 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2491 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2492 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2495 __ CmpObjectType(input,
TestType(instr->hydrogen()), temp);
2500 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2502 Register result =
ToRegister(instr->result());
2504 __ AssertString(input);
2507 __ IndexFromHash(result, result);
2511 void LCodeGen::DoHasCachedArrayIndexAndBranch(
2512 LHasCachedArrayIndexAndBranch* instr) {
2525 Handle<String>class_name,
2530 DCHECK(!input.is(temp2));
2532 __ JumpIfSmi(input, is_false);
2534 if (
String::Equals(isolate()->factory()->Function_string(), class_name)) {
2564 if (
String::Equals(class_name, isolate()->factory()->Object_string())) {
2581 __ cmp(temp, class_name);
2586 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
2591 Handle<String> class_name = instr->hydrogen()->class_name();
2594 class_name, input, temp, temp2);
2600 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
2607 void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
2613 Label true_value, done;
2615 __ j(
zero, &true_value, Label::kNear);
2616 __ mov(
ToRegister(instr->result()), factory()->false_value());
2617 __ jmp(&done, Label::kNear);
2618 __ bind(&true_value);
2619 __ mov(
ToRegister(instr->result()), factory()->true_value());
2624 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2627 DeferredInstanceOfKnownGlobal(
LCodeGen* codegen,
2628 LInstanceOfKnownGlobal* instr)
2631 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
2633 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
2634 Label* map_check() {
return &map_check_; }
2636 LInstanceOfKnownGlobal* instr_;
2640 DeferredInstanceOfKnownGlobal* deferred;
2641 deferred =
new(zone()) DeferredInstanceOfKnownGlobal(
this, instr);
2643 Label done, false_result;
2644 Register
object =
ToRegister(instr->value());
2648 __ JumpIfSmi(
object, &false_result, Label::kNear);
2656 __ bind(deferred->map_check());
2657 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2658 __ cmp(
map, Operand::ForCell(cache_cell));
2660 __ mov(
eax, factory()->the_hole_value());
2661 __ jmp(&done, Label::kNear);
2665 __ bind(&cache_miss);
2667 __ cmp(
object, factory()->null_value());
2668 __ j(
equal, &false_result, Label::kNear);
2671 Condition is_string = masm_->IsObjectStringType(
object, temp, temp);
2672 __ j(is_string, &false_result, Label::kNear);
2675 __ jmp(deferred->entry());
2677 __ bind(&false_result);
2678 __ mov(
ToRegister(instr->result()), factory()->false_value());
2682 __ bind(deferred->exit());
2689 PushSafepointRegistersScope
scope(
this);
2698 InstanceofStub stub(isolate(),
flags);
2707 static const int kAdditionalDelta = 13;
2708 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
2709 __ mov(temp, Immediate(delta));
2710 __ StoreToSafepointRegisterSlot(temp, temp);
2717 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
2718 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2721 __ StoreToSafepointRegisterSlot(
eax,
eax);
2725 void LCodeGen::DoCmpT(LCmpT* instr) {
2728 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2732 Label true_value, done;
2734 __ j(condition, &true_value, Label::kNear);
2735 __ mov(
ToRegister(instr->result()), factory()->false_value());
2736 __ jmp(&done, Label::kNear);
2737 __ bind(&true_value);
2738 __ mov(
ToRegister(instr->result()), factory()->true_value());
2744 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
2746 if (instr->has_constant_parameter_count()) {
2747 int parameter_count =
ToInteger32(instr->constant_parameter_count());
2748 if (dynamic_frame_alignment && FLAG_debug_code) {
2752 __ Assert(
equal, kExpectedAlignmentMarker);
2756 Register reg =
ToRegister(instr->parameter_count());
2759 Register return_addr_reg = reg.is(
ecx) ?
ebx :
ecx;
2760 if (dynamic_frame_alignment && FLAG_debug_code) {
2761 DCHECK(extra_value_count == 2);
2765 __ Assert(
equal, kExpectedAlignmentMarker);
2769 __ pop(return_addr_reg);
2770 if (dynamic_frame_alignment) {
2775 __ jmp(return_addr_reg);
2780 void LCodeGen::DoReturn(LReturn* instr) {
2781 if (FLAG_trace && info()->IsOptimizing()) {
2796 int no_frame_start = -1;
2800 no_frame_start = masm_->pc_offset();
2805 __ j(
equal, &no_padding, Label::kNear);
2808 __ bind(&no_padding);
2812 if (no_frame_start != -1) {
2813 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2818 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2819 Register result =
ToRegister(instr->result());
2820 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
2821 if (instr->hydrogen()->RequiresHoleCheck()) {
2822 __ cmp(result, factory()->the_hole_value());
2831 Register vector =
ToRegister(instr->temp_vector());
2833 __ mov(vector, instr->hydrogen()->feedback_vector());
2841 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2848 if (FLAG_vector_ics) {
2849 EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
2852 Handle<Code> ic = CodeFactory::LoadIC(isolate(),
mode).code();
2857 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2859 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle();
2865 if (instr->hydrogen()->RequiresHoleCheck()) {
2866 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
2871 __ mov(Operand::ForCell(cell_handle), value);
2876 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2877 Register context =
ToRegister(instr->context());
2878 Register result =
ToRegister(instr->result());
2881 if (instr->hydrogen()->RequiresHoleCheck()) {
2882 __ cmp(result, factory()->the_hole_value());
2883 if (instr->hydrogen()->DeoptimizesOnHole()) {
2888 __ mov(result, factory()->undefined_value());
2889 __ bind(&is_not_hole);
2895 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2896 Register context =
ToRegister(instr->context());
2899 Label skip_assignment;
2902 if (instr->hydrogen()->RequiresHoleCheck()) {
2903 __ cmp(target, factory()->the_hole_value());
2904 if (instr->hydrogen()->DeoptimizesOnHole()) {
2911 __ mov(target, value);
2912 if (instr->hydrogen()->NeedsWriteBarrier()) {
2914 instr->hydrogen()->value()->type().IsHeapObject()
2918 __ RecordWriteContextSlot(context,
2927 __ bind(&skip_assignment);
2931 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
2932 HObjectAccess access = instr->hydrogen()->access();
2933 int offset = access.offset();
2935 if (access.IsExternalMemory()) {
2936 Register result =
ToRegister(instr->result());
2937 MemOperand operand = instr->object()->IsConstantOperand()
2939 LConstantOperand::cast(instr->object())))
2941 __ Load(result, operand, access.representation());
2945 Register
object =
ToRegister(instr->object());
2946 if (instr->hydrogen()->representation().IsDouble()) {
2952 Register result =
ToRegister(instr->result());
2953 if (!access.IsInobject()) {
2957 __ Load(result,
FieldOperand(
object, offset), access.representation());
2962 DCHECK(!operand->IsDoubleRegister());
2963 if (operand->IsConstantOperand()) {
2964 Handle<Object>
object =
ToHandle(LConstantOperand::cast(operand));
2966 if (object->IsSmi()) {
2971 }
else if (operand->IsRegister()) {
2979 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
2985 if (FLAG_vector_ics) {
2986 EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
2988 Handle<Code> ic = CodeFactory::LoadIC(isolate(),
NOT_CONTEXTUAL).code();
2993 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2994 Register
function =
ToRegister(instr->function());
2996 Register result =
ToRegister(instr->result());
3003 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
3019 void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3020 Register result =
ToRegister(instr->result());
3021 __ LoadRoot(result, instr->index());
3025 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3026 Register arguments =
ToRegister(instr->arguments());
3027 Register result =
ToRegister(instr->result());
3028 if (instr->length()->IsConstantOperand() &&
3029 instr->index()->IsConstantOperand()) {
3030 int const_index =
ToInteger32(LConstantOperand::cast(instr->index()));
3031 int const_length =
ToInteger32(LConstantOperand::cast(instr->length()));
3032 int index = (const_length - const_index) + 1;
3035 Register length =
ToRegister(instr->length());
3036 Operand index =
ToOperand(instr->index());
3039 __ sub(length, index);
3047 LOperand* key = instr->key();
3048 if (!key->IsConstantOperand() &&
3056 instr->hydrogen()->key()->representation(),
3058 instr->base_offset()));
3062 __ movss(result, operand);
3063 __ cvtss2sd(result, result);
3068 Register result(
ToRegister(instr->result()));
3069 switch (elements_kind) {
3072 __ movsx_b(result, operand);
3078 __ movzx_b(result, operand);
3082 __ movsx_w(result, operand);
3086 __ movzx_w(result, operand);
3090 __ mov(result, operand);
3094 __ mov(result, operand);
3096 __ test(result, Operand(result));
3120 if (instr->hydrogen()->RequiresHoleCheck()) {
3122 instr->elements(), instr->key(),
3123 instr->hydrogen()->key()->representation(),
3133 instr->hydrogen()->key()->representation(),
3135 instr->base_offset());
3137 __ movsd(result, double_load_operand);
3142 Register result =
ToRegister(instr->result());
3147 instr->hydrogen()->key()->representation(),
3151 if (instr->hydrogen()->RequiresHoleCheck()) {
3156 __ cmp(result, factory()->the_hole_value());
3163 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3164 if (instr->is_typed_elements()) {
3166 }
else if (instr->hydrogen()->representation().IsDouble()) {
3175 LOperand* elements_pointer,
3177 Representation key_representation,
3180 Register elements_pointer_reg =
ToRegister(elements_pointer);
3182 int shift_size = element_shift_size;
3183 if (key->IsConstantOperand()) {
3184 int constant_value =
ToInteger32(LConstantOperand::cast(key));
3185 if (constant_value & 0xF0000000) {
3186 Abort(kArrayIndexConstantValueTooBig);
3188 return Operand(elements_pointer_reg,
3189 ((constant_value) << shift_size)
3193 if (key_representation.IsSmi() && (shift_size >= 1)) {
3197 return Operand(elements_pointer_reg,
3205 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3210 if (FLAG_vector_ics) {
3211 EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
3214 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
3219 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3220 Register result =
ToRegister(instr->result());
3222 if (instr->hydrogen()->from_inlined()) {
3226 Label done, adapted;
3229 __ cmp(Operand(result),
3231 __ j(
equal, &adapted, Label::kNear);
3234 __ mov(result, Operand(
ebp));
3235 __ jmp(&done, Label::kNear);
3248 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
3249 Operand elem =
ToOperand(instr->elements());
3250 Register result =
ToRegister(instr->result());
3256 __ mov(result, Immediate(
scope()->num_parameters()));
3257 __ j(
equal, &done, Label::kNear);
3261 __ mov(result, Operand(result,
3263 __ SmiUntag(result);
3270 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
3271 Register receiver =
ToRegister(instr->receiver());
3272 Register
function =
ToRegister(instr->function());
3277 Label receiver_ok, global_object;
3279 Register scratch =
ToRegister(instr->temp());
3281 if (!instr->hydrogen()->known_function()) {
3286 __ test_b(
FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3291 __ test_b(
FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3297 __ cmp(receiver, factory()->null_value());
3298 __ j(
equal, &global_object, Label::kNear);
3299 __ cmp(receiver, factory()->undefined_value());
3300 __ j(
equal, &global_object, Label::kNear);
3308 __ jmp(&receiver_ok, Label::kNear);
3309 __ bind(&global_object);
3312 __ mov(receiver, Operand(receiver, global_offset));
3315 __ bind(&receiver_ok);
3319 void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3320 Register receiver =
ToRegister(instr->receiver());
3321 Register
function =
ToRegister(instr->function());
3322 Register length =
ToRegister(instr->length());
3323 Register elements =
ToRegister(instr->elements());
3331 __ cmp(length, kArgumentsLimit);
3335 __ mov(receiver, length);
3341 __ test(length, Operand(length));
3342 __ j(
zero, &invoke, Label::kNear);
3350 DCHECK(instr->HasPointerMap());
3351 LPointerMap* pointers = instr->pointer_map();
3353 this, pointers, Safepoint::kLazyDeopt);
3354 ParameterCount actual(
eax);
3355 __ InvokeFunction(
function, actual,
CALL_FUNCTION, safepoint_generator);
3359 void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
3364 void LCodeGen::DoPushArgument(LPushArgument* instr) {
3365 LOperand* argument = instr->value();
3370 void LCodeGen::DoDrop(LDrop* instr) {
3371 __ Drop(instr->count());
3375 void LCodeGen::DoThisFunction(LThisFunction* instr) {
3376 Register result =
ToRegister(instr->result());
3381 void LCodeGen::DoContext(LContext* instr) {
3382 Register result =
ToRegister(instr->result());
3383 if (info()->IsOptimizing()) {
3392 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3395 __ push(Immediate(instr->hydrogen()->pairs()));
3402 int formal_parameter_count,
3404 LInstruction* instr,
3405 EDIState edi_state) {
3406 bool dont_adapt_arguments =
3408 bool can_invoke_directly =
3409 dont_adapt_arguments || formal_parameter_count == arity;
3411 if (can_invoke_directly) {
3413 __ LoadHeapObject(
edi,
function);
3421 if (dont_adapt_arguments) {
3426 if (
function.is_identical_to(info()->closure())) {
3434 LPointerMap* pointers = instr->pointer_map();
3436 this, pointers, Safepoint::kLazyDeopt);
3437 ParameterCount count(arity);
3438 ParameterCount expected(formal_parameter_count);
3439 __ InvokeFunction(
function, expected, count,
CALL_FUNCTION, generator);
3444 void LCodeGen::DoTailCallThroughMegamorphicCache(
3445 LTailCallThroughMegamorphicCache* instr) {
3446 Register receiver =
ToRegister(instr->receiver());
3451 Register scratch =
ebx;
3452 Register extra =
eax;
3453 DCHECK(!scratch.is(receiver) && !scratch.is(
name));
3454 DCHECK(!extra.is(receiver) && !extra.is(
name));
3460 isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
3461 must_teardown_frame, receiver,
name,
3465 if (must_teardown_frame)
__ leave();
3470 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
3473 LPointerMap* pointers = instr->pointer_map();
3476 if (instr->target()->IsConstantOperand()) {
3477 LConstantOperand* target = LConstantOperand::cast(instr->target());
3482 DCHECK(instr->target()->IsRegister());
3483 Register target =
ToRegister(instr->target());
3484 generator.BeforeCall(
__ CallSize(Operand(target)));
3488 generator.AfterCall();
3492 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
3496 if (instr->hydrogen()->pass_argument_count()) {
3497 __ mov(
eax, instr->arity());
3503 bool is_self_call =
false;
3504 if (instr->hydrogen()->function()->IsConstant()) {
3505 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
3506 Handle<JSFunction> jsfun =
3508 is_self_call = jsfun.is_identical_to(info()->closure());
3522 Register input_reg =
ToRegister(instr->value());
3524 factory()->heap_number_map());
3527 Label slow, allocated, done;
3528 Register tmp = input_reg.is(
eax) ?
ecx :
eax;
3532 PushSafepointRegistersScope
scope(
this);
3534 __ mov(tmp,
FieldOperand(input_reg, HeapNumber::kExponentOffset));
3540 __ j(
zero, &done, Label::kNear);
3542 __ AllocateHeapNumber(tmp, tmp2,
no_reg, &slow);
3543 __ jmp(&allocated, Label::kNear);
3548 instr, instr->context());
3550 if (!tmp.is(
eax))
__ mov(tmp,
eax);
3552 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3554 __ bind(&allocated);
3555 __ mov(tmp2,
FieldOperand(input_reg, HeapNumber::kExponentOffset));
3558 __ mov(tmp2,
FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3560 __ StoreToSafepointRegisterSlot(input_reg, tmp);
3567 Register input_reg =
ToRegister(instr->value());
3568 __ test(input_reg, Operand(input_reg));
3573 __ bind(&is_positive);
3577 void LCodeGen::DoMathAbs(LMathAbs* instr) {
3581 DeferredMathAbsTaggedHeapNumber(
LCodeGen* codegen,
3585 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3587 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
3592 DCHECK(instr->value()->Equals(instr->result()));
3593 Representation r = instr->hydrogen()->value()->representation();
3598 __ xorps(scratch, scratch);
3599 __ subsd(scratch, input_reg);
3600 __ andps(input_reg, scratch);
3601 }
else if (r.IsSmiOrInteger32()) {
3604 DeferredMathAbsTaggedHeapNumber* deferred =
3605 new(zone()) DeferredMathAbsTaggedHeapNumber(
this, instr);
3606 Register input_reg =
ToRegister(instr->value());
3608 __ JumpIfNotSmi(input_reg, deferred->entry());
3610 __ bind(deferred->exit());
3615 void LCodeGen::DoMathFloor(LMathFloor* instr) {
3617 Register output_reg =
ToRegister(instr->result());
3625 __ xorps(xmm_scratch, xmm_scratch);
3626 __ ucomisd(input_reg, xmm_scratch);
3628 __ movmskpd(output_reg, input_reg);
3629 __ test(output_reg, Immediate(1));
3634 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3636 __ cmp(output_reg, 0x1);
3639 Label negative_sign, done;
3641 __ xorps(xmm_scratch, xmm_scratch);
3642 __ ucomisd(input_reg, xmm_scratch);
3644 __ j(
below, &negative_sign, Label::kNear);
3648 Label positive_sign;
3649 __ j(
above, &positive_sign, Label::kNear);
3650 __ movmskpd(output_reg, input_reg);
3651 __ test(output_reg, Immediate(1));
3653 __ Move(output_reg, Immediate(0));
3654 __ jmp(&done, Label::kNear);
3655 __ bind(&positive_sign);
3659 __ cvttsd2si(output_reg, Operand(input_reg));
3661 __ cmp(output_reg, 0x1);
3663 __ jmp(&done, Label::kNear);
3666 __ bind(&negative_sign);
3668 __ cvttsd2si(output_reg, Operand(input_reg));
3669 __ Cvtsi2sd(xmm_scratch, output_reg);
3670 __ ucomisd(input_reg, xmm_scratch);
3671 __ j(
equal, &done, Label::kNear);
3672 __ sub(output_reg, Immediate(1));
3680 void LCodeGen::DoMathRound(LMathRound* instr) {
3681 Register output_reg =
ToRegister(instr->result());
3685 ExternalReference one_half = ExternalReference::address_of_one_half();
3686 ExternalReference minus_one_half =
3687 ExternalReference::address_of_minus_one_half();
3689 Label done, round_to_zero, below_one_half, do_not_compensate;
3692 __ movsd(xmm_scratch, Operand::StaticVariable(one_half));
3693 __ ucomisd(xmm_scratch, input_reg);
3694 __ j(
above, &below_one_half, Label::kNear);
3697 __ addsd(xmm_scratch, input_reg);
3698 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3700 __ cmp(output_reg, 0x1);
3702 __ jmp(&done, dist);
3704 __ bind(&below_one_half);
3705 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half));
3706 __ ucomisd(xmm_scratch, input_reg);
3711 __ movaps(input_temp, input_reg);
3712 __ subsd(input_temp, xmm_scratch);
3713 __ cvttsd2si(output_reg, Operand(input_temp));
3715 __ cmp(output_reg, 0x1);
3718 __ Cvtsi2sd(xmm_scratch, output_reg);
3719 __ ucomisd(xmm_scratch, input_temp);
3721 __ sub(output_reg, Immediate(1));
3723 __ jmp(&done, dist);
3725 __ bind(&round_to_zero);
3730 __ movmskpd(output_reg, input_reg);
3731 __ test(output_reg, Immediate(1));
3734 __ Move(output_reg, Immediate(0));
3739 void LCodeGen::DoMathFround(LMathFround* instr) {
3742 __ cvtsd2ss(output_reg, input_reg);
3743 __ cvtss2sd(output_reg, output_reg);
3747 void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
3748 Operand input =
ToOperand(instr->value());
3750 __ sqrtsd(output, input);
3754 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
3757 Register scratch =
ToRegister(instr->temp());
3766 __ mov(scratch, 0xFF800000);
3767 __ movd(xmm_scratch, scratch);
3768 __ cvtss2sd(xmm_scratch, xmm_scratch);
3769 __ ucomisd(input_reg, xmm_scratch);
3773 __ j(
carry, &sqrt, Label::kNear);
3775 __ xorps(input_reg, input_reg);
3776 __ subsd(input_reg, xmm_scratch);
3777 __ jmp(&done, Label::kNear);
3781 __ xorps(xmm_scratch, xmm_scratch);
3782 __ addsd(input_reg, xmm_scratch);
3783 __ sqrtsd(input_reg, input_reg);
3788 void LCodeGen::DoPower(LPower* instr) {
3789 Representation exponent_type = instr->hydrogen()->right()->representation();
3793 DCHECK(!instr->right()->IsDoubleRegister() ||
3795 DCHECK(!instr->right()->IsRegister() ||
3800 if (exponent_type.IsSmi()) {
3803 }
else if (exponent_type.IsTagged()) {
3805 __ JumpIfSmi(tagged_exponent, &no_deopt);
3812 }
else if (exponent_type.IsInteger32()) {
3816 DCHECK(exponent_type.IsDouble());
3823 void LCodeGen::DoMathLog(LMathLog* instr) {
3824 DCHECK(instr->value()->Equals(instr->result()));
3828 __ xorps(xmm_scratch, xmm_scratch);
3829 __ ucomisd(input_reg, xmm_scratch);
3832 ExternalReference nan =
3833 ExternalReference::address_of_canonical_non_hole_nan();
3834 __ movsd(input_reg, Operand::StaticVariable(nan));
3835 __ jmp(&done, Label::kNear);
3837 ExternalReference ninf =
3838 ExternalReference::address_of_negative_infinity();
3839 __ movsd(input_reg, Operand::StaticVariable(ninf));
3840 __ jmp(&done, Label::kNear);
3844 __ movsd(Operand(
esp, 0), input_reg);
3845 __ fld_d(Operand(
esp, 0));
3847 __ fstp_d(Operand(
esp, 0));
3848 __ movsd(input_reg, Operand(
esp, 0));
3854 void LCodeGen::DoMathClz32(LMathClz32* instr) {
3856 Register result =
ToRegister(instr->result());
3857 Label not_zero_input;
3858 __ bsr(result, input);
3861 __ Move(result, Immediate(63));
3863 __ bind(¬_zero_input);
3864 __ xor_(result, Immediate(31));
3868 void LCodeGen::DoMathExp(LMathExp* instr) {
3879 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3882 DCHECK(instr->HasPointerMap());
3884 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3885 if (known_function.is_null()) {
3886 LPointerMap* pointers = instr->pointer_map();
3888 this, pointers, Safepoint::kLazyDeopt);
3889 ParameterCount count(instr->arity());
3893 instr->hydrogen()->formal_parameter_count(),
3901 void LCodeGen::DoCallFunction(LCallFunction* instr) {
3906 int arity = instr->arity();
3907 CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
3912 void LCodeGen::DoCallNew(LCallNew* instr) {
3918 __ mov(
ebx, isolate()->factory()->undefined_value());
3920 __ Move(
eax, Immediate(instr->arity()));
3925 void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
3930 __ Move(
eax, Immediate(instr->arity()));
3931 __ mov(
ebx, isolate()->factory()->undefined_value());
3932 ElementsKind kind = instr->hydrogen()->elements_kind();
3938 if (instr->arity() == 0) {
3939 ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode);
3941 }
else if (instr->arity() == 1) {
3949 __ j(
zero, &packed_case, Label::kNear);
3952 ArraySingleArgumentConstructorStub stub(isolate(),
3956 __ jmp(&done, Label::kNear);
3957 __ bind(&packed_case);
3960 ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode);
3964 ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
3970 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
3972 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
3976 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
3977 Register
function =
ToRegister(instr->function());
3978 Register code_object =
ToRegister(instr->code_object());
3984 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3985 Register result =
ToRegister(instr->result());
3986 Register base =
ToRegister(instr->base_object());
3987 if (instr->offset()->IsConstantOperand()) {
3988 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
3991 Register offset =
ToRegister(instr->offset());
3992 __ lea(result, Operand(base, offset,
times_1, 0));
3997 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3998 Representation representation = instr->hydrogen()->field_representation();
4000 HObjectAccess access = instr->hydrogen()->access();
4001 int offset = access.offset();
4003 if (access.IsExternalMemory()) {
4004 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4005 MemOperand operand = instr->object()->IsConstantOperand()
4006 ? MemOperand::StaticVariable(
4009 if (instr->value()->IsConstantOperand()) {
4010 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4014 __ Store(value, operand, representation);
4019 Register
object =
ToRegister(instr->object());
4020 __ AssertNotSmi(
object);
4022 DCHECK(!representation.IsSmi() ||
4023 !instr->value()->IsConstantOperand() ||
4024 IsSmi(LConstantOperand::cast(instr->value())));
4025 if (representation.IsDouble()) {
4026 DCHECK(access.IsInobject());
4027 DCHECK(!instr->hydrogen()->has_transition());
4028 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4034 if (instr->hydrogen()->has_transition()) {
4035 Handle<Map> transition = instr->hydrogen()->transition_map();
4036 AddDeprecationDependency(transition);
4038 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
4040 Register temp_map =
ToRegister(instr->temp_map());
4042 __ RecordWriteForMap(
object, transition, temp_map, temp,
kSaveFPRegs);
4047 Register write_register = object;
4048 if (!access.IsInobject()) {
4054 if (instr->value()->IsConstantOperand()) {
4055 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4056 if (operand_value->IsRegister()) {
4058 __ Store(value, operand, representation);
4059 }
else if (representation.IsInteger32()) {
4060 Immediate immediate =
ToImmediate(operand_value, representation);
4061 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4062 __ mov(operand, immediate);
4064 Handle<Object> handle_value =
ToHandle(operand_value);
4065 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4066 __ mov(operand, handle_value);
4070 __ Store(value, operand, representation);
4073 if (instr->hydrogen()->NeedsWriteBarrier()) {
4075 Register temp = access.IsInobject() ?
ToRegister(instr->temp()) : object;
4077 __ RecordWriteField(write_register,
4083 instr->hydrogen()->SmiCheckForWriteBarrier(),
4084 instr->hydrogen()->PointersToHereCheckForValue());
4089 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
4100 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
4102 if (instr->index()->IsConstantOperand()) {
4104 ToImmediate(LConstantOperand::cast(instr->index()),
4105 instr->hydrogen()->length()->representation()));
4107 }
else if (instr->length()->IsConstantOperand()) {
4109 ToImmediate(LConstantOperand::cast(instr->length()),
4110 instr->hydrogen()->index()->representation()));
4114 if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
4127 LOperand* key = instr->key();
4128 if (!key->IsConstantOperand() &&
4136 instr->hydrogen()->key()->representation(),
4138 instr->base_offset()));
4143 __ movss(operand, xmm_scratch);
4149 switch (elements_kind) {
4156 __ mov_b(operand, value);
4162 __ mov_w(operand, value);
4168 __ mov(operand, value);
4190 ExternalReference canonical_nan_reference =
4191 ExternalReference::address_of_canonical_non_hole_nan();
4195 instr->hydrogen()->key()->representation(),
4197 instr->base_offset());
4201 if (instr->NeedsCanonicalization()) {
4204 __ ucomisd(value, value);
4207 __ movsd(value, Operand::StaticVariable(canonical_nan_reference));
4208 __ bind(&have_value);
4211 __ movsd(double_store_operand, value);
4216 Register elements =
ToRegister(instr->elements());
4217 Register key = instr->key()->IsRegister() ?
ToRegister(instr->key()) :
no_reg;
4222 instr->hydrogen()->key()->representation(),
4224 instr->base_offset());
4225 if (instr->value()->IsRegister()) {
4228 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4229 if (
IsSmi(operand_value)) {
4231 __ mov(operand, immediate);
4234 Handle<Object> handle_value =
ToHandle(operand_value);
4235 __ mov(operand, handle_value);
4239 if (instr->hydrogen()->NeedsWriteBarrier()) {
4240 DCHECK(instr->value()->IsRegister());
4242 DCHECK(!instr->key()->IsConstantOperand());
4244 instr->hydrogen()->value()->type().IsHeapObject()
4247 __ lea(key, operand);
4248 __ RecordWrite(elements,
4254 instr->hydrogen()->PointersToHereCheckForValue());
4259 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4261 if (instr->is_typed_elements()) {
4263 }
else if (instr->hydrogen()->value()->representation().IsDouble()) {
4271 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
4278 CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code();
4283 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4284 Register
object =
ToRegister(instr->object());
4286 Label no_memento_found;
4287 __ TestJSArrayForAllocationMemento(
object, temp, &no_memento_found);
4289 __ bind(&no_memento_found);
4293 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4294 Register object_reg =
ToRegister(instr->object());
4296 Handle<Map> from_map = instr->original_map();
4297 Handle<Map> to_map = instr->transitioned_map();
4301 Label not_applicable;
4302 bool is_simple_map_transition =
4304 Label::Distance branch_distance =
4305 is_simple_map_transition ? Label::kNear : Label::kFar;
4307 __ j(
not_equal, ¬_applicable, branch_distance);
4308 if (is_simple_map_transition) {
4309 Register new_map_reg =
ToRegister(instr->new_map_temp());
4314 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
4320 PushSafepointRegistersScope
scope(
this);
4321 __ mov(
ebx, to_map);
4322 bool is_js_array = from_map->instance_type() ==
JS_ARRAY_TYPE;
4323 TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array);
4328 __ bind(¬_applicable);
4332 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4335 DeferredStringCharCodeAt(
LCodeGen* codegen,
4336 LStringCharCodeAt* instr)
4339 codegen()->DoDeferredStringCharCodeAt(instr_);
4341 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4343 LStringCharCodeAt* instr_;
4346 DeferredStringCharCodeAt* deferred =
4347 new(zone()) DeferredStringCharCodeAt(
this, instr);
4355 __ bind(deferred->exit());
4360 Register
string =
ToRegister(instr->string());
4361 Register result =
ToRegister(instr->result());
4366 __ Move(result, Immediate(0));
4368 PushSafepointRegistersScope
scope(
this);
4373 if (instr->index()->IsConstantOperand()) {
4374 Immediate immediate =
ToImmediate(LConstantOperand::cast(instr->index()),
4383 instr, instr->context());
4386 __ StoreToSafepointRegisterSlot(result,
eax);
4390 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4393 DeferredStringCharFromCode(
LCodeGen* codegen,
4394 LStringCharFromCode* instr)
4397 codegen()->DoDeferredStringCharFromCode(instr_);
4399 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4401 LStringCharFromCode* instr_;
4404 DeferredStringCharFromCode* deferred =
4405 new(zone()) DeferredStringCharFromCode(
this, instr);
4407 DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
4408 Register char_code =
ToRegister(instr->char_code());
4409 Register result =
ToRegister(instr->result());
4410 DCHECK(!char_code.is(result));
4413 __ j(
above, deferred->entry());
4414 __ Move(result, Immediate(factory()->single_character_string_cache()));
4418 __ cmp(result, factory()->undefined_value());
4419 __ j(
equal, deferred->entry());
4420 __ bind(deferred->exit());
4425 Register char_code =
ToRegister(instr->char_code());
4426 Register result =
ToRegister(instr->result());
4431 __ Move(result, Immediate(0));
4433 PushSafepointRegistersScope
scope(
this);
4434 __ SmiTag(char_code);
4437 __ StoreToSafepointRegisterSlot(result,
eax);
4441 void LCodeGen::DoStringAdd(LStringAdd* instr) {
4445 StringAddStub stub(isolate(),
4446 instr->hydrogen()->flags(),
4447 instr->hydrogen()->pretenure_flag());
4452 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
4453 LOperand* input = instr->value();
4454 LOperand* output = instr->result();
4455 DCHECK(input->IsRegister() || input->IsStackSlot());
4456 DCHECK(output->IsDoubleRegister());
4461 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
4462 LOperand* input = instr->value();
4463 LOperand* output = instr->result();
4468 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4471 DeferredNumberTagI(
LCodeGen* codegen,
4475 codegen()->DoDeferredNumberTagIU(
4476 instr_, instr_->value(), instr_->temp(),
SIGNED_INT32);
4478 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4480 LNumberTagI* instr_;
4483 LOperand* input = instr->value();
4484 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4487 DeferredNumberTagI* deferred =
4488 new(zone()) DeferredNumberTagI(
this, instr);
4491 __ bind(deferred->exit());
4495 void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4498 DeferredNumberTagU(
LCodeGen* codegen, LNumberTagU* instr)
4501 codegen()->DoDeferredNumberTagIU(
4504 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4506 LNumberTagU* instr_;
4509 LOperand* input = instr->value();
4510 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4513 DeferredNumberTagU* deferred =
4514 new(zone()) DeferredNumberTagU(
this, instr);
4516 __ j(
above, deferred->entry());
4518 __ bind(deferred->exit());
4525 IntegerSignedness signedness) {
4536 __ xor_(reg, 0x80000000);
4537 __ Cvtsi2sd(xmm_scratch, Operand(reg));
4539 __ LoadUint32(xmm_scratch, reg);
4542 if (FLAG_inline_new) {
4543 __ AllocateHeapNumber(reg, tmp,
no_reg, &slow);
4544 __ jmp(&done, Label::kNear);
4553 __ Move(reg, Immediate(0));
4556 PushSafepointRegistersScope
scope(
this);
4564 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4566 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4567 __ StoreToSafepointRegisterSlot(reg,
eax);
4577 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4580 DeferredNumberTagD(
LCodeGen* codegen, LNumberTagD* instr)
4583 codegen()->DoDeferredNumberTagD(instr_);
4585 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4587 LNumberTagD* instr_;
4592 DeferredNumberTagD* deferred =
4593 new(zone()) DeferredNumberTagD(
this, instr);
4594 if (FLAG_inline_new) {
4596 __ AllocateHeapNumber(reg, tmp,
no_reg, deferred->entry());
4598 __ jmp(deferred->entry());
4600 __ bind(deferred->exit());
4611 __ Move(reg, Immediate(0));
4613 PushSafepointRegistersScope
scope(
this);
4620 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4622 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4623 __ StoreToSafepointRegisterSlot(reg,
eax);
4627 void LCodeGen::DoSmiTag(LSmiTag* instr) {
4628 HChange* hchange = instr->hydrogen();
4632 __ test(input, Immediate(0xc0000000));
4643 void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4644 LOperand* input = instr->value();
4646 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4647 if (instr->needs_check()) {
4651 __ AssertSmi(result);
4653 __ SmiUntag(result);
4658 Register temp_reg, XMMRegister result_reg,
4660 bool can_convert_undefined_to_nan =
4661 instr->hydrogen()->can_convert_undefined_to_nan();
4662 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero();
4664 Label convert, load_smi, done;
4668 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
4672 factory()->heap_number_map());
4673 if (can_convert_undefined_to_nan) {
4682 if (deoptimize_on_minus_zero) {
4684 __ xorps(xmm_scratch, xmm_scratch);
4685 __ ucomisd(result_reg, xmm_scratch);
4687 __ movmskpd(temp_reg, result_reg);
4688 __ test_b(temp_reg, 1);
4691 __ jmp(&done, Label::kNear);
4693 if (can_convert_undefined_to_nan) {
4697 __ cmp(input_reg, factory()->undefined_value());
4700 ExternalReference nan =
4701 ExternalReference::address_of_canonical_non_hole_nan();
4702 __ movsd(result_reg, Operand::StaticVariable(nan));
4703 __ jmp(&done, Label::kNear);
4712 __ mov(temp_reg, input_reg);
4713 __ SmiUntag(temp_reg);
4714 __ Cvtsi2sd(result_reg, Operand(temp_reg));
4720 Register input_reg =
ToRegister(instr->value());
4726 if (instr->truncating()) {
4727 Label no_heap_number, check_bools, check_false;
4731 factory()->heap_number_map());
4733 __ TruncateHeapNumberToI(input_reg, input_reg);
4736 __ bind(&no_heap_number);
4739 __ cmp(input_reg, factory()->undefined_value());
4741 __ Move(input_reg, Immediate(0));
4744 __ bind(&check_bools);
4745 __ cmp(input_reg, factory()->true_value());
4747 __ Move(input_reg, Immediate(1));
4750 __ bind(&check_false);
4751 __ cmp(input_reg, factory()->false_value());
4753 __ Move(input_reg, Immediate(0));
4758 isolate()->factory()->heap_number_map());
4761 __ cvttsd2si(input_reg, Operand(
xmm0));
4762 __ Cvtsi2sd(scratch, Operand(input_reg));
4763 __ ucomisd(
xmm0, scratch);
4767 __ test(input_reg, Operand(input_reg));
4769 __ movmskpd(input_reg,
xmm0);
4770 __ and_(input_reg, 1);
4777 void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
4780 DeferredTaggedToI(
LCodeGen* codegen, LTaggedToI* instr)
4783 codegen()->DoDeferredTaggedToI(instr_, done());
4785 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4790 LOperand* input = instr->value();
4791 DCHECK(input->IsRegister());
4795 if (instr->hydrogen()->value()->representation().IsSmi()) {
4796 __ SmiUntag(input_reg);
4798 DeferredTaggedToI* deferred =
4799 new(zone()) DeferredTaggedToI(
this, instr);
4803 __ SmiUntag(input_reg);
4806 __ j(
carry, deferred->entry());
4807 __ bind(deferred->exit());
4812 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
4813 LOperand* input = instr->value();
4814 DCHECK(input->IsRegister());
4815 LOperand* temp = instr->temp();
4816 DCHECK(temp->IsRegister());
4817 LOperand* result = instr->result();
4818 DCHECK(result->IsDoubleRegister());
4823 HValue* value = instr->hydrogen()->value();
4832 void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
4833 LOperand* input = instr->value();
4834 DCHECK(input->IsDoubleRegister());
4835 LOperand* result = instr->result();
4836 DCHECK(result->IsRegister());
4839 if (instr->truncating()) {
4841 __ TruncateDoubleToI(result_reg, input_reg);
4843 Label lost_precision, is_nan, minus_zero, done;
4847 __ DoubleToI(result_reg, input_reg, xmm_scratch,
4848 instr->hydrogen()->GetMinusZeroMode(), &lost_precision,
4849 &is_nan, &minus_zero, dist);
4850 __ jmp(&done, dist);
4851 __ bind(&lost_precision);
4855 __ bind(&minus_zero);
4862 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4863 LOperand* input = instr->value();
4864 DCHECK(input->IsDoubleRegister());
4865 LOperand* result = instr->result();
4866 DCHECK(result->IsRegister());
4869 Label lost_precision, is_nan, minus_zero, done;
4873 __ DoubleToI(result_reg, input_reg, xmm_scratch,
4874 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, &is_nan,
4876 __ jmp(&done, dist);
4877 __ bind(&lost_precision);
4881 __ bind(&minus_zero);
4884 __ SmiTag(result_reg);
4889 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
4890 LOperand* input = instr->value();
4896 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
4897 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
4898 LOperand* input = instr->value();
4905 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
4911 if (instr->hydrogen()->is_interval_check()) {
4914 instr->hydrogen()->GetCheckInterval(&first, &last);
4917 static_cast<int8_t
>(first));
4920 if (first == last) {
4927 static_cast<int8_t
>(last));
4934 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4942 __ and_(temp, mask);
4950 void LCodeGen::DoCheckValue(LCheckValue* instr) {
4951 Handle<HeapObject>
object = instr->hydrogen()->object().handle();
4952 if (instr->hydrogen()->object_in_new_space()) {
4954 Handle<Cell> cell = isolate()->factory()->NewCell(
object);
4955 __ cmp(reg, Operand::ForCell(cell));
4957 Operand operand =
ToOperand(instr->value());
4958 __ cmp(operand,
object);
4966 PushSafepointRegistersScope
scope(
this);
4969 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
4971 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
4979 void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
4982 DeferredCheckMaps(
LCodeGen* codegen, LCheckMaps* instr, Register
object)
4984 SetExit(check_maps());
4987 codegen()->DoDeferredInstanceMigration(instr_, object_);
4989 Label* check_maps() {
return &check_maps_; }
4990 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
4997 if (instr->hydrogen()->IsStabilityCheck()) {
4998 const UniqueSet<Map>* maps = instr->hydrogen()->maps();
4999 for (
int i = 0;
i < maps->size(); ++
i) {
5000 AddStabilityDependency(maps->at(
i).handle());
5005 LOperand* input = instr->value();
5006 DCHECK(input->IsRegister());
5009 DeferredCheckMaps* deferred =
NULL;
5010 if (instr->hydrogen()->HasMigrationTarget()) {
5011 deferred =
new(zone()) DeferredCheckMaps(
this, instr, reg);
5012 __ bind(deferred->check_maps());
5015 const UniqueSet<Map>* maps = instr->hydrogen()->maps();
5017 for (
int i = 0;
i < maps->size() - 1;
i++) {
5018 Handle<Map>
map = maps->at(
i).handle();
5019 __ CompareMap(reg,
map);
5020 __ j(
equal, &success, Label::kNear);
5023 Handle<Map>
map = maps->at(maps->size() - 1).handle();
5024 __ CompareMap(reg,
map);
5025 if (instr->hydrogen()->HasMigrationTarget()) {
5035 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5038 Register result_reg =
ToRegister(instr->result());
5039 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
5043 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5044 DCHECK(instr->unclamped()->Equals(instr->result()));
5045 Register value_reg =
ToRegister(instr->result());
5046 __ ClampUint8(value_reg);
5050 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5051 DCHECK(instr->unclamped()->Equals(instr->result()));
5052 Register input_reg =
ToRegister(instr->unclamped());
5055 Label is_smi, done, heap_number;
5057 __ JumpIfSmi(input_reg, &is_smi);
5061 factory()->heap_number_map());
5062 __ j(
equal, &heap_number, Label::kNear);
5066 __ cmp(input_reg, factory()->undefined_value());
5068 __ mov(input_reg, 0);
5069 __ jmp(&done, Label::kNear);
5072 __ bind(&heap_number);
5074 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
5075 __ jmp(&done, Label::kNear);
5079 __ SmiUntag(input_reg);
5080 __ ClampUint8(input_reg);
5085 void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
5087 Register result_reg =
ToRegister(instr->result());
5088 if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
5090 CpuFeatureScope scope2(masm(),
SSE4_1);
5091 __ pextrd(result_reg, value_reg, 1);
5094 __ pshufd(xmm_scratch, value_reg, 1);
5095 __ movd(result_reg, xmm_scratch);
5098 __ movd(result_reg, value_reg);
5103 void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
5109 CpuFeatureScope scope2(masm(),
SSE4_1);
5110 __ movd(result_reg, lo_reg);
5111 __ pinsrd(result_reg, hi_reg, 1);
5114 __ movd(result_reg, hi_reg);
5115 __ psllq(result_reg, 32);
5116 __ movd(xmm_scratch, lo_reg);
5117 __ orps(result_reg, xmm_scratch);
5122 void LCodeGen::DoAllocate(LAllocate* instr) {
5125 DeferredAllocate(
LCodeGen* codegen, LAllocate* instr)
5128 codegen()->DoDeferredAllocate(instr_);
5130 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
5135 DeferredAllocate* deferred =
new(zone()) DeferredAllocate(
this, instr);
5137 Register result =
ToRegister(instr->result());
5142 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5145 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5146 DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5147 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5149 }
else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5150 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5154 if (instr->size()->IsConstantOperand()) {
5159 __ jmp(deferred->entry());
5166 __ bind(deferred->exit());
5168 if (instr->hydrogen()->MustPrefillWithFiller()) {
5169 if (instr->size()->IsConstantOperand()) {
5180 isolate()->factory()->one_pointer_filler_map());
5188 Register result =
ToRegister(instr->result());
5195 PushSafepointRegistersScope
scope(
this);
5196 if (instr->size()->IsRegister()) {
5213 instr->hydrogen()->MustAllocateDoubleAligned());
5214 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5215 DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5216 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5218 }
else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5219 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5227 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
5228 __ StoreToSafepointRegisterSlot(result,
eax);
5232 void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
5235 CallRuntime(Runtime::kToFastProperties, 1, instr);
5239 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
5247 int literal_offset =
5249 __ LoadHeapObject(
ecx, instr->hydrogen()->literals());
5251 __ cmp(
ebx, factory()->undefined_value());
5257 __ push(Immediate(
Smi::FromInt(instr->hydrogen()->literal_index())));
5258 __ push(Immediate(instr->hydrogen()->pattern()));
5259 __ push(Immediate(instr->hydrogen()->flags()));
5260 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5263 __ bind(&materialized);
5265 Label allocated, runtime_allocate;
5267 __ jmp(&allocated, Label::kNear);
5269 __ bind(&runtime_allocate);
5272 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5275 __ bind(&allocated);
5291 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
5295 bool pretenure = instr->hydrogen()->pretenure();
5296 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5297 FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(),
5298 instr->hydrogen()->kind());
5299 __ mov(
ebx, Immediate(instr->hydrogen()->shared_info()));
5303 __ push(Immediate(instr->hydrogen()->shared_info()));
5304 __ push(Immediate(pretenure ? factory()->true_value()
5305 : factory()->false_value()));
5311 void LCodeGen::DoTypeof(LTypeof* instr) {
5313 LOperand* input = instr->value();
5319 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
5329 Label* true_label = instr->TrueLabel(chunk_);
5330 Label* false_label = instr->FalseLabel(chunk_);
5331 Handle<String> type_name = instr->type_literal();
5332 int left_block = instr->TrueDestination(chunk_);
5333 int right_block = instr->FalseDestination(chunk_);
5334 int next_block = GetNextEmittedBlock();
5336 Label::Distance true_distance = left_block == next_block ? Label::kNear
5338 Label::Distance false_distance = right_block == next_block ? Label::kNear
5342 __ JumpIfSmi(input, true_label, true_distance);
5344 factory()->heap_number_map());
5345 final_branch_condition =
equal;
5347 }
else if (
String::Equals(type_name, factory()->string_string())) {
5348 __ JumpIfSmi(input, false_label, false_distance);
5353 final_branch_condition =
zero;
5355 }
else if (
String::Equals(type_name, factory()->symbol_string())) {
5356 __ JumpIfSmi(input, false_label, false_distance);
5358 final_branch_condition =
equal;
5360 }
else if (
String::Equals(type_name, factory()->boolean_string())) {
5361 __ cmp(input, factory()->true_value());
5362 __ j(
equal, true_label, true_distance);
5363 __ cmp(input, factory()->false_value());
5364 final_branch_condition =
equal;
5366 }
else if (
String::Equals(type_name, factory()->undefined_string())) {
5367 __ cmp(input, factory()->undefined_value());
5368 __ j(
equal, true_label, true_distance);
5369 __ JumpIfSmi(input, false_label, false_distance);
5376 }
else if (
String::Equals(type_name, factory()->function_string())) {
5378 __ JumpIfSmi(input, false_label, false_distance);
5380 __ j(
equal, true_label, true_distance);
5382 final_branch_condition =
equal;
5384 }
else if (
String::Equals(type_name, factory()->object_string())) {
5385 __ JumpIfSmi(input, false_label, false_distance);
5386 __ cmp(input, factory()->null_value());
5387 __ j(
equal, true_label, true_distance);
5389 __ j(
below, false_label, false_distance);
5391 __ j(
above, false_label, false_distance);
5395 final_branch_condition =
zero;
5398 __ jmp(false_label, false_distance);
5400 return final_branch_condition;
5404 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
5417 Label check_frame_marker;
5420 __ j(
not_equal, &check_frame_marker, Label::kNear);
5424 __ bind(&check_frame_marker);
5431 if (!info()->IsStub()) {
5434 int current_pc = masm()->pc_offset();
5435 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5436 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5437 __ Nop(padding_size);
5440 last_lazy_deopt_pc_ = masm()->pc_offset();
5444 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
5445 last_lazy_deopt_pc_ = masm()->pc_offset();
5446 DCHECK(instr->HasEnvironment());
5449 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5453 void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5466 void LCodeGen::DoDummy(LDummy* instr) {
5471 void LCodeGen::DoDummyUse(LDummyUse* instr) {
5477 PushSafepointRegistersScope
scope(
this);
5479 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5482 DCHECK(instr->HasEnvironment());
5484 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5488 void LCodeGen::DoStackCheck(LStackCheck* instr) {
5491 DeferredStackCheck(
LCodeGen* codegen, LStackCheck* instr)
5494 codegen()->DoDeferredStackCheck(instr_);
5496 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
5498 LStackCheck* instr_;
5501 DCHECK(instr->HasEnvironment());
5505 if (instr->hydrogen()->is_function_entry()) {
5508 ExternalReference stack_limit =
5509 ExternalReference::address_of_stack_limit(isolate());
5510 __ cmp(
esp, Operand::StaticVariable(stack_limit));
5513 DCHECK(instr->context()->IsRegister());
5515 CallCode(isolate()->builtins()->StackCheck(),
5520 DCHECK(instr->hydrogen()->is_backwards_branch());
5522 DeferredStackCheck* deferred_stack_check =
5523 new(zone()) DeferredStackCheck(
this, instr);
5524 ExternalReference stack_limit =
5525 ExternalReference::address_of_stack_limit(isolate());
5526 __ cmp(
esp, Operand::StaticVariable(stack_limit));
5527 __ j(
below, deferred_stack_check->entry());
5529 __ bind(instr->done_label());
5530 deferred_stack_check->SetExit(instr->done_label());
5539 void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5547 DCHECK(!environment->HasBeenRegistered());
5554 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5556 __ cmp(
eax, isolate()->factory()->undefined_value());
5559 __ cmp(
eax, isolate()->factory()->null_value());
5569 Label use_cache, call_runtime;
5570 __ CheckEnumCache(&call_runtime);
5573 __ jmp(&use_cache, Label::kNear);
5576 __ bind(&call_runtime);
5578 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5581 isolate()->factory()->meta_map());
5583 __ bind(&use_cache);
5587 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5589 Register result =
ToRegister(instr->result());
5590 Label load_cache, done;
5591 __ EnumLength(result,
map);
5594 __ mov(result, isolate()->factory()->empty_fixed_array());
5595 __ jmp(&done, Label::kNear);
5597 __ bind(&load_cache);
5598 __ LoadInstanceDescriptors(
map, result);
5604 __ test(result, result);
5609 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5610 Register
object =
ToRegister(instr->value());
5620 PushSafepointRegistersScope
scope(
this);
5624 __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
5626 instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
5627 __ StoreToSafepointRegisterSlot(
object,
eax);
5631 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5634 DeferredLoadMutableDouble(
LCodeGen* codegen,
5635 LLoadFieldByIndex* instr,
5644 codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
5646 virtual LInstruction* instr()
OVERRIDE {
return instr_; }
5648 LLoadFieldByIndex* instr_;
5653 Register
object =
ToRegister(instr->object());
5656 DeferredLoadMutableDouble* deferred;
5657 deferred =
new(zone()) DeferredLoadMutableDouble(
5658 this, instr,
object, index);
5660 Label out_of_object, done;
5666 __ cmp(index, Immediate(0));
5667 __ j(
less, &out_of_object, Label::kNear);
5672 __ jmp(&done, Label::kNear);
5674 __ bind(&out_of_object);
5682 __ bind(deferred->exit());
5687 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
5688 Register context =
ToRegister(instr->context());
5693 void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
5694 Handle<ScopeInfo> scope_info = instr->scope_info();
5697 CallRuntime(Runtime::kPushBlockContext, 2, instr);
static AllocationSiteMode GetMode(ElementsKind boilerplate_elements_kind)
static const int kLengthOffset
static U update(U previous, T value)
static const int kHeaderSize
static int SlotOffset(int index)
static bool IsSupported(CpuFeature f)
static void EnsureRelocSpaceForLazyDeoptimization(Handle< Code > code)
static Address GetDeoptimizationEntry(Isolate *isolate, int id, BailoutType type, GetEntryMode mode=ENSURE_ENTRY_CODE)
static const int kEnumCacheOffset
static const int kHeaderSize
static int OffsetOfElementAt(int index)
static int SizeFor(int length)
static const int kGlobalProxyOffset
@ kAllUsesTruncatingToInt32
static Handle< T > cast(Handle< S > that)
static const uint32_t kSignMask
static const int kValueOffset
static const int kMapOffset
static const int kValueOffset
static const int kCacheStampOffset
static const int kSharedFunctionInfoOffset
static const int kContextOffset
static const int kCodeEntryOffset
static const int kPrototypeOrInitialMapOffset
static const int kHeaderSize
static const int kPropertiesOffset
static const int kInObjectFieldCount
static const int kDynamicAlignmentStateOffset
static const int kFunctionOffset
bool IsNextEmittedBlock(int block_id) const
void RestoreCallerDoubles()
void DoStoreKeyedFixedArray(LStoreKeyed *instr)
DwVfpRegister ToDoubleRegister(LOperand *op) const
void RecordSafepointWithRegisters(LPointerMap *pointers, int arguments, Safepoint::DeoptMode mode)
@ RECORD_SIMPLE_SAFEPOINT
@ RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
int inlined_function_count_
bool IsSmi(LConstantOperand *op) const
friend class SafepointGenerator
TranslationBuffer translations_
MemOperand BuildSeqStringOperand(Register string, LOperand *index, String::Encoding encoding)
Condition EmitIsString(Register input, Register temp1, Label *is_not_string, SmiCheck check_needed)
void DoDeferredStackCheck(LStackCheck *instr)
SafepointTableBuilder safepoints_
void EmitVectorLoadICRegisters(T *instr)
static Condition TokenToCondition(Token::Value op, bool is_unsigned)
ZoneList< Handle< Object > > deoptimization_literals_
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal *instr, Label *map_check, Label *bool_load)
bool dynamic_frame_alignment_
void PopulateDeoptimizationLiteralsWithInlinedFunctions()
void AddToTranslation(LEnvironment *environment, Translation *translation, LOperand *op, bool is_tagged, bool is_uint32, int *object_index_pointer, int *dematerialized_index_pointer)
ZoneList< LEnvironment * > deoptimizations_
void EmitIntegerMathAbs(LMathAbs *instr)
int32_t ToRepresentation(LConstantOperand *op, const Representation &r) const
void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc, LInstruction *instr, LOperand *context)
void EmitIsConstructCall(Register temp1, Register temp2)
void EmitPushTaggedOperand(LOperand *operand)
int32_t ToInteger32(LConstantOperand *op) const
LPlatformChunk * chunk() const
void FinishCode(Handle< Code > code)
ExternalReference ToExternalReference(LConstantOperand *op) const
int LookupDestination(int block_id) const
Condition EmitTypeofIs(Label *true_label, Label *false_label, Register input, Handle< String > type_name)
void DoDeferredAllocate(LAllocate *instr)
void RecordSafepoint(LPointerMap *pointers, Safepoint::Kind kind, int arguments, Safepoint::DeoptMode mode)
void DoDeferredTaggedToI(LTaggedToI *instr)
LowDwVfpRegister double_scratch0()
void CallCodeGeneric(Handle< Code > code, RelocInfo::Mode mode, LInstruction *instr, SafepointMode safepoint_mode, TargetAddressStorageMode storage_mode=CAN_INLINE_TARGET_ADDRESS)
void DoDeferredStringCharCodeAt(LStringCharCodeAt *instr)
void CallCode(Handle< Code > code, RelocInfo::Mode mode, LInstruction *instr, TargetAddressStorageMode storage_mode=CAN_INLINE_TARGET_ADDRESS)
Safepoint::Kind expected_safepoint_kind_
ZoneList< LDeferredCode * > deferred_
Operand HighOperand(LOperand *op)
bool GenerateDeferredCode()
void DoDeferredNumberTagIU(LInstruction *instr, LOperand *value, LOperand *temp1, LOperand *temp2, IntegerSignedness signedness)
Handle< Object > ToHandle(LConstantOperand *op) const
bool NeedsEagerFrame() const
void GenerateBodyInstructionPost(LInstruction *instr) OVERRIDE
void RegisterEnvironmentForDeoptimization(LEnvironment *environment, Safepoint::DeoptMode mode)
friend class LDeferredCode
void LoadContextFromDeferred(LOperand *context)
void GenerateOsrPrologue()
Operand BuildFastArrayOperand(LOperand *elements_pointer, LOperand *key, Representation key_representation, ElementsKind elements_kind, uint32_t base_offset)
bool NeedsDeferredFrame() const
void DoDeferredInstanceMigration(LCheckMaps *instr, Register object)
bool support_aligned_spilled_doubles_
void DoDeferredLoadMutableDouble(LLoadFieldByIndex *instr, Register result, Register object, Register index)
int DefineDeoptimizationLiteral(Handle< Object > literal)
void DeoptimizeIf(Condition condition, LInstruction *instr, const char *detail, Deoptimizer::BailoutType bailout_type)
int GetStackSlotCount() const
void CallKnownFunction(Handle< JSFunction > function, int formal_parameter_count, int arity, LInstruction *instr, R1State r1_state)
void WriteTranslation(LEnvironment *environment, Translation *translation)
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs *instr)
void DoLoadKeyedFixedDoubleArray(LLoadKeyed *instr)
bool GenerateSafepointTable()
Operand ToOperand(LOperand *op)
void EmitClassOfTest(Label *if_true, Label *if_false, Handle< String > class_name, Register input, Register temporary, Register temporary2)
void DoLoadKeyedExternalArray(LLoadKeyed *instr)
void EmitReturn(LReturn *instr, bool dynamic_frame_alignment)
Immediate ToImmediate(LOperand *op, const Representation &r) const
double ToDouble(LConstantOperand *op) const
Register ToRegister(LOperand *op) const
void DoStoreKeyedExternalArray(LStoreKeyed *instr)
void RecordAndWritePosition(int position) OVERRIDE
bool IsInteger32(LConstantOperand *op) const
void PopulateDeoptimizationData(Handle< Code > code)
void DoParallelMove(LParallelMove *move)
void CallRuntime(const Runtime::Function *function, int num_arguments, LInstruction *instr, SaveFPRegsMode save_doubles=kDontSaveFPRegs)
void DoDeferredStringCharFromCode(LStringCharFromCode *instr)
ZoneList< Deoptimizer::JumpTableEntry > jump_table_
Condition EmitIsObject(Register input, Register temp1, Label *is_not_object, Label *is_object)
void EnsureSpaceForLazyDeopt(int space_needed) OVERRIDE
void EmitNumberUntagD(LNumberUntagD *instr, Register input, DwVfpRegister result, NumberUntagDMode mode)
void GenerateBodyInstructionPre(LInstruction *instr) OVERRIDE
void RecordSafepointWithLazyDeopt(LInstruction *instr, SafepointMode safepoint_mode)
void EmitFalseBranch(InstrType instr, Condition condition)
void DoLoadKeyedFixedArray(LLoadKeyed *instr)
LCodeGen(LChunk *chunk, MacroAssembler *assembler, CompilationInfo *info)
void EmitBranch(InstrType instr, Condition condition)
void DoDeferredNumberTagD(LNumberTagD *instr)
void DoStoreKeyedFixedDoubleArray(LStoreKeyed *instr)
friend class LEnvironment
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
static const Register ReceiverRegister()
static const Register NameRegister()
static void GenerateMiss(MacroAssembler *masm)
static int SafepointRegisterStackIndex(int reg_code)
static const int kIsUndetectable
static const int kBitFieldOffset
static const int kInstanceTypeOffset
static const int kConstructorOffset
static const int kPrototypeOffset
static void EmitMathExp(MacroAssembler *masm, DwVfpRegister input, DwVfpRegister result, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2, Register temp1, Register temp2, Register temp3)
static const Register exponent()
static const int kHashFieldOffset
static const int kMaxRegularHeapObjectSize
static void MaybeCallEntryHook(MacroAssembler *masm)
static const int kNoPosition
static Representation Smi()
static Representation Integer32()
int num_parameters() const
Variable * parameter(int index) const
static const int kHeaderSize
static const int kDontAdaptArgumentsSentinel
static const int kInstanceClassNameOffset
static const int kNativeBitWithinByte
static const int kStrictModeBitWithinByte
static const int kMaxValue
static Smi * FromInt(int value)
static const int kContextOffset
static const int kCallerSPOffset
static const int kMarkerOffset
static const int kCallerFPOffset
static const Register ReceiverRegister()
static const Register NameRegister()
static const Register ValueRegister()
static Handle< Code > initialize_stub(Isolate *isolate, StrictMode strict_mode)
static void Generate(MacroAssembler *masm, Register string, Register index, Register result, Label *call_runtime)
static const unsigned int kContainsCachedArrayIndexMask
static const int32_t kMaxOneByteCharCode
static const int kMaxLength
static const int kLengthOffset
static const int kMaxUtf16CodeUnit
bool Equals(String *other)
static const Register VectorRegister()
static const Register SlotRegister()
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes to(mksnapshot only)") DEFINE_STRING(raw_context_file
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric literals(0o77, 0b11)") DEFINE_BOOL(harmony_object_literals
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
enable harmony numeric enable harmony object literal extensions Optimize object Array shift
#define DCHECK_LE(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK(condition)
@ PRETENURE_OLD_POINTER_SPACE
@ PRETENURE_OLD_DATA_SPACE
bool IsPowerOfTwo32(uint32_t value)
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Vector< const char > CStrVector(const char *data)
const uint32_t kStringEncodingMask
MemOperand ContextOperand(Register context, int index)
const int kAlignmentPaddingPushed
static bool ExternalArrayOpRequiresTemp(Representation key_representation, ElementsKind elements_kind)
Condition CommuteCondition(Condition cond)
bool EvalComparison(Token::Value op, double op1, double op2)
const uint32_t kTwoByteStringTag
Operand FieldOperand(Register object, int offset)
const int kPointerSizeLog2
@ LAST_NONCALLABLE_SPEC_OBJECT_TYPE
@ NUM_OF_CALLABLE_SPEC_OBJECT_TYPES
@ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE
@ EXTERNAL_UINT16_ELEMENTS
@ EXTERNAL_INT16_ELEMENTS
@ EXTERNAL_UINT8_ELEMENTS
@ EXTERNAL_INT32_ELEMENTS
@ FAST_HOLEY_DOUBLE_ELEMENTS
@ SLOPPY_ARGUMENTS_ELEMENTS
@ EXTERNAL_FLOAT32_ELEMENTS
@ EXTERNAL_FLOAT64_ELEMENTS
@ FAST_HOLEY_SMI_ELEMENTS
@ EXTERNAL_UINT32_ELEMENTS
@ EXTERNAL_UINT8_CLAMPED_ELEMENTS
bool IsSimpleMapChangeTransition(ElementsKind from_kind, ElementsKind to_kind)
const uint32_t kOneByteStringTag
int ElementsKindToShiftSize(ElementsKind elements_kind)
int32_t WhichPowerOf2Abs(int32_t x)
int StackSlotOffset(int index)
bool IsFastPackedElementsKind(ElementsKind kind)
@ NUMBER_CANDIDATE_IS_SMI
@ NUMBER_CANDIDATE_IS_ANY_TAGGED
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
AllocationSiteOverrideMode
@ DISABLE_ALLOCATION_SITES
Condition NegateCondition(Condition cond)
static InstanceType TestType(HHasInstanceTypeAndBranch *instr)
@ times_half_pointer_size
const uint32_t kStringRepresentationMask
static Condition BranchCondition(HHasInstanceTypeAndBranch *instr)
OStream & dec(OStream &os)
static int ArgumentsOffsetWithoutFrame(int index)
static Condition ComputeCompareCondition(Token::Value op)
static const char * LabelType(LLabel *label)
const int kAlignmentZapValue
MemOperand GlobalObjectOperand()
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const intptr_t kSmiTagMask
@ NO_CALL_CONSTRUCTOR_FLAGS
const int kNoAlignmentPadding
bool IsFastSmiElementsKind(ElementsKind kind)
const uint32_t kHoleNanLower32
const uint32_t kSlotsZapValue
const uint32_t kHoleNanUpper32
PerThreadAssertScopeDebugOnly< DEFERRED_HANDLE_DEREFERENCE_ASSERT, true > AllowDeferredHandleDereference
Debugger support for the V8 JavaScript engine.
bool is(DwVfpRegister reg) const
static Register FromAllocationIndex(int index)
bool is(Register reg) const
static XMMRegister FromAllocationIndex(int index)
#define T(name, string, precedence)