blob: 904a3b71e1ba0cd61822178ffb9134c43b4414fe [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
28#ifndef V8_CODEGEN_ARM_H_
29#define V8_CODEGEN_ARM_H_
30
31#include "scopes.h"
32
33namespace v8 { namespace internal {
34
35// Forward declarations
36class DeferredCode;
37
38// Mode to overwrite BinaryExpression values.
39enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
40
ager@chromium.org3bf7b912008-11-17 09:09:45 +000041enum InitState { CONST_INIT, NOT_CONST_INIT };
42enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
ager@chromium.org7c537e22008-10-16 08:43:32 +000043
ager@chromium.org3bf7b912008-11-17 09:09:45 +000044
45// -------------------------------------------------------------------------
46// Virtual frame
47
48class VirtualFrame BASE_EMBEDDED {
49 public:
50 explicit VirtualFrame(CodeGenerator* cgen);
51
52 void Enter();
53 void Exit();
54
55 void AllocateLocals();
56
57 MemOperand Top() const { return MemOperand(sp, 0); }
58
59 MemOperand Element(int index) const {
60 return MemOperand(sp, index * kPointerSize);
61 }
62
63 MemOperand Local(int index) const {
64 ASSERT(0 <= index && index < frame_local_count_);
65 return MemOperand(fp, kLocal0Offset - index * kPointerSize);
66 }
67
68 MemOperand Function() const { return MemOperand(fp, kFunctionOffset); }
69
70 MemOperand Context() const { return MemOperand(fp, kContextOffset); }
71
72 MemOperand Parameter(int index) const {
73 // Index -1 corresponds to the receiver.
74 ASSERT(-1 <= index && index <= parameter_count_);
75 return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
76 }
77
78 inline void Drop(int count);
79
80 inline void Pop();
81 inline void Pop(Register reg);
82
83 inline void Push(Register reg);
84
85 private:
86 static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
87 static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
88 static const int kContextOffset = StandardFrameConstants::kContextOffset;
89
90 MacroAssembler* masm_;
91 int frame_local_count_;
92 int parameter_count_;
93};
94
95
96// -------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +000097// Reference support
98
99// A reference is a C++ stack-allocated object that keeps an ECMA
100// reference on the execution stack while in scope. For variables
101// the reference is empty, indicating that it isn't necessary to
102// store state on the stack for keeping track of references to those.
103// For properties, we keep either one (named) or two (indexed) values
104// on the execution stack to represent the reference.
105
ager@chromium.org7c537e22008-10-16 08:43:32 +0000106class Reference BASE_EMBEDDED {
107 public:
108 // The values of the types is important, see size().
109 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
110 Reference(CodeGenerator* cgen, Expression* expression);
111 ~Reference();
112
113 Expression* expression() const { return expression_; }
114 Type type() const { return type_; }
115 void set_type(Type value) {
116 ASSERT(type_ == ILLEGAL);
117 type_ = value;
118 }
119
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000120 // The size the reference takes up on the stack.
121 int size() const { return (type_ == ILLEGAL) ? 0 : type_; }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000122
123 bool is_illegal() const { return type_ == ILLEGAL; }
124 bool is_slot() const { return type_ == SLOT; }
125 bool is_property() const { return type_ == NAMED || type_ == KEYED; }
126
127 // Return the name. Only valid for named property references.
128 Handle<String> GetName();
129
130 // Generate code to push the value of the reference on top of the
131 // expression stack. The reference is expected to be already on top of
132 // the expression stack, and it is left in place with its value above it.
133 void GetValue(TypeofState typeof_state);
134
135 // Generate code to store the value on top of the expression stack in the
136 // reference. The reference is expected to be immediately below the value
137 // on the expression stack. The stored value is left in place (with the
138 // reference intact below it) to support chained assignments.
139 void SetValue(InitState init_state);
140
141 private:
142 CodeGenerator* cgen_;
143 Expression* expression_;
144 Type type_;
145};
146
147
148// -------------------------------------------------------------------------
149// Code generation state
150
151// The state is passed down the AST by the code generator (and back up, in
152// the form of the state of the label pair). It is threaded through the
153// call stack. Constructing a state implicitly pushes it on the owning code
154// generator's stack of states, and destroying one implicitly pops it.
155
156class CodeGenState BASE_EMBEDDED {
157 public:
158 // Create an initial code generator state. Destroying the initial state
159 // leaves the code generator with a NULL state.
160 explicit CodeGenState(CodeGenerator* owner);
161
162 // Create a code generator state based on a code generator's current
163 // state. The new state has its own typeof state and pair of branch
164 // labels.
165 CodeGenState(CodeGenerator* owner,
166 TypeofState typeof_state,
167 Label* true_target,
168 Label* false_target);
169
170 // Destroy a code generator state and restore the owning code generator's
171 // previous state.
172 ~CodeGenState();
173
174 TypeofState typeof_state() const { return typeof_state_; }
175 Label* true_target() const { return true_target_; }
176 Label* false_target() const { return false_target_; }
177
178 private:
179 CodeGenerator* owner_;
180 TypeofState typeof_state_;
181 Label* true_target_;
182 Label* false_target_;
183 CodeGenState* previous_;
184};
185
186
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000187// -------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +0000188// CodeGenerator
189
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000190class CodeGenerator: public AstVisitor {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000191 public:
192 // Takes a function literal, generates code for it. This function should only
193 // be called by compiler.cc.
194 static Handle<Code> MakeCode(FunctionLiteral* fun,
195 Handle<Script> script,
196 bool is_eval);
197
198 static void SetFunctionInfo(Handle<JSFunction> fun,
199 int length,
200 int function_token_position,
201 int start_position,
202 int end_position,
203 bool is_expression,
204 bool is_toplevel,
205 Handle<Script> script);
206
207 // Accessors
208 MacroAssembler* masm() { return masm_; }
209
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000210 VirtualFrame* frame() const { return frame_; }
211
ager@chromium.org7c537e22008-10-16 08:43:32 +0000212 CodeGenState* state() { return state_; }
213 void set_state(CodeGenState* state) { state_ = state; }
214
215 void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
216
217 private:
218 // Construction/Destruction
219 CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
220 virtual ~CodeGenerator() { delete masm_; }
221
222 // Accessors
223 Scope* scope() const { return scope_; }
224
225 void ProcessDeferred();
226
227 bool is_eval() { return is_eval_; }
228
229 // State
230 bool has_cc() const { return cc_reg_ != al; }
231 TypeofState typeof_state() const { return state_->typeof_state(); }
232 Label* true_target() const { return state_->true_target(); }
233 Label* false_target() const { return state_->false_target(); }
234
235
236 // Node visitors.
237#define DEF_VISIT(type) \
238 void Visit##type(type* node);
239 NODE_LIST(DEF_VISIT)
240#undef DEF_VISIT
241
242 // Main code generation function
243 void GenCode(FunctionLiteral* fun);
244
245 // The following are used by class Reference.
246 void LoadReference(Reference* ref);
247 void UnloadReference(Reference* ref);
248
ager@chromium.org7c537e22008-10-16 08:43:32 +0000249 MemOperand ContextOperand(Register context, int index) const {
250 return MemOperand(context, Context::SlotOffset(index));
251 }
252
253 MemOperand SlotOperand(Slot* slot, Register tmp);
254
255 // Expressions
256 MemOperand GlobalObject() const {
257 return ContextOperand(cp, Context::GLOBAL_INDEX);
258 }
259
260 void LoadCondition(Expression* x,
261 TypeofState typeof_state,
262 Label* true_target,
263 Label* false_target,
264 bool force_cc);
265 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
266 void LoadGlobal();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 void LoadGlobalReceiver(Register scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000268
269 // Read a value from a slot and leave it on top of the expression stack.
270 void LoadFromSlot(Slot* slot, TypeofState typeof_state);
271
272 // Special code for typeof expressions: Unfortunately, we must
273 // be careful when loading the expression in 'typeof'
274 // expressions. We are not allowed to throw reference errors for
275 // non-existing properties of the global object, so we must make it
276 // look like an explicit property access, instead of an access
277 // through the context chain.
278 void LoadTypeofExpression(Expression* x);
279
280 void ToBoolean(Label* true_target, Label* false_target);
281
282 void GenericBinaryOperation(Token::Value op);
283 void Comparison(Condition cc, bool strict = false);
284
285 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
286
287 void CallWithArguments(ZoneList<Expression*>* arguments, int position);
288
289 // Control flow
290 void Branch(bool if_true, Label* L);
291 void CheckStack();
292 void CleanStack(int num_bytes);
293
294 bool CheckForInlineRuntimeCall(CallRuntime* node);
295 Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
296 void ProcessDeclarations(ZoneList<Declaration*>* declarations);
297
298 Handle<Code> ComputeCallInitialize(int argc);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000299 Handle<Code> ComputeCallInitializeInLoop(int argc);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000300
301 // Declare global variables and functions in the given array of
302 // name/value pairs.
303 void DeclareGlobals(Handle<FixedArray> pairs);
304
305 // Instantiate the function boilerplate.
306 void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
307
308 // Support for type checks.
309 void GenerateIsSmi(ZoneList<Expression*>* args);
310 void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
311 void GenerateIsArray(ZoneList<Expression*>* args);
312
313 // Support for arguments.length and arguments[?].
314 void GenerateArgumentsLength(ZoneList<Expression*>* args);
315 void GenerateArgumentsAccess(ZoneList<Expression*>* args);
316
317 // Support for accessing the value field of an object (used by Date).
318 void GenerateValueOf(ZoneList<Expression*>* args);
319 void GenerateSetValueOf(ZoneList<Expression*>* args);
320
321 // Fast support for charCodeAt(n).
322 void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
323
324 // Fast support for object equality testing.
325 void GenerateObjectEquals(ZoneList<Expression*>* args);
326
327 // Methods and constants for fast case switch statement support.
328 //
329 // Only allow fast-case switch if the range of labels is at most
330 // this factor times the number of case labels.
331 // Value is derived from comparing the size of code generated by the normal
332 // switch code for Smi-labels to the size of a single pointer. If code
333 // quality increases this number should be decreased to match.
334 static const int kFastSwitchMaxOverheadFactor = 10;
335
336 // Minimal number of switch cases required before we allow jump-table
337 // optimization.
338 static const int kFastSwitchMinCaseCount = 5;
339
340 // The limit of the range of a fast-case switch, as a factor of the number
341 // of cases of the switch. Each platform should return a value that
342 // is optimal compared to the default code generated for a switch statement
343 // on that platform.
344 int FastCaseSwitchMaxOverheadFactor();
345
346 // The minimal number of cases in a switch before the fast-case switch
347 // optimization is enabled. Each platform should return a value that
348 // is optimal compared to the default code generated for a switch statement
349 // on that platform.
350 int FastCaseSwitchMinCaseCount();
351
352 // Allocate a jump table and create code to jump through it.
353 // Should call GenerateFastCaseSwitchCases to generate the code for
354 // all the cases at the appropriate point.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000355 void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
356 int min_index,
357 int range,
358 Label* fail_label,
359 Vector<Label*> case_targets,
360 Vector<Label> case_labels);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000361
362 // Generate the code for cases for the fast case switch.
363 // Called by GenerateFastCaseSwitchJumpTable.
364 void GenerateFastCaseSwitchCases(SwitchStatement* node,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000365 Vector<Label> case_labels);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000366
367 // Fast support for constant-Smi switches.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000368 void GenerateFastCaseSwitchStatement(SwitchStatement* node,
369 int min_index,
370 int range,
371 int default_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000372
373 // Fast support for constant-Smi switches. Tests whether switch statement
374 // permits optimization and calls GenerateFastCaseSwitch if it does.
375 // Returns true if the fast-case switch was generated, and false if not.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000376 bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000377
378
379 // Bottle-neck interface to call the Assembler to generate the statement
380 // position. This allows us to easily control whether statement positions
381 // should be generated or not.
382 void RecordStatementPosition(Node* node);
383
ager@chromium.org7c537e22008-10-16 08:43:32 +0000384 bool is_eval_; // Tells whether code is generated for eval.
385 Handle<Script> script_;
386 List<DeferredCode*> deferred_;
387
388 // Assembler
389 MacroAssembler* masm_; // to generate code
390
391 // Code generation state
392 Scope* scope_;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000393 VirtualFrame* frame_;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000394 Condition cc_reg_;
395 CodeGenState* state_;
396 bool is_inside_try_;
397 int break_stack_height_;
398
399 // Labels
400 Label function_return_;
401
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000402 friend class VirtualFrame;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000403 friend class Reference;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000404
405 DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
406};
407
408} } // namespace v8::internal
409
410#endif // V8_CODEGEN_ARM_H_