blob: f5de0ebcfb6d8266b34457bc7a4d80624237169f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +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_ARM_CODEGEN_ARM_H_
29#define V8_ARM_CODEGEN_ARM_H_
30
31namespace v8 {
32namespace internal {
33
34// Forward declarations
35class DeferredCode;
36class RegisterAllocator;
37class RegisterFile;
38
39enum InitState { CONST_INIT, NOT_CONST_INIT };
40enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
41
42
43// -------------------------------------------------------------------------
44// 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
53class 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
67 // The size the reference takes up on the stack.
68 int size() const { return (type_ == ILLEGAL) ? 0 : type_; }
69
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.
Steve Blockd0582a62009-12-15 09:54:21 +000080 void GetValue();
Steve Blocka7e24c12009-10-30 11:49:00 +000081
82 // 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.
Steve Blockd0582a62009-12-15 09:54:21 +000085 inline void GetValueAndSpill();
Steve Blocka7e24c12009-10-30 11:49:00 +000086
87 // 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
Steve Blockd0582a62009-12-15 09:54:21 +0000115 // state. The new state has its own pair of branch labels.
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 CodeGenState(CodeGenerator* owner,
Steve Blocka7e24c12009-10-30 11:49:00 +0000117 JumpTarget* true_target,
118 JumpTarget* false_target);
119
120 // Destroy a code generator state and restore the owning code generator's
121 // previous state.
122 ~CodeGenState();
123
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 JumpTarget* true_target() const { return true_target_; }
125 JumpTarget* false_target() const { return false_target_; }
126
127 private:
128 CodeGenerator* owner_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 JumpTarget* true_target_;
130 JumpTarget* false_target_;
131 CodeGenState* previous_;
132};
133
134
135// -------------------------------------------------------------------------
136// CodeGenerator
137
138class CodeGenerator: public AstVisitor {
139 public:
140 // Takes a function literal, generates code for it. This function should only
141 // be called by compiler.cc.
142 static Handle<Code> MakeCode(FunctionLiteral* fun,
143 Handle<Script> script,
144 bool is_eval);
145
Steve Block3ce2e202009-11-05 08:53:23 +0000146 // Printing of AST, etc. as requested by flags.
147 static void MakeCodePrologue(FunctionLiteral* fun);
148
149 // Allocate and install the code.
150 static Handle<Code> MakeCodeEpilogue(FunctionLiteral* fun,
151 MacroAssembler* masm,
152 Code::Flags flags,
153 Handle<Script> script);
154
Steve Blocka7e24c12009-10-30 11:49:00 +0000155#ifdef ENABLE_LOGGING_AND_PROFILING
156 static bool ShouldGenerateLog(Expression* type);
157#endif
158
159 static void SetFunctionInfo(Handle<JSFunction> fun,
160 FunctionLiteral* lit,
161 bool is_toplevel,
162 Handle<Script> script);
163
Steve Block3ce2e202009-11-05 08:53:23 +0000164 static void RecordPositions(MacroAssembler* masm, int pos);
165
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 // Accessors
167 MacroAssembler* masm() { return masm_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 VirtualFrame* frame() const { return frame_; }
Steve Blockd0582a62009-12-15 09:54:21 +0000169 Handle<Script> script() { return script_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000170
171 bool has_valid_frame() const { return frame_ != NULL; }
172
173 // Set the virtual frame to be new_frame, with non-frame register
174 // reference counts given by non_frame_registers. The non-frame
175 // register reference counts of the old frame are returned in
176 // non_frame_registers.
177 void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers);
178
179 void DeleteFrame();
180
181 RegisterAllocator* allocator() const { return allocator_; }
182
183 CodeGenState* state() { return state_; }
184 void set_state(CodeGenState* state) { state_ = state; }
185
186 void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
187
188 static const int kUnknownIntValue = -1;
189
Steve Blocka7e24c12009-10-30 11:49:00 +0000190 private:
191 // Construction/Destruction
192 CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
193 virtual ~CodeGenerator() { delete masm_; }
194
195 // Accessors
196 Scope* scope() const { return scope_; }
197
198 // Generating deferred code.
199 void ProcessDeferred();
200
201 bool is_eval() { return is_eval_; }
202
203 // State
204 bool has_cc() const { return cc_reg_ != al; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000205 JumpTarget* true_target() const { return state_->true_target(); }
206 JumpTarget* false_target() const { return state_->false_target(); }
207
208 // We don't track loop nesting level on ARM yet.
209 int loop_nesting() const { return 0; }
210
211 // Node visitors.
212 void VisitStatements(ZoneList<Statement*>* statements);
213
214#define DEF_VISIT(type) \
215 void Visit##type(type* node);
216 AST_NODE_LIST(DEF_VISIT)
217#undef DEF_VISIT
218
219 // Visit a statement and then spill the virtual frame if control flow can
220 // reach the end of the statement (ie, it does not exit via break,
221 // continue, return, or throw). This function is used temporarily while
222 // the code generator is being transformed.
223 inline void VisitAndSpill(Statement* statement);
224
225 // Visit a list of statements and then spill the virtual frame if control
226 // flow can reach the end of the list.
227 inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
228
229 // Main code generation function
230 void GenCode(FunctionLiteral* fun);
231
232 // The following are used by class Reference.
233 void LoadReference(Reference* ref);
234 void UnloadReference(Reference* ref);
235
Steve Block3ce2e202009-11-05 08:53:23 +0000236 static MemOperand ContextOperand(Register context, int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 return MemOperand(context, Context::SlotOffset(index));
238 }
239
240 MemOperand SlotOperand(Slot* slot, Register tmp);
241
242 MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
243 Register tmp,
244 Register tmp2,
245 JumpTarget* slow);
246
247 // Expressions
Steve Block3ce2e202009-11-05 08:53:23 +0000248 static MemOperand GlobalObject() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000249 return ContextOperand(cp, Context::GLOBAL_INDEX);
250 }
251
252 void LoadCondition(Expression* x,
Steve Blocka7e24c12009-10-30 11:49:00 +0000253 JumpTarget* true_target,
254 JumpTarget* false_target,
255 bool force_cc);
Steve Blockd0582a62009-12-15 09:54:21 +0000256 void Load(Expression* expr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 void LoadGlobal();
258 void LoadGlobalReceiver(Register scratch);
259
260 // Generate code to push the value of an expression on top of the frame
261 // and then spill the frame fully to memory. This function is used
262 // temporarily while the code generator is being transformed.
Steve Blockd0582a62009-12-15 09:54:21 +0000263 inline void LoadAndSpill(Expression* expression);
Steve Blocka7e24c12009-10-30 11:49:00 +0000264
265 // Call LoadCondition and then spill the virtual frame unless control flow
266 // cannot reach the end of the expression (ie, by emitting only
267 // unconditional jumps to the control targets).
268 inline void LoadConditionAndSpill(Expression* expression,
Steve Blocka7e24c12009-10-30 11:49:00 +0000269 JumpTarget* true_target,
270 JumpTarget* false_target,
271 bool force_control);
272
273 // Read a value from a slot and leave it on top of the expression stack.
274 void LoadFromSlot(Slot* slot, TypeofState typeof_state);
Leon Clarkee46be812010-01-19 14:06:41 +0000275 // Store the value on top of the stack to a slot.
276 void StoreToSlot(Slot* slot, InitState init_state);
277
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 void LoadFromGlobalSlotCheckExtensions(Slot* slot,
279 TypeofState typeof_state,
280 Register tmp,
281 Register tmp2,
282 JumpTarget* slow);
283
284 // Special code for typeof expressions: Unfortunately, we must
285 // be careful when loading the expression in 'typeof'
286 // expressions. We are not allowed to throw reference errors for
287 // non-existing properties of the global object, so we must make it
288 // look like an explicit property access, instead of an access
289 // through the context chain.
290 void LoadTypeofExpression(Expression* x);
291
292 void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
293
294 void GenericBinaryOperation(Token::Value op,
295 OverwriteMode overwrite_mode,
296 int known_rhs = kUnknownIntValue);
297 void Comparison(Condition cc,
298 Expression* left,
299 Expression* right,
300 bool strict = false);
301
302 void SmiOperation(Token::Value op,
303 Handle<Object> value,
304 bool reversed,
305 OverwriteMode mode);
306
Leon Clarkee46be812010-01-19 14:06:41 +0000307 void CallWithArguments(ZoneList<Expression*>* arguments,
308 CallFunctionFlags flags,
309 int position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000310
311 // Control flow
312 void Branch(bool if_true, JumpTarget* target);
313 void CheckStack();
314
315 struct InlineRuntimeLUT {
316 void (CodeGenerator::*method)(ZoneList<Expression*>*);
317 const char* name;
318 };
319
320 static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
321 bool CheckForInlineRuntimeCall(CallRuntime* node);
322 static bool PatchInlineRuntimeEntry(Handle<String> name,
323 const InlineRuntimeLUT& new_entry,
324 InlineRuntimeLUT* old_entry);
325
Steve Block3ce2e202009-11-05 08:53:23 +0000326 static Handle<Code> ComputeLazyCompile(int argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 void ProcessDeclarations(ZoneList<Declaration*>* declarations);
328
Steve Block3ce2e202009-11-05 08:53:23 +0000329 static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
Steve Blocka7e24c12009-10-30 11:49:00 +0000330
331 // Declare global variables and functions in the given array of
332 // name/value pairs.
333 void DeclareGlobals(Handle<FixedArray> pairs);
334
335 // Instantiate the function boilerplate.
336 void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
337
338 // Support for type checks.
339 void GenerateIsSmi(ZoneList<Expression*>* args);
340 void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
341 void GenerateIsArray(ZoneList<Expression*>* args);
Steve Blockd0582a62009-12-15 09:54:21 +0000342 void GenerateIsObject(ZoneList<Expression*>* args);
343 void GenerateIsFunction(ZoneList<Expression*>* args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000344
345 // Support for construct call checks.
346 void GenerateIsConstructCall(ZoneList<Expression*>* args);
347
348 // Support for arguments.length and arguments[?].
349 void GenerateArgumentsLength(ZoneList<Expression*>* args);
350 void GenerateArgumentsAccess(ZoneList<Expression*>* args);
351
352 // Support for accessing the class and value fields of an object.
353 void GenerateClassOf(ZoneList<Expression*>* args);
354 void GenerateValueOf(ZoneList<Expression*>* args);
355 void GenerateSetValueOf(ZoneList<Expression*>* args);
356
357 // Fast support for charCodeAt(n).
358 void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
359
360 // Fast support for object equality testing.
361 void GenerateObjectEquals(ZoneList<Expression*>* args);
362
363 void GenerateLog(ZoneList<Expression*>* args);
364
365 // Fast support for Math.random().
366 void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
367
Steve Blockd0582a62009-12-15 09:54:21 +0000368 // Fast support for StringAdd.
369 void GenerateStringAdd(ZoneList<Expression*>* args);
370
Leon Clarkee46be812010-01-19 14:06:41 +0000371 // Fast support for SubString.
372 void GenerateSubString(ZoneList<Expression*>* args);
373
374 // Fast support for StringCompare.
375 void GenerateStringCompare(ZoneList<Expression*>* args);
376
377 // Support for direct calls from JavaScript to native RegExp code.
378 void GenerateRegExpExec(ZoneList<Expression*>* args);
379
Steve Block3ce2e202009-11-05 08:53:23 +0000380 // Simple condition analysis.
381 enum ConditionAnalysis {
382 ALWAYS_TRUE,
383 ALWAYS_FALSE,
384 DONT_KNOW
385 };
386 ConditionAnalysis AnalyzeCondition(Expression* cond);
387
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 // Methods used to indicate which source code is generated for. Source
389 // positions are collected by the assembler and emitted with the relocation
390 // information.
391 void CodeForFunctionPosition(FunctionLiteral* fun);
392 void CodeForReturnPosition(FunctionLiteral* fun);
393 void CodeForStatementPosition(Statement* node);
Steve Blockd0582a62009-12-15 09:54:21 +0000394 void CodeForDoWhileConditionPosition(DoWhileStatement* stmt);
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 void CodeForSourcePosition(int pos);
396
397#ifdef DEBUG
398 // True if the registers are valid for entry to a block.
399 bool HasValidEntryRegisters();
400#endif
401
402 bool is_eval_; // Tells whether code is generated for eval.
403
404 Handle<Script> script_;
405 List<DeferredCode*> deferred_;
406
407 // Assembler
408 MacroAssembler* masm_; // to generate code
409
410 // Code generation state
411 Scope* scope_;
412 VirtualFrame* frame_;
413 RegisterAllocator* allocator_;
414 Condition cc_reg_;
415 CodeGenState* state_;
416
417 // Jump targets
418 BreakTarget function_return_;
419
420 // True if the function return is shadowed (ie, jumping to the target
421 // function_return_ does not jump to the true function return, but rather
422 // to some unlinking code).
423 bool function_return_is_shadowed_;
424
425 static InlineRuntimeLUT kInlineRuntimeLUT[];
426
427 friend class VirtualFrame;
428 friend class JumpTarget;
429 friend class Reference;
Steve Block3ce2e202009-11-05 08:53:23 +0000430 friend class FastCodeGenerator;
431 friend class CodeGenSelector;
Steve Blocka7e24c12009-10-30 11:49:00 +0000432
433 DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
434};
435
436
Steve Blocka7e24c12009-10-30 11:49:00 +0000437class GenericBinaryOpStub : public CodeStub {
438 public:
439 GenericBinaryOpStub(Token::Value op,
440 OverwriteMode mode,
441 int constant_rhs = CodeGenerator::kUnknownIntValue)
442 : op_(op),
443 mode_(mode),
444 constant_rhs_(constant_rhs),
Leon Clarkee46be812010-01-19 14:06:41 +0000445 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)),
446 name_(NULL) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000447
448 private:
449 Token::Value op_;
450 OverwriteMode mode_;
451 int constant_rhs_;
452 bool specialized_on_rhs_;
Leon Clarkee46be812010-01-19 14:06:41 +0000453 char* name_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000454
455 static const int kMaxKnownRhs = 0x40000000;
456
457 // Minor key encoding in 16 bits.
458 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
459 class OpBits: public BitField<Token::Value, 2, 6> {};
460 class KnownIntBits: public BitField<int, 8, 8> {};
461
462 Major MajorKey() { return GenericBinaryOp; }
463 int MinorKey() {
464 // Encode the parameters in a unique 16 bit value.
465 return OpBits::encode(op_)
466 | ModeBits::encode(mode_)
467 | KnownIntBits::encode(MinorKeyForKnownInt());
468 }
469
470 void Generate(MacroAssembler* masm);
471 void HandleNonSmiBitwiseOp(MacroAssembler* masm);
472
473 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) {
474 if (constant_rhs == CodeGenerator::kUnknownIntValue) return false;
475 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3;
476 if (op == Token::MOD) {
477 if (constant_rhs <= 1) return false;
478 if (constant_rhs <= 10) return true;
479 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true;
480 return false;
481 }
482 return false;
483 }
484
485 int MinorKeyForKnownInt() {
486 if (!specialized_on_rhs_) return 0;
487 if (constant_rhs_ <= 10) return constant_rhs_ + 1;
488 ASSERT(IsPowerOf2(constant_rhs_));
489 int key = 12;
490 int d = constant_rhs_;
491 while ((d & 1) == 0) {
492 key++;
493 d >>= 1;
494 }
495 return key;
496 }
497
Leon Clarkee46be812010-01-19 14:06:41 +0000498 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000499
500#ifdef DEBUG
501 void Print() {
502 if (!specialized_on_rhs_) {
503 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
504 } else {
505 PrintF("GenericBinaryOpStub (%s by %d)\n",
506 Token::String(op_),
507 constant_rhs_);
508 }
509 }
510#endif
511};
512
513
514} } // namespace v8::internal
515
516#endif // V8_ARM_CODEGEN_ARM_H_