blob: a43856f6fa4b75f078171ee13062a95a0b2dc50a [file] [log] [blame]
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001// Copyright 2010 the V8 project authors. All rights reserved.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002// 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
ager@chromium.org9085a012009-05-11 19:22:57 +000028#ifndef V8_X64_CODEGEN_X64_H_
29#define V8_X64_CODEGEN_X64_H_
30
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000031#include "ic-inl.h"
32
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
ager@chromium.org9085a012009-05-11 19:22:57 +000035
36// Forward declarations
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000037class CompilationInfo;
ager@chromium.org9085a012009-05-11 19:22:57 +000038class DeferredCode;
39class RegisterAllocator;
40class RegisterFile;
41
42enum InitState { CONST_INIT, NOT_CONST_INIT };
43enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
44
45
46// -------------------------------------------------------------------------
47// Reference support
48
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000049// A reference is a C++ stack-allocated object that puts a
50// reference on the virtual frame. The reference may be consumed
51// by GetValue, TakeValue, SetValue, and Codegen::UnloadReference.
52// When the lifetime (scope) of a valid reference ends, it must have
53// been consumed, and be in state UNLOADED.
ager@chromium.org9085a012009-05-11 19:22:57 +000054class Reference BASE_EMBEDDED {
55 public:
56 // The values of the types is important, see size().
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000057 enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
58
59 Reference(CodeGenerator* cgen,
60 Expression* expression,
61 bool persist_after_get = false);
ager@chromium.org9085a012009-05-11 19:22:57 +000062 ~Reference();
63
64 Expression* expression() const { return expression_; }
65 Type type() const { return type_; }
66 void set_type(Type value) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000067 ASSERT_EQ(ILLEGAL, type_);
ager@chromium.org9085a012009-05-11 19:22:57 +000068 type_ = value;
69 }
70
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000071 void set_unloaded() {
72 ASSERT_NE(ILLEGAL, type_);
73 ASSERT_NE(UNLOADED, type_);
74 type_ = UNLOADED;
75 }
ager@chromium.org9085a012009-05-11 19:22:57 +000076 // The size the reference takes up on the stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000077 int size() const {
78 return (type_ < SLOT) ? 0 : type_;
79 }
ager@chromium.org9085a012009-05-11 19:22:57 +000080
81 bool is_illegal() const { return type_ == ILLEGAL; }
82 bool is_slot() const { return type_ == SLOT; }
83 bool is_property() const { return type_ == NAMED || type_ == KEYED; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000084 bool is_unloaded() const { return type_ == UNLOADED; }
ager@chromium.org9085a012009-05-11 19:22:57 +000085
86 // Return the name. Only valid for named property references.
87 Handle<String> GetName();
88
89 // Generate code to push the value of the reference on top of the
90 // expression stack. The reference is expected to be already on top of
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000091 // the expression stack, and it is consumed by the call unless the
92 // reference is for a compound assignment.
93 // If the reference is not consumed, it is left in place under its value.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000094 void GetValue();
ager@chromium.org9085a012009-05-11 19:22:57 +000095
96 // Like GetValue except that the slot is expected to be written to before
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000097 // being read from again. The value of the reference may be invalidated,
ager@chromium.org9085a012009-05-11 19:22:57 +000098 // causing subsequent attempts to read it to fail.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000099 void TakeValue();
ager@chromium.org9085a012009-05-11 19:22:57 +0000100
101 // Generate code to store the value on top of the expression stack in the
102 // reference. The reference is expected to be immediately below the value
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000103 // on the expression stack. The value is stored in the location specified
104 // by the reference, and is left on top of the stack, after the reference
105 // is popped from beneath it (unloaded).
ager@chromium.org9085a012009-05-11 19:22:57 +0000106 void SetValue(InitState init_state);
107
108 private:
109 CodeGenerator* cgen_;
110 Expression* expression_;
111 Type type_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000112 bool persist_after_get_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000113};
114
115
116// -------------------------------------------------------------------------
117// Control destinations.
118
119// A control destination encapsulates a pair of jump targets and a
120// flag indicating which one is the preferred fall-through. The
121// preferred fall-through must be unbound, the other may be already
122// bound (ie, a backward target).
123//
124// The true and false targets may be jumped to unconditionally or
125// control may split conditionally. Unconditional jumping and
126// splitting should be emitted in tail position (as the last thing
127// when compiling an expression) because they can cause either label
128// to be bound or the non-fall through to be jumped to leaving an
129// invalid virtual frame.
130//
131// The labels in the control destination can be extracted and
132// manipulated normally without affecting the state of the
133// destination.
134
135class ControlDestination BASE_EMBEDDED {
136 public:
137 ControlDestination(JumpTarget* true_target,
138 JumpTarget* false_target,
139 bool true_is_fall_through)
140 : true_target_(true_target),
141 false_target_(false_target),
142 true_is_fall_through_(true_is_fall_through),
143 is_used_(false) {
144 ASSERT(true_is_fall_through ? !true_target->is_bound()
145 : !false_target->is_bound());
146 }
147
148 // Accessors for the jump targets. Directly jumping or branching to
149 // or binding the targets will not update the destination's state.
150 JumpTarget* true_target() const { return true_target_; }
151 JumpTarget* false_target() const { return false_target_; }
152
153 // True if the the destination has been jumped to unconditionally or
154 // control has been split to both targets. This predicate does not
155 // test whether the targets have been extracted and manipulated as
156 // raw jump targets.
157 bool is_used() const { return is_used_; }
158
159 // True if the destination is used and the true target (respectively
160 // false target) was the fall through. If the target is backward,
161 // "fall through" included jumping unconditionally to it.
162 bool true_was_fall_through() const {
163 return is_used_ && true_is_fall_through_;
164 }
165
166 bool false_was_fall_through() const {
167 return is_used_ && !true_is_fall_through_;
168 }
169
170 // Emit a branch to one of the true or false targets, and bind the
171 // other target. Because this binds the fall-through target, it
172 // should be emitted in tail position (as the last thing when
173 // compiling an expression).
174 void Split(Condition cc) {
175 ASSERT(!is_used_);
176 if (true_is_fall_through_) {
177 false_target_->Branch(NegateCondition(cc));
178 true_target_->Bind();
179 } else {
180 true_target_->Branch(cc);
181 false_target_->Bind();
182 }
183 is_used_ = true;
184 }
185
186 // Emit an unconditional jump in tail position, to the true target
187 // (if the argument is true) or the false target. The "jump" will
188 // actually bind the jump target if it is forward, jump to it if it
189 // is backward.
190 void Goto(bool where) {
191 ASSERT(!is_used_);
192 JumpTarget* target = where ? true_target_ : false_target_;
193 if (target->is_bound()) {
194 target->Jump();
195 } else {
196 target->Bind();
197 }
198 is_used_ = true;
199 true_is_fall_through_ = where;
200 }
201
202 // Mark this jump target as used as if Goto had been called, but
203 // without generating a jump or binding a label (the control effect
204 // should have already happened). This is used when the left
205 // subexpression of the short-circuit boolean operators are
206 // compiled.
207 void Use(bool where) {
208 ASSERT(!is_used_);
209 ASSERT((where ? true_target_ : false_target_)->is_bound());
210 is_used_ = true;
211 true_is_fall_through_ = where;
212 }
213
214 // Swap the true and false targets but keep the same actual label as
215 // the fall through. This is used when compiling negated
216 // expressions, where we want to swap the targets but preserve the
217 // state.
218 void Invert() {
219 JumpTarget* temp_target = true_target_;
220 true_target_ = false_target_;
221 false_target_ = temp_target;
222
223 true_is_fall_through_ = !true_is_fall_through_;
224 }
225
226 private:
227 // True and false jump targets.
228 JumpTarget* true_target_;
229 JumpTarget* false_target_;
230
231 // Before using the destination: true if the true target is the
232 // preferred fall through, false if the false target is. After
233 // using the destination: true if the true target was actually used
234 // as the fall through, false if the false target was.
235 bool true_is_fall_through_;
236
237 // True if the Split or Goto functions have been called.
238 bool is_used_;
239};
240
241
242// -------------------------------------------------------------------------
243// Code generation state
244
245// The state is passed down the AST by the code generator (and back up, in
246// the form of the state of the jump target pair). It is threaded through
247// the call stack. Constructing a state implicitly pushes it on the owning
248// code generator's stack of states, and destroying one implicitly pops it.
249//
250// The code generator state is only used for expressions, so statements have
251// the initial state.
252
253class CodeGenState BASE_EMBEDDED {
254 public:
255 // Create an initial code generator state. Destroying the initial state
256 // leaves the code generator with a NULL state.
257 explicit CodeGenState(CodeGenerator* owner);
258
259 // Create a code generator state based on a code generator's current
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000260 // state. The new state has its own control destination.
261 CodeGenState(CodeGenerator* owner, ControlDestination* destination);
ager@chromium.org9085a012009-05-11 19:22:57 +0000262
263 // Destroy a code generator state and restore the owning code generator's
264 // previous state.
265 ~CodeGenState();
266
267 // Accessors for the state.
ager@chromium.org9085a012009-05-11 19:22:57 +0000268 ControlDestination* destination() const { return destination_; }
269
270 private:
271 // The owning code generator.
272 CodeGenerator* owner_;
273
ager@chromium.org9085a012009-05-11 19:22:57 +0000274 // A control destination in case the expression has a control-flow
275 // effect.
276 ControlDestination* destination_;
277
278 // The previous state of the owning code generator, restored when
279 // this state is destroyed.
280 CodeGenState* previous_;
281};
282
283
ager@chromium.org3e875802009-06-29 08:26:34 +0000284// -------------------------------------------------------------------------
285// Arguments allocation mode
286
287enum ArgumentsAllocationMode {
288 NO_ARGUMENTS_ALLOCATION,
289 EAGER_ARGUMENTS_ALLOCATION,
290 LAZY_ARGUMENTS_ALLOCATION
291};
ager@chromium.org9085a012009-05-11 19:22:57 +0000292
293
294// -------------------------------------------------------------------------
295// CodeGenerator
296
297class CodeGenerator: public AstVisitor {
298 public:
299 // Takes a function literal, generates code for it. This function should only
300 // be called by compiler.cc.
ager@chromium.org5c838252010-02-19 08:53:10 +0000301 static Handle<Code> MakeCode(CompilationInfo* info);
ager@chromium.org9085a012009-05-11 19:22:57 +0000302
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000303 // Printing of AST, etc. as requested by flags.
ager@chromium.org5c838252010-02-19 08:53:10 +0000304 static void MakeCodePrologue(CompilationInfo* info);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000305
306 // Allocate and install the code.
ager@chromium.org5c838252010-02-19 08:53:10 +0000307 static Handle<Code> MakeCodeEpilogue(MacroAssembler* masm,
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000308 Code::Flags flags,
ager@chromium.org5c838252010-02-19 08:53:10 +0000309 CompilationInfo* info);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000310
ager@chromium.org9085a012009-05-11 19:22:57 +0000311#ifdef ENABLE_LOGGING_AND_PROFILING
312 static bool ShouldGenerateLog(Expression* type);
313#endif
314
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000315 static void RecordPositions(MacroAssembler* masm, int pos);
316
ager@chromium.org9085a012009-05-11 19:22:57 +0000317 // Accessors
318 MacroAssembler* masm() { return masm_; }
ager@chromium.org9085a012009-05-11 19:22:57 +0000319 VirtualFrame* frame() const { return frame_; }
ager@chromium.org5c838252010-02-19 08:53:10 +0000320 inline Handle<Script> script();
ager@chromium.org9085a012009-05-11 19:22:57 +0000321
322 bool has_valid_frame() const { return frame_ != NULL; }
323
324 // Set the virtual frame to be new_frame, with non-frame register
325 // reference counts given by non_frame_registers. The non-frame
326 // register reference counts of the old frame are returned in
327 // non_frame_registers.
328 void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers);
329
330 void DeleteFrame();
331
332 RegisterAllocator* allocator() const { return allocator_; }
333
334 CodeGenState* state() { return state_; }
335 void set_state(CodeGenState* state) { state_ = state; }
336
337 void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
338
339 bool in_spilled_code() const { return in_spilled_code_; }
340 void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
341
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342 // If the name is an inline runtime function call return the number of
343 // expected arguments. Otherwise return -1.
344 static int InlineRuntimeCallArgumentsCount(Handle<String> name);
345
ager@chromium.org9085a012009-05-11 19:22:57 +0000346 private:
347 // Construction/Destruction
ager@chromium.org5c838252010-02-19 08:53:10 +0000348 explicit CodeGenerator(MacroAssembler* masm);
ager@chromium.org9085a012009-05-11 19:22:57 +0000349
350 // Accessors
ager@chromium.org5c838252010-02-19 08:53:10 +0000351 inline bool is_eval();
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +0000352 inline Scope* scope();
ager@chromium.org9085a012009-05-11 19:22:57 +0000353
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000354 // Generating deferred code.
ager@chromium.org9085a012009-05-11 19:22:57 +0000355 void ProcessDeferred();
356
ager@chromium.org9085a012009-05-11 19:22:57 +0000357 // State
ager@chromium.org9085a012009-05-11 19:22:57 +0000358 ControlDestination* destination() const { return state_->destination(); }
359
360 // Track loop nesting level.
361 int loop_nesting() const { return loop_nesting_; }
362 void IncrementLoopNesting() { loop_nesting_++; }
363 void DecrementLoopNesting() { loop_nesting_--; }
364
365
366 // Node visitors.
367 void VisitStatements(ZoneList<Statement*>* statements);
368
369#define DEF_VISIT(type) \
370 void Visit##type(type* node);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000371 AST_NODE_LIST(DEF_VISIT)
ager@chromium.org9085a012009-05-11 19:22:57 +0000372#undef DEF_VISIT
373
374 // Visit a statement and then spill the virtual frame if control flow can
375 // reach the end of the statement (ie, it does not exit via break,
376 // continue, return, or throw). This function is used temporarily while
377 // the code generator is being transformed.
378 void VisitAndSpill(Statement* statement);
379
380 // Visit a list of statements and then spill the virtual frame if control
381 // flow can reach the end of the list.
382 void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
383
384 // Main code generation function
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +0000385 void Generate(CompilationInfo* info);
ager@chromium.org9085a012009-05-11 19:22:57 +0000386
387 // Generate the return sequence code. Should be called no more than
388 // once per compiled function, immediately after binding the return
389 // target (which can not be done more than once).
390 void GenerateReturnSequence(Result* return_value);
391
ager@chromium.org3e875802009-06-29 08:26:34 +0000392 // Returns the arguments allocation mode.
ager@chromium.org5c838252010-02-19 08:53:10 +0000393 ArgumentsAllocationMode ArgumentsMode();
ager@chromium.org3e875802009-06-29 08:26:34 +0000394
395 // Store the arguments object and allocate it if necessary.
396 Result StoreArgumentsObject(bool initial);
397
ager@chromium.org9085a012009-05-11 19:22:57 +0000398 // The following are used by class Reference.
399 void LoadReference(Reference* ref);
400 void UnloadReference(Reference* ref);
401
ager@chromium.org3811b432009-10-28 14:53:37 +0000402 static Operand ContextOperand(Register context, int index) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000403 return Operand(context, Context::SlotOffset(index));
404 }
405
406 Operand SlotOperand(Slot* slot, Register tmp);
407
408 Operand ContextSlotOperandCheckExtensions(Slot* slot,
409 Result tmp,
410 JumpTarget* slow);
411
412 // Expressions
ager@chromium.org3811b432009-10-28 14:53:37 +0000413 static Operand GlobalObject() {
ager@chromium.org9085a012009-05-11 19:22:57 +0000414 return ContextOperand(rsi, Context::GLOBAL_INDEX);
415 }
416
417 void LoadCondition(Expression* x,
ager@chromium.org9085a012009-05-11 19:22:57 +0000418 ControlDestination* destination,
419 bool force_control);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000420 void Load(Expression* expr);
ager@chromium.org9085a012009-05-11 19:22:57 +0000421 void LoadGlobal();
422 void LoadGlobalReceiver();
423
424 // Generate code to push the value of an expression on top of the frame
425 // and then spill the frame fully to memory. This function is used
426 // temporarily while the code generator is being transformed.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000427 void LoadAndSpill(Expression* expression);
ager@chromium.org9085a012009-05-11 19:22:57 +0000428
429 // Read a value from a slot and leave it on top of the expression stack.
430 void LoadFromSlot(Slot* slot, TypeofState typeof_state);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000431 void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
ager@chromium.org9085a012009-05-11 19:22:57 +0000432 Result LoadFromGlobalSlotCheckExtensions(Slot* slot,
433 TypeofState typeof_state,
434 JumpTarget* slow);
435
436 // Store the value on top of the expression stack into a slot, leaving the
437 // value in place.
438 void StoreToSlot(Slot* slot, InitState init_state);
439
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000440 // Load a property of an object, returning it in a Result.
441 // The object and the property name are passed on the stack, and
442 // not changed.
443 Result EmitKeyedLoad(bool is_global);
444
ager@chromium.org9085a012009-05-11 19:22:57 +0000445 // Special code for typeof expressions: Unfortunately, we must
446 // be careful when loading the expression in 'typeof'
447 // expressions. We are not allowed to throw reference errors for
448 // non-existing properties of the global object, so we must make it
449 // look like an explicit property access, instead of an access
450 // through the context chain.
451 void LoadTypeofExpression(Expression* x);
452
453 // Translate the value on top of the frame into control flow to the
454 // control destination.
455 void ToBoolean(ControlDestination* destination);
456
457 void GenericBinaryOperation(
458 Token::Value op,
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000459 StaticType* type,
ager@chromium.org9085a012009-05-11 19:22:57 +0000460 OverwriteMode overwrite_mode);
461
462 // If possible, combine two constant smi values using op to produce
463 // a smi result, and push it on the virtual frame, all at compile time.
464 // Returns true if it succeeds. Otherwise it has no effect.
465 bool FoldConstantSmis(Token::Value op, int left, int right);
466
467 // Emit code to perform a binary operation on a constant
468 // smi and a likely smi. Consumes the Result *operand.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000469 Result ConstantSmiBinaryOperation(Token::Value op,
470 Result* operand,
471 Handle<Object> constant_operand,
472 StaticType* type,
473 bool reversed,
474 OverwriteMode overwrite_mode);
ager@chromium.org9085a012009-05-11 19:22:57 +0000475
476 // Emit code to perform a binary operation on two likely smis.
477 // The code to handle smi arguments is produced inline.
478 // Consumes the Results *left and *right.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000479 Result LikelySmiBinaryOperation(Token::Value op,
480 Result* left,
481 Result* right,
482 OverwriteMode overwrite_mode);
ager@chromium.org9085a012009-05-11 19:22:57 +0000483
ager@chromium.org5c838252010-02-19 08:53:10 +0000484 void Comparison(AstNode* node,
485 Condition cc,
ager@chromium.org9085a012009-05-11 19:22:57 +0000486 bool strict,
487 ControlDestination* destination);
488
489 // To prevent long attacker-controlled byte sequences, integer constants
490 // from the JavaScript source are loaded in two parts if they are larger
491 // than 16 bits.
492 static const int kMaxSmiInlinedBits = 16;
493 bool IsUnsafeSmi(Handle<Object> value);
494 // Load an integer constant x into a register target using
495 // at most 16 bits of user-controlled data per assembly operation.
496 void LoadUnsafeSmi(Register target, Handle<Object> value);
497
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000498 void CallWithArguments(ZoneList<Expression*>* arguments,
499 CallFunctionFlags flags,
500 int position);
ager@chromium.org9085a012009-05-11 19:22:57 +0000501
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000502 // An optimized implementation of expressions of the form
503 // x.apply(y, arguments). We call x the applicand and y the receiver.
504 // The optimization avoids allocating an arguments object if possible.
505 void CallApplyLazy(Expression* applicand,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000506 Expression* receiver,
507 VariableProxy* arguments,
508 int position);
509
ager@chromium.org9085a012009-05-11 19:22:57 +0000510 void CheckStack();
511
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000512 struct InlineRuntimeLUT {
513 void (CodeGenerator::*method)(ZoneList<Expression*>*);
514 const char* name;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000515 int nargs;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000516 };
517 static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
ager@chromium.org9085a012009-05-11 19:22:57 +0000518 bool CheckForInlineRuntimeCall(CallRuntime* node);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000519 static bool PatchInlineRuntimeEntry(Handle<String> name,
520 const InlineRuntimeLUT& new_entry,
521 InlineRuntimeLUT* old_entry);
ager@chromium.org9085a012009-05-11 19:22:57 +0000522 void ProcessDeclarations(ZoneList<Declaration*>* declarations);
523
ager@chromium.org3811b432009-10-28 14:53:37 +0000524 static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
ager@chromium.org9085a012009-05-11 19:22:57 +0000525
526 // Declare global variables and functions in the given array of
527 // name/value pairs.
528 void DeclareGlobals(Handle<FixedArray> pairs);
529
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000530 // Instantiate the function based on the shared function info.
531 void InstantiateFunction(Handle<SharedFunctionInfo> function_info);
ager@chromium.org9085a012009-05-11 19:22:57 +0000532
533 // Support for type checks.
534 void GenerateIsSmi(ZoneList<Expression*>* args);
535 void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
536 void GenerateIsArray(ZoneList<Expression*>* args);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +0000537 void GenerateIsRegExp(ZoneList<Expression*>* args);
ager@chromium.org6141cbe2009-11-20 12:14:52 +0000538 void GenerateIsObject(ZoneList<Expression*>* args);
539 void GenerateIsFunction(ZoneList<Expression*>* args);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000540 void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
ager@chromium.org9085a012009-05-11 19:22:57 +0000541
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000542 // Support for construct call checks.
543 void GenerateIsConstructCall(ZoneList<Expression*>* args);
544
ager@chromium.org9085a012009-05-11 19:22:57 +0000545 // Support for arguments.length and arguments[?].
546 void GenerateArgumentsLength(ZoneList<Expression*>* args);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 void GenerateArguments(ZoneList<Expression*>* args);
ager@chromium.org9085a012009-05-11 19:22:57 +0000548
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000549 // Support for accessing the class and value fields of an object.
550 void GenerateClassOf(ZoneList<Expression*>* args);
ager@chromium.org9085a012009-05-11 19:22:57 +0000551 void GenerateValueOf(ZoneList<Expression*>* args);
552 void GenerateSetValueOf(ZoneList<Expression*>* args);
553
554 // Fast support for charCodeAt(n).
555 void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
556
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000557 // Fast support for string.charAt(n) and string[n].
558 void GenerateCharFromCode(ZoneList<Expression*>* args);
559
ager@chromium.org9085a012009-05-11 19:22:57 +0000560 // Fast support for object equality testing.
561 void GenerateObjectEquals(ZoneList<Expression*>* args);
562
563 void GenerateLog(ZoneList<Expression*>* args);
564
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000565 void GenerateGetFramePointer(ZoneList<Expression*>* args);
566
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000567 // Fast support for Math.random().
568 void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
569
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000570 // Fast support for StringAdd.
571 void GenerateStringAdd(ZoneList<Expression*>* args);
572
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000573 // Fast support for SubString.
574 void GenerateSubString(ZoneList<Expression*>* args);
575
576 // Fast support for StringCompare.
577 void GenerateStringCompare(ZoneList<Expression*>* args);
578
579 // Support for direct calls from JavaScript to native RegExp code.
580 void GenerateRegExpExec(ZoneList<Expression*>* args);
581
ager@chromium.org5c838252010-02-19 08:53:10 +0000582 // Fast support for number to string.
583 void GenerateNumberToString(ZoneList<Expression*>* args);
584
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000585 // Fast call to math functions.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 void GenerateMathPow(ZoneList<Expression*>* args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000587 void GenerateMathSin(ZoneList<Expression*>* args);
588 void GenerateMathCos(ZoneList<Expression*>* args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000589 void GenerateMathSqrt(ZoneList<Expression*>* args);
590
591// Simple condition analysis.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000592 enum ConditionAnalysis {
593 ALWAYS_TRUE,
594 ALWAYS_FALSE,
595 DONT_KNOW
596 };
597 ConditionAnalysis AnalyzeCondition(Expression* cond);
598
ager@chromium.org9085a012009-05-11 19:22:57 +0000599 // Methods used to indicate which source code is generated for. Source
600 // positions are collected by the assembler and emitted with the relocation
601 // information.
602 void CodeForFunctionPosition(FunctionLiteral* fun);
603 void CodeForReturnPosition(FunctionLiteral* fun);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000604 void CodeForStatementPosition(Statement* node);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000605 void CodeForDoWhileConditionPosition(DoWhileStatement* stmt);
ager@chromium.org9085a012009-05-11 19:22:57 +0000606 void CodeForSourcePosition(int pos);
607
608#ifdef DEBUG
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000609 // True if the registers are valid for entry to a block. There should
610 // be no frame-external references to (non-reserved) registers.
ager@chromium.org9085a012009-05-11 19:22:57 +0000611 bool HasValidEntryRegisters();
612#endif
613
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000614 ZoneList<DeferredCode*> deferred_;
ager@chromium.org9085a012009-05-11 19:22:57 +0000615
616 // Assembler
617 MacroAssembler* masm_; // to generate code
618
ager@chromium.org5c838252010-02-19 08:53:10 +0000619 CompilationInfo* info_;
620
ager@chromium.org9085a012009-05-11 19:22:57 +0000621 // Code generation state
ager@chromium.org9085a012009-05-11 19:22:57 +0000622 VirtualFrame* frame_;
623 RegisterAllocator* allocator_;
624 CodeGenState* state_;
625 int loop_nesting_;
626
627 // Jump targets.
628 // The target of the return from the function.
629 BreakTarget function_return_;
630
631 // True if the function return is shadowed (ie, jumping to the target
632 // function_return_ does not jump to the true function return, but rather
633 // to some unlinking code).
634 bool function_return_is_shadowed_;
635
636 // True when we are in code that expects the virtual frame to be fully
637 // spilled. Some virtual frame function are disabled in DEBUG builds when
638 // called from spilled code, because they do not leave the virtual frame
639 // in a spilled state.
640 bool in_spilled_code_;
641
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000642 static InlineRuntimeLUT kInlineRuntimeLUT[];
643
ager@chromium.org9085a012009-05-11 19:22:57 +0000644 friend class VirtualFrame;
645 friend class JumpTarget;
646 friend class Reference;
647 friend class Result;
ager@chromium.org3811b432009-10-28 14:53:37 +0000648 friend class FastCodeGenerator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000649 friend class FullCodeGenerator;
650 friend class FullCodeGenSyntaxChecker;
ager@chromium.org9085a012009-05-11 19:22:57 +0000651
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000652 friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654 DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
655};
656
657
ager@chromium.org3811b432009-10-28 14:53:37 +0000658// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000659enum GenericBinaryFlags {
ager@chromium.org3811b432009-10-28 14:53:37 +0000660 NO_GENERIC_BINARY_FLAGS = 0,
661 NO_SMI_CODE_IN_STUB = 1 << 0 // Omit smi code in stub.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000662};
663
664
665class GenericBinaryOpStub: public CodeStub {
666 public:
667 GenericBinaryOpStub(Token::Value op,
668 OverwriteMode mode,
ager@chromium.org5c838252010-02-19 08:53:10 +0000669 GenericBinaryFlags flags,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 NumberInfo operands_type = NumberInfo::Unknown())
ager@chromium.org3811b432009-10-28 14:53:37 +0000671 : op_(op),
672 mode_(mode),
673 flags_(flags),
674 args_in_registers_(false),
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000675 args_reversed_(false),
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000676 static_operands_type_(operands_type),
677 runtime_operands_type_(BinaryOpIC::DEFAULT),
678 name_(NULL) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000679 use_sse3_ = CpuFeatures::IsSupported(SSE3);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000680 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
681 }
682
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000683 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info)
684 : op_(OpBits::decode(key)),
685 mode_(ModeBits::decode(key)),
686 flags_(FlagBits::decode(key)),
687 args_in_registers_(ArgsInRegistersBits::decode(key)),
688 args_reversed_(ArgsReversedBits::decode(key)),
689 use_sse3_(SSE3Bits::decode(key)),
690 static_operands_type_(NumberInfo::ExpandedRepresentation(
691 StaticTypeInfoBits::decode(key))),
692 runtime_operands_type_(type_info),
693 name_(NULL) {
694 }
695
ager@chromium.org3811b432009-10-28 14:53:37 +0000696 // Generate code to call the stub with the supplied arguments. This will add
697 // code at the call site to prepare arguments either in registers or on the
698 // stack together with the actual call.
699 void GenerateCall(MacroAssembler* masm, Register left, Register right);
700 void GenerateCall(MacroAssembler* masm, Register left, Smi* right);
701 void GenerateCall(MacroAssembler* masm, Smi* left, Register right);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000702
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000703 Result GenerateCall(MacroAssembler* masm,
704 VirtualFrame* frame,
705 Result* left,
706 Result* right);
707
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000708 private:
709 Token::Value op_;
710 OverwriteMode mode_;
711 GenericBinaryFlags flags_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000712 bool args_in_registers_; // Arguments passed in registers not on the stack.
713 bool args_reversed_; // Left and right argument are swapped.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000714 bool use_sse3_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000715
716 // Number type information of operands, determined by code generator.
717 NumberInfo static_operands_type_;
718
719 // Operand type information determined at runtime.
720 BinaryOpIC::TypeInfo runtime_operands_type_;
721
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000722 char* name_;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000723
724 const char* GetName();
725
726#ifdef DEBUG
727 void Print() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000728 PrintF("GenericBinaryOpStub %d (op %s), "
729 "(mode %d, flags %d, registers %d, reversed %d, only_numbers %s)\n",
730 MinorKey(),
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000731 Token::String(op_),
732 static_cast<int>(mode_),
ager@chromium.org3811b432009-10-28 14:53:37 +0000733 static_cast<int>(flags_),
734 static_cast<int>(args_in_registers_),
ager@chromium.org5c838252010-02-19 08:53:10 +0000735 static_cast<int>(args_reversed_),
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000736 static_operands_type_.ToString());
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000737 }
738#endif
739
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000740 // Minor key encoding in 18 bits TTNNNFRASOOOOOOOMM.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000741 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
ager@chromium.org5c838252010-02-19 08:53:10 +0000742 class OpBits: public BitField<Token::Value, 2, 7> {};
743 class SSE3Bits: public BitField<bool, 9, 1> {};
744 class ArgsInRegistersBits: public BitField<bool, 10, 1> {};
745 class ArgsReversedBits: public BitField<bool, 11, 1> {};
746 class FlagBits: public BitField<GenericBinaryFlags, 12, 1> {};
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000747 class StaticTypeInfoBits: public BitField<int, 13, 3> {};
748 class RuntimeTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 16, 2> {};
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000749
750 Major MajorKey() { return GenericBinaryOp; }
751 int MinorKey() {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000752 // Encode the parameters in a unique 18 bit value.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000753 return OpBits::encode(op_)
ager@chromium.org3811b432009-10-28 14:53:37 +0000754 | ModeBits::encode(mode_)
755 | FlagBits::encode(flags_)
756 | SSE3Bits::encode(use_sse3_)
757 | ArgsInRegistersBits::encode(args_in_registers_)
ager@chromium.org5c838252010-02-19 08:53:10 +0000758 | ArgsReversedBits::encode(args_reversed_)
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000759 | StaticTypeInfoBits::encode(
760 static_operands_type_.ThreeBitRepresentation())
761 | RuntimeTypeInfoBits::encode(runtime_operands_type_);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000762 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000763
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000764 void Generate(MacroAssembler* masm);
ager@chromium.org3811b432009-10-28 14:53:37 +0000765 void GenerateSmiCode(MacroAssembler* masm, Label* slow);
766 void GenerateLoadArguments(MacroAssembler* masm);
767 void GenerateReturn(MacroAssembler* masm);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000768 void GenerateRegisterArgsPush(MacroAssembler* masm);
769 void GenerateTypeTransition(MacroAssembler* masm);
ager@chromium.org3811b432009-10-28 14:53:37 +0000770
771 bool ArgsInRegistersSupported() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000772 return (op_ == Token::ADD) || (op_ == Token::SUB)
773 || (op_ == Token::MUL) || (op_ == Token::DIV);
ager@chromium.org3811b432009-10-28 14:53:37 +0000774 }
775 bool IsOperationCommutative() {
776 return (op_ == Token::ADD) || (op_ == Token::MUL);
777 }
778
779 void SetArgsInRegisters() { args_in_registers_ = true; }
780 void SetArgsReversed() { args_reversed_ = true; }
781 bool HasSmiCodeInStub() { return (flags_ & NO_SMI_CODE_IN_STUB) == 0; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000782 bool HasArgsInRegisters() { return args_in_registers_; }
783 bool HasArgsReversed() { return args_reversed_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000784
785 bool ShouldGenerateSmiCode() {
786 return HasSmiCodeInStub() &&
787 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
788 runtime_operands_type_ != BinaryOpIC::STRINGS;
789 }
790
791 bool ShouldGenerateFPCode() {
792 return runtime_operands_type_ != BinaryOpIC::STRINGS;
793 }
794
795 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
796
797 virtual InlineCacheState GetICState() {
798 return BinaryOpIC::ToState(runtime_operands_type_);
799 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000800};
801
802
803class StringStubBase: public CodeStub {
804 public:
805 // Generate code for copying characters using a simple loop. This should only
806 // be used in places where the number of characters is small and the
807 // additional setup and checking in GenerateCopyCharactersREP adds too much
808 // overhead. Copying of overlapping regions is not supported.
809 void GenerateCopyCharacters(MacroAssembler* masm,
810 Register dest,
811 Register src,
812 Register count,
813 bool ascii);
814
815 // Generate code for copying characters using the rep movs instruction.
816 // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
817 // not supported.
818 void GenerateCopyCharactersREP(MacroAssembler* masm,
819 Register dest, // Must be rdi.
820 Register src, // Must be rsi.
821 Register count, // Must be rcx.
822 bool ascii);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000823
824
825 // Probe the symbol table for a two character string. If the string is
826 // not found by probing a jump to the label not_found is performed. This jump
827 // does not guarantee that the string is not in the symbol table. If the
828 // string is found the code falls through with the string in register rax.
829 void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
830 Register c1,
831 Register c2,
832 Register scratch1,
833 Register scratch2,
834 Register scratch3,
835 Register scratch4,
836 Label* not_found);
837
838 // Generate string hash.
839 void GenerateHashInit(MacroAssembler* masm,
840 Register hash,
841 Register character,
842 Register scratch);
843 void GenerateHashAddCharacter(MacroAssembler* masm,
844 Register hash,
845 Register character,
846 Register scratch);
847 void GenerateHashGetHash(MacroAssembler* masm,
848 Register hash,
849 Register scratch);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000850};
851
852
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000853// Flag that indicates how to generate code for the stub StringAddStub.
854enum StringAddFlags {
855 NO_STRING_ADD_FLAGS = 0,
856 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub.
857};
858
859
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000860class StringAddStub: public StringStubBase {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000861 public:
862 explicit StringAddStub(StringAddFlags flags) {
863 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
864 }
865
866 private:
867 Major MajorKey() { return StringAdd; }
868 int MinorKey() { return string_check_ ? 0 : 1; }
869
870 void Generate(MacroAssembler* masm);
871
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000872 // Should the stub check whether arguments are strings?
873 bool string_check_;
874};
875
876
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000877class SubStringStub: public StringStubBase {
878 public:
879 SubStringStub() {}
880
881 private:
882 Major MajorKey() { return SubString; }
883 int MinorKey() { return 0; }
884
885 void Generate(MacroAssembler* masm);
886};
887
888
889class StringCompareStub: public CodeStub {
890 public:
891 explicit StringCompareStub() {}
892
893 // Compare two flat ascii strings and returns result in rax after popping two
894 // arguments from the stack.
895 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
896 Register left,
897 Register right,
898 Register scratch1,
899 Register scratch2,
900 Register scratch3,
901 Register scratch4);
902
903 private:
904 Major MajorKey() { return StringCompare; }
905 int MinorKey() { return 0; }
906
907 void Generate(MacroAssembler* masm);
908};
909
910
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000911class NumberToStringStub: public CodeStub {
912 public:
913 NumberToStringStub() { }
914
915 // Generate code to do a lookup in the number string cache. If the number in
916 // the register object is found in the cache the generated code falls through
917 // with the result in the result register. The object and the result register
918 // can be the same. If the number is not found in the cache the code jumps to
919 // the label not_found with only the content of register object unchanged.
920 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
921 Register object,
922 Register result,
923 Register scratch1,
924 Register scratch2,
925 bool object_is_smi,
926 Label* not_found);
927
928 private:
929 Major MajorKey() { return NumberToString; }
930 int MinorKey() { return 0; }
931
932 void Generate(MacroAssembler* masm);
933
934 const char* GetName() { return "NumberToStringStub"; }
935
936#ifdef DEBUG
937 void Print() {
938 PrintF("NumberToStringStub\n");
939 }
940#endif
941};
942
943
ager@chromium.org9085a012009-05-11 19:22:57 +0000944} } // namespace v8::internal
945
946#endif // V8_X64_CODEGEN_X64_H_