Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Side by Side Diff: src/ia32/lithium-ia32.h

Issue 6529055: [Isolates] Merge crankshaft (r5922 from bleeding_edge). (Closed)
Patch Set: Win32 port Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ia32/lithium-codegen-ia32.cc ('k') | src/ia32/lithium-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 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_IA32_H_
29 #define V8_IA32_LITHIUM_IA32_H_
30
31 #include "hydrogen.h"
32 #include "lithium-allocator.h"
33 #include "safepoint-table.h"
34
35 namespace v8 {
36 namespace internal {
37
38 // Forward declarations.
39 class LCodeGen;
40 class LEnvironment;
41 class Translation;
42 class LGapNode;
43
44
45 // Type hierarchy:
46 //
47 // LInstruction
48 // LAccessArgumentsAt
49 // LArgumentsElements
50 // LArgumentsLength
51 // LBinaryOperation
52 // LAddI
53 // LApplyArguments
54 // LArithmeticD
55 // LArithmeticT
56 // LBitI
57 // LBoundsCheck
58 // LCmpID
59 // LCmpIDAndBranch
60 // LCmpJSObjectEq
61 // LCmpJSObjectEqAndBranch
62 // LCmpT
63 // LDivI
64 // LInstanceOf
65 // LInstanceOfAndBranch
66 // LLoadKeyedFastElement
67 // LLoadKeyedGeneric
68 // LModI
69 // LMulI
70 // LShiftI
71 // LSubI
72 // LCallConstantFunction
73 // LCallFunction
74 // LCallGlobal
75 // LCallKeyed
76 // LCallKnownGlobal
77 // LCallNamed
78 // LCallRuntime
79 // LCallStub
80 // LConstant
81 // LConstantD
82 // LConstantI
83 // LConstantT
84 // LDeoptimize
85 // LFunctionLiteral
86 // LGlobalObject
87 // LGlobalReceiver
88 // LLabel
89 // LLayzBailout
90 // LLoadGlobal
91 // LMaterializedLiteral
92 // LArrayLiteral
93 // LObjectLiteral
94 // LRegExpLiteral
95 // LOsrEntry
96 // LParameter
97 // LRegExpConstructResult
98 // LStackCheck
99 // LStoreKeyed
100 // LStoreKeyedFastElement
101 // LStoreKeyedGeneric
102 // LStoreNamed
103 // LStoreNamedField
104 // LStoreNamedGeneric
105 // LUnaryOperation
106 // LArrayLength
107 // LBitNotI
108 // LBranch
109 // LCallNew
110 // LCheckFunction
111 // LCheckInstanceType
112 // LCheckMap
113 // LCheckPrototypeMaps
114 // LCheckSmi
115 // LClassOfTest
116 // LClassOfTestAndBranch
117 // LDeleteProperty
118 // LDoubleToI
119 // LHasCachedArrayIndex
120 // LHasCachedArrayIndexAndBranch
121 // LHasInstanceType
122 // LHasInstanceTypeAndBranch
123 // LInteger32ToDouble
124 // LIsNull
125 // LIsNullAndBranch
126 // LIsSmi
127 // LIsSmiAndBranch
128 // LLoadNamedField
129 // LLoadNamedGeneric
130 // LNumberTagD
131 // LNumberTagI
132 // LPushArgument
133 // LReturn
134 // LSmiTag
135 // LStoreGlobal
136 // LTaggedToI
137 // LThrow
138 // LTypeof
139 // LTypeofIs
140 // LTypeofIsAndBranch
141 // LUnaryMathOperation
142 // LValueOf
143 // LUnknownOSRValue
144
145 #define LITHIUM_ALL_INSTRUCTION_LIST(V) \
146 V(BinaryOperation) \
147 V(Constant) \
148 V(Call) \
149 V(MaterializedLiteral) \
150 V(StoreKeyed) \
151 V(StoreNamed) \
152 V(UnaryOperation) \
153 LITHIUM_CONCRETE_INSTRUCTION_LIST(V)
154
155
156 #define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
157 V(AccessArgumentsAt) \
158 V(AddI) \
159 V(ApplyArguments) \
160 V(ArgumentsElements) \
161 V(ArgumentsLength) \
162 V(ArithmeticD) \
163 V(ArithmeticT) \
164 V(ArrayLength) \
165 V(ArrayLiteral) \
166 V(BitI) \
167 V(BitNotI) \
168 V(BoundsCheck) \
169 V(Branch) \
170 V(CallConstantFunction) \
171 V(CallFunction) \
172 V(CallGlobal) \
173 V(CallKeyed) \
174 V(CallKnownGlobal) \
175 V(CallNamed) \
176 V(CallNew) \
177 V(CallRuntime) \
178 V(CallStub) \
179 V(CheckFunction) \
180 V(CheckInstanceType) \
181 V(CheckMap) \
182 V(CheckPrototypeMaps) \
183 V(CheckSmi) \
184 V(CmpID) \
185 V(CmpIDAndBranch) \
186 V(CmpJSObjectEq) \
187 V(CmpJSObjectEqAndBranch) \
188 V(CmpMapAndBranch) \
189 V(CmpT) \
190 V(CmpTAndBranch) \
191 V(ConstantD) \
192 V(ConstantI) \
193 V(ConstantT) \
194 V(DeleteProperty) \
195 V(Deoptimize) \
196 V(DivI) \
197 V(DoubleToI) \
198 V(FunctionLiteral) \
199 V(Gap) \
200 V(GlobalObject) \
201 V(GlobalReceiver) \
202 V(Goto) \
203 V(InstanceOf) \
204 V(InstanceOfAndBranch) \
205 V(Integer32ToDouble) \
206 V(IsNull) \
207 V(IsNullAndBranch) \
208 V(IsSmi) \
209 V(IsSmiAndBranch) \
210 V(HasInstanceType) \
211 V(HasInstanceTypeAndBranch) \
212 V(HasCachedArrayIndex) \
213 V(HasCachedArrayIndexAndBranch) \
214 V(ClassOfTest) \
215 V(ClassOfTestAndBranch) \
216 V(Label) \
217 V(LazyBailout) \
218 V(LoadElements) \
219 V(LoadGlobal) \
220 V(LoadKeyedFastElement) \
221 V(LoadKeyedGeneric) \
222 V(LoadNamedField) \
223 V(LoadNamedGeneric) \
224 V(ModI) \
225 V(MulI) \
226 V(NumberTagD) \
227 V(NumberTagI) \
228 V(NumberUntagD) \
229 V(ObjectLiteral) \
230 V(OsrEntry) \
231 V(Parameter) \
232 V(PushArgument) \
233 V(RegExpLiteral) \
234 V(Return) \
235 V(ShiftI) \
236 V(SmiTag) \
237 V(SmiUntag) \
238 V(StackCheck) \
239 V(StoreGlobal) \
240 V(StoreKeyedFastElement) \
241 V(StoreKeyedGeneric) \
242 V(StoreNamedField) \
243 V(StoreNamedGeneric) \
244 V(SubI) \
245 V(TaggedToI) \
246 V(Throw) \
247 V(Typeof) \
248 V(TypeofIs) \
249 V(TypeofIsAndBranch) \
250 V(UnaryMathOperation) \
251 V(UnknownOSRValue) \
252 V(ValueOf)
253
254
255 #define DECLARE_INSTRUCTION(type) \
256 virtual bool Is##type() const { return true; } \
257 static L##type* cast(LInstruction* instr) { \
258 ASSERT(instr->Is##type()); \
259 return reinterpret_cast<L##type*>(instr); \
260 }
261
262
263 #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
264 virtual void CompileToNative(LCodeGen* generator); \
265 virtual const char* Mnemonic() const { return mnemonic; } \
266 DECLARE_INSTRUCTION(type)
267
268
269 #define DECLARE_HYDROGEN_ACCESSOR(type) \
270 H##type* hydrogen() const { \
271 return H##type::cast(hydrogen_value()); \
272 }
273
274
275 class LInstruction: public ZoneObject {
276 public:
277 LInstruction()
278 : hydrogen_value_(NULL) { }
279 virtual ~LInstruction() { }
280
281 virtual void CompileToNative(LCodeGen* generator) = 0;
282 virtual const char* Mnemonic() const = 0;
283 virtual void PrintTo(StringStream* stream) const;
284 virtual void PrintDataTo(StringStream* stream) const { }
285
286 // Declare virtual type testers.
287 #define DECLARE_DO(type) virtual bool Is##type() const { return false; }
288 LITHIUM_ALL_INSTRUCTION_LIST(DECLARE_DO)
289 #undef DECLARE_DO
290 virtual bool IsControl() const { return false; }
291
292 void set_environment(LEnvironment* env) { environment_.set(env); }
293 LEnvironment* environment() const { return environment_.get(); }
294 bool HasEnvironment() const { return environment_.is_set(); }
295
296 void set_pointer_map(LPointerMap* p) { pointer_map_.set(p); }
297 LPointerMap* pointer_map() const { return pointer_map_.get(); }
298 bool HasPointerMap() const { return pointer_map_.is_set(); }
299
300 void set_result(LOperand* operand) { result_.set(operand); }
301 LOperand* result() const { return result_.get(); }
302 bool HasResult() const { return result_.is_set(); }
303
304 void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
305 HValue* hydrogen_value() const { return hydrogen_value_; }
306
307 void set_deoptimization_environment(LEnvironment* env) {
308 deoptimization_environment_.set(env);
309 }
310 LEnvironment* deoptimization_environment() const {
311 return deoptimization_environment_.get();
312 }
313 bool HasDeoptimizationEnvironment() const {
314 return deoptimization_environment_.is_set();
315 }
316
317 private:
318 SetOncePointer<LEnvironment> environment_;
319 SetOncePointer<LPointerMap> pointer_map_;
320 SetOncePointer<LOperand> result_;
321 HValue* hydrogen_value_;
322 SetOncePointer<LEnvironment> deoptimization_environment_;
323 };
324
325
326 class LGapResolver BASE_EMBEDDED {
327 public:
328 LGapResolver(const ZoneList<LMoveOperands>* moves, LOperand* marker_operand);
329 const ZoneList<LMoveOperands>* ResolveInReverseOrder();
330
331 private:
332 LGapNode* LookupNode(LOperand* operand);
333 bool CanReach(LGapNode* a, LGapNode* b, int visited_id);
334 bool CanReach(LGapNode* a, LGapNode* b);
335 void RegisterMove(LMoveOperands move);
336 void AddResultMove(LOperand* from, LOperand* to);
337 void AddResultMove(LGapNode* from, LGapNode* to);
338 void ResolveCycle(LGapNode* start);
339
340 ZoneList<LGapNode*> nodes_;
341 ZoneList<LGapNode*> identified_cycles_;
342 ZoneList<LMoveOperands> result_;
343 LOperand* marker_operand_;
344 int next_visited_id_;
345 int bailout_after_ast_id_;
346 };
347
348
349 class LParallelMove : public ZoneObject {
350 public:
351 LParallelMove() : move_operands_(4) { }
352
353 void AddMove(LOperand* from, LOperand* to) {
354 move_operands_.Add(LMoveOperands(from, to));
355 }
356
357 bool IsRedundant() const;
358
359 const ZoneList<LMoveOperands>* move_operands() const {
360 return &move_operands_;
361 }
362
363 void PrintDataTo(StringStream* stream) const;
364
365 private:
366 ZoneList<LMoveOperands> move_operands_;
367 };
368
369
370 class LGap: public LInstruction {
371 public:
372 explicit LGap(HBasicBlock* block)
373 : block_(block) {
374 parallel_moves_[BEFORE] = NULL;
375 parallel_moves_[START] = NULL;
376 parallel_moves_[END] = NULL;
377 parallel_moves_[AFTER] = NULL;
378 }
379
380 DECLARE_CONCRETE_INSTRUCTION(Gap, "gap")
381 virtual void PrintDataTo(StringStream* stream) const;
382
383 bool IsRedundant() const;
384
385 HBasicBlock* block() const { return block_; }
386
387 enum InnerPosition {
388 BEFORE,
389 START,
390 END,
391 AFTER,
392 FIRST_INNER_POSITION = BEFORE,
393 LAST_INNER_POSITION = AFTER
394 };
395
396 LParallelMove* GetOrCreateParallelMove(InnerPosition pos) {
397 if (parallel_moves_[pos] == NULL) parallel_moves_[pos] = new LParallelMove;
398 return parallel_moves_[pos];
399 }
400
401 LParallelMove* GetParallelMove(InnerPosition pos) {
402 return parallel_moves_[pos];
403 }
404
405 private:
406 LParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
407 HBasicBlock* block_;
408 };
409
410
411 class LGoto: public LInstruction {
412 public:
413 LGoto(int block_id, bool include_stack_check = false)
414 : block_id_(block_id), include_stack_check_(include_stack_check) { }
415
416 DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
417 virtual void PrintDataTo(StringStream* stream) const;
418 virtual bool IsControl() const { return true; }
419
420 int block_id() const { return block_id_; }
421 bool include_stack_check() const { return include_stack_check_; }
422
423 private:
424 int block_id_;
425 bool include_stack_check_;
426 };
427
428
429 class LLazyBailout: public LInstruction {
430 public:
431 LLazyBailout() : gap_instructions_size_(0) { }
432
433 DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
434
435 void set_gap_instructions_size(int gap_instructions_size) {
436 gap_instructions_size_ = gap_instructions_size;
437 }
438 int gap_instructions_size() { return gap_instructions_size_; }
439
440 private:
441 int gap_instructions_size_;
442 };
443
444
445 class LDeoptimize: public LInstruction {
446 public:
447 DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
448 };
449
450
451 class LLabel: public LGap {
452 public:
453 explicit LLabel(HBasicBlock* block)
454 : LGap(block), replacement_(NULL) { }
455
456 DECLARE_CONCRETE_INSTRUCTION(Label, "label")
457
458 virtual void PrintDataTo(StringStream* stream) const;
459
460 int block_id() const { return block()->block_id(); }
461 bool is_loop_header() const { return block()->IsLoopHeader(); }
462 Label* label() { return &label_; }
463 LLabel* replacement() const { return replacement_; }
464 void set_replacement(LLabel* label) { replacement_ = label; }
465 bool HasReplacement() const { return replacement_ != NULL; }
466
467 private:
468 Label label_;
469 LLabel* replacement_;
470 };
471
472
473 class LParameter: public LInstruction {
474 public:
475 DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
476 };
477
478
479 class LCallStub: public LInstruction {
480 public:
481 DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
482 DECLARE_HYDROGEN_ACCESSOR(CallStub)
483
484 TranscendentalCache::Type transcendental_type() {
485 return hydrogen()->transcendental_type();
486 }
487 };
488
489
490 class LUnknownOSRValue: public LInstruction {
491 public:
492 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
493 };
494
495
496 class LUnaryOperation: public LInstruction {
497 public:
498 explicit LUnaryOperation(LOperand* input) : input_(input) { }
499
500 DECLARE_INSTRUCTION(UnaryOperation)
501
502 LOperand* input() const { return input_; }
503
504 virtual void PrintDataTo(StringStream* stream) const;
505
506 private:
507 LOperand* input_;
508 };
509
510
511 class LBinaryOperation: public LInstruction {
512 public:
513 LBinaryOperation(LOperand* left, LOperand* right)
514 : left_(left), right_(right) { }
515
516 DECLARE_INSTRUCTION(BinaryOperation)
517
518 LOperand* left() const { return left_; }
519 LOperand* right() const { return right_; }
520 virtual void PrintDataTo(StringStream* stream) const;
521
522 private:
523 LOperand* left_;
524 LOperand* right_;
525 };
526
527
528 class LApplyArguments: public LBinaryOperation {
529 public:
530 LApplyArguments(LOperand* function,
531 LOperand* receiver,
532 LOperand* length,
533 LOperand* elements)
534 : LBinaryOperation(function, receiver),
535 length_(length),
536 elements_(elements) { }
537
538 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
539
540 LOperand* function() const { return left(); }
541 LOperand* receiver() const { return right(); }
542 LOperand* length() const { return length_; }
543 LOperand* elements() const { return elements_; }
544
545 private:
546 LOperand* length_;
547 LOperand* elements_;
548 };
549
550
551 class LAccessArgumentsAt: public LInstruction {
552 public:
553 LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index)
554 : arguments_(arguments), length_(length), index_(index) { }
555
556 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
557
558 LOperand* arguments() const { return arguments_; }
559 LOperand* length() const { return length_; }
560 LOperand* index() const { return index_; }
561
562 virtual void PrintDataTo(StringStream* stream) const;
563
564 private:
565 LOperand* arguments_;
566 LOperand* length_;
567 LOperand* index_;
568 };
569
570
571 class LArgumentsLength: public LUnaryOperation {
572 public:
573 explicit LArgumentsLength(LOperand* elements) : LUnaryOperation(elements) {}
574
575 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
576 };
577
578
579 class LArgumentsElements: public LInstruction {
580 public:
581 LArgumentsElements() { }
582
583 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
584 };
585
586
587 class LModI: public LBinaryOperation {
588 public:
589 LModI(LOperand* left, LOperand* right) : LBinaryOperation(left, right) { }
590
591 DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
592 DECLARE_HYDROGEN_ACCESSOR(Mod)
593 };
594
595
596 class LDivI: public LBinaryOperation {
597 public:
598 LDivI(LOperand* left, LOperand* right)
599 : LBinaryOperation(left, right) { }
600
601 DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
602 DECLARE_HYDROGEN_ACCESSOR(Div)
603 };
604
605
606 class LMulI: public LBinaryOperation {
607 public:
608 LMulI(LOperand* left, LOperand* right, LOperand* temp)
609 : LBinaryOperation(left, right), temp_(temp) { }
610
611 DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
612 DECLARE_HYDROGEN_ACCESSOR(Mul)
613
614 LOperand* temp() const { return temp_; }
615
616 private:
617 LOperand* temp_;
618 };
619
620
621 class LCmpID: public LBinaryOperation {
622 public:
623 LCmpID(Token::Value op, LOperand* left, LOperand* right, bool is_double)
624 : LBinaryOperation(left, right), op_(op), is_double_(is_double) { }
625
626 Token::Value op() const { return op_; }
627 bool is_double() const { return is_double_; }
628
629 DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id")
630
631 private:
632 Token::Value op_;
633 bool is_double_;
634 };
635
636
637 class LCmpIDAndBranch: public LCmpID {
638 public:
639 LCmpIDAndBranch(Token::Value op,
640 LOperand* left,
641 LOperand* right,
642 int true_block_id,
643 int false_block_id,
644 bool is_double)
645 : LCmpID(op, left, right, is_double),
646 true_block_id_(true_block_id),
647 false_block_id_(false_block_id) { }
648
649 DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
650 virtual void PrintDataTo(StringStream* stream) const;
651 virtual bool IsControl() const { return true; }
652
653 int true_block_id() const { return true_block_id_; }
654 int false_block_id() const { return false_block_id_; }
655
656 private:
657 int true_block_id_;
658 int false_block_id_;
659 };
660
661
662 class LUnaryMathOperation: public LUnaryOperation {
663 public:
664 explicit LUnaryMathOperation(LOperand* value)
665 : LUnaryOperation(value) { }
666
667 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
668 DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
669
670 virtual void PrintDataTo(StringStream* stream) const;
671 MathFunctionId op() const { return hydrogen()->op(); }
672 };
673
674
675 class LCmpJSObjectEq: public LBinaryOperation {
676 public:
677 LCmpJSObjectEq(LOperand* left, LOperand* right)
678 : LBinaryOperation(left, right) {}
679
680 DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEq, "cmp-jsobject-eq")
681 };
682
683
684 class LCmpJSObjectEqAndBranch: public LCmpJSObjectEq {
685 public:
686 LCmpJSObjectEqAndBranch(LOperand* left,
687 LOperand* right,
688 int true_block_id,
689 int false_block_id)
690 : LCmpJSObjectEq(left, right),
691 true_block_id_(true_block_id),
692 false_block_id_(false_block_id) { }
693
694 DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEqAndBranch,
695 "cmp-jsobject-eq-and-branch")
696
697 int true_block_id() const { return true_block_id_; }
698 int false_block_id() const { return false_block_id_; }
699
700 private:
701 int true_block_id_;
702 int false_block_id_;
703 };
704
705
706 class LIsNull: public LUnaryOperation {
707 public:
708 LIsNull(LOperand* value, bool is_strict)
709 : LUnaryOperation(value), is_strict_(is_strict) {}
710
711 DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null")
712
713 bool is_strict() const { return is_strict_; }
714
715 private:
716 bool is_strict_;
717 };
718
719
720 class LIsNullAndBranch: public LIsNull {
721 public:
722 LIsNullAndBranch(LOperand* value,
723 bool is_strict,
724 LOperand* temp,
725 int true_block_id,
726 int false_block_id)
727 : LIsNull(value, is_strict),
728 temp_(temp),
729 true_block_id_(true_block_id),
730 false_block_id_(false_block_id) { }
731
732 DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch")
733 virtual void PrintDataTo(StringStream* stream) const;
734 virtual bool IsControl() const { return true; }
735
736 int true_block_id() const { return true_block_id_; }
737 int false_block_id() const { return false_block_id_; }
738
739 LOperand* temp() const { return temp_; }
740
741 private:
742 LOperand* temp_;
743 int true_block_id_;
744 int false_block_id_;
745 };
746
747
748 class LIsSmi: public LUnaryOperation {
749 public:
750 explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {}
751
752 DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi")
753 DECLARE_HYDROGEN_ACCESSOR(IsSmi)
754 };
755
756
757 class LIsSmiAndBranch: public LIsSmi {
758 public:
759 LIsSmiAndBranch(LOperand* value,
760 int true_block_id,
761 int false_block_id)
762 : LIsSmi(value),
763 true_block_id_(true_block_id),
764 false_block_id_(false_block_id) { }
765
766 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
767 virtual void PrintDataTo(StringStream* stream) const;
768 virtual bool IsControl() const { return true; }
769
770 int true_block_id() const { return true_block_id_; }
771 int false_block_id() const { return false_block_id_; }
772
773 private:
774 int true_block_id_;
775 int false_block_id_;
776 };
777
778
779 class LHasInstanceType: public LUnaryOperation {
780 public:
781 explicit LHasInstanceType(LOperand* value)
782 : LUnaryOperation(value) { }
783
784 DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type")
785 DECLARE_HYDROGEN_ACCESSOR(HasInstanceType)
786
787 InstanceType TestType(); // The type to test against when generating code.
788 Condition BranchCondition(); // The branch condition for 'true'.
789 };
790
791
792 class LHasInstanceTypeAndBranch: public LHasInstanceType {
793 public:
794 LHasInstanceTypeAndBranch(LOperand* value,
795 LOperand* temporary,
796 int true_block_id,
797 int false_block_id)
798 : LHasInstanceType(value),
799 temp_(temporary),
800 true_block_id_(true_block_id),
801 false_block_id_(false_block_id) { }
802
803 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
804 "has-instance-type-and-branch")
805 virtual void PrintDataTo(StringStream* stream) const;
806 virtual bool IsControl() const { return true; }
807
808 int true_block_id() const { return true_block_id_; }
809 int false_block_id() const { return false_block_id_; }
810
811 LOperand* temp() { return temp_; }
812
813 private:
814 LOperand* temp_;
815 int true_block_id_;
816 int false_block_id_;
817 };
818
819
820 class LHasCachedArrayIndex: public LUnaryOperation {
821 public:
822 explicit LHasCachedArrayIndex(LOperand* value) : LUnaryOperation(value) {}
823
824 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index")
825 DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex)
826 };
827
828
829 class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex {
830 public:
831 LHasCachedArrayIndexAndBranch(LOperand* value,
832 int true_block_id,
833 int false_block_id)
834 : LHasCachedArrayIndex(value),
835 true_block_id_(true_block_id),
836 false_block_id_(false_block_id) { }
837
838 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
839 "has-cached-array-index-and-branch")
840 virtual void PrintDataTo(StringStream* stream) const;
841 virtual bool IsControl() const { return true; }
842
843 int true_block_id() const { return true_block_id_; }
844 int false_block_id() const { return false_block_id_; }
845
846 private:
847 int true_block_id_;
848 int false_block_id_;
849 };
850
851
852 class LClassOfTest: public LUnaryOperation {
853 public:
854 LClassOfTest(LOperand* value, LOperand* temp)
855 : LUnaryOperation(value), temporary_(temp) {}
856
857 DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
858 DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
859
860 virtual void PrintDataTo(StringStream* stream) const;
861
862 LOperand* temporary() { return temporary_; }
863
864 private:
865 LOperand *temporary_;
866 };
867
868
869 class LClassOfTestAndBranch: public LClassOfTest {
870 public:
871 LClassOfTestAndBranch(LOperand* value,
872 LOperand* temporary,
873 LOperand* temporary2,
874 int true_block_id,
875 int false_block_id)
876 : LClassOfTest(value, temporary),
877 temporary2_(temporary2),
878 true_block_id_(true_block_id),
879 false_block_id_(false_block_id) { }
880
881 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
882 "class-of-test-and-branch")
883 virtual void PrintDataTo(StringStream* stream) const;
884 virtual bool IsControl() const { return true; }
885
886 int true_block_id() const { return true_block_id_; }
887 int false_block_id() const { return false_block_id_; }
888 LOperand* temporary2() { return temporary2_; }
889
890 private:
891 LOperand* temporary2_;
892 int true_block_id_;
893 int false_block_id_;
894 };
895
896
897 class LCmpT: public LBinaryOperation {
898 public:
899 LCmpT(LOperand* left, LOperand* right) : LBinaryOperation(left, right) {}
900
901 DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
902 DECLARE_HYDROGEN_ACCESSOR(Compare)
903
904 Token::Value op() const { return hydrogen()->token(); }
905 };
906
907
908 class LCmpTAndBranch: public LCmpT {
909 public:
910 LCmpTAndBranch(LOperand* left,
911 LOperand* right,
912 int true_block_id,
913 int false_block_id)
914 : LCmpT(left, right),
915 true_block_id_(true_block_id),
916 false_block_id_(false_block_id) { }
917
918 DECLARE_CONCRETE_INSTRUCTION(CmpTAndBranch, "cmp-t-and-branch")
919
920 int true_block_id() const { return true_block_id_; }
921 int false_block_id() const { return false_block_id_; }
922
923 private:
924 int true_block_id_;
925 int false_block_id_;
926 };
927
928
929 class LInstanceOf: public LBinaryOperation {
930 public:
931 LInstanceOf(LOperand* left, LOperand* right)
932 : LBinaryOperation(left, right) { }
933
934 DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
935 };
936
937
938 class LInstanceOfAndBranch: public LInstanceOf {
939 public:
940 LInstanceOfAndBranch(LOperand* left,
941 LOperand* right,
942 int true_block_id,
943 int false_block_id)
944 : LInstanceOf(left, right),
945 true_block_id_(true_block_id),
946 false_block_id_(false_block_id) { }
947
948 DECLARE_CONCRETE_INSTRUCTION(InstanceOfAndBranch, "instance-of-and-branch")
949
950 int true_block_id() const { return true_block_id_; }
951 int false_block_id() const { return false_block_id_; }
952
953 private:
954 int true_block_id_;
955 int false_block_id_;
956 };
957
958
959 class LBoundsCheck: public LBinaryOperation {
960 public:
961 LBoundsCheck(LOperand* index, LOperand* length)
962 : LBinaryOperation(index, length) { }
963
964 LOperand* index() const { return left(); }
965 LOperand* length() const { return right(); }
966
967 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
968 };
969
970
971 class LBitI: public LBinaryOperation {
972 public:
973 LBitI(Token::Value op, LOperand* left, LOperand* right)
974 : LBinaryOperation(left, right), op_(op) { }
975
976 Token::Value op() const { return op_; }
977
978 DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
979
980 private:
981 Token::Value op_;
982 };
983
984
985 class LShiftI: public LBinaryOperation {
986 public:
987 LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
988 : LBinaryOperation(left, right), op_(op), can_deopt_(can_deopt) { }
989
990 Token::Value op() const { return op_; }
991
992 bool can_deopt() const { return can_deopt_; }
993
994 DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
995
996 private:
997 Token::Value op_;
998 bool can_deopt_;
999 };
1000
1001
1002 class LSubI: public LBinaryOperation {
1003 public:
1004 LSubI(LOperand* left, LOperand* right)
1005 : LBinaryOperation(left, right) { }
1006
1007 DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
1008 DECLARE_HYDROGEN_ACCESSOR(Sub)
1009 };
1010
1011
1012 class LConstant: public LInstruction {
1013 DECLARE_INSTRUCTION(Constant)
1014 };
1015
1016
1017 class LConstantI: public LConstant {
1018 public:
1019 explicit LConstantI(int32_t value) : value_(value) { }
1020 int32_t value() const { return value_; }
1021
1022 DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
1023
1024 private:
1025 int32_t value_;
1026 };
1027
1028
1029 class LConstantD: public LConstant {
1030 public:
1031 explicit LConstantD(double value) : value_(value) { }
1032 double value() const { return value_; }
1033
1034 DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
1035
1036 private:
1037 double value_;
1038 };
1039
1040
1041 class LConstantT: public LConstant {
1042 public:
1043 explicit LConstantT(Handle<Object> value) : value_(value) { }
1044 Handle<Object> value() const { return value_; }
1045
1046 DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
1047
1048 private:
1049 Handle<Object> value_;
1050 };
1051
1052
1053 class LBranch: public LUnaryOperation {
1054 public:
1055 LBranch(LOperand* input, int true_block_id, int false_block_id)
1056 : LUnaryOperation(input),
1057 true_block_id_(true_block_id),
1058 false_block_id_(false_block_id) { }
1059
1060 DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
1061 DECLARE_HYDROGEN_ACCESSOR(Value)
1062
1063 virtual void PrintDataTo(StringStream* stream) const;
1064 virtual bool IsControl() const { return true; }
1065
1066 int true_block_id() const { return true_block_id_; }
1067 int false_block_id() const { return false_block_id_; }
1068
1069 private:
1070 int true_block_id_;
1071 int false_block_id_;
1072 };
1073
1074
1075 class LCmpMapAndBranch: public LUnaryOperation {
1076 public:
1077 LCmpMapAndBranch(LOperand* value,
1078 Handle<Map> map,
1079 int true_block_id,
1080 int false_block_id)
1081 : LUnaryOperation(value),
1082 map_(map),
1083 true_block_id_(true_block_id),
1084 false_block_id_(false_block_id) { }
1085
1086 DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
1087
1088 virtual bool IsControl() const { return true; }
1089
1090 Handle<Map> map() const { return map_; }
1091 int true_block_id() const { return true_block_id_; }
1092 int false_block_id() const { return false_block_id_; }
1093
1094 private:
1095 Handle<Map> map_;
1096 int true_block_id_;
1097 int false_block_id_;
1098 };
1099
1100
1101 class LArrayLength: public LUnaryOperation {
1102 public:
1103 LArrayLength(LOperand* input, LOperand* temporary)
1104 : LUnaryOperation(input), temporary_(temporary) { }
1105
1106 LOperand* temporary() const { return temporary_; }
1107
1108 DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array-length")
1109 DECLARE_HYDROGEN_ACCESSOR(ArrayLength)
1110
1111 private:
1112 LOperand* temporary_;
1113 };
1114
1115
1116 class LValueOf: public LUnaryOperation {
1117 public:
1118 LValueOf(LOperand* input, LOperand* temporary)
1119 : LUnaryOperation(input), temporary_(temporary) { }
1120
1121 LOperand* temporary() const { return temporary_; }
1122
1123 DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of")
1124 DECLARE_HYDROGEN_ACCESSOR(ValueOf)
1125
1126 private:
1127 LOperand* temporary_;
1128 };
1129
1130
1131 class LThrow: public LUnaryOperation {
1132 public:
1133 explicit LThrow(LOperand* value) : LUnaryOperation(value) { }
1134
1135 DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
1136 };
1137
1138
1139 class LBitNotI: public LUnaryOperation {
1140 public:
1141 explicit LBitNotI(LOperand* use) : LUnaryOperation(use) { }
1142
1143 DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i")
1144 };
1145
1146
1147 class LAddI: public LBinaryOperation {
1148 public:
1149 LAddI(LOperand* left, LOperand* right)
1150 : LBinaryOperation(left, right) { }
1151
1152 DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
1153 DECLARE_HYDROGEN_ACCESSOR(Add)
1154 };
1155
1156
1157 class LArithmeticD: public LBinaryOperation {
1158 public:
1159 LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
1160 : LBinaryOperation(left, right), op_(op) { }
1161
1162 Token::Value op() const { return op_; }
1163
1164 virtual void CompileToNative(LCodeGen* generator);
1165 virtual const char* Mnemonic() const;
1166
1167 private:
1168 Token::Value op_;
1169 };
1170
1171
1172 class LArithmeticT: public LBinaryOperation {
1173 public:
1174 LArithmeticT(Token::Value op, LOperand* left, LOperand* right)
1175 : LBinaryOperation(left, right), op_(op) { }
1176
1177 virtual void CompileToNative(LCodeGen* generator);
1178 virtual const char* Mnemonic() const;
1179
1180 Token::Value op() const { return op_; }
1181
1182 private:
1183 Token::Value op_;
1184 };
1185
1186
1187 class LReturn: public LUnaryOperation {
1188 public:
1189 explicit LReturn(LOperand* use) : LUnaryOperation(use) { }
1190
1191 DECLARE_CONCRETE_INSTRUCTION(Return, "return")
1192 };
1193
1194
1195 class LLoadNamedField: public LUnaryOperation {
1196 public:
1197 explicit LLoadNamedField(LOperand* object) : LUnaryOperation(object) { }
1198
1199 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
1200 DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
1201 };
1202
1203
1204 class LLoadNamedGeneric: public LUnaryOperation {
1205 public:
1206 explicit LLoadNamedGeneric(LOperand* object) : LUnaryOperation(object) { }
1207
1208 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
1209 DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
1210
1211 LOperand* object() const { return input(); }
1212 Handle<Object> name() const { return hydrogen()->name(); }
1213 };
1214
1215
1216 class LLoadElements: public LUnaryOperation {
1217 public:
1218 explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { }
1219
1220 DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements")
1221 };
1222
1223
1224 class LLoadKeyedFastElement: public LBinaryOperation {
1225 public:
1226 LLoadKeyedFastElement(LOperand* elements,
1227 LOperand* key,
1228 LOperand* load_result)
1229 : LBinaryOperation(elements, key),
1230 load_result_(load_result) { }
1231
1232 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
1233 DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
1234
1235 LOperand* elements() const { return left(); }
1236 LOperand* key() const { return right(); }
1237 LOperand* load_result() const { return load_result_; }
1238
1239 private:
1240 LOperand* load_result_;
1241 };
1242
1243
1244 class LLoadKeyedGeneric: public LBinaryOperation {
1245 public:
1246 LLoadKeyedGeneric(LOperand* obj, LOperand* key)
1247 : LBinaryOperation(obj, key) { }
1248
1249 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
1250
1251 LOperand* object() const { return left(); }
1252 LOperand* key() const { return right(); }
1253 };
1254
1255
1256 class LLoadGlobal: public LInstruction {
1257 public:
1258 DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load-global")
1259 DECLARE_HYDROGEN_ACCESSOR(LoadGlobal)
1260 };
1261
1262
1263 class LStoreGlobal: public LUnaryOperation {
1264 public:
1265 explicit LStoreGlobal(LOperand* value) : LUnaryOperation(value) {}
1266
1267 DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global")
1268 DECLARE_HYDROGEN_ACCESSOR(StoreGlobal)
1269 };
1270
1271
1272 class LPushArgument: public LUnaryOperation {
1273 public:
1274 explicit LPushArgument(LOperand* argument) : LUnaryOperation(argument) {}
1275
1276 DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
1277 };
1278
1279
1280 class LGlobalObject: public LInstruction {
1281 public:
1282 DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
1283 };
1284
1285
1286 class LGlobalReceiver: public LInstruction {
1287 public:
1288 DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver")
1289 };
1290
1291
1292 class LCallConstantFunction: public LInstruction {
1293 public:
1294 DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function")
1295 DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction)
1296
1297 virtual void PrintDataTo(StringStream* stream) const;
1298
1299 Handle<JSFunction> function() const { return hydrogen()->function(); }
1300 int arity() const { return hydrogen()->argument_count() - 1; }
1301 };
1302
1303
1304 class LCallKeyed: public LInstruction {
1305 public:
1306 DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
1307 DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
1308
1309 virtual void PrintDataTo(StringStream* stream) const;
1310
1311 int arity() const { return hydrogen()->argument_count() - 1; }
1312 };
1313
1314
1315 class LCallNamed: public LInstruction {
1316 public:
1317 DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
1318 DECLARE_HYDROGEN_ACCESSOR(CallNamed)
1319
1320 virtual void PrintDataTo(StringStream* stream) const;
1321
1322 Handle<String> name() const { return hydrogen()->name(); }
1323 int arity() const { return hydrogen()->argument_count() - 1; }
1324 };
1325
1326
1327 class LCallFunction: public LInstruction {
1328 public:
1329 DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
1330 DECLARE_HYDROGEN_ACCESSOR(CallFunction)
1331
1332 int arity() const { return hydrogen()->argument_count() - 2; }
1333 };
1334
1335
1336 class LCallGlobal: public LInstruction {
1337 public:
1338 DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
1339 DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
1340
1341 virtual void PrintDataTo(StringStream* stream) const;
1342
1343 Handle<String> name() const {return hydrogen()->name(); }
1344 int arity() const { return hydrogen()->argument_count() - 1; }
1345 };
1346
1347
1348 class LCallKnownGlobal: public LInstruction {
1349 public:
1350 DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global")
1351 DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal)
1352
1353 virtual void PrintDataTo(StringStream* stream) const;
1354
1355 Handle<JSFunction> target() const { return hydrogen()->target(); }
1356 int arity() const { return hydrogen()->argument_count() - 1; }
1357 };
1358
1359
1360 class LCallNew: public LUnaryOperation {
1361 public:
1362 explicit LCallNew(LOperand* constructor) : LUnaryOperation(constructor) { }
1363
1364 DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
1365 DECLARE_HYDROGEN_ACCESSOR(CallNew)
1366
1367 virtual void PrintDataTo(StringStream* stream) const;
1368
1369 int arity() const { return hydrogen()->argument_count() - 1; }
1370 };
1371
1372
1373 class LCallRuntime: public LInstruction {
1374 public:
1375 DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
1376 DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
1377
1378 const Runtime::Function* function() const { return hydrogen()->function(); }
1379 int arity() const { return hydrogen()->argument_count(); }
1380 };
1381
1382
1383 class LInteger32ToDouble: public LUnaryOperation {
1384 public:
1385 explicit LInteger32ToDouble(LOperand* use) : LUnaryOperation(use) { }
1386
1387 DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
1388 };
1389
1390
1391 class LNumberTagI: public LUnaryOperation {
1392 public:
1393 explicit LNumberTagI(LOperand* use) : LUnaryOperation(use) { }
1394
1395 DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i")
1396 };
1397
1398
1399 class LNumberTagD: public LUnaryOperation {
1400 public:
1401 explicit LNumberTagD(LOperand* value, LOperand* temp)
1402 : LUnaryOperation(value), temp_(temp) { }
1403
1404 DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
1405
1406 LOperand* temp() const { return temp_; }
1407
1408 private:
1409 LOperand* temp_;
1410 };
1411
1412
1413 // Sometimes truncating conversion from a tagged value to an int32.
1414 class LDoubleToI: public LUnaryOperation {
1415 public:
1416 explicit LDoubleToI(LOperand* value) : LUnaryOperation(value) { }
1417
1418 DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
1419 DECLARE_HYDROGEN_ACCESSOR(Change)
1420
1421 bool truncating() { return hydrogen()->CanTruncateToInt32(); }
1422 };
1423
1424
1425 // Truncating conversion from a tagged value to an int32.
1426 class LTaggedToI: public LUnaryOperation {
1427 public:
1428 LTaggedToI(LOperand* value, LOperand* temp)
1429 : LUnaryOperation(value), temp_(temp) { }
1430
1431 DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
1432 DECLARE_HYDROGEN_ACCESSOR(Change)
1433
1434 bool truncating() { return hydrogen()->CanTruncateToInt32(); }
1435 LOperand* temp() const { return temp_; }
1436
1437 private:
1438 LOperand* temp_;
1439 };
1440
1441
1442 class LSmiTag: public LUnaryOperation {
1443 public:
1444 explicit LSmiTag(LOperand* use) : LUnaryOperation(use) { }
1445
1446 DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
1447 };
1448
1449
1450 class LNumberUntagD: public LUnaryOperation {
1451 public:
1452 explicit LNumberUntagD(LOperand* value) : LUnaryOperation(value) { }
1453
1454 DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
1455 };
1456
1457
1458 class LSmiUntag: public LUnaryOperation {
1459 public:
1460 LSmiUntag(LOperand* use, bool needs_check)
1461 : LUnaryOperation(use), needs_check_(needs_check) { }
1462
1463 DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
1464
1465 bool needs_check() const { return needs_check_; }
1466
1467 private:
1468 bool needs_check_;
1469 };
1470
1471
1472 class LStoreNamed: public LInstruction {
1473 public:
1474 LStoreNamed(LOperand* obj, Handle<Object> name, LOperand* val)
1475 : object_(obj), name_(name), value_(val) { }
1476
1477 DECLARE_INSTRUCTION(StoreNamed)
1478
1479 virtual void PrintDataTo(StringStream* stream) const;
1480
1481 LOperand* object() const { return object_; }
1482 Handle<Object> name() const { return name_; }
1483 LOperand* value() const { return value_; }
1484
1485 private:
1486 LOperand* object_;
1487 Handle<Object> name_;
1488 LOperand* value_;
1489 };
1490
1491
1492 class LStoreNamedField: public LStoreNamed {
1493 public:
1494 LStoreNamedField(LOperand* obj,
1495 Handle<Object> name,
1496 LOperand* val,
1497 bool in_object,
1498 int offset,
1499 LOperand* temp,
1500 bool needs_write_barrier,
1501 Handle<Map> transition)
1502 : LStoreNamed(obj, name, val),
1503 is_in_object_(in_object),
1504 offset_(offset),
1505 temp_(temp),
1506 needs_write_barrier_(needs_write_barrier),
1507 transition_(transition) { }
1508
1509 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
1510
1511 bool is_in_object() { return is_in_object_; }
1512 int offset() { return offset_; }
1513 LOperand* temp() { return temp_; }
1514 bool needs_write_barrier() { return needs_write_barrier_; }
1515 Handle<Map> transition() const { return transition_; }
1516 void set_transition(Handle<Map> map) { transition_ = map; }
1517
1518 private:
1519 bool is_in_object_;
1520 int offset_;
1521 LOperand* temp_;
1522 bool needs_write_barrier_;
1523 Handle<Map> transition_;
1524 };
1525
1526
1527 class LStoreNamedGeneric: public LStoreNamed {
1528 public:
1529 LStoreNamedGeneric(LOperand* obj,
1530 Handle<Object> name,
1531 LOperand* val)
1532 : LStoreNamed(obj, name, val) { }
1533
1534 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
1535 };
1536
1537
1538 class LStoreKeyed: public LInstruction {
1539 public:
1540 LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val)
1541 : object_(obj), key_(key), value_(val) { }
1542
1543 DECLARE_INSTRUCTION(StoreKeyed)
1544
1545 virtual void PrintDataTo(StringStream* stream) const;
1546
1547 LOperand* object() const { return object_; }
1548 LOperand* key() const { return key_; }
1549 LOperand* value() const { return value_; }
1550
1551 private:
1552 LOperand* object_;
1553 LOperand* key_;
1554 LOperand* value_;
1555 };
1556
1557
1558 class LStoreKeyedFastElement: public LStoreKeyed {
1559 public:
1560 LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val)
1561 : LStoreKeyed(obj, key, val) {}
1562
1563 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
1564 "store-keyed-fast-element")
1565 DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
1566 };
1567
1568
1569 class LStoreKeyedGeneric: public LStoreKeyed {
1570 public:
1571 LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val)
1572 : LStoreKeyed(obj, key, val) { }
1573
1574 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
1575 };
1576
1577
1578 class LCheckFunction: public LUnaryOperation {
1579 public:
1580 explicit LCheckFunction(LOperand* use) : LUnaryOperation(use) { }
1581
1582 DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
1583 DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
1584 };
1585
1586
1587 class LCheckInstanceType: public LUnaryOperation {
1588 public:
1589 LCheckInstanceType(LOperand* use, LOperand* temp)
1590 : LUnaryOperation(use), temp_(temp) { }
1591
1592 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
1593 DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
1594
1595 LOperand* temp() const { return temp_; }
1596
1597 private:
1598 LOperand* temp_;
1599 };
1600
1601
1602 class LCheckMap: public LUnaryOperation {
1603 public:
1604 explicit LCheckMap(LOperand* use) : LUnaryOperation(use) { }
1605
1606 DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
1607 DECLARE_HYDROGEN_ACCESSOR(CheckMap)
1608 };
1609
1610
1611 class LCheckPrototypeMaps: public LInstruction {
1612 public:
1613 LCheckPrototypeMaps(LOperand* temp,
1614 Handle<JSObject> holder,
1615 Handle<Map> receiver_map)
1616 : temp_(temp),
1617 holder_(holder),
1618 receiver_map_(receiver_map) { }
1619
1620 DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps")
1621
1622 LOperand* temp() const { return temp_; }
1623 Handle<JSObject> holder() const { return holder_; }
1624 Handle<Map> receiver_map() const { return receiver_map_; }
1625
1626 private:
1627 LOperand* temp_;
1628 Handle<JSObject> holder_;
1629 Handle<Map> receiver_map_;
1630 };
1631
1632
1633 class LCheckSmi: public LUnaryOperation {
1634 public:
1635 LCheckSmi(LOperand* use, Condition condition)
1636 : LUnaryOperation(use), condition_(condition) { }
1637
1638 Condition condition() const { return condition_; }
1639
1640 virtual void CompileToNative(LCodeGen* generator);
1641 virtual const char* Mnemonic() const {
1642 return (condition_ == zero) ? "check-non-smi" : "check-smi";
1643 }
1644
1645 private:
1646 Condition condition_;
1647 };
1648
1649
1650 class LMaterializedLiteral: public LInstruction {
1651 public:
1652 DECLARE_INSTRUCTION(MaterializedLiteral)
1653 };
1654
1655
1656 class LArrayLiteral: public LMaterializedLiteral {
1657 public:
1658 DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
1659 DECLARE_HYDROGEN_ACCESSOR(ArrayLiteral)
1660 };
1661
1662
1663 class LObjectLiteral: public LMaterializedLiteral {
1664 public:
1665 DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal")
1666 DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral)
1667 };
1668
1669
1670 class LRegExpLiteral: public LMaterializedLiteral {
1671 public:
1672 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal")
1673 DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral)
1674 };
1675
1676
1677 class LFunctionLiteral: public LInstruction {
1678 public:
1679 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
1680 DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
1681
1682 Handle<SharedFunctionInfo> shared_info() { return hydrogen()->shared_info(); }
1683 };
1684
1685
1686 class LTypeof: public LUnaryOperation {
1687 public:
1688 explicit LTypeof(LOperand* input) : LUnaryOperation(input) { }
1689
1690 DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
1691 };
1692
1693
1694 class LTypeofIs: public LUnaryOperation {
1695 public:
1696 explicit LTypeofIs(LOperand* input) : LUnaryOperation(input) { }
1697 virtual void PrintDataTo(StringStream* stream) const;
1698
1699 DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is")
1700 DECLARE_HYDROGEN_ACCESSOR(TypeofIs)
1701
1702 Handle<String> type_literal() { return hydrogen()->type_literal(); }
1703 };
1704
1705
1706 class LTypeofIsAndBranch: public LTypeofIs {
1707 public:
1708 LTypeofIsAndBranch(LOperand* value,
1709 int true_block_id,
1710 int false_block_id)
1711 : LTypeofIs(value),
1712 true_block_id_(true_block_id),
1713 false_block_id_(false_block_id) { }
1714
1715 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
1716
1717 virtual void PrintDataTo(StringStream* stream) const;
1718 virtual bool IsControl() const { return true; }
1719
1720 int true_block_id() const { return true_block_id_; }
1721 int false_block_id() const { return false_block_id_; }
1722
1723 private:
1724 int true_block_id_;
1725 int false_block_id_;
1726 };
1727
1728
1729 class LDeleteProperty: public LBinaryOperation {
1730 public:
1731 LDeleteProperty(LOperand* obj, LOperand* key) : LBinaryOperation(obj, key) {}
1732
1733 DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property")
1734
1735 LOperand* object() const { return left(); }
1736 LOperand* key() const { return right(); }
1737 };
1738
1739
1740 class LOsrEntry: public LInstruction {
1741 public:
1742 LOsrEntry();
1743
1744 DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
1745
1746 LOperand** SpilledRegisterArray() { return register_spills_; }
1747 LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; }
1748
1749 void MarkSpilledRegister(int allocation_index, LOperand* spill_operand);
1750 void MarkSpilledDoubleRegister(int allocation_index,
1751 LOperand* spill_operand);
1752
1753 private:
1754 // Arrays of spill slot operands for registers with an assigned spill
1755 // slot, i.e., that must also be restored to the spill slot on OSR entry.
1756 // NULL if the register has no assigned spill slot. Indexed by allocation
1757 // index.
1758 LOperand* register_spills_[Register::kNumAllocatableRegisters];
1759 LOperand* double_register_spills_[DoubleRegister::kNumAllocatableRegisters];
1760 };
1761
1762
1763 class LStackCheck: public LInstruction {
1764 public:
1765 DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
1766 };
1767
1768
1769 class LPointerMap: public ZoneObject {
1770 public:
1771 explicit LPointerMap(int position)
1772 : pointer_operands_(8), position_(position), lithium_position_(-1) { }
1773
1774 const ZoneList<LOperand*>* operands() const { return &pointer_operands_; }
1775 int position() const { return position_; }
1776 int lithium_position() const { return lithium_position_; }
1777
1778 void set_lithium_position(int pos) {
1779 ASSERT(lithium_position_ == -1);
1780 lithium_position_ = pos;
1781 }
1782
1783 void RecordPointer(LOperand* op);
1784 void PrintTo(StringStream* stream) const;
1785
1786 private:
1787 ZoneList<LOperand*> pointer_operands_;
1788 int position_;
1789 int lithium_position_;
1790 };
1791
1792
1793 class LEnvironment: public ZoneObject {
1794 public:
1795 LEnvironment(Handle<JSFunction> closure,
1796 int ast_id,
1797 int parameter_count,
1798 int argument_count,
1799 int value_count,
1800 LEnvironment* outer)
1801 : closure_(closure),
1802 arguments_stack_height_(argument_count),
1803 deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
1804 translation_index_(-1),
1805 ast_id_(ast_id),
1806 parameter_count_(parameter_count),
1807 values_(value_count),
1808 representations_(value_count),
1809 spilled_registers_(NULL),
1810 spilled_double_registers_(NULL),
1811 outer_(outer) {
1812 }
1813
1814 Handle<JSFunction> closure() const { return closure_; }
1815 int arguments_stack_height() const { return arguments_stack_height_; }
1816 int deoptimization_index() const { return deoptimization_index_; }
1817 int translation_index() const { return translation_index_; }
1818 int ast_id() const { return ast_id_; }
1819 int parameter_count() const { return parameter_count_; }
1820 const ZoneList<LOperand*>* values() const { return &values_; }
1821 LEnvironment* outer() const { return outer_; }
1822
1823 void AddValue(LOperand* operand, Representation representation) {
1824 values_.Add(operand);
1825 representations_.Add(representation);
1826 }
1827
1828 bool HasTaggedValueAt(int index) const {
1829 return representations_[index].IsTagged();
1830 }
1831
1832 void Register(int deoptimization_index, int translation_index) {
1833 ASSERT(!HasBeenRegistered());
1834 deoptimization_index_ = deoptimization_index;
1835 translation_index_ = translation_index;
1836 }
1837 bool HasBeenRegistered() const {
1838 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
1839 }
1840
1841 void SetSpilledRegisters(LOperand** registers,
1842 LOperand** double_registers) {
1843 spilled_registers_ = registers;
1844 spilled_double_registers_ = double_registers;
1845 }
1846
1847 // Emit frame translation commands for this environment.
1848 void WriteTranslation(LCodeGen* cgen, Translation* translation) const;
1849
1850 void PrintTo(StringStream* stream) const;
1851
1852 private:
1853 Handle<JSFunction> closure_;
1854 int arguments_stack_height_;
1855 int deoptimization_index_;
1856 int translation_index_;
1857 int ast_id_;
1858 int parameter_count_;
1859 ZoneList<LOperand*> values_;
1860 ZoneList<Representation> representations_;
1861
1862 // Allocation index indexed arrays of spill slot operands for registers
1863 // that are also in spill slots at an OSR entry. NULL for environments
1864 // that do not correspond to an OSR entry.
1865 LOperand** spilled_registers_;
1866 LOperand** spilled_double_registers_;
1867
1868 LEnvironment* outer_;
1869 };
1870
1871 class LChunkBuilder;
1872 class LChunk: public ZoneObject {
1873 public:
1874 explicit LChunk(HGraph* graph);
1875
1876 int AddInstruction(LInstruction* instruction, HBasicBlock* block);
1877 LConstantOperand* DefineConstantOperand(HConstant* constant);
1878 Handle<Object> LookupLiteral(LConstantOperand* operand) const;
1879 Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
1880
1881 int GetNextSpillIndex(bool is_double);
1882 LOperand* GetNextSpillSlot(bool is_double);
1883
1884 int ParameterAt(int index);
1885 int GetParameterStackSlot(int index) const;
1886 int spill_slot_count() const { return spill_slot_count_; }
1887 HGraph* graph() const { return graph_; }
1888 const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
1889 void AddGapMove(int index, LOperand* from, LOperand* to);
1890 LGap* GetGapAt(int index) const;
1891 bool IsGapAt(int index) const;
1892 int NearestGapPos(int index) const;
1893 int NearestNextGapPos(int index) const;
1894 void MarkEmptyBlocks();
1895 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
1896 LLabel* GetLabel(int block_id) const {
1897 HBasicBlock* block = graph_->blocks()->at(block_id);
1898 int first_instruction = block->first_instruction_index();
1899 return LLabel::cast(instructions_[first_instruction]);
1900 }
1901 int LookupDestination(int block_id) const {
1902 LLabel* cur = GetLabel(block_id);
1903 while (cur->replacement() != NULL) {
1904 cur = cur->replacement();
1905 }
1906 return cur->block_id();
1907 }
1908 Label* GetAssemblyLabel(int block_id) const {
1909 LLabel* label = GetLabel(block_id);
1910 ASSERT(!label->HasReplacement());
1911 return label->label();
1912 }
1913
1914 const ZoneList<Handle<JSFunction> >* inlined_closures() const {
1915 return &inlined_closures_;
1916 }
1917
1918 void AddInlinedClosure(Handle<JSFunction> closure) {
1919 inlined_closures_.Add(closure);
1920 }
1921
1922 void Verify() const;
1923
1924 private:
1925 int spill_slot_count_;
1926 HGraph* const graph_;
1927 ZoneList<LInstruction*> instructions_;
1928 ZoneList<LPointerMap*> pointer_maps_;
1929 ZoneList<Handle<JSFunction> > inlined_closures_;
1930 };
1931
1932
1933 class LChunkBuilder BASE_EMBEDDED {
1934 public:
1935 LChunkBuilder(HGraph* graph, LAllocator* allocator)
1936 : chunk_(NULL),
1937 graph_(graph),
1938 status_(UNUSED),
1939 current_instruction_(NULL),
1940 current_block_(NULL),
1941 next_block_(NULL),
1942 argument_count_(0),
1943 allocator_(allocator),
1944 position_(RelocInfo::kNoPosition),
1945 instructions_pending_deoptimization_environment_(NULL),
1946 pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
1947
1948 // Build the sequence for the graph.
1949 LChunk* Build();
1950
1951 // Declare methods that deal with the individual node types.
1952 #define DECLARE_DO(type) LInstruction* Do##type(H##type* node);
1953 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
1954 #undef DECLARE_DO
1955
1956 private:
1957 enum Status {
1958 UNUSED,
1959 BUILDING,
1960 DONE,
1961 ABORTED
1962 };
1963
1964 LChunk* chunk() const { return chunk_; }
1965 HGraph* graph() const { return graph_; }
1966
1967 bool is_unused() const { return status_ == UNUSED; }
1968 bool is_building() const { return status_ == BUILDING; }
1969 bool is_done() const { return status_ == DONE; }
1970 bool is_aborted() const { return status_ == ABORTED; }
1971
1972 void Abort(const char* format, ...);
1973
1974 // Methods for getting operands for Use / Define / Temp.
1975 LRegister* ToOperand(Register reg);
1976 LUnallocated* ToUnallocated(Register reg);
1977 LUnallocated* ToUnallocated(XMMRegister reg);
1978
1979 // Methods for setting up define-use relationships.
1980 LOperand* Use(HValue* value, LUnallocated* operand);
1981 LOperand* UseFixed(HValue* value, Register fixed_register);
1982 LOperand* UseFixedDouble(HValue* value, XMMRegister fixed_register);
1983
1984 // A value that is guaranteed to be allocated to a register.
1985 // Operand created by UseRegister is guaranteed to be live until the end of
1986 // instruction. This means that register allocator will not reuse it's
1987 // register for any other operand inside instruction.
1988 // Operand created by UseRegisterAtStart is guaranteed to be live only at
1989 // instruction start. Register allocator is free to assign the same register
1990 // to some other operand used inside instruction (i.e. temporary or
1991 // output).
1992 LOperand* UseRegister(HValue* value);
1993 LOperand* UseRegisterAtStart(HValue* value);
1994
1995 // A value in a register that may be trashed.
1996 LOperand* UseTempRegister(HValue* value);
1997 LOperand* Use(HValue* value);
1998 LOperand* UseAtStart(HValue* value);
1999 LOperand* UseOrConstant(HValue* value);
2000 LOperand* UseOrConstantAtStart(HValue* value);
2001 LOperand* UseRegisterOrConstant(HValue* value);
2002 LOperand* UseRegisterOrConstantAtStart(HValue* value);
2003
2004 // Methods for setting up define-use relationships.
2005 // Return the same instruction that they are passed.
2006 LInstruction* Define(LInstruction* instr, LUnallocated* result);
2007 LInstruction* Define(LInstruction* instr);
2008 LInstruction* DefineAsRegister(LInstruction* instr);
2009 LInstruction* DefineAsSpilled(LInstruction* instr, int index);
2010 LInstruction* DefineSameAsAny(LInstruction* instr);
2011 LInstruction* DefineSameAsFirst(LInstruction* instr);
2012 LInstruction* DefineFixed(LInstruction* instr, Register reg);
2013 LInstruction* DefineFixedDouble(LInstruction* instr, XMMRegister reg);
2014 LInstruction* AssignEnvironment(LInstruction* instr);
2015 LInstruction* AssignPointerMap(LInstruction* instr);
2016
2017 enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
2018
2019 // By default we assume that instruction sequences generated for calls
2020 // cannot deoptimize eagerly and we do not attach environment to this
2021 // instruction.
2022 LInstruction* MarkAsCall(
2023 LInstruction* instr,
2024 HInstruction* hinstr,
2025 CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
2026
2027 LInstruction* SetInstructionPendingDeoptimizationEnvironment(
2028 LInstruction* instr, int ast_id);
2029 void ClearInstructionPendingDeoptimizationEnvironment();
2030
2031 LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
2032
2033 // Temporary operand that may be a memory location.
2034 LOperand* Temp();
2035 // Temporary operand that must be in a register.
2036 LUnallocated* TempRegister();
2037 LOperand* FixedTemp(Register reg);
2038 LOperand* FixedTemp(XMMRegister reg);
2039
2040 void VisitInstruction(HInstruction* current);
2041
2042 void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
2043 LInstruction* DoBit(Token::Value op, HBitwiseBinaryOperation* instr);
2044 LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
2045 LInstruction* DoArithmeticD(Token::Value op,
2046 HArithmeticBinaryOperation* instr);
2047 LInstruction* DoArithmeticT(Token::Value op,
2048 HArithmeticBinaryOperation* instr);
2049
2050 LChunk* chunk_;
2051 HGraph* const graph_;
2052 Status status_;
2053 HInstruction* current_instruction_;
2054 HBasicBlock* current_block_;
2055 HBasicBlock* next_block_;
2056 int argument_count_;
2057 LAllocator* allocator_;
2058 int position_;
2059 LInstruction* instructions_pending_deoptimization_environment_;
2060 int pending_deoptimization_ast_id_;
2061
2062 DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
2063 };
2064
2065 #undef DECLARE_HYDROGEN_ACCESSOR
2066 #undef DECLARE_INSTRUCTION
2067 #undef DECLARE_CONCRETE_INSTRUCTION
2068
2069 } } // namespace v8::internal
2070
2071 #endif // V8_IA32_LITHIUM_IA32_H_
OLDNEW
« no previous file with comments | « src/ia32/lithium-codegen-ia32.cc ('k') | src/ia32/lithium-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698