| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 if (strlen(FLAG_stop_at) > 0 && | 137 if (strlen(FLAG_stop_at) > 0 && |
| 138 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 138 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 139 __ int3(); | 139 __ int3(); |
| 140 } | 140 } |
| 141 #endif | 141 #endif |
| 142 | 142 |
| 143 // Strict mode functions need to replace the receiver with undefined | 143 // Strict mode functions need to replace the receiver with undefined |
| 144 // when called as functions (without an explicit receiver | 144 // when called as functions (without an explicit receiver |
| 145 // object). rcx is zero for method calls and non-zero for function | 145 // object). rcx is zero for method calls and non-zero for function |
| 146 // calls. | 146 // calls. |
| 147 if (info_->is_strict_mode()) { | 147 if (info_->is_strict_mode() || info_->is_native()) { |
| 148 Label ok; | 148 Label ok; |
| 149 __ testq(rcx, rcx); | 149 __ testq(rcx, rcx); |
| 150 __ j(zero, &ok, Label::kNear); | 150 __ j(zero, &ok, Label::kNear); |
| 151 // +1 for return address. | 151 // +1 for return address. |
| 152 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 152 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
| 153 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); | 153 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); |
| 154 __ movq(Operand(rsp, receiver_offset), kScratchRegister); | 154 __ movq(Operand(rsp, receiver_offset), kScratchRegister); |
| 155 __ bind(&ok); | 155 __ bind(&ok); |
| 156 } | 156 } |
| 157 | 157 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 // Possibly allocate a local context. | 190 // Possibly allocate a local context. |
| 191 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 191 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 192 if (heap_slots > 0) { | 192 if (heap_slots > 0) { |
| 193 Comment(";;; Allocate local context"); | 193 Comment(";;; Allocate local context"); |
| 194 // Argument to NewContext is the function, which is still in rdi. | 194 // Argument to NewContext is the function, which is still in rdi. |
| 195 __ push(rdi); | 195 __ push(rdi); |
| 196 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 196 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 197 FastNewContextStub stub(heap_slots); | 197 FastNewContextStub stub(heap_slots); |
| 198 __ CallStub(&stub); | 198 __ CallStub(&stub); |
| 199 } else { | 199 } else { |
| 200 __ CallRuntime(Runtime::kNewContext, 1); | 200 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 201 } | 201 } |
| 202 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); | 202 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); |
| 203 // Context is returned in both rax and rsi. It replaces the context | 203 // Context is returned in both rax and rsi. It replaces the context |
| 204 // passed to us. It's saved in the stack and kept live in rsi. | 204 // passed to us. It's saved in the stack and kept live in rsi. |
| 205 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 205 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
| 206 | 206 |
| 207 // Copy any necessary parameters into the context. | 207 // Copy any necessary parameters into the context. |
| 208 int num_parameters = scope()->num_parameters(); | 208 int num_parameters = scope()->num_parameters(); |
| 209 for (int i = 0; i < num_parameters; i++) { | 209 for (int i = 0; i < num_parameters; i++) { |
| 210 Slot* slot = scope()->parameter(i)->AsSlot(); | 210 Slot* slot = scope()->parameter(i)->AsSlot(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 for (int i = 0; i < jump_table_.length(); i++) { | 265 for (int i = 0; i < jump_table_.length(); i++) { |
| 266 __ bind(&jump_table_[i].label); | 266 __ bind(&jump_table_[i].label); |
| 267 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); | 267 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); |
| 268 } | 268 } |
| 269 return !is_aborted(); | 269 return !is_aborted(); |
| 270 } | 270 } |
| 271 | 271 |
| 272 | 272 |
| 273 bool LCodeGen::GenerateDeferredCode() { | 273 bool LCodeGen::GenerateDeferredCode() { |
| 274 ASSERT(is_generating()); | 274 ASSERT(is_generating()); |
| 275 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 275 if (deferred_.length() > 0) { |
| 276 LDeferredCode* code = deferred_[i]; | 276 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 277 __ bind(code->entry()); | 277 LDeferredCode* code = deferred_[i]; |
| 278 code->Generate(); | 278 __ bind(code->entry()); |
| 279 __ jmp(code->exit()); | 279 code->Generate(); |
| 280 __ jmp(code->exit()); |
| 281 } |
| 282 |
| 283 // Pad code to ensure that the last piece of deferred code have |
| 284 // room for lazy bailout. |
| 285 while ((masm()->pc_offset() - LastSafepointEnd()) |
| 286 < Deoptimizer::patch_size()) { |
| 287 int padding = masm()->pc_offset() - LastSafepointEnd(); |
| 288 if (padding > 9) { |
| 289 __ nop(9); |
| 290 } else { |
| 291 __ nop(padding); |
| 292 } |
| 293 } |
| 280 } | 294 } |
| 281 | 295 |
| 282 // Deferred code is the last part of the instruction sequence. Mark | 296 // Deferred code is the last part of the instruction sequence. Mark |
| 283 // the generated code as done unless we bailed out. | 297 // the generated code as done unless we bailed out. |
| 284 if (!is_aborted()) status_ = DONE; | 298 if (!is_aborted()) status_ = DONE; |
| 285 return !is_aborted(); | 299 return !is_aborted(); |
| 286 } | 300 } |
| 287 | 301 |
| 288 | 302 |
| 289 bool LCodeGen::GenerateSafepointTable() { | 303 bool LCodeGen::GenerateSafepointTable() { |
| (...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 | 696 |
| 683 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 697 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 684 int arguments, | 698 int arguments, |
| 685 int deoptimization_index) { | 699 int deoptimization_index) { |
| 686 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 700 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, |
| 687 deoptimization_index); | 701 deoptimization_index); |
| 688 } | 702 } |
| 689 | 703 |
| 690 | 704 |
| 691 void LCodeGen::RecordPosition(int position) { | 705 void LCodeGen::RecordPosition(int position) { |
| 692 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; | 706 if (position == RelocInfo::kNoPosition) return; |
| 693 masm()->positions_recorder()->RecordPosition(position); | 707 masm()->positions_recorder()->RecordPosition(position); |
| 694 } | 708 } |
| 695 | 709 |
| 696 | 710 |
| 697 void LCodeGen::DoLabel(LLabel* label) { | 711 void LCodeGen::DoLabel(LLabel* label) { |
| 698 if (label->is_loop_header()) { | 712 if (label->is_loop_header()) { |
| 699 Comment(";;; B%d - LOOP entry", label->block_id()); | 713 Comment(";;; B%d - LOOP entry", label->block_id()); |
| 700 } else { | 714 } else { |
| 701 Comment(";;; B%d", label->block_id()); | 715 Comment(";;; B%d", label->block_id()); |
| 702 } | 716 } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 | 813 |
| 800 Label positive_dividend, done; | 814 Label positive_dividend, done; |
| 801 __ testl(dividend, dividend); | 815 __ testl(dividend, dividend); |
| 802 __ j(not_sign, &positive_dividend, Label::kNear); | 816 __ j(not_sign, &positive_dividend, Label::kNear); |
| 803 __ negl(dividend); | 817 __ negl(dividend); |
| 804 __ andl(dividend, Immediate(divisor - 1)); | 818 __ andl(dividend, Immediate(divisor - 1)); |
| 805 __ negl(dividend); | 819 __ negl(dividend); |
| 806 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 820 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 807 __ j(not_zero, &done, Label::kNear); | 821 __ j(not_zero, &done, Label::kNear); |
| 808 DeoptimizeIf(no_condition, instr->environment()); | 822 DeoptimizeIf(no_condition, instr->environment()); |
| 823 } else { |
| 824 __ jmp(&done, Label::kNear); |
| 809 } | 825 } |
| 810 __ bind(&positive_dividend); | 826 __ bind(&positive_dividend); |
| 811 __ andl(dividend, Immediate(divisor - 1)); | 827 __ andl(dividend, Immediate(divisor - 1)); |
| 812 __ bind(&done); | 828 __ bind(&done); |
| 813 } else { | 829 } else { |
| 814 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; | 830 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; |
| 815 Register left_reg = ToRegister(instr->InputAt(0)); | 831 Register left_reg = ToRegister(instr->InputAt(0)); |
| 816 Register right_reg = ToRegister(instr->InputAt(1)); | 832 Register right_reg = ToRegister(instr->InputAt(1)); |
| 817 Register result_reg = ToRegister(instr->result()); | 833 Register result_reg = ToRegister(instr->result()); |
| 818 | 834 |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 } | 1220 } |
| 1205 | 1221 |
| 1206 | 1222 |
| 1207 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { | 1223 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { |
| 1208 Register result = ToRegister(instr->result()); | 1224 Register result = ToRegister(instr->result()); |
| 1209 Register array = ToRegister(instr->InputAt(0)); | 1225 Register array = ToRegister(instr->InputAt(0)); |
| 1210 __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset)); | 1226 __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset)); |
| 1211 } | 1227 } |
| 1212 | 1228 |
| 1213 | 1229 |
| 1230 void LCodeGen::DoElementsKind(LElementsKind* instr) { |
| 1231 Register result = ToRegister(instr->result()); |
| 1232 Register input = ToRegister(instr->InputAt(0)); |
| 1233 |
| 1234 // Load map into |result|. |
| 1235 __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); |
| 1236 // Load the map's "bit field 2" into |result|. We only need the first byte. |
| 1237 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset)); |
| 1238 // Retrieve elements_kind from bit field 2. |
| 1239 __ and_(result, Immediate(Map::kElementsKindMask)); |
| 1240 __ shr(result, Immediate(Map::kElementsKindShift)); |
| 1241 } |
| 1242 |
| 1243 |
| 1214 void LCodeGen::DoValueOf(LValueOf* instr) { | 1244 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1215 Register input = ToRegister(instr->InputAt(0)); | 1245 Register input = ToRegister(instr->InputAt(0)); |
| 1216 Register result = ToRegister(instr->result()); | 1246 Register result = ToRegister(instr->result()); |
| 1217 ASSERT(input.is(result)); | 1247 ASSERT(input.is(result)); |
| 1218 Label done; | 1248 Label done; |
| 1219 // If the object is a smi return the object. | 1249 // If the object is a smi return the object. |
| 1220 __ JumpIfSmi(input, &done, Label::kNear); | 1250 __ JumpIfSmi(input, &done, Label::kNear); |
| 1221 | 1251 |
| 1222 // If the object is not a value type, return the object. | 1252 // If the object is not a value type, return the object. |
| 1223 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); | 1253 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1337 __ jmp(chunk_->GetAssemblyLabel(right_block)); | 1367 __ jmp(chunk_->GetAssemblyLabel(right_block)); |
| 1338 } | 1368 } |
| 1339 } | 1369 } |
| 1340 } | 1370 } |
| 1341 | 1371 |
| 1342 | 1372 |
| 1343 void LCodeGen::DoBranch(LBranch* instr) { | 1373 void LCodeGen::DoBranch(LBranch* instr) { |
| 1344 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1374 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1345 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1375 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1346 | 1376 |
| 1347 Representation r = instr->hydrogen()->representation(); | 1377 Representation r = instr->hydrogen()->value()->representation(); |
| 1348 if (r.IsInteger32()) { | 1378 if (r.IsInteger32()) { |
| 1349 Register reg = ToRegister(instr->InputAt(0)); | 1379 Register reg = ToRegister(instr->InputAt(0)); |
| 1350 __ testl(reg, reg); | 1380 __ testl(reg, reg); |
| 1351 EmitBranch(true_block, false_block, not_zero); | 1381 EmitBranch(true_block, false_block, not_zero); |
| 1352 } else if (r.IsDouble()) { | 1382 } else if (r.IsDouble()) { |
| 1353 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); | 1383 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); |
| 1354 __ xorps(xmm0, xmm0); | 1384 __ xorps(xmm0, xmm0); |
| 1355 __ ucomisd(reg, xmm0); | 1385 __ ucomisd(reg, xmm0); |
| 1356 EmitBranch(true_block, false_block, not_equal); | 1386 EmitBranch(true_block, false_block, not_equal); |
| 1357 } else { | 1387 } else { |
| 1358 ASSERT(r.IsTagged()); | 1388 ASSERT(r.IsTagged()); |
| 1359 Register reg = ToRegister(instr->InputAt(0)); | 1389 Register reg = ToRegister(instr->InputAt(0)); |
| 1360 HType type = instr->hydrogen()->type(); | 1390 HType type = instr->hydrogen()->value()->type(); |
| 1361 if (type.IsBoolean()) { | 1391 if (type.IsBoolean()) { |
| 1362 __ CompareRoot(reg, Heap::kTrueValueRootIndex); | 1392 __ CompareRoot(reg, Heap::kTrueValueRootIndex); |
| 1363 EmitBranch(true_block, false_block, equal); | 1393 EmitBranch(true_block, false_block, equal); |
| 1364 } else if (type.IsSmi()) { | 1394 } else if (type.IsSmi()) { |
| 1365 __ SmiCompare(reg, Smi::FromInt(0)); | 1395 __ SmiCompare(reg, Smi::FromInt(0)); |
| 1366 EmitBranch(true_block, false_block, not_equal); | 1396 EmitBranch(true_block, false_block, not_equal); |
| 1367 } else { | 1397 } else { |
| 1368 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1398 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1369 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1399 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1370 | 1400 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1387 // HeapNumber => false iff +0, -0, or NaN. These three cases set the | 1417 // HeapNumber => false iff +0, -0, or NaN. These three cases set the |
| 1388 // zero flag when compared to zero using ucomisd. | 1418 // zero flag when compared to zero using ucomisd. |
| 1389 __ xorps(xmm0, xmm0); | 1419 __ xorps(xmm0, xmm0); |
| 1390 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); | 1420 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 1391 __ j(zero, false_label); | 1421 __ j(zero, false_label); |
| 1392 __ jmp(true_label); | 1422 __ jmp(true_label); |
| 1393 | 1423 |
| 1394 // The conversion stub doesn't cause garbage collections so it's | 1424 // The conversion stub doesn't cause garbage collections so it's |
| 1395 // safe to not record a safepoint after the call. | 1425 // safe to not record a safepoint after the call. |
| 1396 __ bind(&call_stub); | 1426 __ bind(&call_stub); |
| 1397 ToBooleanStub stub; | 1427 ToBooleanStub stub(rax); |
| 1398 __ Pushad(); | 1428 __ Pushad(); |
| 1399 __ push(reg); | 1429 __ push(reg); |
| 1400 __ CallStub(&stub); | 1430 __ CallStub(&stub); |
| 1401 __ testq(rax, rax); | 1431 __ testq(rax, rax); |
| 1402 __ Popad(); | 1432 __ Popad(); |
| 1403 EmitBranch(true_block, false_block, not_zero); | 1433 EmitBranch(true_block, false_block, not_zero); |
| 1404 } | 1434 } |
| 1405 } | 1435 } |
| 1406 } | 1436 } |
| 1407 | 1437 |
| 1408 | 1438 |
| 1409 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { | 1439 void LCodeGen::EmitGoto(int block) { |
| 1410 block = chunk_->LookupDestination(block); | 1440 block = chunk_->LookupDestination(block); |
| 1411 int next_block = GetNextEmittedBlock(current_block_); | 1441 int next_block = GetNextEmittedBlock(current_block_); |
| 1412 if (block != next_block) { | 1442 if (block != next_block) { |
| 1413 // Perform stack overflow check if this goto needs it before jumping. | 1443 __ jmp(chunk_->GetAssemblyLabel(block)); |
| 1414 if (deferred_stack_check != NULL) { | |
| 1415 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | |
| 1416 __ j(above_equal, chunk_->GetAssemblyLabel(block)); | |
| 1417 __ jmp(deferred_stack_check->entry()); | |
| 1418 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block)); | |
| 1419 } else { | |
| 1420 __ jmp(chunk_->GetAssemblyLabel(block)); | |
| 1421 } | |
| 1422 } | 1444 } |
| 1423 } | 1445 } |
| 1424 | 1446 |
| 1425 | 1447 |
| 1426 void LCodeGen::DoDeferredStackCheck(LGoto* instr) { | 1448 void LCodeGen::DoGoto(LGoto* instr) { |
| 1427 PushSafepointRegistersScope scope(this); | 1449 EmitGoto(instr->block_id()); |
| 1428 CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr); | |
| 1429 } | 1450 } |
| 1430 | 1451 |
| 1431 | 1452 |
| 1432 void LCodeGen::DoGoto(LGoto* instr) { | |
| 1433 class DeferredStackCheck: public LDeferredCode { | |
| 1434 public: | |
| 1435 DeferredStackCheck(LCodeGen* codegen, LGoto* instr) | |
| 1436 : LDeferredCode(codegen), instr_(instr) { } | |
| 1437 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } | |
| 1438 private: | |
| 1439 LGoto* instr_; | |
| 1440 }; | |
| 1441 | |
| 1442 DeferredStackCheck* deferred = NULL; | |
| 1443 if (instr->include_stack_check()) { | |
| 1444 deferred = new DeferredStackCheck(this, instr); | |
| 1445 } | |
| 1446 EmitGoto(instr->block_id(), deferred); | |
| 1447 } | |
| 1448 | |
| 1449 | |
| 1450 inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 1453 inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| 1451 Condition cond = no_condition; | 1454 Condition cond = no_condition; |
| 1452 switch (op) { | 1455 switch (op) { |
| 1453 case Token::EQ: | 1456 case Token::EQ: |
| 1454 case Token::EQ_STRICT: | 1457 case Token::EQ_STRICT: |
| 1455 cond = equal; | 1458 cond = equal; |
| 1456 break; | 1459 break; |
| 1457 case Token::LT: | 1460 case Token::LT: |
| 1458 cond = is_unsigned ? below : less; | 1461 cond = is_unsigned ? below : less; |
| 1459 break; | 1462 break; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1484 __ cmpl(ToOperand(left), Immediate(value)); | 1487 __ cmpl(ToOperand(left), Immediate(value)); |
| 1485 } | 1488 } |
| 1486 } else if (right->IsRegister()) { | 1489 } else if (right->IsRegister()) { |
| 1487 __ cmpl(ToRegister(left), ToRegister(right)); | 1490 __ cmpl(ToRegister(left), ToRegister(right)); |
| 1488 } else { | 1491 } else { |
| 1489 __ cmpl(ToRegister(left), ToOperand(right)); | 1492 __ cmpl(ToRegister(left), ToOperand(right)); |
| 1490 } | 1493 } |
| 1491 } | 1494 } |
| 1492 | 1495 |
| 1493 | 1496 |
| 1494 void LCodeGen::DoCmpID(LCmpID* instr) { | |
| 1495 LOperand* left = instr->InputAt(0); | |
| 1496 LOperand* right = instr->InputAt(1); | |
| 1497 LOperand* result = instr->result(); | |
| 1498 | |
| 1499 Label unordered; | |
| 1500 if (instr->is_double()) { | |
| 1501 // Don't base result on EFLAGS when a NaN is involved. Instead | |
| 1502 // jump to the unordered case, which produces a false value. | |
| 1503 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | |
| 1504 __ j(parity_even, &unordered, Label::kNear); | |
| 1505 } else { | |
| 1506 EmitCmpI(left, right); | |
| 1507 } | |
| 1508 | |
| 1509 Label done; | |
| 1510 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
| 1511 __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex); | |
| 1512 __ j(cc, &done, Label::kNear); | |
| 1513 | |
| 1514 __ bind(&unordered); | |
| 1515 __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex); | |
| 1516 __ bind(&done); | |
| 1517 } | |
| 1518 | |
| 1519 | |
| 1520 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1497 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 1521 LOperand* left = instr->InputAt(0); | 1498 LOperand* left = instr->InputAt(0); |
| 1522 LOperand* right = instr->InputAt(1); | 1499 LOperand* right = instr->InputAt(1); |
| 1523 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1500 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1524 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1501 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1525 | 1502 |
| 1526 if (instr->is_double()) { | 1503 if (instr->is_double()) { |
| 1527 // Don't base result on EFLAGS when a NaN is involved. Instead | 1504 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 1528 // jump to the false block. | 1505 // jump to the false block. |
| 1529 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1506 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 1530 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | 1507 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
| 1531 } else { | 1508 } else { |
| 1532 EmitCmpI(left, right); | 1509 EmitCmpI(left, right); |
| 1533 } | 1510 } |
| 1534 | 1511 |
| 1535 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | 1512 Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| 1536 EmitBranch(true_block, false_block, cc); | 1513 EmitBranch(true_block, false_block, cc); |
| 1537 } | 1514 } |
| 1538 | 1515 |
| 1539 | 1516 |
| 1540 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { | 1517 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
| 1541 Register left = ToRegister(instr->InputAt(0)); | |
| 1542 Register right = ToRegister(instr->InputAt(1)); | |
| 1543 Register result = ToRegister(instr->result()); | |
| 1544 | |
| 1545 Label different, done; | |
| 1546 __ cmpq(left, right); | |
| 1547 __ j(not_equal, &different, Label::kNear); | |
| 1548 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1549 __ jmp(&done, Label::kNear); | |
| 1550 __ bind(&different); | |
| 1551 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1552 __ bind(&done); | |
| 1553 } | |
| 1554 | |
| 1555 | |
| 1556 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { | |
| 1557 Register left = ToRegister(instr->InputAt(0)); | 1518 Register left = ToRegister(instr->InputAt(0)); |
| 1558 Register right = ToRegister(instr->InputAt(1)); | 1519 Register right = ToRegister(instr->InputAt(1)); |
| 1559 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1520 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1560 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1521 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1561 | 1522 |
| 1562 __ cmpq(left, right); | 1523 __ cmpq(left, right); |
| 1563 EmitBranch(true_block, false_block, equal); | 1524 EmitBranch(true_block, false_block, equal); |
| 1564 } | 1525 } |
| 1565 | 1526 |
| 1566 | 1527 |
| 1567 void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) { | 1528 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 1568 Register left = ToRegister(instr->InputAt(0)); | 1529 Register left = ToRegister(instr->InputAt(0)); |
| 1569 Register right = ToRegister(instr->InputAt(1)); | 1530 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1570 Register result = ToRegister(instr->result()); | 1531 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1571 | 1532 |
| 1572 Label done; | 1533 __ cmpq(left, Immediate(instr->hydrogen()->right())); |
| 1573 __ cmpq(left, right); | |
| 1574 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1575 __ j(not_equal, &done, Label::kNear); | |
| 1576 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1577 __ bind(&done); | |
| 1578 } | |
| 1579 | |
| 1580 | |
| 1581 void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) { | |
| 1582 Register left = ToRegister(instr->InputAt(0)); | |
| 1583 Register right = ToRegister(instr->InputAt(1)); | |
| 1584 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 1585 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 1586 | |
| 1587 __ cmpq(left, right); | |
| 1588 EmitBranch(true_block, false_block, equal); | 1534 EmitBranch(true_block, false_block, equal); |
| 1589 } | 1535 } |
| 1590 | 1536 |
| 1591 | 1537 |
| 1592 void LCodeGen::DoIsNull(LIsNull* instr) { | |
| 1593 Register reg = ToRegister(instr->InputAt(0)); | |
| 1594 Register result = ToRegister(instr->result()); | |
| 1595 | |
| 1596 // If the expression is known to be a smi, then it's | |
| 1597 // definitely not null. Materialize false. | |
| 1598 // Consider adding other type and representation tests too. | |
| 1599 if (instr->hydrogen()->value()->type().IsSmi()) { | |
| 1600 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1601 return; | |
| 1602 } | |
| 1603 | |
| 1604 __ CompareRoot(reg, Heap::kNullValueRootIndex); | |
| 1605 if (instr->is_strict()) { | |
| 1606 ASSERT(Heap::kTrueValueRootIndex >= 0); | |
| 1607 __ movl(result, Immediate(Heap::kTrueValueRootIndex)); | |
| 1608 Label load; | |
| 1609 __ j(equal, &load, Label::kNear); | |
| 1610 __ Set(result, Heap::kFalseValueRootIndex); | |
| 1611 __ bind(&load); | |
| 1612 __ LoadRootIndexed(result, result, 0); | |
| 1613 } else { | |
| 1614 Label false_value, true_value, done; | |
| 1615 __ j(equal, &true_value, Label::kNear); | |
| 1616 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); | |
| 1617 __ j(equal, &true_value, Label::kNear); | |
| 1618 __ JumpIfSmi(reg, &false_value, Label::kNear); | |
| 1619 // Check for undetectable objects by looking in the bit field in | |
| 1620 // the map. The object has already been smi checked. | |
| 1621 Register scratch = result; | |
| 1622 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | |
| 1623 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), | |
| 1624 Immediate(1 << Map::kIsUndetectable)); | |
| 1625 __ j(not_zero, &true_value, Label::kNear); | |
| 1626 __ bind(&false_value); | |
| 1627 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1628 __ jmp(&done, Label::kNear); | |
| 1629 __ bind(&true_value); | |
| 1630 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1631 __ bind(&done); | |
| 1632 } | |
| 1633 } | |
| 1634 | |
| 1635 | |
| 1636 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1538 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
| 1637 Register reg = ToRegister(instr->InputAt(0)); | 1539 Register reg = ToRegister(instr->InputAt(0)); |
| 1638 | 1540 |
| 1639 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1541 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1640 | 1542 |
| 1641 if (instr->hydrogen()->representation().IsSpecialization() || | 1543 if (instr->hydrogen()->representation().IsSpecialization() || |
| 1642 instr->hydrogen()->type().IsSmi()) { | 1544 instr->hydrogen()->type().IsSmi()) { |
| 1643 // If the expression is known to untagged or smi, then it's definitely | 1545 // If the expression is known to untagged or smi, then it's definitely |
| 1644 // not null, and it can't be a an undetectable object. | 1546 // not null, and it can't be a an undetectable object. |
| 1645 // Jump directly to the false block. | 1547 // Jump directly to the false block. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1681 __ j(equal, is_object); | 1583 __ j(equal, is_object); |
| 1682 | 1584 |
| 1683 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); | 1585 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); |
| 1684 // Undetectable objects behave like undefined. | 1586 // Undetectable objects behave like undefined. |
| 1685 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 1587 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
| 1686 Immediate(1 << Map::kIsUndetectable)); | 1588 Immediate(1 << Map::kIsUndetectable)); |
| 1687 __ j(not_zero, is_not_object); | 1589 __ j(not_zero, is_not_object); |
| 1688 | 1590 |
| 1689 __ movzxbl(kScratchRegister, | 1591 __ movzxbl(kScratchRegister, |
| 1690 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); | 1592 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
| 1691 __ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE)); | 1593 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 1692 __ j(below, is_not_object); | 1594 __ j(below, is_not_object); |
| 1693 __ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE)); | 1595 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 1694 return below_equal; | 1596 return below_equal; |
| 1695 } | 1597 } |
| 1696 | 1598 |
| 1697 | 1599 |
| 1698 void LCodeGen::DoIsObject(LIsObject* instr) { | |
| 1699 Register reg = ToRegister(instr->InputAt(0)); | |
| 1700 Register result = ToRegister(instr->result()); | |
| 1701 Label is_false, is_true, done; | |
| 1702 | |
| 1703 Condition true_cond = EmitIsObject(reg, &is_false, &is_true); | |
| 1704 __ j(true_cond, &is_true); | |
| 1705 | |
| 1706 __ bind(&is_false); | |
| 1707 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1708 __ jmp(&done); | |
| 1709 | |
| 1710 __ bind(&is_true); | |
| 1711 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1712 | |
| 1713 __ bind(&done); | |
| 1714 } | |
| 1715 | |
| 1716 | |
| 1717 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 1600 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 1718 Register reg = ToRegister(instr->InputAt(0)); | 1601 Register reg = ToRegister(instr->InputAt(0)); |
| 1719 | 1602 |
| 1720 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1603 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1721 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1604 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1722 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1605 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1723 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1606 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1724 | 1607 |
| 1725 Condition true_cond = EmitIsObject(reg, false_label, true_label); | 1608 Condition true_cond = EmitIsObject(reg, false_label, true_label); |
| 1726 | 1609 |
| 1727 EmitBranch(true_block, false_block, true_cond); | 1610 EmitBranch(true_block, false_block, true_cond); |
| 1728 } | 1611 } |
| 1729 | 1612 |
| 1730 | 1613 |
| 1731 void LCodeGen::DoIsSmi(LIsSmi* instr) { | |
| 1732 LOperand* input_operand = instr->InputAt(0); | |
| 1733 Register result = ToRegister(instr->result()); | |
| 1734 if (input_operand->IsRegister()) { | |
| 1735 Register input = ToRegister(input_operand); | |
| 1736 __ CheckSmiToIndicator(result, input); | |
| 1737 } else { | |
| 1738 Operand input = ToOperand(instr->InputAt(0)); | |
| 1739 __ CheckSmiToIndicator(result, input); | |
| 1740 } | |
| 1741 // result is zero if input is a smi, and one otherwise. | |
| 1742 ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1); | |
| 1743 __ LoadRootIndexed(result, result, Heap::kTrueValueRootIndex); | |
| 1744 } | |
| 1745 | |
| 1746 | |
| 1747 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 1614 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 1748 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1615 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1749 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1616 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1750 | 1617 |
| 1751 Condition is_smi; | 1618 Condition is_smi; |
| 1752 if (instr->InputAt(0)->IsRegister()) { | 1619 if (instr->InputAt(0)->IsRegister()) { |
| 1753 Register input = ToRegister(instr->InputAt(0)); | 1620 Register input = ToRegister(instr->InputAt(0)); |
| 1754 is_smi = masm()->CheckSmi(input); | 1621 is_smi = masm()->CheckSmi(input); |
| 1755 } else { | 1622 } else { |
| 1756 Operand input = ToOperand(instr->InputAt(0)); | 1623 Operand input = ToOperand(instr->InputAt(0)); |
| 1757 is_smi = masm()->CheckSmi(input); | 1624 is_smi = masm()->CheckSmi(input); |
| 1758 } | 1625 } |
| 1759 EmitBranch(true_block, false_block, is_smi); | 1626 EmitBranch(true_block, false_block, is_smi); |
| 1760 } | 1627 } |
| 1761 | 1628 |
| 1762 | 1629 |
| 1763 void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) { | |
| 1764 Register input = ToRegister(instr->InputAt(0)); | |
| 1765 Register result = ToRegister(instr->result()); | |
| 1766 | |
| 1767 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1768 Label false_label, done; | |
| 1769 __ JumpIfSmi(input, &false_label); | |
| 1770 __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); | |
| 1771 __ testb(FieldOperand(result, Map::kBitFieldOffset), | |
| 1772 Immediate(1 << Map::kIsUndetectable)); | |
| 1773 __ j(zero, &false_label); | |
| 1774 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1775 __ jmp(&done); | |
| 1776 __ bind(&false_label); | |
| 1777 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1778 __ bind(&done); | |
| 1779 } | |
| 1780 | |
| 1781 | |
| 1782 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 1630 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 1783 Register input = ToRegister(instr->InputAt(0)); | 1631 Register input = ToRegister(instr->InputAt(0)); |
| 1784 Register temp = ToRegister(instr->TempAt(0)); | 1632 Register temp = ToRegister(instr->TempAt(0)); |
| 1785 | 1633 |
| 1786 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1634 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1787 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1635 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1788 | 1636 |
| 1789 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); | 1637 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); |
| 1790 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); | 1638 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 1791 __ testb(FieldOperand(temp, Map::kBitFieldOffset), | 1639 __ testb(FieldOperand(temp, Map::kBitFieldOffset), |
| 1792 Immediate(1 << Map::kIsUndetectable)); | 1640 Immediate(1 << Map::kIsUndetectable)); |
| 1793 EmitBranch(true_block, false_block, not_zero); | 1641 EmitBranch(true_block, false_block, not_zero); |
| 1794 } | 1642 } |
| 1795 | 1643 |
| 1796 | 1644 |
| 1797 static InstanceType TestType(HHasInstanceType* instr) { | 1645 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { |
| 1798 InstanceType from = instr->from(); | 1646 InstanceType from = instr->from(); |
| 1799 InstanceType to = instr->to(); | 1647 InstanceType to = instr->to(); |
| 1800 if (from == FIRST_TYPE) return to; | 1648 if (from == FIRST_TYPE) return to; |
| 1801 ASSERT(from == to || to == LAST_TYPE); | 1649 ASSERT(from == to || to == LAST_TYPE); |
| 1802 return from; | 1650 return from; |
| 1803 } | 1651 } |
| 1804 | 1652 |
| 1805 | 1653 |
| 1806 static Condition BranchCondition(HHasInstanceType* instr) { | 1654 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { |
| 1807 InstanceType from = instr->from(); | 1655 InstanceType from = instr->from(); |
| 1808 InstanceType to = instr->to(); | 1656 InstanceType to = instr->to(); |
| 1809 if (from == to) return equal; | 1657 if (from == to) return equal; |
| 1810 if (to == LAST_TYPE) return above_equal; | 1658 if (to == LAST_TYPE) return above_equal; |
| 1811 if (from == FIRST_TYPE) return below_equal; | 1659 if (from == FIRST_TYPE) return below_equal; |
| 1812 UNREACHABLE(); | 1660 UNREACHABLE(); |
| 1813 return equal; | 1661 return equal; |
| 1814 } | 1662 } |
| 1815 | 1663 |
| 1816 | 1664 |
| 1817 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | |
| 1818 Register input = ToRegister(instr->InputAt(0)); | |
| 1819 Register result = ToRegister(instr->result()); | |
| 1820 | |
| 1821 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1822 __ testl(input, Immediate(kSmiTagMask)); | |
| 1823 Label done, is_false; | |
| 1824 __ j(zero, &is_false); | |
| 1825 __ CmpObjectType(input, TestType(instr->hydrogen()), result); | |
| 1826 __ j(NegateCondition(BranchCondition(instr->hydrogen())), | |
| 1827 &is_false, Label::kNear); | |
| 1828 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1829 __ jmp(&done, Label::kNear); | |
| 1830 __ bind(&is_false); | |
| 1831 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1832 __ bind(&done); | |
| 1833 } | |
| 1834 | |
| 1835 | |
| 1836 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1665 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 1837 Register input = ToRegister(instr->InputAt(0)); | 1666 Register input = ToRegister(instr->InputAt(0)); |
| 1838 | 1667 |
| 1839 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1668 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1840 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1669 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1841 | 1670 |
| 1842 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1671 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1843 | 1672 |
| 1844 __ JumpIfSmi(input, false_label); | 1673 __ JumpIfSmi(input, false_label); |
| 1845 | 1674 |
| 1846 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); | 1675 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); |
| 1847 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 1676 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1848 } | 1677 } |
| 1849 | 1678 |
| 1850 | 1679 |
| 1851 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { | 1680 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 1852 Register input = ToRegister(instr->InputAt(0)); | 1681 Register input = ToRegister(instr->InputAt(0)); |
| 1853 Register result = ToRegister(instr->result()); | 1682 Register result = ToRegister(instr->result()); |
| 1854 | 1683 |
| 1855 if (FLAG_debug_code) { | 1684 if (FLAG_debug_code) { |
| 1856 __ AbortIfNotString(input); | 1685 __ AbortIfNotString(input); |
| 1857 } | 1686 } |
| 1858 | 1687 |
| 1859 __ movl(result, FieldOperand(input, String::kHashFieldOffset)); | 1688 __ movl(result, FieldOperand(input, String::kHashFieldOffset)); |
| 1860 ASSERT(String::kHashShift >= kSmiTagSize); | 1689 ASSERT(String::kHashShift >= kSmiTagSize); |
| 1861 __ IndexFromHash(result, result); | 1690 __ IndexFromHash(result, result); |
| 1862 } | 1691 } |
| 1863 | 1692 |
| 1864 | 1693 |
| 1865 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | |
| 1866 Register input = ToRegister(instr->InputAt(0)); | |
| 1867 Register result = ToRegister(instr->result()); | |
| 1868 | |
| 1869 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1870 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1871 __ testl(FieldOperand(input, String::kHashFieldOffset), | |
| 1872 Immediate(String::kContainsCachedArrayIndexMask)); | |
| 1873 Label done; | |
| 1874 __ j(zero, &done, Label::kNear); | |
| 1875 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1876 __ bind(&done); | |
| 1877 } | |
| 1878 | |
| 1879 | |
| 1880 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1694 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1881 LHasCachedArrayIndexAndBranch* instr) { | 1695 LHasCachedArrayIndexAndBranch* instr) { |
| 1882 Register input = ToRegister(instr->InputAt(0)); | 1696 Register input = ToRegister(instr->InputAt(0)); |
| 1883 | 1697 |
| 1884 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1698 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1885 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1699 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1886 | 1700 |
| 1887 __ testl(FieldOperand(input, String::kHashFieldOffset), | 1701 __ testl(FieldOperand(input, String::kHashFieldOffset), |
| 1888 Immediate(String::kContainsCachedArrayIndexMask)); | 1702 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1889 EmitBranch(true_block, false_block, equal); | 1703 EmitBranch(true_block, false_block, equal); |
| 1890 } | 1704 } |
| 1891 | 1705 |
| 1892 | 1706 |
| 1893 // Branches to a label or falls through with the answer in the z flag. | 1707 // Branches to a label or falls through with the answer in the z flag. |
| 1894 // Trashes the temp register and possibly input (if it and temp are aliased). | 1708 // Trashes the temp register and possibly input (if it and temp are aliased). |
| 1895 void LCodeGen::EmitClassOfTest(Label* is_true, | 1709 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1896 Label* is_false, | 1710 Label* is_false, |
| 1897 Handle<String> class_name, | 1711 Handle<String> class_name, |
| 1898 Register input, | 1712 Register input, |
| 1899 Register temp) { | 1713 Register temp) { |
| 1900 __ JumpIfSmi(input, is_false); | 1714 __ JumpIfSmi(input, is_false); |
| 1901 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp); | 1715 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
| 1902 __ j(below, is_false); | 1716 __ j(below, is_false); |
| 1903 | 1717 |
| 1904 // Map is now in temp. | 1718 // Map is now in temp. |
| 1905 // Functions have class 'Function'. | 1719 // Functions have class 'Function'. |
| 1906 __ CmpInstanceType(temp, JS_FUNCTION_TYPE); | 1720 __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1907 if (class_name->IsEqualTo(CStrVector("Function"))) { | 1721 if (class_name->IsEqualTo(CStrVector("Function"))) { |
| 1908 __ j(equal, is_true); | 1722 __ j(above_equal, is_true); |
| 1909 } else { | 1723 } else { |
| 1910 __ j(equal, is_false); | 1724 __ j(above_equal, is_false); |
| 1911 } | 1725 } |
| 1912 | 1726 |
| 1913 // Check if the constructor in the map is a function. | 1727 // Check if the constructor in the map is a function. |
| 1914 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); | 1728 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); |
| 1915 | 1729 |
| 1916 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 1730 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last type and |
| 1917 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 1731 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
| 1918 // LAST_JS_OBJECT_TYPE. | 1732 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
| 1919 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1733 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1920 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 1734 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
| 1735 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
| 1921 | 1736 |
| 1922 // Objects with a non-function constructor have class 'Object'. | 1737 // Objects with a non-function constructor have class 'Object'. |
| 1923 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); | 1738 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); |
| 1924 if (class_name->IsEqualTo(CStrVector("Object"))) { | 1739 if (class_name->IsEqualTo(CStrVector("Object"))) { |
| 1925 __ j(not_equal, is_true); | 1740 __ j(not_equal, is_true); |
| 1926 } else { | 1741 } else { |
| 1927 __ j(not_equal, is_false); | 1742 __ j(not_equal, is_false); |
| 1928 } | 1743 } |
| 1929 | 1744 |
| 1930 // temp now contains the constructor function. Grab the | 1745 // temp now contains the constructor function. Grab the |
| 1931 // instance class name from there. | 1746 // instance class name from there. |
| 1932 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); | 1747 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
| 1933 __ movq(temp, FieldOperand(temp, | 1748 __ movq(temp, FieldOperand(temp, |
| 1934 SharedFunctionInfo::kInstanceClassNameOffset)); | 1749 SharedFunctionInfo::kInstanceClassNameOffset)); |
| 1935 // The class name we are testing against is a symbol because it's a literal. | 1750 // The class name we are testing against is a symbol because it's a literal. |
| 1936 // The name in the constructor is a symbol because of the way the context is | 1751 // The name in the constructor is a symbol because of the way the context is |
| 1937 // booted. This routine isn't expected to work for random API-created | 1752 // booted. This routine isn't expected to work for random API-created |
| 1938 // classes and it doesn't have to because you can't access it with natives | 1753 // classes and it doesn't have to because you can't access it with natives |
| 1939 // syntax. Since both sides are symbols it is sufficient to use an identity | 1754 // syntax. Since both sides are symbols it is sufficient to use an identity |
| 1940 // comparison. | 1755 // comparison. |
| 1941 ASSERT(class_name->IsSymbol()); | 1756 ASSERT(class_name->IsSymbol()); |
| 1942 __ Cmp(temp, class_name); | 1757 __ Cmp(temp, class_name); |
| 1943 // End with the answer in the z flag. | 1758 // End with the answer in the z flag. |
| 1944 } | 1759 } |
| 1945 | 1760 |
| 1946 | 1761 |
| 1947 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { | |
| 1948 Register input = ToRegister(instr->InputAt(0)); | |
| 1949 Register result = ToRegister(instr->result()); | |
| 1950 ASSERT(input.is(result)); | |
| 1951 Register temp = ToRegister(instr->TempAt(0)); | |
| 1952 Handle<String> class_name = instr->hydrogen()->class_name(); | |
| 1953 Label done; | |
| 1954 Label is_true, is_false; | |
| 1955 | |
| 1956 EmitClassOfTest(&is_true, &is_false, class_name, input, temp); | |
| 1957 | |
| 1958 __ j(not_equal, &is_false); | |
| 1959 | |
| 1960 __ bind(&is_true); | |
| 1961 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 1962 __ jmp(&done, Label::kNear); | |
| 1963 | |
| 1964 __ bind(&is_false); | |
| 1965 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 1966 __ bind(&done); | |
| 1967 } | |
| 1968 | |
| 1969 | |
| 1970 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1762 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 1971 Register input = ToRegister(instr->InputAt(0)); | 1763 Register input = ToRegister(instr->InputAt(0)); |
| 1972 Register temp = ToRegister(instr->TempAt(0)); | 1764 Register temp = ToRegister(instr->TempAt(0)); |
| 1973 Handle<String> class_name = instr->hydrogen()->class_name(); | 1765 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 1974 | 1766 |
| 1975 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1767 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1976 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1768 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1977 | 1769 |
| 1978 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1770 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1979 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1771 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2003 __ testq(rax, rax); | 1795 __ testq(rax, rax); |
| 2004 __ j(zero, &true_value, Label::kNear); | 1796 __ j(zero, &true_value, Label::kNear); |
| 2005 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | 1797 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 2006 __ jmp(&done, Label::kNear); | 1798 __ jmp(&done, Label::kNear); |
| 2007 __ bind(&true_value); | 1799 __ bind(&true_value); |
| 2008 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); | 1800 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
| 2009 __ bind(&done); | 1801 __ bind(&done); |
| 2010 } | 1802 } |
| 2011 | 1803 |
| 2012 | 1804 |
| 2013 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { | |
| 2014 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2015 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2016 | |
| 2017 InstanceofStub stub(InstanceofStub::kNoFlags); | |
| 2018 __ push(ToRegister(instr->InputAt(0))); | |
| 2019 __ push(ToRegister(instr->InputAt(1))); | |
| 2020 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
| 2021 __ testq(rax, rax); | |
| 2022 EmitBranch(true_block, false_block, zero); | |
| 2023 } | |
| 2024 | |
| 2025 | |
| 2026 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1805 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 2027 class DeferredInstanceOfKnownGlobal: public LDeferredCode { | 1806 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 2028 public: | 1807 public: |
| 2029 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 1808 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 2030 LInstanceOfKnownGlobal* instr) | 1809 LInstanceOfKnownGlobal* instr) |
| 2031 : LDeferredCode(codegen), instr_(instr) { } | 1810 : LDeferredCode(codegen), instr_(instr) { } |
| 2032 virtual void Generate() { | 1811 virtual void Generate() { |
| 2033 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); | 1812 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 2034 } | 1813 } |
| 2035 | 1814 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2147 __ testq(rax, rax); | 1926 __ testq(rax, rax); |
| 2148 __ j(condition, &true_value, Label::kNear); | 1927 __ j(condition, &true_value, Label::kNear); |
| 2149 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | 1928 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 2150 __ jmp(&done, Label::kNear); | 1929 __ jmp(&done, Label::kNear); |
| 2151 __ bind(&true_value); | 1930 __ bind(&true_value); |
| 2152 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); | 1931 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
| 2153 __ bind(&done); | 1932 __ bind(&done); |
| 2154 } | 1933 } |
| 2155 | 1934 |
| 2156 | 1935 |
| 2157 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { | |
| 2158 Token::Value op = instr->op(); | |
| 2159 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2160 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2161 | |
| 2162 Handle<Code> ic = CompareIC::GetUninitialized(op); | |
| 2163 CallCode(ic, RelocInfo::CODE_TARGET, instr); | |
| 2164 | |
| 2165 // The compare stub expects compare condition and the input operands | |
| 2166 // reversed for GT and LTE. | |
| 2167 Condition condition = TokenToCondition(op, false); | |
| 2168 if (op == Token::GT || op == Token::LTE) { | |
| 2169 condition = ReverseCondition(condition); | |
| 2170 } | |
| 2171 __ testq(rax, rax); | |
| 2172 EmitBranch(true_block, false_block, condition); | |
| 2173 } | |
| 2174 | |
| 2175 | |
| 2176 void LCodeGen::DoReturn(LReturn* instr) { | 1936 void LCodeGen::DoReturn(LReturn* instr) { |
| 2177 if (FLAG_trace) { | 1937 if (FLAG_trace) { |
| 2178 // Preserve the return value on the stack and rely on the runtime | 1938 // Preserve the return value on the stack and rely on the runtime |
| 2179 // call to return the value in the same register. | 1939 // call to return the value in the same register. |
| 2180 __ push(rax); | 1940 __ push(rax); |
| 2181 __ CallRuntime(Runtime::kTraceExit, 1); | 1941 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2182 } | 1942 } |
| 2183 __ movq(rsp, rbp); | 1943 __ movq(rsp, rbp); |
| 2184 __ pop(rbp); | 1944 __ pop(rbp); |
| 2185 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx); | 1945 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx); |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2413 // All done. | 2173 // All done. |
| 2414 __ bind(&done); | 2174 __ bind(&done); |
| 2415 } | 2175 } |
| 2416 | 2176 |
| 2417 | 2177 |
| 2418 void LCodeGen::DoLoadElements(LLoadElements* instr) { | 2178 void LCodeGen::DoLoadElements(LLoadElements* instr) { |
| 2419 Register result = ToRegister(instr->result()); | 2179 Register result = ToRegister(instr->result()); |
| 2420 Register input = ToRegister(instr->InputAt(0)); | 2180 Register input = ToRegister(instr->InputAt(0)); |
| 2421 __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); | 2181 __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); |
| 2422 if (FLAG_debug_code) { | 2182 if (FLAG_debug_code) { |
| 2423 Label done; | 2183 Label done, ok, fail; |
| 2424 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), | 2184 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), |
| 2425 Heap::kFixedArrayMapRootIndex); | 2185 Heap::kFixedArrayMapRootIndex); |
| 2426 __ j(equal, &done, Label::kNear); | 2186 __ j(equal, &done, Label::kNear); |
| 2427 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), | 2187 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), |
| 2428 Heap::kFixedCOWArrayMapRootIndex); | 2188 Heap::kFixedCOWArrayMapRootIndex); |
| 2429 __ j(equal, &done, Label::kNear); | 2189 __ j(equal, &done, Label::kNear); |
| 2430 Register temp((result.is(rax)) ? rbx : rax); | 2190 Register temp((result.is(rax)) ? rbx : rax); |
| 2431 __ push(temp); | 2191 __ push(temp); |
| 2432 __ movq(temp, FieldOperand(result, HeapObject::kMapOffset)); | 2192 __ movq(temp, FieldOperand(result, HeapObject::kMapOffset)); |
| 2433 __ movzxbq(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 2193 __ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset)); |
| 2434 __ subq(temp, Immediate(FIRST_EXTERNAL_ARRAY_TYPE)); | 2194 __ and_(temp, Immediate(Map::kElementsKindMask)); |
| 2435 __ cmpq(temp, Immediate(kExternalArrayTypeCount)); | 2195 __ shr(temp, Immediate(Map::kElementsKindShift)); |
| 2196 __ cmpl(temp, Immediate(JSObject::FAST_ELEMENTS)); |
| 2197 __ j(equal, &ok, Label::kNear); |
| 2198 __ cmpl(temp, Immediate(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND)); |
| 2199 __ j(less, &fail, Label::kNear); |
| 2200 __ cmpl(temp, Immediate(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND)); |
| 2201 __ j(less_equal, &ok, Label::kNear); |
| 2202 __ bind(&fail); |
| 2203 __ Abort("Check for fast or external elements failed"); |
| 2204 __ bind(&ok); |
| 2436 __ pop(temp); | 2205 __ pop(temp); |
| 2437 __ Check(below, "Check for fast elements failed."); | |
| 2438 __ bind(&done); | 2206 __ bind(&done); |
| 2439 } | 2207 } |
| 2440 } | 2208 } |
| 2441 | 2209 |
| 2442 | 2210 |
| 2443 void LCodeGen::DoLoadExternalArrayPointer( | 2211 void LCodeGen::DoLoadExternalArrayPointer( |
| 2444 LLoadExternalArrayPointer* instr) { | 2212 LLoadExternalArrayPointer* instr) { |
| 2445 Register result = ToRegister(instr->result()); | 2213 Register result = ToRegister(instr->result()); |
| 2446 Register input = ToRegister(instr->InputAt(0)); | 2214 Register input = ToRegister(instr->InputAt(0)); |
| 2447 __ movq(result, FieldOperand(input, | 2215 __ movq(result, FieldOperand(input, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2480 FixedArray::kHeaderSize)); | 2248 FixedArray::kHeaderSize)); |
| 2481 | 2249 |
| 2482 // Check for the hole value. | 2250 // Check for the hole value. |
| 2483 if (instr->hydrogen()->RequiresHoleCheck()) { | 2251 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2484 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2252 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2485 DeoptimizeIf(equal, instr->environment()); | 2253 DeoptimizeIf(equal, instr->environment()); |
| 2486 } | 2254 } |
| 2487 } | 2255 } |
| 2488 | 2256 |
| 2489 | 2257 |
| 2490 Operand LCodeGen::BuildExternalArrayOperand(LOperand* external_pointer, | 2258 Operand LCodeGen::BuildExternalArrayOperand( |
| 2491 LOperand* key, | 2259 LOperand* external_pointer, |
| 2492 ExternalArrayType array_type) { | 2260 LOperand* key, |
| 2261 JSObject::ElementsKind elements_kind) { |
| 2493 Register external_pointer_reg = ToRegister(external_pointer); | 2262 Register external_pointer_reg = ToRegister(external_pointer); |
| 2494 int shift_size = ExternalArrayTypeToShiftSize(array_type); | 2263 int shift_size = ElementsKindToShiftSize(elements_kind); |
| 2495 if (key->IsConstantOperand()) { | 2264 if (key->IsConstantOperand()) { |
| 2496 int constant_value = ToInteger32(LConstantOperand::cast(key)); | 2265 int constant_value = ToInteger32(LConstantOperand::cast(key)); |
| 2497 if (constant_value & 0xF0000000) { | 2266 if (constant_value & 0xF0000000) { |
| 2498 Abort("array index constant value too big"); | 2267 Abort("array index constant value too big"); |
| 2499 } | 2268 } |
| 2500 return Operand(external_pointer_reg, constant_value * (1 << shift_size)); | 2269 return Operand(external_pointer_reg, constant_value * (1 << shift_size)); |
| 2501 } else { | 2270 } else { |
| 2502 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); | 2271 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); |
| 2503 return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); | 2272 return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); |
| 2504 } | 2273 } |
| 2505 } | 2274 } |
| 2506 | 2275 |
| 2507 | 2276 |
| 2508 void LCodeGen::DoLoadKeyedSpecializedArrayElement( | 2277 void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
| 2509 LLoadKeyedSpecializedArrayElement* instr) { | 2278 LLoadKeyedSpecializedArrayElement* instr) { |
| 2510 ExternalArrayType array_type = instr->array_type(); | 2279 JSObject::ElementsKind elements_kind = instr->elements_kind(); |
| 2511 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), | 2280 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), |
| 2512 instr->key(), array_type)); | 2281 instr->key(), elements_kind)); |
| 2513 if (array_type == kExternalFloatArray) { | 2282 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 2514 XMMRegister result(ToDoubleRegister(instr->result())); | 2283 XMMRegister result(ToDoubleRegister(instr->result())); |
| 2515 __ movss(result, operand); | 2284 __ movss(result, operand); |
| 2516 __ cvtss2sd(result, result); | 2285 __ cvtss2sd(result, result); |
| 2517 } else if (array_type == kExternalDoubleArray) { | 2286 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 2518 __ movsd(ToDoubleRegister(instr->result()), operand); | 2287 __ movsd(ToDoubleRegister(instr->result()), operand); |
| 2519 } else { | 2288 } else { |
| 2520 Register result(ToRegister(instr->result())); | 2289 Register result(ToRegister(instr->result())); |
| 2521 switch (array_type) { | 2290 switch (elements_kind) { |
| 2522 case kExternalByteArray: | 2291 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 2523 __ movsxbq(result, operand); | 2292 __ movsxbq(result, operand); |
| 2524 break; | 2293 break; |
| 2525 case kExternalUnsignedByteArray: | 2294 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 2526 case kExternalPixelArray: | 2295 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 2527 __ movzxbq(result, operand); | 2296 __ movzxbq(result, operand); |
| 2528 break; | 2297 break; |
| 2529 case kExternalShortArray: | 2298 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 2530 __ movsxwq(result, operand); | 2299 __ movsxwq(result, operand); |
| 2531 break; | 2300 break; |
| 2532 case kExternalUnsignedShortArray: | 2301 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 2533 __ movzxwq(result, operand); | 2302 __ movzxwq(result, operand); |
| 2534 break; | 2303 break; |
| 2535 case kExternalIntArray: | 2304 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 2536 __ movsxlq(result, operand); | 2305 __ movsxlq(result, operand); |
| 2537 break; | 2306 break; |
| 2538 case kExternalUnsignedIntArray: | 2307 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 2539 __ movl(result, operand); | 2308 __ movl(result, operand); |
| 2540 __ testl(result, result); | 2309 __ testl(result, result); |
| 2541 // TODO(danno): we could be more clever here, perhaps having a special | 2310 // TODO(danno): we could be more clever here, perhaps having a special |
| 2542 // version of the stub that detects if the overflow case actually | 2311 // version of the stub that detects if the overflow case actually |
| 2543 // happens, and generate code that returns a double rather than int. | 2312 // happens, and generate code that returns a double rather than int. |
| 2544 DeoptimizeIf(negative, instr->environment()); | 2313 DeoptimizeIf(negative, instr->environment()); |
| 2545 break; | 2314 break; |
| 2546 case kExternalFloatArray: | 2315 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 2547 case kExternalDoubleArray: | 2316 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 2317 case JSObject::FAST_ELEMENTS: |
| 2318 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 2319 case JSObject::DICTIONARY_ELEMENTS: |
| 2320 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 2548 UNREACHABLE(); | 2321 UNREACHABLE(); |
| 2549 break; | 2322 break; |
| 2550 } | 2323 } |
| 2551 } | 2324 } |
| 2552 } | 2325 } |
| 2553 | 2326 |
| 2554 | 2327 |
| 2555 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2328 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| 2556 ASSERT(ToRegister(instr->object()).is(rdx)); | 2329 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 2557 ASSERT(ToRegister(instr->key()).is(rax)); | 2330 ASSERT(ToRegister(instr->key()).is(rax)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2612 | 2385 |
| 2613 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 2386 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 2614 Register receiver = ToRegister(instr->receiver()); | 2387 Register receiver = ToRegister(instr->receiver()); |
| 2615 Register function = ToRegister(instr->function()); | 2388 Register function = ToRegister(instr->function()); |
| 2616 Register length = ToRegister(instr->length()); | 2389 Register length = ToRegister(instr->length()); |
| 2617 Register elements = ToRegister(instr->elements()); | 2390 Register elements = ToRegister(instr->elements()); |
| 2618 ASSERT(receiver.is(rax)); // Used for parameter count. | 2391 ASSERT(receiver.is(rax)); // Used for parameter count. |
| 2619 ASSERT(function.is(rdi)); // Required by InvokeFunction. | 2392 ASSERT(function.is(rdi)); // Required by InvokeFunction. |
| 2620 ASSERT(ToRegister(instr->result()).is(rax)); | 2393 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2621 | 2394 |
| 2622 // If the receiver is null or undefined, we have to pass the global object | 2395 // If the receiver is null or undefined, we have to pass the global |
| 2623 // as a receiver. | 2396 // object as a receiver to normal functions. Values have to be |
| 2397 // passed unchanged to builtins and strict-mode functions. |
| 2624 Label global_object, receiver_ok; | 2398 Label global_object, receiver_ok; |
| 2399 |
| 2400 // Do not transform the receiver to object for strict mode |
| 2401 // functions. |
| 2402 __ movq(kScratchRegister, |
| 2403 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 2404 __ testb(FieldOperand(kScratchRegister, |
| 2405 SharedFunctionInfo::kStrictModeByteOffset), |
| 2406 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); |
| 2407 __ j(not_equal, &receiver_ok, Label::kNear); |
| 2408 |
| 2409 // Do not transform the receiver to object for builtins. |
| 2410 __ testb(FieldOperand(kScratchRegister, |
| 2411 SharedFunctionInfo::kNativeByteOffset), |
| 2412 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); |
| 2413 __ j(not_equal, &receiver_ok, Label::kNear); |
| 2414 |
| 2415 // Normal function. Replace undefined or null with global receiver. |
| 2625 __ CompareRoot(receiver, Heap::kNullValueRootIndex); | 2416 __ CompareRoot(receiver, Heap::kNullValueRootIndex); |
| 2626 __ j(equal, &global_object, Label::kNear); | 2417 __ j(equal, &global_object, Label::kNear); |
| 2627 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); | 2418 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); |
| 2628 __ j(equal, &global_object, Label::kNear); | 2419 __ j(equal, &global_object, Label::kNear); |
| 2629 | 2420 |
| 2630 // The receiver should be a JS object. | 2421 // The receiver should be a JS object. |
| 2631 Condition is_smi = __ CheckSmi(receiver); | 2422 Condition is_smi = __ CheckSmi(receiver); |
| 2632 DeoptimizeIf(is_smi, instr->environment()); | 2423 DeoptimizeIf(is_smi, instr->environment()); |
| 2633 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 2424 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); |
| 2634 DeoptimizeIf(below, instr->environment()); | 2425 DeoptimizeIf(below, instr->environment()); |
| 2635 __ jmp(&receiver_ok, Label::kNear); | 2426 __ jmp(&receiver_ok, Label::kNear); |
| 2636 | 2427 |
| 2637 __ bind(&global_object); | 2428 __ bind(&global_object); |
| 2638 // TODO(kmillikin): We have a hydrogen value for the global object. See | 2429 // TODO(kmillikin): We have a hydrogen value for the global object. See |
| 2639 // if it's better to use it than to explicitly fetch it from the context | 2430 // if it's better to use it than to explicitly fetch it from the context |
| 2640 // here. | 2431 // here. |
| 2641 __ movq(receiver, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2432 __ movq(receiver, ContextOperand(rsi, Context::GLOBAL_INDEX)); |
| 2642 __ movq(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX)); | 2433 __ movq(receiver, |
| 2434 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset)); |
| 2643 __ bind(&receiver_ok); | 2435 __ bind(&receiver_ok); |
| 2644 | 2436 |
| 2645 // Copy the arguments to this function possibly from the | 2437 // Copy the arguments to this function possibly from the |
| 2646 // adaptor frame below it. | 2438 // adaptor frame below it. |
| 2647 const uint32_t kArgumentsLimit = 1 * KB; | 2439 const uint32_t kArgumentsLimit = 1 * KB; |
| 2648 __ cmpq(length, Immediate(kArgumentsLimit)); | 2440 __ cmpq(length, Immediate(kArgumentsLimit)); |
| 2649 DeoptimizeIf(above, instr->environment()); | 2441 DeoptimizeIf(above, instr->environment()); |
| 2650 | 2442 |
| 2651 __ push(receiver); | 2443 __ push(receiver); |
| 2652 __ movq(receiver, length); | 2444 __ movq(receiver, length); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2666 __ bind(&invoke); | 2458 __ bind(&invoke); |
| 2667 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); | 2459 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 2668 LPointerMap* pointers = instr->pointer_map(); | 2460 LPointerMap* pointers = instr->pointer_map(); |
| 2669 LEnvironment* env = instr->deoptimization_environment(); | 2461 LEnvironment* env = instr->deoptimization_environment(); |
| 2670 RecordPosition(pointers->position()); | 2462 RecordPosition(pointers->position()); |
| 2671 RegisterEnvironmentForDeoptimization(env); | 2463 RegisterEnvironmentForDeoptimization(env); |
| 2672 SafepointGenerator safepoint_generator(this, | 2464 SafepointGenerator safepoint_generator(this, |
| 2673 pointers, | 2465 pointers, |
| 2674 env->deoptimization_index()); | 2466 env->deoptimization_index()); |
| 2675 v8::internal::ParameterCount actual(rax); | 2467 v8::internal::ParameterCount actual(rax); |
| 2676 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator); | 2468 __ InvokeFunction(function, actual, CALL_FUNCTION, |
| 2469 safepoint_generator, CALL_AS_METHOD); |
| 2677 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2470 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2678 } | 2471 } |
| 2679 | 2472 |
| 2680 | 2473 |
| 2681 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2474 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 2682 LOperand* argument = instr->InputAt(0); | 2475 LOperand* argument = instr->InputAt(0); |
| 2683 EmitPushTaggedOperand(argument); | 2476 EmitPushTaggedOperand(argument); |
| 2684 } | 2477 } |
| 2685 | 2478 |
| 2686 | 2479 |
| 2480 void LCodeGen::DoThisFunction(LThisFunction* instr) { |
| 2481 Register result = ToRegister(instr->result()); |
| 2482 __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 2483 } |
| 2484 |
| 2485 |
| 2687 void LCodeGen::DoContext(LContext* instr) { | 2486 void LCodeGen::DoContext(LContext* instr) { |
| 2688 Register result = ToRegister(instr->result()); | 2487 Register result = ToRegister(instr->result()); |
| 2689 __ movq(result, rsi); | 2488 __ movq(result, rsi); |
| 2690 } | 2489 } |
| 2691 | 2490 |
| 2692 | 2491 |
| 2693 void LCodeGen::DoOuterContext(LOuterContext* instr) { | 2492 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
| 2694 Register context = ToRegister(instr->context()); | 2493 Register context = ToRegister(instr->context()); |
| 2695 Register result = ToRegister(instr->result()); | 2494 Register result = ToRegister(instr->result()); |
| 2696 __ movq(result, | 2495 __ movq(result, |
| 2697 Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2496 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 2698 __ movq(result, FieldOperand(result, JSFunction::kContextOffset)); | |
| 2699 } | 2497 } |
| 2700 | 2498 |
| 2701 | 2499 |
| 2702 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { | 2500 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
| 2703 Register result = ToRegister(instr->result()); | 2501 Register result = ToRegister(instr->result()); |
| 2704 __ movq(result, GlobalObjectOperand()); | 2502 __ movq(result, GlobalObjectOperand()); |
| 2705 } | 2503 } |
| 2706 | 2504 |
| 2707 | 2505 |
| 2708 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { | 2506 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3079 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 2877 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3080 ASSERT(ToRegister(instr->function()).is(rdi)); | 2878 ASSERT(ToRegister(instr->function()).is(rdi)); |
| 3081 ASSERT(instr->HasPointerMap()); | 2879 ASSERT(instr->HasPointerMap()); |
| 3082 ASSERT(instr->HasDeoptimizationEnvironment()); | 2880 ASSERT(instr->HasDeoptimizationEnvironment()); |
| 3083 LPointerMap* pointers = instr->pointer_map(); | 2881 LPointerMap* pointers = instr->pointer_map(); |
| 3084 LEnvironment* env = instr->deoptimization_environment(); | 2882 LEnvironment* env = instr->deoptimization_environment(); |
| 3085 RecordPosition(pointers->position()); | 2883 RecordPosition(pointers->position()); |
| 3086 RegisterEnvironmentForDeoptimization(env); | 2884 RegisterEnvironmentForDeoptimization(env); |
| 3087 SafepointGenerator generator(this, pointers, env->deoptimization_index()); | 2885 SafepointGenerator generator(this, pointers, env->deoptimization_index()); |
| 3088 ParameterCount count(instr->arity()); | 2886 ParameterCount count(instr->arity()); |
| 3089 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator); | 2887 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); |
| 3090 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2888 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3091 } | 2889 } |
| 3092 | 2890 |
| 3093 | 2891 |
| 3094 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { | 2892 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { |
| 3095 ASSERT(ToRegister(instr->key()).is(rcx)); | 2893 ASSERT(ToRegister(instr->key()).is(rcx)); |
| 3096 ASSERT(ToRegister(instr->result()).is(rax)); | 2894 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3097 | 2895 |
| 3098 int arity = instr->arity(); | 2896 int arity = instr->arity(); |
| 3099 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( | 2897 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3198 __ Move(rcx, instr->hydrogen()->name()); | 2996 __ Move(rcx, instr->hydrogen()->name()); |
| 3199 Handle<Code> ic = instr->strict_mode() | 2997 Handle<Code> ic = instr->strict_mode() |
| 3200 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2998 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 3201 : isolate()->builtins()->StoreIC_Initialize(); | 2999 : isolate()->builtins()->StoreIC_Initialize(); |
| 3202 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 3000 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3203 } | 3001 } |
| 3204 | 3002 |
| 3205 | 3003 |
| 3206 void LCodeGen::DoStoreKeyedSpecializedArrayElement( | 3004 void LCodeGen::DoStoreKeyedSpecializedArrayElement( |
| 3207 LStoreKeyedSpecializedArrayElement* instr) { | 3005 LStoreKeyedSpecializedArrayElement* instr) { |
| 3208 ExternalArrayType array_type = instr->array_type(); | 3006 JSObject::ElementsKind elements_kind = instr->elements_kind(); |
| 3209 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), | 3007 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), |
| 3210 instr->key(), array_type)); | 3008 instr->key(), elements_kind)); |
| 3211 if (array_type == kExternalFloatArray) { | 3009 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 3212 XMMRegister value(ToDoubleRegister(instr->value())); | 3010 XMMRegister value(ToDoubleRegister(instr->value())); |
| 3213 __ cvtsd2ss(value, value); | 3011 __ cvtsd2ss(value, value); |
| 3214 __ movss(operand, value); | 3012 __ movss(operand, value); |
| 3215 } else if (array_type == kExternalDoubleArray) { | 3013 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 3216 __ movsd(operand, ToDoubleRegister(instr->value())); | 3014 __ movsd(operand, ToDoubleRegister(instr->value())); |
| 3217 } else { | 3015 } else { |
| 3218 Register value(ToRegister(instr->value())); | 3016 Register value(ToRegister(instr->value())); |
| 3219 switch (array_type) { | 3017 switch (elements_kind) { |
| 3220 case kExternalPixelArray: | 3018 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 3221 case kExternalByteArray: | 3019 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3222 case kExternalUnsignedByteArray: | 3020 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3223 __ movb(operand, value); | 3021 __ movb(operand, value); |
| 3224 break; | 3022 break; |
| 3225 case kExternalShortArray: | 3023 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3226 case kExternalUnsignedShortArray: | 3024 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3227 __ movw(operand, value); | 3025 __ movw(operand, value); |
| 3228 break; | 3026 break; |
| 3229 case kExternalIntArray: | 3027 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 3230 case kExternalUnsignedIntArray: | 3028 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3231 __ movl(operand, value); | 3029 __ movl(operand, value); |
| 3232 break; | 3030 break; |
| 3233 case kExternalFloatArray: | 3031 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 3234 case kExternalDoubleArray: | 3032 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 3033 case JSObject::FAST_ELEMENTS: |
| 3034 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 3035 case JSObject::DICTIONARY_ELEMENTS: |
| 3036 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3235 UNREACHABLE(); | 3037 UNREACHABLE(); |
| 3236 break; | 3038 break; |
| 3237 } | 3039 } |
| 3238 } | 3040 } |
| 3239 } | 3041 } |
| 3240 | 3042 |
| 3241 | 3043 |
| 3242 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { | 3044 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| 3243 if (instr->length()->IsRegister()) { | 3045 if (instr->length()->IsRegister()) { |
| 3244 __ cmpq(ToRegister(instr->index()), ToRegister(instr->length())); | 3046 __ cmpq(ToRegister(instr->index()), ToRegister(instr->length())); |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3568 if (instr->needs_check()) { | 3370 if (instr->needs_check()) { |
| 3569 Condition is_smi = __ CheckSmi(input); | 3371 Condition is_smi = __ CheckSmi(input); |
| 3570 DeoptimizeIf(NegateCondition(is_smi), instr->environment()); | 3372 DeoptimizeIf(NegateCondition(is_smi), instr->environment()); |
| 3571 } | 3373 } |
| 3572 __ SmiToInteger32(input, input); | 3374 __ SmiToInteger32(input, input); |
| 3573 } | 3375 } |
| 3574 | 3376 |
| 3575 | 3377 |
| 3576 void LCodeGen::EmitNumberUntagD(Register input_reg, | 3378 void LCodeGen::EmitNumberUntagD(Register input_reg, |
| 3577 XMMRegister result_reg, | 3379 XMMRegister result_reg, |
| 3380 bool deoptimize_on_undefined, |
| 3578 LEnvironment* env) { | 3381 LEnvironment* env) { |
| 3579 Label load_smi, heap_number, done; | 3382 Label load_smi, done; |
| 3580 | 3383 |
| 3581 // Smi check. | 3384 // Smi check. |
| 3582 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); | 3385 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); |
| 3583 | 3386 |
| 3584 // Heap number map check. | 3387 // Heap number map check. |
| 3585 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), | 3388 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 3586 Heap::kHeapNumberMapRootIndex); | 3389 Heap::kHeapNumberMapRootIndex); |
| 3587 __ j(equal, &heap_number, Label::kNear); | 3390 if (deoptimize_on_undefined) { |
| 3391 DeoptimizeIf(not_equal, env); |
| 3392 } else { |
| 3393 Label heap_number; |
| 3394 __ j(equal, &heap_number, Label::kNear); |
| 3588 | 3395 |
| 3589 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); | 3396 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); |
| 3590 DeoptimizeIf(not_equal, env); | 3397 DeoptimizeIf(not_equal, env); |
| 3591 | 3398 |
| 3592 // Convert undefined to NaN. Compute NaN as 0/0. | 3399 // Convert undefined to NaN. Compute NaN as 0/0. |
| 3593 __ xorps(result_reg, result_reg); | 3400 __ xorps(result_reg, result_reg); |
| 3594 __ divsd(result_reg, result_reg); | 3401 __ divsd(result_reg, result_reg); |
| 3595 __ jmp(&done, Label::kNear); | 3402 __ jmp(&done, Label::kNear); |
| 3596 | 3403 |
| 3404 __ bind(&heap_number); |
| 3405 } |
| 3597 // Heap number to XMM conversion. | 3406 // Heap number to XMM conversion. |
| 3598 __ bind(&heap_number); | |
| 3599 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 3407 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 3600 __ jmp(&done, Label::kNear); | 3408 __ jmp(&done, Label::kNear); |
| 3601 | 3409 |
| 3602 // Smi to XMM conversion | 3410 // Smi to XMM conversion |
| 3603 __ bind(&load_smi); | 3411 __ bind(&load_smi); |
| 3604 __ SmiToInteger32(kScratchRegister, input_reg); | 3412 __ SmiToInteger32(kScratchRegister, input_reg); |
| 3605 __ cvtlsi2sd(result_reg, kScratchRegister); | 3413 __ cvtlsi2sd(result_reg, kScratchRegister); |
| 3606 __ bind(&done); | 3414 __ bind(&done); |
| 3607 } | 3415 } |
| 3608 | 3416 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3679 | 3487 |
| 3680 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { | 3488 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| 3681 LOperand* input = instr->InputAt(0); | 3489 LOperand* input = instr->InputAt(0); |
| 3682 ASSERT(input->IsRegister()); | 3490 ASSERT(input->IsRegister()); |
| 3683 LOperand* result = instr->result(); | 3491 LOperand* result = instr->result(); |
| 3684 ASSERT(result->IsDoubleRegister()); | 3492 ASSERT(result->IsDoubleRegister()); |
| 3685 | 3493 |
| 3686 Register input_reg = ToRegister(input); | 3494 Register input_reg = ToRegister(input); |
| 3687 XMMRegister result_reg = ToDoubleRegister(result); | 3495 XMMRegister result_reg = ToDoubleRegister(result); |
| 3688 | 3496 |
| 3689 EmitNumberUntagD(input_reg, result_reg, instr->environment()); | 3497 EmitNumberUntagD(input_reg, result_reg, |
| 3498 instr->hydrogen()->deoptimize_on_undefined(), |
| 3499 instr->environment()); |
| 3690 } | 3500 } |
| 3691 | 3501 |
| 3692 | 3502 |
| 3693 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 3503 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 3694 LOperand* input = instr->InputAt(0); | 3504 LOperand* input = instr->InputAt(0); |
| 3695 ASSERT(input->IsDoubleRegister()); | 3505 ASSERT(input->IsDoubleRegister()); |
| 3696 LOperand* result = instr->result(); | 3506 LOperand* result = instr->result(); |
| 3697 ASSERT(result->IsRegister()); | 3507 ASSERT(result->IsRegister()); |
| 3698 | 3508 |
| 3699 XMMRegister input_reg = ToDoubleRegister(input); | 3509 XMMRegister input_reg = ToDoubleRegister(input); |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4023 } | 3833 } |
| 4024 | 3834 |
| 4025 | 3835 |
| 4026 void LCodeGen::DoTypeof(LTypeof* instr) { | 3836 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 4027 LOperand* input = instr->InputAt(0); | 3837 LOperand* input = instr->InputAt(0); |
| 4028 EmitPushTaggedOperand(input); | 3838 EmitPushTaggedOperand(input); |
| 4029 CallRuntime(Runtime::kTypeof, 1, instr); | 3839 CallRuntime(Runtime::kTypeof, 1, instr); |
| 4030 } | 3840 } |
| 4031 | 3841 |
| 4032 | 3842 |
| 4033 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { | |
| 4034 Register input = ToRegister(instr->InputAt(0)); | |
| 4035 Register result = ToRegister(instr->result()); | |
| 4036 Label true_label; | |
| 4037 Label false_label; | |
| 4038 Label done; | |
| 4039 | |
| 4040 Condition final_branch_condition = EmitTypeofIs(&true_label, | |
| 4041 &false_label, | |
| 4042 input, | |
| 4043 instr->type_literal()); | |
| 4044 __ j(final_branch_condition, &true_label); | |
| 4045 __ bind(&false_label); | |
| 4046 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 4047 __ jmp(&done, Label::kNear); | |
| 4048 | |
| 4049 __ bind(&true_label); | |
| 4050 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 4051 | |
| 4052 __ bind(&done); | |
| 4053 } | |
| 4054 | |
| 4055 | |
| 4056 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { | 3843 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { |
| 4057 ASSERT(!operand->IsDoubleRegister()); | 3844 ASSERT(!operand->IsDoubleRegister()); |
| 4058 if (operand->IsConstantOperand()) { | 3845 if (operand->IsConstantOperand()) { |
| 4059 __ Push(ToHandle(LConstantOperand::cast(operand))); | 3846 __ Push(ToHandle(LConstantOperand::cast(operand))); |
| 4060 } else if (operand->IsRegister()) { | 3847 } else if (operand->IsRegister()) { |
| 4061 __ push(ToRegister(operand)); | 3848 __ push(ToRegister(operand)); |
| 4062 } else { | 3849 } else { |
| 4063 __ push(ToOperand(operand)); | 3850 __ push(ToOperand(operand)); |
| 4064 } | 3851 } |
| 4065 } | 3852 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4112 __ j(equal, true_label); | 3899 __ j(equal, true_label); |
| 4113 __ JumpIfSmi(input, false_label); | 3900 __ JumpIfSmi(input, false_label); |
| 4114 // Check for undetectable objects => true. | 3901 // Check for undetectable objects => true. |
| 4115 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 3902 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 4116 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 3903 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 4117 Immediate(1 << Map::kIsUndetectable)); | 3904 Immediate(1 << Map::kIsUndetectable)); |
| 4118 final_branch_condition = not_zero; | 3905 final_branch_condition = not_zero; |
| 4119 | 3906 |
| 4120 } else if (type_name->Equals(heap()->function_symbol())) { | 3907 } else if (type_name->Equals(heap()->function_symbol())) { |
| 4121 __ JumpIfSmi(input, false_label); | 3908 __ JumpIfSmi(input, false_label); |
| 4122 __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input); | 3909 __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input); |
| 4123 final_branch_condition = above_equal; | 3910 final_branch_condition = above_equal; |
| 4124 | 3911 |
| 4125 } else if (type_name->Equals(heap()->object_symbol())) { | 3912 } else if (type_name->Equals(heap()->object_symbol())) { |
| 4126 __ JumpIfSmi(input, false_label); | 3913 __ JumpIfSmi(input, false_label); |
| 4127 __ CompareRoot(input, Heap::kNullValueRootIndex); | 3914 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 4128 __ j(equal, true_label); | 3915 __ j(equal, true_label); |
| 4129 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input); | 3916 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
| 4130 __ j(below, false_label); | 3917 __ j(below, false_label); |
| 4131 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); | 3918 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4132 __ j(above_equal, false_label); | 3919 __ j(above, false_label); |
| 4133 // Check for undetectable objects => false. | 3920 // Check for undetectable objects => false. |
| 4134 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 3921 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 4135 Immediate(1 << Map::kIsUndetectable)); | 3922 Immediate(1 << Map::kIsUndetectable)); |
| 4136 final_branch_condition = zero; | 3923 final_branch_condition = zero; |
| 4137 | 3924 |
| 4138 } else { | 3925 } else { |
| 4139 final_branch_condition = never; | 3926 final_branch_condition = never; |
| 4140 __ jmp(false_label); | 3927 __ jmp(false_label); |
| 4141 } | 3928 } |
| 4142 | 3929 |
| 4143 return final_branch_condition; | 3930 return final_branch_condition; |
| 4144 } | 3931 } |
| 4145 | 3932 |
| 4146 | 3933 |
| 4147 void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) { | |
| 4148 Register result = ToRegister(instr->result()); | |
| 4149 Label true_label; | |
| 4150 Label done; | |
| 4151 | |
| 4152 EmitIsConstructCall(result); | |
| 4153 __ j(equal, &true_label, Label::kNear); | |
| 4154 | |
| 4155 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 4156 __ jmp(&done, Label::kNear); | |
| 4157 | |
| 4158 __ bind(&true_label); | |
| 4159 __ LoadRoot(result, Heap::kTrueValueRootIndex); | |
| 4160 | |
| 4161 | |
| 4162 __ bind(&done); | |
| 4163 } | |
| 4164 | |
| 4165 | |
| 4166 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 3934 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 4167 Register temp = ToRegister(instr->TempAt(0)); | 3935 Register temp = ToRegister(instr->TempAt(0)); |
| 4168 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 3936 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 4169 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 3937 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 4170 | 3938 |
| 4171 EmitIsConstructCall(temp); | 3939 EmitIsConstructCall(temp); |
| 4172 EmitBranch(true_block, false_block, equal); | 3940 EmitBranch(true_block, false_block, equal); |
| 4173 } | 3941 } |
| 4174 | 3942 |
| 4175 | 3943 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4236 // Create safepoint generator that will also ensure enough space in the | 4004 // Create safepoint generator that will also ensure enough space in the |
| 4237 // reloc info for patching in deoptimization (since this is invoking a | 4005 // reloc info for patching in deoptimization (since this is invoking a |
| 4238 // builtin) | 4006 // builtin) |
| 4239 SafepointGenerator safepoint_generator(this, | 4007 SafepointGenerator safepoint_generator(this, |
| 4240 pointers, | 4008 pointers, |
| 4241 env->deoptimization_index()); | 4009 env->deoptimization_index()); |
| 4242 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); | 4010 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); |
| 4243 } | 4011 } |
| 4244 | 4012 |
| 4245 | 4013 |
| 4014 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 4015 { |
| 4016 PushSafepointRegistersScope scope(this); |
| 4017 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 4018 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 4019 RegisterLazyDeoptimization(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); |
| 4020 } |
| 4021 |
| 4022 // The gap code includes the restoring of the safepoint registers. |
| 4023 int pc = masm()->pc_offset(); |
| 4024 safepoints_.SetPcAfterGap(pc); |
| 4025 } |
| 4026 |
| 4027 |
| 4246 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 4028 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 4247 // Perform stack overflow check. | 4029 class DeferredStackCheck: public LDeferredCode { |
| 4248 Label done; | 4030 public: |
| 4249 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 4031 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
| 4250 __ j(above_equal, &done, Label::kNear); | 4032 : LDeferredCode(codegen), instr_(instr) { } |
| 4033 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
| 4034 private: |
| 4035 LStackCheck* instr_; |
| 4036 }; |
| 4251 | 4037 |
| 4252 StackCheckStub stub; | 4038 if (instr->hydrogen()->is_function_entry()) { |
| 4253 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4039 // Perform stack overflow check. |
| 4254 __ bind(&done); | 4040 Label done; |
| 4041 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 4042 __ j(above_equal, &done, Label::kNear); |
| 4043 StackCheckStub stub; |
| 4044 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4045 __ bind(&done); |
| 4046 } else { |
| 4047 ASSERT(instr->hydrogen()->is_backwards_branch()); |
| 4048 // Perform stack overflow check if this goto needs it before jumping. |
| 4049 DeferredStackCheck* deferred_stack_check = |
| 4050 new DeferredStackCheck(this, instr); |
| 4051 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 4052 __ j(below, deferred_stack_check->entry()); |
| 4053 __ bind(instr->done_label()); |
| 4054 deferred_stack_check->SetExit(instr->done_label()); |
| 4055 } |
| 4255 } | 4056 } |
| 4256 | 4057 |
| 4257 | 4058 |
| 4258 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 4059 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 4259 // This is a pseudo-instruction that ensures that the environment here is | 4060 // This is a pseudo-instruction that ensures that the environment here is |
| 4260 // properly registered for deoptimization and records the assembler's PC | 4061 // properly registered for deoptimization and records the assembler's PC |
| 4261 // offset. | 4062 // offset. |
| 4262 LEnvironment* environment = instr->environment(); | 4063 LEnvironment* environment = instr->environment(); |
| 4263 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), | 4064 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), |
| 4264 instr->SpilledDoubleRegisterArray()); | 4065 instr->SpilledDoubleRegisterArray()); |
| 4265 | 4066 |
| 4266 // If the environment were already registered, we would have no way of | 4067 // If the environment were already registered, we would have no way of |
| 4267 // backpatching it with the spill slot operands. | 4068 // backpatching it with the spill slot operands. |
| 4268 ASSERT(!environment->HasBeenRegistered()); | 4069 ASSERT(!environment->HasBeenRegistered()); |
| 4269 RegisterEnvironmentForDeoptimization(environment); | 4070 RegisterEnvironmentForDeoptimization(environment); |
| 4270 ASSERT(osr_pc_offset_ == -1); | 4071 ASSERT(osr_pc_offset_ == -1); |
| 4271 osr_pc_offset_ = masm()->pc_offset(); | 4072 osr_pc_offset_ = masm()->pc_offset(); |
| 4272 } | 4073 } |
| 4273 | 4074 |
| 4274 #undef __ | 4075 #undef __ |
| 4275 | 4076 |
| 4276 } } // namespace v8::internal | 4077 } } // namespace v8::internal |
| 4277 | 4078 |
| 4278 #endif // V8_TARGET_ARCH_X64 | 4079 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |