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