1 // Copyright 2012 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 #ifndef V8_CRANKSHAFT_X64_LITHIUM_CODEGEN_X64_H_ 6 #define V8_CRANKSHAFT_X64_LITHIUM_CODEGEN_X64_H_ 7 8 9 #include "src/ast/scopes.h" 10 #include "src/base/logging.h" 11 #include "src/crankshaft/lithium-codegen.h" 12 #include "src/crankshaft/x64/lithium-gap-resolver-x64.h" 13 #include "src/crankshaft/x64/lithium-x64.h" 14 #include "src/deoptimizer.h" 15 #include "src/safepoint-table.h" 16 #include "src/utils.h" 17 18 namespace v8 { 19 namespace internal { 20 21 // Forward declarations. 22 class LDeferredCode; 23 class SafepointGenerator; 24 25 class LCodeGen: public LCodeGenBase { 26 public: LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)27 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 28 : LCodeGenBase(chunk, assembler, info), 29 jump_table_(4, info->zone()), 30 scope_(info->scope()), 31 deferred_(8, info->zone()), 32 frame_is_built_(false), 33 safepoints_(info->zone()), 34 resolver_(this), 35 expected_safepoint_kind_(Safepoint::kSimple) { 36 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 37 } 38 LookupDestination(int block_id)39 int LookupDestination(int block_id) const { 40 return chunk()->LookupDestination(block_id); 41 } 42 IsNextEmittedBlock(int block_id)43 bool IsNextEmittedBlock(int block_id) const { 44 return LookupDestination(block_id) == GetNextEmittedBlock(); 45 } 46 NeedsEagerFrame()47 bool NeedsEagerFrame() const { 48 return GetStackSlotCount() > 0 || 49 info()->is_non_deferred_calling() || 50 !info()->IsStub() || 51 info()->requires_frame(); 52 } NeedsDeferredFrame()53 bool NeedsDeferredFrame() const { 54 return !NeedsEagerFrame() && info()->is_deferred_calling(); 55 } 56 57 // Support for converting LOperands to assembler types. 58 Register ToRegister(LOperand* op) const; 59 XMMRegister ToDoubleRegister(LOperand* op) const; 60 bool IsInteger32Constant(LConstantOperand* op) const; 61 bool IsExternalConstant(LConstantOperand* op) const; 62 bool IsDehoistedKeyConstant(LConstantOperand* op) const; 63 bool IsSmiConstant(LConstantOperand* op) const; 64 int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; 65 int32_t ToInteger32(LConstantOperand* op) const; 66 Smi* ToSmi(LConstantOperand* op) const; 67 double ToDouble(LConstantOperand* op) const; 68 ExternalReference ToExternalReference(LConstantOperand* op) const; 69 Handle<Object> ToHandle(LConstantOperand* op) const; 70 Operand ToOperand(LOperand* op) const; 71 72 // Try to generate code for the entire chunk, but it may fail if the 73 // chunk contains constructs we cannot handle. Returns true if the 74 // code generation attempt succeeded. 75 bool GenerateCode(); 76 77 // Finish the code by setting stack height, safepoint, and bailout 78 // information on it. 79 void FinishCode(Handle<Code> code); 80 81 // Deferred code support. 82 void DoDeferredNumberTagD(LNumberTagD* instr); 83 84 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; 85 void DoDeferredNumberTagIU(LInstruction* instr, 86 LOperand* value, 87 LOperand* temp1, 88 LOperand* temp2, 89 IntegerSignedness signedness); 90 91 void DoDeferredTaggedToI(LTaggedToI* instr, Label* done); 92 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 93 void DoDeferredStackCheck(LStackCheck* instr); 94 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr); 95 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 96 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 97 void DoDeferredAllocate(LAllocate* instr); 98 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 99 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, 100 Register object, 101 Register index); 102 103 // Parallel move support. 104 void DoParallelMove(LParallelMove* move); 105 void DoGap(LGap* instr); 106 107 // Emit frame translation commands for an environment. 108 void WriteTranslation(LEnvironment* environment, Translation* translation); 109 110 // Declare methods that deal with the individual node types. 111 #define DECLARE_DO(type) void Do##type(L##type* node); LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)112 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 113 #undef DECLARE_DO 114 115 private: 116 LanguageMode language_mode() const { return info()->language_mode(); } 117 chunk()118 LPlatformChunk* chunk() const { return chunk_; } scope()119 Scope* scope() const { return scope_; } graph()120 HGraph* graph() const { return chunk()->graph(); } 121 double_scratch0()122 XMMRegister double_scratch0() const { return xmm0; } 123 124 void EmitClassOfTest(Label* if_true, 125 Label* if_false, 126 Handle<String> class_name, 127 Register input, 128 Register temporary, 129 Register scratch); 130 GetStackSlotCount()131 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 132 AddDeferredCode(LDeferredCode * code)133 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 134 135 136 void SaveCallerDoubles(); 137 void RestoreCallerDoubles(); 138 139 // Code generation passes. Returns true if code generation should 140 // continue. 141 void GenerateBodyInstructionPre(LInstruction* instr) override; 142 void GenerateBodyInstructionPost(LInstruction* instr) override; 143 bool GeneratePrologue(); 144 bool GenerateDeferredCode(); 145 bool GenerateJumpTable(); 146 bool GenerateSafepointTable(); 147 148 // Generates the custom OSR entrypoint and sets the osr_pc_offset. 149 void GenerateOsrPrologue(); 150 151 enum SafepointMode { 152 RECORD_SIMPLE_SAFEPOINT, 153 RECORD_SAFEPOINT_WITH_REGISTERS 154 }; 155 156 void CallCodeGeneric(Handle<Code> code, 157 RelocInfo::Mode mode, 158 LInstruction* instr, 159 SafepointMode safepoint_mode, 160 int argc); 161 162 163 void CallCode(Handle<Code> code, 164 RelocInfo::Mode mode, 165 LInstruction* instr); 166 167 void CallRuntime(const Runtime::Function* function, 168 int num_arguments, 169 LInstruction* instr, 170 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 171 CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)172 void CallRuntime(Runtime::FunctionId id, 173 int num_arguments, 174 LInstruction* instr) { 175 const Runtime::Function* function = Runtime::FunctionForId(id); 176 CallRuntime(function, num_arguments, instr); 177 } 178 CallRuntime(Runtime::FunctionId id,LInstruction * instr)179 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) { 180 const Runtime::Function* function = Runtime::FunctionForId(id); 181 CallRuntime(function, function->nargs, instr); 182 } 183 184 void CallRuntimeFromDeferred(Runtime::FunctionId id, 185 int argc, 186 LInstruction* instr, 187 LOperand* context); 188 189 void LoadContextFromDeferred(LOperand* context); 190 191 // Generate a direct call to a known function. Expects the function 192 // to be in rdi. 193 void CallKnownFunction(Handle<JSFunction> function, 194 int formal_parameter_count, int arity, 195 LInstruction* instr); 196 197 void RecordSafepointWithLazyDeopt(LInstruction* instr, 198 SafepointMode safepoint_mode, 199 int argc); 200 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 201 Safepoint::DeoptMode mode); 202 void DeoptimizeIf(Condition cc, LInstruction* instr, 203 Deoptimizer::DeoptReason deopt_reason, 204 Deoptimizer::BailoutType bailout_type); 205 void DeoptimizeIf(Condition cc, LInstruction* instr, 206 Deoptimizer::DeoptReason deopt_reason); 207 DeoptEveryNTimes()208 bool DeoptEveryNTimes() { 209 return FLAG_deopt_every_n_times != 0 && !info()->IsStub(); 210 } 211 212 void AddToTranslation(LEnvironment* environment, 213 Translation* translation, 214 LOperand* op, 215 bool is_tagged, 216 bool is_uint32, 217 int* object_index_pointer, 218 int* dematerialized_index_pointer); 219 220 Register ToRegister(int index) const; 221 XMMRegister ToDoubleRegister(int index) const; 222 Operand BuildFastArrayOperand( 223 LOperand* elements_pointer, 224 LOperand* key, 225 Representation key_representation, 226 ElementsKind elements_kind, 227 uint32_t base_offset); 228 229 Operand BuildSeqStringOperand(Register string, 230 LOperand* index, 231 String::Encoding encoding); 232 233 void EmitIntegerMathAbs(LMathAbs* instr); 234 void EmitSmiMathAbs(LMathAbs* instr); 235 236 // Support for recording safepoint and position information. 237 void RecordSafepoint(LPointerMap* pointers, 238 Safepoint::Kind kind, 239 int arguments, 240 Safepoint::DeoptMode mode); 241 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 242 void RecordSafepoint(Safepoint::DeoptMode mode); 243 void RecordSafepointWithRegisters(LPointerMap* pointers, 244 int arguments, 245 Safepoint::DeoptMode mode); 246 void RecordAndWritePosition(int position) override; 247 248 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 249 void EmitGoto(int block); 250 251 // EmitBranch expects to be the last instruction of a block. 252 template<class InstrType> 253 void EmitBranch(InstrType instr, Condition cc); 254 template <class InstrType> 255 void EmitTrueBranch(InstrType instr, Condition cc); 256 template <class InstrType> 257 void EmitFalseBranch(InstrType instr, Condition cc); 258 void EmitNumberUntagD(LNumberUntagD* instr, Register input, 259 XMMRegister result, NumberUntagDMode mode); 260 261 // Emits optimized code for typeof x == "y". Modifies input register. 262 // Returns the condition on which a final split to 263 // true and false label should be made, to optimize fallthrough. 264 Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input); 265 266 // Emits optimized code for %_IsString(x). Preserves input register. 267 // Returns the condition on which a final split to 268 // true and false label should be made, to optimize fallthrough. 269 Condition EmitIsString(Register input, 270 Register temp1, 271 Label* is_not_string, 272 SmiCheck check_needed); 273 274 // Emits code for pushing either a tagged constant, a (non-double) 275 // register, or a stack slot operand. 276 void EmitPushTaggedOperand(LOperand* operand); 277 278 // Emits optimized code to deep-copy the contents of statically known 279 // object graphs (e.g. object literal boilerplate). 280 void EmitDeepCopy(Handle<JSObject> object, 281 Register result, 282 Register source, 283 int* offset, 284 AllocationSiteMode mode); 285 286 void EnsureSpaceForLazyDeopt(int space_needed) override; 287 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 288 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 289 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 290 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 291 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 292 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 293 294 template <class T> 295 void EmitVectorLoadICRegisters(T* instr); 296 template <class T> 297 void EmitVectorStoreICRegisters(T* instr); 298 299 #ifdef _MSC_VER 300 // On windows, you may not access the stack more than one page below 301 // the most recently mapped page. To make the allocated area randomly 302 // accessible, we write an arbitrary value to each page in range 303 // rsp + offset - page_size .. rsp in turn. 304 void MakeSureStackPagesMapped(int offset); 305 #endif 306 307 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; 308 Scope* const scope_; 309 ZoneList<LDeferredCode*> deferred_; 310 bool frame_is_built_; 311 312 // Builder that keeps track of safepoints in the code. The table 313 // itself is emitted at the end of the generated code. 314 SafepointTableBuilder safepoints_; 315 316 // Compiler from a set of parallel moves to a sequential list of moves. 317 LGapResolver resolver_; 318 319 Safepoint::Kind expected_safepoint_kind_; 320 321 class PushSafepointRegistersScope final BASE_EMBEDDED { 322 public: PushSafepointRegistersScope(LCodeGen * codegen)323 explicit PushSafepointRegistersScope(LCodeGen* codegen) 324 : codegen_(codegen) { 325 DCHECK(codegen_->info()->is_calling()); 326 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 327 codegen_->masm_->PushSafepointRegisters(); 328 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 329 } 330 ~PushSafepointRegistersScope()331 ~PushSafepointRegistersScope() { 332 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 333 codegen_->masm_->PopSafepointRegisters(); 334 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 335 } 336 337 private: 338 LCodeGen* codegen_; 339 }; 340 341 friend class LDeferredCode; 342 friend class LEnvironment; 343 friend class SafepointGenerator; 344 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 345 }; 346 347 348 class LDeferredCode: public ZoneObject { 349 public: LDeferredCode(LCodeGen * codegen)350 explicit LDeferredCode(LCodeGen* codegen) 351 : codegen_(codegen), 352 external_exit_(NULL), 353 instruction_index_(codegen->current_instruction_) { 354 codegen->AddDeferredCode(this); 355 } 356 ~LDeferredCode()357 virtual ~LDeferredCode() {} 358 virtual void Generate() = 0; 359 virtual LInstruction* instr() = 0; 360 SetExit(Label * exit)361 void SetExit(Label* exit) { external_exit_ = exit; } entry()362 Label* entry() { return &entry_; } exit()363 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } done()364 Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); } instruction_index()365 int instruction_index() const { return instruction_index_; } 366 367 protected: codegen()368 LCodeGen* codegen() const { return codegen_; } masm()369 MacroAssembler* masm() const { return codegen_->masm(); } 370 371 private: 372 LCodeGen* codegen_; 373 Label entry_; 374 Label exit_; 375 Label done_; 376 Label* external_exit_; 377 int instruction_index_; 378 }; 379 380 } // namespace internal 381 } // namespace v8 382 383 #endif // V8_CRANKSHAFT_X64_LITHIUM_CODEGEN_X64_H_ 384