blob: 7b50b01049fc5c135d0d394bedb43ae473a088d9 [file] [log] [blame]
ager@chromium.org7c537e22008-10-16 08:43:32 +00001// Copyright 2006-2008 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
ager@chromium.org5ec48922009-05-05 07:25:34 +000028#ifndef V8_ARM_CODEGEN_ARM_H_
29#define V8_ARM_CODEGEN_ARM_H_
ager@chromium.org7c537e22008-10-16 08:43:32 +000030
kasperl@chromium.org71affb52009-05-26 05:44:31 +000031namespace v8 {
32namespace internal {
ager@chromium.org7c537e22008-10-16 08:43:32 +000033
34// Forward declarations
35class DeferredCode;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000036class RegisterAllocator;
37class RegisterFile;
ager@chromium.org7c537e22008-10-16 08:43:32 +000038
ager@chromium.org3bf7b912008-11-17 09:09:45 +000039enum InitState { CONST_INIT, NOT_CONST_INIT };
40enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
ager@chromium.org7c537e22008-10-16 08:43:32 +000041
ager@chromium.org3bf7b912008-11-17 09:09:45 +000042
43// -------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +000044// Reference support
45
46// A reference is a C++ stack-allocated object that keeps an ECMA
47// reference on the execution stack while in scope. For variables
48// the reference is empty, indicating that it isn't necessary to
49// store state on the stack for keeping track of references to those.
50// For properties, we keep either one (named) or two (indexed) values
51// on the execution stack to represent the reference.
52
ager@chromium.org7c537e22008-10-16 08:43:32 +000053class Reference BASE_EMBEDDED {
54 public:
55 // The values of the types is important, see size().
56 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
57 Reference(CodeGenerator* cgen, Expression* expression);
58 ~Reference();
59
60 Expression* expression() const { return expression_; }
61 Type type() const { return type_; }
62 void set_type(Type value) {
63 ASSERT(type_ == ILLEGAL);
64 type_ = value;
65 }
66
ager@chromium.org3bf7b912008-11-17 09:09:45 +000067 // The size the reference takes up on the stack.
68 int size() const { return (type_ == ILLEGAL) ? 0 : type_; }
ager@chromium.org7c537e22008-10-16 08:43:32 +000069
70 bool is_illegal() const { return type_ == ILLEGAL; }
71 bool is_slot() const { return type_ == SLOT; }
72 bool is_property() const { return type_ == NAMED || type_ == KEYED; }
73
74 // Return the name. Only valid for named property references.
75 Handle<String> GetName();
76
77 // Generate code to push the value of the reference on top of the
78 // expression stack. The reference is expected to be already on top of
79 // the expression stack, and it is left in place with its value above it.
80 void GetValue(TypeofState typeof_state);
81
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000082 // Generate code to push the value of a reference on top of the expression
83 // stack and then spill the stack frame. This function is used temporarily
84 // while the code generator is being transformed.
85 inline void GetValueAndSpill(TypeofState typeof_state);
86
ager@chromium.org7c537e22008-10-16 08:43:32 +000087 // Generate code to store the value on top of the expression stack in the
88 // reference. The reference is expected to be immediately below the value
89 // on the expression stack. The stored value is left in place (with the
90 // reference intact below it) to support chained assignments.
91 void SetValue(InitState init_state);
92
93 private:
94 CodeGenerator* cgen_;
95 Expression* expression_;
96 Type type_;
97};
98
99
100// -------------------------------------------------------------------------
101// Code generation state
102
103// The state is passed down the AST by the code generator (and back up, in
104// the form of the state of the label pair). It is threaded through the
105// call stack. Constructing a state implicitly pushes it on the owning code
106// generator's stack of states, and destroying one implicitly pops it.
107
108class CodeGenState BASE_EMBEDDED {
109 public:
110 // Create an initial code generator state. Destroying the initial state
111 // leaves the code generator with a NULL state.
112 explicit CodeGenState(CodeGenerator* owner);
113
114 // Create a code generator state based on a code generator's current
115 // state. The new state has its own typeof state and pair of branch
116 // labels.
117 CodeGenState(CodeGenerator* owner,
118 TypeofState typeof_state,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000119 JumpTarget* true_target,
120 JumpTarget* false_target);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000121
122 // Destroy a code generator state and restore the owning code generator's
123 // previous state.
124 ~CodeGenState();
125
126 TypeofState typeof_state() const { return typeof_state_; }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000127 JumpTarget* true_target() const { return true_target_; }
128 JumpTarget* false_target() const { return false_target_; }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000129
130 private:
131 CodeGenerator* owner_;
132 TypeofState typeof_state_;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000133 JumpTarget* true_target_;
134 JumpTarget* false_target_;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000135 CodeGenState* previous_;
136};
137
138
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000139// -------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +0000140// CodeGenerator
141
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000142class CodeGenerator: public AstVisitor {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000143 public:
144 // Takes a function literal, generates code for it. This function should only
145 // be called by compiler.cc.
146 static Handle<Code> MakeCode(FunctionLiteral* fun,
147 Handle<Script> script,
148 bool is_eval);
149
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000150 // Printing of AST, etc. as requested by flags.
151 static void MakeCodePrologue(FunctionLiteral* fun);
152
153 // Allocate and install the code.
154 static Handle<Code> MakeCodeEpilogue(FunctionLiteral* fun,
155 MacroAssembler* masm,
156 Code::Flags flags,
157 Handle<Script> script);
158
christian.plesner.hansen@gmail.comaca49682009-01-07 14:29:04 +0000159#ifdef ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000160 static bool ShouldGenerateLog(Expression* type);
christian.plesner.hansen@gmail.comaca49682009-01-07 14:29:04 +0000161#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000162
ager@chromium.org7c537e22008-10-16 08:43:32 +0000163 static void SetFunctionInfo(Handle<JSFunction> fun,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000164 FunctionLiteral* lit,
ager@chromium.org7c537e22008-10-16 08:43:32 +0000165 bool is_toplevel,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000166 Handle<Script> script);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000167
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000168 static void RecordPositions(MacroAssembler* masm, int pos);
169
ager@chromium.org7c537e22008-10-16 08:43:32 +0000170 // Accessors
171 MacroAssembler* masm() { return masm_; }
172
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000173 VirtualFrame* frame() const { return frame_; }
174
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000175 bool has_valid_frame() const { return frame_ != NULL; }
176
177 // Set the virtual frame to be new_frame, with non-frame register
178 // reference counts given by non_frame_registers. The non-frame
179 // register reference counts of the old frame are returned in
180 // non_frame_registers.
181 void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers);
182
183 void DeleteFrame();
184
185 RegisterAllocator* allocator() const { return allocator_; }
186
ager@chromium.org7c537e22008-10-16 08:43:32 +0000187 CodeGenState* state() { return state_; }
188 void set_state(CodeGenState* state) { state_ = state; }
189
190 void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
191
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000192 static const int kUnknownIntValue = -1;
193
ager@chromium.org4af710e2009-09-15 12:20:11 +0000194 // Number of instructions used for the JS return sequence. The constant is
195 // used by the debugger to patch the JS return sequence.
196 static const int kJSReturnSequenceLength = 4;
197
ager@chromium.org7c537e22008-10-16 08:43:32 +0000198 private:
199 // Construction/Destruction
200 CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
201 virtual ~CodeGenerator() { delete masm_; }
202
203 // Accessors
204 Scope* scope() const { return scope_; }
205
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000206 // Generating deferred code.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000207 void ProcessDeferred();
208
209 bool is_eval() { return is_eval_; }
210
211 // State
212 bool has_cc() const { return cc_reg_ != al; }
213 TypeofState typeof_state() const { return state_->typeof_state(); }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000214 JumpTarget* true_target() const { return state_->true_target(); }
215 JumpTarget* false_target() const { return state_->false_target(); }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000216
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000217 // We don't track loop nesting level on ARM yet.
218 int loop_nesting() const { return 0; }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000219
220 // Node visitors.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000221 void VisitStatements(ZoneList<Statement*>* statements);
222
ager@chromium.org7c537e22008-10-16 08:43:32 +0000223#define DEF_VISIT(type) \
224 void Visit##type(type* node);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000225 AST_NODE_LIST(DEF_VISIT)
ager@chromium.org7c537e22008-10-16 08:43:32 +0000226#undef DEF_VISIT
227
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000228 // Visit a statement and then spill the virtual frame if control flow can
229 // reach the end of the statement (ie, it does not exit via break,
230 // continue, return, or throw). This function is used temporarily while
231 // the code generator is being transformed.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000232 inline void VisitAndSpill(Statement* statement);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000233
234 // Visit a list of statements and then spill the virtual frame if control
235 // flow can reach the end of the list.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000236 inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000237
ager@chromium.org7c537e22008-10-16 08:43:32 +0000238 // Main code generation function
239 void GenCode(FunctionLiteral* fun);
240
241 // The following are used by class Reference.
242 void LoadReference(Reference* ref);
243 void UnloadReference(Reference* ref);
244
ager@chromium.org7c537e22008-10-16 08:43:32 +0000245 MemOperand ContextOperand(Register context, int index) const {
246 return MemOperand(context, Context::SlotOffset(index));
247 }
248
249 MemOperand SlotOperand(Slot* slot, Register tmp);
250
ager@chromium.org381abbb2009-02-25 13:23:22 +0000251 MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
252 Register tmp,
253 Register tmp2,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000254 JumpTarget* slow);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000255
ager@chromium.org7c537e22008-10-16 08:43:32 +0000256 // Expressions
257 MemOperand GlobalObject() const {
258 return ContextOperand(cp, Context::GLOBAL_INDEX);
259 }
260
261 void LoadCondition(Expression* x,
262 TypeofState typeof_state,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000263 JumpTarget* true_target,
264 JumpTarget* false_target,
ager@chromium.org7c537e22008-10-16 08:43:32 +0000265 bool force_cc);
266 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
267 void LoadGlobal();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 void LoadGlobalReceiver(Register scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000269
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000270 // Generate code to push the value of an expression on top of the frame
271 // and then spill the frame fully to memory. This function is used
272 // temporarily while the code generator is being transformed.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000273 inline void LoadAndSpill(Expression* expression,
274 TypeofState typeof_state = NOT_INSIDE_TYPEOF);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000275
276 // Call LoadCondition and then spill the virtual frame unless control flow
277 // cannot reach the end of the expression (ie, by emitting only
278 // unconditional jumps to the control targets).
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000279 inline void LoadConditionAndSpill(Expression* expression,
280 TypeofState typeof_state,
281 JumpTarget* true_target,
282 JumpTarget* false_target,
283 bool force_control);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000284
ager@chromium.org7c537e22008-10-16 08:43:32 +0000285 // Read a value from a slot and leave it on top of the expression stack.
286 void LoadFromSlot(Slot* slot, TypeofState typeof_state);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000287 void LoadFromGlobalSlotCheckExtensions(Slot* slot,
288 TypeofState typeof_state,
289 Register tmp,
290 Register tmp2,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000291 JumpTarget* slow);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000292
293 // Special code for typeof expressions: Unfortunately, we must
294 // be careful when loading the expression in 'typeof'
295 // expressions. We are not allowed to throw reference errors for
296 // non-existing properties of the global object, so we must make it
297 // look like an explicit property access, instead of an access
298 // through the context chain.
299 void LoadTypeofExpression(Expression* x);
300
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000301 void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000302
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000303 void GenericBinaryOperation(Token::Value op,
304 OverwriteMode overwrite_mode,
305 int known_rhs = kUnknownIntValue);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000306 void Comparison(Condition cc,
307 Expression* left,
308 Expression* right,
309 bool strict = false);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000310
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000311 void SmiOperation(Token::Value op,
312 Handle<Object> value,
313 bool reversed,
314 OverwriteMode mode);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000315
316 void CallWithArguments(ZoneList<Expression*>* arguments, int position);
317
318 // Control flow
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000319 void Branch(bool if_true, JumpTarget* target);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000320 void CheckStack();
ager@chromium.org7c537e22008-10-16 08:43:32 +0000321
ager@chromium.org9085a012009-05-11 19:22:57 +0000322 struct InlineRuntimeLUT {
323 void (CodeGenerator::*method)(ZoneList<Expression*>*);
324 const char* name;
325 };
326
327 static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000328 bool CheckForInlineRuntimeCall(CallRuntime* node);
ager@chromium.org9085a012009-05-11 19:22:57 +0000329 static bool PatchInlineRuntimeEntry(Handle<String> name,
330 const InlineRuntimeLUT& new_entry,
331 InlineRuntimeLUT* old_entry);
332
ager@chromium.org7c537e22008-10-16 08:43:32 +0000333 Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
334 void ProcessDeclarations(ZoneList<Declaration*>* declarations);
335
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000336 Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000337
338 // Declare global variables and functions in the given array of
339 // name/value pairs.
340 void DeclareGlobals(Handle<FixedArray> pairs);
341
342 // Instantiate the function boilerplate.
343 void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
344
345 // Support for type checks.
346 void GenerateIsSmi(ZoneList<Expression*>* args);
347 void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
348 void GenerateIsArray(ZoneList<Expression*>* args);
349
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000350 // Support for construct call checks.
351 void GenerateIsConstructCall(ZoneList<Expression*>* args);
352
ager@chromium.org7c537e22008-10-16 08:43:32 +0000353 // Support for arguments.length and arguments[?].
354 void GenerateArgumentsLength(ZoneList<Expression*>* args);
355 void GenerateArgumentsAccess(ZoneList<Expression*>* args);
356
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000357 // Support for accessing the class and value fields of an object.
358 void GenerateClassOf(ZoneList<Expression*>* args);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000359 void GenerateValueOf(ZoneList<Expression*>* args);
360 void GenerateSetValueOf(ZoneList<Expression*>* args);
361
362 // Fast support for charCodeAt(n).
363 void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
364
365 // Fast support for object equality testing.
366 void GenerateObjectEquals(ZoneList<Expression*>* args);
367
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000368 void GenerateLog(ZoneList<Expression*>* args);
369
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000370 // Fast support for Math.random().
371 void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
372
373 // Fast support for Math.sin and Math.cos.
374 enum MathOp { SIN, COS };
375 void GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args);
376 inline void GenerateMathSin(ZoneList<Expression*>* args);
377 inline void GenerateMathCos(ZoneList<Expression*>* args);
378
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000379 // Simple condition analysis.
380 enum ConditionAnalysis {
381 ALWAYS_TRUE,
382 ALWAYS_FALSE,
383 DONT_KNOW
384 };
385 ConditionAnalysis AnalyzeCondition(Expression* cond);
386
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000387 // Methods used to indicate which source code is generated for. Source
388 // positions are collected by the assembler and emitted with the relocation
389 // information.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000390 void CodeForFunctionPosition(FunctionLiteral* fun);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +0000391 void CodeForReturnPosition(FunctionLiteral* fun);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000392 void CodeForStatementPosition(Statement* node);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000393 void CodeForSourcePosition(int pos);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000394
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000395#ifdef DEBUG
396 // True if the registers are valid for entry to a block.
397 bool HasValidEntryRegisters();
398#endif
399
ager@chromium.org7c537e22008-10-16 08:43:32 +0000400 bool is_eval_; // Tells whether code is generated for eval.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401
ager@chromium.org7c537e22008-10-16 08:43:32 +0000402 Handle<Script> script_;
403 List<DeferredCode*> deferred_;
404
405 // Assembler
406 MacroAssembler* masm_; // to generate code
407
408 // Code generation state
409 Scope* scope_;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000410 VirtualFrame* frame_;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000411 RegisterAllocator* allocator_;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000412 Condition cc_reg_;
413 CodeGenState* state_;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000414
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000415 // Jump targets
416 BreakTarget function_return_;
417
418 // True if the function return is shadowed (ie, jumping to the target
419 // function_return_ does not jump to the true function return, but rather
420 // to some unlinking code).
421 bool function_return_is_shadowed_;
422
ager@chromium.org9085a012009-05-11 19:22:57 +0000423 static InlineRuntimeLUT kInlineRuntimeLUT[];
424
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000425 friend class VirtualFrame;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000426 friend class JumpTarget;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000427 friend class Reference;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000428
429 DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
430};
431
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000433class GenericBinaryOpStub : public CodeStub {
434 public:
435 GenericBinaryOpStub(Token::Value op,
436 OverwriteMode mode,
437 int constant_rhs = CodeGenerator::kUnknownIntValue)
438 : op_(op),
439 mode_(mode),
440 constant_rhs_(constant_rhs),
441 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)) { }
442
443 private:
444 Token::Value op_;
445 OverwriteMode mode_;
446 int constant_rhs_;
447 bool specialized_on_rhs_;
448
449 static const int kMaxKnownRhs = 0x40000000;
450
451 // Minor key encoding in 16 bits.
452 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
453 class OpBits: public BitField<Token::Value, 2, 6> {};
454 class KnownIntBits: public BitField<int, 8, 8> {};
455
456 Major MajorKey() { return GenericBinaryOp; }
457 int MinorKey() {
458 // Encode the parameters in a unique 16 bit value.
459 return OpBits::encode(op_)
460 | ModeBits::encode(mode_)
461 | KnownIntBits::encode(MinorKeyForKnownInt());
462 }
463
464 void Generate(MacroAssembler* masm);
465 void HandleNonSmiBitwiseOp(MacroAssembler* masm);
466
467 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) {
468 if (constant_rhs == CodeGenerator::kUnknownIntValue) return false;
469 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3;
470 if (op == Token::MOD) {
471 if (constant_rhs <= 1) return false;
472 if (constant_rhs <= 10) return true;
473 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true;
474 return false;
475 }
476 return false;
477 }
478
479 int MinorKeyForKnownInt() {
480 if (!specialized_on_rhs_) return 0;
481 if (constant_rhs_ <= 10) return constant_rhs_ + 1;
482 ASSERT(IsPowerOf2(constant_rhs_));
483 int key = 12;
484 int d = constant_rhs_;
485 while ((d & 1) == 0) {
486 key++;
487 d >>= 1;
488 }
489 return key;
490 }
491
492 const char* GetName() {
493 switch (op_) {
494 case Token::ADD: return "GenericBinaryOpStub_ADD";
495 case Token::SUB: return "GenericBinaryOpStub_SUB";
496 case Token::MUL: return "GenericBinaryOpStub_MUL";
497 case Token::DIV: return "GenericBinaryOpStub_DIV";
498 case Token::MOD: return "GenericBinaryOpStub_MOD";
499 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
500 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
501 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
502 case Token::SAR: return "GenericBinaryOpStub_SAR";
503 case Token::SHL: return "GenericBinaryOpStub_SHL";
504 case Token::SHR: return "GenericBinaryOpStub_SHR";
505 default: return "GenericBinaryOpStub";
506 }
507 }
508
509#ifdef DEBUG
510 void Print() {
511 if (!specialized_on_rhs_) {
512 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
513 } else {
514 PrintF("GenericBinaryOpStub (%s by %d)\n",
515 Token::String(op_),
516 constant_rhs_);
517 }
518 }
519#endif
520};
521
522
ager@chromium.org7c537e22008-10-16 08:43:32 +0000523} } // namespace v8::internal
524
ager@chromium.org5ec48922009-05-05 07:25:34 +0000525#endif // V8_ARM_CODEGEN_ARM_H_