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_ARM_LITHIUM_CODEGEN_ARM_H_ 29 #define V8_ARM_LITHIUM_CODEGEN_ARM_H_ 30 31 #include "arm/lithium-arm.h" 32 33 #include "arm/lithium-gap-resolver-arm.h" 34 #include "deoptimizer.h" 35 #include "safepoint-table.h" 36 #include "scopes.h" 37 #include "v8utils.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 : zone_(info->zone()), 50 chunk_(static_cast<LPlatformChunk*>(chunk)), 51 masm_(assembler), 52 info_(info), 53 current_block_(-1), 54 current_instruction_(-1), 55 instructions_(chunk->instructions()), 56 deoptimizations_(4, info->zone()), 57 deopt_jump_table_(4, info->zone()), 58 deoptimization_literals_(8, info->zone()), 59 inlined_function_count_(0), 60 scope_(info->scope()), 61 status_(UNUSED), 62 translations_(info->zone()), 63 deferred_(8, info->zone()), 64 osr_pc_offset_(-1), 65 last_lazy_deopt_pc_(0), 66 frame_is_built_(false), 67 safepoints_(info->zone()), 68 resolver_(this), 69 expected_safepoint_kind_(Safepoint::kSimple), 70 old_position_(RelocInfo::kNoPosition) { 71 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 72 } 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 LinkRegisterStatus GetLinkRegisterState() const { 102 return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved; 103 } 104 105 // Support for converting LOperands to assembler types. 106 // LOperand must be a register. 107 Register ToRegister(LOperand* op) const; 108 109 // LOperand is loaded into scratch, unless already a register. 110 Register EmitLoadRegister(LOperand* op, Register scratch); 111 112 // LOperand must be a double register. 113 DwVfpRegister ToDoubleRegister(LOperand* op) const; 114 115 // LOperand is loaded into dbl_scratch, unless already a double register. 116 DwVfpRegister EmitLoadDoubleRegister(LOperand* op, 117 SwVfpRegister flt_scratch, 118 DwVfpRegister dbl_scratch); 119 int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; 120 int32_t ToInteger32(LConstantOperand* op) const; 121 Smi* ToSmi(LConstantOperand* op) const; 122 double ToDouble(LConstantOperand* op) const; 123 Operand ToOperand(LOperand* op); 124 MemOperand ToMemOperand(LOperand* op) const; 125 // Returns a MemOperand pointing to the high word of a DoubleStackSlot. 126 MemOperand ToHighMemOperand(LOperand* op) const; 127 128 bool IsInteger32(LConstantOperand* op) const; 129 bool IsSmi(LConstantOperand* op) const; 130 Handle<Object> ToHandle(LConstantOperand* op) const; 131 132 // Try to generate code for the entire chunk, but it may fail if the 133 // chunk contains constructs we cannot handle. Returns true if the 134 // code generation attempt succeeded. 135 bool GenerateCode(); 136 137 // Finish the code by setting stack height, safepoint, and bailout 138 // information on it. 139 void FinishCode(Handle<Code> code); 140 141 // Deferred code support. 142 void DoDeferredNumberTagD(LNumberTagD* instr); 143 144 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; 145 void DoDeferredNumberTagI(LInstruction* instr, 146 LOperand* value, 147 IntegerSignedness signedness); 148 149 void DoDeferredTaggedToI(LTaggedToI* instr); 150 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 151 void DoDeferredStackCheck(LStackCheck* instr); 152 void DoDeferredRandom(LRandom* instr); 153 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 154 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 155 void DoDeferredAllocate(LAllocate* instr); 156 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 157 Label* map_check); 158 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 159 160 // Parallel move support. 161 void DoParallelMove(LParallelMove* move); 162 void DoGap(LGap* instr); 163 164 MemOperand PrepareKeyedOperand(Register key, 165 Register base, 166 bool key_is_constant, 167 int constant_key, 168 int element_size, 169 int shift_size, 170 int additional_index, 171 int additional_offset); 172 173 // Emit frame translation commands for an environment. 174 void WriteTranslation(LEnvironment* environment, Translation* translation); 175 176 // Declare methods that deal with the individual node types. 177 #define DECLARE_DO(type) void Do##type(L##type* node); 178 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 179 #undef DECLARE_DO 180 181 private: 182 enum Status { 183 UNUSED, 184 GENERATING, 185 DONE, 186 ABORTED 187 }; 188 189 bool is_unused() const { return status_ == UNUSED; } 190 bool is_generating() const { return status_ == GENERATING; } 191 bool is_done() const { return status_ == DONE; } 192 bool is_aborted() const { return status_ == ABORTED; } 193 194 StrictModeFlag strict_mode_flag() const { 195 return info()->is_classic_mode() ? kNonStrictMode : kStrictMode; 196 } 197 198 LPlatformChunk* chunk() const { return chunk_; } 199 Scope* scope() const { return scope_; } 200 HGraph* graph() const { return chunk()->graph(); } 201 202 Register scratch0() { return r9; } 203 LowDwVfpRegister double_scratch0() { return kScratchDoubleReg; } 204 205 int GetNextEmittedBlock() const; 206 LInstruction* GetNextInstruction(); 207 208 void EmitClassOfTest(Label* if_true, 209 Label* if_false, 210 Handle<String> class_name, 211 Register input, 212 Register temporary, 213 Register temporary2); 214 215 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 216 217 void Abort(BailoutReason reason); 218 void FPRINTF_CHECKING Comment(const char* format, ...); 219 220 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 221 222 // Code generation passes. Returns true if code generation should 223 // continue. 224 bool GeneratePrologue(); 225 bool GenerateBody(); 226 bool GenerateDeferredCode(); 227 bool GenerateDeoptJumpTable(); 228 bool GenerateSafepointTable(); 229 230 enum SafepointMode { 231 RECORD_SIMPLE_SAFEPOINT, 232 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 233 }; 234 235 void CallCode( 236 Handle<Code> code, 237 RelocInfo::Mode mode, 238 LInstruction* instr, 239 TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS); 240 241 void CallCodeGeneric( 242 Handle<Code> code, 243 RelocInfo::Mode mode, 244 LInstruction* instr, 245 SafepointMode safepoint_mode, 246 TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS); 247 248 void CallRuntime(const Runtime::Function* function, 249 int num_arguments, 250 LInstruction* instr); 251 252 void CallRuntime(Runtime::FunctionId id, 253 int num_arguments, 254 LInstruction* instr) { 255 const Runtime::Function* function = Runtime::FunctionForId(id); 256 CallRuntime(function, num_arguments, instr); 257 } 258 259 void CallRuntimeFromDeferred(Runtime::FunctionId id, 260 int argc, 261 LInstruction* instr); 262 263 enum R1State { 264 R1_UNINITIALIZED, 265 R1_CONTAINS_TARGET 266 }; 267 268 // Generate a direct call to a known function. Expects the function 269 // to be in r1. 270 void CallKnownFunction(Handle<JSFunction> function, 271 int formal_parameter_count, 272 int arity, 273 LInstruction* instr, 274 CallKind call_kind, 275 R1State r1_state); 276 277 void LoadHeapObject(Register result, Handle<HeapObject> object); 278 279 void RecordSafepointWithLazyDeopt(LInstruction* instr, 280 SafepointMode safepoint_mode); 281 282 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 283 Safepoint::DeoptMode mode); 284 void DeoptimizeIf(Condition condition, 285 LEnvironment* environment, 286 Deoptimizer::BailoutType bailout_type); 287 void DeoptimizeIf(Condition condition, LEnvironment* environment); 288 void ApplyCheckIf(Condition condition, LBoundsCheck* check); 289 290 void AddToTranslation(LEnvironment* environment, 291 Translation* translation, 292 LOperand* op, 293 bool is_tagged, 294 bool is_uint32, 295 int* object_index_pointer, 296 int* dematerialized_index_pointer); 297 void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code); 298 void PopulateDeoptimizationData(Handle<Code> code); 299 int DefineDeoptimizationLiteral(Handle<Object> literal); 300 301 void PopulateDeoptimizationLiteralsWithInlinedFunctions(); 302 303 Register ToRegister(int index) const; 304 DwVfpRegister ToDoubleRegister(int index) const; 305 306 void EmitIntegerMathAbs(LMathAbs* instr); 307 308 // Support for recording safepoint and position information. 309 void RecordSafepoint(LPointerMap* pointers, 310 Safepoint::Kind kind, 311 int arguments, 312 Safepoint::DeoptMode mode); 313 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 314 void RecordSafepoint(Safepoint::DeoptMode mode); 315 void RecordSafepointWithRegisters(LPointerMap* pointers, 316 int arguments, 317 Safepoint::DeoptMode mode); 318 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers, 319 int arguments, 320 Safepoint::DeoptMode mode); 321 void RecordPosition(int position); 322 void RecordAndUpdatePosition(int position); 323 324 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 325 void EmitGoto(int block); 326 template<class InstrType> 327 void EmitBranch(InstrType instr, Condition condition); 328 template<class InstrType> 329 void EmitFalseBranch(InstrType instr, Condition condition); 330 void EmitNumberUntagD(Register input, 331 DwVfpRegister result, 332 bool allow_undefined_as_nan, 333 bool deoptimize_on_minus_zero, 334 LEnvironment* env, 335 NumberUntagDMode mode); 336 337 // Emits optimized code for typeof x == "y". Modifies input register. 338 // Returns the condition on which a final split to 339 // true and false label should be made, to optimize fallthrough. 340 Condition EmitTypeofIs(Label* true_label, 341 Label* false_label, 342 Register input, 343 Handle<String> type_name); 344 345 // Emits optimized code for %_IsObject(x). Preserves input register. 346 // Returns the condition on which a final split to 347 // true and false label should be made, to optimize fallthrough. 348 Condition EmitIsObject(Register input, 349 Register temp1, 350 Label* is_not_object, 351 Label* is_object); 352 353 // Emits optimized code for %_IsString(x). Preserves input register. 354 // Returns the condition on which a final split to 355 // true and false label should be made, to optimize fallthrough. 356 Condition EmitIsString(Register input, 357 Register temp1, 358 Label* is_not_string, 359 SmiCheck check_needed); 360 361 // Emits optimized code for %_IsConstructCall(). 362 // Caller should branch on equal condition. 363 void EmitIsConstructCall(Register temp1, Register temp2); 364 365 // Emits optimized code to deep-copy the contents of statically known 366 // object graphs (e.g. object literal boilerplate). 367 void EmitDeepCopy(Handle<JSObject> object, 368 Register result, 369 Register source, 370 int* offset, 371 AllocationSiteMode mode); 372 373 // Emit optimized code for integer division. 374 // Inputs are signed. 375 // All registers are clobbered. 376 // If 'remainder' is no_reg, it is not computed. 377 void EmitSignedIntegerDivisionByConstant(Register result, 378 Register dividend, 379 int32_t divisor, 380 Register remainder, 381 Register scratch, 382 LEnvironment* environment); 383 384 void EnsureSpaceForLazyDeopt(); 385 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 386 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 387 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 388 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 389 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 390 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 391 392 Zone* zone_; 393 LPlatformChunk* const chunk_; 394 MacroAssembler* const masm_; 395 CompilationInfo* const info_; 396 397 int current_block_; 398 int current_instruction_; 399 const ZoneList<LInstruction*>* instructions_; 400 ZoneList<LEnvironment*> deoptimizations_; 401 ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_; 402 ZoneList<Handle<Object> > deoptimization_literals_; 403 int inlined_function_count_; 404 Scope* const scope_; 405 Status status_; 406 TranslationBuffer translations_; 407 ZoneList<LDeferredCode*> deferred_; 408 int osr_pc_offset_; 409 int last_lazy_deopt_pc_; 410 bool frame_is_built_; 411 412 // Builder that keeps track of safepoints in the code. The table 413 // itself is emitted at the end of the generated code. 414 SafepointTableBuilder safepoints_; 415 416 // Compiler from a set of parallel moves to a sequential list of moves. 417 LGapResolver resolver_; 418 419 Safepoint::Kind expected_safepoint_kind_; 420 421 int old_position_; 422 423 class PushSafepointRegistersScope BASE_EMBEDDED { 424 public: 425 PushSafepointRegistersScope(LCodeGen* codegen, 426 Safepoint::Kind kind) 427 : codegen_(codegen) { 428 ASSERT(codegen_->info()->is_calling()); 429 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 430 codegen_->expected_safepoint_kind_ = kind; 431 432 switch (codegen_->expected_safepoint_kind_) { 433 case Safepoint::kWithRegisters: 434 codegen_->masm_->PushSafepointRegisters(); 435 break; 436 case Safepoint::kWithRegistersAndDoubles: 437 codegen_->masm_->PushSafepointRegistersAndDoubles(); 438 break; 439 default: 440 UNREACHABLE(); 441 } 442 } 443 444 ~PushSafepointRegistersScope() { 445 Safepoint::Kind kind = codegen_->expected_safepoint_kind_; 446 ASSERT((kind & Safepoint::kWithRegisters) != 0); 447 switch (kind) { 448 case Safepoint::kWithRegisters: 449 codegen_->masm_->PopSafepointRegisters(); 450 break; 451 case Safepoint::kWithRegistersAndDoubles: 452 codegen_->masm_->PopSafepointRegistersAndDoubles(); 453 break; 454 default: 455 UNREACHABLE(); 456 } 457 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 458 } 459 460 private: 461 LCodeGen* codegen_; 462 }; 463 464 friend class LDeferredCode; 465 friend class LEnvironment; 466 friend class SafepointGenerator; 467 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 468 }; 469 470 471 class LDeferredCode: public ZoneObject { 472 public: 473 explicit LDeferredCode(LCodeGen* codegen) 474 : codegen_(codegen), 475 external_exit_(NULL), 476 instruction_index_(codegen->current_instruction_) { 477 codegen->AddDeferredCode(this); 478 } 479 480 virtual ~LDeferredCode() { } 481 virtual void Generate() = 0; 482 virtual LInstruction* instr() = 0; 483 484 void SetExit(Label* exit) { external_exit_ = exit; } 485 Label* entry() { return &entry_; } 486 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } 487 int instruction_index() const { return instruction_index_; } 488 489 protected: 490 LCodeGen* codegen() const { return codegen_; } 491 MacroAssembler* masm() const { return codegen_->masm(); } 492 493 private: 494 LCodeGen* codegen_; 495 Label entry_; 496 Label exit_; 497 Label* external_exit_; 498 int instruction_index_; 499 }; 500 501 } } // namespace v8::internal 502 503 #endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_ 504