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 #include "arm/lithium-gap-resolver-arm.h" 33 #include "deoptimizer.h" 34 #include "safepoint-table.h" 35 #include "scopes.h" 36 37 namespace v8 { 38 namespace internal { 39 40 // Forward declarations. 41 class LDeferredCode; 42 class SafepointGenerator; 43 44 class LCodeGen BASE_EMBEDDED { 45 public: LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)46 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 47 : chunk_(chunk), 48 masm_(assembler), 49 info_(info), 50 current_block_(-1), 51 current_instruction_(-1), 52 instructions_(chunk->instructions()), 53 deoptimizations_(4), 54 deopt_jump_table_(4), 55 deoptimization_literals_(8), 56 inlined_function_count_(0), 57 scope_(info->scope()), 58 status_(UNUSED), 59 deferred_(8), 60 osr_pc_offset_(-1), 61 last_lazy_deopt_pc_(0), 62 resolver_(this), 63 expected_safepoint_kind_(Safepoint::kSimple) { 64 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 65 } 66 67 68 // Simple accessors. masm()69 MacroAssembler* masm() const { return masm_; } info()70 CompilationInfo* info() const { return info_; } isolate()71 Isolate* isolate() const { return info_->isolate(); } factory()72 Factory* factory() const { return isolate()->factory(); } heap()73 Heap* heap() const { return isolate()->heap(); } 74 75 // Support for converting LOperands to assembler types. 76 // LOperand must be a register. 77 Register ToRegister(LOperand* op) const; 78 79 // LOperand is loaded into scratch, unless already a register. 80 Register EmitLoadRegister(LOperand* op, Register scratch); 81 82 // LOperand must be a double register. 83 DoubleRegister ToDoubleRegister(LOperand* op) const; 84 85 // LOperand is loaded into dbl_scratch, unless already a double register. 86 DoubleRegister EmitLoadDoubleRegister(LOperand* op, 87 SwVfpRegister flt_scratch, 88 DoubleRegister dbl_scratch); 89 int ToInteger32(LConstantOperand* op) const; 90 double ToDouble(LConstantOperand* op) const; 91 Operand ToOperand(LOperand* op); 92 MemOperand ToMemOperand(LOperand* op) const; 93 // Returns a MemOperand pointing to the high word of a DoubleStackSlot. 94 MemOperand ToHighMemOperand(LOperand* op) const; 95 96 bool IsInteger32(LConstantOperand* op) const; 97 Handle<Object> ToHandle(LConstantOperand* op) const; 98 99 // Try to generate code for the entire chunk, but it may fail if the 100 // chunk contains constructs we cannot handle. Returns true if the 101 // code generation attempt succeeded. 102 bool GenerateCode(); 103 104 // Finish the code by setting stack height, safepoint, and bailout 105 // information on it. 106 void FinishCode(Handle<Code> code); 107 108 // Deferred code support. 109 template<int T> 110 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, 111 Token::Value op); 112 void DoDeferredNumberTagD(LNumberTagD* instr); 113 void DoDeferredNumberTagI(LNumberTagI* instr); 114 void DoDeferredTaggedToI(LTaggedToI* instr); 115 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); 116 void DoDeferredStackCheck(LStackCheck* instr); 117 void DoDeferredRandom(LRandom* instr); 118 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 119 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 120 void DoDeferredAllocateObject(LAllocateObject* instr); 121 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 122 Label* map_check); 123 124 void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map, 125 CompareMapMode mode, LEnvironment* env); 126 127 // Parallel move support. 128 void DoParallelMove(LParallelMove* move); 129 void DoGap(LGap* instr); 130 131 // Emit frame translation commands for an environment. 132 void WriteTranslation(LEnvironment* environment, Translation* translation); 133 134 // Declare methods that deal with the individual node types. 135 #define DECLARE_DO(type) void Do##type(L##type* node); 136 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 137 #undef DECLARE_DO 138 139 private: 140 enum Status { 141 UNUSED, 142 GENERATING, 143 DONE, 144 ABORTED 145 }; 146 is_unused()147 bool is_unused() const { return status_ == UNUSED; } is_generating()148 bool is_generating() const { return status_ == GENERATING; } is_done()149 bool is_done() const { return status_ == DONE; } is_aborted()150 bool is_aborted() const { return status_ == ABORTED; } 151 strict_mode_flag()152 StrictModeFlag strict_mode_flag() const { 153 return info()->is_classic_mode() ? kNonStrictMode : kStrictMode; 154 } 155 chunk()156 LChunk* chunk() const { return chunk_; } scope()157 Scope* scope() const { return scope_; } graph()158 HGraph* graph() const { return chunk_->graph(); } 159 scratch0()160 Register scratch0() { return r9; } double_scratch0()161 DwVfpRegister double_scratch0() { return kScratchDoubleReg; } 162 163 int GetNextEmittedBlock(int block); 164 LInstruction* GetNextInstruction(); 165 166 void EmitClassOfTest(Label* if_true, 167 Label* if_false, 168 Handle<String> class_name, 169 Register input, 170 Register temporary, 171 Register temporary2); 172 GetStackSlotCount()173 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } GetParameterCount()174 int GetParameterCount() const { return scope()->num_parameters(); } 175 176 void Abort(const char* format, ...); 177 void Comment(const char* format, ...); 178 AddDeferredCode(LDeferredCode * code)179 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); } 180 181 // Code generation passes. Returns true if code generation should 182 // continue. 183 bool GeneratePrologue(); 184 bool GenerateBody(); 185 bool GenerateDeferredCode(); 186 bool GenerateDeoptJumpTable(); 187 bool GenerateSafepointTable(); 188 189 enum SafepointMode { 190 RECORD_SIMPLE_SAFEPOINT, 191 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 192 }; 193 194 void CallCode(Handle<Code> code, 195 RelocInfo::Mode mode, 196 LInstruction* instr); 197 198 void CallCodeGeneric(Handle<Code> code, 199 RelocInfo::Mode mode, 200 LInstruction* instr, 201 SafepointMode safepoint_mode); 202 203 void CallRuntime(const Runtime::Function* function, 204 int num_arguments, 205 LInstruction* instr); 206 CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)207 void CallRuntime(Runtime::FunctionId id, 208 int num_arguments, 209 LInstruction* instr) { 210 const Runtime::Function* function = Runtime::FunctionForId(id); 211 CallRuntime(function, num_arguments, instr); 212 } 213 214 void CallRuntimeFromDeferred(Runtime::FunctionId id, 215 int argc, 216 LInstruction* instr); 217 218 // Generate a direct call to a known function. Expects the function 219 // to be in r1. 220 void CallKnownFunction(Handle<JSFunction> function, 221 int arity, 222 LInstruction* instr, 223 CallKind call_kind); 224 225 void LoadHeapObject(Register result, Handle<HeapObject> object); 226 227 void RecordSafepointWithLazyDeopt(LInstruction* instr, 228 SafepointMode safepoint_mode); 229 230 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 231 Safepoint::DeoptMode mode); 232 void DeoptimizeIf(Condition cc, LEnvironment* environment); 233 234 void AddToTranslation(Translation* translation, 235 LOperand* op, 236 bool is_tagged); 237 void PopulateDeoptimizationData(Handle<Code> code); 238 int DefineDeoptimizationLiteral(Handle<Object> literal); 239 240 void PopulateDeoptimizationLiteralsWithInlinedFunctions(); 241 242 Register ToRegister(int index) const; 243 DoubleRegister ToDoubleRegister(int index) const; 244 245 // Specific math operations - used from DoUnaryMathOperation. 246 void EmitIntegerMathAbs(LUnaryMathOperation* instr); 247 void DoMathAbs(LUnaryMathOperation* instr); 248 void DoMathFloor(LUnaryMathOperation* instr); 249 void DoMathRound(LUnaryMathOperation* instr); 250 void DoMathSqrt(LUnaryMathOperation* instr); 251 void DoMathPowHalf(LUnaryMathOperation* instr); 252 void DoMathLog(LUnaryMathOperation* instr); 253 void DoMathTan(LUnaryMathOperation* instr); 254 void DoMathCos(LUnaryMathOperation* instr); 255 void DoMathSin(LUnaryMathOperation* instr); 256 257 // Support for recording safepoint and position information. 258 void RecordSafepoint(LPointerMap* pointers, 259 Safepoint::Kind kind, 260 int arguments, 261 Safepoint::DeoptMode mode); 262 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 263 void RecordSafepoint(Safepoint::DeoptMode mode); 264 void RecordSafepointWithRegisters(LPointerMap* pointers, 265 int arguments, 266 Safepoint::DeoptMode mode); 267 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers, 268 int arguments, 269 Safepoint::DeoptMode mode); 270 void RecordPosition(int position); 271 272 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 273 void EmitGoto(int block); 274 void EmitBranch(int left_block, int right_block, Condition cc); 275 void EmitNumberUntagD(Register input, 276 DoubleRegister result, 277 bool deoptimize_on_undefined, 278 bool deoptimize_on_minus_zero, 279 LEnvironment* env); 280 281 // Emits optimized code for typeof x == "y". Modifies input register. 282 // Returns the condition on which a final split to 283 // true and false label should be made, to optimize fallthrough. 284 Condition EmitTypeofIs(Label* true_label, 285 Label* false_label, 286 Register input, 287 Handle<String> type_name); 288 289 // Emits optimized code for %_IsObject(x). Preserves input register. 290 // Returns the condition on which a final split to 291 // true and false label should be made, to optimize fallthrough. 292 Condition EmitIsObject(Register input, 293 Register temp1, 294 Label* is_not_object, 295 Label* is_object); 296 297 // Emits optimized code for %_IsString(x). Preserves input register. 298 // Returns the condition on which a final split to 299 // true and false label should be made, to optimize fallthrough. 300 Condition EmitIsString(Register input, 301 Register temp1, 302 Label* is_not_string); 303 304 // Emits optimized code for %_IsConstructCall(). 305 // Caller should branch on equal condition. 306 void EmitIsConstructCall(Register temp1, Register temp2); 307 308 void EmitLoadFieldOrConstantFunction(Register result, 309 Register object, 310 Handle<Map> type, 311 Handle<String> name); 312 313 // Emits optimized code to deep-copy the contents of statically known 314 // object graphs (e.g. object literal boilerplate). 315 void EmitDeepCopy(Handle<JSObject> object, 316 Register result, 317 Register source, 318 int* offset); 319 320 struct JumpTableEntry { JumpTableEntryJumpTableEntry321 explicit inline JumpTableEntry(Address entry) 322 : label(), 323 address(entry) { } 324 Label label; 325 Address address; 326 }; 327 328 void EnsureSpaceForLazyDeopt(); 329 330 LChunk* const chunk_; 331 MacroAssembler* const masm_; 332 CompilationInfo* const info_; 333 334 int current_block_; 335 int current_instruction_; 336 const ZoneList<LInstruction*>* instructions_; 337 ZoneList<LEnvironment*> deoptimizations_; 338 ZoneList<JumpTableEntry> deopt_jump_table_; 339 ZoneList<Handle<Object> > deoptimization_literals_; 340 int inlined_function_count_; 341 Scope* const scope_; 342 Status status_; 343 TranslationBuffer translations_; 344 ZoneList<LDeferredCode*> deferred_; 345 int osr_pc_offset_; 346 int last_lazy_deopt_pc_; 347 348 // Builder that keeps track of safepoints in the code. The table 349 // itself is emitted at the end of the generated code. 350 SafepointTableBuilder safepoints_; 351 352 // Compiler from a set of parallel moves to a sequential list of moves. 353 LGapResolver resolver_; 354 355 Safepoint::Kind expected_safepoint_kind_; 356 357 class PushSafepointRegistersScope BASE_EMBEDDED { 358 public: PushSafepointRegistersScope(LCodeGen * codegen,Safepoint::Kind kind)359 PushSafepointRegistersScope(LCodeGen* codegen, 360 Safepoint::Kind kind) 361 : codegen_(codegen) { 362 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 363 codegen_->expected_safepoint_kind_ = kind; 364 365 switch (codegen_->expected_safepoint_kind_) { 366 case Safepoint::kWithRegisters: 367 codegen_->masm_->PushSafepointRegisters(); 368 break; 369 case Safepoint::kWithRegistersAndDoubles: 370 codegen_->masm_->PushSafepointRegistersAndDoubles(); 371 break; 372 default: 373 UNREACHABLE(); 374 } 375 } 376 ~PushSafepointRegistersScope()377 ~PushSafepointRegistersScope() { 378 Safepoint::Kind kind = codegen_->expected_safepoint_kind_; 379 ASSERT((kind & Safepoint::kWithRegisters) != 0); 380 switch (kind) { 381 case Safepoint::kWithRegisters: 382 codegen_->masm_->PopSafepointRegisters(); 383 break; 384 case Safepoint::kWithRegistersAndDoubles: 385 codegen_->masm_->PopSafepointRegistersAndDoubles(); 386 break; 387 default: 388 UNREACHABLE(); 389 } 390 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 391 } 392 393 private: 394 LCodeGen* codegen_; 395 }; 396 397 friend class LDeferredCode; 398 friend class LEnvironment; 399 friend class SafepointGenerator; 400 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 401 }; 402 403 404 class LDeferredCode: public ZoneObject { 405 public: LDeferredCode(LCodeGen * codegen)406 explicit LDeferredCode(LCodeGen* codegen) 407 : codegen_(codegen), 408 external_exit_(NULL), 409 instruction_index_(codegen->current_instruction_) { 410 codegen->AddDeferredCode(this); 411 } 412 ~LDeferredCode()413 virtual ~LDeferredCode() { } 414 virtual void Generate() = 0; 415 virtual LInstruction* instr() = 0; 416 SetExit(Label * exit)417 void SetExit(Label* exit) { external_exit_ = exit; } entry()418 Label* entry() { return &entry_; } exit()419 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } instruction_index()420 int instruction_index() const { return instruction_index_; } 421 422 protected: codegen()423 LCodeGen* codegen() const { return codegen_; } masm()424 MacroAssembler* masm() const { return codegen_->masm(); } 425 426 private: 427 LCodeGen* codegen_; 428 Label entry_; 429 Label exit_; 430 Label* external_exit_; 431 int instruction_index_; 432 }; 433 434 } } // namespace v8::internal 435 436 #endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_ 437