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