| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 info()->CommitDependencies(code); | 91 info()->CommitDependencies(code); |
| 92 } | 92 } |
| 93 | 93 |
| 94 | 94 |
| 95 void LCodeGen::Abort(BailoutReason reason) { | 95 void LCodeGen::Abort(BailoutReason reason) { |
| 96 info()->set_bailout_reason(reason); | 96 info()->set_bailout_reason(reason); |
| 97 status_ = ABORTED; | 97 status_ = ABORTED; |
| 98 } | 98 } |
| 99 | 99 |
| 100 | 100 |
| 101 void LCodeGen::Comment(const char* format, ...) { | |
| 102 if (!FLAG_code_comments) return; | |
| 103 char buffer[4 * KB]; | |
| 104 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); | |
| 105 va_list arguments; | |
| 106 va_start(arguments, format); | |
| 107 builder.AddFormattedList(format, arguments); | |
| 108 va_end(arguments); | |
| 109 | |
| 110 // Copy the string before recording it in the assembler to avoid | |
| 111 // issues when the stack allocated buffer goes out of scope. | |
| 112 size_t length = builder.position(); | |
| 113 Vector<char> copy = Vector<char>::New(length + 1); | |
| 114 OS::MemCopy(copy.start(), builder.Finalize(), copy.length()); | |
| 115 masm()->RecordComment(copy.start()); | |
| 116 } | |
| 117 | |
| 118 | |
| 119 bool LCodeGen::GeneratePrologue() { | 101 bool LCodeGen::GeneratePrologue() { |
| 120 ASSERT(is_generating()); | 102 ASSERT(is_generating()); |
| 121 | 103 |
| 122 if (info()->IsOptimizing()) { | 104 if (info()->IsOptimizing()) { |
| 123 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 105 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 124 | 106 |
| 125 #ifdef DEBUG | 107 #ifdef DEBUG |
| 126 if (strlen(FLAG_stop_at) > 0 && | 108 if (strlen(FLAG_stop_at) > 0 && |
| 127 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 109 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 128 __ stop("stop_at"); | 110 __ stop("stop_at"); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 osr_pc_offset_ = masm()->pc_offset(); | 246 osr_pc_offset_ = masm()->pc_offset(); |
| 265 | 247 |
| 266 // Adjust the frame size, subsuming the unoptimized frame into the | 248 // Adjust the frame size, subsuming the unoptimized frame into the |
| 267 // optimized frame. | 249 // optimized frame. |
| 268 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); | 250 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); |
| 269 ASSERT(slots >= 0); | 251 ASSERT(slots >= 0); |
| 270 __ sub(sp, sp, Operand(slots * kPointerSize)); | 252 __ sub(sp, sp, Operand(slots * kPointerSize)); |
| 271 } | 253 } |
| 272 | 254 |
| 273 | 255 |
| 274 bool LCodeGen::GenerateBody() { | |
| 275 ASSERT(is_generating()); | |
| 276 bool emit_instructions = true; | |
| 277 for (current_instruction_ = 0; | |
| 278 !is_aborted() && current_instruction_ < instructions_->length(); | |
| 279 current_instruction_++) { | |
| 280 LInstruction* instr = instructions_->at(current_instruction_); | |
| 281 | |
| 282 // Don't emit code for basic blocks with a replacement. | |
| 283 if (instr->IsLabel()) { | |
| 284 emit_instructions = !LLabel::cast(instr)->HasReplacement(); | |
| 285 } | |
| 286 if (!emit_instructions) continue; | |
| 287 | |
| 288 if (FLAG_code_comments && instr->HasInterestingComment(this)) { | |
| 289 Comment(";;; <@%d,#%d> %s", | |
| 290 current_instruction_, | |
| 291 instr->hydrogen_value()->id(), | |
| 292 instr->Mnemonic()); | |
| 293 } | |
| 294 | |
| 295 RecordAndUpdatePosition(instr->position()); | |
| 296 | |
| 297 instr->CompileToNative(this); | |
| 298 } | |
| 299 EnsureSpaceForLazyDeopt(); | |
| 300 last_lazy_deopt_pc_ = masm()->pc_offset(); | |
| 301 return !is_aborted(); | |
| 302 } | |
| 303 | |
| 304 | |
| 305 bool LCodeGen::GenerateDeferredCode() { | 256 bool LCodeGen::GenerateDeferredCode() { |
| 306 ASSERT(is_generating()); | 257 ASSERT(is_generating()); |
| 307 if (deferred_.length() > 0) { | 258 if (deferred_.length() > 0) { |
| 308 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 259 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 309 LDeferredCode* code = deferred_[i]; | 260 LDeferredCode* code = deferred_[i]; |
| 310 | 261 |
| 311 int pos = instructions_->at(code->instruction_index())->position(); | 262 int pos = instructions_->at(code->instruction_index())->position(); |
| 312 RecordAndUpdatePosition(pos); | 263 RecordAndUpdatePosition(pos); |
| 313 | 264 |
| 314 Comment(";;; <@%d,#%d> " | 265 Comment(";;; <@%d,#%d> " |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 TargetAddressStorageMode storage_mode) { | 673 TargetAddressStorageMode storage_mode) { |
| 723 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, storage_mode); | 674 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, storage_mode); |
| 724 } | 675 } |
| 725 | 676 |
| 726 | 677 |
| 727 void LCodeGen::CallCodeGeneric(Handle<Code> code, | 678 void LCodeGen::CallCodeGeneric(Handle<Code> code, |
| 728 RelocInfo::Mode mode, | 679 RelocInfo::Mode mode, |
| 729 LInstruction* instr, | 680 LInstruction* instr, |
| 730 SafepointMode safepoint_mode, | 681 SafepointMode safepoint_mode, |
| 731 TargetAddressStorageMode storage_mode) { | 682 TargetAddressStorageMode storage_mode) { |
| 732 EnsureSpaceForLazyDeopt(); | 683 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 733 ASSERT(instr != NULL); | 684 ASSERT(instr != NULL); |
| 734 // Block literal pool emission to ensure nop indicating no inlined smi code | 685 // Block literal pool emission to ensure nop indicating no inlined smi code |
| 735 // is in the correct position. | 686 // is in the correct position. |
| 736 Assembler::BlockConstPoolScope block_const_pool(masm()); | 687 Assembler::BlockConstPoolScope block_const_pool(masm()); |
| 737 LPointerMap* pointers = instr->pointer_map(); | 688 LPointerMap* pointers = instr->pointer_map(); |
| 738 RecordPosition(pointers->position()); | 689 RecordPosition(pointers->position()); |
| 739 __ Call(code, mode, TypeFeedbackId::None(), al, storage_mode); | 690 __ Call(code, mode, TypeFeedbackId::None(), al, storage_mode); |
| 740 RecordSafepointWithLazyDeopt(instr, safepoint_mode); | 691 RecordSafepointWithLazyDeopt(instr, safepoint_mode); |
| 741 | 692 |
| 742 // Signal that we don't inline smi code before these stubs in the | 693 // Signal that we don't inline smi code before these stubs in the |
| 743 // optimizing code generator. | 694 // optimizing code generator. |
| 744 if (code->kind() == Code::BINARY_OP_IC || | 695 if (code->kind() == Code::BINARY_OP_IC || |
| 745 code->kind() == Code::COMPARE_IC) { | 696 code->kind() == Code::COMPARE_IC) { |
| 746 __ nop(); | 697 __ nop(); |
| 747 } | 698 } |
| 748 } | 699 } |
| 749 | 700 |
| 750 | 701 |
| 751 void LCodeGen::CallRuntime(const Runtime::Function* function, | 702 void LCodeGen::CallRuntime(const Runtime::Function* function, |
| 752 int num_arguments, | 703 int num_arguments, |
| 753 LInstruction* instr) { | 704 LInstruction* instr, |
| 705 SaveFPRegsMode save_doubles) { |
| 754 ASSERT(instr != NULL); | 706 ASSERT(instr != NULL); |
| 755 LPointerMap* pointers = instr->pointer_map(); | 707 LPointerMap* pointers = instr->pointer_map(); |
| 756 ASSERT(pointers != NULL); | 708 ASSERT(pointers != NULL); |
| 757 RecordPosition(pointers->position()); | 709 RecordPosition(pointers->position()); |
| 758 | 710 |
| 759 __ CallRuntime(function, num_arguments); | 711 __ CallRuntime(function, num_arguments, save_doubles); |
| 712 |
| 760 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 713 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 761 } | 714 } |
| 762 | 715 |
| 763 | 716 |
| 764 void LCodeGen::LoadContextFromDeferred(LOperand* context) { | 717 void LCodeGen::LoadContextFromDeferred(LOperand* context) { |
| 765 if (context->IsRegister()) { | 718 if (context->IsRegister()) { |
| 766 __ Move(cp, ToRegister(context)); | 719 __ Move(cp, ToRegister(context)); |
| 767 } else if (context->IsStackSlot()) { | 720 } else if (context->IsStackSlot()) { |
| 768 __ ldr(cp, ToMemOperand(context)); | 721 __ ldr(cp, ToMemOperand(context)); |
| 722 } else if (context->IsConstantOperand()) { |
| 723 HConstant* constant = |
| 724 chunk_->LookupConstant(LConstantOperand::cast(context)); |
| 725 __ LoadObject(cp, Handle<Object>::cast(constant->handle(isolate()))); |
| 769 } else { | 726 } else { |
| 770 UNREACHABLE(); | 727 UNREACHABLE(); |
| 771 } | 728 } |
| 772 } | 729 } |
| 773 | 730 |
| 774 | 731 |
| 775 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, | 732 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
| 776 int argc, | 733 int argc, |
| 777 LInstruction* instr, | 734 LInstruction* instr, |
| 778 LOperand* context) { | 735 LOperand* context) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 870 LEnvironment* environment) { | 827 LEnvironment* environment) { |
| 871 Deoptimizer::BailoutType bailout_type = info()->IsStub() | 828 Deoptimizer::BailoutType bailout_type = info()->IsStub() |
| 872 ? Deoptimizer::LAZY | 829 ? Deoptimizer::LAZY |
| 873 : Deoptimizer::EAGER; | 830 : Deoptimizer::EAGER; |
| 874 DeoptimizeIf(condition, environment, bailout_type); | 831 DeoptimizeIf(condition, environment, bailout_type); |
| 875 } | 832 } |
| 876 | 833 |
| 877 | 834 |
| 878 void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) { | 835 void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) { |
| 879 ZoneList<Handle<Map> > maps(1, zone()); | 836 ZoneList<Handle<Map> > maps(1, zone()); |
| 837 ZoneList<Handle<JSObject> > objects(1, zone()); |
| 880 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | 838 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 881 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { | 839 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
| 882 RelocInfo::Mode mode = it.rinfo()->rmode(); | 840 if (Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_object())) { |
| 883 if (mode == RelocInfo::EMBEDDED_OBJECT && | 841 if (it.rinfo()->target_object()->IsMap()) { |
| 884 it.rinfo()->target_object()->IsMap()) { | 842 Handle<Map> map(Map::cast(it.rinfo()->target_object())); |
| 885 Handle<Map> map(Map::cast(it.rinfo()->target_object())); | |
| 886 if (map->CanTransition()) { | |
| 887 maps.Add(map, zone()); | 843 maps.Add(map, zone()); |
| 844 } else if (it.rinfo()->target_object()->IsJSObject()) { |
| 845 Handle<JSObject> object(JSObject::cast(it.rinfo()->target_object())); |
| 846 objects.Add(object, zone()); |
| 888 } | 847 } |
| 889 } | 848 } |
| 890 } | 849 } |
| 891 #ifdef VERIFY_HEAP | 850 #ifdef VERIFY_HEAP |
| 892 // This disables verification of weak embedded maps after full GC. | 851 // This disables verification of weak embedded objects after full GC. |
| 893 // AddDependentCode can cause a GC, which would observe the state where | 852 // AddDependentCode can cause a GC, which would observe the state where |
| 894 // this code is not yet in the depended code lists of the embedded maps. | 853 // this code is not yet in the depended code lists of the embedded maps. |
| 895 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps; | 854 NoWeakObjectVerificationScope disable_verification_of_embedded_objects; |
| 896 #endif | 855 #endif |
| 897 for (int i = 0; i < maps.length(); i++) { | 856 for (int i = 0; i < maps.length(); i++) { |
| 898 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code); | 857 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code); |
| 899 } | 858 } |
| 859 for (int i = 0; i < objects.length(); i++) { |
| 860 AddWeakObjectToCodeDependency(isolate()->heap(), objects.at(i), code); |
| 861 } |
| 900 } | 862 } |
| 901 | 863 |
| 902 | 864 |
| 903 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { | 865 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
| 904 int length = deoptimizations_.length(); | 866 int length = deoptimizations_.length(); |
| 905 if (length == 0) return; | 867 if (length == 0) return; |
| 906 Handle<DeoptimizationInputData> data = | 868 Handle<DeoptimizationInputData> data = |
| 907 factory()->NewDeoptimizationInputData(length, TENURED); | 869 factory()->NewDeoptimizationInputData(length, TENURED); |
| 908 | 870 |
| 909 Handle<ByteArray> translations = | 871 Handle<ByteArray> translations = |
| (...skipping 1270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2180 | 2142 |
| 2181 BinaryOpStub stub(instr->op(), NO_OVERWRITE); | 2143 BinaryOpStub stub(instr->op(), NO_OVERWRITE); |
| 2182 // Block literal pool emission to ensure nop indicating no inlined smi code | 2144 // Block literal pool emission to ensure nop indicating no inlined smi code |
| 2183 // is in the correct position. | 2145 // is in the correct position. |
| 2184 Assembler::BlockConstPoolScope block_const_pool(masm()); | 2146 Assembler::BlockConstPoolScope block_const_pool(masm()); |
| 2185 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 2147 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 2186 __ nop(); // Signals no inlined code. | 2148 __ nop(); // Signals no inlined code. |
| 2187 } | 2149 } |
| 2188 | 2150 |
| 2189 | 2151 |
| 2190 int LCodeGen::GetNextEmittedBlock() const { | |
| 2191 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | |
| 2192 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | |
| 2193 } | |
| 2194 return -1; | |
| 2195 } | |
| 2196 | |
| 2197 template<class InstrType> | 2152 template<class InstrType> |
| 2198 void LCodeGen::EmitBranch(InstrType instr, Condition condition) { | 2153 void LCodeGen::EmitBranch(InstrType instr, Condition condition) { |
| 2199 int left_block = instr->TrueDestination(chunk_); | 2154 int left_block = instr->TrueDestination(chunk_); |
| 2200 int right_block = instr->FalseDestination(chunk_); | 2155 int right_block = instr->FalseDestination(chunk_); |
| 2201 | 2156 |
| 2202 int next_block = GetNextEmittedBlock(); | 2157 int next_block = GetNextEmittedBlock(); |
| 2203 | 2158 |
| 2204 if (right_block == left_block || condition == al) { | 2159 if (right_block == left_block || condition == al) { |
| 2205 EmitGoto(left_block); | 2160 EmitGoto(left_block); |
| 2206 } else if (left_block == next_block) { | 2161 } else if (left_block == next_block) { |
| (...skipping 878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3085 } | 3040 } |
| 3086 | 3041 |
| 3087 | 3042 |
| 3088 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 3043 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 3089 HObjectAccess access = instr->hydrogen()->access(); | 3044 HObjectAccess access = instr->hydrogen()->access(); |
| 3090 int offset = access.offset(); | 3045 int offset = access.offset(); |
| 3091 Register object = ToRegister(instr->object()); | 3046 Register object = ToRegister(instr->object()); |
| 3092 | 3047 |
| 3093 if (access.IsExternalMemory()) { | 3048 if (access.IsExternalMemory()) { |
| 3094 Register result = ToRegister(instr->result()); | 3049 Register result = ToRegister(instr->result()); |
| 3095 __ ldr(result, MemOperand(object, offset)); | 3050 MemOperand operand = MemOperand(object, offset); |
| 3051 if (access.representation().IsByte()) { |
| 3052 __ ldrb(result, operand); |
| 3053 } else { |
| 3054 __ ldr(result, operand); |
| 3055 } |
| 3096 return; | 3056 return; |
| 3097 } | 3057 } |
| 3098 | 3058 |
| 3099 if (instr->hydrogen()->representation().IsDouble()) { | 3059 if (instr->hydrogen()->representation().IsDouble()) { |
| 3100 DwVfpRegister result = ToDoubleRegister(instr->result()); | 3060 DwVfpRegister result = ToDoubleRegister(instr->result()); |
| 3101 __ vldr(result, FieldMemOperand(object, offset)); | 3061 __ vldr(result, FieldMemOperand(object, offset)); |
| 3102 return; | 3062 return; |
| 3103 } | 3063 } |
| 3104 | 3064 |
| 3105 Register result = ToRegister(instr->result()); | 3065 Register result = ToRegister(instr->result()); |
| 3106 if (access.IsInobject()) { | 3066 if (!access.IsInobject()) { |
| 3107 __ ldr(result, FieldMemOperand(object, offset)); | 3067 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 3068 object = result; |
| 3069 } |
| 3070 MemOperand operand = FieldMemOperand(object, offset); |
| 3071 if (access.representation().IsByte()) { |
| 3072 __ ldrb(result, operand); |
| 3108 } else { | 3073 } else { |
| 3109 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 3074 __ ldr(result, operand); |
| 3110 __ ldr(result, FieldMemOperand(result, offset)); | |
| 3111 } | 3075 } |
| 3112 } | 3076 } |
| 3113 | 3077 |
| 3114 | 3078 |
| 3115 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { | 3079 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { |
| 3116 ASSERT(ToRegister(instr->context()).is(cp)); | 3080 ASSERT(ToRegister(instr->context()).is(cp)); |
| 3117 ASSERT(ToRegister(instr->object()).is(r0)); | 3081 ASSERT(ToRegister(instr->object()).is(r0)); |
| 3118 ASSERT(ToRegister(instr->result()).is(r0)); | 3082 ASSERT(ToRegister(instr->result()).is(r0)); |
| 3119 | 3083 |
| 3120 // Name is always in r2. | 3084 // Name is always in r2. |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3284 | 3248 |
| 3285 | 3249 |
| 3286 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { | 3250 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
| 3287 Register elements = ToRegister(instr->elements()); | 3251 Register elements = ToRegister(instr->elements()); |
| 3288 bool key_is_constant = instr->key()->IsConstantOperand(); | 3252 bool key_is_constant = instr->key()->IsConstantOperand(); |
| 3289 Register key = no_reg; | 3253 Register key = no_reg; |
| 3290 DwVfpRegister result = ToDoubleRegister(instr->result()); | 3254 DwVfpRegister result = ToDoubleRegister(instr->result()); |
| 3291 Register scratch = scratch0(); | 3255 Register scratch = scratch0(); |
| 3292 | 3256 |
| 3293 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); | 3257 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); |
| 3294 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) | 3258 |
| 3295 ? (element_size_shift - kSmiTagSize) : element_size_shift; | 3259 int base_offset = |
| 3296 int constant_key = 0; | 3260 FixedDoubleArray::kHeaderSize - kHeapObjectTag + |
| 3261 (instr->additional_index() << element_size_shift); |
| 3297 if (key_is_constant) { | 3262 if (key_is_constant) { |
| 3298 constant_key = ToInteger32(LConstantOperand::cast(instr->key())); | 3263 int constant_key = ToInteger32(LConstantOperand::cast(instr->key())); |
| 3299 if (constant_key & 0xF0000000) { | 3264 if (constant_key & 0xF0000000) { |
| 3300 Abort(kArrayIndexConstantValueTooBig); | 3265 Abort(kArrayIndexConstantValueTooBig); |
| 3301 } | 3266 } |
| 3302 } else { | 3267 base_offset += constant_key << element_size_shift; |
| 3268 } |
| 3269 __ add(scratch, elements, Operand(base_offset)); |
| 3270 |
| 3271 if (!key_is_constant) { |
| 3303 key = ToRegister(instr->key()); | 3272 key = ToRegister(instr->key()); |
| 3273 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) |
| 3274 ? (element_size_shift - kSmiTagSize) : element_size_shift; |
| 3275 __ add(scratch, scratch, Operand(key, LSL, shift_size)); |
| 3304 } | 3276 } |
| 3305 | 3277 |
| 3306 int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) + | 3278 __ vldr(result, scratch, 0); |
| 3307 ((constant_key + instr->additional_index()) << element_size_shift); | 3279 |
| 3308 if (!key_is_constant) { | |
| 3309 __ add(elements, elements, Operand(key, LSL, shift_size)); | |
| 3310 } | |
| 3311 __ add(elements, elements, Operand(base_offset)); | |
| 3312 __ vldr(result, elements, 0); | |
| 3313 if (instr->hydrogen()->RequiresHoleCheck()) { | 3280 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3314 __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); | 3281 __ ldr(scratch, MemOperand(scratch, sizeof(kHoleNanLower32))); |
| 3315 __ cmp(scratch, Operand(kHoleNanUpper32)); | 3282 __ cmp(scratch, Operand(kHoleNanUpper32)); |
| 3316 DeoptimizeIf(eq, instr->environment()); | 3283 DeoptimizeIf(eq, instr->environment()); |
| 3317 } | 3284 } |
| 3318 } | 3285 } |
| 3319 | 3286 |
| 3320 | 3287 |
| 3321 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { | 3288 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { |
| 3322 Register elements = ToRegister(instr->elements()); | 3289 Register elements = ToRegister(instr->elements()); |
| 3323 Register result = ToRegister(instr->result()); | 3290 Register result = ToRegister(instr->result()); |
| 3324 Register scratch = scratch0(); | 3291 Register scratch = scratch0(); |
| 3325 Register store_base = scratch; | 3292 Register store_base = scratch; |
| 3326 int offset = 0; | 3293 int offset = 0; |
| 3327 | 3294 |
| 3328 if (instr->key()->IsConstantOperand()) { | 3295 if (instr->key()->IsConstantOperand()) { |
| 3329 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); | 3296 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
| 3330 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + | 3297 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + |
| 3331 instr->additional_index()); | 3298 instr->additional_index()); |
| 3332 store_base = elements; | 3299 store_base = elements; |
| 3333 } else { | 3300 } else { |
| 3334 Register key = EmitLoadRegister(instr->key(), scratch0()); | 3301 Register key = ToRegister(instr->key()); |
| 3335 // Even though the HLoadKeyed instruction forces the input | 3302 // Even though the HLoadKeyed instruction forces the input |
| 3336 // representation for the key to be an integer, the input gets replaced | 3303 // representation for the key to be an integer, the input gets replaced |
| 3337 // during bound check elimination with the index argument to the bounds | 3304 // during bound check elimination with the index argument to the bounds |
| 3338 // check, which can be tagged, so that case must be handled here, too. | 3305 // check, which can be tagged, so that case must be handled here, too. |
| 3339 if (instr->hydrogen()->key()->representation().IsSmi()) { | 3306 if (instr->hydrogen()->key()->representation().IsSmi()) { |
| 3340 __ add(scratch, elements, Operand::PointerOffsetFromSmiKey(key)); | 3307 __ add(scratch, elements, Operand::PointerOffsetFromSmiKey(key)); |
| 3341 } else { | 3308 } else { |
| 3342 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); | 3309 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
| 3343 } | 3310 } |
| 3344 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); | 3311 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
| (...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4203 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { | 4170 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { |
| 4204 Representation representation = instr->representation(); | 4171 Representation representation = instr->representation(); |
| 4205 | 4172 |
| 4206 Register object = ToRegister(instr->object()); | 4173 Register object = ToRegister(instr->object()); |
| 4207 Register scratch = scratch0(); | 4174 Register scratch = scratch0(); |
| 4208 HObjectAccess access = instr->hydrogen()->access(); | 4175 HObjectAccess access = instr->hydrogen()->access(); |
| 4209 int offset = access.offset(); | 4176 int offset = access.offset(); |
| 4210 | 4177 |
| 4211 if (access.IsExternalMemory()) { | 4178 if (access.IsExternalMemory()) { |
| 4212 Register value = ToRegister(instr->value()); | 4179 Register value = ToRegister(instr->value()); |
| 4213 __ str(value, MemOperand(object, offset)); | 4180 MemOperand operand = MemOperand(object, offset); |
| 4181 if (representation.IsByte()) { |
| 4182 __ strb(value, operand); |
| 4183 } else { |
| 4184 __ str(value, operand); |
| 4185 } |
| 4214 return; | 4186 return; |
| 4215 } | 4187 } |
| 4216 | 4188 |
| 4217 Handle<Map> transition = instr->transition(); | 4189 Handle<Map> transition = instr->transition(); |
| 4218 | 4190 |
| 4219 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { | 4191 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { |
| 4220 Register value = ToRegister(instr->value()); | 4192 Register value = ToRegister(instr->value()); |
| 4221 if (!instr->hydrogen()->value()->type().IsHeapObject()) { | 4193 if (!instr->hydrogen()->value()->type().IsHeapObject()) { |
| 4222 __ SmiTst(value); | 4194 __ SmiTst(value); |
| 4223 DeoptimizeIf(eq, instr->environment()); | 4195 DeoptimizeIf(eq, instr->environment()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4248 } | 4220 } |
| 4249 } | 4221 } |
| 4250 | 4222 |
| 4251 // Do the store. | 4223 // Do the store. |
| 4252 Register value = ToRegister(instr->value()); | 4224 Register value = ToRegister(instr->value()); |
| 4253 ASSERT(!object.is(value)); | 4225 ASSERT(!object.is(value)); |
| 4254 SmiCheck check_needed = | 4226 SmiCheck check_needed = |
| 4255 instr->hydrogen()->value()->IsHeapObject() | 4227 instr->hydrogen()->value()->IsHeapObject() |
| 4256 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4228 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4257 if (access.IsInobject()) { | 4229 if (access.IsInobject()) { |
| 4258 __ str(value, FieldMemOperand(object, offset)); | 4230 MemOperand operand = FieldMemOperand(object, offset); |
| 4231 if (representation.IsByte()) { |
| 4232 __ strb(value, operand); |
| 4233 } else { |
| 4234 __ str(value, operand); |
| 4235 } |
| 4259 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4236 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4260 // Update the write barrier for the object for in-object properties. | 4237 // Update the write barrier for the object for in-object properties. |
| 4261 __ RecordWriteField(object, | 4238 __ RecordWriteField(object, |
| 4262 offset, | 4239 offset, |
| 4263 value, | 4240 value, |
| 4264 scratch, | 4241 scratch, |
| 4265 GetLinkRegisterState(), | 4242 GetLinkRegisterState(), |
| 4266 kSaveFPRegs, | 4243 kSaveFPRegs, |
| 4267 EMIT_REMEMBERED_SET, | 4244 EMIT_REMEMBERED_SET, |
| 4268 check_needed); | 4245 check_needed); |
| 4269 } | 4246 } |
| 4270 } else { | 4247 } else { |
| 4271 __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 4248 __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 4272 __ str(value, FieldMemOperand(scratch, offset)); | 4249 MemOperand operand = FieldMemOperand(scratch, offset); |
| 4250 if (representation.IsByte()) { |
| 4251 __ strb(value, operand); |
| 4252 } else { |
| 4253 __ str(value, operand); |
| 4254 } |
| 4273 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4255 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4274 // Update the write barrier for the properties array. | 4256 // Update the write barrier for the properties array. |
| 4275 // object is used as a scratch register. | 4257 // object is used as a scratch register. |
| 4276 __ RecordWriteField(scratch, | 4258 __ RecordWriteField(scratch, |
| 4277 offset, | 4259 offset, |
| 4278 value, | 4260 value, |
| 4279 object, | 4261 object, |
| 4280 GetLinkRegisterState(), | 4262 GetLinkRegisterState(), |
| 4281 kSaveFPRegs, | 4263 kSaveFPRegs, |
| 4282 EMIT_REMEMBERED_SET, | 4264 EMIT_REMEMBERED_SET, |
| (...skipping 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5626 __ b(ne, &check_frame_marker); | 5608 __ b(ne, &check_frame_marker); |
| 5627 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset)); | 5609 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset)); |
| 5628 | 5610 |
| 5629 // Check the marker in the calling frame. | 5611 // Check the marker in the calling frame. |
| 5630 __ bind(&check_frame_marker); | 5612 __ bind(&check_frame_marker); |
| 5631 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset)); | 5613 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset)); |
| 5632 __ cmp(temp1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); | 5614 __ cmp(temp1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); |
| 5633 } | 5615 } |
| 5634 | 5616 |
| 5635 | 5617 |
| 5636 void LCodeGen::EnsureSpaceForLazyDeopt() { | 5618 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { |
| 5637 if (info()->IsStub()) return; | 5619 if (info()->IsStub()) return; |
| 5638 // Ensure that we have enough space after the previous lazy-bailout | 5620 // Ensure that we have enough space after the previous lazy-bailout |
| 5639 // instruction for patching the code here. | 5621 // instruction for patching the code here. |
| 5640 int current_pc = masm()->pc_offset(); | 5622 int current_pc = masm()->pc_offset(); |
| 5641 int patch_size = Deoptimizer::patch_size(); | 5623 if (current_pc < last_lazy_deopt_pc_ + space_needed) { |
| 5642 if (current_pc < last_lazy_deopt_pc_ + patch_size) { | |
| 5643 // Block literal pool emission for duration of padding. | 5624 // Block literal pool emission for duration of padding. |
| 5644 Assembler::BlockConstPoolScope block_const_pool(masm()); | 5625 Assembler::BlockConstPoolScope block_const_pool(masm()); |
| 5645 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; | 5626 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; |
| 5646 ASSERT_EQ(0, padding_size % Assembler::kInstrSize); | 5627 ASSERT_EQ(0, padding_size % Assembler::kInstrSize); |
| 5647 while (padding_size > 0) { | 5628 while (padding_size > 0) { |
| 5648 __ nop(); | 5629 __ nop(); |
| 5649 padding_size -= Assembler::kInstrSize; | 5630 padding_size -= Assembler::kInstrSize; |
| 5650 } | 5631 } |
| 5651 } | 5632 } |
| 5652 } | 5633 } |
| 5653 | 5634 |
| 5654 | 5635 |
| 5655 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { | 5636 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { |
| 5656 EnsureSpaceForLazyDeopt(); | 5637 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 5657 last_lazy_deopt_pc_ = masm()->pc_offset(); | 5638 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 5658 ASSERT(instr->HasEnvironment()); | 5639 ASSERT(instr->HasEnvironment()); |
| 5659 LEnvironment* env = instr->environment(); | 5640 LEnvironment* env = instr->environment(); |
| 5660 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); | 5641 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 5661 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | 5642 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 5662 } | 5643 } |
| 5663 | 5644 |
| 5664 | 5645 |
| 5665 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 5646 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
| 5666 Deoptimizer::BailoutType type = instr->hydrogen()->type(); | 5647 Deoptimizer::BailoutType type = instr->hydrogen()->type(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5716 Label done; | 5697 Label done; |
| 5717 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 5698 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| 5718 __ cmp(sp, Operand(ip)); | 5699 __ cmp(sp, Operand(ip)); |
| 5719 __ b(hs, &done); | 5700 __ b(hs, &done); |
| 5720 PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); | 5701 PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); |
| 5721 ASSERT(instr->context()->IsRegister()); | 5702 ASSERT(instr->context()->IsRegister()); |
| 5722 ASSERT(ToRegister(instr->context()).is(cp)); | 5703 ASSERT(ToRegister(instr->context()).is(cp)); |
| 5723 CallCode(isolate()->builtins()->StackCheck(), | 5704 CallCode(isolate()->builtins()->StackCheck(), |
| 5724 RelocInfo::CODE_TARGET, | 5705 RelocInfo::CODE_TARGET, |
| 5725 instr); | 5706 instr); |
| 5726 EnsureSpaceForLazyDeopt(); | 5707 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 5727 last_lazy_deopt_pc_ = masm()->pc_offset(); | 5708 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 5728 __ bind(&done); | 5709 __ bind(&done); |
| 5729 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); | 5710 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 5730 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | 5711 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 5731 } else { | 5712 } else { |
| 5732 ASSERT(instr->hydrogen()->is_backwards_branch()); | 5713 ASSERT(instr->hydrogen()->is_backwards_branch()); |
| 5733 // Perform stack overflow check if this goto needs it before jumping. | 5714 // Perform stack overflow check if this goto needs it before jumping. |
| 5734 DeferredStackCheck* deferred_stack_check = | 5715 DeferredStackCheck* deferred_stack_check = |
| 5735 new(zone()) DeferredStackCheck(this, instr); | 5716 new(zone()) DeferredStackCheck(this, instr); |
| 5736 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 5717 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| 5737 __ cmp(sp, Operand(ip)); | 5718 __ cmp(sp, Operand(ip)); |
| 5738 __ b(lo, deferred_stack_check->entry()); | 5719 __ b(lo, deferred_stack_check->entry()); |
| 5739 EnsureSpaceForLazyDeopt(); | 5720 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 5740 last_lazy_deopt_pc_ = masm()->pc_offset(); | 5721 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 5741 __ bind(instr->done_label()); | 5722 __ bind(instr->done_label()); |
| 5742 deferred_stack_check->SetExit(instr->done_label()); | 5723 deferred_stack_check->SetExit(instr->done_label()); |
| 5743 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); | 5724 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 5744 // Don't record a deoptimization index for the safepoint here. | 5725 // Don't record a deoptimization index for the safepoint here. |
| 5745 // This will be done explicitly when emitting call and the safepoint in | 5726 // This will be done explicitly when emitting call and the safepoint in |
| 5746 // the deferred code. | 5727 // the deferred code. |
| 5747 } | 5728 } |
| 5748 } | 5729 } |
| 5749 | 5730 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5853 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); | 5834 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); |
| 5854 __ ldr(result, FieldMemOperand(scratch, | 5835 __ ldr(result, FieldMemOperand(scratch, |
| 5855 FixedArray::kHeaderSize - kPointerSize)); | 5836 FixedArray::kHeaderSize - kPointerSize)); |
| 5856 __ bind(&done); | 5837 __ bind(&done); |
| 5857 } | 5838 } |
| 5858 | 5839 |
| 5859 | 5840 |
| 5860 #undef __ | 5841 #undef __ |
| 5861 | 5842 |
| 5862 } } // namespace v8::internal | 5843 } } // namespace v8::internal |
| OLD | NEW |