| 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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 bool LCodeGen::GeneratePrologue() { | 121 bool LCodeGen::GeneratePrologue() { |
| 122 ASSERT(is_generating()); | 122 ASSERT(is_generating()); |
| 123 | 123 |
| 124 #ifdef DEBUG | 124 #ifdef DEBUG |
| 125 if (strlen(FLAG_stop_at) > 0 && | 125 if (strlen(FLAG_stop_at) > 0 && |
| 126 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 126 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 127 __ int3(); | 127 __ int3(); |
| 128 } | 128 } |
| 129 #endif | 129 #endif |
| 130 | 130 |
| 131 // Strict mode functions need to replace the receiver with undefined | 131 // Strict mode functions and builtins need to replace the receiver |
| 132 // when called as functions (without an explicit receiver | 132 // with undefined when called as functions (without an explicit |
| 133 // object). ecx is zero for method calls and non-zero for function | 133 // receiver object). ecx is zero for method calls and non-zero for |
| 134 // calls. | 134 // function calls. |
| 135 if (info_->is_strict_mode()) { | 135 if (info_->is_strict_mode() || info_->is_native()) { |
| 136 Label ok; | 136 Label ok; |
| 137 __ test(ecx, Operand(ecx)); | 137 __ test(ecx, Operand(ecx)); |
| 138 __ j(zero, &ok, Label::kNear); | 138 __ j(zero, &ok, Label::kNear); |
| 139 // +1 for return address. | 139 // +1 for return address. |
| 140 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 140 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
| 141 __ mov(Operand(esp, receiver_offset), | 141 __ mov(Operand(esp, receiver_offset), |
| 142 Immediate(isolate()->factory()->undefined_value())); | 142 Immediate(isolate()->factory()->undefined_value())); |
| 143 __ bind(&ok); | 143 __ bind(&ok); |
| 144 } | 144 } |
| 145 | 145 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 // Possibly allocate a local context. | 177 // Possibly allocate a local context. |
| 178 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 178 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 179 if (heap_slots > 0) { | 179 if (heap_slots > 0) { |
| 180 Comment(";;; Allocate local context"); | 180 Comment(";;; Allocate local context"); |
| 181 // Argument to NewContext is the function, which is still in edi. | 181 // Argument to NewContext is the function, which is still in edi. |
| 182 __ push(edi); | 182 __ push(edi); |
| 183 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 183 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 184 FastNewContextStub stub(heap_slots); | 184 FastNewContextStub stub(heap_slots); |
| 185 __ CallStub(&stub); | 185 __ CallStub(&stub); |
| 186 } else { | 186 } else { |
| 187 __ CallRuntime(Runtime::kNewContext, 1); | 187 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 188 } | 188 } |
| 189 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); | 189 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); |
| 190 // Context is returned in both eax and esi. It replaces the context | 190 // Context is returned in both eax and esi. It replaces the context |
| 191 // passed to us. It's saved in the stack and kept live in esi. | 191 // passed to us. It's saved in the stack and kept live in esi. |
| 192 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 192 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 193 | 193 |
| 194 // Copy parameters into context if necessary. | 194 // Copy parameters into context if necessary. |
| 195 int num_parameters = scope()->num_parameters(); | 195 int num_parameters = scope()->num_parameters(); |
| 196 for (int i = 0; i < num_parameters; i++) { | 196 for (int i = 0; i < num_parameters; i++) { |
| 197 Slot* slot = scope()->parameter(i)->AsSlot(); | 197 Slot* slot = scope()->parameter(i)->AsSlot(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 if (current_instruction_ < instructions_->length() - 1) { | 249 if (current_instruction_ < instructions_->length() - 1) { |
| 250 return instructions_->at(current_instruction_ + 1); | 250 return instructions_->at(current_instruction_ + 1); |
| 251 } else { | 251 } else { |
| 252 return NULL; | 252 return NULL; |
| 253 } | 253 } |
| 254 } | 254 } |
| 255 | 255 |
| 256 | 256 |
| 257 bool LCodeGen::GenerateDeferredCode() { | 257 bool LCodeGen::GenerateDeferredCode() { |
| 258 ASSERT(is_generating()); | 258 ASSERT(is_generating()); |
| 259 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 259 if (deferred_.length() > 0) { |
| 260 LDeferredCode* code = deferred_[i]; | 260 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 261 __ bind(code->entry()); | 261 LDeferredCode* code = deferred_[i]; |
| 262 code->Generate(); | 262 __ bind(code->entry()); |
| 263 __ jmp(code->exit()); | 263 code->Generate(); |
| 264 __ jmp(code->exit()); |
| 265 } |
| 266 |
| 267 // Pad code to ensure that the last piece of deferred code have |
| 268 // room for lazy bailout. |
| 269 while ((masm()->pc_offset() - LastSafepointEnd()) |
| 270 < Deoptimizer::patch_size()) { |
| 271 __ nop(); |
| 272 } |
| 264 } | 273 } |
| 265 | 274 |
| 266 // Deferred code is the last part of the instruction sequence. Mark | 275 // Deferred code is the last part of the instruction sequence. Mark |
| 267 // the generated code as done unless we bailed out. | 276 // the generated code as done unless we bailed out. |
| 268 if (!is_aborted()) status_ = DONE; | 277 if (!is_aborted()) status_ = DONE; |
| 269 return !is_aborted(); | 278 return !is_aborted(); |
| 270 } | 279 } |
| 271 | 280 |
| 272 | 281 |
| 273 bool LCodeGen::GenerateSafepointTable() { | 282 bool LCodeGen::GenerateSafepointTable() { |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 translation->StoreLiteral(src_index); | 431 translation->StoreLiteral(src_index); |
| 423 } else { | 432 } else { |
| 424 UNREACHABLE(); | 433 UNREACHABLE(); |
| 425 } | 434 } |
| 426 } | 435 } |
| 427 | 436 |
| 428 | 437 |
| 429 void LCodeGen::CallCodeGeneric(Handle<Code> code, | 438 void LCodeGen::CallCodeGeneric(Handle<Code> code, |
| 430 RelocInfo::Mode mode, | 439 RelocInfo::Mode mode, |
| 431 LInstruction* instr, | 440 LInstruction* instr, |
| 432 ContextMode context_mode, | |
| 433 SafepointMode safepoint_mode) { | 441 SafepointMode safepoint_mode) { |
| 434 ASSERT(instr != NULL); | 442 ASSERT(instr != NULL); |
| 435 LPointerMap* pointers = instr->pointer_map(); | 443 LPointerMap* pointers = instr->pointer_map(); |
| 436 RecordPosition(pointers->position()); | 444 RecordPosition(pointers->position()); |
| 437 | 445 |
| 438 if (context_mode == RESTORE_CONTEXT) { | |
| 439 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | |
| 440 } | |
| 441 __ call(code, mode); | 446 __ call(code, mode); |
| 442 | 447 |
| 443 RegisterLazyDeoptimization(instr, safepoint_mode); | 448 RegisterLazyDeoptimization(instr, safepoint_mode); |
| 444 | 449 |
| 445 // Signal that we don't inline smi code before these stubs in the | 450 // Signal that we don't inline smi code before these stubs in the |
| 446 // optimizing code generator. | 451 // optimizing code generator. |
| 447 if (code->kind() == Code::BINARY_OP_IC || | 452 if (code->kind() == Code::BINARY_OP_IC || |
| 448 code->kind() == Code::COMPARE_IC) { | 453 code->kind() == Code::COMPARE_IC) { |
| 449 __ nop(); | 454 __ nop(); |
| 450 } | 455 } |
| 451 } | 456 } |
| 452 | 457 |
| 453 | 458 |
| 454 void LCodeGen::CallCode(Handle<Code> code, | 459 void LCodeGen::CallCode(Handle<Code> code, |
| 455 RelocInfo::Mode mode, | 460 RelocInfo::Mode mode, |
| 456 LInstruction* instr, | 461 LInstruction* instr) { |
| 457 ContextMode context_mode) { | 462 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); |
| 458 CallCodeGeneric(code, mode, instr, context_mode, RECORD_SIMPLE_SAFEPOINT); | |
| 459 } | 463 } |
| 460 | 464 |
| 461 | 465 |
| 462 void LCodeGen::CallRuntime(const Runtime::Function* fun, | 466 void LCodeGen::CallRuntime(const Runtime::Function* fun, |
| 463 int argc, | 467 int argc, |
| 464 LInstruction* instr, | 468 LInstruction* instr) { |
| 465 ContextMode context_mode) { | |
| 466 ASSERT(instr != NULL); | 469 ASSERT(instr != NULL); |
| 467 ASSERT(instr->HasPointerMap()); | 470 ASSERT(instr->HasPointerMap()); |
| 468 LPointerMap* pointers = instr->pointer_map(); | 471 LPointerMap* pointers = instr->pointer_map(); |
| 469 RecordPosition(pointers->position()); | 472 RecordPosition(pointers->position()); |
| 470 | 473 |
| 471 if (context_mode == RESTORE_CONTEXT) { | |
| 472 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | |
| 473 } | |
| 474 __ CallRuntime(fun, argc); | 474 __ CallRuntime(fun, argc); |
| 475 | 475 |
| 476 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); | 476 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); |
| 477 } | 477 } |
| 478 | 478 |
| 479 | 479 |
| 480 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, | 480 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
| 481 int argc, | 481 int argc, |
| 482 LInstruction* instr) { | 482 LInstruction* instr, |
| 483 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 483 LOperand* context) { |
| 484 ASSERT(context->IsRegister() || context->IsStackSlot()); |
| 485 if (context->IsRegister()) { |
| 486 if (!ToRegister(context).is(esi)) { |
| 487 __ mov(esi, ToRegister(context)); |
| 488 } |
| 489 } else { |
| 490 // Context is stack slot. |
| 491 __ mov(esi, ToOperand(context)); |
| 492 } |
| 493 |
| 484 __ CallRuntimeSaveDoubles(id); | 494 __ CallRuntimeSaveDoubles(id); |
| 485 RecordSafepointWithRegisters( | 495 RecordSafepointWithRegisters( |
| 486 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); | 496 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); |
| 487 } | 497 } |
| 488 | 498 |
| 489 | 499 |
| 490 void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, | 500 void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, |
| 491 SafepointMode safepoint_mode) { | 501 SafepointMode safepoint_mode) { |
| 492 // Create the environment to bailout to. If the call has side effects | 502 // Create the environment to bailout to. If the call has side effects |
| 493 // execution has to continue after the call otherwise execution can continue | 503 // execution has to continue after the call otherwise execution can continue |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 | 697 |
| 688 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 698 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 689 int arguments, | 699 int arguments, |
| 690 int deoptimization_index) { | 700 int deoptimization_index) { |
| 691 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 701 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, |
| 692 deoptimization_index); | 702 deoptimization_index); |
| 693 } | 703 } |
| 694 | 704 |
| 695 | 705 |
| 696 void LCodeGen::RecordPosition(int position) { | 706 void LCodeGen::RecordPosition(int position) { |
| 697 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; | 707 if (position == RelocInfo::kNoPosition) return; |
| 698 masm()->positions_recorder()->RecordPosition(position); | 708 masm()->positions_recorder()->RecordPosition(position); |
| 699 } | 709 } |
| 700 | 710 |
| 701 | 711 |
| 702 void LCodeGen::DoLabel(LLabel* label) { | 712 void LCodeGen::DoLabel(LLabel* label) { |
| 703 if (label->is_loop_header()) { | 713 if (label->is_loop_header()) { |
| 704 Comment(";;; B%d - LOOP entry", label->block_id()); | 714 Comment(";;; B%d - LOOP entry", label->block_id()); |
| 705 } else { | 715 } else { |
| 706 Comment(";;; B%d", label->block_id()); | 716 Comment(";;; B%d", label->block_id()); |
| 707 } | 717 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 // Nothing to do. | 752 // Nothing to do. |
| 743 } | 753 } |
| 744 | 754 |
| 745 | 755 |
| 746 void LCodeGen::DoCallStub(LCallStub* instr) { | 756 void LCodeGen::DoCallStub(LCallStub* instr) { |
| 747 ASSERT(ToRegister(instr->context()).is(esi)); | 757 ASSERT(ToRegister(instr->context()).is(esi)); |
| 748 ASSERT(ToRegister(instr->result()).is(eax)); | 758 ASSERT(ToRegister(instr->result()).is(eax)); |
| 749 switch (instr->hydrogen()->major_key()) { | 759 switch (instr->hydrogen()->major_key()) { |
| 750 case CodeStub::RegExpConstructResult: { | 760 case CodeStub::RegExpConstructResult: { |
| 751 RegExpConstructResultStub stub; | 761 RegExpConstructResultStub stub; |
| 752 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 762 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 753 break; | 763 break; |
| 754 } | 764 } |
| 755 case CodeStub::RegExpExec: { | 765 case CodeStub::RegExpExec: { |
| 756 RegExpExecStub stub; | 766 RegExpExecStub stub; |
| 757 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 767 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 758 break; | 768 break; |
| 759 } | 769 } |
| 760 case CodeStub::SubString: { | 770 case CodeStub::SubString: { |
| 761 SubStringStub stub; | 771 SubStringStub stub; |
| 762 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 772 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 763 break; | 773 break; |
| 764 } | 774 } |
| 765 case CodeStub::NumberToString: { | 775 case CodeStub::NumberToString: { |
| 766 NumberToStringStub stub; | 776 NumberToStringStub stub; |
| 767 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 777 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 768 break; | 778 break; |
| 769 } | 779 } |
| 770 case CodeStub::StringAdd: { | 780 case CodeStub::StringAdd: { |
| 771 StringAddStub stub(NO_STRING_ADD_FLAGS); | 781 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 772 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 782 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 773 break; | 783 break; |
| 774 } | 784 } |
| 775 case CodeStub::StringCompare: { | 785 case CodeStub::StringCompare: { |
| 776 StringCompareStub stub; | 786 StringCompareStub stub; |
| 777 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 787 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 778 break; | 788 break; |
| 779 } | 789 } |
| 780 case CodeStub::TranscendentalCache: { | 790 case CodeStub::TranscendentalCache: { |
| 781 TranscendentalCacheStub stub(instr->transcendental_type(), | 791 TranscendentalCacheStub stub(instr->transcendental_type(), |
| 782 TranscendentalCacheStub::TAGGED); | 792 TranscendentalCacheStub::TAGGED); |
| 783 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 793 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 784 break; | 794 break; |
| 785 } | 795 } |
| 786 default: | 796 default: |
| 787 UNREACHABLE(); | 797 UNREACHABLE(); |
| 788 } | 798 } |
| 789 } | 799 } |
| 790 | 800 |
| 791 | 801 |
| 792 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 802 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 793 // Nothing to do. | 803 // Nothing to do. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 805 | 815 |
| 806 Label positive_dividend, done; | 816 Label positive_dividend, done; |
| 807 __ test(dividend, Operand(dividend)); | 817 __ test(dividend, Operand(dividend)); |
| 808 __ j(not_sign, &positive_dividend, Label::kNear); | 818 __ j(not_sign, &positive_dividend, Label::kNear); |
| 809 __ neg(dividend); | 819 __ neg(dividend); |
| 810 __ and_(dividend, divisor - 1); | 820 __ and_(dividend, divisor - 1); |
| 811 __ neg(dividend); | 821 __ neg(dividend); |
| 812 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 822 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 813 __ j(not_zero, &done, Label::kNear); | 823 __ j(not_zero, &done, Label::kNear); |
| 814 DeoptimizeIf(no_condition, instr->environment()); | 824 DeoptimizeIf(no_condition, instr->environment()); |
| 825 } else { |
| 826 __ jmp(&done, Label::kNear); |
| 815 } | 827 } |
| 816 __ bind(&positive_dividend); | 828 __ bind(&positive_dividend); |
| 817 __ and_(dividend, divisor - 1); | 829 __ and_(dividend, divisor - 1); |
| 818 __ bind(&done); | 830 __ bind(&done); |
| 819 } else { | 831 } else { |
| 820 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; | 832 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; |
| 821 Register left_reg = ToRegister(instr->InputAt(0)); | 833 Register left_reg = ToRegister(instr->InputAt(0)); |
| 822 Register right_reg = ToRegister(instr->InputAt(1)); | 834 Register right_reg = ToRegister(instr->InputAt(1)); |
| 823 Register result_reg = ToRegister(instr->result()); | 835 Register result_reg = ToRegister(instr->result()); |
| 824 | 836 |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1207 } | 1219 } |
| 1208 | 1220 |
| 1209 | 1221 |
| 1210 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { | 1222 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { |
| 1211 Register result = ToRegister(instr->result()); | 1223 Register result = ToRegister(instr->result()); |
| 1212 Register array = ToRegister(instr->InputAt(0)); | 1224 Register array = ToRegister(instr->InputAt(0)); |
| 1213 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset)); | 1225 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset)); |
| 1214 } | 1226 } |
| 1215 | 1227 |
| 1216 | 1228 |
| 1229 void LCodeGen::DoElementsKind(LElementsKind* instr) { |
| 1230 Register result = ToRegister(instr->result()); |
| 1231 Register input = ToRegister(instr->InputAt(0)); |
| 1232 |
| 1233 // Load map into |result|. |
| 1234 __ mov(result, FieldOperand(input, HeapObject::kMapOffset)); |
| 1235 // Load the map's "bit field 2" into |result|. We only need the first byte, |
| 1236 // but the following masking takes care of that anyway. |
| 1237 __ mov(result, FieldOperand(result, Map::kBitField2Offset)); |
| 1238 // Retrieve elements_kind from bit field 2. |
| 1239 __ and_(result, Map::kElementsKindMask); |
| 1240 __ shr(result, Map::kElementsKindShift); |
| 1241 } |
| 1242 |
| 1243 |
| 1217 void LCodeGen::DoValueOf(LValueOf* instr) { | 1244 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1218 Register input = ToRegister(instr->InputAt(0)); | 1245 Register input = ToRegister(instr->InputAt(0)); |
| 1219 Register result = ToRegister(instr->result()); | 1246 Register result = ToRegister(instr->result()); |
| 1220 Register map = ToRegister(instr->TempAt(0)); | 1247 Register map = ToRegister(instr->TempAt(0)); |
| 1221 ASSERT(input.is(result)); | 1248 ASSERT(input.is(result)); |
| 1222 Label done; | 1249 Label done; |
| 1223 // If the object is a smi return the object. | 1250 // If the object is a smi return the object. |
| 1224 __ test(input, Immediate(kSmiTagMask)); | 1251 __ JumpIfSmi(input, &done, Label::kNear); |
| 1225 __ j(zero, &done, Label::kNear); | |
| 1226 | 1252 |
| 1227 // If the object is not a value type, return the object. | 1253 // If the object is not a value type, return the object. |
| 1228 __ CmpObjectType(input, JS_VALUE_TYPE, map); | 1254 __ CmpObjectType(input, JS_VALUE_TYPE, map); |
| 1229 __ j(not_equal, &done, Label::kNear); | 1255 __ j(not_equal, &done, Label::kNear); |
| 1230 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); | 1256 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); |
| 1231 | 1257 |
| 1232 __ bind(&done); | 1258 __ bind(&done); |
| 1233 } | 1259 } |
| 1234 | 1260 |
| 1235 | 1261 |
| 1236 void LCodeGen::DoBitNotI(LBitNotI* instr) { | 1262 void LCodeGen::DoBitNotI(LBitNotI* instr) { |
| 1237 LOperand* input = instr->InputAt(0); | 1263 LOperand* input = instr->InputAt(0); |
| 1238 ASSERT(input->Equals(instr->result())); | 1264 ASSERT(input->Equals(instr->result())); |
| 1239 __ not_(ToRegister(input)); | 1265 __ not_(ToRegister(input)); |
| 1240 } | 1266 } |
| 1241 | 1267 |
| 1242 | 1268 |
| 1243 void LCodeGen::DoThrow(LThrow* instr) { | 1269 void LCodeGen::DoThrow(LThrow* instr) { |
| 1244 __ push(ToOperand(instr->InputAt(0))); | 1270 __ push(ToOperand(instr->value())); |
| 1245 CallRuntime(Runtime::kThrow, 1, instr, RESTORE_CONTEXT); | 1271 ASSERT(ToRegister(instr->context()).is(esi)); |
| 1272 CallRuntime(Runtime::kThrow, 1, instr); |
| 1246 | 1273 |
| 1247 if (FLAG_debug_code) { | 1274 if (FLAG_debug_code) { |
| 1248 Comment("Unreachable code."); | 1275 Comment("Unreachable code."); |
| 1249 __ int3(); | 1276 __ int3(); |
| 1250 } | 1277 } |
| 1251 } | 1278 } |
| 1252 | 1279 |
| 1253 | 1280 |
| 1254 void LCodeGen::DoAddI(LAddI* instr) { | 1281 void LCodeGen::DoAddI(LAddI* instr) { |
| 1255 LOperand* left = instr->InputAt(0); | 1282 LOperand* left = instr->InputAt(0); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1305 break; | 1332 break; |
| 1306 } | 1333 } |
| 1307 default: | 1334 default: |
| 1308 UNREACHABLE(); | 1335 UNREACHABLE(); |
| 1309 break; | 1336 break; |
| 1310 } | 1337 } |
| 1311 } | 1338 } |
| 1312 | 1339 |
| 1313 | 1340 |
| 1314 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { | 1341 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { |
| 1315 ASSERT(ToRegister(instr->InputAt(0)).is(edx)); | 1342 ASSERT(ToRegister(instr->context()).is(esi)); |
| 1316 ASSERT(ToRegister(instr->InputAt(1)).is(eax)); | 1343 ASSERT(ToRegister(instr->left()).is(edx)); |
| 1344 ASSERT(ToRegister(instr->right()).is(eax)); |
| 1317 ASSERT(ToRegister(instr->result()).is(eax)); | 1345 ASSERT(ToRegister(instr->result()).is(eax)); |
| 1318 | 1346 |
| 1319 BinaryOpStub stub(instr->op(), NO_OVERWRITE); | 1347 BinaryOpStub stub(instr->op(), NO_OVERWRITE); |
| 1320 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 1348 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1321 } | 1349 } |
| 1322 | 1350 |
| 1323 | 1351 |
| 1324 int LCodeGen::GetNextEmittedBlock(int block) { | 1352 int LCodeGen::GetNextEmittedBlock(int block) { |
| 1325 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { | 1353 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { |
| 1326 LLabel* label = chunk_->GetLabel(i); | 1354 LLabel* label = chunk_->GetLabel(i); |
| 1327 if (!label->HasReplacement()) return i; | 1355 if (!label->HasReplacement()) return i; |
| 1328 } | 1356 } |
| 1329 return -1; | 1357 return -1; |
| 1330 } | 1358 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1345 __ j(cc, chunk_->GetAssemblyLabel(left_block)); | 1373 __ j(cc, chunk_->GetAssemblyLabel(left_block)); |
| 1346 __ jmp(chunk_->GetAssemblyLabel(right_block)); | 1374 __ jmp(chunk_->GetAssemblyLabel(right_block)); |
| 1347 } | 1375 } |
| 1348 } | 1376 } |
| 1349 | 1377 |
| 1350 | 1378 |
| 1351 void LCodeGen::DoBranch(LBranch* instr) { | 1379 void LCodeGen::DoBranch(LBranch* instr) { |
| 1352 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1380 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1353 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1381 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1354 | 1382 |
| 1355 Representation r = instr->hydrogen()->representation(); | 1383 Representation r = instr->hydrogen()->value()->representation(); |
| 1356 if (r.IsInteger32()) { | 1384 if (r.IsInteger32()) { |
| 1357 Register reg = ToRegister(instr->InputAt(0)); | 1385 Register reg = ToRegister(instr->InputAt(0)); |
| 1358 __ test(reg, Operand(reg)); | 1386 __ test(reg, Operand(reg)); |
| 1359 EmitBranch(true_block, false_block, not_zero); | 1387 EmitBranch(true_block, false_block, not_zero); |
| 1360 } else if (r.IsDouble()) { | 1388 } else if (r.IsDouble()) { |
| 1361 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); | 1389 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); |
| 1362 __ xorps(xmm0, xmm0); | 1390 __ xorps(xmm0, xmm0); |
| 1363 __ ucomisd(reg, xmm0); | 1391 __ ucomisd(reg, xmm0); |
| 1364 EmitBranch(true_block, false_block, not_equal); | 1392 EmitBranch(true_block, false_block, not_equal); |
| 1365 } else { | 1393 } else { |
| 1366 ASSERT(r.IsTagged()); | 1394 ASSERT(r.IsTagged()); |
| 1367 Register reg = ToRegister(instr->InputAt(0)); | 1395 Register reg = ToRegister(instr->InputAt(0)); |
| 1368 if (instr->hydrogen()->type().IsBoolean()) { | 1396 if (instr->hydrogen()->value()->type().IsBoolean()) { |
| 1369 __ cmp(reg, factory()->true_value()); | 1397 __ cmp(reg, factory()->true_value()); |
| 1370 EmitBranch(true_block, false_block, equal); | 1398 EmitBranch(true_block, false_block, equal); |
| 1371 } else { | 1399 } else { |
| 1372 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1400 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1373 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1401 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1374 | 1402 |
| 1375 __ cmp(reg, factory()->undefined_value()); | 1403 __ cmp(reg, factory()->undefined_value()); |
| 1376 __ j(equal, false_label); | 1404 __ j(equal, false_label); |
| 1377 __ cmp(reg, factory()->true_value()); | 1405 __ cmp(reg, factory()->true_value()); |
| 1378 __ j(equal, true_label); | 1406 __ j(equal, true_label); |
| 1379 __ cmp(reg, factory()->false_value()); | 1407 __ cmp(reg, factory()->false_value()); |
| 1380 __ j(equal, false_label); | 1408 __ j(equal, false_label); |
| 1381 __ test(reg, Operand(reg)); | 1409 __ test(reg, Operand(reg)); |
| 1382 __ j(equal, false_label); | 1410 __ j(equal, false_label); |
| 1383 __ test(reg, Immediate(kSmiTagMask)); | 1411 __ JumpIfSmi(reg, true_label); |
| 1384 __ j(zero, true_label); | |
| 1385 | 1412 |
| 1386 // Test for double values. Zero is false. | 1413 // Test for double values. Zero is false. |
| 1387 Label call_stub; | 1414 Label call_stub; |
| 1388 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 1415 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 1389 factory()->heap_number_map()); | 1416 factory()->heap_number_map()); |
| 1390 __ j(not_equal, &call_stub, Label::kNear); | 1417 __ j(not_equal, &call_stub, Label::kNear); |
| 1391 __ fldz(); | 1418 __ fldz(); |
| 1392 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset)); | 1419 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
| 1393 __ FCmp(); | 1420 __ FCmp(); |
| 1394 __ j(zero, false_label); | 1421 __ j(zero, false_label); |
| 1395 __ jmp(true_label); | 1422 __ jmp(true_label); |
| 1396 | 1423 |
| 1397 // The conversion stub doesn't cause garbage collections so it's | 1424 // The conversion stub doesn't cause garbage collections so it's |
| 1398 // safe to not record a safepoint after the call. | 1425 // safe to not record a safepoint after the call. |
| 1399 __ bind(&call_stub); | 1426 __ bind(&call_stub); |
| 1400 ToBooleanStub stub; | 1427 ToBooleanStub stub(eax); |
| 1401 __ pushad(); | 1428 __ pushad(); |
| 1402 __ push(reg); | 1429 __ push(reg); |
| 1403 __ CallStub(&stub); | 1430 __ CallStub(&stub); |
| 1404 __ test(eax, Operand(eax)); | 1431 __ test(eax, Operand(eax)); |
| 1405 __ popad(); | 1432 __ popad(); |
| 1406 EmitBranch(true_block, false_block, not_zero); | 1433 EmitBranch(true_block, false_block, not_zero); |
| 1407 } | 1434 } |
| 1408 } | 1435 } |
| 1409 } | 1436 } |
| 1410 | 1437 |
| 1411 | 1438 |
| 1412 void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { | 1439 void LCodeGen::EmitGoto(int block) { |
| 1413 block = chunk_->LookupDestination(block); | 1440 block = chunk_->LookupDestination(block); |
| 1414 int next_block = GetNextEmittedBlock(current_block_); | 1441 int next_block = GetNextEmittedBlock(current_block_); |
| 1415 if (block != next_block) { | 1442 if (block != next_block) { |
| 1416 // Perform stack overflow check if this goto needs it before jumping. | 1443 __ jmp(chunk_->GetAssemblyLabel(block)); |
| 1417 if (deferred_stack_check != NULL) { | |
| 1418 ExternalReference stack_limit = | |
| 1419 ExternalReference::address_of_stack_limit(isolate()); | |
| 1420 __ cmp(esp, Operand::StaticVariable(stack_limit)); | |
| 1421 __ j(above_equal, chunk_->GetAssemblyLabel(block)); | |
| 1422 __ jmp(deferred_stack_check->entry()); | |
| 1423 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block)); | |
| 1424 } else { | |
| 1425 __ jmp(chunk_->GetAssemblyLabel(block)); | |
| 1426 } | |
| 1427 } | 1444 } |
| 1428 } | 1445 } |
| 1429 | 1446 |
| 1430 | 1447 |
| 1431 void LCodeGen::DoDeferredStackCheck(LGoto* instr) { | |
| 1432 PushSafepointRegistersScope scope(this); | |
| 1433 CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr); | |
| 1434 } | |
| 1435 | |
| 1436 void LCodeGen::DoGoto(LGoto* instr) { | 1448 void LCodeGen::DoGoto(LGoto* instr) { |
| 1437 class DeferredStackCheck: public LDeferredCode { | 1449 EmitGoto(instr->block_id()); |
| 1438 public: | |
| 1439 DeferredStackCheck(LCodeGen* codegen, LGoto* instr) | |
| 1440 : LDeferredCode(codegen), instr_(instr) { } | |
| 1441 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } | |
| 1442 private: | |
| 1443 LGoto* instr_; | |
| 1444 }; | |
| 1445 | |
| 1446 DeferredStackCheck* deferred = NULL; | |
| 1447 if (instr->include_stack_check()) { | |
| 1448 deferred = new DeferredStackCheck(this, instr); | |
| 1449 } | |
| 1450 EmitGoto(instr->block_id(), deferred); | |
| 1451 } | 1450 } |
| 1452 | 1451 |
| 1453 | 1452 |
| 1454 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 1453 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| 1455 Condition cond = no_condition; | 1454 Condition cond = no_condition; |
| 1456 switch (op) { | 1455 switch (op) { |
| 1457 case Token::EQ: | 1456 case Token::EQ: |
| 1458 case Token::EQ_STRICT: | 1457 case Token::EQ_STRICT: |
| 1459 cond = equal; | 1458 cond = equal; |
| 1460 break; | 1459 break; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1481 | 1480 |
| 1482 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { | 1481 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { |
| 1483 if (right->IsConstantOperand()) { | 1482 if (right->IsConstantOperand()) { |
| 1484 __ cmp(ToOperand(left), ToImmediate(right)); | 1483 __ cmp(ToOperand(left), ToImmediate(right)); |
| 1485 } else { | 1484 } else { |
| 1486 __ cmp(ToRegister(left), ToOperand(right)); | 1485 __ cmp(ToRegister(left), ToOperand(right)); |
| 1487 } | 1486 } |
| 1488 } | 1487 } |
| 1489 | 1488 |
| 1490 | 1489 |
| 1491 void LCodeGen::DoCmpID(LCmpID* instr) { | |
| 1492 LOperand* left = instr->InputAt(0); | |
| 1493 LOperand* right = instr->InputAt(1); | |
| 1494 LOperand* result = instr->result(); | |
| 1495 | |
| 1496 Label unordered; | |
| 1497 if (instr->is_double()) { | |
| 1498 // Don't base result on EFLAGS when a NaN is involved. Instead | |
| 1499 // jump to the unordered case, which produces a false value. | |
| 1500 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | |
| 1501 __ j(parity_even, &unordered, Label::kNear); | |
| 1502 } else { | |
| 1503 EmitCmpI(left, right); | |
| 1504 } | |
| 1505 | |
| 1506 Label done; | |
| 1507 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
| 1508 __ mov(ToRegister(result), factory()->true_value()); | |
| 1509 __ j(cc, &done, Label::kNear); | |
| 1510 | |
| 1511 __ bind(&unordered); | |
| 1512 __ mov(ToRegister(result), factory()->false_value()); | |
| 1513 __ bind(&done); | |
| 1514 } | |
| 1515 | |
| 1516 | |
| 1517 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1490 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 1518 LOperand* left = instr->InputAt(0); | 1491 LOperand* left = instr->InputAt(0); |
| 1519 LOperand* right = instr->InputAt(1); | 1492 LOperand* right = instr->InputAt(1); |
| 1520 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1493 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1521 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1494 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1522 | 1495 |
| 1523 if (instr->is_double()) { | 1496 if (instr->is_double()) { |
| 1524 // Don't base result on EFLAGS when a NaN is involved. Instead | 1497 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 1525 // jump to the false block. | 1498 // jump to the false block. |
| 1526 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1499 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 1527 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | 1500 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
| 1528 } else { | 1501 } else { |
| 1529 EmitCmpI(left, right); | 1502 EmitCmpI(left, right); |
| 1530 } | 1503 } |
| 1531 | 1504 |
| 1532 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | 1505 Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| 1533 EmitBranch(true_block, false_block, cc); | 1506 EmitBranch(true_block, false_block, cc); |
| 1534 } | 1507 } |
| 1535 | 1508 |
| 1536 | 1509 |
| 1537 void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { | 1510 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
| 1538 Register left = ToRegister(instr->InputAt(0)); | 1511 Register left = ToRegister(instr->InputAt(0)); |
| 1539 Register right = ToRegister(instr->InputAt(1)); | 1512 Operand right = ToOperand(instr->InputAt(1)); |
| 1540 Register result = ToRegister(instr->result()); | |
| 1541 | |
| 1542 __ cmp(left, Operand(right)); | |
| 1543 __ mov(result, factory()->true_value()); | |
| 1544 Label done; | |
| 1545 __ j(equal, &done, Label::kNear); | |
| 1546 __ mov(result, factory()->false_value()); | |
| 1547 __ bind(&done); | |
| 1548 } | |
| 1549 | |
| 1550 | |
| 1551 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { | |
| 1552 Register left = ToRegister(instr->InputAt(0)); | |
| 1553 Register right = ToRegister(instr->InputAt(1)); | |
| 1554 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1513 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1555 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1514 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1556 | 1515 |
| 1557 __ cmp(left, Operand(right)); | 1516 __ cmp(left, Operand(right)); |
| 1558 EmitBranch(true_block, false_block, equal); | 1517 EmitBranch(true_block, false_block, equal); |
| 1559 } | 1518 } |
| 1560 | 1519 |
| 1561 | 1520 |
| 1562 void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) { | 1521 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 1563 Register left = ToRegister(instr->InputAt(0)); | 1522 Register left = ToRegister(instr->InputAt(0)); |
| 1564 Register right = ToRegister(instr->InputAt(1)); | 1523 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1565 Register result = ToRegister(instr->result()); | 1524 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1566 | 1525 |
| 1567 Label done; | 1526 __ cmp(left, instr->hydrogen()->right()); |
| 1568 __ cmp(left, Operand(right)); | |
| 1569 __ mov(result, factory()->false_value()); | |
| 1570 __ j(not_equal, &done, Label::kNear); | |
| 1571 __ mov(result, factory()->true_value()); | |
| 1572 __ bind(&done); | |
| 1573 } | |
| 1574 | |
| 1575 | |
| 1576 void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) { | |
| 1577 Register left = ToRegister(instr->InputAt(0)); | |
| 1578 Register right = ToRegister(instr->InputAt(1)); | |
| 1579 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 1580 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 1581 | |
| 1582 __ cmp(left, Operand(right)); | |
| 1583 EmitBranch(true_block, false_block, equal); | 1527 EmitBranch(true_block, false_block, equal); |
| 1584 } | 1528 } |
| 1585 | 1529 |
| 1586 | 1530 |
| 1587 void LCodeGen::DoIsNull(LIsNull* instr) { | |
| 1588 Register reg = ToRegister(instr->InputAt(0)); | |
| 1589 Register result = ToRegister(instr->result()); | |
| 1590 | |
| 1591 // TODO(fsc): If the expression is known to be a smi, then it's | |
| 1592 // definitely not null. Materialize false. | |
| 1593 | |
| 1594 __ cmp(reg, factory()->null_value()); | |
| 1595 if (instr->is_strict()) { | |
| 1596 __ mov(result, factory()->true_value()); | |
| 1597 Label done; | |
| 1598 __ j(equal, &done, Label::kNear); | |
| 1599 __ mov(result, factory()->false_value()); | |
| 1600 __ bind(&done); | |
| 1601 } else { | |
| 1602 Label true_value, false_value, done; | |
| 1603 __ j(equal, &true_value, Label::kNear); | |
| 1604 __ cmp(reg, factory()->undefined_value()); | |
| 1605 __ j(equal, &true_value, Label::kNear); | |
| 1606 __ test(reg, Immediate(kSmiTagMask)); | |
| 1607 __ j(zero, &false_value, Label::kNear); | |
| 1608 // Check for undetectable objects by looking in the bit field in | |
| 1609 // the map. The object has already been smi checked. | |
| 1610 Register scratch = result; | |
| 1611 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | |
| 1612 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); | |
| 1613 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); | |
| 1614 __ j(not_zero, &true_value, Label::kNear); | |
| 1615 __ bind(&false_value); | |
| 1616 __ mov(result, factory()->false_value()); | |
| 1617 __ jmp(&done, Label::kNear); | |
| 1618 __ bind(&true_value); | |
| 1619 __ mov(result, factory()->true_value()); | |
| 1620 __ bind(&done); | |
| 1621 } | |
| 1622 } | |
| 1623 | |
| 1624 | |
| 1625 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1531 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
| 1626 Register reg = ToRegister(instr->InputAt(0)); | 1532 Register reg = ToRegister(instr->InputAt(0)); |
| 1627 | 1533 |
| 1628 // TODO(fsc): If the expression is known to be a smi, then it's | 1534 // TODO(fsc): If the expression is known to be a smi, then it's |
| 1629 // definitely not null. Jump to the false block. | 1535 // definitely not null. Jump to the false block. |
| 1630 | 1536 |
| 1631 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1537 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1632 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1538 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1633 | 1539 |
| 1634 __ cmp(reg, factory()->null_value()); | 1540 __ cmp(reg, factory()->null_value()); |
| 1635 if (instr->is_strict()) { | 1541 if (instr->is_strict()) { |
| 1636 EmitBranch(true_block, false_block, equal); | 1542 EmitBranch(true_block, false_block, equal); |
| 1637 } else { | 1543 } else { |
| 1638 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1544 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1639 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1545 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1640 __ j(equal, true_label); | 1546 __ j(equal, true_label); |
| 1641 __ cmp(reg, factory()->undefined_value()); | 1547 __ cmp(reg, factory()->undefined_value()); |
| 1642 __ j(equal, true_label); | 1548 __ j(equal, true_label); |
| 1643 __ test(reg, Immediate(kSmiTagMask)); | 1549 __ JumpIfSmi(reg, false_label); |
| 1644 __ j(zero, false_label); | |
| 1645 // Check for undetectable objects by looking in the bit field in | 1550 // Check for undetectable objects by looking in the bit field in |
| 1646 // the map. The object has already been smi checked. | 1551 // the map. The object has already been smi checked. |
| 1647 Register scratch = ToRegister(instr->TempAt(0)); | 1552 Register scratch = ToRegister(instr->TempAt(0)); |
| 1648 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 1553 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1649 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); | 1554 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); |
| 1650 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); | 1555 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); |
| 1651 EmitBranch(true_block, false_block, not_zero); | 1556 EmitBranch(true_block, false_block, not_zero); |
| 1652 } | 1557 } |
| 1653 } | 1558 } |
| 1654 | 1559 |
| 1655 | 1560 |
| 1656 Condition LCodeGen::EmitIsObject(Register input, | 1561 Condition LCodeGen::EmitIsObject(Register input, |
| 1657 Register temp1, | 1562 Register temp1, |
| 1658 Register temp2, | |
| 1659 Label* is_not_object, | 1563 Label* is_not_object, |
| 1660 Label* is_object) { | 1564 Label* is_object) { |
| 1661 ASSERT(!input.is(temp1)); | 1565 __ JumpIfSmi(input, is_not_object); |
| 1662 ASSERT(!input.is(temp2)); | |
| 1663 ASSERT(!temp1.is(temp2)); | |
| 1664 | |
| 1665 __ test(input, Immediate(kSmiTagMask)); | |
| 1666 __ j(equal, is_not_object); | |
| 1667 | 1566 |
| 1668 __ cmp(input, isolate()->factory()->null_value()); | 1567 __ cmp(input, isolate()->factory()->null_value()); |
| 1669 __ j(equal, is_object); | 1568 __ j(equal, is_object); |
| 1670 | 1569 |
| 1671 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset)); | 1570 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset)); |
| 1672 // Undetectable objects behave like undefined. | 1571 // Undetectable objects behave like undefined. |
| 1673 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset)); | 1572 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset), |
| 1674 __ test(temp2, Immediate(1 << Map::kIsUndetectable)); | 1573 1 << Map::kIsUndetectable); |
| 1675 __ j(not_zero, is_not_object); | 1574 __ j(not_zero, is_not_object); |
| 1676 | 1575 |
| 1677 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset)); | 1576 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset)); |
| 1678 __ cmp(temp2, FIRST_JS_OBJECT_TYPE); | 1577 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 1679 __ j(below, is_not_object); | 1578 __ j(below, is_not_object); |
| 1680 __ cmp(temp2, LAST_JS_OBJECT_TYPE); | 1579 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 1681 return below_equal; | 1580 return below_equal; |
| 1682 } | 1581 } |
| 1683 | 1582 |
| 1684 | 1583 |
| 1685 void LCodeGen::DoIsObject(LIsObject* instr) { | |
| 1686 Register reg = ToRegister(instr->InputAt(0)); | |
| 1687 Register result = ToRegister(instr->result()); | |
| 1688 Register temp = ToRegister(instr->TempAt(0)); | |
| 1689 Label is_false, is_true, done; | |
| 1690 | |
| 1691 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); | |
| 1692 __ j(true_cond, &is_true); | |
| 1693 | |
| 1694 __ bind(&is_false); | |
| 1695 __ mov(result, factory()->false_value()); | |
| 1696 __ jmp(&done); | |
| 1697 | |
| 1698 __ bind(&is_true); | |
| 1699 __ mov(result, factory()->true_value()); | |
| 1700 | |
| 1701 __ bind(&done); | |
| 1702 } | |
| 1703 | |
| 1704 | |
| 1705 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 1584 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 1706 Register reg = ToRegister(instr->InputAt(0)); | 1585 Register reg = ToRegister(instr->InputAt(0)); |
| 1707 Register temp = ToRegister(instr->TempAt(0)); | 1586 Register temp = ToRegister(instr->TempAt(0)); |
| 1708 Register temp2 = ToRegister(instr->TempAt(1)); | |
| 1709 | 1587 |
| 1710 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1588 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1711 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1589 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1712 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1590 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1713 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1591 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1714 | 1592 |
| 1715 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); | 1593 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label); |
| 1716 | 1594 |
| 1717 EmitBranch(true_block, false_block, true_cond); | 1595 EmitBranch(true_block, false_block, true_cond); |
| 1718 } | 1596 } |
| 1719 | 1597 |
| 1720 | 1598 |
| 1721 void LCodeGen::DoIsSmi(LIsSmi* instr) { | |
| 1722 Operand input = ToOperand(instr->InputAt(0)); | |
| 1723 Register result = ToRegister(instr->result()); | |
| 1724 | |
| 1725 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1726 __ test(input, Immediate(kSmiTagMask)); | |
| 1727 __ mov(result, factory()->true_value()); | |
| 1728 Label done; | |
| 1729 __ j(zero, &done, Label::kNear); | |
| 1730 __ mov(result, factory()->false_value()); | |
| 1731 __ bind(&done); | |
| 1732 } | |
| 1733 | |
| 1734 | |
| 1735 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 1599 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 1736 Operand input = ToOperand(instr->InputAt(0)); | 1600 Operand input = ToOperand(instr->InputAt(0)); |
| 1737 | 1601 |
| 1738 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1602 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1739 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1603 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1740 | 1604 |
| 1741 __ test(input, Immediate(kSmiTagMask)); | 1605 __ test(input, Immediate(kSmiTagMask)); |
| 1742 EmitBranch(true_block, false_block, zero); | 1606 EmitBranch(true_block, false_block, zero); |
| 1743 } | 1607 } |
| 1744 | 1608 |
| 1745 | 1609 |
| 1746 void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) { | |
| 1747 Register input = ToRegister(instr->InputAt(0)); | |
| 1748 Register result = ToRegister(instr->result()); | |
| 1749 | |
| 1750 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1751 Label false_label, done; | |
| 1752 STATIC_ASSERT(kSmiTag == 0); | |
| 1753 __ test(input, Immediate(kSmiTagMask)); | |
| 1754 __ j(zero, &false_label, Label::kNear); | |
| 1755 __ mov(result, FieldOperand(input, HeapObject::kMapOffset)); | |
| 1756 __ test_b(FieldOperand(result, Map::kBitFieldOffset), | |
| 1757 1 << Map::kIsUndetectable); | |
| 1758 __ j(zero, &false_label, Label::kNear); | |
| 1759 __ mov(result, factory()->true_value()); | |
| 1760 __ jmp(&done); | |
| 1761 __ bind(&false_label); | |
| 1762 __ mov(result, factory()->false_value()); | |
| 1763 __ bind(&done); | |
| 1764 } | |
| 1765 | |
| 1766 | |
| 1767 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 1610 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 1768 Register input = ToRegister(instr->InputAt(0)); | 1611 Register input = ToRegister(instr->InputAt(0)); |
| 1769 Register temp = ToRegister(instr->TempAt(0)); | 1612 Register temp = ToRegister(instr->TempAt(0)); |
| 1770 | 1613 |
| 1771 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1614 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1772 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1615 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1773 | 1616 |
| 1774 STATIC_ASSERT(kSmiTag == 0); | 1617 STATIC_ASSERT(kSmiTag == 0); |
| 1775 __ test(input, Immediate(kSmiTagMask)); | 1618 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); |
| 1776 __ j(zero, chunk_->GetAssemblyLabel(false_block)); | |
| 1777 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 1619 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 1778 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), | 1620 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), |
| 1779 1 << Map::kIsUndetectable); | 1621 1 << Map::kIsUndetectable); |
| 1780 EmitBranch(true_block, false_block, not_zero); | 1622 EmitBranch(true_block, false_block, not_zero); |
| 1781 } | 1623 } |
| 1782 | 1624 |
| 1783 | 1625 |
| 1784 static InstanceType TestType(HHasInstanceType* instr) { | 1626 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { |
| 1785 InstanceType from = instr->from(); | 1627 InstanceType from = instr->from(); |
| 1786 InstanceType to = instr->to(); | 1628 InstanceType to = instr->to(); |
| 1787 if (from == FIRST_TYPE) return to; | 1629 if (from == FIRST_TYPE) return to; |
| 1788 ASSERT(from == to || to == LAST_TYPE); | 1630 ASSERT(from == to || to == LAST_TYPE); |
| 1789 return from; | 1631 return from; |
| 1790 } | 1632 } |
| 1791 | 1633 |
| 1792 | 1634 |
| 1793 static Condition BranchCondition(HHasInstanceType* instr) { | 1635 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { |
| 1794 InstanceType from = instr->from(); | 1636 InstanceType from = instr->from(); |
| 1795 InstanceType to = instr->to(); | 1637 InstanceType to = instr->to(); |
| 1796 if (from == to) return equal; | 1638 if (from == to) return equal; |
| 1797 if (to == LAST_TYPE) return above_equal; | 1639 if (to == LAST_TYPE) return above_equal; |
| 1798 if (from == FIRST_TYPE) return below_equal; | 1640 if (from == FIRST_TYPE) return below_equal; |
| 1799 UNREACHABLE(); | 1641 UNREACHABLE(); |
| 1800 return equal; | 1642 return equal; |
| 1801 } | 1643 } |
| 1802 | 1644 |
| 1803 | 1645 |
| 1804 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | |
| 1805 Register input = ToRegister(instr->InputAt(0)); | |
| 1806 Register result = ToRegister(instr->result()); | |
| 1807 | |
| 1808 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1809 __ test(input, Immediate(kSmiTagMask)); | |
| 1810 Label done, is_false; | |
| 1811 __ j(zero, &is_false, Label::kNear); | |
| 1812 __ CmpObjectType(input, TestType(instr->hydrogen()), result); | |
| 1813 __ j(NegateCondition(BranchCondition(instr->hydrogen())), | |
| 1814 &is_false, Label::kNear); | |
| 1815 __ mov(result, factory()->true_value()); | |
| 1816 __ jmp(&done, Label::kNear); | |
| 1817 __ bind(&is_false); | |
| 1818 __ mov(result, factory()->false_value()); | |
| 1819 __ bind(&done); | |
| 1820 } | |
| 1821 | |
| 1822 | |
| 1823 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1646 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 1824 Register input = ToRegister(instr->InputAt(0)); | 1647 Register input = ToRegister(instr->InputAt(0)); |
| 1825 Register temp = ToRegister(instr->TempAt(0)); | 1648 Register temp = ToRegister(instr->TempAt(0)); |
| 1826 | 1649 |
| 1827 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1650 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1828 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1651 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1829 | 1652 |
| 1830 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1653 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1831 | 1654 |
| 1832 __ test(input, Immediate(kSmiTagMask)); | 1655 __ JumpIfSmi(input, false_label); |
| 1833 __ j(zero, false_label); | |
| 1834 | 1656 |
| 1835 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); | 1657 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); |
| 1836 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 1658 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1837 } | 1659 } |
| 1838 | 1660 |
| 1839 | 1661 |
| 1840 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { | 1662 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 1841 Register input = ToRegister(instr->InputAt(0)); | 1663 Register input = ToRegister(instr->InputAt(0)); |
| 1842 Register result = ToRegister(instr->result()); | 1664 Register result = ToRegister(instr->result()); |
| 1843 | 1665 |
| 1844 if (FLAG_debug_code) { | 1666 if (FLAG_debug_code) { |
| 1845 __ AbortIfNotString(input); | 1667 __ AbortIfNotString(input); |
| 1846 } | 1668 } |
| 1847 | 1669 |
| 1848 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); | 1670 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); |
| 1849 __ IndexFromHash(result, result); | 1671 __ IndexFromHash(result, result); |
| 1850 } | 1672 } |
| 1851 | 1673 |
| 1852 | 1674 |
| 1853 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | |
| 1854 Register input = ToRegister(instr->InputAt(0)); | |
| 1855 Register result = ToRegister(instr->result()); | |
| 1856 | |
| 1857 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | |
| 1858 __ mov(result, factory()->true_value()); | |
| 1859 __ test(FieldOperand(input, String::kHashFieldOffset), | |
| 1860 Immediate(String::kContainsCachedArrayIndexMask)); | |
| 1861 Label done; | |
| 1862 __ j(zero, &done, Label::kNear); | |
| 1863 __ mov(result, factory()->false_value()); | |
| 1864 __ bind(&done); | |
| 1865 } | |
| 1866 | |
| 1867 | |
| 1868 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1675 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1869 LHasCachedArrayIndexAndBranch* instr) { | 1676 LHasCachedArrayIndexAndBranch* instr) { |
| 1870 Register input = ToRegister(instr->InputAt(0)); | 1677 Register input = ToRegister(instr->InputAt(0)); |
| 1871 | 1678 |
| 1872 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1679 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1873 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1680 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1874 | 1681 |
| 1875 __ test(FieldOperand(input, String::kHashFieldOffset), | 1682 __ test(FieldOperand(input, String::kHashFieldOffset), |
| 1876 Immediate(String::kContainsCachedArrayIndexMask)); | 1683 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1877 EmitBranch(true_block, false_block, equal); | 1684 EmitBranch(true_block, false_block, equal); |
| 1878 } | 1685 } |
| 1879 | 1686 |
| 1880 | 1687 |
| 1881 // Branches to a label or falls through with the answer in the z flag. Trashes | 1688 // Branches to a label or falls through with the answer in the z flag. Trashes |
| 1882 // the temp registers, but not the input. Only input and temp2 may alias. | 1689 // the temp registers, but not the input. Only input and temp2 may alias. |
| 1883 void LCodeGen::EmitClassOfTest(Label* is_true, | 1690 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1884 Label* is_false, | 1691 Label* is_false, |
| 1885 Handle<String>class_name, | 1692 Handle<String>class_name, |
| 1886 Register input, | 1693 Register input, |
| 1887 Register temp, | 1694 Register temp, |
| 1888 Register temp2) { | 1695 Register temp2) { |
| 1889 ASSERT(!input.is(temp)); | 1696 ASSERT(!input.is(temp)); |
| 1890 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. | 1697 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. |
| 1891 __ test(input, Immediate(kSmiTagMask)); | 1698 __ JumpIfSmi(input, is_false); |
| 1892 __ j(zero, is_false); | 1699 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
| 1893 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp); | |
| 1894 __ j(below, is_false); | 1700 __ j(below, is_false); |
| 1895 | 1701 |
| 1896 // Map is now in temp. | 1702 // Map is now in temp. |
| 1897 // Functions have class 'Function'. | 1703 // Functions have class 'Function'. |
| 1898 __ CmpInstanceType(temp, JS_FUNCTION_TYPE); | 1704 __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1899 if (class_name->IsEqualTo(CStrVector("Function"))) { | 1705 if (class_name->IsEqualTo(CStrVector("Function"))) { |
| 1900 __ j(equal, is_true); | 1706 __ j(above_equal, is_true); |
| 1901 } else { | 1707 } else { |
| 1902 __ j(equal, is_false); | 1708 __ j(above_equal, is_false); |
| 1903 } | 1709 } |
| 1904 | 1710 |
| 1905 // Check if the constructor in the map is a function. | 1711 // Check if the constructor in the map is a function. |
| 1906 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset)); | 1712 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset)); |
| 1907 | 1713 |
| 1908 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 1714 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
| 1909 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 1715 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
| 1910 // LAST_JS_OBJECT_TYPE. | 1716 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
| 1911 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1717 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1912 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 1718 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
| 1719 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
| 1913 | 1720 |
| 1914 // Objects with a non-function constructor have class 'Object'. | 1721 // Objects with a non-function constructor have class 'Object'. |
| 1915 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2); | 1722 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2); |
| 1916 if (class_name->IsEqualTo(CStrVector("Object"))) { | 1723 if (class_name->IsEqualTo(CStrVector("Object"))) { |
| 1917 __ j(not_equal, is_true); | 1724 __ j(not_equal, is_true); |
| 1918 } else { | 1725 } else { |
| 1919 __ j(not_equal, is_false); | 1726 __ j(not_equal, is_false); |
| 1920 } | 1727 } |
| 1921 | 1728 |
| 1922 // temp now contains the constructor function. Grab the | 1729 // temp now contains the constructor function. Grab the |
| 1923 // instance class name from there. | 1730 // instance class name from there. |
| 1924 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); | 1731 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
| 1925 __ mov(temp, FieldOperand(temp, | 1732 __ mov(temp, FieldOperand(temp, |
| 1926 SharedFunctionInfo::kInstanceClassNameOffset)); | 1733 SharedFunctionInfo::kInstanceClassNameOffset)); |
| 1927 // The class name we are testing against is a symbol because it's a literal. | 1734 // The class name we are testing against is a symbol because it's a literal. |
| 1928 // The name in the constructor is a symbol because of the way the context is | 1735 // The name in the constructor is a symbol because of the way the context is |
| 1929 // booted. This routine isn't expected to work for random API-created | 1736 // booted. This routine isn't expected to work for random API-created |
| 1930 // classes and it doesn't have to because you can't access it with natives | 1737 // classes and it doesn't have to because you can't access it with natives |
| 1931 // syntax. Since both sides are symbols it is sufficient to use an identity | 1738 // syntax. Since both sides are symbols it is sufficient to use an identity |
| 1932 // comparison. | 1739 // comparison. |
| 1933 __ cmp(temp, class_name); | 1740 __ cmp(temp, class_name); |
| 1934 // End with the answer in the z flag. | 1741 // End with the answer in the z flag. |
| 1935 } | 1742 } |
| 1936 | 1743 |
| 1937 | 1744 |
| 1938 void LCodeGen::DoClassOfTest(LClassOfTest* instr) { | |
| 1939 Register input = ToRegister(instr->InputAt(0)); | |
| 1940 Register result = ToRegister(instr->result()); | |
| 1941 ASSERT(input.is(result)); | |
| 1942 Register temp = ToRegister(instr->TempAt(0)); | |
| 1943 Handle<String> class_name = instr->hydrogen()->class_name(); | |
| 1944 Label done; | |
| 1945 Label is_true, is_false; | |
| 1946 | |
| 1947 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input); | |
| 1948 | |
| 1949 __ j(not_equal, &is_false, Label::kNear); | |
| 1950 | |
| 1951 __ bind(&is_true); | |
| 1952 __ mov(result, factory()->true_value()); | |
| 1953 __ jmp(&done, Label::kNear); | |
| 1954 | |
| 1955 __ bind(&is_false); | |
| 1956 __ mov(result, factory()->false_value()); | |
| 1957 __ bind(&done); | |
| 1958 } | |
| 1959 | |
| 1960 | |
| 1961 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 1745 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 1962 Register input = ToRegister(instr->InputAt(0)); | 1746 Register input = ToRegister(instr->InputAt(0)); |
| 1963 Register temp = ToRegister(instr->TempAt(0)); | 1747 Register temp = ToRegister(instr->TempAt(0)); |
| 1964 Register temp2 = ToRegister(instr->TempAt(1)); | 1748 Register temp2 = ToRegister(instr->TempAt(1)); |
| 1965 if (input.is(temp)) { | 1749 if (input.is(temp)) { |
| 1966 // Swap. | 1750 // Swap. |
| 1967 Register swapper = temp; | 1751 Register swapper = temp; |
| 1968 temp = temp2; | 1752 temp = temp2; |
| 1969 temp2 = swapper; | 1753 temp2 = swapper; |
| 1970 } | 1754 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1989 | 1773 |
| 1990 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); | 1774 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); |
| 1991 EmitBranch(true_block, false_block, equal); | 1775 EmitBranch(true_block, false_block, equal); |
| 1992 } | 1776 } |
| 1993 | 1777 |
| 1994 | 1778 |
| 1995 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 1779 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 1996 // Object and function are in fixed registers defined by the stub. | 1780 // Object and function are in fixed registers defined by the stub. |
| 1997 ASSERT(ToRegister(instr->context()).is(esi)); | 1781 ASSERT(ToRegister(instr->context()).is(esi)); |
| 1998 InstanceofStub stub(InstanceofStub::kArgsInRegisters); | 1782 InstanceofStub stub(InstanceofStub::kArgsInRegisters); |
| 1999 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 1783 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2000 | 1784 |
| 2001 Label true_value, done; | 1785 Label true_value, done; |
| 2002 __ test(eax, Operand(eax)); | 1786 __ test(eax, Operand(eax)); |
| 2003 __ j(zero, &true_value, Label::kNear); | 1787 __ j(zero, &true_value, Label::kNear); |
| 2004 __ mov(ToRegister(instr->result()), factory()->false_value()); | 1788 __ mov(ToRegister(instr->result()), factory()->false_value()); |
| 2005 __ jmp(&done, Label::kNear); | 1789 __ jmp(&done, Label::kNear); |
| 2006 __ bind(&true_value); | 1790 __ bind(&true_value); |
| 2007 __ mov(ToRegister(instr->result()), factory()->true_value()); | 1791 __ mov(ToRegister(instr->result()), factory()->true_value()); |
| 2008 __ bind(&done); | 1792 __ bind(&done); |
| 2009 } | 1793 } |
| 2010 | 1794 |
| 2011 | 1795 |
| 2012 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { | |
| 2013 ASSERT(ToRegister(instr->context()).is(esi)); | |
| 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::kArgsInRegisters); | |
| 2018 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | |
| 2019 __ test(eax, Operand(eax)); | |
| 2020 EmitBranch(true_block, false_block, zero); | |
| 2021 } | |
| 2022 | |
| 2023 | |
| 2024 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1796 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 2025 class DeferredInstanceOfKnownGlobal: public LDeferredCode { | 1797 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 2026 public: | 1798 public: |
| 2027 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 1799 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 2028 LInstanceOfKnownGlobal* instr) | 1800 LInstanceOfKnownGlobal* instr) |
| 2029 : LDeferredCode(codegen), instr_(instr) { } | 1801 : LDeferredCode(codegen), instr_(instr) { } |
| 2030 virtual void Generate() { | 1802 virtual void Generate() { |
| 2031 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); | 1803 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 2032 } | 1804 } |
| 2033 | 1805 |
| 2034 Label* map_check() { return &map_check_; } | 1806 Label* map_check() { return &map_check_; } |
| 2035 | 1807 |
| 2036 private: | 1808 private: |
| 2037 LInstanceOfKnownGlobal* instr_; | 1809 LInstanceOfKnownGlobal* instr_; |
| 2038 Label map_check_; | 1810 Label map_check_; |
| 2039 }; | 1811 }; |
| 2040 | 1812 |
| 2041 DeferredInstanceOfKnownGlobal* deferred; | 1813 DeferredInstanceOfKnownGlobal* deferred; |
| 2042 deferred = new DeferredInstanceOfKnownGlobal(this, instr); | 1814 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 2043 | 1815 |
| 2044 Label done, false_result; | 1816 Label done, false_result; |
| 2045 Register object = ToRegister(instr->InputAt(0)); | 1817 Register object = ToRegister(instr->InputAt(1)); |
| 2046 Register temp = ToRegister(instr->TempAt(0)); | 1818 Register temp = ToRegister(instr->TempAt(0)); |
| 2047 | 1819 |
| 2048 // A Smi is not an instance of anything. | 1820 // A Smi is not an instance of anything. |
| 2049 __ test(object, Immediate(kSmiTagMask)); | 1821 __ JumpIfSmi(object, &false_result); |
| 2050 __ j(zero, &false_result); | |
| 2051 | 1822 |
| 2052 // This is the inlined call site instanceof cache. The two occurences of the | 1823 // This is the inlined call site instanceof cache. The two occurences of the |
| 2053 // hole value will be patched to the last map/result pair generated by the | 1824 // hole value will be patched to the last map/result pair generated by the |
| 2054 // instanceof stub. | 1825 // instanceof stub. |
| 2055 Label cache_miss; | 1826 Label cache_miss; |
| 2056 Register map = ToRegister(instr->TempAt(0)); | 1827 Register map = ToRegister(instr->TempAt(0)); |
| 2057 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); | 1828 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 2058 __ bind(deferred->map_check()); // Label for calculating code patching. | 1829 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 2059 __ cmp(map, factory()->the_hole_value()); // Patched to cached map. | 1830 __ cmp(map, factory()->the_hole_value()); // Patched to cached map. |
| 2060 __ j(not_equal, &cache_miss, Label::kNear); | 1831 __ j(not_equal, &cache_miss, Label::kNear); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2098 flags | InstanceofStub::kReturnTrueFalseObject); | 1869 flags | InstanceofStub::kReturnTrueFalseObject); |
| 2099 InstanceofStub stub(flags); | 1870 InstanceofStub stub(flags); |
| 2100 | 1871 |
| 2101 // Get the temp register reserved by the instruction. This needs to be a | 1872 // Get the temp register reserved by the instruction. This needs to be a |
| 2102 // register which is pushed last by PushSafepointRegisters as top of the | 1873 // register which is pushed last by PushSafepointRegisters as top of the |
| 2103 // stack is used to pass the offset to the location of the map check to | 1874 // stack is used to pass the offset to the location of the map check to |
| 2104 // the stub. | 1875 // the stub. |
| 2105 Register temp = ToRegister(instr->TempAt(0)); | 1876 Register temp = ToRegister(instr->TempAt(0)); |
| 2106 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0); | 1877 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0); |
| 2107 __ mov(InstanceofStub::right(), Immediate(instr->function())); | 1878 __ mov(InstanceofStub::right(), Immediate(instr->function())); |
| 2108 static const int kAdditionalDelta = 16; | 1879 static const int kAdditionalDelta = 13; |
| 2109 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; | 1880 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; |
| 2110 __ mov(temp, Immediate(delta)); | 1881 __ mov(temp, Immediate(delta)); |
| 2111 __ StoreToSafepointRegisterSlot(temp, temp); | 1882 __ StoreToSafepointRegisterSlot(temp, temp); |
| 2112 CallCodeGeneric(stub.GetCode(), | 1883 CallCodeGeneric(stub.GetCode(), |
| 2113 RelocInfo::CODE_TARGET, | 1884 RelocInfo::CODE_TARGET, |
| 2114 instr, | 1885 instr, |
| 2115 RESTORE_CONTEXT, | |
| 2116 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); | 1886 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); |
| 2117 // Put the result value into the eax slot and restore all registers. | 1887 // Put the result value into the eax slot and restore all registers. |
| 2118 __ StoreToSafepointRegisterSlot(eax, eax); | 1888 __ StoreToSafepointRegisterSlot(eax, eax); |
| 2119 } | 1889 } |
| 2120 | 1890 |
| 2121 | 1891 |
| 2122 static Condition ComputeCompareCondition(Token::Value op) { | 1892 static Condition ComputeCompareCondition(Token::Value op) { |
| 2123 switch (op) { | 1893 switch (op) { |
| 2124 case Token::EQ_STRICT: | 1894 case Token::EQ_STRICT: |
| 2125 case Token::EQ: | 1895 case Token::EQ: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2136 UNREACHABLE(); | 1906 UNREACHABLE(); |
| 2137 return no_condition; | 1907 return no_condition; |
| 2138 } | 1908 } |
| 2139 } | 1909 } |
| 2140 | 1910 |
| 2141 | 1911 |
| 2142 void LCodeGen::DoCmpT(LCmpT* instr) { | 1912 void LCodeGen::DoCmpT(LCmpT* instr) { |
| 2143 Token::Value op = instr->op(); | 1913 Token::Value op = instr->op(); |
| 2144 | 1914 |
| 2145 Handle<Code> ic = CompareIC::GetUninitialized(op); | 1915 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 2146 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 1916 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2147 | 1917 |
| 2148 Condition condition = ComputeCompareCondition(op); | 1918 Condition condition = ComputeCompareCondition(op); |
| 2149 if (op == Token::GT || op == Token::LTE) { | 1919 if (op == Token::GT || op == Token::LTE) { |
| 2150 condition = ReverseCondition(condition); | 1920 condition = ReverseCondition(condition); |
| 2151 } | 1921 } |
| 2152 Label true_value, done; | 1922 Label true_value, done; |
| 2153 __ test(eax, Operand(eax)); | 1923 __ test(eax, Operand(eax)); |
| 2154 __ j(condition, &true_value, Label::kNear); | 1924 __ j(condition, &true_value, Label::kNear); |
| 2155 __ mov(ToRegister(instr->result()), factory()->false_value()); | 1925 __ mov(ToRegister(instr->result()), factory()->false_value()); |
| 2156 __ jmp(&done, Label::kNear); | 1926 __ jmp(&done, Label::kNear); |
| 2157 __ bind(&true_value); | 1927 __ bind(&true_value); |
| 2158 __ mov(ToRegister(instr->result()), factory()->true_value()); | 1928 __ mov(ToRegister(instr->result()), factory()->true_value()); |
| 2159 __ bind(&done); | 1929 __ bind(&done); |
| 2160 } | 1930 } |
| 2161 | 1931 |
| 2162 | 1932 |
| 2163 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { | |
| 2164 Token::Value op = instr->op(); | |
| 2165 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2166 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2167 | |
| 2168 Handle<Code> ic = CompareIC::GetUninitialized(op); | |
| 2169 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | |
| 2170 | |
| 2171 // The compare stub expects compare condition and the input operands | |
| 2172 // reversed for GT and LTE. | |
| 2173 Condition condition = ComputeCompareCondition(op); | |
| 2174 if (op == Token::GT || op == Token::LTE) { | |
| 2175 condition = ReverseCondition(condition); | |
| 2176 } | |
| 2177 __ test(eax, Operand(eax)); | |
| 2178 EmitBranch(true_block, false_block, condition); | |
| 2179 } | |
| 2180 | |
| 2181 | |
| 2182 void LCodeGen::DoReturn(LReturn* instr) { | 1933 void LCodeGen::DoReturn(LReturn* instr) { |
| 2183 if (FLAG_trace) { | 1934 if (FLAG_trace) { |
| 2184 // Preserve the return value on the stack and rely on the runtime call | 1935 // Preserve the return value on the stack and rely on the runtime call |
| 2185 // to return the value in the same register. We're leaving the code | 1936 // to return the value in the same register. We're leaving the code |
| 2186 // managed by the register allocator and tearing down the frame, it's | 1937 // managed by the register allocator and tearing down the frame, it's |
| 2187 // safe to write to the context register. | 1938 // safe to write to the context register. |
| 2188 __ push(eax); | 1939 __ push(eax); |
| 2189 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1940 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2190 __ CallRuntime(Runtime::kTraceExit, 1); | 1941 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2191 } | 1942 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2207 | 1958 |
| 2208 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { | 1959 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { |
| 2209 ASSERT(ToRegister(instr->context()).is(esi)); | 1960 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2210 ASSERT(ToRegister(instr->global_object()).is(eax)); | 1961 ASSERT(ToRegister(instr->global_object()).is(eax)); |
| 2211 ASSERT(ToRegister(instr->result()).is(eax)); | 1962 ASSERT(ToRegister(instr->result()).is(eax)); |
| 2212 | 1963 |
| 2213 __ mov(ecx, instr->name()); | 1964 __ mov(ecx, instr->name()); |
| 2214 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET : | 1965 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET : |
| 2215 RelocInfo::CODE_TARGET_CONTEXT; | 1966 RelocInfo::CODE_TARGET_CONTEXT; |
| 2216 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1967 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2217 CallCode(ic, mode, instr, CONTEXT_ADJUSTED); | 1968 CallCode(ic, mode, instr); |
| 2218 } | 1969 } |
| 2219 | 1970 |
| 2220 | 1971 |
| 2221 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { | 1972 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { |
| 2222 Register object = ToRegister(instr->TempAt(0)); | 1973 Register object = ToRegister(instr->TempAt(0)); |
| 2223 Register address = ToRegister(instr->TempAt(1)); | 1974 Register address = ToRegister(instr->TempAt(1)); |
| 2224 Register value = ToRegister(instr->InputAt(0)); | 1975 Register value = ToRegister(instr->InputAt(0)); |
| 2225 ASSERT(!value.is(object)); | 1976 ASSERT(!value.is(object)); |
| 2226 Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell()); | 1977 Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell()); |
| 2227 | 1978 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2252 | 2003 |
| 2253 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2004 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
| 2254 ASSERT(ToRegister(instr->context()).is(esi)); | 2005 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2255 ASSERT(ToRegister(instr->global_object()).is(edx)); | 2006 ASSERT(ToRegister(instr->global_object()).is(edx)); |
| 2256 ASSERT(ToRegister(instr->value()).is(eax)); | 2007 ASSERT(ToRegister(instr->value()).is(eax)); |
| 2257 | 2008 |
| 2258 __ mov(ecx, instr->name()); | 2009 __ mov(ecx, instr->name()); |
| 2259 Handle<Code> ic = instr->strict_mode() | 2010 Handle<Code> ic = instr->strict_mode() |
| 2260 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2011 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 2261 : isolate()->builtins()->StoreIC_Initialize(); | 2012 : isolate()->builtins()->StoreIC_Initialize(); |
| 2262 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr, CONTEXT_ADJUSTED); | 2013 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
| 2263 } | 2014 } |
| 2264 | 2015 |
| 2265 | 2016 |
| 2266 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2017 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2267 Register context = ToRegister(instr->context()); | 2018 Register context = ToRegister(instr->context()); |
| 2268 Register result = ToRegister(instr->result()); | 2019 Register result = ToRegister(instr->result()); |
| 2269 __ mov(result, ContextOperand(context, instr->slot_index())); | 2020 __ mov(result, ContextOperand(context, instr->slot_index())); |
| 2270 } | 2021 } |
| 2271 | 2022 |
| 2272 | 2023 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2324 void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { | 2075 void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { |
| 2325 Register object = ToRegister(instr->object()); | 2076 Register object = ToRegister(instr->object()); |
| 2326 Register result = ToRegister(instr->result()); | 2077 Register result = ToRegister(instr->result()); |
| 2327 | 2078 |
| 2328 int map_count = instr->hydrogen()->types()->length(); | 2079 int map_count = instr->hydrogen()->types()->length(); |
| 2329 Handle<String> name = instr->hydrogen()->name(); | 2080 Handle<String> name = instr->hydrogen()->name(); |
| 2330 if (map_count == 0) { | 2081 if (map_count == 0) { |
| 2331 ASSERT(instr->hydrogen()->need_generic()); | 2082 ASSERT(instr->hydrogen()->need_generic()); |
| 2332 __ mov(ecx, name); | 2083 __ mov(ecx, name); |
| 2333 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2084 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2334 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 2085 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2335 } else { | 2086 } else { |
| 2336 Label done; | 2087 Label done; |
| 2337 for (int i = 0; i < map_count - 1; ++i) { | 2088 for (int i = 0; i < map_count - 1; ++i) { |
| 2338 Handle<Map> map = instr->hydrogen()->types()->at(i); | 2089 Handle<Map> map = instr->hydrogen()->types()->at(i); |
| 2339 Label next; | 2090 Label next; |
| 2340 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); | 2091 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); |
| 2341 __ j(not_equal, &next, Label::kNear); | 2092 __ j(not_equal, &next, Label::kNear); |
| 2342 EmitLoadFieldOrConstantFunction(result, object, map, name); | 2093 EmitLoadFieldOrConstantFunction(result, object, map, name); |
| 2343 __ jmp(&done, Label::kNear); | 2094 __ jmp(&done, Label::kNear); |
| 2344 __ bind(&next); | 2095 __ bind(&next); |
| 2345 } | 2096 } |
| 2346 Handle<Map> map = instr->hydrogen()->types()->last(); | 2097 Handle<Map> map = instr->hydrogen()->types()->last(); |
| 2347 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); | 2098 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); |
| 2348 if (instr->hydrogen()->need_generic()) { | 2099 if (instr->hydrogen()->need_generic()) { |
| 2349 Label generic; | 2100 Label generic; |
| 2350 __ j(not_equal, &generic, Label::kNear); | 2101 __ j(not_equal, &generic, Label::kNear); |
| 2351 EmitLoadFieldOrConstantFunction(result, object, map, name); | 2102 EmitLoadFieldOrConstantFunction(result, object, map, name); |
| 2352 __ jmp(&done, Label::kNear); | 2103 __ jmp(&done, Label::kNear); |
| 2353 __ bind(&generic); | 2104 __ bind(&generic); |
| 2354 __ mov(ecx, name); | 2105 __ mov(ecx, name); |
| 2355 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2106 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2356 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 2107 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2357 } else { | 2108 } else { |
| 2358 DeoptimizeIf(not_equal, instr->environment()); | 2109 DeoptimizeIf(not_equal, instr->environment()); |
| 2359 EmitLoadFieldOrConstantFunction(result, object, map, name); | 2110 EmitLoadFieldOrConstantFunction(result, object, map, name); |
| 2360 } | 2111 } |
| 2361 __ bind(&done); | 2112 __ bind(&done); |
| 2362 } | 2113 } |
| 2363 } | 2114 } |
| 2364 | 2115 |
| 2365 | 2116 |
| 2366 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { | 2117 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { |
| 2367 ASSERT(ToRegister(instr->context()).is(esi)); | 2118 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2368 ASSERT(ToRegister(instr->object()).is(eax)); | 2119 ASSERT(ToRegister(instr->object()).is(eax)); |
| 2369 ASSERT(ToRegister(instr->result()).is(eax)); | 2120 ASSERT(ToRegister(instr->result()).is(eax)); |
| 2370 | 2121 |
| 2371 __ mov(ecx, instr->name()); | 2122 __ mov(ecx, instr->name()); |
| 2372 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2123 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2373 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 2124 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2374 } | 2125 } |
| 2375 | 2126 |
| 2376 | 2127 |
| 2377 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { | 2128 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { |
| 2378 Register function = ToRegister(instr->function()); | 2129 Register function = ToRegister(instr->function()); |
| 2379 Register temp = ToRegister(instr->TempAt(0)); | 2130 Register temp = ToRegister(instr->TempAt(0)); |
| 2380 Register result = ToRegister(instr->result()); | 2131 Register result = ToRegister(instr->result()); |
| 2381 | 2132 |
| 2382 // Check that the function really is a function. | 2133 // Check that the function really is a function. |
| 2383 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); | 2134 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2414 // All done. | 2165 // All done. |
| 2415 __ bind(&done); | 2166 __ bind(&done); |
| 2416 } | 2167 } |
| 2417 | 2168 |
| 2418 | 2169 |
| 2419 void LCodeGen::DoLoadElements(LLoadElements* instr) { | 2170 void LCodeGen::DoLoadElements(LLoadElements* instr) { |
| 2420 Register result = ToRegister(instr->result()); | 2171 Register result = ToRegister(instr->result()); |
| 2421 Register input = ToRegister(instr->InputAt(0)); | 2172 Register input = ToRegister(instr->InputAt(0)); |
| 2422 __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); | 2173 __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); |
| 2423 if (FLAG_debug_code) { | 2174 if (FLAG_debug_code) { |
| 2424 Label done; | 2175 Label done, ok, fail; |
| 2425 __ cmp(FieldOperand(result, HeapObject::kMapOffset), | 2176 __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
| 2426 Immediate(factory()->fixed_array_map())); | 2177 Immediate(factory()->fixed_array_map())); |
| 2427 __ j(equal, &done, Label::kNear); | 2178 __ j(equal, &done, Label::kNear); |
| 2428 __ cmp(FieldOperand(result, HeapObject::kMapOffset), | 2179 __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
| 2429 Immediate(factory()->fixed_cow_array_map())); | 2180 Immediate(factory()->fixed_cow_array_map())); |
| 2430 __ j(equal, &done, Label::kNear); | 2181 __ j(equal, &done, Label::kNear); |
| 2431 Register temp((result.is(eax)) ? ebx : eax); | 2182 Register temp((result.is(eax)) ? ebx : eax); |
| 2432 __ push(temp); | 2183 __ push(temp); |
| 2433 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset)); | 2184 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset)); |
| 2434 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 2185 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset)); |
| 2435 __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE)); | 2186 __ and_(temp, Map::kElementsKindMask); |
| 2436 __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount)); | 2187 __ shr(temp, Map::kElementsKindShift); |
| 2188 __ cmp(temp, JSObject::FAST_ELEMENTS); |
| 2189 __ j(equal, &ok, Label::kNear); |
| 2190 __ cmp(temp, JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 2191 __ j(less, &fail, Label::kNear); |
| 2192 __ cmp(temp, JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 2193 __ j(less_equal, &ok, Label::kNear); |
| 2194 __ bind(&fail); |
| 2195 __ Abort("Check for fast or external elements failed."); |
| 2196 __ bind(&ok); |
| 2437 __ pop(temp); | 2197 __ pop(temp); |
| 2438 __ Check(below, "Check for fast elements or pixel array failed."); | |
| 2439 __ bind(&done); | 2198 __ bind(&done); |
| 2440 } | 2199 } |
| 2441 } | 2200 } |
| 2442 | 2201 |
| 2443 | 2202 |
| 2444 void LCodeGen::DoLoadExternalArrayPointer( | 2203 void LCodeGen::DoLoadExternalArrayPointer( |
| 2445 LLoadExternalArrayPointer* instr) { | 2204 LLoadExternalArrayPointer* instr) { |
| 2446 Register result = ToRegister(instr->result()); | 2205 Register result = ToRegister(instr->result()); |
| 2447 Register input = ToRegister(instr->InputAt(0)); | 2206 Register input = ToRegister(instr->InputAt(0)); |
| 2448 __ mov(result, FieldOperand(input, | 2207 __ mov(result, FieldOperand(input, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2478 FixedArray::kHeaderSize)); | 2237 FixedArray::kHeaderSize)); |
| 2479 | 2238 |
| 2480 // Check for the hole value. | 2239 // Check for the hole value. |
| 2481 if (instr->hydrogen()->RequiresHoleCheck()) { | 2240 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2482 __ cmp(result, factory()->the_hole_value()); | 2241 __ cmp(result, factory()->the_hole_value()); |
| 2483 DeoptimizeIf(equal, instr->environment()); | 2242 DeoptimizeIf(equal, instr->environment()); |
| 2484 } | 2243 } |
| 2485 } | 2244 } |
| 2486 | 2245 |
| 2487 | 2246 |
| 2488 Operand LCodeGen::BuildExternalArrayOperand(LOperand* external_pointer, | 2247 Operand LCodeGen::BuildExternalArrayOperand( |
| 2489 LOperand* key, | 2248 LOperand* external_pointer, |
| 2490 ExternalArrayType array_type) { | 2249 LOperand* key, |
| 2250 JSObject::ElementsKind elements_kind) { |
| 2491 Register external_pointer_reg = ToRegister(external_pointer); | 2251 Register external_pointer_reg = ToRegister(external_pointer); |
| 2492 int shift_size = ExternalArrayTypeToShiftSize(array_type); | 2252 int shift_size = ElementsKindToShiftSize(elements_kind); |
| 2493 if (key->IsConstantOperand()) { | 2253 if (key->IsConstantOperand()) { |
| 2494 int constant_value = ToInteger32(LConstantOperand::cast(key)); | 2254 int constant_value = ToInteger32(LConstantOperand::cast(key)); |
| 2495 if (constant_value & 0xF0000000) { | 2255 if (constant_value & 0xF0000000) { |
| 2496 Abort("array index constant value too big"); | 2256 Abort("array index constant value too big"); |
| 2497 } | 2257 } |
| 2498 return Operand(external_pointer_reg, constant_value * (1 << shift_size)); | 2258 return Operand(external_pointer_reg, constant_value * (1 << shift_size)); |
| 2499 } else { | 2259 } else { |
| 2500 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); | 2260 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); |
| 2501 return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); | 2261 return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); |
| 2502 } | 2262 } |
| 2503 } | 2263 } |
| 2504 | 2264 |
| 2505 | 2265 |
| 2506 void LCodeGen::DoLoadKeyedSpecializedArrayElement( | 2266 void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
| 2507 LLoadKeyedSpecializedArrayElement* instr) { | 2267 LLoadKeyedSpecializedArrayElement* instr) { |
| 2508 ExternalArrayType array_type = instr->array_type(); | 2268 JSObject::ElementsKind elements_kind = instr->elements_kind(); |
| 2509 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), | 2269 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), |
| 2510 instr->key(), array_type)); | 2270 instr->key(), elements_kind)); |
| 2511 if (array_type == kExternalFloatArray) { | 2271 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 2512 XMMRegister result(ToDoubleRegister(instr->result())); | 2272 XMMRegister result(ToDoubleRegister(instr->result())); |
| 2513 __ movss(result, operand); | 2273 __ movss(result, operand); |
| 2514 __ cvtss2sd(result, result); | 2274 __ cvtss2sd(result, result); |
| 2515 } else if (array_type == kExternalDoubleArray) { | 2275 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 2516 __ movdbl(ToDoubleRegister(instr->result()), operand); | 2276 __ movdbl(ToDoubleRegister(instr->result()), operand); |
| 2517 } else { | 2277 } else { |
| 2518 Register result(ToRegister(instr->result())); | 2278 Register result(ToRegister(instr->result())); |
| 2519 switch (array_type) { | 2279 switch (elements_kind) { |
| 2520 case kExternalByteArray: | 2280 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 2521 __ movsx_b(result, operand); | 2281 __ movsx_b(result, operand); |
| 2522 break; | 2282 break; |
| 2523 case kExternalUnsignedByteArray: | 2283 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 2524 case kExternalPixelArray: | 2284 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 2525 __ movzx_b(result, operand); | 2285 __ movzx_b(result, operand); |
| 2526 break; | 2286 break; |
| 2527 case kExternalShortArray: | 2287 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 2528 __ movsx_w(result, operand); | 2288 __ movsx_w(result, operand); |
| 2529 break; | 2289 break; |
| 2530 case kExternalUnsignedShortArray: | 2290 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 2531 __ movzx_w(result, operand); | 2291 __ movzx_w(result, operand); |
| 2532 break; | 2292 break; |
| 2533 case kExternalIntArray: | 2293 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 2534 __ mov(result, operand); | 2294 __ mov(result, operand); |
| 2535 break; | 2295 break; |
| 2536 case kExternalUnsignedIntArray: | 2296 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 2537 __ mov(result, operand); | 2297 __ mov(result, operand); |
| 2538 __ test(result, Operand(result)); | 2298 __ test(result, Operand(result)); |
| 2539 // TODO(danno): we could be more clever here, perhaps having a special | 2299 // TODO(danno): we could be more clever here, perhaps having a special |
| 2540 // version of the stub that detects if the overflow case actually | 2300 // version of the stub that detects if the overflow case actually |
| 2541 // happens, and generate code that returns a double rather than int. | 2301 // happens, and generate code that returns a double rather than int. |
| 2542 DeoptimizeIf(negative, instr->environment()); | 2302 DeoptimizeIf(negative, instr->environment()); |
| 2543 break; | 2303 break; |
| 2544 case kExternalFloatArray: | 2304 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 2545 case kExternalDoubleArray: | 2305 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 2306 case JSObject::FAST_ELEMENTS: |
| 2307 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 2308 case JSObject::DICTIONARY_ELEMENTS: |
| 2309 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 2546 UNREACHABLE(); | 2310 UNREACHABLE(); |
| 2547 break; | 2311 break; |
| 2548 } | 2312 } |
| 2549 } | 2313 } |
| 2550 } | 2314 } |
| 2551 | 2315 |
| 2552 | 2316 |
| 2553 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2317 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| 2554 ASSERT(ToRegister(instr->context()).is(esi)); | 2318 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2555 ASSERT(ToRegister(instr->object()).is(edx)); | 2319 ASSERT(ToRegister(instr->object()).is(edx)); |
| 2556 ASSERT(ToRegister(instr->key()).is(eax)); | 2320 ASSERT(ToRegister(instr->key()).is(eax)); |
| 2557 | 2321 |
| 2558 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2322 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2559 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 2323 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2560 } | 2324 } |
| 2561 | 2325 |
| 2562 | 2326 |
| 2563 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { | 2327 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { |
| 2564 Register result = ToRegister(instr->result()); | 2328 Register result = ToRegister(instr->result()); |
| 2565 | 2329 |
| 2566 // Check for arguments adapter frame. | 2330 // Check for arguments adapter frame. |
| 2567 Label done, adapted; | 2331 Label done, adapted; |
| 2568 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 2332 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2569 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset)); | 2333 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2610 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 2374 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 2611 Register receiver = ToRegister(instr->receiver()); | 2375 Register receiver = ToRegister(instr->receiver()); |
| 2612 Register function = ToRegister(instr->function()); | 2376 Register function = ToRegister(instr->function()); |
| 2613 Register length = ToRegister(instr->length()); | 2377 Register length = ToRegister(instr->length()); |
| 2614 Register elements = ToRegister(instr->elements()); | 2378 Register elements = ToRegister(instr->elements()); |
| 2615 Register scratch = ToRegister(instr->TempAt(0)); | 2379 Register scratch = ToRegister(instr->TempAt(0)); |
| 2616 ASSERT(receiver.is(eax)); // Used for parameter count. | 2380 ASSERT(receiver.is(eax)); // Used for parameter count. |
| 2617 ASSERT(function.is(edi)); // Required by InvokeFunction. | 2381 ASSERT(function.is(edi)); // Required by InvokeFunction. |
| 2618 ASSERT(ToRegister(instr->result()).is(eax)); | 2382 ASSERT(ToRegister(instr->result()).is(eax)); |
| 2619 | 2383 |
| 2620 // If the receiver is null or undefined, we have to pass the global object | 2384 // If the receiver is null or undefined, we have to pass the global |
| 2621 // as a receiver. | 2385 // object as a receiver to normal functions. Values have to be |
| 2386 // passed unchanged to builtins and strict-mode functions. |
| 2622 Label global_object, receiver_ok; | 2387 Label global_object, receiver_ok; |
| 2388 |
| 2389 // Do not transform the receiver to object for strict mode |
| 2390 // functions. |
| 2391 __ mov(scratch, |
| 2392 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 2393 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), |
| 2394 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
| 2395 __ j(not_equal, &receiver_ok, Label::kNear); |
| 2396 |
| 2397 // Do not transform the receiver to object for builtins. |
| 2398 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), |
| 2399 1 << SharedFunctionInfo::kNativeBitWithinByte); |
| 2400 __ j(not_equal, &receiver_ok, Label::kNear); |
| 2401 |
| 2402 // Normal function. Replace undefined or null with global receiver. |
| 2623 __ cmp(receiver, factory()->null_value()); | 2403 __ cmp(receiver, factory()->null_value()); |
| 2624 __ j(equal, &global_object, Label::kNear); | 2404 __ j(equal, &global_object, Label::kNear); |
| 2625 __ cmp(receiver, factory()->undefined_value()); | 2405 __ cmp(receiver, factory()->undefined_value()); |
| 2626 __ j(equal, &global_object, Label::kNear); | 2406 __ j(equal, &global_object, Label::kNear); |
| 2627 | 2407 |
| 2628 // The receiver should be a JS object. | 2408 // The receiver should be a JS object. |
| 2629 __ test(receiver, Immediate(kSmiTagMask)); | 2409 __ test(receiver, Immediate(kSmiTagMask)); |
| 2630 DeoptimizeIf(equal, instr->environment()); | 2410 DeoptimizeIf(equal, instr->environment()); |
| 2631 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch); | 2411 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch); |
| 2632 DeoptimizeIf(below, instr->environment()); | 2412 DeoptimizeIf(below, instr->environment()); |
| 2633 __ jmp(&receiver_ok, Label::kNear); | 2413 __ jmp(&receiver_ok, Label::kNear); |
| 2634 | 2414 |
| 2635 __ bind(&global_object); | 2415 __ bind(&global_object); |
| 2636 // TODO(kmillikin): We have a hydrogen value for the global object. See | 2416 // TODO(kmillikin): We have a hydrogen value for the global object. See |
| 2637 // if it's better to use it than to explicitly fetch it from the context | 2417 // if it's better to use it than to explicitly fetch it from the context |
| 2638 // here. | 2418 // here. |
| 2639 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2419 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2640 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX)); | 2420 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX)); |
| 2421 __ mov(receiver, |
| 2422 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset)); |
| 2641 __ bind(&receiver_ok); | 2423 __ bind(&receiver_ok); |
| 2642 | 2424 |
| 2643 // Copy the arguments to this function possibly from the | 2425 // Copy the arguments to this function possibly from the |
| 2644 // adaptor frame below it. | 2426 // adaptor frame below it. |
| 2645 const uint32_t kArgumentsLimit = 1 * KB; | 2427 const uint32_t kArgumentsLimit = 1 * KB; |
| 2646 __ cmp(length, kArgumentsLimit); | 2428 __ cmp(length, kArgumentsLimit); |
| 2647 DeoptimizeIf(above, instr->environment()); | 2429 DeoptimizeIf(above, instr->environment()); |
| 2648 | 2430 |
| 2649 __ push(receiver); | 2431 __ push(receiver); |
| 2650 __ mov(receiver, length); | 2432 __ mov(receiver, length); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2664 __ bind(&invoke); | 2446 __ bind(&invoke); |
| 2665 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); | 2447 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 2666 LPointerMap* pointers = instr->pointer_map(); | 2448 LPointerMap* pointers = instr->pointer_map(); |
| 2667 LEnvironment* env = instr->deoptimization_environment(); | 2449 LEnvironment* env = instr->deoptimization_environment(); |
| 2668 RecordPosition(pointers->position()); | 2450 RecordPosition(pointers->position()); |
| 2669 RegisterEnvironmentForDeoptimization(env); | 2451 RegisterEnvironmentForDeoptimization(env); |
| 2670 SafepointGenerator safepoint_generator(this, | 2452 SafepointGenerator safepoint_generator(this, |
| 2671 pointers, | 2453 pointers, |
| 2672 env->deoptimization_index()); | 2454 env->deoptimization_index()); |
| 2673 ParameterCount actual(eax); | 2455 ParameterCount actual(eax); |
| 2674 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator); | 2456 __ InvokeFunction(function, actual, CALL_FUNCTION, |
| 2457 safepoint_generator, CALL_AS_METHOD); |
| 2675 } | 2458 } |
| 2676 | 2459 |
| 2677 | 2460 |
| 2678 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2461 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 2679 LOperand* argument = instr->InputAt(0); | 2462 LOperand* argument = instr->InputAt(0); |
| 2680 if (argument->IsConstantOperand()) { | 2463 if (argument->IsConstantOperand()) { |
| 2681 __ push(ToImmediate(argument)); | 2464 __ push(ToImmediate(argument)); |
| 2682 } else { | 2465 } else { |
| 2683 __ push(ToOperand(argument)); | 2466 __ push(ToOperand(argument)); |
| 2684 } | 2467 } |
| 2685 } | 2468 } |
| 2686 | 2469 |
| 2687 | 2470 |
| 2471 void LCodeGen::DoThisFunction(LThisFunction* instr) { |
| 2472 Register result = ToRegister(instr->result()); |
| 2473 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 2474 } |
| 2475 |
| 2476 |
| 2688 void LCodeGen::DoContext(LContext* instr) { | 2477 void LCodeGen::DoContext(LContext* instr) { |
| 2689 Register result = ToRegister(instr->result()); | 2478 Register result = ToRegister(instr->result()); |
| 2690 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2479 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2691 } | 2480 } |
| 2692 | 2481 |
| 2693 | 2482 |
| 2694 void LCodeGen::DoOuterContext(LOuterContext* instr) { | 2483 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
| 2695 Register context = ToRegister(instr->context()); | 2484 Register context = ToRegister(instr->context()); |
| 2696 Register result = ToRegister(instr->result()); | 2485 Register result = ToRegister(instr->result()); |
| 2697 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2486 __ mov(result, |
| 2698 __ mov(result, FieldOperand(result, JSFunction::kContextOffset)); | 2487 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 2699 } | 2488 } |
| 2700 | 2489 |
| 2701 | 2490 |
| 2702 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { | 2491 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
| 2703 Register context = ToRegister(instr->context()); | 2492 Register context = ToRegister(instr->context()); |
| 2704 Register result = ToRegister(instr->result()); | 2493 Register result = ToRegister(instr->result()); |
| 2705 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2494 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2706 } | 2495 } |
| 2707 | 2496 |
| 2708 | 2497 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2754 ASSERT(ToRegister(instr->result()).is(eax)); | 2543 ASSERT(ToRegister(instr->result()).is(eax)); |
| 2755 __ mov(edi, instr->function()); | 2544 __ mov(edi, instr->function()); |
| 2756 CallKnownFunction(instr->function(), | 2545 CallKnownFunction(instr->function(), |
| 2757 instr->arity(), | 2546 instr->arity(), |
| 2758 instr, | 2547 instr, |
| 2759 CALL_AS_METHOD); | 2548 CALL_AS_METHOD); |
| 2760 } | 2549 } |
| 2761 | 2550 |
| 2762 | 2551 |
| 2763 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { | 2552 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { |
| 2764 Register input_reg = ToRegister(instr->InputAt(0)); | 2553 Register input_reg = ToRegister(instr->value()); |
| 2765 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 2554 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 2766 factory()->heap_number_map()); | 2555 factory()->heap_number_map()); |
| 2767 DeoptimizeIf(not_equal, instr->environment()); | 2556 DeoptimizeIf(not_equal, instr->environment()); |
| 2768 | 2557 |
| 2769 Label done; | 2558 Label done; |
| 2770 Register tmp = input_reg.is(eax) ? ecx : eax; | 2559 Register tmp = input_reg.is(eax) ? ecx : eax; |
| 2771 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; | 2560 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; |
| 2772 | 2561 |
| 2773 // Preserve the value of all registers. | 2562 // Preserve the value of all registers. |
| 2774 PushSafepointRegistersScope scope(this); | 2563 PushSafepointRegistersScope scope(this); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2785 | 2574 |
| 2786 __ bind(&negative); | 2575 __ bind(&negative); |
| 2787 | 2576 |
| 2788 Label allocated, slow; | 2577 Label allocated, slow; |
| 2789 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow); | 2578 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow); |
| 2790 __ jmp(&allocated); | 2579 __ jmp(&allocated); |
| 2791 | 2580 |
| 2792 // Slow case: Call the runtime system to do the number allocation. | 2581 // Slow case: Call the runtime system to do the number allocation. |
| 2793 __ bind(&slow); | 2582 __ bind(&slow); |
| 2794 | 2583 |
| 2795 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); | 2584 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, |
| 2585 instr, instr->context()); |
| 2796 | 2586 |
| 2797 // Set the pointer to the new heap number in tmp. | 2587 // Set the pointer to the new heap number in tmp. |
| 2798 if (!tmp.is(eax)) __ mov(tmp, eax); | 2588 if (!tmp.is(eax)) __ mov(tmp, eax); |
| 2799 | 2589 |
| 2800 // Restore input_reg after call to runtime. | 2590 // Restore input_reg after call to runtime. |
| 2801 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); | 2591 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); |
| 2802 | 2592 |
| 2803 __ bind(&allocated); | 2593 __ bind(&allocated); |
| 2804 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | 2594 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 2805 __ and_(tmp2, ~HeapNumber::kSignMask); | 2595 __ and_(tmp2, ~HeapNumber::kSignMask); |
| 2806 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2); | 2596 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2); |
| 2807 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); | 2597 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); |
| 2808 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2); | 2598 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2); |
| 2809 __ StoreToSafepointRegisterSlot(input_reg, tmp); | 2599 __ StoreToSafepointRegisterSlot(input_reg, tmp); |
| 2810 | 2600 |
| 2811 __ bind(&done); | 2601 __ bind(&done); |
| 2812 } | 2602 } |
| 2813 | 2603 |
| 2814 | 2604 |
| 2815 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { | 2605 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| 2816 Register input_reg = ToRegister(instr->InputAt(0)); | 2606 Register input_reg = ToRegister(instr->value()); |
| 2817 __ test(input_reg, Operand(input_reg)); | 2607 __ test(input_reg, Operand(input_reg)); |
| 2818 Label is_positive; | 2608 Label is_positive; |
| 2819 __ j(not_sign, &is_positive); | 2609 __ j(not_sign, &is_positive); |
| 2820 __ neg(input_reg); | 2610 __ neg(input_reg); |
| 2821 __ test(input_reg, Operand(input_reg)); | 2611 __ test(input_reg, Operand(input_reg)); |
| 2822 DeoptimizeIf(negative, instr->environment()); | 2612 DeoptimizeIf(negative, instr->environment()); |
| 2823 __ bind(&is_positive); | 2613 __ bind(&is_positive); |
| 2824 } | 2614 } |
| 2825 | 2615 |
| 2826 | 2616 |
| 2827 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { | 2617 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| 2828 // Class for deferred case. | 2618 // Class for deferred case. |
| 2829 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { | 2619 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 2830 public: | 2620 public: |
| 2831 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, | 2621 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 2832 LUnaryMathOperation* instr) | 2622 LUnaryMathOperation* instr) |
| 2833 : LDeferredCode(codegen), instr_(instr) { } | 2623 : LDeferredCode(codegen), instr_(instr) { } |
| 2834 virtual void Generate() { | 2624 virtual void Generate() { |
| 2835 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); | 2625 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
| 2836 } | 2626 } |
| 2837 private: | 2627 private: |
| 2838 LUnaryMathOperation* instr_; | 2628 LUnaryMathOperation* instr_; |
| 2839 }; | 2629 }; |
| 2840 | 2630 |
| 2841 ASSERT(instr->InputAt(0)->Equals(instr->result())); | 2631 ASSERT(instr->value()->Equals(instr->result())); |
| 2842 Representation r = instr->hydrogen()->value()->representation(); | 2632 Representation r = instr->hydrogen()->value()->representation(); |
| 2843 | 2633 |
| 2844 if (r.IsDouble()) { | 2634 if (r.IsDouble()) { |
| 2845 XMMRegister scratch = xmm0; | 2635 XMMRegister scratch = xmm0; |
| 2846 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2636 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 2847 __ xorps(scratch, scratch); | 2637 __ xorps(scratch, scratch); |
| 2848 __ subsd(scratch, input_reg); | 2638 __ subsd(scratch, input_reg); |
| 2849 __ pand(input_reg, scratch); | 2639 __ pand(input_reg, scratch); |
| 2850 } else if (r.IsInteger32()) { | 2640 } else if (r.IsInteger32()) { |
| 2851 EmitIntegerMathAbs(instr); | 2641 EmitIntegerMathAbs(instr); |
| 2852 } else { // Tagged case. | 2642 } else { // Tagged case. |
| 2853 DeferredMathAbsTaggedHeapNumber* deferred = | 2643 DeferredMathAbsTaggedHeapNumber* deferred = |
| 2854 new DeferredMathAbsTaggedHeapNumber(this, instr); | 2644 new DeferredMathAbsTaggedHeapNumber(this, instr); |
| 2855 Register input_reg = ToRegister(instr->InputAt(0)); | 2645 Register input_reg = ToRegister(instr->value()); |
| 2856 // Smi check. | 2646 // Smi check. |
| 2857 __ test(input_reg, Immediate(kSmiTagMask)); | 2647 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 2858 __ j(not_zero, deferred->entry()); | |
| 2859 EmitIntegerMathAbs(instr); | 2648 EmitIntegerMathAbs(instr); |
| 2860 __ bind(deferred->exit()); | 2649 __ bind(deferred->exit()); |
| 2861 } | 2650 } |
| 2862 } | 2651 } |
| 2863 | 2652 |
| 2864 | 2653 |
| 2865 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { | 2654 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| 2866 XMMRegister xmm_scratch = xmm0; | 2655 XMMRegister xmm_scratch = xmm0; |
| 2867 Register output_reg = ToRegister(instr->result()); | 2656 Register output_reg = ToRegister(instr->result()); |
| 2868 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2657 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 2869 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. | 2658 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. |
| 2870 __ ucomisd(input_reg, xmm_scratch); | 2659 __ ucomisd(input_reg, xmm_scratch); |
| 2871 | 2660 |
| 2872 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 2661 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 2873 DeoptimizeIf(below_equal, instr->environment()); | 2662 DeoptimizeIf(below_equal, instr->environment()); |
| 2874 } else { | 2663 } else { |
| 2875 DeoptimizeIf(below, instr->environment()); | 2664 DeoptimizeIf(below, instr->environment()); |
| 2876 } | 2665 } |
| 2877 | 2666 |
| 2878 // Use truncating instruction (OK because input is positive). | 2667 // Use truncating instruction (OK because input is positive). |
| 2879 __ cvttsd2si(output_reg, Operand(input_reg)); | 2668 __ cvttsd2si(output_reg, Operand(input_reg)); |
| 2880 | 2669 |
| 2881 // Overflow is signalled with minint. | 2670 // Overflow is signalled with minint. |
| 2882 __ cmp(output_reg, 0x80000000u); | 2671 __ cmp(output_reg, 0x80000000u); |
| 2883 DeoptimizeIf(equal, instr->environment()); | 2672 DeoptimizeIf(equal, instr->environment()); |
| 2884 } | 2673 } |
| 2885 | 2674 |
| 2886 | 2675 |
| 2887 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { | 2676 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
| 2888 XMMRegister xmm_scratch = xmm0; | 2677 XMMRegister xmm_scratch = xmm0; |
| 2889 Register output_reg = ToRegister(instr->result()); | 2678 Register output_reg = ToRegister(instr->result()); |
| 2890 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2679 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 2891 | 2680 |
| 2892 Label below_half, done; | 2681 Label below_half, done; |
| 2893 // xmm_scratch = 0.5 | 2682 // xmm_scratch = 0.5 |
| 2894 ExternalReference one_half = ExternalReference::address_of_one_half(); | 2683 ExternalReference one_half = ExternalReference::address_of_one_half(); |
| 2895 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half)); | 2684 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half)); |
| 2896 | 2685 |
| 2897 __ ucomisd(xmm_scratch, input_reg); | 2686 __ ucomisd(xmm_scratch, input_reg); |
| 2898 __ j(above, &below_half); | 2687 __ j(above, &below_half); |
| 2899 // input = input + 0.5 | 2688 // input = input + 0.5 |
| 2900 __ addsd(input_reg, xmm_scratch); | 2689 __ addsd(input_reg, xmm_scratch); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2925 __ cvtss2sd(xmm_scratch, xmm_scratch); | 2714 __ cvtss2sd(xmm_scratch, xmm_scratch); |
| 2926 __ ucomisd(input_reg, xmm_scratch); | 2715 __ ucomisd(input_reg, xmm_scratch); |
| 2927 DeoptimizeIf(below, instr->environment()); | 2716 DeoptimizeIf(below, instr->environment()); |
| 2928 } | 2717 } |
| 2929 __ Set(output_reg, Immediate(0)); | 2718 __ Set(output_reg, Immediate(0)); |
| 2930 __ bind(&done); | 2719 __ bind(&done); |
| 2931 } | 2720 } |
| 2932 | 2721 |
| 2933 | 2722 |
| 2934 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { | 2723 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
| 2935 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2724 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 2936 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); | 2725 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2937 __ sqrtsd(input_reg, input_reg); | 2726 __ sqrtsd(input_reg, input_reg); |
| 2938 } | 2727 } |
| 2939 | 2728 |
| 2940 | 2729 |
| 2941 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { | 2730 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| 2942 XMMRegister xmm_scratch = xmm0; | 2731 XMMRegister xmm_scratch = xmm0; |
| 2943 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2732 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 2944 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); | 2733 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2945 __ xorps(xmm_scratch, xmm_scratch); | 2734 __ xorps(xmm_scratch, xmm_scratch); |
| 2946 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. | 2735 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. |
| 2947 __ sqrtsd(input_reg, input_reg); | 2736 __ sqrtsd(input_reg, input_reg); |
| 2948 } | 2737 } |
| 2949 | 2738 |
| 2950 | 2739 |
| 2951 void LCodeGen::DoPower(LPower* instr) { | 2740 void LCodeGen::DoPower(LPower* instr) { |
| 2952 LOperand* left = instr->InputAt(0); | 2741 LOperand* left = instr->InputAt(0); |
| 2953 LOperand* right = instr->InputAt(1); | 2742 LOperand* right = instr->InputAt(1); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2970 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); | 2759 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); |
| 2971 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right)); | 2760 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right)); |
| 2972 __ CallCFunction(ExternalReference::power_double_int_function(isolate()), | 2761 __ CallCFunction(ExternalReference::power_double_int_function(isolate()), |
| 2973 4); | 2762 4); |
| 2974 } else { | 2763 } else { |
| 2975 ASSERT(exponent_type.IsTagged()); | 2764 ASSERT(exponent_type.IsTagged()); |
| 2976 CpuFeatures::Scope scope(SSE2); | 2765 CpuFeatures::Scope scope(SSE2); |
| 2977 Register right_reg = ToRegister(right); | 2766 Register right_reg = ToRegister(right); |
| 2978 | 2767 |
| 2979 Label non_smi, call; | 2768 Label non_smi, call; |
| 2980 __ test(right_reg, Immediate(kSmiTagMask)); | 2769 __ JumpIfNotSmi(right_reg, &non_smi); |
| 2981 __ j(not_zero, &non_smi); | |
| 2982 __ SmiUntag(right_reg); | 2770 __ SmiUntag(right_reg); |
| 2983 __ cvtsi2sd(result_reg, Operand(right_reg)); | 2771 __ cvtsi2sd(result_reg, Operand(right_reg)); |
| 2984 __ jmp(&call); | 2772 __ jmp(&call); |
| 2985 | 2773 |
| 2986 __ bind(&non_smi); | 2774 __ bind(&non_smi); |
| 2987 // It is safe to use ebx directly since the instruction is marked | 2775 // It is safe to use ebx directly since the instruction is marked |
| 2988 // as a call. | 2776 // as a call. |
| 2989 ASSERT(!right_reg.is(ebx)); | 2777 ASSERT(!right_reg.is(ebx)); |
| 2990 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx); | 2778 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx); |
| 2991 DeoptimizeIf(not_equal, instr->environment()); | 2779 DeoptimizeIf(not_equal, instr->environment()); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3002 // Return value is in st(0) on ia32. | 2790 // Return value is in st(0) on ia32. |
| 3003 // Store it into the (fixed) result register. | 2791 // Store it into the (fixed) result register. |
| 3004 __ sub(Operand(esp), Immediate(kDoubleSize)); | 2792 __ sub(Operand(esp), Immediate(kDoubleSize)); |
| 3005 __ fstp_d(Operand(esp, 0)); | 2793 __ fstp_d(Operand(esp, 0)); |
| 3006 __ movdbl(result_reg, Operand(esp, 0)); | 2794 __ movdbl(result_reg, Operand(esp, 0)); |
| 3007 __ add(Operand(esp), Immediate(kDoubleSize)); | 2795 __ add(Operand(esp), Immediate(kDoubleSize)); |
| 3008 } | 2796 } |
| 3009 | 2797 |
| 3010 | 2798 |
| 3011 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { | 2799 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
| 3012 ASSERT(instr->InputAt(0)->Equals(instr->result())); | 2800 ASSERT(instr->value()->Equals(instr->result())); |
| 3013 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2801 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3014 Label positive, done, zero; | 2802 Label positive, done, zero; |
| 3015 __ xorps(xmm0, xmm0); | 2803 __ xorps(xmm0, xmm0); |
| 3016 __ ucomisd(input_reg, xmm0); | 2804 __ ucomisd(input_reg, xmm0); |
| 3017 __ j(above, &positive, Label::kNear); | 2805 __ j(above, &positive, Label::kNear); |
| 3018 __ j(equal, &zero, Label::kNear); | 2806 __ j(equal, &zero, Label::kNear); |
| 3019 ExternalReference nan = ExternalReference::address_of_nan(); | 2807 ExternalReference nan = ExternalReference::address_of_nan(); |
| 3020 __ movdbl(input_reg, Operand::StaticVariable(nan)); | 2808 __ movdbl(input_reg, Operand::StaticVariable(nan)); |
| 3021 __ jmp(&done, Label::kNear); | 2809 __ jmp(&done, Label::kNear); |
| 3022 __ bind(&zero); | 2810 __ bind(&zero); |
| 3023 __ push(Immediate(0xFFF00000)); | 2811 __ push(Immediate(0xFFF00000)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3035 __ movdbl(input_reg, Operand(esp, 0)); | 2823 __ movdbl(input_reg, Operand(esp, 0)); |
| 3036 __ add(Operand(esp), Immediate(kDoubleSize)); | 2824 __ add(Operand(esp), Immediate(kDoubleSize)); |
| 3037 __ bind(&done); | 2825 __ bind(&done); |
| 3038 } | 2826 } |
| 3039 | 2827 |
| 3040 | 2828 |
| 3041 void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { | 2829 void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { |
| 3042 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); | 2830 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
| 3043 TranscendentalCacheStub stub(TranscendentalCache::COS, | 2831 TranscendentalCacheStub stub(TranscendentalCache::COS, |
| 3044 TranscendentalCacheStub::UNTAGGED); | 2832 TranscendentalCacheStub::UNTAGGED); |
| 3045 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 2833 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3046 } | 2834 } |
| 3047 | 2835 |
| 3048 | 2836 |
| 3049 void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { | 2837 void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { |
| 3050 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); | 2838 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
| 3051 TranscendentalCacheStub stub(TranscendentalCache::SIN, | 2839 TranscendentalCacheStub stub(TranscendentalCache::SIN, |
| 3052 TranscendentalCacheStub::UNTAGGED); | 2840 TranscendentalCacheStub::UNTAGGED); |
| 3053 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 2841 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3054 } | 2842 } |
| 3055 | 2843 |
| 3056 | 2844 |
| 3057 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { | 2845 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { |
| 3058 switch (instr->op()) { | 2846 switch (instr->op()) { |
| 3059 case kMathAbs: | 2847 case kMathAbs: |
| 3060 DoMathAbs(instr); | 2848 DoMathAbs(instr); |
| 3061 break; | 2849 break; |
| 3062 case kMathFloor: | 2850 case kMathFloor: |
| 3063 DoMathFloor(instr); | 2851 DoMathFloor(instr); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3091 ASSERT(ToRegister(instr->context()).is(esi)); | 2879 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3092 ASSERT(ToRegister(instr->function()).is(edi)); | 2880 ASSERT(ToRegister(instr->function()).is(edi)); |
| 3093 ASSERT(instr->HasPointerMap()); | 2881 ASSERT(instr->HasPointerMap()); |
| 3094 ASSERT(instr->HasDeoptimizationEnvironment()); | 2882 ASSERT(instr->HasDeoptimizationEnvironment()); |
| 3095 LPointerMap* pointers = instr->pointer_map(); | 2883 LPointerMap* pointers = instr->pointer_map(); |
| 3096 LEnvironment* env = instr->deoptimization_environment(); | 2884 LEnvironment* env = instr->deoptimization_environment(); |
| 3097 RecordPosition(pointers->position()); | 2885 RecordPosition(pointers->position()); |
| 3098 RegisterEnvironmentForDeoptimization(env); | 2886 RegisterEnvironmentForDeoptimization(env); |
| 3099 SafepointGenerator generator(this, pointers, env->deoptimization_index()); | 2887 SafepointGenerator generator(this, pointers, env->deoptimization_index()); |
| 3100 ParameterCount count(instr->arity()); | 2888 ParameterCount count(instr->arity()); |
| 3101 __ InvokeFunction(edi, count, CALL_FUNCTION, generator); | 2889 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); |
| 3102 } | 2890 } |
| 3103 | 2891 |
| 3104 | 2892 |
| 3105 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { | 2893 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { |
| 3106 ASSERT(ToRegister(instr->context()).is(esi)); | 2894 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3107 ASSERT(ToRegister(instr->key()).is(ecx)); | 2895 ASSERT(ToRegister(instr->key()).is(ecx)); |
| 3108 ASSERT(ToRegister(instr->result()).is(eax)); | 2896 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3109 | 2897 |
| 3110 int arity = instr->arity(); | 2898 int arity = instr->arity(); |
| 3111 Handle<Code> ic = isolate()->stub_cache()-> | 2899 Handle<Code> ic = isolate()->stub_cache()-> |
| 3112 ComputeKeyedCallInitialize(arity, NOT_IN_LOOP); | 2900 ComputeKeyedCallInitialize(arity, NOT_IN_LOOP); |
| 3113 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 2901 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3114 } | 2902 } |
| 3115 | 2903 |
| 3116 | 2904 |
| 3117 void LCodeGen::DoCallNamed(LCallNamed* instr) { | 2905 void LCodeGen::DoCallNamed(LCallNamed* instr) { |
| 3118 ASSERT(ToRegister(instr->context()).is(esi)); | 2906 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3119 ASSERT(ToRegister(instr->result()).is(eax)); | 2907 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3120 | 2908 |
| 3121 int arity = instr->arity(); | 2909 int arity = instr->arity(); |
| 3122 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; | 2910 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; |
| 3123 Handle<Code> ic = | 2911 Handle<Code> ic = |
| 3124 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode); | 2912 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode); |
| 3125 __ mov(ecx, instr->name()); | 2913 __ mov(ecx, instr->name()); |
| 3126 CallCode(ic, mode, instr, CONTEXT_ADJUSTED); | 2914 CallCode(ic, mode, instr); |
| 3127 } | 2915 } |
| 3128 | 2916 |
| 3129 | 2917 |
| 3130 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 2918 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 3131 ASSERT(ToRegister(instr->context()).is(esi)); | 2919 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3132 ASSERT(ToRegister(instr->result()).is(eax)); | 2920 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3133 | 2921 |
| 3134 int arity = instr->arity(); | 2922 int arity = instr->arity(); |
| 3135 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT); | 2923 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT); |
| 3136 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 2924 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3137 __ Drop(1); | 2925 __ Drop(1); |
| 3138 } | 2926 } |
| 3139 | 2927 |
| 3140 | 2928 |
| 3141 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 2929 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 3142 ASSERT(ToRegister(instr->context()).is(esi)); | 2930 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3143 ASSERT(ToRegister(instr->result()).is(eax)); | 2931 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3144 | 2932 |
| 3145 int arity = instr->arity(); | 2933 int arity = instr->arity(); |
| 3146 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; | 2934 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; |
| 3147 Handle<Code> ic = | 2935 Handle<Code> ic = |
| 3148 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode); | 2936 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode); |
| 3149 __ mov(ecx, instr->name()); | 2937 __ mov(ecx, instr->name()); |
| 3150 CallCode(ic, mode, instr, CONTEXT_ADJUSTED); | 2938 CallCode(ic, mode, instr); |
| 3151 } | 2939 } |
| 3152 | 2940 |
| 3153 | 2941 |
| 3154 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { | 2942 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { |
| 3155 ASSERT(ToRegister(instr->result()).is(eax)); | 2943 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3156 __ mov(edi, instr->target()); | 2944 __ mov(edi, instr->target()); |
| 3157 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); | 2945 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); |
| 3158 } | 2946 } |
| 3159 | 2947 |
| 3160 | 2948 |
| 3161 void LCodeGen::DoCallNew(LCallNew* instr) { | 2949 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 3162 ASSERT(ToRegister(instr->context()).is(esi)); | 2950 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3163 ASSERT(ToRegister(instr->constructor()).is(edi)); | 2951 ASSERT(ToRegister(instr->constructor()).is(edi)); |
| 3164 ASSERT(ToRegister(instr->result()).is(eax)); | 2952 ASSERT(ToRegister(instr->result()).is(eax)); |
| 3165 | 2953 |
| 3166 Handle<Code> builtin = isolate()->builtins()->JSConstructCall(); | 2954 Handle<Code> builtin = isolate()->builtins()->JSConstructCall(); |
| 3167 __ Set(eax, Immediate(instr->arity())); | 2955 __ Set(eax, Immediate(instr->arity())); |
| 3168 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr, CONTEXT_ADJUSTED); | 2956 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); |
| 3169 } | 2957 } |
| 3170 | 2958 |
| 3171 | 2959 |
| 3172 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { | 2960 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { |
| 3173 CallRuntime(instr->function(), instr->arity(), instr, RESTORE_CONTEXT); | 2961 CallRuntime(instr->function(), instr->arity(), instr); |
| 3174 } | 2962 } |
| 3175 | 2963 |
| 3176 | 2964 |
| 3177 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { | 2965 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { |
| 3178 Register object = ToRegister(instr->object()); | 2966 Register object = ToRegister(instr->object()); |
| 3179 Register value = ToRegister(instr->value()); | 2967 Register value = ToRegister(instr->value()); |
| 3180 int offset = instr->offset(); | 2968 int offset = instr->offset(); |
| 3181 | 2969 |
| 3182 if (!instr->transition().is_null()) { | 2970 if (!instr->transition().is_null()) { |
| 3183 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); | 2971 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3206 | 2994 |
| 3207 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 2995 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 3208 ASSERT(ToRegister(instr->context()).is(esi)); | 2996 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3209 ASSERT(ToRegister(instr->object()).is(edx)); | 2997 ASSERT(ToRegister(instr->object()).is(edx)); |
| 3210 ASSERT(ToRegister(instr->value()).is(eax)); | 2998 ASSERT(ToRegister(instr->value()).is(eax)); |
| 3211 | 2999 |
| 3212 __ mov(ecx, instr->name()); | 3000 __ mov(ecx, instr->name()); |
| 3213 Handle<Code> ic = instr->strict_mode() | 3001 Handle<Code> ic = instr->strict_mode() |
| 3214 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 3002 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 3215 : isolate()->builtins()->StoreIC_Initialize(); | 3003 : isolate()->builtins()->StoreIC_Initialize(); |
| 3216 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 3004 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3217 } | 3005 } |
| 3218 | 3006 |
| 3219 | 3007 |
| 3220 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { | 3008 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| 3221 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); | 3009 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); |
| 3222 DeoptimizeIf(above_equal, instr->environment()); | 3010 DeoptimizeIf(above_equal, instr->environment()); |
| 3223 } | 3011 } |
| 3224 | 3012 |
| 3225 | 3013 |
| 3226 void LCodeGen::DoStoreKeyedSpecializedArrayElement( | 3014 void LCodeGen::DoStoreKeyedSpecializedArrayElement( |
| 3227 LStoreKeyedSpecializedArrayElement* instr) { | 3015 LStoreKeyedSpecializedArrayElement* instr) { |
| 3228 ExternalArrayType array_type = instr->array_type(); | 3016 JSObject::ElementsKind elements_kind = instr->elements_kind(); |
| 3229 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), | 3017 Operand operand(BuildExternalArrayOperand(instr->external_pointer(), |
| 3230 instr->key(), array_type)); | 3018 instr->key(), elements_kind)); |
| 3231 if (array_type == kExternalFloatArray) { | 3019 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { |
| 3232 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); | 3020 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); |
| 3233 __ movss(operand, xmm0); | 3021 __ movss(operand, xmm0); |
| 3234 } else if (array_type == kExternalDoubleArray) { | 3022 } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { |
| 3235 __ movdbl(operand, ToDoubleRegister(instr->value())); | 3023 __ movdbl(operand, ToDoubleRegister(instr->value())); |
| 3236 } else { | 3024 } else { |
| 3237 Register value = ToRegister(instr->value()); | 3025 Register value = ToRegister(instr->value()); |
| 3238 switch (array_type) { | 3026 switch (elements_kind) { |
| 3239 case kExternalPixelArray: | 3027 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 3240 case kExternalByteArray: | 3028 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3241 case kExternalUnsignedByteArray: | 3029 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 3242 __ mov_b(operand, value); | 3030 __ mov_b(operand, value); |
| 3243 break; | 3031 break; |
| 3244 case kExternalShortArray: | 3032 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 3245 case kExternalUnsignedShortArray: | 3033 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3246 __ mov_w(operand, value); | 3034 __ mov_w(operand, value); |
| 3247 break; | 3035 break; |
| 3248 case kExternalIntArray: | 3036 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 3249 case kExternalUnsignedIntArray: | 3037 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3250 __ mov(operand, value); | 3038 __ mov(operand, value); |
| 3251 break; | 3039 break; |
| 3252 case kExternalFloatArray: | 3040 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 3253 case kExternalDoubleArray: | 3041 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 3042 case JSObject::FAST_ELEMENTS: |
| 3043 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 3044 case JSObject::DICTIONARY_ELEMENTS: |
| 3045 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3254 UNREACHABLE(); | 3046 UNREACHABLE(); |
| 3255 break; | 3047 break; |
| 3256 } | 3048 } |
| 3257 } | 3049 } |
| 3258 } | 3050 } |
| 3259 | 3051 |
| 3260 | 3052 |
| 3261 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { | 3053 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { |
| 3262 Register value = ToRegister(instr->value()); | 3054 Register value = ToRegister(instr->value()); |
| 3263 Register elements = ToRegister(instr->object()); | 3055 Register elements = ToRegister(instr->object()); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3292 | 3084 |
| 3293 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 3085 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 3294 ASSERT(ToRegister(instr->context()).is(esi)); | 3086 ASSERT(ToRegister(instr->context()).is(esi)); |
| 3295 ASSERT(ToRegister(instr->object()).is(edx)); | 3087 ASSERT(ToRegister(instr->object()).is(edx)); |
| 3296 ASSERT(ToRegister(instr->key()).is(ecx)); | 3088 ASSERT(ToRegister(instr->key()).is(ecx)); |
| 3297 ASSERT(ToRegister(instr->value()).is(eax)); | 3089 ASSERT(ToRegister(instr->value()).is(eax)); |
| 3298 | 3090 |
| 3299 Handle<Code> ic = instr->strict_mode() | 3091 Handle<Code> ic = instr->strict_mode() |
| 3300 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3092 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 3301 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3093 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 3302 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); | 3094 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3303 } | 3095 } |
| 3304 | 3096 |
| 3305 | 3097 |
| 3306 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 3098 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 3307 class DeferredStringCharCodeAt: public LDeferredCode { | 3099 class DeferredStringCharCodeAt: public LDeferredCode { |
| 3308 public: | 3100 public: |
| 3309 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 3101 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 3310 : LDeferredCode(codegen), instr_(instr) { } | 3102 : LDeferredCode(codegen), instr_(instr) { } |
| 3311 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 3103 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| 3312 private: | 3104 private: |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3423 // DoStringCharCodeAt above. | 3215 // DoStringCharCodeAt above. |
| 3424 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | 3216 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 3425 if (instr->index()->IsConstantOperand()) { | 3217 if (instr->index()->IsConstantOperand()) { |
| 3426 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); | 3218 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 3427 __ push(Immediate(Smi::FromInt(const_index))); | 3219 __ push(Immediate(Smi::FromInt(const_index))); |
| 3428 } else { | 3220 } else { |
| 3429 Register index = ToRegister(instr->index()); | 3221 Register index = ToRegister(instr->index()); |
| 3430 __ SmiTag(index); | 3222 __ SmiTag(index); |
| 3431 __ push(index); | 3223 __ push(index); |
| 3432 } | 3224 } |
| 3433 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); | 3225 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, |
| 3226 instr, instr->context()); |
| 3434 if (FLAG_debug_code) { | 3227 if (FLAG_debug_code) { |
| 3435 __ AbortIfNotSmi(eax); | 3228 __ AbortIfNotSmi(eax); |
| 3436 } | 3229 } |
| 3437 __ SmiUntag(eax); | 3230 __ SmiUntag(eax); |
| 3438 __ StoreToSafepointRegisterSlot(result, eax); | 3231 __ StoreToSafepointRegisterSlot(result, eax); |
| 3439 } | 3232 } |
| 3440 | 3233 |
| 3441 | 3234 |
| 3442 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { | 3235 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3443 class DeferredStringCharFromCode: public LDeferredCode { | 3236 class DeferredStringCharFromCode: public LDeferredCode { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3474 Register result = ToRegister(instr->result()); | 3267 Register result = ToRegister(instr->result()); |
| 3475 | 3268 |
| 3476 // TODO(3095996): Get rid of this. For now, we need to make the | 3269 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3477 // result register contain a valid pointer because it is already | 3270 // result register contain a valid pointer because it is already |
| 3478 // contained in the register pointer map. | 3271 // contained in the register pointer map. |
| 3479 __ Set(result, Immediate(0)); | 3272 __ Set(result, Immediate(0)); |
| 3480 | 3273 |
| 3481 PushSafepointRegistersScope scope(this); | 3274 PushSafepointRegistersScope scope(this); |
| 3482 __ SmiTag(char_code); | 3275 __ SmiTag(char_code); |
| 3483 __ push(char_code); | 3276 __ push(char_code); |
| 3484 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr); | 3277 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context()); |
| 3485 __ StoreToSafepointRegisterSlot(result, eax); | 3278 __ StoreToSafepointRegisterSlot(result, eax); |
| 3486 } | 3279 } |
| 3487 | 3280 |
| 3488 | 3281 |
| 3489 void LCodeGen::DoStringLength(LStringLength* instr) { | 3282 void LCodeGen::DoStringLength(LStringLength* instr) { |
| 3490 Register string = ToRegister(instr->string()); | 3283 Register string = ToRegister(instr->string()); |
| 3491 Register result = ToRegister(instr->result()); | 3284 Register result = ToRegister(instr->result()); |
| 3492 __ mov(result, FieldOperand(string, String::kLengthOffset)); | 3285 __ mov(result, FieldOperand(string, String::kLengthOffset)); |
| 3493 } | 3286 } |
| 3494 | 3287 |
| 3495 | 3288 |
| 3496 void LCodeGen::DoStringAdd(LStringAdd* instr) { | 3289 void LCodeGen::DoStringAdd(LStringAdd* instr) { |
| 3497 if (instr->left()->IsConstantOperand()) { | 3290 if (instr->left()->IsConstantOperand()) { |
| 3498 __ push(ToImmediate(instr->left())); | 3291 __ push(ToImmediate(instr->left())); |
| 3499 } else { | 3292 } else { |
| 3500 __ push(ToOperand(instr->left())); | 3293 __ push(ToOperand(instr->left())); |
| 3501 } | 3294 } |
| 3502 if (instr->right()->IsConstantOperand()) { | 3295 if (instr->right()->IsConstantOperand()) { |
| 3503 __ push(ToImmediate(instr->right())); | 3296 __ push(ToImmediate(instr->right())); |
| 3504 } else { | 3297 } else { |
| 3505 __ push(ToOperand(instr->right())); | 3298 __ push(ToOperand(instr->right())); |
| 3506 } | 3299 } |
| 3507 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | 3300 StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
| 3508 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 3301 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3509 } | 3302 } |
| 3510 | 3303 |
| 3511 | 3304 |
| 3512 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 3305 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| 3513 LOperand* input = instr->InputAt(0); | 3306 LOperand* input = instr->InputAt(0); |
| 3514 ASSERT(input->IsRegister() || input->IsStackSlot()); | 3307 ASSERT(input->IsRegister() || input->IsStackSlot()); |
| 3515 LOperand* output = instr->result(); | 3308 LOperand* output = instr->result(); |
| 3516 ASSERT(output->IsDoubleRegister()); | 3309 ASSERT(output->IsDoubleRegister()); |
| 3517 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input)); | 3310 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input)); |
| 3518 } | 3311 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3559 __ jmp(&done, Label::kNear); | 3352 __ jmp(&done, Label::kNear); |
| 3560 } | 3353 } |
| 3561 | 3354 |
| 3562 // Slow case: Call the runtime system to do the number allocation. | 3355 // Slow case: Call the runtime system to do the number allocation. |
| 3563 __ bind(&slow); | 3356 __ bind(&slow); |
| 3564 | 3357 |
| 3565 // TODO(3095996): Put a valid pointer value in the stack slot where the result | 3358 // TODO(3095996): Put a valid pointer value in the stack slot where the result |
| 3566 // register is stored, as this register is in the pointer map, but contains an | 3359 // register is stored, as this register is in the pointer map, but contains an |
| 3567 // integer value. | 3360 // integer value. |
| 3568 __ StoreToSafepointRegisterSlot(reg, Immediate(0)); | 3361 __ StoreToSafepointRegisterSlot(reg, Immediate(0)); |
| 3569 | 3362 // NumberTagI and NumberTagD use the context from the frame, rather than |
| 3570 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); | 3363 // the environment's HContext or HInlinedContext value. |
| 3364 // They only call Runtime::kAllocateHeapNumber. |
| 3365 // The corresponding HChange instructions are added in a phase that does |
| 3366 // not have easy access to the local context. |
| 3367 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3368 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 3369 RecordSafepointWithRegisters( |
| 3370 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 3571 if (!reg.is(eax)) __ mov(reg, eax); | 3371 if (!reg.is(eax)) __ mov(reg, eax); |
| 3572 | 3372 |
| 3573 // Done. Put the value in xmm0 into the value of the allocated heap | 3373 // Done. Put the value in xmm0 into the value of the allocated heap |
| 3574 // number. | 3374 // number. |
| 3575 __ bind(&done); | 3375 __ bind(&done); |
| 3576 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); | 3376 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); |
| 3577 __ StoreToSafepointRegisterSlot(reg, reg); | 3377 __ StoreToSafepointRegisterSlot(reg, reg); |
| 3578 } | 3378 } |
| 3579 | 3379 |
| 3580 | 3380 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3604 | 3404 |
| 3605 | 3405 |
| 3606 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { | 3406 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { |
| 3607 // TODO(3095996): Get rid of this. For now, we need to make the | 3407 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3608 // result register contain a valid pointer because it is already | 3408 // result register contain a valid pointer because it is already |
| 3609 // contained in the register pointer map. | 3409 // contained in the register pointer map. |
| 3610 Register reg = ToRegister(instr->result()); | 3410 Register reg = ToRegister(instr->result()); |
| 3611 __ Set(reg, Immediate(0)); | 3411 __ Set(reg, Immediate(0)); |
| 3612 | 3412 |
| 3613 PushSafepointRegistersScope scope(this); | 3413 PushSafepointRegistersScope scope(this); |
| 3614 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); | 3414 // NumberTagI and NumberTagD use the context from the frame, rather than |
| 3415 // the environment's HContext or HInlinedContext value. |
| 3416 // They only call Runtime::kAllocateHeapNumber. |
| 3417 // The corresponding HChange instructions are added in a phase that does |
| 3418 // not have easy access to the local context. |
| 3419 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3420 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 3421 RecordSafepointWithRegisters(instr->pointer_map(), 0, |
| 3422 Safepoint::kNoDeoptimizationIndex); |
| 3615 __ StoreToSafepointRegisterSlot(reg, eax); | 3423 __ StoreToSafepointRegisterSlot(reg, eax); |
| 3616 } | 3424 } |
| 3617 | 3425 |
| 3618 | 3426 |
| 3619 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 3427 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 3620 LOperand* input = instr->InputAt(0); | 3428 LOperand* input = instr->InputAt(0); |
| 3621 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3429 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 3622 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 3430 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); |
| 3623 __ SmiTag(ToRegister(input)); | 3431 __ SmiTag(ToRegister(input)); |
| 3624 } | 3432 } |
| 3625 | 3433 |
| 3626 | 3434 |
| 3627 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 3435 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 3628 LOperand* input = instr->InputAt(0); | 3436 LOperand* input = instr->InputAt(0); |
| 3629 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3437 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 3630 if (instr->needs_check()) { | 3438 if (instr->needs_check()) { |
| 3631 __ test(ToRegister(input), Immediate(kSmiTagMask)); | 3439 __ test(ToRegister(input), Immediate(kSmiTagMask)); |
| 3632 DeoptimizeIf(not_zero, instr->environment()); | 3440 DeoptimizeIf(not_zero, instr->environment()); |
| 3633 } | 3441 } |
| 3634 __ SmiUntag(ToRegister(input)); | 3442 __ SmiUntag(ToRegister(input)); |
| 3635 } | 3443 } |
| 3636 | 3444 |
| 3637 | 3445 |
| 3638 void LCodeGen::EmitNumberUntagD(Register input_reg, | 3446 void LCodeGen::EmitNumberUntagD(Register input_reg, |
| 3639 XMMRegister result_reg, | 3447 XMMRegister result_reg, |
| 3448 bool deoptimize_on_undefined, |
| 3640 LEnvironment* env) { | 3449 LEnvironment* env) { |
| 3641 Label load_smi, heap_number, done; | 3450 Label load_smi, done; |
| 3642 | 3451 |
| 3643 // Smi check. | 3452 // Smi check. |
| 3644 __ test(input_reg, Immediate(kSmiTagMask)); | 3453 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); |
| 3645 __ j(zero, &load_smi, Label::kNear); | |
| 3646 | 3454 |
| 3647 // Heap number map check. | 3455 // Heap number map check. |
| 3648 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 3456 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 3649 factory()->heap_number_map()); | 3457 factory()->heap_number_map()); |
| 3650 __ j(equal, &heap_number, Label::kNear); | 3458 if (deoptimize_on_undefined) { |
| 3459 DeoptimizeIf(not_equal, env); |
| 3460 } else { |
| 3461 Label heap_number; |
| 3462 __ j(equal, &heap_number, Label::kNear); |
| 3651 | 3463 |
| 3652 __ cmp(input_reg, factory()->undefined_value()); | 3464 __ cmp(input_reg, factory()->undefined_value()); |
| 3653 DeoptimizeIf(not_equal, env); | 3465 DeoptimizeIf(not_equal, env); |
| 3654 | 3466 |
| 3655 // Convert undefined to NaN. | 3467 // Convert undefined to NaN. |
| 3656 ExternalReference nan = ExternalReference::address_of_nan(); | 3468 ExternalReference nan = ExternalReference::address_of_nan(); |
| 3657 __ movdbl(result_reg, Operand::StaticVariable(nan)); | 3469 __ movdbl(result_reg, Operand::StaticVariable(nan)); |
| 3658 __ jmp(&done, Label::kNear); | 3470 __ jmp(&done, Label::kNear); |
| 3659 | 3471 |
| 3472 __ bind(&heap_number); |
| 3473 } |
| 3660 // Heap number to XMM conversion. | 3474 // Heap number to XMM conversion. |
| 3661 __ bind(&heap_number); | |
| 3662 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 3475 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 3663 __ jmp(&done, Label::kNear); | 3476 __ jmp(&done, Label::kNear); |
| 3664 | 3477 |
| 3665 // Smi to XMM conversion | 3478 // Smi to XMM conversion |
| 3666 __ bind(&load_smi); | 3479 __ bind(&load_smi); |
| 3667 __ SmiUntag(input_reg); // Untag smi before converting to float. | 3480 __ SmiUntag(input_reg); // Untag smi before converting to float. |
| 3668 __ cvtsi2sd(result_reg, Operand(input_reg)); | 3481 __ cvtsi2sd(result_reg, Operand(input_reg)); |
| 3669 __ SmiTag(input_reg); // Retag smi. | 3482 __ SmiTag(input_reg); // Retag smi. |
| 3670 __ bind(&done); | 3483 __ bind(&done); |
| 3671 } | 3484 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3764 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 3577 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 3765 LOperand* input = instr->InputAt(0); | 3578 LOperand* input = instr->InputAt(0); |
| 3766 ASSERT(input->IsRegister()); | 3579 ASSERT(input->IsRegister()); |
| 3767 ASSERT(input->Equals(instr->result())); | 3580 ASSERT(input->Equals(instr->result())); |
| 3768 | 3581 |
| 3769 Register input_reg = ToRegister(input); | 3582 Register input_reg = ToRegister(input); |
| 3770 | 3583 |
| 3771 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); | 3584 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); |
| 3772 | 3585 |
| 3773 // Smi check. | 3586 // Smi check. |
| 3774 __ test(input_reg, Immediate(kSmiTagMask)); | 3587 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 3775 __ j(not_zero, deferred->entry()); | |
| 3776 | 3588 |
| 3777 // Smi to int32 conversion | 3589 // Smi to int32 conversion |
| 3778 __ SmiUntag(input_reg); // Untag smi. | 3590 __ SmiUntag(input_reg); // Untag smi. |
| 3779 | 3591 |
| 3780 __ bind(deferred->exit()); | 3592 __ bind(deferred->exit()); |
| 3781 } | 3593 } |
| 3782 | 3594 |
| 3783 | 3595 |
| 3784 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { | 3596 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| 3785 LOperand* input = instr->InputAt(0); | 3597 LOperand* input = instr->InputAt(0); |
| 3786 ASSERT(input->IsRegister()); | 3598 ASSERT(input->IsRegister()); |
| 3787 LOperand* result = instr->result(); | 3599 LOperand* result = instr->result(); |
| 3788 ASSERT(result->IsDoubleRegister()); | 3600 ASSERT(result->IsDoubleRegister()); |
| 3789 | 3601 |
| 3790 Register input_reg = ToRegister(input); | 3602 Register input_reg = ToRegister(input); |
| 3791 XMMRegister result_reg = ToDoubleRegister(result); | 3603 XMMRegister result_reg = ToDoubleRegister(result); |
| 3792 | 3604 |
| 3793 EmitNumberUntagD(input_reg, result_reg, instr->environment()); | 3605 EmitNumberUntagD(input_reg, result_reg, |
| 3606 instr->hydrogen()->deoptimize_on_undefined(), |
| 3607 instr->environment()); |
| 3794 } | 3608 } |
| 3795 | 3609 |
| 3796 | 3610 |
| 3797 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 3611 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 3798 LOperand* input = instr->InputAt(0); | 3612 LOperand* input = instr->InputAt(0); |
| 3799 ASSERT(input->IsDoubleRegister()); | 3613 ASSERT(input->IsDoubleRegister()); |
| 3800 LOperand* result = instr->result(); | 3614 LOperand* result = instr->result(); |
| 3801 ASSERT(result->IsRegister()); | 3615 ASSERT(result->IsRegister()); |
| 3802 | 3616 |
| 3803 XMMRegister input_reg = ToDoubleRegister(input); | 3617 XMMRegister input_reg = ToDoubleRegister(input); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3906 __ and_(result_reg, 1); | 3720 __ and_(result_reg, 1); |
| 3907 DeoptimizeIf(not_zero, instr->environment()); | 3721 DeoptimizeIf(not_zero, instr->environment()); |
| 3908 } | 3722 } |
| 3909 __ bind(&done); | 3723 __ bind(&done); |
| 3910 } | 3724 } |
| 3911 } | 3725 } |
| 3912 | 3726 |
| 3913 | 3727 |
| 3914 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 3728 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 3915 LOperand* input = instr->InputAt(0); | 3729 LOperand* input = instr->InputAt(0); |
| 3916 __ test(ToRegister(input), Immediate(kSmiTagMask)); | 3730 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 3917 DeoptimizeIf(not_zero, instr->environment()); | 3731 DeoptimizeIf(not_zero, instr->environment()); |
| 3918 } | 3732 } |
| 3919 | 3733 |
| 3920 | 3734 |
| 3921 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 3735 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 3922 LOperand* input = instr->InputAt(0); | 3736 LOperand* input = instr->InputAt(0); |
| 3923 __ test(ToRegister(input), Immediate(kSmiTagMask)); | 3737 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 3924 DeoptimizeIf(zero, instr->environment()); | 3738 DeoptimizeIf(zero, instr->environment()); |
| 3925 } | 3739 } |
| 3926 | 3740 |
| 3927 | 3741 |
| 3928 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 3742 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 3929 Register input = ToRegister(instr->InputAt(0)); | 3743 Register input = ToRegister(instr->InputAt(0)); |
| 3930 Register temp = ToRegister(instr->TempAt(0)); | 3744 Register temp = ToRegister(instr->TempAt(0)); |
| 3931 | 3745 |
| 3932 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 3746 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 3933 | 3747 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3965 __ and_(temp, mask); | 3779 __ and_(temp, mask); |
| 3966 __ cmpb(Operand(temp), tag); | 3780 __ cmpb(Operand(temp), tag); |
| 3967 DeoptimizeIf(not_equal, instr->environment()); | 3781 DeoptimizeIf(not_equal, instr->environment()); |
| 3968 } | 3782 } |
| 3969 } | 3783 } |
| 3970 } | 3784 } |
| 3971 | 3785 |
| 3972 | 3786 |
| 3973 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { | 3787 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
| 3974 ASSERT(instr->InputAt(0)->IsRegister()); | 3788 ASSERT(instr->InputAt(0)->IsRegister()); |
| 3975 Register reg = ToRegister(instr->InputAt(0)); | 3789 Operand operand = ToOperand(instr->InputAt(0)); |
| 3976 __ cmp(reg, instr->hydrogen()->target()); | 3790 __ cmp(operand, instr->hydrogen()->target()); |
| 3977 DeoptimizeIf(not_equal, instr->environment()); | 3791 DeoptimizeIf(not_equal, instr->environment()); |
| 3978 } | 3792 } |
| 3979 | 3793 |
| 3980 | 3794 |
| 3981 void LCodeGen::DoCheckMap(LCheckMap* instr) { | 3795 void LCodeGen::DoCheckMap(LCheckMap* instr) { |
| 3982 LOperand* input = instr->InputAt(0); | 3796 LOperand* input = instr->InputAt(0); |
| 3983 ASSERT(input->IsRegister()); | 3797 ASSERT(input->IsRegister()); |
| 3984 Register reg = ToRegister(input); | 3798 Register reg = ToRegister(input); |
| 3985 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 3799 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 3986 instr->hydrogen()->map()); | 3800 instr->hydrogen()->map()); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4068 } | 3882 } |
| 4069 | 3883 |
| 4070 // Check the holder map. | 3884 // Check the holder map. |
| 4071 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 3885 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 4072 Handle<Map>(current_prototype->map())); | 3886 Handle<Map>(current_prototype->map())); |
| 4073 DeoptimizeIf(not_equal, instr->environment()); | 3887 DeoptimizeIf(not_equal, instr->environment()); |
| 4074 } | 3888 } |
| 4075 | 3889 |
| 4076 | 3890 |
| 4077 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { | 3891 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
| 3892 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4078 // Setup the parameters to the stub/runtime call. | 3893 // Setup the parameters to the stub/runtime call. |
| 4079 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 3894 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4080 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); | 3895 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); |
| 4081 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); | 3896 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
| 4082 __ push(Immediate(instr->hydrogen()->constant_elements())); | 3897 __ push(Immediate(instr->hydrogen()->constant_elements())); |
| 4083 | 3898 |
| 4084 // Pick the right runtime function or stub to call. | 3899 // Pick the right runtime function or stub to call. |
| 4085 int length = instr->hydrogen()->length(); | 3900 int length = instr->hydrogen()->length(); |
| 4086 if (instr->hydrogen()->IsCopyOnWrite()) { | 3901 if (instr->hydrogen()->IsCopyOnWrite()) { |
| 4087 ASSERT(instr->hydrogen()->depth() == 1); | 3902 ASSERT(instr->hydrogen()->depth() == 1); |
| 4088 FastCloneShallowArrayStub::Mode mode = | 3903 FastCloneShallowArrayStub::Mode mode = |
| 4089 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; | 3904 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; |
| 4090 FastCloneShallowArrayStub stub(mode, length); | 3905 FastCloneShallowArrayStub stub(mode, length); |
| 4091 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 3906 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4092 } else if (instr->hydrogen()->depth() > 1) { | 3907 } else if (instr->hydrogen()->depth() > 1) { |
| 4093 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, RESTORE_CONTEXT); | 3908 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); |
| 4094 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 3909 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 4095 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, RESTORE_CONTEXT); | 3910 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); |
| 4096 } else { | 3911 } else { |
| 4097 FastCloneShallowArrayStub::Mode mode = | 3912 FastCloneShallowArrayStub::Mode mode = |
| 4098 FastCloneShallowArrayStub::CLONE_ELEMENTS; | 3913 FastCloneShallowArrayStub::CLONE_ELEMENTS; |
| 4099 FastCloneShallowArrayStub stub(mode, length); | 3914 FastCloneShallowArrayStub stub(mode, length); |
| 4100 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 3915 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4101 } | 3916 } |
| 4102 } | 3917 } |
| 4103 | 3918 |
| 4104 | 3919 |
| 4105 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { | 3920 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { |
| 4106 ASSERT(ToRegister(instr->context()).is(esi)); | 3921 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4107 // Setup the parameters to the stub/runtime call. | 3922 // Setup the parameters to the stub/runtime call. |
| 4108 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 3923 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4109 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); | 3924 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); |
| 4110 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); | 3925 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
| 4111 __ push(Immediate(instr->hydrogen()->constant_properties())); | 3926 __ push(Immediate(instr->hydrogen()->constant_properties())); |
| 4112 int flags = instr->hydrogen()->fast_elements() | 3927 int flags = instr->hydrogen()->fast_elements() |
| 4113 ? ObjectLiteral::kFastElements | 3928 ? ObjectLiteral::kFastElements |
| 4114 : ObjectLiteral::kNoFlags; | 3929 : ObjectLiteral::kNoFlags; |
| 4115 flags |= instr->hydrogen()->has_function() | 3930 flags |= instr->hydrogen()->has_function() |
| 4116 ? ObjectLiteral::kHasFunction | 3931 ? ObjectLiteral::kHasFunction |
| 4117 : ObjectLiteral::kNoFlags; | 3932 : ObjectLiteral::kNoFlags; |
| 4118 __ push(Immediate(Smi::FromInt(flags))); | 3933 __ push(Immediate(Smi::FromInt(flags))); |
| 4119 | 3934 |
| 4120 // Pick the right runtime function to call. | 3935 // Pick the right runtime function to call. |
| 4121 if (instr->hydrogen()->depth() > 1) { | 3936 if (instr->hydrogen()->depth() > 1) { |
| 4122 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr, CONTEXT_ADJUSTED); | 3937 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); |
| 4123 } else { | 3938 } else { |
| 4124 CallRuntime(Runtime::kCreateObjectLiteralShallow, | 3939 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); |
| 4125 4, | |
| 4126 instr, | |
| 4127 CONTEXT_ADJUSTED); | |
| 4128 } | 3940 } |
| 4129 } | 3941 } |
| 4130 | 3942 |
| 4131 | 3943 |
| 4132 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { | 3944 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { |
| 4133 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); | 3945 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); |
| 4134 __ push(eax); | 3946 __ push(eax); |
| 4135 CallRuntime(Runtime::kToFastProperties, 1, instr, CONTEXT_ADJUSTED); | 3947 CallRuntime(Runtime::kToFastProperties, 1, instr); |
| 4136 } | 3948 } |
| 4137 | 3949 |
| 4138 | 3950 |
| 4139 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { | 3951 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { |
| 3952 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4140 Label materialized; | 3953 Label materialized; |
| 4141 // Registers will be used as follows: | 3954 // Registers will be used as follows: |
| 4142 // edi = JS function. | 3955 // edi = JS function. |
| 4143 // ecx = literals array. | 3956 // ecx = literals array. |
| 4144 // ebx = regexp literal. | 3957 // ebx = regexp literal. |
| 4145 // eax = regexp literal clone. | 3958 // eax = regexp literal clone. |
| 3959 // esi = context. |
| 4146 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 3960 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4147 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 3961 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 4148 int literal_offset = FixedArray::kHeaderSize + | 3962 int literal_offset = FixedArray::kHeaderSize + |
| 4149 instr->hydrogen()->literal_index() * kPointerSize; | 3963 instr->hydrogen()->literal_index() * kPointerSize; |
| 4150 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 3964 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 4151 __ cmp(ebx, factory()->undefined_value()); | 3965 __ cmp(ebx, factory()->undefined_value()); |
| 4152 __ j(not_equal, &materialized, Label::kNear); | 3966 __ j(not_equal, &materialized, Label::kNear); |
| 4153 | 3967 |
| 4154 // Create regexp literal using runtime function | 3968 // Create regexp literal using runtime function |
| 4155 // Result will be in eax. | 3969 // Result will be in eax. |
| 4156 __ push(ecx); | 3970 __ push(ecx); |
| 4157 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); | 3971 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
| 4158 __ push(Immediate(instr->hydrogen()->pattern())); | 3972 __ push(Immediate(instr->hydrogen()->pattern())); |
| 4159 __ push(Immediate(instr->hydrogen()->flags())); | 3973 __ push(Immediate(instr->hydrogen()->flags())); |
| 4160 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, RESTORE_CONTEXT); | 3974 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); |
| 4161 __ mov(ebx, eax); | 3975 __ mov(ebx, eax); |
| 4162 | 3976 |
| 4163 __ bind(&materialized); | 3977 __ bind(&materialized); |
| 4164 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | 3978 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 4165 Label allocated, runtime_allocate; | 3979 Label allocated, runtime_allocate; |
| 4166 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); | 3980 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); |
| 4167 __ jmp(&allocated); | 3981 __ jmp(&allocated); |
| 4168 | 3982 |
| 4169 __ bind(&runtime_allocate); | 3983 __ bind(&runtime_allocate); |
| 4170 __ push(ebx); | 3984 __ push(ebx); |
| 4171 __ push(Immediate(Smi::FromInt(size))); | 3985 __ push(Immediate(Smi::FromInt(size))); |
| 4172 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, RESTORE_CONTEXT); | 3986 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); |
| 4173 __ pop(ebx); | 3987 __ pop(ebx); |
| 4174 | 3988 |
| 4175 __ bind(&allocated); | 3989 __ bind(&allocated); |
| 4176 // Copy the content into the newly allocated memory. | 3990 // Copy the content into the newly allocated memory. |
| 4177 // (Unroll copy loop once for better throughput). | 3991 // (Unroll copy loop once for better throughput). |
| 4178 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { | 3992 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { |
| 4179 __ mov(edx, FieldOperand(ebx, i)); | 3993 __ mov(edx, FieldOperand(ebx, i)); |
| 4180 __ mov(ecx, FieldOperand(ebx, i + kPointerSize)); | 3994 __ mov(ecx, FieldOperand(ebx, i + kPointerSize)); |
| 4181 __ mov(FieldOperand(eax, i), edx); | 3995 __ mov(FieldOperand(eax, i), edx); |
| 4182 __ mov(FieldOperand(eax, i + kPointerSize), ecx); | 3996 __ mov(FieldOperand(eax, i + kPointerSize), ecx); |
| 4183 } | 3997 } |
| 4184 if ((size % (2 * kPointerSize)) != 0) { | 3998 if ((size % (2 * kPointerSize)) != 0) { |
| 4185 __ mov(edx, FieldOperand(ebx, size - kPointerSize)); | 3999 __ mov(edx, FieldOperand(ebx, size - kPointerSize)); |
| 4186 __ mov(FieldOperand(eax, size - kPointerSize), edx); | 4000 __ mov(FieldOperand(eax, size - kPointerSize), edx); |
| 4187 } | 4001 } |
| 4188 } | 4002 } |
| 4189 | 4003 |
| 4190 | 4004 |
| 4191 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 4005 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
| 4006 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4192 // Use the fast case closure allocation code that allocates in new | 4007 // Use the fast case closure allocation code that allocates in new |
| 4193 // space for nested functions that don't need literals cloning. | 4008 // space for nested functions that don't need literals cloning. |
| 4194 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); | 4009 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
| 4195 bool pretenure = instr->hydrogen()->pretenure(); | 4010 bool pretenure = instr->hydrogen()->pretenure(); |
| 4196 if (!pretenure && shared_info->num_literals() == 0) { | 4011 if (!pretenure && shared_info->num_literals() == 0) { |
| 4197 FastNewClosureStub stub( | 4012 FastNewClosureStub stub( |
| 4198 shared_info->strict_mode() ? kStrictMode : kNonStrictMode); | 4013 shared_info->strict_mode() ? kStrictMode : kNonStrictMode); |
| 4199 __ push(Immediate(shared_info)); | 4014 __ push(Immediate(shared_info)); |
| 4200 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 4015 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4201 } else { | 4016 } else { |
| 4202 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); | 4017 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 4203 __ push(Immediate(shared_info)); | 4018 __ push(Immediate(shared_info)); |
| 4204 __ push(Immediate(pretenure | 4019 __ push(Immediate(pretenure |
| 4205 ? factory()->true_value() | 4020 ? factory()->true_value() |
| 4206 : factory()->false_value())); | 4021 : factory()->false_value())); |
| 4207 CallRuntime(Runtime::kNewClosure, 3, instr, RESTORE_CONTEXT); | 4022 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 4208 } | 4023 } |
| 4209 } | 4024 } |
| 4210 | 4025 |
| 4211 | 4026 |
| 4212 void LCodeGen::DoTypeof(LTypeof* instr) { | 4027 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 4213 LOperand* input = instr->InputAt(0); | 4028 LOperand* input = instr->InputAt(1); |
| 4214 if (input->IsConstantOperand()) { | 4029 if (input->IsConstantOperand()) { |
| 4215 __ push(ToImmediate(input)); | 4030 __ push(ToImmediate(input)); |
| 4216 } else { | 4031 } else { |
| 4217 __ push(ToOperand(input)); | 4032 __ push(ToOperand(input)); |
| 4218 } | 4033 } |
| 4219 CallRuntime(Runtime::kTypeof, 1, instr, RESTORE_CONTEXT); | 4034 CallRuntime(Runtime::kTypeof, 1, instr); |
| 4220 } | |
| 4221 | |
| 4222 | |
| 4223 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { | |
| 4224 Register input = ToRegister(instr->InputAt(0)); | |
| 4225 Register result = ToRegister(instr->result()); | |
| 4226 Label true_label; | |
| 4227 Label false_label; | |
| 4228 Label done; | |
| 4229 | |
| 4230 Condition final_branch_condition = EmitTypeofIs(&true_label, | |
| 4231 &false_label, | |
| 4232 input, | |
| 4233 instr->type_literal()); | |
| 4234 __ j(final_branch_condition, &true_label, Label::kNear); | |
| 4235 __ bind(&false_label); | |
| 4236 __ mov(result, factory()->false_value()); | |
| 4237 __ jmp(&done, Label::kNear); | |
| 4238 | |
| 4239 __ bind(&true_label); | |
| 4240 __ mov(result, factory()->true_value()); | |
| 4241 | |
| 4242 __ bind(&done); | |
| 4243 } | 4035 } |
| 4244 | 4036 |
| 4245 | 4037 |
| 4246 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 4038 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 4247 Register input = ToRegister(instr->InputAt(0)); | 4039 Register input = ToRegister(instr->InputAt(0)); |
| 4248 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4040 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 4249 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 4041 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 4250 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 4042 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 4251 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 4043 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 4252 | 4044 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4288 __ cmp(input, factory()->undefined_value()); | 4080 __ cmp(input, factory()->undefined_value()); |
| 4289 __ j(equal, true_label); | 4081 __ j(equal, true_label); |
| 4290 __ JumpIfSmi(input, false_label); | 4082 __ JumpIfSmi(input, false_label); |
| 4291 // Check for undetectable objects => true. | 4083 // Check for undetectable objects => true. |
| 4292 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); | 4084 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 4293 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 4085 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
| 4294 1 << Map::kIsUndetectable); | 4086 1 << Map::kIsUndetectable); |
| 4295 final_branch_condition = not_zero; | 4087 final_branch_condition = not_zero; |
| 4296 | 4088 |
| 4297 } else if (type_name->Equals(heap()->function_symbol())) { | 4089 } else if (type_name->Equals(heap()->function_symbol())) { |
| 4090 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 4298 __ JumpIfSmi(input, false_label); | 4091 __ JumpIfSmi(input, false_label); |
| 4299 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); | 4092 __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input); |
| 4300 __ j(equal, true_label); | 4093 final_branch_condition = above_equal; |
| 4301 // Regular expressions => 'function' (they are callable). | |
| 4302 __ CmpInstanceType(input, JS_REGEXP_TYPE); | |
| 4303 final_branch_condition = equal; | |
| 4304 | 4094 |
| 4305 } else if (type_name->Equals(heap()->object_symbol())) { | 4095 } else if (type_name->Equals(heap()->object_symbol())) { |
| 4306 __ JumpIfSmi(input, false_label); | 4096 __ JumpIfSmi(input, false_label); |
| 4307 __ cmp(input, factory()->null_value()); | 4097 __ cmp(input, factory()->null_value()); |
| 4308 __ j(equal, true_label); | 4098 __ j(equal, true_label); |
| 4309 // Regular expressions => 'function', not 'object'. | 4099 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
| 4310 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input); | |
| 4311 __ j(below, false_label); | 4100 __ j(below, false_label); |
| 4312 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); | 4101 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4313 __ j(above_equal, false_label); | 4102 __ j(above, false_label); |
| 4314 // Check for undetectable objects => false. | 4103 // Check for undetectable objects => false. |
| 4315 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 4104 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
| 4316 1 << Map::kIsUndetectable); | 4105 1 << Map::kIsUndetectable); |
| 4317 final_branch_condition = zero; | 4106 final_branch_condition = zero; |
| 4318 | 4107 |
| 4319 } else { | 4108 } else { |
| 4320 final_branch_condition = not_equal; | 4109 final_branch_condition = not_equal; |
| 4321 __ jmp(false_label); | 4110 __ jmp(false_label); |
| 4322 // A dead branch instruction will be generated after this point. | 4111 // A dead branch instruction will be generated after this point. |
| 4323 } | 4112 } |
| 4324 | 4113 |
| 4325 return final_branch_condition; | 4114 return final_branch_condition; |
| 4326 } | 4115 } |
| 4327 | 4116 |
| 4328 | 4117 |
| 4329 void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) { | |
| 4330 Register result = ToRegister(instr->result()); | |
| 4331 Label true_label; | |
| 4332 Label done; | |
| 4333 | |
| 4334 EmitIsConstructCall(result); | |
| 4335 __ j(equal, &true_label, Label::kNear); | |
| 4336 | |
| 4337 __ mov(result, factory()->false_value()); | |
| 4338 __ jmp(&done, Label::kNear); | |
| 4339 | |
| 4340 __ bind(&true_label); | |
| 4341 __ mov(result, factory()->true_value()); | |
| 4342 | |
| 4343 __ bind(&done); | |
| 4344 } | |
| 4345 | |
| 4346 | |
| 4347 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 4118 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 4348 Register temp = ToRegister(instr->TempAt(0)); | 4119 Register temp = ToRegister(instr->TempAt(0)); |
| 4349 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4120 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 4350 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 4121 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 4351 | 4122 |
| 4352 EmitIsConstructCall(temp); | 4123 EmitIsConstructCall(temp); |
| 4353 EmitBranch(true_block, false_block, equal); | 4124 EmitBranch(true_block, false_block, equal); |
| 4354 } | 4125 } |
| 4355 | 4126 |
| 4356 | 4127 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4396 LPointerMap* pointers = instr->pointer_map(); | 4167 LPointerMap* pointers = instr->pointer_map(); |
| 4397 LEnvironment* env = instr->deoptimization_environment(); | 4168 LEnvironment* env = instr->deoptimization_environment(); |
| 4398 RecordPosition(pointers->position()); | 4169 RecordPosition(pointers->position()); |
| 4399 RegisterEnvironmentForDeoptimization(env); | 4170 RegisterEnvironmentForDeoptimization(env); |
| 4400 // Create safepoint generator that will also ensure enough space in the | 4171 // Create safepoint generator that will also ensure enough space in the |
| 4401 // reloc info for patching in deoptimization (since this is invoking a | 4172 // reloc info for patching in deoptimization (since this is invoking a |
| 4402 // builtin) | 4173 // builtin) |
| 4403 SafepointGenerator safepoint_generator(this, | 4174 SafepointGenerator safepoint_generator(this, |
| 4404 pointers, | 4175 pointers, |
| 4405 env->deoptimization_index()); | 4176 env->deoptimization_index()); |
| 4406 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | |
| 4407 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 4177 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 4408 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); | 4178 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); |
| 4409 } | 4179 } |
| 4410 | 4180 |
| 4411 | 4181 |
| 4412 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 4182 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 4413 // Perform stack overflow check. | 4183 { |
| 4414 Label done; | 4184 PushSafepointRegistersScope scope(this); |
| 4415 ExternalReference stack_limit = | 4185 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 4416 ExternalReference::address_of_stack_limit(isolate()); | 4186 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 4417 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 4187 RegisterLazyDeoptimization( |
| 4418 __ j(above_equal, &done, Label::kNear); | 4188 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); |
| 4189 } |
| 4419 | 4190 |
| 4420 StackCheckStub stub; | 4191 // The gap code includes the restoring of the safepoint registers. |
| 4421 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); | 4192 int pc = masm()->pc_offset(); |
| 4422 __ bind(&done); | 4193 safepoints_.SetPcAfterGap(pc); |
| 4423 } | 4194 } |
| 4424 | 4195 |
| 4425 | 4196 |
| 4197 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 4198 class DeferredStackCheck: public LDeferredCode { |
| 4199 public: |
| 4200 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
| 4201 : LDeferredCode(codegen), instr_(instr) { } |
| 4202 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
| 4203 private: |
| 4204 LStackCheck* instr_; |
| 4205 }; |
| 4206 |
| 4207 if (instr->hydrogen()->is_function_entry()) { |
| 4208 // Perform stack overflow check. |
| 4209 Label done; |
| 4210 ExternalReference stack_limit = |
| 4211 ExternalReference::address_of_stack_limit(isolate()); |
| 4212 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 4213 __ j(above_equal, &done, Label::kNear); |
| 4214 |
| 4215 ASSERT(instr->context()->IsRegister()); |
| 4216 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4217 StackCheckStub stub; |
| 4218 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4219 __ bind(&done); |
| 4220 } else { |
| 4221 ASSERT(instr->hydrogen()->is_backwards_branch()); |
| 4222 // Perform stack overflow check if this goto needs it before jumping. |
| 4223 DeferredStackCheck* deferred_stack_check = |
| 4224 new DeferredStackCheck(this, instr); |
| 4225 ExternalReference stack_limit = |
| 4226 ExternalReference::address_of_stack_limit(isolate()); |
| 4227 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 4228 __ j(below, deferred_stack_check->entry()); |
| 4229 __ bind(instr->done_label()); |
| 4230 deferred_stack_check->SetExit(instr->done_label()); |
| 4231 } |
| 4232 } |
| 4233 |
| 4234 |
| 4426 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 4235 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 4427 // This is a pseudo-instruction that ensures that the environment here is | 4236 // This is a pseudo-instruction that ensures that the environment here is |
| 4428 // properly registered for deoptimization and records the assembler's PC | 4237 // properly registered for deoptimization and records the assembler's PC |
| 4429 // offset. | 4238 // offset. |
| 4430 LEnvironment* environment = instr->environment(); | 4239 LEnvironment* environment = instr->environment(); |
| 4431 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), | 4240 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), |
| 4432 instr->SpilledDoubleRegisterArray()); | 4241 instr->SpilledDoubleRegisterArray()); |
| 4433 | 4242 |
| 4434 // If the environment were already registered, we would have no way of | 4243 // If the environment were already registered, we would have no way of |
| 4435 // backpatching it with the spill slot operands. | 4244 // backpatching it with the spill slot operands. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 4457 LPointerMap* pointers = instr->pointer_map(); | 4266 LPointerMap* pointers = instr->pointer_map(); |
| 4458 LEnvironment* env = instr->deoptimization_environment(); | 4267 LEnvironment* env = instr->deoptimization_environment(); |
| 4459 RecordPosition(pointers->position()); | 4268 RecordPosition(pointers->position()); |
| 4460 RegisterEnvironmentForDeoptimization(env); | 4269 RegisterEnvironmentForDeoptimization(env); |
| 4461 // Create safepoint generator that will also ensure enough space in the | 4270 // Create safepoint generator that will also ensure enough space in the |
| 4462 // reloc info for patching in deoptimization (since this is invoking a | 4271 // reloc info for patching in deoptimization (since this is invoking a |
| 4463 // builtin) | 4272 // builtin) |
| 4464 SafepointGenerator safepoint_generator(this, | 4273 SafepointGenerator safepoint_generator(this, |
| 4465 pointers, | 4274 pointers, |
| 4466 env->deoptimization_index()); | 4275 env->deoptimization_index()); |
| 4467 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | |
| 4468 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); | 4276 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); |
| 4469 } | 4277 } |
| 4470 | 4278 |
| 4471 | 4279 |
| 4472 #undef __ | 4280 #undef __ |
| 4473 | 4281 |
| 4474 } } // namespace v8::internal | 4282 } } // namespace v8::internal |
| 4475 | 4283 |
| 4476 #endif // V8_TARGET_ARCH_IA32 | 4284 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |