blob: b71c7029c5234120345757c92c2c254880831695 [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);
288 virtual void GenerateIsArray(ZoneList<Expression*>* args);
289
290 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args);
291 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args);
292
293 virtual void GenerateValueOf(ZoneList<Expression*>* args);
294 virtual void GenerateSetValueOf(ZoneList<Expression*>* args);
kasper.lund7276f142008-07-30 08:49:36 +0000295
296 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297};
298
299
300// -----------------------------------------------------------------------------
301// ArmCodeGenerator implementation
302
303#define __ masm_->
304
305
306Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit,
307 Handle<Script> script,
308 bool is_eval) {
mads.s.ager31e71382008-08-13 09:32:07 +0000309#ifdef ENABLE_DISASSEMBLER
310 bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
311#endif // ENABLE_DISASSEMBLER
312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313#ifdef DEBUG
314 bool print_source = false;
315 bool print_ast = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 const char* ftype;
317
318 if (Bootstrapper::IsActive()) {
319 print_source = FLAG_print_builtin_source;
320 print_ast = FLAG_print_builtin_ast;
321 print_code = FLAG_print_builtin_code;
322 ftype = "builtin";
323 } else {
324 print_source = FLAG_print_source;
325 print_ast = FLAG_print_ast;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 ftype = "user-defined";
327 }
328
329 if (FLAG_trace_codegen || print_source || print_ast) {
330 PrintF("*** Generate code for %s function: ", ftype);
331 flit->name()->ShortPrint();
332 PrintF(" ***\n");
333 }
334
335 if (print_source) {
336 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
337 }
338
339 if (print_ast) {
340 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
341 }
342#endif // DEBUG
343
344 // Generate code.
345 const int initial_buffer_size = 4 * KB;
346 ArmCodeGenerator cgen(initial_buffer_size, script, is_eval);
347 cgen.GenCode(flit);
348 if (cgen.HasStackOverflow()) {
kasper.lund212ac232008-07-16 07:07:30 +0000349 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 return Handle<Code>::null();
351 }
352
353 // Process any deferred code.
354 cgen.ProcessDeferred();
355
356 // Allocate and install the code.
357 CodeDesc desc;
358 cgen.masm()->GetCode(&desc);
359 ScopeInfo<> sinfo(flit->scope());
360 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
361 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
362
363 // Add unresolved entries in the code to the fixup list.
364 Bootstrapper::AddFixup(*code, cgen.masm());
365
mads.s.ager31e71382008-08-13 09:32:07 +0000366#ifdef ENABLE_DISASSEMBLER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 if (print_code) {
368 // Print the source code if available.
369 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
370 PrintF("--- Raw source ---\n");
371 StringInputBuffer stream(String::cast(script->source()));
372 stream.Seek(flit->start_position());
373 // flit->end_position() points to the last character in the stream. We
374 // need to compensate by adding one to calculate the length.
375 int source_len = flit->end_position() - flit->start_position() + 1;
376 for (int i = 0; i < source_len; i++) {
377 if (stream.has_more()) PrintF("%c", stream.GetNext());
378 }
379 PrintF("\n\n");
380 }
381 PrintF("--- Code ---\n");
mads.s.ager31e71382008-08-13 09:32:07 +0000382 code->Disassemble();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
mads.s.ager31e71382008-08-13 09:32:07 +0000384#endif // ENABLE_DISASSEMBLER
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385
386 return code;
387}
388
389
390ArmCodeGenerator::ArmCodeGenerator(int buffer_size,
391 Handle<Script> script,
392 bool is_eval)
393 : CodeGenerator(is_eval, script),
394 masm_(new MacroAssembler(NULL, buffer_size)),
395 scope_(NULL),
396 cc_reg_(al),
397 state_(NULL),
398 break_stack_height_(0) {
399}
400
401
402// Calling conventions:
403
mads.s.ager31e71382008-08-13 09:32:07 +0000404// r0: the number of arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405// fp: frame pointer
406// sp: stack pointer
407// pp: caller's parameter pointer
408// cp: callee's context
409
410void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
411 Scope* scope = fun->scope();
412 ZoneList<Statement*>* body = fun->body();
413
414 // Initialize state.
415 { CodeGenState state;
416 state_ = &state;
417 scope_ = scope;
418 cc_reg_ = al;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419
420 // Entry
421 // stack: function, receiver, arguments, return address
422 // r0: number of arguments
423 // sp: stack pointer
424 // fp: frame pointer
425 // pp: caller's parameter pointer
426 // cp: callee's context
427
428 { Comment cmnt(masm_, "[ enter JS frame");
kasper.lund7276f142008-07-30 08:49:36 +0000429 EnterJSFrame(scope->num_parameters());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430 }
431 // tos: code slot
432#ifdef DEBUG
433 if (strlen(FLAG_stop_at) > 0 &&
434 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
kasper.lund7276f142008-07-30 08:49:36 +0000435 __ stop("stop-at");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 }
437#endif
438
439 // Allocate space for locals and initialize them.
kasper.lund7276f142008-07-30 08:49:36 +0000440 if (scope->num_stack_slots() > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 Comment cmnt(masm_, "[ allocate space for locals");
mads.s.ager31e71382008-08-13 09:32:07 +0000442 // Initialize stack slots with 'undefined' value.
443 __ mov(ip, Operand(Factory::undefined_value()));
444 for (int i = 0; i < scope->num_stack_slots(); i++) {
445 __ push(ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 }
447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448
449 if (scope->num_heap_slots() > 0) {
450 // Allocate local context.
451 // Get outer context and create a new context based on it.
mads.s.ager31e71382008-08-13 09:32:07 +0000452 __ ldr(r0, FunctionOperand());
453 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +0000454 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
455
456 if (kDebug) {
457 Label verified_true;
458 __ cmp(r0, Operand(cp));
459 __ b(eq, &verified_true);
460 __ stop("NewContext: r0 is expected to be the same as cp");
461 __ bind(&verified_true);
462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463 // Update context local.
464 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
465 }
466
467 // TODO(1241774): Improve this code!!!
468 // 1) only needed if we have a context
469 // 2) no need to recompute context ptr every single time
470 // 3) don't copy parameter operand code from SlotOperand!
471 {
472 Comment cmnt2(masm_, "[ copy context parameters into .context");
473
474 // Note that iteration order is relevant here! If we have the same
475 // parameter twice (e.g., function (x, y, x)), and that parameter
476 // needs to be copied into the context, it must be the last argument
477 // passed to the parameter that needs to be copied. This is a rare
478 // case so we don't check for it, instead we rely on the copying
479 // order: such a parameter is copied repeatedly into the same
480 // context location and thus the last value is what is seen inside
481 // the function.
482 for (int i = 0; i < scope->num_parameters(); i++) {
483 Variable* par = scope->parameter(i);
484 Slot* slot = par->slot();
485 if (slot != NULL && slot->type() == Slot::CONTEXT) {
486 ASSERT(!scope->is_global_scope()); // no parameters in global scope
487 int parameter_offset =
488 JavaScriptFrameConstants::kParam0Offset - i * kPointerSize;
489 __ ldr(r1, MemOperand(pp, parameter_offset));
490 // Loads r2 with context; used below in RecordWrite.
491 __ str(r1, SlotOperand(slot, r2));
492 // Load the offset into r3.
493 int slot_offset =
494 FixedArray::kHeaderSize + slot->index() * kPointerSize;
495 __ mov(r3, Operand(slot_offset));
496 __ RecordWrite(r2, r3, r1);
497 }
498 }
499 }
500
501 // Store the arguments object.
502 // This must happen after context initialization because
503 // the arguments array may be stored in the context!
504 if (scope->arguments() != NULL) {
505 ASSERT(scope->arguments_shadow() != NULL);
506 Comment cmnt(masm_, "[ allocate arguments object");
507 {
508 Reference target(this, scope->arguments());
mads.s.ager31e71382008-08-13 09:32:07 +0000509 __ ldr(r0, FunctionOperand());
510 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511 __ CallRuntime(Runtime::kNewArguments, 1);
mads.s.ager31e71382008-08-13 09:32:07 +0000512 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513 SetValue(&target);
514 }
515 // The value of arguments must also be stored in .arguments.
516 // TODO(1241813): This code can probably be improved by fusing it with
517 // the code that stores the arguments object above.
518 {
519 Reference target(this, scope->arguments_shadow());
520 Load(scope->arguments());
521 SetValue(&target);
522 }
523 }
524
525 // Generate code to 'execute' declarations and initialize
526 // functions (source elements). In case of an illegal
527 // redeclaration we need to handle that instead of processing the
528 // declarations.
529 if (scope->HasIllegalRedeclaration()) {
530 Comment cmnt(masm_, "[ illegal redeclarations");
531 scope->VisitIllegalRedeclaration(this);
532 } else {
533 Comment cmnt(masm_, "[ declarations");
mads.s.ager31e71382008-08-13 09:32:07 +0000534 // ProcessDeclarations calls DeclareGlobals indirectly
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 ProcessDeclarations(scope->declarations());
mads.s.ager31e71382008-08-13 09:32:07 +0000536
kasper.lund212ac232008-07-16 07:07:30 +0000537 // Bail out if a stack-overflow exception occured when
538 // processing declarations.
539 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 }
541
mads.s.ager31e71382008-08-13 09:32:07 +0000542 if (FLAG_trace) {
543 // Push a valid value as the parameter. The runtime call only uses
544 // it as the return value to indicate non-failure.
545 __ mov(r0, Operand(Smi::FromInt(0)));
546 __ push(r0);
547 __ CallRuntime(Runtime::kTraceEnter, 1);
548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 CheckStack();
550
551 // Compile the body of the function in a vanilla state. Don't
552 // bother compiling all the code if the scope has an illegal
553 // redeclaration.
554 if (!scope->HasIllegalRedeclaration()) {
555 Comment cmnt(masm_, "[ function body");
556#ifdef DEBUG
557 bool is_builtin = Bootstrapper::IsActive();
558 bool should_trace =
559 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
mads.s.ager31e71382008-08-13 09:32:07 +0000560 if (should_trace) {
561 // Push a valid value as the parameter. The runtime call only uses
562 // it as the return value to indicate non-failure.
563 __ mov(r0, Operand(Smi::FromInt(0)));
564 __ push(r0);
565 __ CallRuntime(Runtime::kDebugTrace, 1);
566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567#endif
568 VisitStatements(body);
569 }
570
571 state_ = NULL;
572 }
573
574 // exit
575 // r0: result
576 // sp: stack pointer
577 // fp: frame pointer
578 // pp: parameter pointer
579 // cp: callee's context
mads.s.ager31e71382008-08-13 09:32:07 +0000580 __ mov(r0, Operand(Factory::undefined_value()));
581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582 __ bind(&function_return_);
mads.s.ager31e71382008-08-13 09:32:07 +0000583 if (FLAG_trace) {
584 // Push the return value on the stack as the parameter.
585 // Runtime::TraceExit returns the parameter as it is.
586 __ push(r0);
587 __ CallRuntime(Runtime::kTraceExit, 1);
588 }
589
kasper.lund7276f142008-07-30 08:49:36 +0000590 ExitJSFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591
592 // Code generation state must be reset.
593 scope_ = NULL;
594 ASSERT(!has_cc());
595 ASSERT(state_ == NULL);
596}
597
598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
600 // Currently, this assertion will fail if we try to assign to
601 // a constant variable that is constant because it is read-only
602 // (such as the variable referring to a named function expression).
603 // We need to implement assignments to read-only variables.
604 // Ideally, we should do this during AST generation (by converting
605 // such assignments into expression statements); however, in general
606 // we may not be able to make the decision until past AST generation,
607 // that is when the entire program is known.
608 ASSERT(slot != NULL);
609 int index = slot->index();
610 switch (slot->type()) {
611 case Slot::PARAMETER:
612 return ParameterOperand(index);
613
614 case Slot::LOCAL: {
615 ASSERT(0 <= index &&
616 index < scope_->num_stack_slots() &&
kasper.lund7276f142008-07-30 08:49:36 +0000617 index >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 int local_offset = JavaScriptFrameConstants::kLocal0Offset -
kasper.lund7276f142008-07-30 08:49:36 +0000619 index * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 return MemOperand(fp, local_offset);
621 }
622
623 case Slot::CONTEXT: {
624 // Follow the context chain if necessary.
625 ASSERT(!tmp.is(cp)); // do not overwrite context register
626 Register context = cp;
627 int chain_length = scope_->ContextChainLength(slot->var()->scope());
628 for (int i = chain_length; i-- > 0;) {
629 // Load the closure.
630 // (All contexts, even 'with' contexts, have a closure,
631 // and it is the same for all contexts inside a function.
632 // There is no need to go to the function context first.)
633 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
634 // Load the function context (which is the incoming, outer context).
635 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
636 context = tmp;
637 }
638 // We may have a 'with' context now. Get the function context.
639 // (In fact this mov may never be the needed, since the scope analysis
640 // may not permit a direct context access in this case and thus we are
641 // always at a function context. However it is safe to dereference be-
642 // cause the function context of a function context is itself. Before
643 // deleting this mov we should try to create a counter-example first,
644 // though...)
645 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
646 return ContextOperand(tmp, index);
647 }
648
649 default:
650 UNREACHABLE();
651 return MemOperand(r0, 0);
652 }
653}
654
655
mads.s.ager31e71382008-08-13 09:32:07 +0000656// Loads a value on the stack. If it is a boolean value, the result may have
657// been (partially) translated into branches, or it may have set the condition
658// code register. If force_cc is set, the value is forced to set the condition
659// code register and no value is pushed. If the condition code register was set,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
661void ArmCodeGenerator::LoadCondition(Expression* x,
662 CodeGenState::AccessType access,
663 Label* true_target,
664 Label* false_target,
665 bool force_cc) {
666 ASSERT(access == CodeGenState::LOAD ||
667 access == CodeGenState::LOAD_TYPEOF_EXPR);
668 ASSERT(!has_cc() && !is_referenced());
669
670 CodeGenState* old_state = state_;
671 CodeGenState new_state(access, NULL, true_target, false_target);
672 state_ = &new_state;
673 Visit(x);
674 state_ = old_state;
675 if (force_cc && !has_cc()) {
mads.s.ager31e71382008-08-13 09:32:07 +0000676 // Convert the TOS value to a boolean in the condition code register.
677 ToBoolean(true_target, false_target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678 }
679 ASSERT(has_cc() || !force_cc);
680}
681
682
683void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {
684 ASSERT(access == CodeGenState::LOAD ||
685 access == CodeGenState::LOAD_TYPEOF_EXPR);
686
687 Label true_target;
688 Label false_target;
689 LoadCondition(x, access, &true_target, &false_target, false);
690
691 if (has_cc()) {
692 // convert cc_reg_ into a bool
693 Label loaded, materialize_true;
694 __ b(cc_reg_, &materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000695 __ mov(r0, Operand(Factory::false_value()));
696 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 __ b(&loaded);
698 __ bind(&materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000699 __ mov(r0, Operand(Factory::true_value()));
700 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 __ bind(&loaded);
702 cc_reg_ = al;
703 }
704
705 if (true_target.is_linked() || false_target.is_linked()) {
706 // we have at least one condition value
707 // that has been "translated" into a branch,
708 // thus it needs to be loaded explicitly again
709 Label loaded;
710 __ b(&loaded); // don't lose current TOS
711 bool both = true_target.is_linked() && false_target.is_linked();
712 // reincarnate "true", if necessary
713 if (true_target.is_linked()) {
714 __ bind(&true_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000715 __ mov(r0, Operand(Factory::true_value()));
716 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717 }
718 // if both "true" and "false" need to be reincarnated,
719 // jump across code for "false"
720 if (both)
721 __ b(&loaded);
722 // reincarnate "false", if necessary
723 if (false_target.is_linked()) {
724 __ bind(&false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000725 __ mov(r0, Operand(Factory::false_value()));
726 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727 }
728 // everything is loaded at this point
729 __ bind(&loaded);
730 }
731 ASSERT(!has_cc());
732}
733
734
735void ArmCodeGenerator::LoadGlobal() {
mads.s.ager31e71382008-08-13 09:32:07 +0000736 __ ldr(r0, GlobalObject());
737 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738}
739
740
741// TODO(1241834): Get rid of this function in favor of just using Load, now
742// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle
743// global variables w/o reference errors elsewhere.
744void ArmCodeGenerator::LoadTypeofExpression(Expression* x) {
745 Variable* variable = x->AsVariableProxy()->AsVariable();
746 if (variable != NULL && !variable->is_this() && variable->is_global()) {
747 // NOTE: This is somewhat nasty. We force the compiler to load
748 // the variable as if through '<global>.<variable>' to make sure we
749 // do not get reference errors.
750 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
751 Literal key(variable->name());
752 // TODO(1241834): Fetch the position from the variable instead of using
753 // no position.
754 Property property(&global, &key, kNoPosition);
755 Load(&property);
756 } else {
757 Load(x, CodeGenState::LOAD_TYPEOF_EXPR);
758 }
759}
760
761
762Reference::Reference(ArmCodeGenerator* cgen, Expression* expression)
763 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
764 cgen->LoadReference(this);
765}
766
767
768Reference::~Reference() {
769 cgen_->UnloadReference(this);
770}
771
772
773void ArmCodeGenerator::LoadReference(Reference* ref) {
774 Expression* e = ref->expression();
775 Property* property = e->AsProperty();
776 Variable* var = e->AsVariableProxy()->AsVariable();
777
778 if (property != NULL) {
779 Load(property->obj());
780 // Used a named reference if the key is a literal symbol.
781 // We don't use a named reference if they key is a string that can be
782 // legally parsed as an integer. This is because, otherwise we don't
783 // get into the slow case code that handles [] on String objects.
784 Literal* literal = property->key()->AsLiteral();
785 uint32_t dummy;
786 if (literal != NULL && literal->handle()->IsSymbol() &&
787 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
788 ref->set_type(Reference::NAMED);
789 } else {
790 Load(property->key());
791 ref->set_type(Reference::KEYED);
792 }
793 } else if (var != NULL) {
794 if (var->is_global()) {
795 // global variable
796 LoadGlobal();
797 ref->set_type(Reference::NAMED);
798 } else {
799 // local variable
800 ref->set_type(Reference::EMPTY);
801 }
802 } else {
803 Load(e);
804 __ CallRuntime(Runtime::kThrowReferenceError, 1);
mads.s.ager31e71382008-08-13 09:32:07 +0000805 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806 }
807}
808
809
810void ArmCodeGenerator::UnloadReference(Reference* ref) {
811 int size = ref->size();
812 if (size <= 0) {
813 // Do nothing. No popping is necessary.
814 } else {
mads.s.ager31e71382008-08-13 09:32:07 +0000815 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 __ add(sp, sp, Operand(size * kPointerSize));
mads.s.ager31e71382008-08-13 09:32:07 +0000817 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 }
819}
820
821
822void ArmCodeGenerator::AccessReference(Reference* ref,
823 CodeGenState::AccessType access) {
824 ASSERT(!has_cc());
825 ASSERT(ref->type() != Reference::ILLEGAL);
826 CodeGenState* old_state = state_;
827 CodeGenState new_state(access, ref, true_target(), false_target());
828 state_ = &new_state;
829 Visit(ref->expression());
830 state_ = old_state;
831}
832
833
834// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
835// register to a boolean in the condition code register. The code
836// may jump to 'false_target' in case the register converts to 'false'.
mads.s.ager31e71382008-08-13 09:32:07 +0000837void ArmCodeGenerator::ToBoolean(Label* true_target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838 Label* false_target) {
mads.s.ager31e71382008-08-13 09:32:07 +0000839 // Note: The generated code snippet does not change stack variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 // Only the condition code should be set.
mads.s.ager31e71382008-08-13 09:32:07 +0000841 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843 // Fast case checks
844
mads.s.ager31e71382008-08-13 09:32:07 +0000845 // Check if the value is 'false'.
846 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 __ b(eq, false_target);
848
mads.s.ager31e71382008-08-13 09:32:07 +0000849 // Check if the value is 'true'.
850 __ cmp(r0, Operand(Factory::true_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851 __ b(eq, true_target);
852
mads.s.ager31e71382008-08-13 09:32:07 +0000853 // Check if the value is 'undefined'.
854 __ cmp(r0, Operand(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 __ b(eq, false_target);
856
mads.s.ager31e71382008-08-13 09:32:07 +0000857 // Check if the value is a smi.
858 __ cmp(r0, Operand(Smi::FromInt(0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 __ b(eq, false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000860 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861 __ b(eq, true_target);
862
863 // Slow case: call the runtime.
864 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +0000865 __ CallRuntime(Runtime::kToBool, 1);
866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 // Convert result (r0) to condition code
868 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869
870 cc_reg_ = ne;
871}
872
873
874#undef __
875#define __ masm->
876
877
878class GetPropertyStub : public CodeStub {
879 public:
880 GetPropertyStub() { }
881
882 private:
883 Major MajorKey() { return GetProperty; }
884 int MinorKey() { return 0; }
885 void Generate(MacroAssembler* masm);
886
887 const char* GetName() { return "GetPropertyStub"; }
888};
889
890
891void GetPropertyStub::Generate(MacroAssembler* masm) {
mads.s.ager31e71382008-08-13 09:32:07 +0000892 // sp[0]: key
893 // sp[1]: receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 Label slow, fast;
mads.s.ager31e71382008-08-13 09:32:07 +0000895 // Get the key and receiver object from the stack.
896 __ ldm(ia, sp, r0.bit() | r1.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 // Check that the key is a smi.
898 __ tst(r0, Operand(kSmiTagMask));
899 __ b(ne, &slow);
900 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
901 // Check that the object isn't a smi.
902 __ tst(r1, Operand(kSmiTagMask));
903 __ b(eq, &slow);
904 // Check that the object is some kind of JS object.
905 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
906 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
907 __ cmp(r2, Operand(JS_OBJECT_TYPE));
908 __ b(lt, &slow);
909
910 // Check if the object is a value-wrapper object. In that case we
911 // enter the runtime system to make sure that indexing into string
912 // objects work as intended.
913 __ cmp(r2, Operand(JS_VALUE_TYPE));
914 __ b(eq, &slow);
915
916 // 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.
982 __ cmp(r2, Operand(JS_OBJECT_TYPE));
983 __ 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
1846 // throw a reference errror).
1847 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));
2695 __ cmp(r1, Operand(JS_OBJECT_TYPE));
2696 __ 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));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 if (node->type() == Slot::CONTEXT) {
3242 // Skip write barrier if the written value is a smi.
3243 Label exit;
3244 __ tst(r0, Operand(kSmiTagMask));
3245 __ b(eq, &exit);
3246 // r2 is loaded with context when calling SlotOperand above.
3247 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
3248 __ mov(r3, Operand(offset));
3249 __ RecordWrite(r2, r3, r1);
3250 __ bind(&exit);
3251 }
mads.s.ager31e71382008-08-13 09:32:07 +00003252 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253 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
kasper.lund7276f142008-07-30 08:49:36 +00003942// This should generate code that performs a charCodeAt() call or returns
3943// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3944// It is not yet implemented on ARM, so it always goes to the slow case.
3945void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
3946 ASSERT(args->length() == 2);
kasper.lund7276f142008-07-30 08:49:36 +00003947 __ mov(r0, Operand(Factory::undefined_value()));
mads.s.ager31e71382008-08-13 09:32:07 +00003948 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003949}
3950
3951
3952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953// This is used in the implementation of apply on ia32 but it is not
3954// used on ARM yet.
3955void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
kasper.lund7276f142008-07-30 08:49:36 +00003956 __ stop("ArmCodeGenerator::GenerateIsArray");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 cc_reg_ = eq;
3958}
3959
3960
3961void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3962 ASSERT(args->length() == 0);
3963
mads.s.ager31e71382008-08-13 09:32:07 +00003964 // Seed the result with the formal parameters count, which will be used
3965 // in case no arguments adaptor frame is found below the current frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003966 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
3967
3968 // Call the shared stub to get to the arguments.length.
3969 ArgumentsAccessStub stub(true);
3970 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003971 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972}
3973
3974
3975void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3976 ASSERT(args->length() == 1);
3977
3978 // Load the key onto the stack and set register r1 to the formal
3979 // parameters count for the currently executing function.
3980 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003981 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 __ mov(r1, Operand(Smi::FromInt(scope_->num_parameters())));
3983
3984 // Call the shared stub to get to arguments[key].
3985 ArgumentsAccessStub stub(false);
3986 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003987 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988}
3989
3990
3991void ArmCodeGenerator::GenerateShiftDownAndTailCall(
3992 ZoneList<Expression*>* args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003993 // r0 = number of arguments
3994 ASSERT(args->length() == 1);
3995 Load(args->at(0));
3996 __ pop(r0);
3997 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998
mads.s.ager31e71382008-08-13 09:32:07 +00003999 // Get the 'this' function and exit the frame without returning.
4000 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
4001 ExitJSFrame(DO_NOT_RETURN);
4002 // return address in lr
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003
mads.s.ager31e71382008-08-13 09:32:07 +00004004 // Move arguments one element down the stack.
4005 Label move;
4006 Label moved;
4007 __ sub(r2, r0, Operand(0), SetCC);
4008 __ b(eq, &moved);
4009 __ bind(&move);
4010 __ sub(ip, r2, Operand(1));
4011 __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2));
4012 __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2));
4013 __ sub(r2, r2, Operand(1), SetCC);
4014 __ b(ne, &move);
4015 __ bind(&moved);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016
mads.s.ager31e71382008-08-13 09:32:07 +00004017 // Remove the TOS (copy of last argument)
4018 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019
mads.s.ager31e71382008-08-13 09:32:07 +00004020 // Jump (tail-call) to the function in register r1.
4021 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
4022 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
4023 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
4024 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
4025
4026 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027}
4028
4029
4030void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) {
4031 if (CheckForInlineRuntimeCall(node))
4032 return;
4033
4034 ZoneList<Expression*>* args = node->arguments();
4035 Comment cmnt(masm_, "[ CallRuntime");
4036 Runtime::Function* function = node->function();
4037
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 if (function != NULL) {
mads.s.ager31e71382008-08-13 09:32:07 +00004039 // Push the arguments ("left-to-right").
4040 for (int i = 0; i < args->length(); i++) Load(args->at(i));
4041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 // Call the C runtime function.
4043 __ CallRuntime(function, args->length());
mads.s.ager31e71382008-08-13 09:32:07 +00004044 __ push(r0);
4045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00004047 // Prepare stack for calling JS runtime function.
4048 __ mov(r0, Operand(node->name()));
4049 __ push(r0);
4050 // Push the builtins object found in the current global object.
4051 __ ldr(r1, GlobalObject());
4052 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
4053 __ push(r0);
4054
4055 for (int i = 0; i < args->length(); i++) Load(args->at(i));
4056
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 // Call the JS runtime function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 Handle<Code> stub = ComputeCallInitialize(args->length());
4059 __ Call(stub, code_target);
4060 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00004061 __ pop();
4062 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 }
4064}
4065
4066
4067void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
4068 Comment cmnt(masm_, "[ UnaryOperation");
4069
4070 Token::Value op = node->op();
4071
4072 if (op == Token::NOT) {
4073 LoadCondition(node->expression(),
4074 CodeGenState::LOAD,
4075 false_target(),
4076 true_target(),
4077 true);
4078 cc_reg_ = NegateCondition(cc_reg_);
4079
4080 } else if (op == Token::DELETE) {
4081 Property* property = node->expression()->AsProperty();
mads.s.ager31e71382008-08-13 09:32:07 +00004082 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 if (property != NULL) {
4084 Load(property->obj());
4085 Load(property->key());
mads.s.ager31e71382008-08-13 09:32:07 +00004086 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088
mads.s.ager31e71382008-08-13 09:32:07 +00004089 } else if (variable != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 Slot* slot = variable->slot();
4091 if (variable->is_global()) {
4092 LoadGlobal();
mads.s.ager31e71382008-08-13 09:32:07 +00004093 __ mov(r0, Operand(variable->name()));
4094 __ push(r0);
4095 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097
4098 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
4099 // lookup the context holding the named variable
mads.s.ager31e71382008-08-13 09:32:07 +00004100 __ push(cp);
4101 __ mov(r0, Operand(variable->name()));
4102 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 __ CallRuntime(Runtime::kLookupContext, 2);
4104 // r0: context
mads.s.ager31e71382008-08-13 09:32:07 +00004105 __ push(r0);
4106 __ mov(r0, Operand(variable->name()));
4107 __ push(r0);
4108 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110
mads.s.ager31e71382008-08-13 09:32:07 +00004111 } else {
4112 // Default: Result of deleting non-global, not dynamically
4113 // introduced variables is false.
4114 __ mov(r0, Operand(Factory::false_value()));
4115 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116
4117 } else {
4118 // Default: Result of deleting expressions is true.
4119 Load(node->expression()); // may have side-effects
mads.s.ager31e71382008-08-13 09:32:07 +00004120 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 __ mov(r0, Operand(Factory::true_value()));
4122 }
mads.s.ager31e71382008-08-13 09:32:07 +00004123 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124
4125 } else if (op == Token::TYPEOF) {
4126 // Special case for loading the typeof expression; see comment on
4127 // LoadTypeofExpression().
4128 LoadTypeofExpression(node->expression());
4129 __ CallRuntime(Runtime::kTypeof, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00004130 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131
4132 } else {
4133 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004134 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 switch (op) {
4136 case Token::NOT:
4137 case Token::DELETE:
4138 case Token::TYPEOF:
4139 UNREACHABLE(); // handled above
4140 break;
4141
4142 case Token::SUB: {
4143 UnarySubStub stub;
4144 __ CallStub(&stub);
4145 break;
4146 }
4147
4148 case Token::BIT_NOT: {
4149 // smi check
4150 Label smi_label;
4151 Label continue_label;
4152 __ tst(r0, Operand(kSmiTagMask));
4153 __ b(eq, &smi_label);
4154
mads.s.ager31e71382008-08-13 09:32:07 +00004155 __ push(r0);
4156 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157 __ InvokeBuiltin("BIT_NOT", 0, CALL_JS);
4158
4159 __ b(&continue_label);
4160 __ bind(&smi_label);
4161 __ mvn(r0, Operand(r0));
4162 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
4163 __ bind(&continue_label);
4164 break;
4165 }
4166
4167 case Token::VOID:
4168 // since the stack top is cached in r0, popping and then
4169 // pushing a value can be done by just writing to r0.
4170 __ mov(r0, Operand(Factory::undefined_value()));
4171 break;
4172
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 case Token::ADD: {
4174 // Smi check.
4175 Label continue_label;
4176 __ tst(r0, Operand(kSmiTagMask));
4177 __ b(eq, &continue_label);
mads.s.ager31e71382008-08-13 09:32:07 +00004178 __ push(r0);
4179 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 __ InvokeBuiltin("TO_NUMBER", 0, CALL_JS);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004181 __ bind(&continue_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 default:
4185 UNREACHABLE();
4186 }
mads.s.ager31e71382008-08-13 09:32:07 +00004187 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 }
4189}
4190
4191
4192void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
4193 Comment cmnt(masm_, "[ CountOperation");
4194
4195 bool is_postfix = node->is_postfix();
4196 bool is_increment = node->op() == Token::INC;
4197
4198 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
4199 bool is_const = (var != NULL && var->mode() == Variable::CONST);
4200
4201 // Postfix: Make room for the result.
mads.s.ager31e71382008-08-13 09:32:07 +00004202 if (is_postfix) {
4203 __ mov(r0, Operand(0));
4204 __ push(r0);
4205 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206
4207 { Reference target(this, node->expression());
4208 if (target.is_illegal()) return;
4209 GetValue(&target);
mads.s.ager31e71382008-08-13 09:32:07 +00004210 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211
4212 Label slow, exit;
4213
4214 // Load the value (1) into register r1.
4215 __ mov(r1, Operand(Smi::FromInt(1)));
4216
4217 // Check for smi operand.
4218 __ tst(r0, Operand(kSmiTagMask));
4219 __ b(ne, &slow);
4220
4221 // Postfix: Store the old value as the result.
4222 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4223
4224 // Perform optimistic increment/decrement.
4225 if (is_increment) {
4226 __ add(r0, r0, Operand(r1), SetCC);
4227 } else {
4228 __ sub(r0, r0, Operand(r1), SetCC);
4229 }
4230
4231 // If the increment/decrement didn't overflow, we're done.
4232 __ b(vc, &exit);
4233
4234 // Revert optimistic increment/decrement.
4235 if (is_increment) {
4236 __ sub(r0, r0, Operand(r1));
4237 } else {
4238 __ add(r0, r0, Operand(r1));
4239 }
4240
4241 // Slow case: Convert to number.
4242 __ bind(&slow);
4243
4244 // Postfix: Convert the operand to a number and store it as the result.
4245 if (is_postfix) {
4246 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
4247 __ CallStub(&stub);
4248 // Store to result (on the stack).
4249 __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4250 }
4251
4252 // Compute the new value by calling the right JavaScript native.
4253 if (is_increment) {
4254 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
4255 __ CallStub(&stub);
4256 } else {
4257 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
4258 __ CallStub(&stub);
4259 }
4260
4261 // Store the new value in the target if not const.
4262 __ bind(&exit);
mads.s.ager31e71382008-08-13 09:32:07 +00004263 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004264 if (!is_const) SetValue(&target);
4265 }
4266
4267 // Postfix: Discard the new value and use the old.
4268 if (is_postfix) __ pop(r0);
4269}
4270
4271
4272void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
4273 Comment cmnt(masm_, "[ BinaryOperation");
4274 Token::Value op = node->op();
4275
4276 // According to ECMA-262 section 11.11, page 58, the binary logical
4277 // operators must yield the result of one of the two expressions
4278 // before any ToBoolean() conversions. This means that the value
4279 // produced by a && or || operator is not necessarily a boolean.
4280
4281 // NOTE: If the left hand side produces a materialized value (not in
4282 // the CC register), we force the right hand side to do the
4283 // same. This is necessary because we may have to branch to the exit
4284 // after evaluating the left hand side (due to the shortcut
4285 // semantics), but the compiler must (statically) know if the result
4286 // of compiling the binary operation is materialized or not.
4287
4288 if (op == Token::AND) {
4289 Label is_true;
4290 LoadCondition(node->left(),
4291 CodeGenState::LOAD,
4292 &is_true,
4293 false_target(),
4294 false);
4295 if (has_cc()) {
4296 Branch(false, false_target());
4297
4298 // Evaluate right side expression.
4299 __ bind(&is_true);
4300 LoadCondition(node->right(),
4301 CodeGenState::LOAD,
4302 true_target(),
4303 false_target(),
4304 false);
4305
4306 } else {
4307 Label pop_and_continue, exit;
4308
mads.s.ager31e71382008-08-13 09:32:07 +00004309 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
4310 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311 // Avoid popping the result if it converts to 'false' using the
4312 // standard ToBoolean() conversion as described in ECMA-262,
4313 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004314 ToBoolean(&pop_and_continue, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 Branch(false, &exit);
4316
4317 // Pop the result of evaluating the first part.
4318 __ bind(&pop_and_continue);
4319 __ pop(r0);
4320
4321 // Evaluate right side expression.
4322 __ bind(&is_true);
4323 Load(node->right());
4324
4325 // Exit (always with a materialized value).
4326 __ bind(&exit);
4327 }
4328
4329 } else if (op == Token::OR) {
4330 Label is_false;
4331 LoadCondition(node->left(),
4332 CodeGenState::LOAD,
4333 true_target(),
4334 &is_false,
4335 false);
4336 if (has_cc()) {
4337 Branch(true, true_target());
4338
4339 // Evaluate right side expression.
4340 __ bind(&is_false);
4341 LoadCondition(node->right(),
4342 CodeGenState::LOAD,
4343 true_target(),
4344 false_target(),
4345 false);
4346
4347 } else {
4348 Label pop_and_continue, exit;
4349
mads.s.ager31e71382008-08-13 09:32:07 +00004350 __ ldr(r0, MemOperand(sp, 0));
4351 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 // Avoid popping the result if it converts to 'true' using the
4353 // standard ToBoolean() conversion as described in ECMA-262,
4354 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004355 ToBoolean(&exit, &pop_and_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004356 Branch(true, &exit);
4357
4358 // Pop the result of evaluating the first part.
4359 __ bind(&pop_and_continue);
4360 __ pop(r0);
4361
4362 // Evaluate right side expression.
4363 __ bind(&is_false);
4364 Load(node->right());
4365
4366 // Exit (always with a materialized value).
4367 __ bind(&exit);
4368 }
4369
4370 } else {
4371 // Optimize for the case where (at least) one of the expressions
4372 // is a literal small integer.
4373 Literal* lliteral = node->left()->AsLiteral();
4374 Literal* rliteral = node->right()->AsLiteral();
4375
4376 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
4377 Load(node->left());
4378 SmiOperation(node->op(), rliteral->handle(), false);
4379
4380 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
4381 Load(node->right());
4382 SmiOperation(node->op(), lliteral->handle(), true);
4383
4384 } else {
4385 Load(node->left());
4386 Load(node->right());
kasper.lund7276f142008-07-30 08:49:36 +00004387 GenericBinaryOperation(node->op());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 }
mads.s.ager31e71382008-08-13 09:32:07 +00004389 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390 }
4391}
4392
4393
4394void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) {
mads.s.ager31e71382008-08-13 09:32:07 +00004395 __ ldr(r0, FunctionOperand());
4396 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004397}
4398
4399
4400void ArmCodeGenerator::VisitCompareOperation(CompareOperation* node) {
4401 Comment cmnt(masm_, "[ CompareOperation");
4402
4403 // Get the expressions from the node.
4404 Expression* left = node->left();
4405 Expression* right = node->right();
4406 Token::Value op = node->op();
4407
4408 // NOTE: To make null checks efficient, we check if either left or
4409 // right is the literal 'null'. If so, we optimize the code by
4410 // inlining a null check instead of calling the (very) general
4411 // runtime routine for checking equality.
4412
4413 bool left_is_null =
4414 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
4415 bool right_is_null =
4416 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
4417
4418 if (op == Token::EQ || op == Token::EQ_STRICT) {
4419 // The 'null' value is only equal to 'null' or 'undefined'.
4420 if (left_is_null || right_is_null) {
4421 Load(left_is_null ? right : left);
4422 Label exit, undetectable;
mads.s.ager31e71382008-08-13 09:32:07 +00004423 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424 __ cmp(r0, Operand(Factory::null_value()));
4425
4426 // The 'null' value is only equal to 'undefined' if using
4427 // non-strict comparisons.
4428 if (op != Token::EQ_STRICT) {
4429 __ b(eq, &exit);
4430 __ cmp(r0, Operand(Factory::undefined_value()));
4431
4432 // NOTE: it can be undetectable object.
4433 __ b(eq, &exit);
4434 __ tst(r0, Operand(kSmiTagMask));
4435
4436 __ b(ne, &undetectable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 __ b(false_target());
4438
4439 __ bind(&undetectable);
4440 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
4441 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4442 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4443 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4444 }
4445
4446 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447
4448 cc_reg_ = eq;
4449 return;
4450 }
4451 }
4452
4453
4454 // NOTE: To make typeof testing for natives implemented in
4455 // JavaScript really efficient, we generate special code for
4456 // expressions of the form: 'typeof <expression> == <string>'.
4457
4458 UnaryOperation* operation = left->AsUnaryOperation();
4459 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
4460 (operation != NULL && operation->op() == Token::TYPEOF) &&
4461 (right->AsLiteral() != NULL &&
4462 right->AsLiteral()->handle()->IsString())) {
4463 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
4464
mads.s.ager31e71382008-08-13 09:32:07 +00004465 // Load the operand, move it to register r1.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 LoadTypeofExpression(operation->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004467 __ pop(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468
4469 if (check->Equals(Heap::number_symbol())) {
4470 __ tst(r1, Operand(kSmiTagMask));
4471 __ b(eq, true_target());
4472 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4473 __ cmp(r1, Operand(Factory::heap_number_map()));
4474 cc_reg_ = eq;
4475
4476 } else if (check->Equals(Heap::string_symbol())) {
4477 __ tst(r1, Operand(kSmiTagMask));
4478 __ b(eq, false_target());
4479
4480 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4481
4482 // NOTE: it might be an undetectable string object
4483 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4484 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4485 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4486 __ b(eq, false_target());
4487
4488 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4489 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
4490 cc_reg_ = lt;
4491
4492 } else if (check->Equals(Heap::boolean_symbol())) {
4493 __ cmp(r1, Operand(Factory::true_value()));
4494 __ b(eq, true_target());
4495 __ cmp(r1, Operand(Factory::false_value()));
4496 cc_reg_ = eq;
4497
4498 } else if (check->Equals(Heap::undefined_symbol())) {
4499 __ cmp(r1, Operand(Factory::undefined_value()));
4500 __ b(eq, true_target());
4501
4502 __ tst(r1, Operand(kSmiTagMask));
4503 __ b(eq, false_target());
4504
4505 // NOTE: it can be undetectable object.
4506 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4507 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4508 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4509 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4510
4511 cc_reg_ = eq;
4512
4513 } else if (check->Equals(Heap::function_symbol())) {
4514 __ tst(r1, Operand(kSmiTagMask));
4515 __ b(eq, false_target());
4516 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4517 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4518 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
4519 cc_reg_ = eq;
4520
4521 } else if (check->Equals(Heap::object_symbol())) {
4522 __ tst(r1, Operand(kSmiTagMask));
4523 __ b(eq, false_target());
4524
4525 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
4526 __ cmp(r1, Operand(Factory::null_value()));
4527 __ b(eq, true_target());
4528
4529 // NOTE: it might be an undetectable object.
4530 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
4531 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
4532 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
4533 __ b(eq, false_target());
4534
4535 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4536 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
4537 __ b(lt, false_target());
4538 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
4539 cc_reg_ = le;
4540
4541 } else {
4542 // Uncommon case: Typeof testing against a string literal that
4543 // is never returned from the typeof operator.
4544 __ b(false_target());
4545 }
4546 return;
4547 }
4548
4549 Load(left);
4550 Load(right);
4551 switch (op) {
4552 case Token::EQ:
4553 Comparison(eq, false);
4554 break;
4555
4556 case Token::LT:
4557 Comparison(lt);
4558 break;
4559
4560 case Token::GT:
4561 Comparison(gt);
4562 break;
4563
4564 case Token::LTE:
4565 Comparison(le);
4566 break;
4567
4568 case Token::GTE:
4569 Comparison(ge);
4570 break;
4571
4572 case Token::EQ_STRICT:
4573 Comparison(eq, true);
4574 break;
4575
4576 case Token::IN:
mads.s.ager31e71382008-08-13 09:32:07 +00004577 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004578 __ InvokeBuiltin("IN", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004579 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 break;
4581
4582 case Token::INSTANCEOF:
mads.s.ager31e71382008-08-13 09:32:07 +00004583 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 __ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004585 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 break;
4587
4588 default:
4589 UNREACHABLE();
4590 }
4591}
4592
4593
4594void ArmCodeGenerator::RecordStatementPosition(Node* node) {
4595 if (FLAG_debug_info) {
4596 int statement_pos = node->statement_pos();
4597 if (statement_pos == kNoPosition) return;
4598 __ RecordStatementPosition(statement_pos);
4599 }
4600}
4601
4602
kasper.lund7276f142008-07-30 08:49:36 +00004603void ArmCodeGenerator::EnterJSFrame(int argc) {
4604 __ EnterJSFrame(argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605}
4606
4607
kasper.lund7276f142008-07-30 08:49:36 +00004608void ArmCodeGenerator::ExitJSFrame(ExitJSFlag flag) {
4609 JSExitStub stub(flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 __ CallJSExitStub(&stub);
4611}
4612
4613
4614#undef __
4615
4616
4617// -----------------------------------------------------------------------------
4618// CodeGenerator interface
4619
4620// MakeCode() is just a wrapper for CodeGenerator::MakeCode()
4621// so we don't have to expose the entire CodeGenerator class in
4622// the .h file.
4623Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
4624 Handle<Script> script,
4625 bool is_eval) {
4626 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval);
4627 if (!code.is_null()) {
4628 Counters::total_compiled_code_size.Increment(code->instruction_size());
4629 }
4630 return code;
4631}
4632
4633
4634} } // namespace v8::internal