1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #include "src/lithium-codegen.h" 8 9 #if V8_TARGET_ARCH_IA32 10 #include "src/ia32/lithium-ia32.h" 11 #include "src/ia32/lithium-codegen-ia32.h" 12 #elif V8_TARGET_ARCH_X64 13 #include "src/x64/lithium-x64.h" 14 #include "src/x64/lithium-codegen-x64.h" 15 #elif V8_TARGET_ARCH_ARM 16 #include "src/arm/lithium-arm.h" 17 #include "src/arm/lithium-codegen-arm.h" 18 #elif V8_TARGET_ARCH_ARM64 19 #include "src/arm64/lithium-arm64.h" 20 #include "src/arm64/lithium-codegen-arm64.h" 21 #elif V8_TARGET_ARCH_MIPS 22 #include "src/mips/lithium-mips.h" 23 #include "src/mips/lithium-codegen-mips.h" 24 #elif V8_TARGET_ARCH_X87 25 #include "src/x87/lithium-x87.h" 26 #include "src/x87/lithium-codegen-x87.h" 27 #else 28 #error Unsupported target architecture. 29 #endif 30 31 namespace v8 { 32 namespace internal { 33 34 35 HGraph* LCodeGenBase::graph() const { 36 return chunk()->graph(); 37 } 38 39 40 LCodeGenBase::LCodeGenBase(LChunk* chunk, 41 MacroAssembler* assembler, 42 CompilationInfo* info) 43 : chunk_(static_cast<LPlatformChunk*>(chunk)), 44 masm_(assembler), 45 info_(info), 46 zone_(info->zone()), 47 status_(UNUSED), 48 current_block_(-1), 49 current_instruction_(-1), 50 instructions_(chunk->instructions()), 51 last_lazy_deopt_pc_(0) { 52 } 53 54 55 bool LCodeGenBase::GenerateBody() { 56 ASSERT(is_generating()); 57 bool emit_instructions = true; 58 LCodeGen* codegen = static_cast<LCodeGen*>(this); 59 for (current_instruction_ = 0; 60 !is_aborted() && current_instruction_ < instructions_->length(); 61 current_instruction_++) { 62 LInstruction* instr = instructions_->at(current_instruction_); 63 64 // Don't emit code for basic blocks with a replacement. 65 if (instr->IsLabel()) { 66 emit_instructions = !LLabel::cast(instr)->HasReplacement() && 67 (!FLAG_unreachable_code_elimination || 68 instr->hydrogen_value()->block()->IsReachable()); 69 if (FLAG_code_comments && !emit_instructions) { 70 Comment( 71 ";;; <@%d,#%d> -------------------- B%d (unreachable/replaced) " 72 "--------------------", 73 current_instruction_, 74 instr->hydrogen_value()->id(), 75 instr->hydrogen_value()->block()->block_id()); 76 } 77 } 78 if (!emit_instructions) continue; 79 80 if (FLAG_code_comments && instr->HasInterestingComment(codegen)) { 81 Comment(";;; <@%d,#%d> %s", 82 current_instruction_, 83 instr->hydrogen_value()->id(), 84 instr->Mnemonic()); 85 } 86 87 GenerateBodyInstructionPre(instr); 88 89 HValue* value = instr->hydrogen_value(); 90 if (!value->position().IsUnknown()) { 91 RecordAndWritePosition( 92 chunk()->graph()->SourcePositionToScriptPosition(value->position())); 93 } 94 95 instr->CompileToNative(codegen); 96 97 GenerateBodyInstructionPost(instr); 98 } 99 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 100 last_lazy_deopt_pc_ = masm()->pc_offset(); 101 return !is_aborted(); 102 } 103 104 105 void LCodeGenBase::CheckEnvironmentUsage() { 106 #ifdef DEBUG 107 bool dead_block = false; 108 for (int i = 0; i < instructions_->length(); i++) { 109 LInstruction* instr = instructions_->at(i); 110 HValue* hval = instr->hydrogen_value(); 111 if (instr->IsLabel()) dead_block = LLabel::cast(instr)->HasReplacement(); 112 if (dead_block || !hval->block()->IsReachable()) continue; 113 114 HInstruction* hinstr = HInstruction::cast(hval); 115 if (!hinstr->CanDeoptimize() && instr->HasEnvironment()) { 116 V8_Fatal(__FILE__, __LINE__, "CanDeoptimize is wrong for %s (%s)\n", 117 hinstr->Mnemonic(), instr->Mnemonic()); 118 } 119 120 if (instr->HasEnvironment() && !instr->environment()->has_been_used()) { 121 V8_Fatal(__FILE__, __LINE__, "unused environment for %s (%s)\n", 122 hinstr->Mnemonic(), instr->Mnemonic()); 123 } 124 } 125 #endif 126 } 127 128 129 void LCodeGenBase::Comment(const char* format, ...) { 130 if (!FLAG_code_comments) return; 131 char buffer[4 * KB]; 132 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); 133 va_list arguments; 134 va_start(arguments, format); 135 builder.AddFormattedList(format, arguments); 136 va_end(arguments); 137 138 // Copy the string before recording it in the assembler to avoid 139 // issues when the stack allocated buffer goes out of scope. 140 size_t length = builder.position(); 141 Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1); 142 MemCopy(copy.start(), builder.Finalize(), copy.length()); 143 masm()->RecordComment(copy.start()); 144 } 145 146 147 int LCodeGenBase::GetNextEmittedBlock() const { 148 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { 149 if (!graph()->blocks()->at(i)->IsReachable()) continue; 150 if (!chunk_->GetLabel(i)->HasReplacement()) return i; 151 } 152 return -1; 153 } 154 155 156 static void AddWeakObjectToCodeDependency(Isolate* isolate, 157 Handle<Object> object, 158 Handle<Code> code) { 159 Heap* heap = isolate->heap(); 160 heap->EnsureWeakObjectToCodeTable(); 161 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); 162 dep = DependentCode::Insert(dep, DependentCode::kWeakCodeGroup, code); 163 heap->AddWeakObjectToCodeDependency(object, dep); 164 } 165 166 167 void LCodeGenBase::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) { 168 ASSERT(code->is_optimized_code()); 169 ZoneList<Handle<Map> > maps(1, zone()); 170 ZoneList<Handle<JSObject> > objects(1, zone()); 171 ZoneList<Handle<Cell> > cells(1, zone()); 172 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 173 RelocInfo::ModeMask(RelocInfo::CELL); 174 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { 175 RelocInfo::Mode mode = it.rinfo()->rmode(); 176 if (mode == RelocInfo::CELL && 177 code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) { 178 Handle<Cell> cell(it.rinfo()->target_cell()); 179 cells.Add(cell, zone()); 180 } else if (mode == RelocInfo::EMBEDDED_OBJECT && 181 code->IsWeakObjectInOptimizedCode(it.rinfo()->target_object())) { 182 if (it.rinfo()->target_object()->IsMap()) { 183 Handle<Map> map(Map::cast(it.rinfo()->target_object())); 184 maps.Add(map, zone()); 185 } else if (it.rinfo()->target_object()->IsJSObject()) { 186 Handle<JSObject> object(JSObject::cast(it.rinfo()->target_object())); 187 objects.Add(object, zone()); 188 } else if (it.rinfo()->target_object()->IsCell()) { 189 Handle<Cell> cell(Cell::cast(it.rinfo()->target_object())); 190 cells.Add(cell, zone()); 191 } 192 } 193 } 194 if (FLAG_enable_ool_constant_pool) { 195 code->constant_pool()->set_weak_object_state( 196 ConstantPoolArray::WEAK_OBJECTS_IN_OPTIMIZED_CODE); 197 } 198 #ifdef VERIFY_HEAP 199 // This disables verification of weak embedded objects after full GC. 200 // AddDependentCode can cause a GC, which would observe the state where 201 // this code is not yet in the depended code lists of the embedded maps. 202 NoWeakObjectVerificationScope disable_verification_of_embedded_objects; 203 #endif 204 for (int i = 0; i < maps.length(); i++) { 205 Map::AddDependentCode(maps.at(i), DependentCode::kWeakCodeGroup, code); 206 } 207 for (int i = 0; i < objects.length(); i++) { 208 AddWeakObjectToCodeDependency(isolate(), objects.at(i), code); 209 } 210 for (int i = 0; i < cells.length(); i++) { 211 AddWeakObjectToCodeDependency(isolate(), cells.at(i), code); 212 } 213 } 214 215 216 void LCodeGenBase::Abort(BailoutReason reason) { 217 info()->set_bailout_reason(reason); 218 status_ = ABORTED; 219 } 220 221 222 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) { 223 if (map->is_deprecated()) return Abort(kMapBecameDeprecated); 224 chunk_->AddDeprecationDependency(map); 225 } 226 227 228 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) { 229 if (!map->is_stable()) return Abort(kMapBecameUnstable); 230 chunk_->AddStabilityDependency(map); 231 } 232 233 } } // namespace v8::internal 234