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 "v8utils.h" 38#include "x64/lithium-gap-resolver-x64.h" 39 40namespace v8 { 41namespace internal { 42 43// Forward declarations. 44class LDeferredCode; 45class SafepointGenerator; 46 47class LCodeGen BASE_EMBEDDED { 48 public: 49 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 50 : zone_(info->zone()), 51 chunk_(static_cast<LPlatformChunk*>(chunk)), 52 masm_(assembler), 53 info_(info), 54 current_block_(-1), 55 current_instruction_(-1), 56 instructions_(chunk->instructions()), 57 deoptimizations_(4, info->zone()), 58 jump_table_(4, info->zone()), 59 deoptimization_literals_(8, info->zone()), 60 inlined_function_count_(0), 61 scope_(info->scope()), 62 status_(UNUSED), 63 translations_(info->zone()), 64 deferred_(8, info->zone()), 65 osr_pc_offset_(-1), 66 last_lazy_deopt_pc_(0), 67 frame_is_built_(false), 68 safepoints_(info->zone()), 69 resolver_(this), 70 expected_safepoint_kind_(Safepoint::kSimple), 71 old_position_(RelocInfo::kNoPosition) { 72 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 73 } 74 75 // Simple accessors. 76 MacroAssembler* masm() const { return masm_; } 77 CompilationInfo* info() const { return info_; } 78 Isolate* isolate() const { return info_->isolate(); } 79 Factory* factory() const { return isolate()->factory(); } 80 Heap* heap() const { return isolate()->heap(); } 81 Zone* zone() const { return zone_; } 82 83 int LookupDestination(int block_id) const { 84 return chunk()->LookupDestination(block_id); 85 } 86 87 bool IsNextEmittedBlock(int block_id) const { 88 return LookupDestination(block_id) == GetNextEmittedBlock(); 89 } 90 91 bool NeedsEagerFrame() const { 92 return GetStackSlotCount() > 0 || 93 info()->is_non_deferred_calling() || 94 !info()->IsStub() || 95 info()->requires_frame(); 96 } 97 bool NeedsDeferredFrame() const { 98 return !NeedsEagerFrame() && info()->is_deferred_calling(); 99 } 100 101 // Support for converting LOperands to assembler types. 102 Register ToRegister(LOperand* op) const; 103 XMMRegister ToDoubleRegister(LOperand* op) const; 104 bool IsInteger32Constant(LConstantOperand* op) const; 105 bool IsSmiConstant(LConstantOperand* op) const; 106 int32_t ToInteger32(LConstantOperand* op) const; 107 Smi* ToSmi(LConstantOperand* op) const; 108 double ToDouble(LConstantOperand* op) const; 109 ExternalReference ToExternalReference(LConstantOperand* op) const; 110 bool IsTaggedConstant(LConstantOperand* op) const; 111 Handle<Object> ToHandle(LConstantOperand* op) const; 112 Operand ToOperand(LOperand* op) const; 113 114 // Try to generate code for the entire chunk, but it may fail if the 115 // chunk contains constructs we cannot handle. Returns true if the 116 // code generation attempt succeeded. 117 bool GenerateCode(); 118 119 // Finish the code by setting stack height, safepoint, and bailout 120 // information on it. 121 void FinishCode(Handle<Code> code); 122 123 // Deferred code support. 124 void DoDeferredNumberTagD(LNumberTagD* instr); 125 void DoDeferredNumberTagU(LNumberTagU* instr); 126 void DoDeferredTaggedToI(LTaggedToI* instr); 127 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 128 void DoDeferredStackCheck(LStackCheck* instr); 129 void DoDeferredRandom(LRandom* instr); 130 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 131 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 132 void DoDeferredAllocate(LAllocate* instr); 133 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 134 Label* map_check); 135 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 136 137// Parallel move support. 138 void DoParallelMove(LParallelMove* move); 139 void DoGap(LGap* instr); 140 141 // Emit frame translation commands for an environment. 142 void WriteTranslation(LEnvironment* environment, Translation* translation); 143 144 // Declare methods that deal with the individual node types. 145#define DECLARE_DO(type) void Do##type(L##type* node); 146 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 147#undef DECLARE_DO 148 149 private: 150 enum Status { 151 UNUSED, 152 GENERATING, 153 DONE, 154 ABORTED 155 }; 156 157 bool is_unused() const { return status_ == UNUSED; } 158 bool is_generating() const { return status_ == GENERATING; } 159 bool is_done() const { return status_ == DONE; } 160 bool is_aborted() const { return status_ == ABORTED; } 161 162 StrictModeFlag strict_mode_flag() const { 163 return info()->is_classic_mode() ? kNonStrictMode : kStrictMode; 164 } 165 166 LPlatformChunk* chunk() const { return chunk_; } 167 Scope* scope() const { return scope_; } 168 HGraph* graph() const { return chunk()->graph(); } 169 170 int GetNextEmittedBlock() const; 171 172 void EmitClassOfTest(Label* if_true, 173 Label* if_false, 174 Handle<String> class_name, 175 Register input, 176 Register temporary, 177 Register scratch); 178 179 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 180 181 void Abort(BailoutReason reason); 182 void FPRINTF_CHECKING Comment(const char* format, ...); 183 184 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 185 186 // Code generation passes. Returns true if code generation should 187 // continue. 188 bool GeneratePrologue(); 189 bool GenerateBody(); 190 bool GenerateDeferredCode(); 191 bool GenerateJumpTable(); 192 bool GenerateSafepointTable(); 193 194 enum SafepointMode { 195 RECORD_SIMPLE_SAFEPOINT, 196 RECORD_SAFEPOINT_WITH_REGISTERS 197 }; 198 199 void CallCodeGeneric(Handle<Code> code, 200 RelocInfo::Mode mode, 201 LInstruction* instr, 202 SafepointMode safepoint_mode, 203 int argc); 204 205 206 void CallCode(Handle<Code> code, 207 RelocInfo::Mode mode, 208 LInstruction* instr); 209 210 void CallRuntime(const Runtime::Function* function, 211 int num_arguments, 212 LInstruction* instr); 213 214 void CallRuntime(Runtime::FunctionId id, 215 int num_arguments, 216 LInstruction* instr) { 217 const Runtime::Function* function = Runtime::FunctionForId(id); 218 CallRuntime(function, num_arguments, instr); 219 } 220 221 void CallRuntimeFromDeferred(Runtime::FunctionId id, 222 int argc, 223 LInstruction* instr); 224 225 enum RDIState { 226 RDI_UNINITIALIZED, 227 RDI_CONTAINS_TARGET 228 }; 229 230 // Generate a direct call to a known function. Expects the function 231 // to be in rdi. 232 void CallKnownFunction(Handle<JSFunction> function, 233 int formal_parameter_count, 234 int arity, 235 LInstruction* instr, 236 CallKind call_kind, 237 RDIState rdi_state); 238 239 void RecordSafepointWithLazyDeopt(LInstruction* instr, 240 SafepointMode safepoint_mode, 241 int argc); 242 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 243 Safepoint::DeoptMode mode); 244 void DeoptimizeIf(Condition cc, 245 LEnvironment* environment, 246 Deoptimizer::BailoutType bailout_type); 247 void DeoptimizeIf(Condition cc, LEnvironment* environment); 248 void ApplyCheckIf(Condition cc, LBoundsCheck* check); 249 250 void AddToTranslation(LEnvironment* environment, 251 Translation* translation, 252 LOperand* op, 253 bool is_tagged, 254 bool is_uint32, 255 int* object_index_pointer, 256 int* dematerialized_index_pointer); 257 void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); 258 void PopulateDeoptimizationData(Handle<Code> code); 259 int DefineDeoptimizationLiteral(Handle<Object> literal); 260 261 void PopulateDeoptimizationLiteralsWithInlinedFunctions(); 262 263 Register ToRegister(int index) const; 264 XMMRegister ToDoubleRegister(int index) const; 265 Operand BuildFastArrayOperand( 266 LOperand* elements_pointer, 267 LOperand* key, 268 ElementsKind elements_kind, 269 uint32_t offset, 270 uint32_t additional_index = 0); 271 272 void EmitIntegerMathAbs(LMathAbs* instr); 273 void EmitSmiMathAbs(LMathAbs* instr); 274 275 // Support for recording safepoint and position information. 276 void RecordSafepoint(LPointerMap* pointers, 277 Safepoint::Kind kind, 278 int arguments, 279 Safepoint::DeoptMode mode); 280 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 281 void RecordSafepoint(Safepoint::DeoptMode mode); 282 void RecordSafepointWithRegisters(LPointerMap* pointers, 283 int arguments, 284 Safepoint::DeoptMode mode); 285 void RecordPosition(int position); 286 void RecordAndUpdatePosition(int position); 287 288 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 289 void EmitGoto(int block); 290 template<class InstrType> 291 void EmitBranch(InstrType instr, Condition cc); 292 template<class InstrType> 293 void EmitFalseBranch(InstrType instr, Condition cc); 294 void EmitNumberUntagD( 295 Register input, 296 XMMRegister result, 297 bool allow_undefined_as_nan, 298 bool deoptimize_on_minus_zero, 299 LEnvironment* env, 300 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED); 301 302 // Emits optimized code for typeof x == "y". Modifies input register. 303 // Returns the condition on which a final split to 304 // true and false label should be made, to optimize fallthrough. 305 Condition EmitTypeofIs(Label* true_label, 306 Label* false_label, 307 Register input, 308 Handle<String> type_name); 309 310 // Emits optimized code for %_IsObject(x). Preserves input register. 311 // Returns the condition on which a final split to 312 // true and false label should be made, to optimize fallthrough. 313 Condition EmitIsObject(Register input, 314 Label* is_not_object, 315 Label* is_object); 316 317 // Emits optimized code for %_IsString(x). Preserves input register. 318 // Returns the condition on which a final split to 319 // true and false label should be made, to optimize fallthrough. 320 Condition EmitIsString(Register input, 321 Register temp1, 322 Label* is_not_string, 323 SmiCheck check_needed); 324 325 // Emits optimized code for %_IsConstructCall(). 326 // Caller should branch on equal condition. 327 void EmitIsConstructCall(Register temp); 328 329 // Emits code for pushing either a tagged constant, a (non-double) 330 // register, or a stack slot operand. 331 void EmitPushTaggedOperand(LOperand* operand); 332 333 // Emits optimized code to deep-copy the contents of statically known 334 // object graphs (e.g. object literal boilerplate). 335 void EmitDeepCopy(Handle<JSObject> object, 336 Register result, 337 Register source, 338 int* offset, 339 AllocationSiteMode mode); 340 341 void EnsureSpaceForLazyDeopt(int space_needed); 342 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 343 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 344 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 345 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 346 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 347 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 348#ifdef _MSC_VER 349 // On windows, you may not access the stack more than one page below 350 // the most recently mapped page. To make the allocated area randomly 351 // accessible, we write an arbitrary value to each page in range 352 // rsp + offset - page_size .. rsp in turn. 353 void MakeSureStackPagesMapped(int offset); 354#endif 355 356 Zone* zone_; 357 LPlatformChunk* const chunk_; 358 MacroAssembler* const masm_; 359 CompilationInfo* const info_; 360 361 int current_block_; 362 int current_instruction_; 363 const ZoneList<LInstruction*>* instructions_; 364 ZoneList<LEnvironment*> deoptimizations_; 365 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; 366 ZoneList<Handle<Object> > deoptimization_literals_; 367 int inlined_function_count_; 368 Scope* const scope_; 369 Status status_; 370 TranslationBuffer translations_; 371 ZoneList<LDeferredCode*> deferred_; 372 int osr_pc_offset_; 373 int last_lazy_deopt_pc_; 374 bool frame_is_built_; 375 376 // Builder that keeps track of safepoints in the code. The table 377 // itself is emitted at the end of the generated code. 378 SafepointTableBuilder safepoints_; 379 380 // Compiler from a set of parallel moves to a sequential list of moves. 381 LGapResolver resolver_; 382 383 Safepoint::Kind expected_safepoint_kind_; 384 385 int old_position_; 386 387 class PushSafepointRegistersScope BASE_EMBEDDED { 388 public: 389 explicit PushSafepointRegistersScope(LCodeGen* codegen) 390 : codegen_(codegen) { 391 ASSERT(codegen_->info()->is_calling()); 392 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 393 codegen_->masm_->PushSafepointRegisters(); 394 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 395 } 396 397 ~PushSafepointRegistersScope() { 398 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 399 codegen_->masm_->PopSafepointRegisters(); 400 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 401 } 402 403 private: 404 LCodeGen* codegen_; 405 }; 406 407 friend class LDeferredCode; 408 friend class LEnvironment; 409 friend class SafepointGenerator; 410 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 411}; 412 413 414class LDeferredCode: public ZoneObject { 415 public: 416 explicit LDeferredCode(LCodeGen* codegen) 417 : codegen_(codegen), 418 external_exit_(NULL), 419 instruction_index_(codegen->current_instruction_) { 420 codegen->AddDeferredCode(this); 421 } 422 423 virtual ~LDeferredCode() { } 424 virtual void Generate() = 0; 425 virtual LInstruction* instr() = 0; 426 427 void SetExit(Label* exit) { external_exit_ = exit; } 428 Label* entry() { return &entry_; } 429 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } 430 int instruction_index() const { return instruction_index_; } 431 432 protected: 433 LCodeGen* codegen() const { return codegen_; } 434 MacroAssembler* masm() const { return codegen_->masm(); } 435 436 private: 437 LCodeGen* codegen_; 438 Label entry_; 439 Label exit_; 440 Label* external_exit_; 441 int instruction_index_; 442}; 443 444} } // namespace v8::internal 445 446#endif // V8_X64_LITHIUM_CODEGEN_X64_H_ 447