1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_X64_LITHIUM_CODEGEN_X64_H_ 29 #define V8_X64_LITHIUM_CODEGEN_X64_H_ 30 31 #include "x64/lithium-x64.h" 32 33 #include "checks.h" 34 #include "deoptimizer.h" 35 #include "safepoint-table.h" 36 #include "scopes.h" 37 #include "x64/lithium-gap-resolver-x64.h" 38 39 namespace v8 { 40 namespace internal { 41 42 // Forward declarations. 43 class LDeferredCode; 44 class SafepointGenerator; 45 46 class LCodeGen BASE_EMBEDDED { 47 public: 48 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 49 : chunk_(chunk), 50 masm_(assembler), 51 info_(info), 52 current_block_(-1), 53 current_instruction_(-1), 54 instructions_(chunk->instructions()), 55 deoptimizations_(4), 56 jump_table_(4), 57 deoptimization_literals_(8), 58 inlined_function_count_(0), 59 scope_(info->scope()), 60 status_(UNUSED), 61 deferred_(8), 62 osr_pc_offset_(-1), 63 last_lazy_deopt_pc_(0), 64 resolver_(this), 65 expected_safepoint_kind_(Safepoint::kSimple) { 66 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 67 } 68 69 // Simple accessors. 70 MacroAssembler* masm() const { return masm_; } 71 CompilationInfo* info() const { return info_; } 72 Isolate* isolate() const { return info_->isolate(); } 73 Factory* factory() const { return isolate()->factory(); } 74 Heap* heap() const { return isolate()->heap(); } 75 76 // Support for converting LOperands to assembler types. 77 Register ToRegister(LOperand* op) const; 78 XMMRegister ToDoubleRegister(LOperand* op) const; 79 bool IsInteger32Constant(LConstantOperand* op) const; 80 int ToInteger32(LConstantOperand* op) const; 81 double ToDouble(LConstantOperand* op) const; 82 bool IsTaggedConstant(LConstantOperand* op) const; 83 Handle<Object> ToHandle(LConstantOperand* op) const; 84 Operand ToOperand(LOperand* op) const; 85 86 // Try to generate code for the entire chunk, but it may fail if the 87 // chunk contains constructs we cannot handle. Returns true if the 88 // code generation attempt succeeded. 89 bool GenerateCode(); 90 91 // Finish the code by setting stack height, safepoint, and bailout 92 // information on it. 93 void FinishCode(Handle<Code> code); 94 95 // Deferred code support. 96 void DoDeferredNumberTagD(LNumberTagD* instr); 97 void DoDeferredTaggedToI(LTaggedToI* instr); 98 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); 99 void DoDeferredStackCheck(LStackCheck* instr); 100 void DoDeferredRandom(LRandom* instr); 101 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 102 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 103 void DoDeferredAllocateObject(LAllocateObject* instr); 104 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 105 Label* map_check); 106 107 void DoCheckMapCommon(Register reg, Handle<Map> map, 108 CompareMapMode mode, LEnvironment* env); 109 110 // Parallel move support. 111 void DoParallelMove(LParallelMove* move); 112 void DoGap(LGap* instr); 113 114 // Emit frame translation commands for an environment. 115 void WriteTranslation(LEnvironment* environment, Translation* translation); 116 117 // Declare methods that deal with the individual node types. 118 #define DECLARE_DO(type) void Do##type(L##type* node); 119 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 120 #undef DECLARE_DO 121 122 private: 123 enum Status { 124 UNUSED, 125 GENERATING, 126 DONE, 127 ABORTED 128 }; 129 130 bool is_unused() const { return status_ == UNUSED; } 131 bool is_generating() const { return status_ == GENERATING; } 132 bool is_done() const { return status_ == DONE; } 133 bool is_aborted() const { return status_ == ABORTED; } 134 135 StrictModeFlag strict_mode_flag() const { 136 return info()->is_classic_mode() ? kNonStrictMode : kStrictMode; 137 } 138 139 LChunk* chunk() const { return chunk_; } 140 Scope* scope() const { return scope_; } 141 HGraph* graph() const { return chunk_->graph(); } 142 143 int GetNextEmittedBlock(int block); 144 145 void EmitClassOfTest(Label* if_true, 146 Label* if_false, 147 Handle<String> class_name, 148 Register input, 149 Register temporary, 150 Register scratch); 151 152 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 153 int GetParameterCount() const { return scope()->num_parameters(); } 154 155 void Abort(const char* format, ...); 156 void Comment(const char* format, ...); 157 158 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); } 159 160 // Code generation passes. Returns true if code generation should 161 // continue. 162 bool GeneratePrologue(); 163 bool GenerateBody(); 164 bool GenerateDeferredCode(); 165 bool GenerateJumpTable(); 166 bool GenerateSafepointTable(); 167 168 enum SafepointMode { 169 RECORD_SIMPLE_SAFEPOINT, 170 RECORD_SAFEPOINT_WITH_REGISTERS 171 }; 172 173 void CallCodeGeneric(Handle<Code> code, 174 RelocInfo::Mode mode, 175 LInstruction* instr, 176 SafepointMode safepoint_mode, 177 int argc); 178 179 180 void CallCode(Handle<Code> code, 181 RelocInfo::Mode mode, 182 LInstruction* instr); 183 184 void CallRuntime(const Runtime::Function* function, 185 int num_arguments, 186 LInstruction* instr); 187 188 void CallRuntime(Runtime::FunctionId id, 189 int num_arguments, 190 LInstruction* instr) { 191 const Runtime::Function* function = Runtime::FunctionForId(id); 192 CallRuntime(function, num_arguments, instr); 193 } 194 195 void CallRuntimeFromDeferred(Runtime::FunctionId id, 196 int argc, 197 LInstruction* instr); 198 199 // Generate a direct call to a known function. Expects the function 200 // to be in rdi. 201 void CallKnownFunction(Handle<JSFunction> function, 202 int arity, 203 LInstruction* instr, 204 CallKind call_kind); 205 206 207 void RecordSafepointWithLazyDeopt(LInstruction* instr, 208 SafepointMode safepoint_mode, 209 int argc); 210 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 211 Safepoint::DeoptMode mode); 212 void DeoptimizeIf(Condition cc, LEnvironment* environment); 213 214 void AddToTranslation(Translation* translation, 215 LOperand* op, 216 bool is_tagged); 217 void PopulateDeoptimizationData(Handle<Code> code); 218 int DefineDeoptimizationLiteral(Handle<Object> literal); 219 220 void PopulateDeoptimizationLiteralsWithInlinedFunctions(); 221 222 Register ToRegister(int index) const; 223 XMMRegister ToDoubleRegister(int index) const; 224 Operand BuildFastArrayOperand( 225 LOperand* elements_pointer, 226 LOperand* key, 227 ElementsKind elements_kind, 228 uint32_t offset); 229 230 // Specific math operations - used from DoUnaryMathOperation. 231 void EmitIntegerMathAbs(LUnaryMathOperation* instr); 232 void DoMathAbs(LUnaryMathOperation* instr); 233 void DoMathFloor(LUnaryMathOperation* instr); 234 void DoMathRound(LUnaryMathOperation* instr); 235 void DoMathSqrt(LUnaryMathOperation* instr); 236 void DoMathPowHalf(LUnaryMathOperation* instr); 237 void DoMathLog(LUnaryMathOperation* instr); 238 void DoMathTan(LUnaryMathOperation* instr); 239 void DoMathCos(LUnaryMathOperation* instr); 240 void DoMathSin(LUnaryMathOperation* instr); 241 242 // Support for recording safepoint and position information. 243 void RecordSafepoint(LPointerMap* pointers, 244 Safepoint::Kind kind, 245 int arguments, 246 Safepoint::DeoptMode mode); 247 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 248 void RecordSafepoint(Safepoint::DeoptMode mode); 249 void RecordSafepointWithRegisters(LPointerMap* pointers, 250 int arguments, 251 Safepoint::DeoptMode mode); 252 void RecordPosition(int position); 253 254 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 255 void EmitGoto(int block); 256 void EmitBranch(int left_block, int right_block, Condition cc); 257 void EmitNumberUntagD(Register input, 258 XMMRegister result, 259 bool deoptimize_on_undefined, 260 bool deoptimize_on_minus_zero, 261 LEnvironment* env); 262 263 // Emits optimized code for typeof x == "y". Modifies input register. 264 // Returns the condition on which a final split to 265 // true and false label should be made, to optimize fallthrough. 266 Condition EmitTypeofIs(Label* true_label, 267 Label* false_label, 268 Register input, 269 Handle<String> type_name); 270 271 // Emits optimized code for %_IsObject(x). Preserves input register. 272 // Returns the condition on which a final split to 273 // true and false label should be made, to optimize fallthrough. 274 Condition EmitIsObject(Register input, 275 Label* is_not_object, 276 Label* is_object); 277 278 // Emits optimized code for %_IsString(x). Preserves input register. 279 // Returns the condition on which a final split to 280 // true and false label should be made, to optimize fallthrough. 281 Condition EmitIsString(Register input, 282 Register temp1, 283 Label* is_not_string); 284 285 // Emits optimized code for %_IsConstructCall(). 286 // Caller should branch on equal condition. 287 void EmitIsConstructCall(Register temp); 288 289 void EmitLoadFieldOrConstantFunction(Register result, 290 Register object, 291 Handle<Map> type, 292 Handle<String> name); 293 294 // Emits code for pushing either a tagged constant, a (non-double) 295 // register, or a stack slot operand. 296 void EmitPushTaggedOperand(LOperand* operand); 297 298 // Emits optimized code to deep-copy the contents of statically known 299 // object graphs (e.g. object literal boilerplate). 300 void EmitDeepCopy(Handle<JSObject> object, 301 Register result, 302 Register source, 303 int* offset); 304 305 struct JumpTableEntry { 306 explicit inline JumpTableEntry(Address entry) 307 : label(), 308 address(entry) { } 309 Label label; 310 Address address; 311 }; 312 313 void EnsureSpaceForLazyDeopt(int space_needed); 314 315 LChunk* const chunk_; 316 MacroAssembler* const masm_; 317 CompilationInfo* const info_; 318 319 int current_block_; 320 int current_instruction_; 321 const ZoneList<LInstruction*>* instructions_; 322 ZoneList<LEnvironment*> deoptimizations_; 323 ZoneList<JumpTableEntry> jump_table_; 324 ZoneList<Handle<Object> > deoptimization_literals_; 325 int inlined_function_count_; 326 Scope* const scope_; 327 Status status_; 328 TranslationBuffer translations_; 329 ZoneList<LDeferredCode*> deferred_; 330 int osr_pc_offset_; 331 int last_lazy_deopt_pc_; 332 333 // Builder that keeps track of safepoints in the code. The table 334 // itself is emitted at the end of the generated code. 335 SafepointTableBuilder safepoints_; 336 337 // Compiler from a set of parallel moves to a sequential list of moves. 338 LGapResolver resolver_; 339 340 Safepoint::Kind expected_safepoint_kind_; 341 342 class PushSafepointRegistersScope BASE_EMBEDDED { 343 public: 344 explicit PushSafepointRegistersScope(LCodeGen* codegen) 345 : codegen_(codegen) { 346 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 347 codegen_->masm_->PushSafepointRegisters(); 348 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 349 } 350 351 ~PushSafepointRegistersScope() { 352 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 353 codegen_->masm_->PopSafepointRegisters(); 354 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 355 } 356 357 private: 358 LCodeGen* codegen_; 359 }; 360 361 friend class LDeferredCode; 362 friend class LEnvironment; 363 friend class SafepointGenerator; 364 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 365 }; 366 367 368 class LDeferredCode: public ZoneObject { 369 public: 370 explicit LDeferredCode(LCodeGen* codegen) 371 : codegen_(codegen), 372 external_exit_(NULL), 373 instruction_index_(codegen->current_instruction_) { 374 codegen->AddDeferredCode(this); 375 } 376 377 virtual ~LDeferredCode() { } 378 virtual void Generate() = 0; 379 virtual LInstruction* instr() = 0; 380 381 void SetExit(Label* exit) { external_exit_ = exit; } 382 Label* entry() { return &entry_; } 383 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } 384 int instruction_index() const { return instruction_index_; } 385 386 protected: 387 LCodeGen* codegen() const { return codegen_; } 388 MacroAssembler* masm() const { return codegen_->masm(); } 389 390 private: 391 LCodeGen* codegen_; 392 Label entry_; 393 Label exit_; 394 Label* external_exit_; 395 int instruction_index_; 396 }; 397 398 } } // namespace v8::internal 399 400 #endif // V8_X64_LITHIUM_CODEGEN_X64_H_ 401