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