OLD | NEW |
| (Empty) |
1 // Copyright 2012 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef V8_X64_LITHIUM_CODEGEN_X64_H_ | |
6 #define V8_X64_LITHIUM_CODEGEN_X64_H_ | |
7 | |
8 #include "src/x64/lithium-x64.h" | |
9 | |
10 #include "src/base/logging.h" | |
11 #include "src/deoptimizer.h" | |
12 #include "src/lithium-codegen.h" | |
13 #include "src/safepoint-table.h" | |
14 #include "src/scopes.h" | |
15 #include "src/utils.h" | |
16 #include "src/x64/lithium-gap-resolver-x64.h" | |
17 | |
18 namespace v8 { | |
19 namespace internal { | |
20 | |
21 // Forward declarations. | |
22 class LDeferredCode; | |
23 class SafepointGenerator; | |
24 | |
25 class LCodeGen: public LCodeGenBase { | |
26 public: | |
27 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) | |
28 : LCodeGenBase(chunk, assembler, info), | |
29 deoptimizations_(4, info->zone()), | |
30 jump_table_(4, info->zone()), | |
31 inlined_function_count_(0), | |
32 scope_(info->scope()), | |
33 translations_(info->zone()), | |
34 deferred_(8, info->zone()), | |
35 osr_pc_offset_(-1), | |
36 frame_is_built_(false), | |
37 safepoints_(info->zone()), | |
38 resolver_(this), | |
39 expected_safepoint_kind_(Safepoint::kSimple) { | |
40 PopulateDeoptimizationLiteralsWithInlinedFunctions(); | |
41 } | |
42 | |
43 int LookupDestination(int block_id) const { | |
44 return chunk()->LookupDestination(block_id); | |
45 } | |
46 | |
47 bool IsNextEmittedBlock(int block_id) const { | |
48 return LookupDestination(block_id) == GetNextEmittedBlock(); | |
49 } | |
50 | |
51 bool NeedsEagerFrame() const { | |
52 return GetStackSlotCount() > 0 || | |
53 info()->is_non_deferred_calling() || | |
54 !info()->IsStub() || | |
55 info()->requires_frame(); | |
56 } | |
57 bool NeedsDeferredFrame() const { | |
58 return !NeedsEagerFrame() && info()->is_deferred_calling(); | |
59 } | |
60 | |
61 // Support for converting LOperands to assembler types. | |
62 Register ToRegister(LOperand* op) const; | |
63 XMMRegister ToDoubleRegister(LOperand* op) const; | |
64 bool IsInteger32Constant(LConstantOperand* op) const; | |
65 bool IsExternalConstant(LConstantOperand* op) const; | |
66 bool IsDehoistedKeyConstant(LConstantOperand* op) const; | |
67 bool IsSmiConstant(LConstantOperand* op) const; | |
68 int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; | |
69 int32_t ToInteger32(LConstantOperand* op) const; | |
70 Smi* ToSmi(LConstantOperand* op) const; | |
71 double ToDouble(LConstantOperand* op) const; | |
72 ExternalReference ToExternalReference(LConstantOperand* op) const; | |
73 Handle<Object> ToHandle(LConstantOperand* op) const; | |
74 Operand ToOperand(LOperand* op) const; | |
75 | |
76 // Try to generate code for the entire chunk, but it may fail if the | |
77 // chunk contains constructs we cannot handle. Returns true if the | |
78 // code generation attempt succeeded. | |
79 bool GenerateCode(); | |
80 | |
81 // Finish the code by setting stack height, safepoint, and bailout | |
82 // information on it. | |
83 void FinishCode(Handle<Code> code); | |
84 | |
85 // Deferred code support. | |
86 void DoDeferredNumberTagD(LNumberTagD* instr); | |
87 | |
88 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; | |
89 void DoDeferredNumberTagIU(LInstruction* instr, | |
90 LOperand* value, | |
91 LOperand* temp1, | |
92 LOperand* temp2, | |
93 IntegerSignedness signedness); | |
94 | |
95 void DoDeferredTaggedToI(LTaggedToI* instr, Label* done); | |
96 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); | |
97 void DoDeferredStackCheck(LStackCheck* instr); | |
98 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr); | |
99 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); | |
100 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); | |
101 void DoDeferredAllocate(LAllocate* instr); | |
102 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); | |
103 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, | |
104 Register object, | |
105 Register index); | |
106 | |
107 // Parallel move support. | |
108 void DoParallelMove(LParallelMove* move); | |
109 void DoGap(LGap* instr); | |
110 | |
111 // Emit frame translation commands for an environment. | |
112 void WriteTranslation(LEnvironment* environment, Translation* translation); | |
113 | |
114 // Declare methods that deal with the individual node types. | |
115 #define DECLARE_DO(type) void Do##type(L##type* node); | |
116 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) | |
117 #undef DECLARE_DO | |
118 | |
119 private: | |
120 LanguageMode language_mode() const { return info()->language_mode(); } | |
121 | |
122 LPlatformChunk* chunk() const { return chunk_; } | |
123 Scope* scope() const { return scope_; } | |
124 HGraph* graph() const { return chunk()->graph(); } | |
125 | |
126 XMMRegister double_scratch0() const { return xmm0; } | |
127 | |
128 void EmitClassOfTest(Label* if_true, | |
129 Label* if_false, | |
130 Handle<String> class_name, | |
131 Register input, | |
132 Register temporary, | |
133 Register scratch); | |
134 | |
135 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } | |
136 | |
137 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } | |
138 | |
139 | |
140 void SaveCallerDoubles(); | |
141 void RestoreCallerDoubles(); | |
142 | |
143 // Code generation passes. Returns true if code generation should | |
144 // continue. | |
145 void GenerateBodyInstructionPre(LInstruction* instr) override; | |
146 void GenerateBodyInstructionPost(LInstruction* instr) override; | |
147 bool GeneratePrologue(); | |
148 bool GenerateDeferredCode(); | |
149 bool GenerateJumpTable(); | |
150 bool GenerateSafepointTable(); | |
151 | |
152 // Generates the custom OSR entrypoint and sets the osr_pc_offset. | |
153 void GenerateOsrPrologue(); | |
154 | |
155 enum SafepointMode { | |
156 RECORD_SIMPLE_SAFEPOINT, | |
157 RECORD_SAFEPOINT_WITH_REGISTERS | |
158 }; | |
159 | |
160 void CallCodeGeneric(Handle<Code> code, | |
161 RelocInfo::Mode mode, | |
162 LInstruction* instr, | |
163 SafepointMode safepoint_mode, | |
164 int argc); | |
165 | |
166 | |
167 void CallCode(Handle<Code> code, | |
168 RelocInfo::Mode mode, | |
169 LInstruction* instr); | |
170 | |
171 void CallRuntime(const Runtime::Function* function, | |
172 int num_arguments, | |
173 LInstruction* instr, | |
174 SaveFPRegsMode save_doubles = kDontSaveFPRegs); | |
175 | |
176 void CallRuntime(Runtime::FunctionId id, | |
177 int num_arguments, | |
178 LInstruction* instr) { | |
179 const Runtime::Function* function = Runtime::FunctionForId(id); | |
180 CallRuntime(function, num_arguments, instr); | |
181 } | |
182 | |
183 void CallRuntimeFromDeferred(Runtime::FunctionId id, | |
184 int argc, | |
185 LInstruction* instr, | |
186 LOperand* context); | |
187 | |
188 void LoadContextFromDeferred(LOperand* context); | |
189 | |
190 // Generate a direct call to a known function. Expects the function | |
191 // to be in rdi. | |
192 void CallKnownFunction(Handle<JSFunction> function, | |
193 int formal_parameter_count, int arity, | |
194 LInstruction* instr); | |
195 | |
196 void RecordSafepointWithLazyDeopt(LInstruction* instr, | |
197 SafepointMode safepoint_mode, | |
198 int argc); | |
199 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, | |
200 Safepoint::DeoptMode mode); | |
201 void DeoptimizeIf(Condition cc, LInstruction* instr, | |
202 Deoptimizer::DeoptReason deopt_reason, | |
203 Deoptimizer::BailoutType bailout_type); | |
204 void DeoptimizeIf(Condition cc, LInstruction* instr, | |
205 Deoptimizer::DeoptReason deopt_reason); | |
206 | |
207 bool DeoptEveryNTimes() { | |
208 return FLAG_deopt_every_n_times != 0 && !info()->IsStub(); | |
209 } | |
210 | |
211 void AddToTranslation(LEnvironment* environment, | |
212 Translation* translation, | |
213 LOperand* op, | |
214 bool is_tagged, | |
215 bool is_uint32, | |
216 int* object_index_pointer, | |
217 int* dematerialized_index_pointer); | |
218 void PopulateDeoptimizationData(Handle<Code> code); | |
219 | |
220 void PopulateDeoptimizationLiteralsWithInlinedFunctions(); | |
221 | |
222 Register ToRegister(int index) const; | |
223 XMMRegister ToDoubleRegister(int index) const; | |
224 Operand BuildFastArrayOperand( | |
225 LOperand* elements_pointer, | |
226 LOperand* key, | |
227 Representation key_representation, | |
228 ElementsKind elements_kind, | |
229 uint32_t base_offset); | |
230 | |
231 Operand BuildSeqStringOperand(Register string, | |
232 LOperand* index, | |
233 String::Encoding encoding); | |
234 | |
235 void EmitIntegerMathAbs(LMathAbs* instr); | |
236 void EmitSmiMathAbs(LMathAbs* instr); | |
237 | |
238 // Support for recording safepoint and position information. | |
239 void RecordSafepoint(LPointerMap* pointers, | |
240 Safepoint::Kind kind, | |
241 int arguments, | |
242 Safepoint::DeoptMode mode); | |
243 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); | |
244 void RecordSafepoint(Safepoint::DeoptMode mode); | |
245 void RecordSafepointWithRegisters(LPointerMap* pointers, | |
246 int arguments, | |
247 Safepoint::DeoptMode mode); | |
248 void RecordAndWritePosition(int position) override; | |
249 | |
250 static Condition TokenToCondition(Token::Value op, bool is_unsigned); | |
251 void EmitGoto(int block); | |
252 | |
253 // EmitBranch expects to be the last instruction of a block. | |
254 template<class InstrType> | |
255 void EmitBranch(InstrType instr, Condition cc); | |
256 template <class InstrType> | |
257 void EmitTrueBranch(InstrType instr, Condition cc); | |
258 template <class InstrType> | |
259 void EmitFalseBranch(InstrType instr, Condition cc); | |
260 void EmitNumberUntagD(LNumberUntagD* instr, Register input, | |
261 XMMRegister result, NumberUntagDMode mode); | |
262 | |
263 // Emits optimized code for typeof x == "y". Modifies input register. | |
264 // Returns the condition on which a final split to | |
265 // true and false label should be made, to optimize fallthrough. | |
266 Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input); | |
267 | |
268 // Emits optimized code for %_IsString(x). Preserves input register. | |
269 // Returns the condition on which a final split to | |
270 // true and false label should be made, to optimize fallthrough. | |
271 Condition EmitIsString(Register input, | |
272 Register temp1, | |
273 Label* is_not_string, | |
274 SmiCheck check_needed); | |
275 | |
276 // Emits optimized code for %_IsConstructCall(). | |
277 // Caller should branch on equal condition. | |
278 void EmitIsConstructCall(Register temp); | |
279 | |
280 // Emits code for pushing either a tagged constant, a (non-double) | |
281 // register, or a stack slot operand. | |
282 void EmitPushTaggedOperand(LOperand* operand); | |
283 | |
284 // Emits optimized code to deep-copy the contents of statically known | |
285 // object graphs (e.g. object literal boilerplate). | |
286 void EmitDeepCopy(Handle<JSObject> object, | |
287 Register result, | |
288 Register source, | |
289 int* offset, | |
290 AllocationSiteMode mode); | |
291 | |
292 void EnsureSpaceForLazyDeopt(int space_needed) override; | |
293 void DoLoadKeyedExternalArray(LLoadKeyed* instr); | |
294 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); | |
295 void DoLoadKeyedFixedArray(LLoadKeyed* instr); | |
296 void DoStoreKeyedExternalArray(LStoreKeyed* instr); | |
297 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); | |
298 void DoStoreKeyedFixedArray(LStoreKeyed* instr); | |
299 | |
300 template <class T> | |
301 void EmitVectorLoadICRegisters(T* instr); | |
302 template <class T> | |
303 void EmitVectorStoreICRegisters(T* instr); | |
304 | |
305 #ifdef _MSC_VER | |
306 // On windows, you may not access the stack more than one page below | |
307 // the most recently mapped page. To make the allocated area randomly | |
308 // accessible, we write an arbitrary value to each page in range | |
309 // rsp + offset - page_size .. rsp in turn. | |
310 void MakeSureStackPagesMapped(int offset); | |
311 #endif | |
312 | |
313 ZoneList<LEnvironment*> deoptimizations_; | |
314 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; | |
315 int inlined_function_count_; | |
316 Scope* const scope_; | |
317 TranslationBuffer translations_; | |
318 ZoneList<LDeferredCode*> deferred_; | |
319 int osr_pc_offset_; | |
320 bool frame_is_built_; | |
321 | |
322 // Builder that keeps track of safepoints in the code. The table | |
323 // itself is emitted at the end of the generated code. | |
324 SafepointTableBuilder safepoints_; | |
325 | |
326 // Compiler from a set of parallel moves to a sequential list of moves. | |
327 LGapResolver resolver_; | |
328 | |
329 Safepoint::Kind expected_safepoint_kind_; | |
330 | |
331 class PushSafepointRegistersScope final BASE_EMBEDDED { | |
332 public: | |
333 explicit PushSafepointRegistersScope(LCodeGen* codegen) | |
334 : codegen_(codegen) { | |
335 DCHECK(codegen_->info()->is_calling()); | |
336 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); | |
337 codegen_->masm_->PushSafepointRegisters(); | |
338 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; | |
339 } | |
340 | |
341 ~PushSafepointRegistersScope() { | |
342 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); | |
343 codegen_->masm_->PopSafepointRegisters(); | |
344 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; | |
345 } | |
346 | |
347 private: | |
348 LCodeGen* codegen_; | |
349 }; | |
350 | |
351 friend class LDeferredCode; | |
352 friend class LEnvironment; | |
353 friend class SafepointGenerator; | |
354 DISALLOW_COPY_AND_ASSIGN(LCodeGen); | |
355 }; | |
356 | |
357 | |
358 class LDeferredCode: public ZoneObject { | |
359 public: | |
360 explicit LDeferredCode(LCodeGen* codegen) | |
361 : codegen_(codegen), | |
362 external_exit_(NULL), | |
363 instruction_index_(codegen->current_instruction_) { | |
364 codegen->AddDeferredCode(this); | |
365 } | |
366 | |
367 virtual ~LDeferredCode() {} | |
368 virtual void Generate() = 0; | |
369 virtual LInstruction* instr() = 0; | |
370 | |
371 void SetExit(Label* exit) { external_exit_ = exit; } | |
372 Label* entry() { return &entry_; } | |
373 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } | |
374 Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); } | |
375 int instruction_index() const { return instruction_index_; } | |
376 | |
377 protected: | |
378 LCodeGen* codegen() const { return codegen_; } | |
379 MacroAssembler* masm() const { return codegen_->masm(); } | |
380 | |
381 private: | |
382 LCodeGen* codegen_; | |
383 Label entry_; | |
384 Label exit_; | |
385 Label done_; | |
386 Label* external_exit_; | |
387 int instruction_index_; | |
388 }; | |
389 | |
390 } // namespace internal | |
391 } // namespace v8 | |
392 | |
393 #endif // V8_X64_LITHIUM_CODEGEN_X64_H_ | |
OLD | NEW |