blob: c4d3f3867c7d30afb5b83d8353578853e820477a [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. 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#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
32#include "debug.h"
33#include "prettyprinter.h"
34#include "scopeinfo.h"
35#include "scopes.h"
36#include "runtime.h"
37
38namespace v8 { namespace internal {
39
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040DEFINE_bool(trace, false, "trace function calls");
41DECLARE_bool(debug_info);
42DECLARE_bool(debug_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043
mads.s.ager31e71382008-08-13 09:32:07 +000044#ifdef ENABLE_DISASSEMBLER
45DEFINE_bool(print_code, false, "print generated code");
46#endif
47
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#ifdef DEBUG
49DECLARE_bool(gc_greedy);
50DEFINE_bool(trace_codegen, false,
51 "print name of functions for which code is generated");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052DEFINE_bool(print_builtin_code, false, "print generated code for builtins");
53DEFINE_bool(print_source, false, "pretty print source code");
54DEFINE_bool(print_builtin_source, false,
55 "pretty print source code for builtins");
56DEFINE_bool(print_ast, false, "print source AST");
57DEFINE_bool(print_builtin_ast, false, "print source AST for builtins");
58DEFINE_bool(trace_calls, false, "trace calls");
59DEFINE_bool(trace_builtin_calls, false, "trace builtins calls");
60DEFINE_string(stop_at, "", "function name where to insert a breakpoint");
61#endif // DEBUG
62
63
64DEFINE_bool(check_stack, true,
65 "check stack for overflow, interrupt, breakpoint");
66
67
68class ArmCodeGenerator;
69
70
71// -----------------------------------------------------------------------------
72// Reference support
73
74// A reference is a C++ stack-allocated object that keeps an ECMA
75// reference on the execution stack while in scope. For variables
76// the reference is empty, indicating that it isn't necessary to
77// store state on the stack for keeping track of references to those.
78// For properties, we keep either one (named) or two (indexed) values
79// on the execution stack to represent the reference.
80
81class Reference BASE_EMBEDDED {
82 public:
83 enum Type { ILLEGAL = -1, EMPTY = 0, NAMED = 1, KEYED = 2 };
84 Reference(ArmCodeGenerator* cgen, Expression* expression);
85 ~Reference();
86
87 Expression* expression() const { return expression_; }
88 Type type() const { return type_; }
89 void set_type(Type value) {
90 ASSERT(type_ == ILLEGAL);
91 type_ = value;
92 }
93 int size() const { return type_; }
94
95 bool is_illegal() const { return type_ == ILLEGAL; }
96
97 private:
98 ArmCodeGenerator* cgen_;
99 Expression* expression_;
100 Type type_;
101};
102
103
104// -----------------------------------------------------------------------------
105// Code generation state
106
107class CodeGenState BASE_EMBEDDED {
108 public:
109 enum AccessType {
110 UNDEFINED,
111 LOAD,
112 LOAD_TYPEOF_EXPR,
113 STORE,
114 INIT_CONST
115 };
116
117 CodeGenState()
118 : access_(UNDEFINED),
119 ref_(NULL),
120 true_target_(NULL),
121 false_target_(NULL) {
122 }
123
124 CodeGenState(AccessType access,
125 Reference* ref,
126 Label* true_target,
127 Label* false_target)
128 : access_(access),
129 ref_(ref),
130 true_target_(true_target),
131 false_target_(false_target) {
132 }
133
134 AccessType access() const { return access_; }
135 Reference* ref() const { return ref_; }
136 Label* true_target() const { return true_target_; }
137 Label* false_target() const { return false_target_; }
138
139 private:
140 AccessType access_;
141 Reference* ref_;
142 Label* true_target_;
143 Label* false_target_;
144};
145
146
147// -----------------------------------------------------------------------------
148// ArmCodeGenerator
149
150class ArmCodeGenerator: public CodeGenerator {
151 public:
152 static Handle<Code> MakeCode(FunctionLiteral* fun,
153 Handle<Script> script,
154 bool is_eval);
155
156 MacroAssembler* masm() { return masm_; }
157
158 private:
159 // Assembler
160 MacroAssembler* masm_; // to generate code
161
162 // Code generation state
163 Scope* scope_;
164 Condition cc_reg_;
165 CodeGenState* state_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 int break_stack_height_;
167
168 // Labels
169 Label function_return_;
170
171 // Construction/destruction
172 ArmCodeGenerator(int buffer_size,
173 Handle<Script> script,
174 bool is_eval);
175
176 virtual ~ArmCodeGenerator() { delete masm_; }
177
178 // Main code generation function
179 void GenCode(FunctionLiteral* fun);
180
181 // The following are used by class Reference.
182 void LoadReference(Reference* ref);
183 void UnloadReference(Reference* ref);
184 friend class Reference;
185
186 // State
187 bool has_cc() const { return cc_reg_ != al; }
188 CodeGenState::AccessType access() const { return state_->access(); }
189 Reference* ref() const { return state_->ref(); }
190 bool is_referenced() const { return state_->ref() != NULL; }
191 Label* true_target() const { return state_->true_target(); }
192 Label* false_target() const { return state_->false_target(); }
193
194
195 // Expressions
196 MemOperand GlobalObject() const {
197 return ContextOperand(cp, Context::GLOBAL_INDEX);
198 }
199
200 MemOperand ContextOperand(Register context, int index) const {
201 return MemOperand(context, Context::SlotOffset(index));
202 }
203
204 MemOperand ParameterOperand(int index) const {
205 // index -2 corresponds to the activated closure, -1 corresponds
206 // to the receiver
207 ASSERT(-2 <= index && index < scope_->num_parameters());
208 int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize;
209 return MemOperand(pp, offset);
210 }
211
212 MemOperand FunctionOperand() const { return ParameterOperand(-2); }
213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 MemOperand SlotOperand(Slot* slot, Register tmp);
215
216 void LoadCondition(Expression* x, CodeGenState::AccessType access,
217 Label* true_target, Label* false_target, bool force_cc);
218 void Load(Expression* x,
219 CodeGenState::AccessType access = CodeGenState::LOAD);
220 void LoadGlobal();
221
222 // Special code for typeof expressions: Unfortunately, we must
223 // be careful when loading the expression in 'typeof'
224 // expressions. We are not allowed to throw reference errors for
225 // non-existing properties of the global object, so we must make it
226 // look like an explicit property access, instead of an access
227 // through the context chain.
228 void LoadTypeofExpression(Expression* x);
229
230 // References
231 void AccessReference(Reference* ref, CodeGenState::AccessType access);
232
233 void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); }
234 void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); }
235 void InitConst(Reference* ref) {
236 AccessReference(ref, CodeGenState::INIT_CONST);
237 }
238
mads.s.ager31e71382008-08-13 09:32:07 +0000239 void ToBoolean(Label* true_target, Label* false_target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
241
242 // Access property from the reference (must be at the TOS).
243 void AccessReferenceProperty(Expression* key,
244 CodeGenState::AccessType access);
245
kasper.lund7276f142008-07-30 08:49:36 +0000246 void GenericBinaryOperation(Token::Value op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 void Comparison(Condition cc, bool strict = false);
248
249 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
250
251 void CallWithArguments(ZoneList<Expression*>* arguments, int position);
252
253 // Declare global variables and functions in the given array of
254 // name/value pairs.
255 virtual void DeclareGlobals(Handle<FixedArray> pairs);
256
257 // Instantiate the function boilerplate.
258 void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
259
260 // Control flow
261 void Branch(bool if_true, Label* L);
262 void CheckStack();
263 void CleanStack(int num_bytes);
264
265 // Node visitors
266#define DEF_VISIT(type) \
267 virtual void Visit##type(type* node);
268 NODE_LIST(DEF_VISIT)
269#undef DEF_VISIT
270
271 void RecordStatementPosition(Node* node);
272
273 // Activation frames
kasper.lund7276f142008-07-30 08:49:36 +0000274 void EnterJSFrame(int argc); // preserves r1
275 void ExitJSFrame(ExitJSFlag flag = RETURN); // preserves r0-r2
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276
277 virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args);
278 virtual void GenerateSetThisFunction(ZoneList<Expression*>* args);
279 virtual void GenerateGetThisFunction(ZoneList<Expression*>* args);
280 virtual void GenerateSetThis(ZoneList<Expression*>* args);
281 virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args);
282 virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args);
283 virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args);
284 virtual void GenerateSetArgument(ZoneList<Expression*>* args);
285 virtual void GenerateSquashFrame(ZoneList<Expression*>* args);
286 virtual void GenerateExpandFrame(ZoneList<Expression*>* args);
287 virtual void GenerateIsSmi(ZoneList<Expression*>* args);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000288 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289 virtual void GenerateIsArray(ZoneList<Expression*>* args);
290
291 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args);
292 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args);
293
294 virtual void GenerateValueOf(ZoneList<Expression*>* args);
295 virtual void GenerateSetValueOf(ZoneList<Expression*>* args);
kasper.lund7276f142008-07-30 08:49:36 +0000296
297 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298};
299
300
301// -----------------------------------------------------------------------------
302// ArmCodeGenerator implementation
303
304#define __ masm_->
305
306
307Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit,
308 Handle<Script> script,
309 bool is_eval) {
mads.s.ager31e71382008-08-13 09:32:07 +0000310#ifdef ENABLE_DISASSEMBLER
311 bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
312#endif // ENABLE_DISASSEMBLER
313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314#ifdef DEBUG
315 bool print_source = false;
316 bool print_ast = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 const char* ftype;
318
319 if (Bootstrapper::IsActive()) {
320 print_source = FLAG_print_builtin_source;
321 print_ast = FLAG_print_builtin_ast;
322 print_code = FLAG_print_builtin_code;
323 ftype = "builtin";
324 } else {
325 print_source = FLAG_print_source;
326 print_ast = FLAG_print_ast;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 ftype = "user-defined";
328 }
329
330 if (FLAG_trace_codegen || print_source || print_ast) {
331 PrintF("*** Generate code for %s function: ", ftype);
332 flit->name()->ShortPrint();
333 PrintF(" ***\n");
334 }
335
336 if (print_source) {
337 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
338 }
339
340 if (print_ast) {
341 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
342 }
343#endif // DEBUG
344
345 // Generate code.
346 const int initial_buffer_size = 4 * KB;
347 ArmCodeGenerator cgen(initial_buffer_size, script, is_eval);
348 cgen.GenCode(flit);
349 if (cgen.HasStackOverflow()) {
kasper.lund212ac232008-07-16 07:07:30 +0000350 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 return Handle<Code>::null();
352 }
353
354 // Process any deferred code.
355 cgen.ProcessDeferred();
356
357 // Allocate and install the code.
358 CodeDesc desc;
359 cgen.masm()->GetCode(&desc);
360 ScopeInfo<> sinfo(flit->scope());
361 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
362 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
363
364 // Add unresolved entries in the code to the fixup list.
365 Bootstrapper::AddFixup(*code, cgen.masm());
366
mads.s.ager31e71382008-08-13 09:32:07 +0000367#ifdef ENABLE_DISASSEMBLER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 if (print_code) {
369 // Print the source code if available.
370 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
371 PrintF("--- Raw source ---\n");
372 StringInputBuffer stream(String::cast(script->source()));
373 stream.Seek(flit->start_position());
374 // flit->end_position() points to the last character in the stream. We
375 // need to compensate by adding one to calculate the length.
376 int source_len = flit->end_position() - flit->start_position() + 1;
377 for (int i = 0; i < source_len; i++) {
378 if (stream.has_more()) PrintF("%c", stream.GetNext());
379 }
380 PrintF("\n\n");
381 }
382 PrintF("--- Code ---\n");
mads.s.ager31e71382008-08-13 09:32:07 +0000383 code->Disassemble();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
mads.s.ager31e71382008-08-13 09:32:07 +0000385#endif // ENABLE_DISASSEMBLER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386
387 return code;
388}
389
390
391ArmCodeGenerator::ArmCodeGenerator(int buffer_size,
392 Handle<Script> script,
393 bool is_eval)
394 : CodeGenerator(is_eval, script),
395 masm_(new MacroAssembler(NULL, buffer_size)),
396 scope_(NULL),
397 cc_reg_(al),
398 state_(NULL),
399 break_stack_height_(0) {
400}
401
402
403// Calling conventions:
404
mads.s.ager31e71382008-08-13 09:32:07 +0000405// r0: the number of arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406// fp: frame pointer
407// sp: stack pointer
408// pp: caller's parameter pointer
409// cp: callee's context
410
411void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
412 Scope* scope = fun->scope();
413 ZoneList<Statement*>* body = fun->body();
414
415 // Initialize state.
416 { CodeGenState state;
417 state_ = &state;
418 scope_ = scope;
419 cc_reg_ = al;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420
421 // Entry
422 // stack: function, receiver, arguments, return address
423 // r0: number of arguments
424 // sp: stack pointer
425 // fp: frame pointer
426 // pp: caller's parameter pointer
427 // cp: callee's context
428
429 { Comment cmnt(masm_, "[ enter JS frame");
kasper.lund7276f142008-07-30 08:49:36 +0000430 EnterJSFrame(scope->num_parameters());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432 // tos: code slot
433#ifdef DEBUG
434 if (strlen(FLAG_stop_at) > 0 &&
435 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
kasper.lund7276f142008-07-30 08:49:36 +0000436 __ stop("stop-at");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 }
438#endif
439
440 // Allocate space for locals and initialize them.
kasper.lund7276f142008-07-30 08:49:36 +0000441 if (scope->num_stack_slots() > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 Comment cmnt(masm_, "[ allocate space for locals");
mads.s.ager31e71382008-08-13 09:32:07 +0000443 // Initialize stack slots with 'undefined' value.
444 __ mov(ip, Operand(Factory::undefined_value()));
445 for (int i = 0; i < scope->num_stack_slots(); i++) {
446 __ push(ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447 }
448 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449
450 if (scope->num_heap_slots() > 0) {
451 // Allocate local context.
452 // Get outer context and create a new context based on it.
mads.s.ager31e71382008-08-13 09:32:07 +0000453 __ ldr(r0, FunctionOperand());
454 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +0000455 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
456
457 if (kDebug) {
458 Label verified_true;
459 __ cmp(r0, Operand(cp));
460 __ b(eq, &verified_true);
461 __ stop("NewContext: r0 is expected to be the same as cp");
462 __ bind(&verified_true);
463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464 // Update context local.
465 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
466 }
467
468 // TODO(1241774): Improve this code!!!
469 // 1) only needed if we have a context
470 // 2) no need to recompute context ptr every single time
471 // 3) don't copy parameter operand code from SlotOperand!
472 {
473 Comment cmnt2(masm_, "[ copy context parameters into .context");
474
475 // Note that iteration order is relevant here! If we have the same
476 // parameter twice (e.g., function (x, y, x)), and that parameter
477 // needs to be copied into the context, it must be the last argument
478 // passed to the parameter that needs to be copied. This is a rare
479 // case so we don't check for it, instead we rely on the copying
480 // order: such a parameter is copied repeatedly into the same
481 // context location and thus the last value is what is seen inside
482 // the function.
483 for (int i = 0; i < scope->num_parameters(); i++) {
484 Variable* par = scope->parameter(i);
485 Slot* slot = par->slot();
486 if (slot != NULL && slot->type() == Slot::CONTEXT) {
487 ASSERT(!scope->is_global_scope()); // no parameters in global scope
488 int parameter_offset =
489 JavaScriptFrameConstants::kParam0Offset - i * kPointerSize;
490 __ ldr(r1, MemOperand(pp, parameter_offset));
491 // Loads r2 with context; used below in RecordWrite.
492 __ str(r1, SlotOperand(slot, r2));
493 // Load the offset into r3.
494 int slot_offset =
495 FixedArray::kHeaderSize + slot->index() * kPointerSize;
496 __ mov(r3, Operand(slot_offset));
497 __ RecordWrite(r2, r3, r1);
498 }
499 }
500 }
501
502 // Store the arguments object.
503 // This must happen after context initialization because
504 // the arguments array may be stored in the context!
505 if (scope->arguments() != NULL) {
506 ASSERT(scope->arguments_shadow() != NULL);
507 Comment cmnt(masm_, "[ allocate arguments object");
508 {
509 Reference target(this, scope->arguments());
mads.s.ager31e71382008-08-13 09:32:07 +0000510 __ ldr(r0, FunctionOperand());
511 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 __ CallRuntime(Runtime::kNewArguments, 1);
mads.s.ager31e71382008-08-13 09:32:07 +0000513 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514 SetValue(&target);
515 }
516 // The value of arguments must also be stored in .arguments.
517 // TODO(1241813): This code can probably be improved by fusing it with
518 // the code that stores the arguments object above.
519 {
520 Reference target(this, scope->arguments_shadow());
521 Load(scope->arguments());
522 SetValue(&target);
523 }
524 }
525
526 // Generate code to 'execute' declarations and initialize
527 // functions (source elements). In case of an illegal
528 // redeclaration we need to handle that instead of processing the
529 // declarations.
530 if (scope->HasIllegalRedeclaration()) {
531 Comment cmnt(masm_, "[ illegal redeclarations");
532 scope->VisitIllegalRedeclaration(this);
533 } else {
534 Comment cmnt(masm_, "[ declarations");
mads.s.ager31e71382008-08-13 09:32:07 +0000535 // ProcessDeclarations calls DeclareGlobals indirectly
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 ProcessDeclarations(scope->declarations());
mads.s.ager31e71382008-08-13 09:32:07 +0000537
v8.team.kasperl727e9952008-09-02 14:56:44 +0000538 // Bail out if a stack-overflow exception occurred when
kasper.lund212ac232008-07-16 07:07:30 +0000539 // processing declarations.
540 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 }
542
mads.s.ager31e71382008-08-13 09:32:07 +0000543 if (FLAG_trace) {
544 // Push a valid value as the parameter. The runtime call only uses
545 // it as the return value to indicate non-failure.
546 __ mov(r0, Operand(Smi::FromInt(0)));
547 __ push(r0);
548 __ CallRuntime(Runtime::kTraceEnter, 1);
549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 CheckStack();
551
552 // Compile the body of the function in a vanilla state. Don't
553 // bother compiling all the code if the scope has an illegal
554 // redeclaration.
555 if (!scope->HasIllegalRedeclaration()) {
556 Comment cmnt(masm_, "[ function body");
557#ifdef DEBUG
558 bool is_builtin = Bootstrapper::IsActive();
559 bool should_trace =
560 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
mads.s.ager31e71382008-08-13 09:32:07 +0000561 if (should_trace) {
562 // Push a valid value as the parameter. The runtime call only uses
563 // it as the return value to indicate non-failure.
564 __ mov(r0, Operand(Smi::FromInt(0)));
565 __ push(r0);
566 __ CallRuntime(Runtime::kDebugTrace, 1);
567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568#endif
569 VisitStatements(body);
570 }
571
572 state_ = NULL;
573 }
574
575 // exit
576 // r0: result
577 // sp: stack pointer
578 // fp: frame pointer
579 // pp: parameter pointer
580 // cp: callee's context
mads.s.ager31e71382008-08-13 09:32:07 +0000581 __ mov(r0, Operand(Factory::undefined_value()));
582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 __ bind(&function_return_);
mads.s.ager31e71382008-08-13 09:32:07 +0000584 if (FLAG_trace) {
585 // Push the return value on the stack as the parameter.
586 // Runtime::TraceExit returns the parameter as it is.
587 __ push(r0);
588 __ CallRuntime(Runtime::kTraceExit, 1);
589 }
590
kasper.lund7276f142008-07-30 08:49:36 +0000591 ExitJSFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592
593 // Code generation state must be reset.
594 scope_ = NULL;
595 ASSERT(!has_cc());
596 ASSERT(state_ == NULL);
597}
598
599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
601 // Currently, this assertion will fail if we try to assign to
602 // a constant variable that is constant because it is read-only
603 // (such as the variable referring to a named function expression).
604 // We need to implement assignments to read-only variables.
605 // Ideally, we should do this during AST generation (by converting
606 // such assignments into expression statements); however, in general
607 // we may not be able to make the decision until past AST generation,
608 // that is when the entire program is known.
609 ASSERT(slot != NULL);
610 int index = slot->index();
611 switch (slot->type()) {
612 case Slot::PARAMETER:
613 return ParameterOperand(index);
614
615 case Slot::LOCAL: {
616 ASSERT(0 <= index &&
617 index < scope_->num_stack_slots() &&
kasper.lund7276f142008-07-30 08:49:36 +0000618 index >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 int local_offset = JavaScriptFrameConstants::kLocal0Offset -
kasper.lund7276f142008-07-30 08:49:36 +0000620 index * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 return MemOperand(fp, local_offset);
622 }
623
624 case Slot::CONTEXT: {
625 // Follow the context chain if necessary.
626 ASSERT(!tmp.is(cp)); // do not overwrite context register
627 Register context = cp;
628 int chain_length = scope_->ContextChainLength(slot->var()->scope());
629 for (int i = chain_length; i-- > 0;) {
630 // Load the closure.
631 // (All contexts, even 'with' contexts, have a closure,
632 // and it is the same for all contexts inside a function.
633 // There is no need to go to the function context first.)
634 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
635 // Load the function context (which is the incoming, outer context).
636 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
637 context = tmp;
638 }
639 // We may have a 'with' context now. Get the function context.
640 // (In fact this mov may never be the needed, since the scope analysis
641 // may not permit a direct context access in this case and thus we are
642 // always at a function context. However it is safe to dereference be-
643 // cause the function context of a function context is itself. Before
644 // deleting this mov we should try to create a counter-example first,
645 // though...)
646 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
647 return ContextOperand(tmp, index);
648 }
649
650 default:
651 UNREACHABLE();
652 return MemOperand(r0, 0);
653 }
654}
655
656
mads.s.ager31e71382008-08-13 09:32:07 +0000657// Loads a value on the stack. If it is a boolean value, the result may have
658// been (partially) translated into branches, or it may have set the condition
659// code register. If force_cc is set, the value is forced to set the condition
660// code register and no value is pushed. If the condition code register was set,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
662void ArmCodeGenerator::LoadCondition(Expression* x,
663 CodeGenState::AccessType access,
664 Label* true_target,
665 Label* false_target,
666 bool force_cc) {
667 ASSERT(access == CodeGenState::LOAD ||
668 access == CodeGenState::LOAD_TYPEOF_EXPR);
669 ASSERT(!has_cc() && !is_referenced());
670
671 CodeGenState* old_state = state_;
672 CodeGenState new_state(access, NULL, true_target, false_target);
673 state_ = &new_state;
674 Visit(x);
675 state_ = old_state;
676 if (force_cc && !has_cc()) {
mads.s.ager31e71382008-08-13 09:32:07 +0000677 // Convert the TOS value to a boolean in the condition code register.
678 ToBoolean(true_target, false_target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 }
680 ASSERT(has_cc() || !force_cc);
681}
682
683
684void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
685 ASSERT(access == CodeGenState::LOAD ||
686 access == CodeGenState::LOAD_TYPEOF_EXPR);
687
688 Label true_target;
689 Label false_target;
690 LoadCondition(x, access, &true_target, &false_target, false);
691
692 if (has_cc()) {
693 // convert cc_reg_ into a bool
694 Label loaded, materialize_true;
695 __ b(cc_reg_, &materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000696 __ mov(r0, Operand(Factory::false_value()));
697 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 __ b(&loaded);
699 __ bind(&materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000700 __ mov(r0, Operand(Factory::true_value()));
701 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 __ bind(&loaded);
703 cc_reg_ = al;
704 }
705
706 if (true_target.is_linked() || false_target.is_linked()) {
707 // we have at least one condition value
708 // that has been "translated" into a branch,
709 // thus it needs to be loaded explicitly again
710 Label loaded;
711 __ b(&loaded); // don't lose current TOS
712 bool both = true_target.is_linked() && false_target.is_linked();
713 // reincarnate "true", if necessary
714 if (true_target.is_linked()) {
715 __ bind(&true_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000716 __ mov(r0, Operand(Factory::true_value()));
717 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718 }
719 // if both "true" and "false" need to be reincarnated,
720 // jump across code for "false"
721 if (both)
722 __ b(&loaded);
723 // reincarnate "false", if necessary
724 if (false_target.is_linked()) {
725 __ bind(&false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000726 __ mov(r0, Operand(Factory::false_value()));
727 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728 }
729 // everything is loaded at this point
730 __ bind(&loaded);
731 }
732 ASSERT(!has_cc());
733}
734
735
736void ArmCodeGenerator::LoadGlobal() {
mads.s.ager31e71382008-08-13 09:32:07 +0000737 __ ldr(r0, GlobalObject());
738 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739}
740
741
742// TODO(1241834): Get rid of this function in favor of just using Load, now
743// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle
744// global variables w/o reference errors elsewhere.
745void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
746 Variable* variable = x->AsVariableProxy()->AsVariable();
747 if (variable != NULL && !variable->is_this() && variable->is_global()) {
748 // NOTE: This is somewhat nasty. We force the compiler to load
749 // the variable as if through '<global>.<variable>' to make sure we
750 // do not get reference errors.
751 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
752 Literal key(variable->name());
753 // TODO(1241834): Fetch the position from the variable instead of using
754 // no position.
755 Property property(&global, &key, kNoPosition);
756 Load(&property);
757 } else {
758 Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
759 }
760}
761
762
763Reference::Reference(ArmCodeGenerator* cgen, Expression* expression)
764 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
765 cgen->LoadReference(this);
766}
767
768
769Reference::~Reference() {
770 cgen_->UnloadReference(this);
771}
772
773
774void ArmCodeGenerator::LoadReference(Reference* ref) {
775 Expression* e = ref->expression();
776 Property* property = e->AsProperty();
777 Variable* var = e->AsVariableProxy()->AsVariable();
778
779 if (property != NULL) {
780 Load(property->obj());
781 // Used a named reference if the key is a literal symbol.
782 // We don't use a named reference if they key is a string that can be
783 // legally parsed as an integer. This is because, otherwise we don't
784 // get into the slow case code that handles [] on String objects.
785 Literal* literal = property->key()->AsLiteral();
786 uint32_t dummy;
787 if (literal != NULL && literal->handle()->IsSymbol() &&
788 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
789 ref->set_type(Reference::NAMED);
790 } else {
791 Load(property->key());
792 ref->set_type(Reference::KEYED);
793 }
794 } else if (var != NULL) {
795 if (var->is_global()) {
796 // global variable
797 LoadGlobal();
798 ref->set_type(Reference::NAMED);
799 } else {
800 // local variable
801 ref->set_type(Reference::EMPTY);
802 }
803 } else {
804 Load(e);
805 __ CallRuntime(Runtime::kThrowReferenceError, 1);
mads.s.ager31e71382008-08-13 09:32:07 +0000806 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 }
808}
809
810
811void ArmCodeGenerator::UnloadReference(Reference* ref) {
812 int size = ref->size();
813 if (size <= 0) {
814 // Do nothing. No popping is necessary.
815 } else {
mads.s.ager31e71382008-08-13 09:32:07 +0000816 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 __ add(sp, sp, Operand(size * kPointerSize));
mads.s.ager31e71382008-08-13 09:32:07 +0000818 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 }
820}
821
822
823void ArmCodeGenerator::AccessReference(Reference* ref,
824 CodeGenState::AccessType access) {
825 ASSERT(!has_cc());
826 ASSERT(ref->type() != Reference::ILLEGAL);
827 CodeGenState* old_state = state_;
828 CodeGenState new_state(access, ref, true_target(), false_target());
829 state_ = &new_state;
830 Visit(ref->expression());
831 state_ = old_state;
832}
833
834
835// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
836// register to a boolean in the condition code register. The code
837// may jump to 'false_target' in case the register converts to 'false'.
mads.s.ager31e71382008-08-13 09:32:07 +0000838void ArmCodeGenerator::ToBoolean(Label* true_target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 Label* false_target) {
mads.s.ager31e71382008-08-13 09:32:07 +0000840 // Note: The generated code snippet does not change stack variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 // Only the condition code should be set.
mads.s.ager31e71382008-08-13 09:32:07 +0000842 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843
844 // Fast case checks
845
mads.s.ager31e71382008-08-13 09:32:07 +0000846 // Check if the value is 'false'.
847 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848 __ b(eq, false_target);
849
mads.s.ager31e71382008-08-13 09:32:07 +0000850 // Check if the value is 'true'.
851 __ cmp(r0, Operand(Factory::true_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 __ b(eq, true_target);
853
mads.s.ager31e71382008-08-13 09:32:07 +0000854 // Check if the value is 'undefined'.
855 __ cmp(r0, Operand(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 __ b(eq, false_target);
857
mads.s.ager31e71382008-08-13 09:32:07 +0000858 // Check if the value is a smi.
859 __ cmp(r0, Operand(Smi::FromInt(0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 __ b(eq, false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000861 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 __ b(eq, true_target);
863
864 // Slow case: call the runtime.
865 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +0000866 __ CallRuntime(Runtime::kToBool, 1);
867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 // Convert result (r0) to condition code
869 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870
871 cc_reg_ = ne;
872}
873
874
875#undef __
876#define __ masm->
877
878
879class GetPropertyStub : public CodeStub {
880 public:
881 GetPropertyStub() { }
882
883 private:
884 Major MajorKey() { return GetProperty; }
885 int MinorKey() { return 0; }
886 void Generate(MacroAssembler* masm);
887
888 const char* GetName() { return "GetPropertyStub"; }
889};
890
891
892void GetPropertyStub::Generate(MacroAssembler* masm) {
mads.s.ager31e71382008-08-13 09:32:07 +0000893 // sp[0]: key
894 // sp[1]: receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 Label slow, fast;
mads.s.ager31e71382008-08-13 09:32:07 +0000896 // Get the key and receiver object from the stack.
897 __ ldm(ia, sp, r0.bit() | r1.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 // Check that the key is a smi.
899 __ tst(r0, Operand(kSmiTagMask));
900 __ b(ne, &slow);
901 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
902 // Check that the object isn't a smi.
903 __ tst(r1, Operand(kSmiTagMask));
904 __ b(eq, &slow);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000905
906 // Check that the object is some kind of JS object EXCEPT JS Value type.
907 // In the case that the object is a value-wrapper object,
908 // we enter the runtime system to make sure that indexing into string
909 // objects work as intended.
910 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
912 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
913 __ cmp(r2, Operand(JS_OBJECT_TYPE));
914 __ b(lt, &slow);
915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 // Get the elements array of the object.
917 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
918 // Check that the object is in fast mode (not dictionary).
919 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
920 __ cmp(r3, Operand(Factory::hash_table_map()));
921 __ b(eq, &slow);
922 // Check that the key (index) is within bounds.
923 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
924 __ cmp(r0, Operand(r3));
925 __ b(lo, &fast);
926
927 // Slow case: Push extra copies of the arguments (2).
928 __ bind(&slow);
929 __ ldm(ia, sp, r0.bit() | r1.bit());
930 __ stm(db_w, sp, r0.bit() | r1.bit());
931 // Do tail-call to runtime routine.
mads.s.ager31e71382008-08-13 09:32:07 +0000932 __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933
934 // Fast case: Do the load.
935 __ bind(&fast);
936 __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
937 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
938 __ cmp(r0, Operand(Factory::the_hole_value()));
939 // In case the loaded value is the_hole we have to consult GetProperty
940 // to ensure the prototype chain is searched.
941 __ b(eq, &slow);
942
943 masm->StubReturn(1);
944}
945
946
947class SetPropertyStub : public CodeStub {
948 public:
949 SetPropertyStub() { }
950
951 private:
952 Major MajorKey() { return SetProperty; }
953 int MinorKey() { return 0; }
954 void Generate(MacroAssembler* masm);
955
956 const char* GetName() { return "GetPropertyStub"; }
957};
958
959
mads.s.ager31e71382008-08-13 09:32:07 +0000960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961void SetPropertyStub::Generate(MacroAssembler* masm) {
mads.s.ager31e71382008-08-13 09:32:07 +0000962 // r0 : value
963 // sp[0] : key
964 // sp[1] : receiver
965
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 Label slow, fast, array, extra, exit;
967 // Get the key and the object from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +0000968 __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 // Check that the key is a smi.
970 __ tst(r1, Operand(kSmiTagMask));
971 __ b(ne, &slow);
972 // Check that the object isn't a smi.
973 __ tst(r3, Operand(kSmiTagMask));
974 __ b(eq, &slow);
975 // Get the type of the object from its map.
976 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
977 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
978 // Check if the object is a JS array or not.
979 __ cmp(r2, Operand(JS_ARRAY_TYPE));
980 __ b(eq, &array);
981 // Check that the object is some kind of JS object.
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000982 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 __ b(lt, &slow);
984
985
986 // Object case: Check key against length in the elements array.
987 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
988 // Check that the object is in fast mode (not dictionary).
989 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
990 __ cmp(r2, Operand(Factory::hash_table_map()));
991 __ b(eq, &slow);
992 // Untag the key (for checking against untagged length in the fixed array).
993 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
994 // Compute address to store into and check array bounds.
995 __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
996 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
997 __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
998 __ cmp(r1, Operand(ip));
999 __ b(lo, &fast);
1000
1001
1002 // Slow case: Push extra copies of the arguments (3).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 __ bind(&slow);
1004 __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
1005 __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
1006 // Do tail-call to runtime routine.
mads.s.ager31e71382008-08-13 09:32:07 +00001007 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008
1009
1010 // Extra capacity case: Check if there is extra capacity to
1011 // perform the store and update the length. Used for adding one
1012 // element to the array by writing to array[array.length].
1013 // r0 == value, r1 == key, r2 == elements, r3 == object
1014 __ bind(&extra);
1015 __ b(ne, &slow); // do not leave holes in the array
1016 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag
1017 __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
1018 __ cmp(r1, Operand(ip));
1019 __ b(hs, &slow);
1020 __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag
1021 __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment
1022 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
1023 __ mov(r3, Operand(r2));
1024 // NOTE: Computing the address to store into must take the fact
1025 // that the key has been incremented into account.
1026 int displacement = Array::kHeaderSize - kHeapObjectTag -
1027 ((1 << kSmiTagSize) * 2);
1028 __ add(r2, r2, Operand(displacement));
1029 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
1030 __ b(&fast);
1031
1032
1033 // Array case: Get the length and the elements array from the JS
1034 // array. Check that the array is in fast mode; if it is the
1035 // length is always a smi.
1036 // r0 == value, r3 == object
1037 __ bind(&array);
1038 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
1039 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
1040 __ cmp(r1, Operand(Factory::hash_table_map()));
1041 __ b(eq, &slow);
1042
1043 // Check the key against the length in the array, compute the
1044 // address to store into and fall through to fast case.
1045 __ ldr(r1, MemOperand(sp));
1046 // r0 == value, r1 == key, r2 == elements, r3 == object.
1047 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
1048 __ cmp(r1, Operand(ip));
1049 __ b(hs, &extra);
1050 __ mov(r3, Operand(r2));
1051 __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
1052 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
1053
1054
1055 // Fast case: Do the store.
1056 // r0 == value, r2 == address to store into, r3 == elements
1057 __ bind(&fast);
1058 __ str(r0, MemOperand(r2));
1059 // Skip write barrier if the written value is a smi.
1060 __ tst(r0, Operand(kSmiTagMask));
1061 __ b(eq, &exit);
1062 // Update write barrier for the elements array address.
1063 __ sub(r1, r2, Operand(r3));
1064 __ RecordWrite(r3, r1, r2);
1065 __ bind(&exit);
1066 masm->StubReturn(1);
1067}
1068
1069
kasper.lund7276f142008-07-30 08:49:36 +00001070class GenericBinaryOpStub : public CodeStub {
1071 public:
1072 explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
1073
1074 private:
1075 Token::Value op_;
1076
1077 Major MajorKey() { return GenericBinaryOp; }
1078 int MinorKey() { return static_cast<int>(op_); }
1079 void Generate(MacroAssembler* masm);
1080
1081 const char* GetName() {
1082 switch (op_) {
1083 case Token::ADD: return "GenericBinaryOpStub_ADD";
1084 case Token::SUB: return "GenericBinaryOpStub_SUB";
1085 case Token::MUL: return "GenericBinaryOpStub_MUL";
1086 case Token::DIV: return "GenericBinaryOpStub_DIV";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001087 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
1088 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
1089 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
1090 case Token::SAR: return "GenericBinaryOpStub_SAR";
1091 case Token::SHL: return "GenericBinaryOpStub_SHL";
1092 case Token::SHR: return "GenericBinaryOpStub_SHR";
kasper.lund7276f142008-07-30 08:49:36 +00001093 default: return "GenericBinaryOpStub";
1094 }
1095 }
1096
1097#ifdef DEBUG
1098 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
1099#endif
1100};
1101
1102
1103void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001104 // r1 : x
1105 // r0 : y
1106 // result : r0
1107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108 switch (op_) {
1109 case Token::ADD: {
1110 Label slow, exit;
1111 // fast path
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1113 __ add(r0, r1, Operand(r0), SetCC); // add y optimistically
1114 // go slow-path in case of overflow
1115 __ b(vs, &slow);
1116 // go slow-path in case of non-smi operands
1117 ASSERT(kSmiTag == 0); // adjust code below
1118 __ tst(r2, Operand(kSmiTagMask));
1119 __ b(eq, &exit);
1120 // slow path
1121 __ bind(&slow);
1122 __ sub(r0, r0, Operand(r1)); // revert optimistic add
mads.s.ager31e71382008-08-13 09:32:07 +00001123 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124 __ push(r0);
1125 __ mov(r0, Operand(1)); // set number of arguments
1126 __ InvokeBuiltin("ADD", 1, JUMP_JS);
1127 // done
1128 __ bind(&exit);
1129 break;
1130 }
1131
1132 case Token::SUB: {
1133 Label slow, exit;
1134 // fast path
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1136 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
1137 // go slow-path in case of overflow
1138 __ b(vs, &slow);
1139 // go slow-path in case of non-smi operands
1140 ASSERT(kSmiTag == 0); // adjust code below
1141 __ tst(r2, Operand(kSmiTagMask));
1142 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result
1143 __ b(eq, &exit);
1144 // slow path
1145 __ bind(&slow);
mads.s.ager31e71382008-08-13 09:32:07 +00001146 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 __ push(r0);
1148 __ mov(r0, Operand(1)); // set number of arguments
1149 __ InvokeBuiltin("SUB", 1, JUMP_JS);
1150 // done
1151 __ bind(&exit);
1152 break;
1153 }
1154
1155 case Token::MUL: {
1156 Label slow, exit;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 // tag check
1158 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1159 ASSERT(kSmiTag == 0); // adjust code below
1160 __ tst(r2, Operand(kSmiTagMask));
1161 __ b(ne, &slow);
1162 // remove tag from one operand (but keep sign), so that result is smi
1163 __ mov(ip, Operand(r0, ASR, kSmiTagSize));
1164 // do multiplication
1165 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1
1166 // go slow on overflows (overflow bit is not set)
1167 __ mov(ip, Operand(r3, ASR, 31));
1168 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical
1169 __ b(ne, &slow);
1170 // go slow on zero result to handle -0
1171 __ tst(r3, Operand(r3));
1172 __ mov(r0, Operand(r3), LeaveCC, ne);
1173 __ b(ne, &exit);
1174 // slow case
1175 __ bind(&slow);
mads.s.ager31e71382008-08-13 09:32:07 +00001176 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 __ push(r0);
1178 __ mov(r0, Operand(1)); // set number of arguments
1179 __ InvokeBuiltin("MUL", 1, JUMP_JS);
1180 // done
1181 __ bind(&exit);
1182 break;
1183 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001184
1185 case Token::BIT_OR:
1186 case Token::BIT_AND:
1187 case Token::BIT_XOR: {
1188 Label slow, exit;
1189 // tag check
1190 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1191 ASSERT(kSmiTag == 0); // adjust code below
1192 __ tst(r2, Operand(kSmiTagMask));
1193 __ b(ne, &slow);
1194 switch (op_) {
1195 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
1196 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
1197 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
1198 default: UNREACHABLE();
1199 }
1200 __ b(&exit);
1201 __ bind(&slow);
1202 __ push(r1); // restore stack
1203 __ push(r0);
1204 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
1205 switch (op_) {
1206 case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, JUMP_JS); break;
1207 case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, JUMP_JS); break;
1208 case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, JUMP_JS); break;
1209 default: UNREACHABLE();
1210 }
1211 __ bind(&exit);
1212 break;
1213 }
1214
1215 case Token::SHL:
1216 case Token::SHR:
1217 case Token::SAR: {
1218 Label slow, exit;
1219 // tag check
1220 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1221 ASSERT(kSmiTag == 0); // adjust code below
1222 __ tst(r2, Operand(kSmiTagMask));
1223 __ b(ne, &slow);
1224 // remove tags from operands (but keep sign)
1225 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
1226 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
1227 // use only the 5 least significant bits of the shift count
1228 __ and_(r2, r2, Operand(0x1f));
1229 // perform operation
1230 switch (op_) {
1231 case Token::SAR:
1232 __ mov(r3, Operand(r3, ASR, r2));
1233 // no checks of result necessary
1234 break;
1235
1236 case Token::SHR:
1237 __ mov(r3, Operand(r3, LSR, r2));
1238 // check that the *unsigned* result fits in a smi
1239 // neither of the two high-order bits can be set:
1240 // - 0x80000000: high bit would be lost when smi tagging
1241 // - 0x40000000: this number would convert to negative when
1242 // smi tagging these two cases can only happen with shifts
1243 // by 0 or 1 when handed a valid smi
1244 __ and_(r2, r3, Operand(0xc0000000), SetCC);
1245 __ b(ne, &slow);
1246 break;
1247
1248 case Token::SHL:
1249 __ mov(r3, Operand(r3, LSL, r2));
1250 // check that the *signed* result fits in a smi
1251 __ add(r2, r3, Operand(0x40000000), SetCC);
1252 __ b(mi, &slow);
1253 break;
1254
1255 default: UNREACHABLE();
1256 }
1257 // tag result and store it in r0
1258 ASSERT(kSmiTag == 0); // adjust code below
1259 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
1260 __ b(&exit);
1261 // slow case
1262 __ bind(&slow);
1263 __ push(r1); // restore stack
1264 __ push(r0);
1265 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
1266 switch (op_) {
1267 case Token::SAR: __ InvokeBuiltin("SAR", 1, JUMP_JS); break;
1268 case Token::SHR: __ InvokeBuiltin("SHR", 1, JUMP_JS); break;
1269 case Token::SHL: __ InvokeBuiltin("SHL", 1, JUMP_JS); break;
1270 default: UNREACHABLE();
1271 }
1272 __ bind(&exit);
1273 break;
1274 }
1275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 default: UNREACHABLE();
1277 }
mads.s.ager31e71382008-08-13 09:32:07 +00001278 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279}
1280
1281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282void StackCheckStub::Generate(MacroAssembler* masm) {
1283 Label within_limit;
1284 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
1285 __ ldr(ip, MemOperand(ip));
1286 __ cmp(sp, Operand(ip));
1287 __ b(hs, &within_limit);
1288 // Do tail-call to runtime routine.
1289 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001290 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 __ bind(&within_limit);
1292
1293 masm->StubReturn(1);
1294}
1295
1296
1297void UnarySubStub::Generate(MacroAssembler* masm) {
1298 Label undo;
1299 Label slow;
1300 Label done;
1301
1302 // Enter runtime system if the value is not a smi.
1303 __ tst(r0, Operand(kSmiTagMask));
1304 __ b(ne, &slow);
1305
1306 // Enter runtime system if the value of the expression is zero
1307 // to make sure that we switch between 0 and -0.
1308 __ cmp(r0, Operand(0));
1309 __ b(eq, &slow);
1310
1311 // The value of the expression is a smi that is not zero. Try
1312 // optimistic subtraction '0 - value'.
1313 __ rsb(r1, r0, Operand(0), SetCC);
1314 __ b(vs, &slow);
1315
1316 // If result is a smi we are done.
1317 __ tst(r1, Operand(kSmiTagMask));
1318 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result
1319 __ b(eq, &done);
1320
1321 // Enter runtime system.
1322 __ bind(&slow);
1323 __ push(r0);
1324 __ mov(r0, Operand(0)); // set number of arguments
1325 __ InvokeBuiltin("UNARY_MINUS", 0, JUMP_JS);
1326
1327 __ bind(&done);
1328 masm->StubReturn(1);
1329}
1330
1331
1332class InvokeBuiltinStub : public CodeStub {
1333 public:
1334 enum Kind { Inc, Dec, ToNumber };
1335 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
1336
1337 private:
1338 Kind kind_;
1339 int argc_;
1340
1341 Major MajorKey() { return InvokeBuiltin; }
1342 int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
1343 void Generate(MacroAssembler* masm);
1344
1345 const char* GetName() { return "InvokeBuiltinStub"; }
1346
1347#ifdef DEBUG
1348 void Print() {
1349 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
1350 static_cast<int>(kind_),
1351 argc_);
1352 }
1353#endif
1354};
1355
1356
1357void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
1358 __ push(r0);
1359 __ mov(r0, Operand(0)); // set number of arguments
1360 switch (kind_) {
1361 case ToNumber: __ InvokeBuiltin("TO_NUMBER", 0, JUMP_JS); break;
1362 case Inc: __ InvokeBuiltin("INC", 0, JUMP_JS); break;
1363 case Dec: __ InvokeBuiltin("DEC", 0, JUMP_JS); break;
1364 default: UNREACHABLE();
1365 }
1366 masm->StubReturn(argc_);
1367}
1368
1369
1370class JSExitStub : public CodeStub {
1371 public:
1372 enum Kind { Inc, Dec, ToNumber };
1373
kasper.lund7276f142008-07-30 08:49:36 +00001374 explicit JSExitStub(ExitJSFlag flag) : flag_(flag) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375
1376 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 ExitJSFlag flag_;
1378
1379 Major MajorKey() { return JSExit; }
kasper.lund7276f142008-07-30 08:49:36 +00001380 int MinorKey() { return static_cast<int>(flag_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 void Generate(MacroAssembler* masm);
1382
1383 const char* GetName() { return "JSExitStub"; }
1384
1385#ifdef DEBUG
1386 void Print() {
kasper.lund7276f142008-07-30 08:49:36 +00001387 PrintF("JSExitStub flag %d)\n", static_cast<int>(flag_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 }
1389#endif
1390};
1391
1392
1393void JSExitStub::Generate(MacroAssembler* masm) {
kasper.lund7276f142008-07-30 08:49:36 +00001394 __ ExitJSFrame(flag_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395 masm->StubReturn(1);
1396}
1397
1398
1399
1400void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
1401 // r0 holds exception
1402 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1404 __ ldr(sp, MemOperand(r3));
1405 __ pop(r2); // pop next in chain
1406 __ str(r2, MemOperand(r3));
1407 // restore parameter- and frame-pointer and pop state.
1408 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
1409 // Before returning we restore the context from the frame pointer if not NULL.
1410 // The frame pointer is NULL in the exception handler of a JS entry frame.
1411 __ cmp(fp, Operand(0));
1412 // Set cp to NULL if fp is NULL.
1413 __ mov(cp, Operand(0), LeaveCC, eq);
1414 // Restore cp otherwise.
1415 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
1416 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
1417 __ pop(pc);
1418}
1419
1420
1421void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
1422 // Fetch top stack handler.
1423 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1424 __ ldr(r3, MemOperand(r3));
1425
1426 // Unwind the handlers until the ENTRY handler is found.
1427 Label loop, done;
1428 __ bind(&loop);
1429 // Load the type of the current stack handler.
1430 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
1431 StackHandlerConstants::kStateOffset;
1432 __ ldr(r2, MemOperand(r3, kStateOffset));
1433 __ cmp(r2, Operand(StackHandler::ENTRY));
1434 __ b(eq, &done);
1435 // Fetch the next handler in the list.
1436 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
1437 StackHandlerConstants::kNextOffset;
1438 __ ldr(r3, MemOperand(r3, kNextOffset));
1439 __ jmp(&loop);
1440 __ bind(&done);
1441
1442 // Set the top handler address to next handler past the current ENTRY handler.
1443 __ ldr(r0, MemOperand(r3, kNextOffset));
1444 __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
1445 __ str(r0, MemOperand(r2));
1446
1447 // Set external caught exception to false.
1448 __ mov(r0, Operand(false));
1449 ExternalReference external_caught(Top::k_external_caught_exception_address);
1450 __ mov(r2, Operand(external_caught));
1451 __ str(r0, MemOperand(r2));
1452
mads.s.ager31e71382008-08-13 09:32:07 +00001453 // Set pending exception and r0 to out of memory exception.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454 Failure* out_of_memory = Failure::OutOfMemoryException();
1455 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
1456 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
1457 __ str(r0, MemOperand(r2));
1458
1459 // Restore the stack to the address of the ENTRY handler
1460 __ mov(sp, Operand(r3));
1461
1462 // restore parameter- and frame-pointer and pop state.
1463 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
1464 // Before returning we restore the context from the frame pointer if not NULL.
1465 // The frame pointer is NULL in the exception handler of a JS entry frame.
1466 __ cmp(fp, Operand(0));
1467 // Set cp to NULL if fp is NULL.
1468 __ mov(cp, Operand(0), LeaveCC, eq);
1469 // Restore cp otherwise.
1470 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
1471 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
1472 __ pop(pc);
1473}
1474
1475
1476void CEntryStub::GenerateCore(MacroAssembler* masm,
1477 Label* throw_normal_exception,
1478 Label* throw_out_of_memory_exception,
1479 bool do_gc,
1480 bool do_restore) {
1481 // r0: result parameter for PerformGC, if any
mads.s.ager31e71382008-08-13 09:32:07 +00001482 // r4: number of arguments including receiver (C callee-saved)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 // r5: pointer to builtin function (C callee-saved)
1484
1485 if (do_gc) {
1486 __ Call(FUNCTION_ADDR(Runtime::PerformGC), runtime_entry); // passing r0
1487 }
1488
mads.s.ager31e71382008-08-13 09:32:07 +00001489 // Call C built-in.
1490 // r0 = argc.
1491 __ mov(r0, Operand(r4));
1492 // r1 = argv.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 __ add(r1, fp, Operand(r4, LSL, kPointerSizeLog2));
mads.s.ager31e71382008-08-13 09:32:07 +00001494 __ add(r1, r1, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495
1496 // TODO(1242173): To let the GC traverse the return address of the exit
1497 // frames, we need to know where the return address is. Right now,
1498 // we push it on the stack to be able to find it again, but we never
1499 // restore from it in case of changes, which makes it impossible to
1500 // support moving the C entry code stub. This should be fixed, but currently
1501 // this is OK because the CEntryStub gets generated so early in the V8 boot
1502 // sequence that it is not moving ever.
1503 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4
1504 __ push(lr);
1505#if !defined(__arm__)
1506 // Notify the simulator of the transition to C code.
1507 __ swi(assembler::arm::call_rt_r5);
1508#else /* !defined(__arm__) */
1509 __ mov(pc, Operand(r5));
1510#endif /* !defined(__arm__) */
1511 // result is in r0 or r0:r1 - do not destroy these registers!
1512
1513 // check for failure result
1514 Label failure_returned;
1515 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
1516 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
1517 __ add(r2, r0, Operand(1));
1518 __ tst(r2, Operand(kFailureTagMask));
1519 __ b(eq, &failure_returned);
1520
1521 // clear top frame
1522 __ mov(r3, Operand(0));
1523 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1524 __ str(r3, MemOperand(ip));
1525
1526 // Restore the memory copy of the registers by digging them out from
1527 // the stack.
1528 if (do_restore) {
1529 // Ok to clobber r2 and r3.
1530 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
1531 const int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
1532 __ add(r3, fp, Operand(kOffset));
1533 __ CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
1534 }
1535
1536 // Exit C frame and return
1537 // r0:r1: result
1538 // sp: stack pointer
1539 // fp: frame pointer
1540 // pp: caller's parameter pointer pp (restored as C callee-saved)
1541
1542 // Restore current context from top and clear it in debug mode.
1543 __ mov(r3, Operand(Top::context_address()));
1544 __ ldr(cp, MemOperand(r3));
1545 __ mov(sp, Operand(fp)); // respect ABI stack constraint
kasper.lund7276f142008-07-30 08:49:36 +00001546 __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | pc.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
1548 // check if we should retry or throw exception
1549 Label retry;
1550 __ bind(&failure_returned);
1551 ASSERT(Failure::RETRY_AFTER_GC == 0);
1552 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
1553 __ b(eq, &retry);
1554
1555 Label continue_exception;
1556 // If the returned failure is EXCEPTION then promote Top::pending_exception().
1557 __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
1558 __ b(ne, &continue_exception);
1559
1560 // Retrieve the pending exception and clear the variable.
1561 __ mov(ip, Operand(Factory::the_hole_value().location()));
1562 __ ldr(r3, MemOperand(ip));
1563 __ mov(ip, Operand(Top::pending_exception_address()));
1564 __ ldr(r0, MemOperand(ip));
1565 __ str(r3, MemOperand(ip));
1566
1567 __ bind(&continue_exception);
1568 // Special handling of out of memory exception.
1569 Failure* out_of_memory = Failure::OutOfMemoryException();
1570 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
1571 __ b(eq, throw_out_of_memory_exception);
1572
1573 // Handle normal exception.
1574 __ jmp(throw_normal_exception);
1575
1576 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
1577}
1578
1579
1580void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
1581 // Called from JavaScript; parameters are on stack as if calling JS function
mads.s.ager31e71382008-08-13 09:32:07 +00001582 // r0: number of arguments including receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 // r1: pointer to builtin function
1584 // fp: frame pointer (restored after C call)
1585 // sp: stack pointer (restored as callee's pp after C call)
1586 // cp: current context (C callee-saved)
1587 // pp: caller's parameter pointer pp (C callee-saved)
1588
1589 // NOTE: Invocations of builtins may return failure objects
1590 // instead of a proper result. The builtin entry handles
1591 // this by performing a garbage collection and retrying the
1592 // builtin once.
1593
1594 // Enter C frame
1595 // Compute parameter pointer before making changes and save it as ip register
1596 // so that it is restored as sp register on exit, thereby popping the args.
mads.s.ager31e71382008-08-13 09:32:07 +00001597 // ip = sp + kPointerSize*args_len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
1600 // all JS callee-saved are saved and traversed by GC; push in reverse order:
1601 // JS callee-saved, caller_pp, caller_fp, sp_on_exit (ip==pp), caller_pc
kasper.lund7276f142008-07-30 08:49:36 +00001602 __ stm(db_w, sp, pp.bit() | fp.bit() | ip.bit() | lr.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 __ mov(fp, Operand(sp)); // setup new frame pointer
1604
1605 // Store the current context in top.
1606 __ mov(ip, Operand(Top::context_address()));
1607 __ str(cp, MemOperand(ip));
1608
1609 // remember top frame
1610 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1611 __ str(fp, MemOperand(ip));
1612
1613 // Push debug marker.
1614 __ mov(ip, Operand(is_debug_break ? 1 : 0));
1615 __ push(ip);
1616
1617 if (is_debug_break) {
1618 // Save the state of all registers to the stack from the memory location.
1619 // Use sp as base to push.
1620 __ CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
1621 }
1622
1623 // move number of arguments (argc) into callee-saved register
1624 __ mov(r4, Operand(r0));
1625
1626 // move pointer to builtin function into callee-saved register
1627 __ mov(r5, Operand(r1));
1628
1629 // r0: result parameter for PerformGC, if any (setup below)
1630 // r4: number of arguments
1631 // r5: pointer to builtin function (C callee-saved)
1632
1633 Label entry;
1634 __ bind(&entry);
1635
1636 Label throw_out_of_memory_exception;
1637 Label throw_normal_exception;
1638
1639#ifdef DEBUG
1640 if (FLAG_gc_greedy) {
1641 Failure* failure = Failure::RetryAfterGC(0, NEW_SPACE);
1642 __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
1643 }
1644 GenerateCore(masm,
1645 &throw_normal_exception,
1646 &throw_out_of_memory_exception,
1647 FLAG_gc_greedy,
1648 is_debug_break);
1649#else
1650 GenerateCore(masm,
1651 &throw_normal_exception,
1652 &throw_out_of_memory_exception,
1653 false,
1654 is_debug_break);
1655#endif
1656 GenerateCore(masm,
1657 &throw_normal_exception,
1658 &throw_out_of_memory_exception,
1659 true,
1660 is_debug_break);
1661
1662 __ bind(&throw_out_of_memory_exception);
1663 GenerateThrowOutOfMemory(masm);
1664 // control flow for generated will not return.
1665
1666 __ bind(&throw_normal_exception);
1667 GenerateThrowTOS(masm);
1668}
1669
1670
1671void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
1672 // r0: code entry
1673 // r1: function
1674 // r2: receiver
1675 // r3: argc
1676 // [sp+0]: argv
1677
1678 Label invoke, exit;
1679
1680 // Called from C, so do not pop argc and args on exit (preserve sp)
1681 // No need to save register-passed args
1682 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr
1683 __ mov(ip, Operand(sp));
1684 __ stm(db_w, sp, kCalleeSaved | ip.bit() | lr.bit());
1685
1686 // Setup frame pointer
1687 __ mov(fp, Operand(sp));
1688
1689 // Add constructor mark.
1690 __ mov(ip, Operand(is_construct ? 1 : 0));
1691 __ push(ip);
1692
1693 // Move arguments into registers expected by Builtins::JSEntryTrampoline
1694 // preserve r0-r3, set r4, r5-r7 may be clobbered
1695
1696 // Get address of argv, see stm above.
1697 __ add(r4, sp, Operand((kNumCalleeSaved + 3)*kPointerSize));
1698 __ ldr(r4, MemOperand(r4)); // argv
1699
1700 // Save copies of the top frame descriptors on the stack.
1701 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1702 __ ldr(r6, MemOperand(ip));
1703 __ stm(db_w, sp, r6.bit());
1704
1705 // Call a faked try-block that does the invoke.
1706 __ bl(&invoke);
1707
1708 // Caught exception: Store result (exception) in the pending
1709 // exception field in the JSEnv and return a failure sentinel.
1710 __ mov(ip, Operand(Top::pending_exception_address()));
1711 __ str(r0, MemOperand(ip));
1712 __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
1713 __ b(&exit);
1714
1715 // Invoke: Link this frame into the handler chain.
1716 __ bind(&invoke);
1717 // Must preserve r0-r3, r5-r7 are available.
1718 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
1719 // If an exception not caught by another handler occurs, this handler returns
1720 // control to the code after the bl(&invoke) above, which restores all
1721 // kCalleeSaved registers (including cp, pp and fp) to their saved values
1722 // before returning a failure to C.
1723
1724 // Clear any pending exceptions.
1725 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
1726 __ ldr(r5, MemOperand(ip));
1727 __ mov(ip, Operand(Top::pending_exception_address()));
1728 __ str(r5, MemOperand(ip));
1729
1730 // Invoke the function by calling through JS entry trampoline builtin.
1731 // Notice that we cannot store a reference to the trampoline code directly in
1732 // this stub, because runtime stubs are not traversed when doing GC.
1733
1734 // Expected registers by Builtins::JSEntryTrampoline
1735 // r0: code entry
1736 // r1: function
1737 // r2: receiver
1738 // r3: argc
1739 // r4: argv
1740 if (is_construct) {
1741 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
1742 __ mov(ip, Operand(construct_entry));
1743 } else {
1744 ExternalReference entry(Builtins::JSEntryTrampoline);
1745 __ mov(ip, Operand(entry));
1746 }
1747 __ ldr(ip, MemOperand(ip)); // deref address
1748
1749 // Branch and link to JSEntryTrampoline
1750 __ mov(lr, Operand(pc));
1751 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
1752
1753 // Unlink this frame from the handler chain. When reading the
1754 // address of the next handler, there is no need to use the address
1755 // displacement since the current stack pointer (sp) points directly
1756 // to the stack handler.
1757 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
1758 __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
1759 __ str(r3, MemOperand(ip));
1760 // No need to restore registers
1761 __ add(sp, sp, Operand(StackHandlerConstants::kSize));
1762
1763 __ bind(&exit); // r0 holds result
1764 // Restore the top frame descriptors from the stack.
1765 __ ldm(ia_w, sp, r3.bit());
1766 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1767 __ str(r3, MemOperand(ip));
1768
1769 // Remove constructor mark.
mads.s.ager31e71382008-08-13 09:32:07 +00001770 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771
1772 // Restore callee-saved registers, sp, and return.
1773#ifdef DEBUG
1774 if (FLAG_debug_code) __ mov(lr, Operand(pc));
1775#endif
1776 __ ldm(ia, sp, kCalleeSaved | sp.bit() | pc.bit());
1777}
1778
1779
1780class ArgumentsAccessStub: public CodeStub {
1781 public:
1782 explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { }
1783
1784 private:
1785 bool is_length_;
1786
1787 Major MajorKey() { return ArgumentsAccess; }
1788 int MinorKey() { return is_length_ ? 1 : 0; }
1789 void Generate(MacroAssembler* masm);
1790
1791 const char* GetName() { return "ArgumentsAccessStub"; }
1792
1793#ifdef DEBUG
1794 void Print() {
1795 PrintF("ArgumentsAccessStub (is_length %s)\n",
1796 is_length_ ? "true" : "false");
1797 }
1798#endif
1799};
1800
1801
1802void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
1803 if (is_length_) {
1804 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
1805 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1806 __ Ret();
1807 } else {
1808 // Check that the key is a smi.
1809 Label slow;
1810 __ tst(r0, Operand(kSmiTagMask));
1811 __ b(ne, &slow);
1812
1813 // Get the actual number of arguments passed and do bounds
1814 // check. Use unsigned comparison to get negative check for free.
1815 __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
1816 __ cmp(r0, Operand(r1, LSL, kSmiTagSize));
1817 __ b(hs, &slow);
1818
1819 // Load the argument directly from the stack and return.
1820 __ sub(r1, pp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1821 __ ldr(r0, MemOperand(r1, JavaScriptFrameConstants::kParam0Offset));
1822 __ Ret();
1823
1824 // Slow-case: Handle non-smi or out-of-bounds access to arguments
1825 // by calling the runtime system.
1826 __ bind(&slow);
1827 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001828 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 }
1830}
1831
1832
1833#undef __
1834#define __ masm_->
1835
1836
1837void ArmCodeGenerator::AccessReferenceProperty(
1838 Expression* key,
1839 CodeGenState::AccessType access) {
1840 Reference::Type type = ref()->type();
1841 ASSERT(type != Reference::ILLEGAL);
1842
1843 // TODO(1241834): Make sure that this is sufficient. If there is a chance
1844 // that reference errors can be thrown below, we must distinguish
1845 // between the 2 kinds of loads (typeof expression loads must not
v8.team.kasperl727e9952008-09-02 14:56:44 +00001846 // throw a reference error).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001847 bool is_load = (access == CodeGenState::LOAD ||
1848 access == CodeGenState::LOAD_TYPEOF_EXPR);
1849
1850 if (type == Reference::NAMED) {
1851 // Compute the name of the property.
1852 Literal* literal = key->AsLiteral();
1853 Handle<String> name(String::cast(*literal->handle()));
1854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855 // Call the appropriate IC code.
1856 if (is_load) {
mads.s.ager31e71382008-08-13 09:32:07 +00001857 // Setup the name register.
1858 __ mov(r2, Operand(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1860 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
1861 if (var != NULL) {
1862 ASSERT(var->is_global());
1863 __ Call(ic, code_target_context);
1864 } else {
1865 __ Call(ic, code_target);
1866 }
mads.s.ager31e71382008-08-13 09:32:07 +00001867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001868 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001869 __ pop(r0); // value
1870 // Setup the name register.
1871 __ mov(r2, Operand(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1873 __ Call(ic, code_target);
1874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001877 // Access keyed property.
1878 ASSERT(type == Reference::KEYED);
1879
1880 if (is_load) {
1881 // TODO(1224671): Implement inline caching for keyed loads as on ia32.
1882 GetPropertyStub stub;
1883 __ CallStub(&stub);
1884
1885 } else {
1886 __ pop(r0); // value
1887 SetPropertyStub stub;
1888 __ CallStub(&stub);
1889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 }
mads.s.ager31e71382008-08-13 09:32:07 +00001891 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892}
1893
1894
kasper.lund7276f142008-07-30 08:49:36 +00001895void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
mads.s.ager31e71382008-08-13 09:32:07 +00001896 // sp[0] : y
1897 // sp[1] : x
1898 // result : r0
1899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 // Stub is entered with a call: 'return address' is in lr.
1901 switch (op) {
1902 case Token::ADD: // fall through.
1903 case Token::SUB: // fall through.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001904 case Token::MUL:
1905 case Token::BIT_OR:
1906 case Token::BIT_AND:
1907 case Token::BIT_XOR:
1908 case Token::SHL:
1909 case Token::SHR:
1910 case Token::SAR: {
mads.s.ager31e71382008-08-13 09:32:07 +00001911 __ pop(r0); // r0 : y
1912 __ pop(r1); // r1 : x
kasper.lund7276f142008-07-30 08:49:36 +00001913 GenericBinaryOpStub stub(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 __ CallStub(&stub);
1915 break;
1916 }
1917
1918 case Token::DIV: {
mads.s.ager31e71382008-08-13 09:32:07 +00001919 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 __ InvokeBuiltin("DIV", 1, CALL_JS);
1921 break;
1922 }
1923
1924 case Token::MOD: {
mads.s.ager31e71382008-08-13 09:32:07 +00001925 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 __ InvokeBuiltin("MOD", 1, CALL_JS);
1927 break;
1928 }
1929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001930 case Token::COMMA:
mads.s.ager31e71382008-08-13 09:32:07 +00001931 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 // simply discard left value
mads.s.ager31e71382008-08-13 09:32:07 +00001933 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 break;
1935
1936 default:
1937 // Other cases should have been handled before this point.
1938 UNREACHABLE();
1939 break;
1940 }
1941}
1942
1943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001944class DeferredInlinedSmiOperation: public DeferredCode {
1945 public:
1946 DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
1947 int value, bool reversed) :
1948 DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
1949 set_comment("[ DeferredInlinedSmiOperation");
1950 }
1951
1952 virtual void Generate() {
1953 switch (op_) {
1954 case Token::ADD: {
1955 if (reversed_) {
1956 // revert optimistic add
1957 __ sub(r0, r0, Operand(Smi::FromInt(value_)));
1958 __ mov(r1, Operand(Smi::FromInt(value_))); // x
1959 } else {
1960 // revert optimistic add
1961 __ sub(r1, r0, Operand(Smi::FromInt(value_)));
1962 __ mov(r0, Operand(Smi::FromInt(value_)));
1963 }
1964 break;
1965 }
1966
1967 case Token::SUB: {
1968 if (reversed_) {
1969 // revert optimistic sub
1970 __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
1971 __ mov(r1, Operand(Smi::FromInt(value_)));
1972 } else {
1973 __ add(r1, r0, Operand(Smi::FromInt(value_)));
1974 __ mov(r0, Operand(Smi::FromInt(value_)));
1975 }
1976 break;
1977 }
1978
1979 case Token::BIT_OR:
1980 case Token::BIT_XOR:
1981 case Token::BIT_AND: {
1982 if (reversed_) {
1983 __ mov(r1, Operand(Smi::FromInt(value_)));
1984 } else {
1985 __ mov(r1, Operand(r0));
1986 __ mov(r0, Operand(Smi::FromInt(value_)));
1987 }
1988 break;
1989 }
1990
1991 case Token::SHL:
1992 case Token::SHR:
1993 case Token::SAR: {
1994 if (!reversed_) {
1995 __ mov(r1, Operand(r0));
1996 __ mov(r0, Operand(Smi::FromInt(value_)));
1997 } else {
1998 UNREACHABLE(); // should have been handled in SmiOperation
1999 }
2000 break;
2001 }
2002
2003 default:
2004 // other cases should have been handled before this point.
2005 UNREACHABLE();
2006 break;
2007 }
2008
2009 GenericBinaryOpStub igostub(op_);
2010 __ CallStub(&igostub);
2011 }
2012
2013 private:
2014 Token::Value op_;
2015 int value_;
2016 bool reversed_;
2017};
2018
2019
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020void ArmCodeGenerator::SmiOperation(Token::Value op,
2021 Handle<Object> value,
2022 bool reversed) {
2023 // NOTE: This is an attempt to inline (a bit) more of the code for
2024 // some possible smi operations (like + and -) when (at least) one
2025 // of the operands is a literal smi. With this optimization, the
2026 // performance of the system is increased by ~15%, and the generated
2027 // code size is increased by ~1% (measured on a combination of
2028 // different benchmarks).
2029
mads.s.ager31e71382008-08-13 09:32:07 +00002030 // sp[0] : operand
2031
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002032 int int_value = Smi::cast(*value)->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033
2034 Label exit;
mads.s.ager31e71382008-08-13 09:32:07 +00002035 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036
2037 switch (op) {
2038 case Token::ADD: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039 DeferredCode* deferred =
2040 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002042 __ add(r0, r0, Operand(value), SetCC);
2043 __ b(vs, deferred->enter());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 __ tst(r0, Operand(kSmiTagMask));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002045 __ b(ne, deferred->enter());
2046 __ bind(deferred->exit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 break;
2048 }
2049
2050 case Token::SUB: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002051 DeferredCode* deferred =
2052 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 if (!reversed) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002055 __ sub(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002057 __ rsb(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002059 __ b(vs, deferred->enter());
2060 __ tst(r0, Operand(kSmiTagMask));
2061 __ b(ne, deferred->enter());
2062 __ bind(deferred->exit());
2063 break;
2064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002065
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002066 case Token::BIT_OR:
2067 case Token::BIT_XOR:
2068 case Token::BIT_AND: {
2069 DeferredCode* deferred =
2070 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
2071 __ tst(r0, Operand(kSmiTagMask));
2072 __ b(ne, deferred->enter());
2073 switch (op) {
2074 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
2075 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
2076 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
2077 default: UNREACHABLE();
2078 }
2079 __ bind(deferred->exit());
2080 break;
2081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002082
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002083 case Token::SHL:
2084 case Token::SHR:
2085 case Token::SAR: {
2086 if (reversed) {
2087 __ mov(ip, Operand(value));
2088 __ push(ip);
2089 __ push(r0);
2090 GenericBinaryOperation(op);
2091
2092 } else {
2093 int shift_value = int_value & 0x1f; // least significant 5 bits
2094 DeferredCode* deferred =
2095 new DeferredInlinedSmiOperation(this, op, shift_value, false);
2096 __ tst(r0, Operand(kSmiTagMask));
2097 __ b(ne, deferred->enter());
2098 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
2099 switch (op) {
2100 case Token::SHL: {
2101 __ mov(r2, Operand(r2, LSL, shift_value));
2102 // check that the *unsigned* result fits in a smi
2103 __ add(r3, r2, Operand(0x40000000), SetCC);
2104 __ b(mi, deferred->enter());
2105 break;
2106 }
2107 case Token::SHR: {
2108 // LSR by immediate 0 means shifting 32 bits.
2109 if (shift_value != 0) {
2110 __ mov(r2, Operand(r2, LSR, shift_value));
2111 }
2112 // check that the *unsigned* result fits in a smi
2113 // neither of the two high-order bits can be set:
2114 // - 0x80000000: high bit would be lost when smi tagging
2115 // - 0x40000000: this number would convert to negative when
2116 // smi tagging these two cases can only happen with shifts
2117 // by 0 or 1 when handed a valid smi
2118 __ and_(r3, r2, Operand(0xc0000000), SetCC);
2119 __ b(ne, deferred->enter());
2120 break;
2121 }
2122 case Token::SAR: {
2123 if (shift_value != 0) {
2124 // ASR by immediate 0 means shifting 32 bits.
2125 __ mov(r2, Operand(r2, ASR, shift_value));
2126 }
2127 break;
2128 }
2129 default: UNREACHABLE();
2130 }
2131 __ mov(r0, Operand(r2, LSL, kSmiTagSize));
2132 __ bind(deferred->exit());
2133 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134 break;
2135 }
2136
2137 default:
2138 if (!reversed) {
mads.s.ager31e71382008-08-13 09:32:07 +00002139 __ push(r0);
2140 __ mov(r0, Operand(value));
2141 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142 } else {
2143 __ mov(ip, Operand(value));
2144 __ push(ip);
mads.s.ager31e71382008-08-13 09:32:07 +00002145 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002146 }
kasper.lund7276f142008-07-30 08:49:36 +00002147 GenericBinaryOperation(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 break;
2149 }
2150
2151 __ bind(&exit);
2152}
2153
2154
2155void ArmCodeGenerator::Comparison(Condition cc, bool strict) {
mads.s.ager31e71382008-08-13 09:32:07 +00002156 // sp[0] : y
2157 // sp[1] : x
2158 // result : cc register
2159
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 // Strict only makes sense for equality comparisons.
2161 ASSERT(!strict || cc == eq);
2162
2163 Label exit, smi;
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002164 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
2165 if (cc == gt || cc == le) {
2166 cc = ReverseCondition(cc);
mads.s.ager31e71382008-08-13 09:32:07 +00002167 __ pop(r1);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002168 __ pop(r0);
2169 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002170 __ pop(r0);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002171 __ pop(r1);
2172 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 __ orr(r2, r0, Operand(r1));
2174 __ tst(r2, Operand(kSmiTagMask));
2175 __ b(eq, &smi);
2176
2177 // Perform non-smi comparison by runtime call.
2178 __ push(r1);
2179
2180 // Figure out which native to call and setup the arguments.
2181 const char* native;
2182 int argc;
2183 if (cc == eq) {
2184 native = strict ? "STRICT_EQUALS" : "EQUALS";
2185 argc = 1;
2186 } else {
2187 native = "COMPARE";
2188 int ncr; // NaN compare result
2189 if (cc == lt || cc == le) {
2190 ncr = GREATER;
2191 } else {
2192 ASSERT(cc == gt || cc == ge); // remaining cases
2193 ncr = LESS;
2194 }
mads.s.ager31e71382008-08-13 09:32:07 +00002195 __ push(r0);
2196 __ mov(r0, Operand(Smi::FromInt(ncr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 argc = 2;
2198 }
2199
2200 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
2201 // tagged as a small integer.
mads.s.ager31e71382008-08-13 09:32:07 +00002202 __ push(r0);
2203 __ mov(r0, Operand(argc));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002204 __ InvokeBuiltin(native, argc, CALL_JS);
2205 __ cmp(r0, Operand(0));
2206 __ b(&exit);
2207
2208 // test smi equality by pointer comparison.
2209 __ bind(&smi);
2210 __ cmp(r1, Operand(r0));
2211
2212 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 cc_reg_ = cc;
2214}
2215
2216
kasper.lund7276f142008-07-30 08:49:36 +00002217class CallFunctionStub: public CodeStub {
2218 public:
2219 explicit CallFunctionStub(int argc) : argc_(argc) {}
2220
2221 void Generate(MacroAssembler* masm);
2222
2223 private:
2224 int argc_;
2225
2226 const char* GetName() { return "CallFuntionStub"; }
2227
2228#if defined(DEBUG)
2229 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
2230#endif // defined(DEBUG)
2231
2232 Major MajorKey() { return CallFunction; }
2233 int MinorKey() { return argc_; }
2234};
2235
2236
2237void CallFunctionStub::Generate(MacroAssembler* masm) {
2238 Label slow;
kasper.lund7276f142008-07-30 08:49:36 +00002239 // Get the function to call from the stack.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002240 // function, receiver [, arguments]
kasper.lund7276f142008-07-30 08:49:36 +00002241 masm->ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
2242
2243 // Check that the function is really a JavaScript function.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002244 // r1: pushed function (to be verified)
kasper.lund7276f142008-07-30 08:49:36 +00002245 masm->tst(r1, Operand(kSmiTagMask));
2246 masm->b(eq, &slow);
2247 // Get the map of the function object.
2248 masm->ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
2249 masm->ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
2250 masm->cmp(r2, Operand(JS_FUNCTION_TYPE));
2251 masm->b(ne, &slow);
2252
2253 // Fast-case: Invoke the function now.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002254 // r1: pushed function
2255 ParameterCount actual(argc_);
2256 masm->InvokeFunction(r1, actual, JUMP_FUNCTION);
kasper.lund7276f142008-07-30 08:49:36 +00002257
2258 // Slow-case: Non-function called.
2259 masm->bind(&slow);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002260 masm->mov(r0, Operand(argc_)); // Setup the number of arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002261 masm->InvokeBuiltin("CALL_NON_FUNCTION", argc_, JUMP_JS);
kasper.lund7276f142008-07-30 08:49:36 +00002262}
2263
2264
mads.s.ager31e71382008-08-13 09:32:07 +00002265// Call the function on the stack with the given arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002266void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
2267 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002268 // Push the arguments ("left-to-right") on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002269 for (int i = 0; i < args->length(); i++) {
2270 Load(args->at(i));
2271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272
kasper.lund7276f142008-07-30 08:49:36 +00002273 // Record the position for debugging purposes.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274 __ RecordPosition(position);
2275
kasper.lund7276f142008-07-30 08:49:36 +00002276 // Use the shared code stub to call the function.
2277 CallFunctionStub call_function(args->length());
2278 __ CallStub(&call_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002279
2280 // Restore context and pop function from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00002282 __ pop(); // discard the TOS
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
2285
2286void ArmCodeGenerator::Branch(bool if_true, Label* L) {
2287 ASSERT(has_cc());
2288 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
2289 __ b(cc, L);
2290 cc_reg_ = al;
2291}
2292
2293
2294void ArmCodeGenerator::CheckStack() {
2295 if (FLAG_check_stack) {
2296 Comment cmnt(masm_, "[ check stack");
2297 StackCheckStub stub;
2298 __ CallStub(&stub);
2299 }
2300}
2301
2302
2303void ArmCodeGenerator::VisitBlock(Block* node) {
2304 Comment cmnt(masm_, "[ Block");
2305 if (FLAG_debug_info) RecordStatementPosition(node);
2306 node->set_break_stack_height(break_stack_height_);
2307 VisitStatements(node->statements());
2308 __ bind(node->break_target());
2309}
2310
2311
2312void ArmCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
mads.s.ager31e71382008-08-13 09:32:07 +00002313 __ mov(r0, Operand(pairs));
2314 __ push(r0);
2315 __ push(cp);
2316 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
2317 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002318 __ CallRuntime(Runtime::kDeclareGlobals, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00002319 // The result is discarded.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320}
2321
2322
2323void ArmCodeGenerator::VisitDeclaration(Declaration* node) {
2324 Comment cmnt(masm_, "[ Declaration");
2325 Variable* var = node->proxy()->var();
2326 ASSERT(var != NULL); // must have been resolved
2327 Slot* slot = var->slot();
2328
2329 // If it was not possible to allocate the variable at compile time,
2330 // we need to "declare" it at runtime to make sure it actually
2331 // exists in the local context.
2332 if (slot != NULL && slot->type() == Slot::LOOKUP) {
2333 // Variables with a "LOOKUP" slot were introduced as non-locals
2334 // during variable resolution and must have mode DYNAMIC.
2335 ASSERT(var->mode() == Variable::DYNAMIC);
2336 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00002337 __ push(cp);
2338 __ mov(r0, Operand(var->name()));
2339 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340 // Declaration nodes are always declared in only two modes.
2341 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
2342 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
mads.s.ager31e71382008-08-13 09:32:07 +00002343 __ mov(r0, Operand(Smi::FromInt(attr)));
2344 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002345 // Push initial value, if any.
2346 // Note: For variables we must not push an initial value (such as
2347 // 'undefined') because we may have a (legal) redeclaration and we
2348 // must not destroy the current value.
2349 if (node->mode() == Variable::CONST) {
mads.s.ager31e71382008-08-13 09:32:07 +00002350 __ mov(r0, Operand(Factory::the_hole_value()));
2351 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352 } else if (node->fun() != NULL) {
2353 Load(node->fun());
2354 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002355 __ mov(r0, Operand(0)); // no initial value!
2356 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002357 }
2358 __ CallRuntime(Runtime::kDeclareContextSlot, 5);
mads.s.ager31e71382008-08-13 09:32:07 +00002359 __ push(r0);
2360
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002361 return;
2362 }
2363
2364 ASSERT(!var->is_global());
2365
2366 // If we have a function or a constant, we need to initialize the variable.
2367 Expression* val = NULL;
2368 if (node->mode() == Variable::CONST) {
2369 val = new Literal(Factory::the_hole_value());
2370 } else {
2371 val = node->fun(); // NULL if we don't have a function
2372 }
2373
2374 if (val != NULL) {
2375 // Set initial value.
2376 Reference target(this, node->proxy());
2377 Load(val);
2378 SetValue(&target);
2379 // Get rid of the assigned value (declarations are statements).
mads.s.ager31e71382008-08-13 09:32:07 +00002380 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002381 }
2382}
2383
2384
2385void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
2386 Comment cmnt(masm_, "[ ExpressionStatement");
2387 if (FLAG_debug_info) RecordStatementPosition(node);
2388 Expression* expression = node->expression();
2389 expression->MarkAsStatement();
2390 Load(expression);
mads.s.ager31e71382008-08-13 09:32:07 +00002391 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002392}
2393
2394
2395void ArmCodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
2396 Comment cmnt(masm_, "// EmptyStatement");
2397 // nothing to do
2398}
2399
2400
2401void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
2402 Comment cmnt(masm_, "[ IfStatement");
2403 // Generate different code depending on which
2404 // parts of the if statement are present or not.
2405 bool has_then_stm = node->HasThenStatement();
2406 bool has_else_stm = node->HasElseStatement();
2407
2408 if (FLAG_debug_info) RecordStatementPosition(node);
2409
2410 Label exit;
2411 if (has_then_stm && has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002412 Comment cmnt(masm_, "[ IfThenElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002413 Label then;
2414 Label else_;
2415 // if (cond)
2416 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
2417 Branch(false, &else_);
2418 // then
2419 __ bind(&then);
2420 Visit(node->then_statement());
2421 __ b(&exit);
2422 // else
2423 __ bind(&else_);
2424 Visit(node->else_statement());
2425
2426 } else if (has_then_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002427 Comment cmnt(masm_, "[ IfThen");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002428 ASSERT(!has_else_stm);
2429 Label then;
2430 // if (cond)
2431 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
2432 Branch(false, &exit);
2433 // then
2434 __ bind(&then);
2435 Visit(node->then_statement());
2436
2437 } else if (has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002438 Comment cmnt(masm_, "[ IfElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002439 ASSERT(!has_then_stm);
2440 Label else_;
2441 // if (!cond)
2442 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
2443 Branch(true, &exit);
2444 // else
2445 __ bind(&else_);
2446 Visit(node->else_statement());
2447
2448 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002449 Comment cmnt(masm_, "[ If");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450 ASSERT(!has_then_stm && !has_else_stm);
2451 // if (cond)
2452 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
2453 if (has_cc()) {
2454 cc_reg_ = al;
2455 } else {
2456 __ pop(r0); // __ Pop(no_reg)
2457 }
2458 }
2459
2460 // end
2461 __ bind(&exit);
2462}
2463
2464
2465void ArmCodeGenerator::CleanStack(int num_bytes) {
2466 ASSERT(num_bytes >= 0);
2467 if (num_bytes > 0) {
mads.s.ager31e71382008-08-13 09:32:07 +00002468 __ add(sp, sp, Operand(num_bytes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469 }
2470}
2471
2472
2473void ArmCodeGenerator::VisitContinueStatement(ContinueStatement* node) {
2474 Comment cmnt(masm_, "[ ContinueStatement");
2475 if (FLAG_debug_info) RecordStatementPosition(node);
2476 CleanStack(break_stack_height_ - node->target()->break_stack_height());
2477 __ b(node->target()->continue_target());
2478}
2479
2480
2481void ArmCodeGenerator::VisitBreakStatement(BreakStatement* node) {
2482 Comment cmnt(masm_, "[ BreakStatement");
2483 if (FLAG_debug_info) RecordStatementPosition(node);
2484 CleanStack(break_stack_height_ - node->target()->break_stack_height());
2485 __ b(node->target()->break_target());
2486}
2487
2488
2489void ArmCodeGenerator::VisitReturnStatement(ReturnStatement* node) {
2490 Comment cmnt(masm_, "[ ReturnStatement");
2491 if (FLAG_debug_info) RecordStatementPosition(node);
2492 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00002493 // Move the function result into r0.
2494 __ pop(r0);
2495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496 __ b(&function_return_);
2497}
2498
2499
2500void ArmCodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
2501 Comment cmnt(masm_, "[ WithEnterStatement");
2502 if (FLAG_debug_info) RecordStatementPosition(node);
2503 Load(node->expression());
kasper.lund7276f142008-07-30 08:49:36 +00002504 __ CallRuntime(Runtime::kPushContext, 1);
2505 if (kDebug) {
2506 Label verified_true;
2507 __ cmp(r0, Operand(cp));
2508 __ b(eq, &verified_true);
2509 __ stop("PushContext: r0 is expected to be the same as cp");
2510 __ bind(&verified_true);
2511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002512 // Update context local.
2513 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2514}
2515
2516
2517void ArmCodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
2518 Comment cmnt(masm_, "[ WithExitStatement");
2519 // Pop context.
2520 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
2521 // Update context local.
2522 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2523}
2524
2525
2526void ArmCodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
2527 Comment cmnt(masm_, "[ SwitchStatement");
2528 if (FLAG_debug_info) RecordStatementPosition(node);
2529 node->set_break_stack_height(break_stack_height_);
2530
2531 Load(node->tag());
2532
2533 Label next, fall_through, default_case;
2534 ZoneList<CaseClause*>* cases = node->cases();
2535 int length = cases->length();
2536
2537 for (int i = 0; i < length; i++) {
2538 CaseClause* clause = cases->at(i);
2539
2540 Comment cmnt(masm_, "[ case clause");
2541
2542 if (clause->is_default()) {
2543 // Bind the default case label, so we can branch to it when we
2544 // have compared against all other cases.
2545 ASSERT(default_case.is_unused()); // at most one default clause
2546
2547 // If the default case is the first (but not only) case, we have
2548 // to jump past it for now. Once we're done with the remaining
2549 // clauses, we'll branch back here. If it isn't the first case,
2550 // we jump past it by avoiding to chain it into the next chain.
2551 if (length > 1) {
2552 if (i == 0) __ b(&next);
2553 __ bind(&default_case);
2554 }
2555
2556 } else {
2557 __ bind(&next);
2558 next.Unuse();
mads.s.ager31e71382008-08-13 09:32:07 +00002559 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002560 __ push(r0); // duplicate TOS
2561 Load(clause->label());
2562 Comparison(eq, true);
2563 Branch(false, &next);
mads.s.ager31e71382008-08-13 09:32:07 +00002564 // Entering the case statement -> remove the switch value from the stack
2565 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566 }
2567
2568 // Generate code for the body.
2569 __ bind(&fall_through);
2570 fall_through.Unuse();
2571 VisitStatements(clause->statements());
2572 __ b(&fall_through);
2573 }
2574
2575 __ bind(&next);
mads.s.ager31e71382008-08-13 09:32:07 +00002576 // Reached the end of the case statements -> remove the switch value
2577 // from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002578 __ pop(r0); // __ Pop(no_reg)
2579 if (default_case.is_bound()) __ b(&default_case);
2580
2581 __ bind(&fall_through);
2582 __ bind(node->break_target());
2583}
2584
2585
2586void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) {
2587 Comment cmnt(masm_, "[ LoopStatement");
2588 if (FLAG_debug_info) RecordStatementPosition(node);
2589 node->set_break_stack_height(break_stack_height_);
2590
2591 // simple condition analysis
2592 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
2593 if (node->cond() == NULL) {
2594 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2595 info = ALWAYS_TRUE;
2596 } else {
2597 Literal* lit = node->cond()->AsLiteral();
2598 if (lit != NULL) {
2599 if (lit->IsTrue()) {
2600 info = ALWAYS_TRUE;
2601 } else if (lit->IsFalse()) {
2602 info = ALWAYS_FALSE;
2603 }
2604 }
2605 }
2606
2607 Label loop, entry;
2608
2609 // init
2610 if (node->init() != NULL) {
2611 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2612 Visit(node->init());
2613 }
2614 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
2615 __ b(&entry);
2616 }
2617
2618 // body
2619 __ bind(&loop);
2620 Visit(node->body());
2621
2622 // next
2623 __ bind(node->continue_target());
2624 if (node->next() != NULL) {
2625 // Record source position of the statement as this code which is after the
2626 // code for the body actually belongs to the loop statement and not the
2627 // body.
2628 if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
2629 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2630 Visit(node->next());
2631 }
2632
2633 // cond
2634 __ bind(&entry);
2635 switch (info) {
2636 case ALWAYS_TRUE:
2637 CheckStack(); // TODO(1222600): ignore if body contains calls.
2638 __ b(&loop);
2639 break;
2640 case ALWAYS_FALSE:
2641 break;
2642 case DONT_KNOW:
2643 CheckStack(); // TODO(1222600): ignore if body contains calls.
2644 LoadCondition(node->cond(),
2645 CodeGenState::LOAD,
2646 &loop,
2647 node->break_target(),
2648 true);
2649 Branch(true, &loop);
2650 break;
2651 }
2652
2653 // exit
2654 __ bind(node->break_target());
2655}
2656
2657
2658void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) {
2659 Comment cmnt(masm_, "[ ForInStatement");
2660 if (FLAG_debug_info) RecordStatementPosition(node);
2661
2662 // We keep stuff on the stack while the body is executing.
2663 // Record it, so that a break/continue crossing this statement
2664 // can restore the stack.
2665 const int kForInStackSize = 5 * kPointerSize;
2666 break_stack_height_ += kForInStackSize;
2667 node->set_break_stack_height(break_stack_height_);
2668
2669 Label loop, next, entry, cleanup, exit, primitive, jsobject;
2670 Label filter_key, end_del_check, fixed_array, non_string;
2671
2672 // Get the object to enumerate over (converted to JSObject).
2673 Load(node->enumerable());
mads.s.ager31e71382008-08-13 09:32:07 +00002674 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675
2676 // Both SpiderMonkey and kjs ignore null and undefined in contrast
2677 // to the specification. 12.6.4 mandates a call to ToObject.
2678 __ cmp(r0, Operand(Factory::undefined_value()));
2679 __ b(eq, &exit);
2680 __ cmp(r0, Operand(Factory::null_value()));
2681 __ b(eq, &exit);
2682
2683 // Stack layout in body:
2684 // [iteration counter (Smi)]
2685 // [length of array]
2686 // [FixedArray]
2687 // [Map or 0]
2688 // [Object]
2689
2690 // Check if enumerable is already a JSObject
2691 __ tst(r0, Operand(kSmiTagMask));
2692 __ b(eq, &primitive);
2693 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2694 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00002695 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002696 __ b(hs, &jsobject);
2697
2698 __ bind(&primitive);
mads.s.ager31e71382008-08-13 09:32:07 +00002699 __ push(r0);
2700 __ mov(r0, Operand(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 __ InvokeBuiltin("TO_OBJECT", 0, CALL_JS);
2702
2703
2704 __ bind(&jsobject);
2705
2706 // Get the set of properties (as a FixedArray or Map).
2707 __ push(r0); // duplicate the object being enumerated
mads.s.ager31e71382008-08-13 09:32:07 +00002708 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
2710
2711 // If we got a Map, we can do a fast modification check.
2712 // Otherwise, we got a FixedArray, and we have to do a slow check.
2713 __ mov(r2, Operand(r0));
2714 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
2715 __ cmp(r1, Operand(Factory::meta_map()));
2716 __ b(ne, &fixed_array);
2717
2718 // Get enum cache
2719 __ mov(r1, Operand(r0));
2720 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
2721 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
2722 __ ldr(r2,
2723 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
2724
mads.s.ager31e71382008-08-13 09:32:07 +00002725 __ push(r0); // map
2726 __ push(r2); // enum cache bridge cache
2727 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002728 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00002729 __ push(r0);
2730 __ mov(r0, Operand(Smi::FromInt(0)));
2731 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 __ b(&entry);
2733
2734
2735 __ bind(&fixed_array);
2736
2737 __ mov(r1, Operand(Smi::FromInt(0)));
2738 __ push(r1); // insert 0 in place of Map
mads.s.ager31e71382008-08-13 09:32:07 +00002739 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740
2741 // Push the length of the array and the initial index onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002742 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00002744 __ push(r0);
2745 __ mov(r0, Operand(Smi::FromInt(0))); // init index
2746 __ push(r0);
2747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748 __ b(&entry);
2749
2750 // Body.
2751 __ bind(&loop);
2752 Visit(node->body());
2753
2754 // Next.
2755 __ bind(node->continue_target());
2756 __ bind(&next);
mads.s.ager31e71382008-08-13 09:32:07 +00002757 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 __ add(r0, r0, Operand(Smi::FromInt(1)));
mads.s.ager31e71382008-08-13 09:32:07 +00002759 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002760
2761 // Condition.
2762 __ bind(&entry);
2763
mads.s.ager31e71382008-08-13 09:32:07 +00002764 // sp[0] : index
2765 // sp[1] : array/enum cache length
2766 // sp[2] : array or enum cache
2767 // sp[3] : 0 or map
2768 // sp[4] : enumerable
2769 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count
2770 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length
2771 __ cmp(r0, Operand(r1)); // compare to the array length
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 __ b(hs, &cleanup);
2773
mads.s.ager31e71382008-08-13 09:32:07 +00002774 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2775
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776 // Get the i'th entry of the array.
mads.s.ager31e71382008-08-13 09:32:07 +00002777 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2779 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
2780
2781 // Get Map or 0.
mads.s.ager31e71382008-08-13 09:32:07 +00002782 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 // Check if this (still) matches the map of the enumerable.
2784 // If not, we have to filter the key.
mads.s.ager31e71382008-08-13 09:32:07 +00002785 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
2787 __ cmp(r1, Operand(r2));
2788 __ b(eq, &end_del_check);
2789
2790 // Convert the entry to a string (or null if it isn't a property anymore).
mads.s.ager31e71382008-08-13 09:32:07 +00002791 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable
2792 __ push(r0);
2793 __ push(r3); // push entry
2794 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002795 __ InvokeBuiltin("FILTER_KEY", 1, CALL_JS);
2796 __ mov(r3, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002797
2798 // If the property has been removed while iterating, we just skip it.
2799 __ cmp(r3, Operand(Factory::null_value()));
2800 __ b(eq, &next);
2801
2802
2803 __ bind(&end_del_check);
2804
2805 // Store the entry in the 'each' expression and take another spin in the loop.
mads.s.ager31e71382008-08-13 09:32:07 +00002806 // r3: i'th entry of the enum cache (or string there of)
2807 __ push(r3); // push entry
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 { Reference each(this, node->each());
2809 if (!each.is_illegal()) {
mads.s.ager31e71382008-08-13 09:32:07 +00002810 if (each.size() > 0) {
2811 __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
2812 __ push(r0);
2813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814 SetValue(&each);
mads.s.ager31e71382008-08-13 09:32:07 +00002815 if (each.size() > 0) {
2816 __ pop(r0); // discard the value
2817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818 }
2819 }
mads.s.ager31e71382008-08-13 09:32:07 +00002820 __ pop(); // pop the i'th entry pushed above
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821 CheckStack(); // TODO(1222600): ignore if body contains calls.
2822 __ jmp(&loop);
2823
2824 // Cleanup.
2825 __ bind(&cleanup);
2826 __ bind(node->break_target());
mads.s.ager31e71382008-08-13 09:32:07 +00002827 __ add(sp, sp, Operand(5 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828
2829 // Exit.
2830 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002831
2832 break_stack_height_ -= kForInStackSize;
2833}
2834
2835
2836void ArmCodeGenerator::VisitTryCatch(TryCatch* node) {
2837 Comment cmnt(masm_, "[ TryCatch");
2838
2839 Label try_block, exit;
2840
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002841 __ bl(&try_block);
2842
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843 // --- Catch block ---
2844
2845 // Store the caught exception in the catch variable.
mads.s.ager31e71382008-08-13 09:32:07 +00002846 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 { Reference ref(this, node->catch_var());
2848 // Load the exception to the top of the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002849 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
2850 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002851 SetValue(&ref);
mads.s.ager31e71382008-08-13 09:32:07 +00002852 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002853 }
2854
2855 // Remove the exception from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002856 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857
2858 VisitStatements(node->catch_block()->statements());
2859 __ b(&exit);
2860
2861
2862 // --- Try block ---
2863 __ bind(&try_block);
2864
2865 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
2866
2867 // Introduce shadow labels for all escapes from the try block,
2868 // including returns. We should probably try to unify the escaping
2869 // labels and the return label.
2870 int nof_escapes = node->escaping_labels()->length();
2871 List<LabelShadow*> shadows(1 + nof_escapes);
2872 shadows.Add(new LabelShadow(&function_return_));
2873 for (int i = 0; i < nof_escapes; i++) {
2874 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
2875 }
2876
2877 // Generate code for the statements in the try block.
2878 VisitStatements(node->try_block()->statements());
mads.s.ager31e71382008-08-13 09:32:07 +00002879 __ pop(r0); // Discard the result.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002880
2881 // Stop the introduced shadowing and count the number of required unlinks.
2882 int nof_unlinks = 0;
2883 for (int i = 0; i <= nof_escapes; i++) {
2884 shadows[i]->StopShadowing();
2885 if (shadows[i]->is_linked()) nof_unlinks++;
2886 }
2887
2888 // Unlink from try chain.
2889 // TOS contains code slot
2890 const int kNextOffset = StackHandlerConstants::kNextOffset +
2891 StackHandlerConstants::kAddressDisplacement;
2892 __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp
2893 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2894 __ str(r1, MemOperand(r3));
2895 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
2896 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
2897 // Code slot popped.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898 if (nof_unlinks > 0) __ b(&exit);
2899
2900 // Generate unlink code for all used shadow labels.
2901 for (int i = 0; i <= nof_escapes; i++) {
2902 if (shadows[i]->is_linked()) {
mads.s.ager31e71382008-08-13 09:32:07 +00002903 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 __ bind(shadows[i]);
2905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002906 // Reload sp from the top handler, because some statements that we
2907 // break from (eg, for...in) may have left stuff on the stack.
2908 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2909 __ ldr(sp, MemOperand(r3));
2910
2911 __ ldr(r1, MemOperand(sp, kNextOffset));
2912 __ str(r1, MemOperand(r3));
2913 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
2914 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
2915 // Code slot popped.
2916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917 __ b(shadows[i]->shadowed());
2918 }
2919 }
2920
2921 __ bind(&exit);
2922}
2923
2924
2925void ArmCodeGenerator::VisitTryFinally(TryFinally* node) {
2926 Comment cmnt(masm_, "[ TryFinally");
2927
2928 // State: Used to keep track of reason for entering the finally
2929 // block. Should probably be extended to hold information for
2930 // break/continue from within the try block.
2931 enum { FALLING, THROWING, JUMPING };
2932
2933 Label exit, unlink, try_block, finally_block;
2934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935 __ bl(&try_block);
2936
mads.s.ager31e71382008-08-13 09:32:07 +00002937 __ push(r0); // save exception object on the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002938 // In case of thrown exceptions, this is where we continue.
2939 __ mov(r2, Operand(Smi::FromInt(THROWING)));
2940 __ b(&finally_block);
2941
2942
2943 // --- Try block ---
2944 __ bind(&try_block);
2945
2946 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
2947
2948 // Introduce shadow labels for all escapes from the try block,
2949 // including returns. We should probably try to unify the escaping
2950 // labels and the return label.
2951 int nof_escapes = node->escaping_labels()->length();
2952 List<LabelShadow*> shadows(1 + nof_escapes);
2953 shadows.Add(new LabelShadow(&function_return_));
2954 for (int i = 0; i < nof_escapes; i++) {
2955 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
2956 }
2957
2958 // Generate code for the statements in the try block.
2959 VisitStatements(node->try_block()->statements());
2960
2961 // Stop the introduced shadowing and count the number of required
2962 // unlinks.
2963 int nof_unlinks = 0;
2964 for (int i = 0; i <= nof_escapes; i++) {
2965 shadows[i]->StopShadowing();
2966 if (shadows[i]->is_linked()) nof_unlinks++;
2967 }
2968
2969 // Set the state on the stack to FALLING.
mads.s.ager31e71382008-08-13 09:32:07 +00002970 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS
2971 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002972 __ mov(r2, Operand(Smi::FromInt(FALLING)));
2973 if (nof_unlinks > 0) __ b(&unlink);
2974
2975 // Generate code that sets the state for all used shadow labels.
2976 for (int i = 0; i <= nof_escapes; i++) {
2977 if (shadows[i]->is_linked()) {
2978 __ bind(shadows[i]);
mads.s.ager31e71382008-08-13 09:32:07 +00002979 if (shadows[i]->shadowed() == &function_return_) {
2980 __ push(r0); // Materialize the return value on the stack
2981 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002982 // Fake TOS for break and continue (not return).
mads.s.ager31e71382008-08-13 09:32:07 +00002983 __ mov(r0, Operand(Factory::undefined_value()));
2984 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985 }
2986 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
2987 __ b(&unlink);
2988 }
2989 }
2990
mads.s.ager31e71382008-08-13 09:32:07 +00002991 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992 __ bind(&unlink);
2993
mads.s.ager31e71382008-08-13 09:32:07 +00002994 __ pop(r0); // Store TOS in r0 across stack manipulation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002995 // Reload sp from the top handler, because some statements that we
2996 // break from (eg, for...in) may have left stuff on the stack.
2997 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2998 __ ldr(sp, MemOperand(r3));
2999 const int kNextOffset = StackHandlerConstants::kNextOffset +
3000 StackHandlerConstants::kAddressDisplacement;
3001 __ ldr(r1, MemOperand(sp, kNextOffset));
3002 __ str(r1, MemOperand(r3));
3003 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
3004 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
3005 // Code slot popped.
mads.s.ager31e71382008-08-13 09:32:07 +00003006 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007
3008 // --- Finally block ---
3009 __ bind(&finally_block);
3010
3011 // Push the state on the stack. If necessary move the state to a
3012 // local variable to avoid having extra values on the stack while
3013 // evaluating the finally block.
mads.s.ager31e71382008-08-13 09:32:07 +00003014 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003015 if (node->finally_var() != NULL) {
3016 Reference target(this, node->finally_var());
3017 SetValue(&target);
3018 ASSERT(target.size() == 0); // no extra stuff on the stack
mads.s.ager31e71382008-08-13 09:32:07 +00003019 __ pop(); // remove the extra avalue that was pushed above
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003020 }
3021
3022 // Generate code for the statements in the finally block.
3023 VisitStatements(node->finally_block()->statements());
3024
mads.s.ager31e71382008-08-13 09:32:07 +00003025 // Get the state from the stack - or the local variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026 if (node->finally_var() != NULL) {
3027 Reference target(this, node->finally_var());
3028 GetValue(&target);
3029 }
mads.s.ager31e71382008-08-13 09:32:07 +00003030 __ pop(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003031
mads.s.ager31e71382008-08-13 09:32:07 +00003032 __ pop(r0); // Restore value or faked TOS.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003033 // Generate code that jumps to the right destination for all used
3034 // shadow labels.
3035 for (int i = 0; i <= nof_escapes; i++) {
3036 if (shadows[i]->is_bound()) {
3037 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
3038 if (shadows[i]->shadowed() != &function_return_) {
3039 Label next;
3040 __ b(ne, &next);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003041 __ b(shadows[i]->shadowed());
3042 __ bind(&next);
3043 } else {
3044 __ b(eq, shadows[i]->shadowed());
3045 }
3046 }
3047 }
3048
3049 // Check if we need to rethrow the exception.
3050 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
3051 __ b(ne, &exit);
3052
3053 // Rethrow exception.
mads.s.ager31e71382008-08-13 09:32:07 +00003054 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003055 __ CallRuntime(Runtime::kReThrow, 1);
3056
3057 // Done.
3058 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059}
3060
3061
3062void ArmCodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
3063 Comment cmnt(masm_, "[ DebuggerStatament");
3064 if (FLAG_debug_info) RecordStatementPosition(node);
3065 __ CallRuntime(Runtime::kDebugBreak, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003066 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067}
3068
3069
3070void ArmCodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
3071 ASSERT(boilerplate->IsBoilerplate());
3072
3073 // Push the boilerplate on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003074 __ mov(r0, Operand(boilerplate));
3075 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076
3077 // Create a new closure.
mads.s.ager31e71382008-08-13 09:32:07 +00003078 __ push(cp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079 __ CallRuntime(Runtime::kNewClosure, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003080 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081}
3082
3083
3084void ArmCodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
3085 Comment cmnt(masm_, "[ FunctionLiteral");
3086
3087 // Build the function boilerplate and instantiate it.
3088 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
kasper.lund212ac232008-07-16 07:07:30 +00003089 // Check for stack-overflow exception.
3090 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 InstantiateBoilerplate(boilerplate);
3092}
3093
3094
3095void ArmCodeGenerator::VisitFunctionBoilerplateLiteral(
3096 FunctionBoilerplateLiteral* node) {
3097 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
3098 InstantiateBoilerplate(node->boilerplate());
3099}
3100
3101
3102void ArmCodeGenerator::VisitConditional(Conditional* node) {
3103 Comment cmnt(masm_, "[ Conditional");
3104 Label then, else_, exit;
3105 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
3106 Branch(false, &else_);
3107 __ bind(&then);
3108 Load(node->then_expression(), access());
3109 __ b(&exit);
3110 __ bind(&else_);
3111 Load(node->else_expression(), access());
3112 __ bind(&exit);
3113}
3114
3115
3116void ArmCodeGenerator::VisitSlot(Slot* node) {
3117 Comment cmnt(masm_, "[ Slot");
3118
3119 if (node->type() == Slot::LOOKUP) {
3120 ASSERT(node->var()->mode() == Variable::DYNAMIC);
3121
3122 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00003123 __ push(cp);
3124 __ mov(r0, Operand(node->var()->name()));
3125 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126
3127 switch (access()) {
3128 case CodeGenState::UNDEFINED:
3129 UNREACHABLE();
3130 break;
3131
3132 case CodeGenState::LOAD:
3133 __ CallRuntime(Runtime::kLoadContextSlot, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003134 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003135 break;
3136
3137 case CodeGenState::LOAD_TYPEOF_EXPR:
3138 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003139 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003140 break;
3141
3142 case CodeGenState::STORE:
3143 // Storing a variable must keep the (new) value on the stack. This
3144 // is necessary for compiling assignment expressions.
3145 __ CallRuntime(Runtime::kStoreContextSlot, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003146 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 // result (TOS) is the value that was stored
3148 break;
3149
3150 case CodeGenState::INIT_CONST:
3151 // Same as STORE but ignores attribute (e.g. READ_ONLY) of
3152 // context slot so that we can initialize const properties
3153 // (introduced via eval("const foo = (some expr);")). Also,
3154 // uses the current function context instead of the top
3155 // context.
3156 //
3157 // Note that we must declare the foo upon entry of eval(),
3158 // via a context slot declaration, but we cannot initialize
3159 // it at the same time, because the const declaration may
3160 // be at the end of the eval code (sigh...) and the const
3161 // variable may have been used before (where its value is
3162 // 'undefined'). Thus, we can only do the initialization
3163 // when we actually encounter the expression and when the
3164 // expression operands are defined and valid, and thus we
3165 // need the split into 2 operations: declaration of the
3166 // context slot followed by initialization.
3167 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003168 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003169 break;
3170 }
3171
3172 } else {
3173 // Note: We would like to keep the assert below, but it fires because
3174 // of some nasty code in LoadTypeofExpression() which should be removed...
3175 // ASSERT(node->var()->mode() != Variable::DYNAMIC);
3176
3177 switch (access()) {
3178 case CodeGenState::UNDEFINED:
3179 UNREACHABLE();
3180 break;
3181
3182 case CodeGenState::LOAD: // fall through
3183 case CodeGenState::LOAD_TYPEOF_EXPR:
3184 // Special handling for locals allocated in registers.
mads.s.ager31e71382008-08-13 09:32:07 +00003185 __ ldr(r0, SlotOperand(node, r2));
3186 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003187 if (node->var()->mode() == Variable::CONST) {
3188 // Const slots may contain 'the hole' value (the constant hasn't
3189 // been initialized yet) which needs to be converted into the
3190 // 'undefined' value.
3191 Comment cmnt(masm_, "[ Unhole const");
mads.s.ager31e71382008-08-13 09:32:07 +00003192 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193 __ cmp(r0, Operand(Factory::the_hole_value()));
3194 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
mads.s.ager31e71382008-08-13 09:32:07 +00003195 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003196 }
3197 break;
3198
3199 case CodeGenState::INIT_CONST: {
3200 ASSERT(node->var()->mode() == Variable::CONST);
3201 // Only the first const initialization must be executed (the slot
3202 // still contains 'the hole' value). When the assignment is executed,
3203 // the code is identical to a normal store (see below).
3204 { Comment cmnt(masm_, "[ Init const");
3205 Label L;
kasper.lund7276f142008-07-30 08:49:36 +00003206 __ ldr(r2, SlotOperand(node, r2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207 __ cmp(r2, Operand(Factory::the_hole_value()));
3208 __ b(ne, &L);
3209 // We must execute the store.
kasper.lund7276f142008-07-30 08:49:36 +00003210 // r2 may be loaded with context; used below in RecordWrite.
mads.s.ager31e71382008-08-13 09:32:07 +00003211 __ ldr(r0, MemOperand(sp, 0));
kasper.lund7276f142008-07-30 08:49:36 +00003212 __ str(r0, SlotOperand(node, r2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003213 if (node->type() == Slot::CONTEXT) {
3214 // Skip write barrier if the written value is a smi.
3215 Label exit;
3216 __ tst(r0, Operand(kSmiTagMask));
3217 __ b(eq, &exit);
3218 // r2 is loaded with context when calling SlotOperand above.
3219 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
3220 __ mov(r3, Operand(offset));
3221 __ RecordWrite(r2, r3, r1);
3222 __ bind(&exit);
3223 }
3224 __ bind(&L);
3225 }
3226 break;
3227 }
3228
3229 case CodeGenState::STORE: {
3230 // Storing a variable must keep the (new) value on the stack. This
3231 // is necessary for compiling assignment expressions.
3232 // Special handling for locals allocated in registers.
3233 //
3234 // Note: We will reach here even with node->var()->mode() ==
3235 // Variable::CONST because of const declarations which will
3236 // initialize consts to 'the hole' value and by doing so, end
3237 // up calling this code.
kasper.lund7276f142008-07-30 08:49:36 +00003238 // r2 may be loaded with context; used below in RecordWrite.
mads.s.ager31e71382008-08-13 09:32:07 +00003239 __ pop(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003240 __ str(r0, SlotOperand(node, r2));
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00003241 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003242 if (node->type() == Slot::CONTEXT) {
3243 // Skip write barrier if the written value is a smi.
3244 Label exit;
3245 __ tst(r0, Operand(kSmiTagMask));
3246 __ b(eq, &exit);
3247 // r2 is loaded with context when calling SlotOperand above.
3248 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
3249 __ mov(r3, Operand(offset));
3250 __ RecordWrite(r2, r3, r1);
3251 __ bind(&exit);
3252 }
3253 break;
3254 }
3255 }
3256 }
3257}
3258
3259
3260void ArmCodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) {
3261 Comment cmnt(masm_, "[ VariableProxy");
3262 Variable* node = proxy_node->var();
3263
3264 Expression* x = node->rewrite();
3265 if (x != NULL) {
3266 Visit(x);
3267 return;
3268 }
3269
3270 ASSERT(node->is_global());
3271 if (is_referenced()) {
3272 if (node->AsProperty() != NULL) {
3273 __ RecordPosition(node->AsProperty()->position());
3274 }
3275 AccessReferenceProperty(new Literal(node->name()), access());
3276
3277 } else {
3278 // All stores are through references.
3279 ASSERT(access() != CodeGenState::STORE);
3280 Reference property(this, proxy_node);
3281 GetValue(&property);
3282 }
3283}
3284
3285
3286void ArmCodeGenerator::VisitLiteral(Literal* node) {
3287 Comment cmnt(masm_, "[ Literal");
mads.s.ager31e71382008-08-13 09:32:07 +00003288 __ mov(r0, Operand(node->handle()));
3289 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290}
3291
3292
3293void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
3294 Comment cmnt(masm_, "[ RexExp Literal");
3295
3296 // Retrieve the literal array and check the allocated entry.
3297
3298 // Load the function of this activation.
3299 __ ldr(r1, MemOperand(pp, 0));
3300
3301 // Load the literals array of the function.
3302 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
3303
3304 // Load the literal at the ast saved index.
3305 int literal_offset =
3306 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3307 __ ldr(r2, FieldMemOperand(r1, literal_offset));
3308
3309 Label done;
3310 __ cmp(r2, Operand(Factory::undefined_value()));
3311 __ b(ne, &done);
3312
3313 // If the entry is undefined we call the runtime system to computed
3314 // the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00003315 __ push(r1); // literal array (0)
3316 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
3317 __ push(r0); // literal index (1)
3318 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
3319 __ push(r0);
3320 __ mov(r0, Operand(node->flags())); // RegExp flags (3)
3321 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003322 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003323 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324
mads.s.ager31e71382008-08-13 09:32:07 +00003325 __ bind(&done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003326 // Push the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00003327 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003328}
3329
3330
3331// This deferred code stub will be used for creating the boilerplate
3332// by calling Runtime_CreateObjectLiteral.
3333// Each created boilerplate is stored in the JSFunction and they are
3334// therefore context dependent.
3335class ObjectLiteralDeferred: public DeferredCode {
3336 public:
3337 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node)
3338 : DeferredCode(generator), node_(node) {
3339 set_comment("[ ObjectLiteralDeferred");
3340 }
3341 virtual void Generate();
3342 private:
3343 ObjectLiteral* node_;
3344};
3345
3346
3347void ObjectLiteralDeferred::Generate() {
3348 // If the entry is undefined we call the runtime system to computed
3349 // the literal.
3350
3351 // Literal array (0).
mads.s.ager31e71382008-08-13 09:32:07 +00003352 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 // Literal index (1).
mads.s.ager31e71382008-08-13 09:32:07 +00003354 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
3355 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356 // Constant properties (2).
mads.s.ager31e71382008-08-13 09:32:07 +00003357 __ mov(r0, Operand(node_->constant_properties()));
3358 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003360 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361}
3362
3363
3364void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
3365 Comment cmnt(masm_, "[ ObjectLiteral");
3366
3367 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
3368
3369 // Retrieve the literal array and check the allocated entry.
3370
3371 // Load the function of this activation.
3372 __ ldr(r1, MemOperand(pp, 0));
3373
3374 // Load the literals array of the function.
3375 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
3376
3377 // Load the literal at the ast saved index.
3378 int literal_offset =
3379 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3380 __ ldr(r2, FieldMemOperand(r1, literal_offset));
3381
3382 // Check whether we need to materialize the object literal boilerplate.
3383 // If so, jump to the deferred code.
3384 __ cmp(r2, Operand(Factory::undefined_value()));
3385 __ b(eq, deferred->enter());
3386 __ bind(deferred->exit());
3387
3388 // Push the object literal boilerplate.
mads.s.ager31e71382008-08-13 09:32:07 +00003389 __ push(r2);
3390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 // Clone the boilerplate object.
3392 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003393 __ push(r0); // save the result
3394 // r0: cloned object literal
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395
3396 for (int i = 0; i < node->properties()->length(); i++) {
3397 ObjectLiteral::Property* property = node->properties()->at(i);
3398 Literal* key = property->key();
3399 Expression* value = property->value();
3400 switch (property->kind()) {
3401 case ObjectLiteral::Property::CONSTANT: break;
3402 case ObjectLiteral::Property::COMPUTED: // fall through
3403 case ObjectLiteral::Property::PROTOTYPE: {
mads.s.ager31e71382008-08-13 09:32:07 +00003404 __ push(r0); // dup the result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 Load(key);
3406 Load(value);
3407 __ CallRuntime(Runtime::kSetProperty, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003408 // restore r0
3409 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 break;
3411 }
3412 case ObjectLiteral::Property::SETTER: {
3413 __ push(r0);
3414 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00003415 __ mov(r0, Operand(Smi::FromInt(1)));
3416 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 Load(value);
3418 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003419 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420 break;
3421 }
3422 case ObjectLiteral::Property::GETTER: {
3423 __ push(r0);
3424 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00003425 __ mov(r0, Operand(Smi::FromInt(0)));
3426 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427 Load(value);
3428 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003429 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 break;
3431 }
3432 }
3433 }
3434}
3435
3436
3437void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
3438 Comment cmnt(masm_, "[ ArrayLiteral");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003439
3440 // Call runtime to create the array literal.
3441 __ mov(r0, Operand(node->literals()));
3442 __ push(r0);
3443 // TODO(1332579): The second argument to CreateArrayLiteral is
3444 // supposed to be the literals array of the function of this frame.
3445 // Until the new ARM calling convention is in place, that function
3446 // is not always available. Therefore, on ARM we pass in the hole
3447 // until the new calling convention is in place.
3448 __ mov(r0, Operand(Factory::the_hole_value()));
3449 __ push(r0);
3450 __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
3451
3452 // Push the resulting array literal on the stack.
3453 __ push(r0);
3454
3455 // Generate code to set the elements in the array that are not
3456 // literals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 for (int i = 0; i < node->values()->length(); i++) {
3458 Expression* value = node->values()->at(i);
3459
3460 // If value is literal the property value is already
3461 // set in the boilerplate object.
3462 if (value->AsLiteral() == NULL) {
3463 // The property must be set by generated code.
3464 Load(value);
mads.s.ager31e71382008-08-13 09:32:07 +00003465 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
3467 // Fetch the object literal
3468 __ ldr(r1, MemOperand(sp, 0));
3469 // Get the elements array.
3470 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
3471
3472 // Write to the indexed properties array.
3473 int offset = i * kPointerSize + Array::kHeaderSize;
3474 __ str(r0, FieldMemOperand(r1, offset));
3475
3476 // Update the write barrier for the array address.
3477 __ mov(r3, Operand(offset));
3478 __ RecordWrite(r1, r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479 }
3480 }
3481}
3482
3483
3484void ArmCodeGenerator::VisitAssignment(Assignment* node) {
3485 Comment cmnt(masm_, "[ Assignment");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 if (FLAG_debug_info) RecordStatementPosition(node);
mads.s.ager31e71382008-08-13 09:32:07 +00003487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 Reference target(this, node->target());
3489 if (target.is_illegal()) return;
3490
3491 if (node->op() == Token::ASSIGN ||
3492 node->op() == Token::INIT_VAR ||
3493 node->op() == Token::INIT_CONST) {
3494 Load(node->value());
3495
3496 } else {
3497 GetValue(&target);
3498 Literal* literal = node->value()->AsLiteral();
3499 if (literal != NULL && literal->handle()->IsSmi()) {
3500 SmiOperation(node->binary_op(), literal->handle(), false);
mads.s.ager31e71382008-08-13 09:32:07 +00003501 __ push(r0);
3502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003503 } else {
3504 Load(node->value());
kasper.lund7276f142008-07-30 08:49:36 +00003505 GenericBinaryOperation(node->binary_op());
mads.s.ager31e71382008-08-13 09:32:07 +00003506 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003507 }
3508 }
3509
3510 Variable* var = node->target()->AsVariableProxy()->AsVariable();
3511 if (var != NULL &&
3512 (var->mode() == Variable::CONST) &&
3513 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
3514 // Assignment ignored - leave the value on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516 } else {
3517 __ RecordPosition(node->position());
3518 if (node->op() == Token::INIT_CONST) {
3519 // Dynamic constant initializations must use the function context
3520 // and initialize the actual constant declared. Dynamic variable
3521 // initializations are simply assignments and use SetValue.
3522 InitConst(&target);
3523 } else {
3524 SetValue(&target);
3525 }
3526 }
3527}
3528
3529
3530void ArmCodeGenerator::VisitThrow(Throw* node) {
3531 Comment cmnt(masm_, "[ Throw");
3532
3533 Load(node->exception());
3534 __ RecordPosition(node->position());
3535 __ CallRuntime(Runtime::kThrow, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003536 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537}
3538
3539
3540void ArmCodeGenerator::VisitProperty(Property* node) {
3541 Comment cmnt(masm_, "[ Property");
3542 if (is_referenced()) {
3543 __ RecordPosition(node->position());
3544 AccessReferenceProperty(node->key(), access());
mads.s.ager31e71382008-08-13 09:32:07 +00003545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 } else {
3547 // All stores are through references.
3548 ASSERT(access() != CodeGenState::STORE);
3549 Reference property(this, node);
3550 __ RecordPosition(node->position());
3551 GetValue(&property);
3552 }
3553}
3554
3555
3556void ArmCodeGenerator::VisitCall(Call* node) {
3557 Comment cmnt(masm_, "[ Call");
3558
3559 ZoneList<Expression*>* args = node->arguments();
3560
3561 if (FLAG_debug_info) RecordStatementPosition(node);
3562 // Standard function call.
3563
3564 // Check if the function is a variable or a property.
3565 Expression* function = node->expression();
3566 Variable* var = function->AsVariableProxy()->AsVariable();
3567 Property* property = function->AsProperty();
3568
3569 // ------------------------------------------------------------------------
3570 // Fast-case: Use inline caching.
3571 // ---
3572 // According to ECMA-262, section 11.2.3, page 44, the function to call
3573 // must be resolved after the arguments have been evaluated. The IC code
3574 // automatically handles this by loading the arguments before the function
3575 // is resolved in cache misses (this also holds for megamorphic calls).
3576 // ------------------------------------------------------------------------
3577
3578 if (var != NULL && !var->is_this() && var->is_global()) {
3579 // ----------------------------------
3580 // JavaScript example: 'foo(1, 2, 3)' // foo is global
3581 // ----------------------------------
3582
3583 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003584 __ mov(r0, Operand(var->name()));
3585 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 LoadGlobal();
3587
3588 // Load the arguments.
3589 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590
3591 // Setup the receiver register and call the IC initialization code.
3592 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593 __ RecordPosition(node->position());
3594 __ Call(stub, code_target_context);
3595 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003597 __ pop();
3598 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599
3600 } else if (var != NULL && var->slot() != NULL &&
3601 var->slot()->type() == Slot::LOOKUP) {
3602 // ----------------------------------
3603 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
3604 // ----------------------------------
3605
3606 // Load the function
mads.s.ager31e71382008-08-13 09:32:07 +00003607 __ push(cp);
3608 __ mov(r0, Operand(var->name()));
3609 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 __ CallRuntime(Runtime::kLoadContextSlot, 2);
3611 // r0: slot value; r1: receiver
3612
3613 // Load the receiver.
mads.s.ager31e71382008-08-13 09:32:07 +00003614 __ push(r0); // function
3615 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616
3617 // Call the function.
3618 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003619 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620
3621 } else if (property != NULL) {
3622 // Check if the key is a literal string.
3623 Literal* literal = property->key()->AsLiteral();
3624
3625 if (literal != NULL && literal->handle()->IsSymbol()) {
3626 // ------------------------------------------------------------------
3627 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
3628 // ------------------------------------------------------------------
3629
3630 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003631 __ mov(r0, Operand(literal->handle()));
3632 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 Load(property->obj());
3634
3635 // Load the arguments.
3636 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637
3638 // Set the receiver register and call the IC initialization code.
3639 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 __ RecordPosition(node->position());
3641 __ Call(stub, code_target);
3642 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3643
3644 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003645 __ pop();
3646
3647 __ push(r0); // push after get rid of function from the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648
3649 } else {
3650 // -------------------------------------------
3651 // JavaScript example: 'array[index](1, 2, 3)'
3652 // -------------------------------------------
3653
3654 // Load the function to call from the property through a reference.
3655 Reference ref(this, property);
mads.s.ager31e71382008-08-13 09:32:07 +00003656 GetValue(&ref); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003657
3658 // Pass receiver to called function.
mads.s.ager31e71382008-08-13 09:32:07 +00003659 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
3660 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 // Call the function.
3662 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003663 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 }
3665
3666 } else {
3667 // ----------------------------------
3668 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
3669 // ----------------------------------
3670
3671 // Load the function.
3672 Load(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 // Pass the global object as the receiver.
3674 LoadGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 // Call the function.
3676 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003677 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678 }
3679}
3680
3681
3682void ArmCodeGenerator::VisitCallNew(CallNew* node) {
3683 Comment cmnt(masm_, "[ CallNew");
3684
3685 // According to ECMA-262, section 11.2.2, page 44, the function
3686 // expression in new calls must be evaluated before the
3687 // arguments. This is different from ordinary calls, where the
3688 // actual function to call is resolved after the arguments have been
3689 // evaluated.
3690
3691 // Compute function to call and use the global object as the
3692 // receiver.
3693 Load(node->expression());
3694 LoadGlobal();
3695
3696 // Push the arguments ("left-to-right") on the stack.
3697 ZoneList<Expression*>* args = node->arguments();
3698 for (int i = 0; i < args->length(); i++) Load(args->at(i));
3699
mads.s.ager31e71382008-08-13 09:32:07 +00003700 // r0: the number of arguments.
3701 __ mov(r0, Operand(args->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702
3703 // Call the construct call builtin that handles allocation and
3704 // constructor invocation.
3705 __ RecordPosition(position);
3706 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
3707 js_construct_call);
mads.s.ager31e71382008-08-13 09:32:07 +00003708
3709 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
3710 __ str(r0, MemOperand(sp, 0 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711}
3712
3713
3714void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) {
3715 ASSERT(args->length() == 1);
3716 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003717 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003718 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3719}
3720
3721
3722void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) {
3723 ASSERT(args->length() == 0);
mads.s.ager31e71382008-08-13 09:32:07 +00003724 __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3725 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726}
3727
3728
3729void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) {
3730 ASSERT(args->length() == 1);
3731 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003732 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003733 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kReceiverOffset));
3734}
3735
3736
3737void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) {
3738 ASSERT(args->length() == 1);
3739 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003740 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
3742 __ str(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003743 __ mov(r0, Operand(Smi::FromInt(0))); // return a meaningful value
3744 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745}
3746
3747
3748void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) {
3749 ASSERT(args->length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
3751 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00003752 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753}
3754
3755
3756void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
3757 ASSERT(args->length() == 1);
3758 Label leave;
3759 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003760 __ pop(r0); // r0 contains object.
3761 // if (object->IsSmi()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 __ tst(r0, Operand(kSmiTagMask));
3763 __ b(eq, &leave);
3764 // It is a heap object - get map.
3765 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3766 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003767 // if (!object->IsJSValue()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 __ cmp(r1, Operand(JS_VALUE_TYPE));
3769 __ b(ne, &leave);
3770 // Load the value.
3771 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
3772 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00003773 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
3777void ArmCodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
3778 ASSERT(args->length() == 2);
3779 Label leave;
3780 Load(args->at(0)); // Load the object.
3781 Load(args->at(1)); // Load the value.
mads.s.ager31e71382008-08-13 09:32:07 +00003782 __ pop(r0); // r0 contains value
3783 __ pop(r1); // r1 contains object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 // if (object->IsSmi()) return object.
3785 __ tst(r1, Operand(kSmiTagMask));
3786 __ b(eq, &leave);
3787 // It is a heap object - get map.
3788 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3789 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3790 // if (!object->IsJSValue()) return object.
3791 __ cmp(r2, Operand(JS_VALUE_TYPE));
3792 __ b(ne, &leave);
3793 // Store the value.
3794 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
3795 // Update the write barrier.
3796 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
3797 __ RecordWrite(r1, r2, r3);
3798 // Leave.
3799 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00003800 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003801}
3802
3803
3804void ArmCodeGenerator::GenerateTailCallWithArguments(
3805 ZoneList<Expression*>* args) {
3806 // r0 = number of arguments (smi)
3807 ASSERT(args->length() == 1);
3808 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003809 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003810 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
3811
3812 // r1 = new function (previously written to stack)
3813 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3814
3815 // Reset parameter pointer and frame pointer to previous frame
kasper.lund7276f142008-07-30 08:49:36 +00003816 ExitJSFrame(DO_NOT_RETURN);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003817
3818 // Jump (tail-call) to the function in register r1.
3819 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
3820 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3821 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
3822 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823}
3824
3825
3826void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) {
3827 ASSERT(args->length() == 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003828 // r0 = args[i]; r1 = i
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829 Comment cmnt(masm_, "[ GenerateSetArgument");
mads.s.ager31e71382008-08-13 09:32:07 +00003830 Load(args->at(1)); // args[i] (value)
3831 Load(args->at(0)); // i
3832 __ pop(r1); // i
3833 __ pop(r0); // value
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834#if defined(DEBUG)
3835 { Label L;
mads.s.ager31e71382008-08-13 09:32:07 +00003836 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003837 __ b(eq, &L);
3838 __ stop("SMI expected");
3839 __ bind(&L);
3840 }
3841#endif // defined(DEBUG)
3842 __ add(r2, pp, Operand(JavaScriptFrameConstants::kParam0Offset));
mads.s.ager31e71382008-08-13 09:32:07 +00003843 __ str(r0,
3844 MemOperand(r2, r1, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset));
3845 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003846}
3847
3848
3849void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) {
3850 ASSERT(args->length() == 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003851 Load(args->at(0)); // old number of arguments
3852 Load(args->at(1)); // new number of arguments, r1 > r0
3853 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003854 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00003855 __ pop(r1);
3856 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857 // r1 = number of words to move stack.
3858 __ sub(r1, r1, Operand(r0));
3859 // r2 is source.
3860 __ add(r2, fp, Operand(StandardFrameConstants::kCallerPCOffset));
3861 // Move down frame pointer fp.
3862 __ add(fp, fp, Operand(r1, LSL, kPointerSizeLog2));
3863 // r1 is destination.
3864 __ add(r1, fp, Operand(StandardFrameConstants::kCallerPCOffset));
3865
3866 Label move;
3867 __ bind(&move);
3868 __ ldr(r3, MemOperand(r2, -kPointerSize, PostIndex));
3869 __ str(r3, MemOperand(r1, -kPointerSize, PostIndex));
3870 __ cmp(r2, Operand(sp));
3871 __ b(ne, &move);
3872 __ ldr(r3, MemOperand(r2));
3873 __ str(r3, MemOperand(r1));
3874
3875 // Move down stack pointer esp.
3876 __ mov(sp, Operand(r1));
mads.s.ager31e71382008-08-13 09:32:07 +00003877 // Put something GC-able in r0.
3878 __ mov(r0, Operand(Smi::FromInt(0)));
3879 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880}
3881
3882
3883void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) {
3884 ASSERT(args->length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 Load(args->at(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003887 __ pop(r0); // new number of arguments
3888 __ pop(r1); // old number of arguments, r1 > r0
3889 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
3890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003891 // r1 = number of words to move stack.
3892 __ sub(r1, r1, Operand(r0, LSR, kSmiTagSize));
3893 Label end_of_expand_frame;
3894 if (FLAG_check_stack) {
3895 Label not_too_big;
3896 __ sub(r2, sp, Operand(r1, LSL, kPointerSizeLog2));
3897 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
3898 __ ldr(ip, MemOperand(ip));
3899 __ cmp(r2, Operand(ip));
3900 __ b(gt, &not_too_big);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 __ mov(r0, Operand(Factory::false_value()));
3902 __ b(&end_of_expand_frame);
3903 __ bind(&not_too_big);
3904 }
3905 // r3 is source.
3906 __ mov(r3, Operand(sp));
3907 // r0 is copy limit + 1 word
3908 __ add(r0, fp,
3909 Operand(StandardFrameConstants::kCallerPCOffset + kPointerSize));
3910 // Move up frame pointer fp.
3911 __ sub(fp, fp, Operand(r1, LSL, kPointerSizeLog2));
3912 // Move up stack pointer sp.
3913 __ sub(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
3914 // r1 is destination (r1 = source - r1).
3915 __ mov(r2, Operand(0));
3916 __ sub(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
3917 __ add(r1, r3, Operand(r2));
3918
3919 Label move;
3920 __ bind(&move);
3921 __ ldr(r2, MemOperand(r3, kPointerSize, PostIndex));
3922 __ str(r2, MemOperand(r1, kPointerSize, PostIndex));
3923 __ cmp(r3, Operand(r0));
3924 __ b(ne, &move);
3925
mads.s.ager31e71382008-08-13 09:32:07 +00003926 // Put success value in top of stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927 __ mov(r0, Operand(Factory::true_value()));
3928 __ bind(&end_of_expand_frame);
mads.s.ager31e71382008-08-13 09:32:07 +00003929 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003930}
3931
3932
3933void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
3934 ASSERT(args->length() == 1);
3935 Load(args->at(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003936 __ pop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003937 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 cc_reg_ = eq;
3939}
3940
3941
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00003942void ArmCodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
3943 ASSERT(args->length() == 1);
3944 Load(args->at(0));
3945 __ pop(r0);
3946 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
3947 cc_reg_ = eq;
3948}
3949
3950
3951
kasper.lund7276f142008-07-30 08:49:36 +00003952// This should generate code that performs a charCodeAt() call or returns
3953// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3954// It is not yet implemented on ARM, so it always goes to the slow case.
3955void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
3956 ASSERT(args->length() == 2);
kasper.lund7276f142008-07-30 08:49:36 +00003957 __ mov(r0, Operand(Factory::undefined_value()));
mads.s.ager31e71382008-08-13 09:32:07 +00003958 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003959}
3960
3961
3962
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963// This is used in the implementation of apply on ia32 but it is not
3964// used on ARM yet.
3965void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
kasper.lund7276f142008-07-30 08:49:36 +00003966 __ stop("ArmCodeGenerator::GenerateIsArray");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 cc_reg_ = eq;
3968}
3969
3970
3971void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3972 ASSERT(args->length() == 0);
3973
mads.s.ager31e71382008-08-13 09:32:07 +00003974 // Seed the result with the formal parameters count, which will be used
3975 // in case no arguments adaptor frame is found below the current frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
3977
3978 // Call the shared stub to get to the arguments.length.
3979 ArgumentsAccessStub stub(true);
3980 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003981 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982}
3983
3984
3985void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3986 ASSERT(args->length() == 1);
3987
3988 // Load the key onto the stack and set register r1 to the formal
3989 // parameters count for the currently executing function.
3990 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003991 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 __ mov(r1, Operand(Smi::FromInt(scope_->num_parameters())));
3993
3994 // Call the shared stub to get to arguments[key].
3995 ArgumentsAccessStub stub(false);
3996 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003997 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998}
3999
4000
4001void ArmCodeGenerator::GenerateShiftDownAndTailCall(
4002 ZoneList<Expression*>* args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004003 // r0 = number of arguments
4004 ASSERT(args->length() == 1);
4005 Load(args->at(0));
4006 __ pop(r0);
4007 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008
mads.s.ager31e71382008-08-13 09:32:07 +00004009 // Get the 'this' function and exit the frame without returning.
4010 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
4011 ExitJSFrame(DO_NOT_RETURN);
4012 // return address in lr
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013
mads.s.ager31e71382008-08-13 09:32:07 +00004014 // Move arguments one element down the stack.
4015 Label move;
4016 Label moved;
4017 __ sub(r2, r0, Operand(0), SetCC);
4018 __ b(eq, &moved);
4019 __ bind(&move);
4020 __ sub(ip, r2, Operand(1));
4021 __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2));
4022 __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2));
4023 __ sub(r2, r2, Operand(1), SetCC);
4024 __ b(ne, &move);
4025 __ bind(&moved);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026
mads.s.ager31e71382008-08-13 09:32:07 +00004027 // Remove the TOS (copy of last argument)
4028 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029
mads.s.ager31e71382008-08-13 09:32:07 +00004030 // Jump (tail-call) to the function in register r1.
4031 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
4032 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
4033 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
4034 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
4035
4036 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037}
4038
4039
4040void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) {
4041 if (CheckForInlineRuntimeCall(node))
4042 return;
4043
4044 ZoneList<Expression*>* args = node->arguments();
4045 Comment cmnt(masm_, "[ CallRuntime");
4046 Runtime::Function* function = node->function();
4047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 if (function != NULL) {
mads.s.ager31e71382008-08-13 09:32:07 +00004049 // Push the arguments ("left-to-right").
4050 for (int i = 0; i < args->length(); i++) Load(args->at(i));
4051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 // Call the C runtime function.
4053 __ CallRuntime(function, args->length());
mads.s.ager31e71382008-08-13 09:32:07 +00004054 __ push(r0);
4055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00004057 // Prepare stack for calling JS runtime function.
4058 __ mov(r0, Operand(node->name()));
4059 __ push(r0);
4060 // Push the builtins object found in the current global object.
4061 __ ldr(r1, GlobalObject());
4062 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
4063 __ push(r0);
4064
4065 for (int i = 0; i < args->length(); i++) Load(args->at(i));
4066
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 // Call the JS runtime function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 Handle<Code> stub = ComputeCallInitialize(args->length());
4069 __ Call(stub, code_target);
4070 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00004071 __ pop();
4072 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
4074}
4075
4076
4077void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
4078 Comment cmnt(masm_, "[ UnaryOperation");
4079
4080 Token::Value op = node->op();
4081
4082 if (op == Token::NOT) {
4083 LoadCondition(node->expression(),
4084 CodeGenState::LOAD,
4085 false_target(),
4086 true_target(),
4087 true);
4088 cc_reg_ = NegateCondition(cc_reg_);
4089
4090 } else if (op == Token::DELETE) {
4091 Property* property = node->expression()->AsProperty();
mads.s.ager31e71382008-08-13 09:32:07 +00004092 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 if (property != NULL) {
4094 Load(property->obj());
4095 Load(property->key());
mads.s.ager31e71382008-08-13 09:32:07 +00004096 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098
mads.s.ager31e71382008-08-13 09:32:07 +00004099 } else if (variable != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 Slot* slot = variable->slot();
4101 if (variable->is_global()) {
4102 LoadGlobal();
mads.s.ager31e71382008-08-13 09:32:07 +00004103 __ mov(r0, Operand(variable->name()));
4104 __ push(r0);
4105 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107
4108 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
4109 // lookup the context holding the named variable
mads.s.ager31e71382008-08-13 09:32:07 +00004110 __ push(cp);
4111 __ mov(r0, Operand(variable->name()));
4112 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 __ CallRuntime(Runtime::kLookupContext, 2);
4114 // r0: context
mads.s.ager31e71382008-08-13 09:32:07 +00004115 __ push(r0);
4116 __ mov(r0, Operand(variable->name()));
4117 __ push(r0);
4118 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120
mads.s.ager31e71382008-08-13 09:32:07 +00004121 } else {
4122 // Default: Result of deleting non-global, not dynamically
4123 // introduced variables is false.
4124 __ mov(r0, Operand(Factory::false_value()));
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
4127 } else {
4128 // Default: Result of deleting expressions is true.
4129 Load(node->expression()); // may have side-effects
mads.s.ager31e71382008-08-13 09:32:07 +00004130 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 __ mov(r0, Operand(Factory::true_value()));
4132 }
mads.s.ager31e71382008-08-13 09:32:07 +00004133 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134
4135 } else if (op == Token::TYPEOF) {
4136 // Special case for loading the typeof expression; see comment on
4137 // LoadTypeofExpression().
4138 LoadTypeofExpression(node->expression());
4139 __ CallRuntime(Runtime::kTypeof, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00004140 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141
4142 } else {
4143 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004144 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 switch (op) {
4146 case Token::NOT:
4147 case Token::DELETE:
4148 case Token::TYPEOF:
4149 UNREACHABLE(); // handled above
4150 break;
4151
4152 case Token::SUB: {
4153 UnarySubStub stub;
4154 __ CallStub(&stub);
4155 break;
4156 }
4157
4158 case Token::BIT_NOT: {
4159 // smi check
4160 Label smi_label;
4161 Label continue_label;
4162 __ tst(r0, Operand(kSmiTagMask));
4163 __ b(eq, &smi_label);
4164
mads.s.ager31e71382008-08-13 09:32:07 +00004165 __ push(r0);
4166 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 __ InvokeBuiltin("BIT_NOT", 0, CALL_JS);
4168
4169 __ b(&continue_label);
4170 __ bind(&smi_label);
4171 __ mvn(r0, Operand(r0));
4172 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
4173 __ bind(&continue_label);
4174 break;
4175 }
4176
4177 case Token::VOID:
4178 // since the stack top is cached in r0, popping and then
4179 // pushing a value can be done by just writing to r0.
4180 __ mov(r0, Operand(Factory::undefined_value()));
4181 break;
4182
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004183 case Token::ADD: {
4184 // Smi check.
4185 Label continue_label;
4186 __ tst(r0, Operand(kSmiTagMask));
4187 __ b(eq, &continue_label);
mads.s.ager31e71382008-08-13 09:32:07 +00004188 __ push(r0);
4189 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 __ InvokeBuiltin("TO_NUMBER", 0, CALL_JS);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004191 __ bind(&continue_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 default:
4195 UNREACHABLE();
4196 }
mads.s.ager31e71382008-08-13 09:32:07 +00004197 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 }
4199}
4200
4201
4202void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
4203 Comment cmnt(masm_, "[ CountOperation");
4204
4205 bool is_postfix = node->is_postfix();
4206 bool is_increment = node->op() == Token::INC;
4207
4208 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
4209 bool is_const = (var != NULL && var->mode() == Variable::CONST);
4210
4211 // Postfix: Make room for the result.
mads.s.ager31e71382008-08-13 09:32:07 +00004212 if (is_postfix) {
4213 __ mov(r0, Operand(0));
4214 __ push(r0);
4215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216
4217 { Reference target(this, node->expression());
4218 if (target.is_illegal()) return;
4219 GetValue(&target);
mads.s.ager31e71382008-08-13 09:32:07 +00004220 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
4222 Label slow, exit;
4223
4224 // Load the value (1) into register r1.
4225 __ mov(r1, Operand(Smi::FromInt(1)));
4226
4227 // Check for smi operand.
4228 __ tst(r0, Operand(kSmiTagMask));
4229 __ b(ne, &slow);
4230
4231 // Postfix: Store the old value as the result.
4232 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4233
4234 // Perform optimistic increment/decrement.
4235 if (is_increment) {
4236 __ add(r0, r0, Operand(r1), SetCC);
4237 } else {
4238 __ sub(r0, r0, Operand(r1), SetCC);
4239 }
4240
4241 // If the increment/decrement didn't overflow, we're done.
4242 __ b(vc, &exit);
4243
4244 // Revert optimistic increment/decrement.
4245 if (is_increment) {
4246 __ sub(r0, r0, Operand(r1));
4247 } else {
4248 __ add(r0, r0, Operand(r1));
4249 }
4250
4251 // Slow case: Convert to number.
4252 __ bind(&slow);
4253
4254 // Postfix: Convert the operand to a number and store it as the result.
4255 if (is_postfix) {
4256 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
4257 __ CallStub(&stub);
4258 // Store to result (on the stack).
4259 __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4260 }
4261
4262 // Compute the new value by calling the right JavaScript native.
4263 if (is_increment) {
4264 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
4265 __ CallStub(&stub);
4266 } else {
4267 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
4268 __ CallStub(&stub);
4269 }
4270
4271 // Store the new value in the target if not const.
4272 __ bind(&exit);
mads.s.ager31e71382008-08-13 09:32:07 +00004273 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274 if (!is_const) SetValue(&target);
4275 }
4276
4277 // Postfix: Discard the new value and use the old.
4278 if (is_postfix) __ pop(r0);
4279}
4280
4281
4282void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
4283 Comment cmnt(masm_, "[ BinaryOperation");
4284 Token::Value op = node->op();
4285
4286 // According to ECMA-262 section 11.11, page 58, the binary logical
4287 // operators must yield the result of one of the two expressions
4288 // before any ToBoolean() conversions. This means that the value
4289 // produced by a && or || operator is not necessarily a boolean.
4290
4291 // NOTE: If the left hand side produces a materialized value (not in
4292 // the CC register), we force the right hand side to do the
4293 // same. This is necessary because we may have to branch to the exit
4294 // after evaluating the left hand side (due to the shortcut
4295 // semantics), but the compiler must (statically) know if the result
4296 // of compiling the binary operation is materialized or not.
4297
4298 if (op == Token::AND) {
4299 Label is_true;
4300 LoadCondition(node->left(),
4301 CodeGenState::LOAD,
4302 &is_true,
4303 false_target(),
4304 false);
4305 if (has_cc()) {
4306 Branch(false, false_target());
4307
4308 // Evaluate right side expression.
4309 __ bind(&is_true);
4310 LoadCondition(node->right(),
4311 CodeGenState::LOAD,
4312 true_target(),
4313 false_target(),
4314 false);
4315
4316 } else {
4317 Label pop_and_continue, exit;
4318
mads.s.ager31e71382008-08-13 09:32:07 +00004319 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
4320 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 // Avoid popping the result if it converts to 'false' using the
4322 // standard ToBoolean() conversion as described in ECMA-262,
4323 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004324 ToBoolean(&pop_and_continue, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325 Branch(false, &exit);
4326
4327 // Pop the result of evaluating the first part.
4328 __ bind(&pop_and_continue);
4329 __ pop(r0);
4330
4331 // Evaluate right side expression.
4332 __ bind(&is_true);
4333 Load(node->right());
4334
4335 // Exit (always with a materialized value).
4336 __ bind(&exit);
4337 }
4338
4339 } else if (op == Token::OR) {
4340 Label is_false;
4341 LoadCondition(node->left(),
4342 CodeGenState::LOAD,
4343 true_target(),
4344 &is_false,
4345 false);
4346 if (has_cc()) {
4347 Branch(true, true_target());
4348
4349 // Evaluate right side expression.
4350 __ bind(&is_false);
4351 LoadCondition(node->right(),
4352 CodeGenState::LOAD,
4353 true_target(),
4354 false_target(),
4355 false);
4356
4357 } else {
4358 Label pop_and_continue, exit;
4359
mads.s.ager31e71382008-08-13 09:32:07 +00004360 __ ldr(r0, MemOperand(sp, 0));
4361 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362 // Avoid popping the result if it converts to 'true' using the
4363 // standard ToBoolean() conversion as described in ECMA-262,
4364 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004365 ToBoolean(&exit, &pop_and_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004366 Branch(true, &exit);
4367
4368 // Pop the result of evaluating the first part.
4369 __ bind(&pop_and_continue);
4370 __ pop(r0);
4371
4372 // Evaluate right side expression.
4373 __ bind(&is_false);
4374 Load(node->right());
4375
4376 // Exit (always with a materialized value).
4377 __ bind(&exit);
4378 }
4379
4380 } else {
4381 // Optimize for the case where (at least) one of the expressions
4382 // is a literal small integer.
4383 Literal* lliteral = node->left()->AsLiteral();
4384 Literal* rliteral = node->right()->AsLiteral();
4385
4386 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
4387 Load(node->left());
4388 SmiOperation(node->op(), rliteral->handle(), false);
4389
4390 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
4391 Load(node->right());
4392 SmiOperation(node->op(), lliteral->handle(), true);
4393
4394 } else {
4395 Load(node->left());
4396 Load(node->right());
kasper.lund7276f142008-07-30 08:49:36 +00004397 GenericBinaryOperation(node->op());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398 }
mads.s.ager31e71382008-08-13 09:32:07 +00004399 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400 }
4401}
4402
4403
4404void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) {
mads.s.ager31e71382008-08-13 09:32:07 +00004405 __ ldr(r0, FunctionOperand());
4406 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407}
4408
4409
4410void ArmCodeGenerator::VisitCompareOperation(CompareOperation* node) {
4411 Comment cmnt(masm_, "[ CompareOperation");
4412
4413 // Get the expressions from the node.
4414 Expression* left = node->left();
4415 Expression* right = node->right();
4416 Token::Value op = node->op();
4417
4418 // NOTE: To make null checks efficient, we check if either left or
4419 // right is the literal 'null'. If so, we optimize the code by
4420 // inlining a null check instead of calling the (very) general
4421 // runtime routine for checking equality.
4422
4423 bool left_is_null =
4424 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
4425 bool right_is_null =
4426 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
4427
4428 if (op == Token::EQ || op == Token::EQ_STRICT) {
4429 // The 'null' value is only equal to 'null' or 'undefined'.
4430 if (left_is_null || right_is_null) {
4431 Load(left_is_null ? right : left);
4432 Label exit, undetectable;
mads.s.ager31e71382008-08-13 09:32:07 +00004433 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 __ cmp(r0, Operand(Factory::null_value()));
4435
4436 // The 'null' value is only equal to 'undefined' if using
4437 // non-strict comparisons.
4438 if (op != Token::EQ_STRICT) {
4439 __ b(eq, &exit);
4440 __ cmp(r0, Operand(Factory::undefined_value()));
4441
4442 // NOTE: it can be undetectable object.
4443 __ b(eq, &exit);
4444 __ tst(r0, Operand(kSmiTagMask));
4445
4446 __ b(ne, &undetectable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 __ b(false_target());
4448
4449 __ bind(&undetectable);
4450 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
4451 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4452 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4453 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4454 }
4455
4456 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004457
4458 cc_reg_ = eq;
4459 return;
4460 }
4461 }
4462
4463
4464 // NOTE: To make typeof testing for natives implemented in
4465 // JavaScript really efficient, we generate special code for
4466 // expressions of the form: 'typeof <expression> == <string>'.
4467
4468 UnaryOperation* operation = left->AsUnaryOperation();
4469 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
4470 (operation != NULL && operation->op() == Token::TYPEOF) &&
4471 (right->AsLiteral() != NULL &&
4472 right->AsLiteral()->handle()->IsString())) {
4473 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
4474
mads.s.ager31e71382008-08-13 09:32:07 +00004475 // Load the operand, move it to register r1.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 LoadTypeofExpression(operation->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004477 __ pop(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478
4479 if (check->Equals(Heap::number_symbol())) {
4480 __ tst(r1, Operand(kSmiTagMask));
4481 __ b(eq, true_target());
4482 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4483 __ cmp(r1, Operand(Factory::heap_number_map()));
4484 cc_reg_ = eq;
4485
4486 } else if (check->Equals(Heap::string_symbol())) {
4487 __ tst(r1, Operand(kSmiTagMask));
4488 __ b(eq, false_target());
4489
4490 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4491
4492 // NOTE: it might be an undetectable string object
4493 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4494 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4495 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4496 __ b(eq, false_target());
4497
4498 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4499 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
4500 cc_reg_ = lt;
4501
4502 } else if (check->Equals(Heap::boolean_symbol())) {
4503 __ cmp(r1, Operand(Factory::true_value()));
4504 __ b(eq, true_target());
4505 __ cmp(r1, Operand(Factory::false_value()));
4506 cc_reg_ = eq;
4507
4508 } else if (check->Equals(Heap::undefined_symbol())) {
4509 __ cmp(r1, Operand(Factory::undefined_value()));
4510 __ b(eq, true_target());
4511
4512 __ tst(r1, Operand(kSmiTagMask));
4513 __ b(eq, false_target());
4514
4515 // NOTE: it can be undetectable object.
4516 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4517 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4518 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4519 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4520
4521 cc_reg_ = eq;
4522
4523 } else if (check->Equals(Heap::function_symbol())) {
4524 __ tst(r1, Operand(kSmiTagMask));
4525 __ b(eq, false_target());
4526 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4527 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4528 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
4529 cc_reg_ = eq;
4530
4531 } else if (check->Equals(Heap::object_symbol())) {
4532 __ tst(r1, Operand(kSmiTagMask));
4533 __ b(eq, false_target());
4534
4535 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
4536 __ cmp(r1, Operand(Factory::null_value()));
4537 __ b(eq, true_target());
4538
4539 // NOTE: it might be an undetectable object.
4540 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
4541 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
4542 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
4543 __ b(eq, false_target());
4544
4545 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4546 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
4547 __ b(lt, false_target());
4548 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
4549 cc_reg_ = le;
4550
4551 } else {
4552 // Uncommon case: Typeof testing against a string literal that
4553 // is never returned from the typeof operator.
4554 __ b(false_target());
4555 }
4556 return;
4557 }
4558
4559 Load(left);
4560 Load(right);
4561 switch (op) {
4562 case Token::EQ:
4563 Comparison(eq, false);
4564 break;
4565
4566 case Token::LT:
4567 Comparison(lt);
4568 break;
4569
4570 case Token::GT:
4571 Comparison(gt);
4572 break;
4573
4574 case Token::LTE:
4575 Comparison(le);
4576 break;
4577
4578 case Token::GTE:
4579 Comparison(ge);
4580 break;
4581
4582 case Token::EQ_STRICT:
4583 Comparison(eq, true);
4584 break;
4585
4586 case Token::IN:
mads.s.ager31e71382008-08-13 09:32:07 +00004587 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 __ InvokeBuiltin("IN", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004589 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590 break;
4591
4592 case Token::INSTANCEOF:
mads.s.ager31e71382008-08-13 09:32:07 +00004593 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 __ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004595 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 break;
4597
4598 default:
4599 UNREACHABLE();
4600 }
4601}
4602
4603
4604void ArmCodeGenerator::RecordStatementPosition(Node* node) {
4605 if (FLAG_debug_info) {
4606 int statement_pos = node->statement_pos();
4607 if (statement_pos == kNoPosition) return;
4608 __ RecordStatementPosition(statement_pos);
4609 }
4610}
4611
4612
kasper.lund7276f142008-07-30 08:49:36 +00004613void ArmCodeGenerator::EnterJSFrame(int argc) {
4614 __ EnterJSFrame(argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615}
4616
4617
kasper.lund7276f142008-07-30 08:49:36 +00004618void ArmCodeGenerator::ExitJSFrame(ExitJSFlag flag) {
4619 JSExitStub stub(flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620 __ CallJSExitStub(&stub);
4621}
4622
4623
4624#undef __
4625
4626
4627// -----------------------------------------------------------------------------
4628// CodeGenerator interface
4629
4630// MakeCode() is just a wrapper for CodeGenerator::MakeCode()
4631// so we don't have to expose the entire CodeGenerator class in
4632// the .h file.
4633Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
4634 Handle<Script> script,
4635 bool is_eval) {
4636 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval);
4637 if (!code.is_null()) {
4638 Counters::total_compiled_code_size.Increment(code->instruction_size());
4639 }
4640 return code;
4641}
4642
4643
4644} } // namespace v8::internal