blob: da7c73f57da077d6f48bf117448e3d7a6c437c13 [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";
1087 default: return "GenericBinaryOpStub";
1088 }
1089 }
1090
1091#ifdef DEBUG
1092 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
1093#endif
1094};
1095
1096
1097void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001098 // r1 : x
1099 // r0 : y
1100 // result : r0
1101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 switch (op_) {
1103 case Token::ADD: {
1104 Label slow, exit;
1105 // fast path
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1107 __ add(r0, r1, Operand(r0), SetCC); // add y optimistically
1108 // go slow-path in case of overflow
1109 __ b(vs, &slow);
1110 // go slow-path in case of non-smi operands
1111 ASSERT(kSmiTag == 0); // adjust code below
1112 __ tst(r2, Operand(kSmiTagMask));
1113 __ b(eq, &exit);
1114 // slow path
1115 __ bind(&slow);
1116 __ sub(r0, r0, Operand(r1)); // revert optimistic add
mads.s.ager31e71382008-08-13 09:32:07 +00001117 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 __ push(r0);
1119 __ mov(r0, Operand(1)); // set number of arguments
1120 __ InvokeBuiltin("ADD", 1, JUMP_JS);
1121 // done
1122 __ bind(&exit);
1123 break;
1124 }
1125
1126 case Token::SUB: {
1127 Label slow, exit;
1128 // fast path
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1130 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
1131 // go slow-path in case of overflow
1132 __ b(vs, &slow);
1133 // go slow-path in case of non-smi operands
1134 ASSERT(kSmiTag == 0); // adjust code below
1135 __ tst(r2, Operand(kSmiTagMask));
1136 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result
1137 __ b(eq, &exit);
1138 // slow path
1139 __ bind(&slow);
mads.s.ager31e71382008-08-13 09:32:07 +00001140 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 __ push(r0);
1142 __ mov(r0, Operand(1)); // set number of arguments
1143 __ InvokeBuiltin("SUB", 1, JUMP_JS);
1144 // done
1145 __ bind(&exit);
1146 break;
1147 }
1148
1149 case Token::MUL: {
1150 Label slow, exit;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 // tag check
1152 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1153 ASSERT(kSmiTag == 0); // adjust code below
1154 __ tst(r2, Operand(kSmiTagMask));
1155 __ b(ne, &slow);
1156 // remove tag from one operand (but keep sign), so that result is smi
1157 __ mov(ip, Operand(r0, ASR, kSmiTagSize));
1158 // do multiplication
1159 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1
1160 // go slow on overflows (overflow bit is not set)
1161 __ mov(ip, Operand(r3, ASR, 31));
1162 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical
1163 __ b(ne, &slow);
1164 // go slow on zero result to handle -0
1165 __ tst(r3, Operand(r3));
1166 __ mov(r0, Operand(r3), LeaveCC, ne);
1167 __ b(ne, &exit);
1168 // slow case
1169 __ bind(&slow);
mads.s.ager31e71382008-08-13 09:32:07 +00001170 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171 __ push(r0);
1172 __ mov(r0, Operand(1)); // set number of arguments
1173 __ InvokeBuiltin("MUL", 1, JUMP_JS);
1174 // done
1175 __ bind(&exit);
1176 break;
1177 }
1178 default: UNREACHABLE();
1179 }
mads.s.ager31e71382008-08-13 09:32:07 +00001180 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001181}
1182
1183
1184class SmiOpStub : public CodeStub {
1185 public:
1186 SmiOpStub(Token::Value op, bool reversed)
1187 : op_(op), reversed_(reversed) {}
1188
1189 private:
1190 Token::Value op_;
1191 bool reversed_;
1192
1193 Major MajorKey() { return SmiOp; }
1194 int MinorKey() {
1195 return (op_ == Token::ADD ? 2 : 0) | (reversed_ ? 1 : 0);
1196 }
1197 void Generate(MacroAssembler* masm);
1198 void GenerateShared(MacroAssembler* masm);
1199
1200 const char* GetName() { return "SmiOpStub"; }
1201
1202#ifdef DEBUG
1203 void Print() {
1204 PrintF("SmiOpStub (token %s), (reversed %s)\n",
1205 Token::String(op_), reversed_ ? "true" : "false");
1206 }
1207#endif
1208};
1209
1210
1211void SmiOpStub::Generate(MacroAssembler* masm) {
1212 switch (op_) {
1213 case Token::ADD: {
1214 if (!reversed_) {
1215 __ sub(r0, r0, Operand(r1)); // revert optimistic add
1216 __ push(r0);
1217 __ push(r1);
1218 __ mov(r0, Operand(1)); // set number of arguments
1219 __ InvokeBuiltin("ADD", 1, JUMP_JS);
1220 } else {
1221 __ sub(r0, r0, Operand(r1)); // revert optimistic add
1222 __ push(r1); // reversed
1223 __ push(r0);
1224 __ mov(r0, Operand(1)); // set number of arguments
1225 __ InvokeBuiltin("ADD", 1, JUMP_JS);
1226 }
1227 break;
1228 }
1229 case Token::SUB: {
1230 if (!reversed_) {
1231 __ push(r0);
1232 __ push(r1);
1233 __ mov(r0, Operand(1)); // set number of arguments
1234 __ InvokeBuiltin("SUB", 1, JUMP_JS);
1235 } else {
1236 __ push(r1);
1237 __ push(r0);
1238 __ mov(r0, Operand(1)); // set number of arguments
1239 __ InvokeBuiltin("SUB", 1, JUMP_JS);
1240 }
1241 break;
1242 }
1243 default: UNREACHABLE();
1244 }
1245}
1246
1247void StackCheckStub::Generate(MacroAssembler* masm) {
1248 Label within_limit;
1249 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
1250 __ ldr(ip, MemOperand(ip));
1251 __ cmp(sp, Operand(ip));
1252 __ b(hs, &within_limit);
1253 // Do tail-call to runtime routine.
1254 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001255 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 __ bind(&within_limit);
1257
1258 masm->StubReturn(1);
1259}
1260
1261
1262void UnarySubStub::Generate(MacroAssembler* masm) {
1263 Label undo;
1264 Label slow;
1265 Label done;
1266
1267 // Enter runtime system if the value is not a smi.
1268 __ tst(r0, Operand(kSmiTagMask));
1269 __ b(ne, &slow);
1270
1271 // Enter runtime system if the value of the expression is zero
1272 // to make sure that we switch between 0 and -0.
1273 __ cmp(r0, Operand(0));
1274 __ b(eq, &slow);
1275
1276 // The value of the expression is a smi that is not zero. Try
1277 // optimistic subtraction '0 - value'.
1278 __ rsb(r1, r0, Operand(0), SetCC);
1279 __ b(vs, &slow);
1280
1281 // If result is a smi we are done.
1282 __ tst(r1, Operand(kSmiTagMask));
1283 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result
1284 __ b(eq, &done);
1285
1286 // Enter runtime system.
1287 __ bind(&slow);
1288 __ push(r0);
1289 __ mov(r0, Operand(0)); // set number of arguments
1290 __ InvokeBuiltin("UNARY_MINUS", 0, JUMP_JS);
1291
1292 __ bind(&done);
1293 masm->StubReturn(1);
1294}
1295
1296
1297class InvokeBuiltinStub : public CodeStub {
1298 public:
1299 enum Kind { Inc, Dec, ToNumber };
1300 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
1301
1302 private:
1303 Kind kind_;
1304 int argc_;
1305
1306 Major MajorKey() { return InvokeBuiltin; }
1307 int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
1308 void Generate(MacroAssembler* masm);
1309
1310 const char* GetName() { return "InvokeBuiltinStub"; }
1311
1312#ifdef DEBUG
1313 void Print() {
1314 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
1315 static_cast<int>(kind_),
1316 argc_);
1317 }
1318#endif
1319};
1320
1321
1322void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
1323 __ push(r0);
1324 __ mov(r0, Operand(0)); // set number of arguments
1325 switch (kind_) {
1326 case ToNumber: __ InvokeBuiltin("TO_NUMBER", 0, JUMP_JS); break;
1327 case Inc: __ InvokeBuiltin("INC", 0, JUMP_JS); break;
1328 case Dec: __ InvokeBuiltin("DEC", 0, JUMP_JS); break;
1329 default: UNREACHABLE();
1330 }
1331 masm->StubReturn(argc_);
1332}
1333
1334
1335class JSExitStub : public CodeStub {
1336 public:
1337 enum Kind { Inc, Dec, ToNumber };
1338
kasper.lund7276f142008-07-30 08:49:36 +00001339 explicit JSExitStub(ExitJSFlag flag) : flag_(flag) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 ExitJSFlag flag_;
1343
1344 Major MajorKey() { return JSExit; }
kasper.lund7276f142008-07-30 08:49:36 +00001345 int MinorKey() { return static_cast<int>(flag_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 void Generate(MacroAssembler* masm);
1347
1348 const char* GetName() { return "JSExitStub"; }
1349
1350#ifdef DEBUG
1351 void Print() {
kasper.lund7276f142008-07-30 08:49:36 +00001352 PrintF("JSExitStub flag %d)\n", static_cast<int>(flag_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
1354#endif
1355};
1356
1357
1358void JSExitStub::Generate(MacroAssembler* masm) {
kasper.lund7276f142008-07-30 08:49:36 +00001359 __ ExitJSFrame(flag_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 masm->StubReturn(1);
1361}
1362
1363
1364
1365void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
1366 // r0 holds exception
1367 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1369 __ ldr(sp, MemOperand(r3));
1370 __ pop(r2); // pop next in chain
1371 __ str(r2, MemOperand(r3));
1372 // restore parameter- and frame-pointer and pop state.
1373 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
1374 // Before returning we restore the context from the frame pointer if not NULL.
1375 // The frame pointer is NULL in the exception handler of a JS entry frame.
1376 __ cmp(fp, Operand(0));
1377 // Set cp to NULL if fp is NULL.
1378 __ mov(cp, Operand(0), LeaveCC, eq);
1379 // Restore cp otherwise.
1380 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
1381 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
1382 __ pop(pc);
1383}
1384
1385
1386void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
1387 // Fetch top stack handler.
1388 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1389 __ ldr(r3, MemOperand(r3));
1390
1391 // Unwind the handlers until the ENTRY handler is found.
1392 Label loop, done;
1393 __ bind(&loop);
1394 // Load the type of the current stack handler.
1395 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
1396 StackHandlerConstants::kStateOffset;
1397 __ ldr(r2, MemOperand(r3, kStateOffset));
1398 __ cmp(r2, Operand(StackHandler::ENTRY));
1399 __ b(eq, &done);
1400 // Fetch the next handler in the list.
1401 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
1402 StackHandlerConstants::kNextOffset;
1403 __ ldr(r3, MemOperand(r3, kNextOffset));
1404 __ jmp(&loop);
1405 __ bind(&done);
1406
1407 // Set the top handler address to next handler past the current ENTRY handler.
1408 __ ldr(r0, MemOperand(r3, kNextOffset));
1409 __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
1410 __ str(r0, MemOperand(r2));
1411
1412 // Set external caught exception to false.
1413 __ mov(r0, Operand(false));
1414 ExternalReference external_caught(Top::k_external_caught_exception_address);
1415 __ mov(r2, Operand(external_caught));
1416 __ str(r0, MemOperand(r2));
1417
mads.s.ager31e71382008-08-13 09:32:07 +00001418 // Set pending exception and r0 to out of memory exception.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 Failure* out_of_memory = Failure::OutOfMemoryException();
1420 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
1421 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
1422 __ str(r0, MemOperand(r2));
1423
1424 // Restore the stack to the address of the ENTRY handler
1425 __ mov(sp, Operand(r3));
1426
1427 // restore parameter- and frame-pointer and pop state.
1428 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
1429 // Before returning we restore the context from the frame pointer if not NULL.
1430 // The frame pointer is NULL in the exception handler of a JS entry frame.
1431 __ cmp(fp, Operand(0));
1432 // Set cp to NULL if fp is NULL.
1433 __ mov(cp, Operand(0), LeaveCC, eq);
1434 // Restore cp otherwise.
1435 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
1436 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
1437 __ pop(pc);
1438}
1439
1440
1441void CEntryStub::GenerateCore(MacroAssembler* masm,
1442 Label* throw_normal_exception,
1443 Label* throw_out_of_memory_exception,
1444 bool do_gc,
1445 bool do_restore) {
1446 // r0: result parameter for PerformGC, if any
mads.s.ager31e71382008-08-13 09:32:07 +00001447 // r4: number of arguments including receiver (C callee-saved)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448 // r5: pointer to builtin function (C callee-saved)
1449
1450 if (do_gc) {
1451 __ Call(FUNCTION_ADDR(Runtime::PerformGC), runtime_entry); // passing r0
1452 }
1453
mads.s.ager31e71382008-08-13 09:32:07 +00001454 // Call C built-in.
1455 // r0 = argc.
1456 __ mov(r0, Operand(r4));
1457 // r1 = argv.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 __ add(r1, fp, Operand(r4, LSL, kPointerSizeLog2));
mads.s.ager31e71382008-08-13 09:32:07 +00001459 __ add(r1, r1, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // TODO(1242173): To let the GC traverse the return address of the exit
1462 // frames, we need to know where the return address is. Right now,
1463 // we push it on the stack to be able to find it again, but we never
1464 // restore from it in case of changes, which makes it impossible to
1465 // support moving the C entry code stub. This should be fixed, but currently
1466 // this is OK because the CEntryStub gets generated so early in the V8 boot
1467 // sequence that it is not moving ever.
1468 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4
1469 __ push(lr);
1470#if !defined(__arm__)
1471 // Notify the simulator of the transition to C code.
1472 __ swi(assembler::arm::call_rt_r5);
1473#else /* !defined(__arm__) */
1474 __ mov(pc, Operand(r5));
1475#endif /* !defined(__arm__) */
1476 // result is in r0 or r0:r1 - do not destroy these registers!
1477
1478 // check for failure result
1479 Label failure_returned;
1480 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
1481 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
1482 __ add(r2, r0, Operand(1));
1483 __ tst(r2, Operand(kFailureTagMask));
1484 __ b(eq, &failure_returned);
1485
1486 // clear top frame
1487 __ mov(r3, Operand(0));
1488 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1489 __ str(r3, MemOperand(ip));
1490
1491 // Restore the memory copy of the registers by digging them out from
1492 // the stack.
1493 if (do_restore) {
1494 // Ok to clobber r2 and r3.
1495 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
1496 const int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
1497 __ add(r3, fp, Operand(kOffset));
1498 __ CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
1499 }
1500
1501 // Exit C frame and return
1502 // r0:r1: result
1503 // sp: stack pointer
1504 // fp: frame pointer
1505 // pp: caller's parameter pointer pp (restored as C callee-saved)
1506
1507 // Restore current context from top and clear it in debug mode.
1508 __ mov(r3, Operand(Top::context_address()));
1509 __ ldr(cp, MemOperand(r3));
1510 __ mov(sp, Operand(fp)); // respect ABI stack constraint
kasper.lund7276f142008-07-30 08:49:36 +00001511 __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | pc.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512
1513 // check if we should retry or throw exception
1514 Label retry;
1515 __ bind(&failure_returned);
1516 ASSERT(Failure::RETRY_AFTER_GC == 0);
1517 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
1518 __ b(eq, &retry);
1519
1520 Label continue_exception;
1521 // If the returned failure is EXCEPTION then promote Top::pending_exception().
1522 __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
1523 __ b(ne, &continue_exception);
1524
1525 // Retrieve the pending exception and clear the variable.
1526 __ mov(ip, Operand(Factory::the_hole_value().location()));
1527 __ ldr(r3, MemOperand(ip));
1528 __ mov(ip, Operand(Top::pending_exception_address()));
1529 __ ldr(r0, MemOperand(ip));
1530 __ str(r3, MemOperand(ip));
1531
1532 __ bind(&continue_exception);
1533 // Special handling of out of memory exception.
1534 Failure* out_of_memory = Failure::OutOfMemoryException();
1535 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
1536 __ b(eq, throw_out_of_memory_exception);
1537
1538 // Handle normal exception.
1539 __ jmp(throw_normal_exception);
1540
1541 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
1542}
1543
1544
1545void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
1546 // Called from JavaScript; parameters are on stack as if calling JS function
mads.s.ager31e71382008-08-13 09:32:07 +00001547 // r0: number of arguments including receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 // r1: pointer to builtin function
1549 // fp: frame pointer (restored after C call)
1550 // sp: stack pointer (restored as callee's pp after C call)
1551 // cp: current context (C callee-saved)
1552 // pp: caller's parameter pointer pp (C callee-saved)
1553
1554 // NOTE: Invocations of builtins may return failure objects
1555 // instead of a proper result. The builtin entry handles
1556 // this by performing a garbage collection and retrying the
1557 // builtin once.
1558
1559 // Enter C frame
1560 // Compute parameter pointer before making changes and save it as ip register
1561 // so that it is restored as sp register on exit, thereby popping the args.
mads.s.ager31e71382008-08-13 09:32:07 +00001562 // ip = sp + kPointerSize*args_len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
1565 // all JS callee-saved are saved and traversed by GC; push in reverse order:
1566 // JS callee-saved, caller_pp, caller_fp, sp_on_exit (ip==pp), caller_pc
kasper.lund7276f142008-07-30 08:49:36 +00001567 __ stm(db_w, sp, pp.bit() | fp.bit() | ip.bit() | lr.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 __ mov(fp, Operand(sp)); // setup new frame pointer
1569
1570 // Store the current context in top.
1571 __ mov(ip, Operand(Top::context_address()));
1572 __ str(cp, MemOperand(ip));
1573
1574 // remember top frame
1575 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1576 __ str(fp, MemOperand(ip));
1577
1578 // Push debug marker.
1579 __ mov(ip, Operand(is_debug_break ? 1 : 0));
1580 __ push(ip);
1581
1582 if (is_debug_break) {
1583 // Save the state of all registers to the stack from the memory location.
1584 // Use sp as base to push.
1585 __ CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
1586 }
1587
1588 // move number of arguments (argc) into callee-saved register
1589 __ mov(r4, Operand(r0));
1590
1591 // move pointer to builtin function into callee-saved register
1592 __ mov(r5, Operand(r1));
1593
1594 // r0: result parameter for PerformGC, if any (setup below)
1595 // r4: number of arguments
1596 // r5: pointer to builtin function (C callee-saved)
1597
1598 Label entry;
1599 __ bind(&entry);
1600
1601 Label throw_out_of_memory_exception;
1602 Label throw_normal_exception;
1603
1604#ifdef DEBUG
1605 if (FLAG_gc_greedy) {
1606 Failure* failure = Failure::RetryAfterGC(0, NEW_SPACE);
1607 __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
1608 }
1609 GenerateCore(masm,
1610 &throw_normal_exception,
1611 &throw_out_of_memory_exception,
1612 FLAG_gc_greedy,
1613 is_debug_break);
1614#else
1615 GenerateCore(masm,
1616 &throw_normal_exception,
1617 &throw_out_of_memory_exception,
1618 false,
1619 is_debug_break);
1620#endif
1621 GenerateCore(masm,
1622 &throw_normal_exception,
1623 &throw_out_of_memory_exception,
1624 true,
1625 is_debug_break);
1626
1627 __ bind(&throw_out_of_memory_exception);
1628 GenerateThrowOutOfMemory(masm);
1629 // control flow for generated will not return.
1630
1631 __ bind(&throw_normal_exception);
1632 GenerateThrowTOS(masm);
1633}
1634
1635
1636void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
1637 // r0: code entry
1638 // r1: function
1639 // r2: receiver
1640 // r3: argc
1641 // [sp+0]: argv
1642
1643 Label invoke, exit;
1644
1645 // Called from C, so do not pop argc and args on exit (preserve sp)
1646 // No need to save register-passed args
1647 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr
1648 __ mov(ip, Operand(sp));
1649 __ stm(db_w, sp, kCalleeSaved | ip.bit() | lr.bit());
1650
1651 // Setup frame pointer
1652 __ mov(fp, Operand(sp));
1653
1654 // Add constructor mark.
1655 __ mov(ip, Operand(is_construct ? 1 : 0));
1656 __ push(ip);
1657
1658 // Move arguments into registers expected by Builtins::JSEntryTrampoline
1659 // preserve r0-r3, set r4, r5-r7 may be clobbered
1660
1661 // Get address of argv, see stm above.
1662 __ add(r4, sp, Operand((kNumCalleeSaved + 3)*kPointerSize));
1663 __ ldr(r4, MemOperand(r4)); // argv
1664
1665 // Save copies of the top frame descriptors on the stack.
1666 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1667 __ ldr(r6, MemOperand(ip));
1668 __ stm(db_w, sp, r6.bit());
1669
1670 // Call a faked try-block that does the invoke.
1671 __ bl(&invoke);
1672
1673 // Caught exception: Store result (exception) in the pending
1674 // exception field in the JSEnv and return a failure sentinel.
1675 __ mov(ip, Operand(Top::pending_exception_address()));
1676 __ str(r0, MemOperand(ip));
1677 __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
1678 __ b(&exit);
1679
1680 // Invoke: Link this frame into the handler chain.
1681 __ bind(&invoke);
1682 // Must preserve r0-r3, r5-r7 are available.
1683 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
1684 // If an exception not caught by another handler occurs, this handler returns
1685 // control to the code after the bl(&invoke) above, which restores all
1686 // kCalleeSaved registers (including cp, pp and fp) to their saved values
1687 // before returning a failure to C.
1688
1689 // Clear any pending exceptions.
1690 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
1691 __ ldr(r5, MemOperand(ip));
1692 __ mov(ip, Operand(Top::pending_exception_address()));
1693 __ str(r5, MemOperand(ip));
1694
1695 // Invoke the function by calling through JS entry trampoline builtin.
1696 // Notice that we cannot store a reference to the trampoline code directly in
1697 // this stub, because runtime stubs are not traversed when doing GC.
1698
1699 // Expected registers by Builtins::JSEntryTrampoline
1700 // r0: code entry
1701 // r1: function
1702 // r2: receiver
1703 // r3: argc
1704 // r4: argv
1705 if (is_construct) {
1706 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
1707 __ mov(ip, Operand(construct_entry));
1708 } else {
1709 ExternalReference entry(Builtins::JSEntryTrampoline);
1710 __ mov(ip, Operand(entry));
1711 }
1712 __ ldr(ip, MemOperand(ip)); // deref address
1713
1714 // Branch and link to JSEntryTrampoline
1715 __ mov(lr, Operand(pc));
1716 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
1717
1718 // Unlink this frame from the handler chain. When reading the
1719 // address of the next handler, there is no need to use the address
1720 // displacement since the current stack pointer (sp) points directly
1721 // to the stack handler.
1722 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
1723 __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
1724 __ str(r3, MemOperand(ip));
1725 // No need to restore registers
1726 __ add(sp, sp, Operand(StackHandlerConstants::kSize));
1727
1728 __ bind(&exit); // r0 holds result
1729 // Restore the top frame descriptors from the stack.
1730 __ ldm(ia_w, sp, r3.bit());
1731 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
1732 __ str(r3, MemOperand(ip));
1733
1734 // Remove constructor mark.
mads.s.ager31e71382008-08-13 09:32:07 +00001735 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736
1737 // Restore callee-saved registers, sp, and return.
1738#ifdef DEBUG
1739 if (FLAG_debug_code) __ mov(lr, Operand(pc));
1740#endif
1741 __ ldm(ia, sp, kCalleeSaved | sp.bit() | pc.bit());
1742}
1743
1744
1745class ArgumentsAccessStub: public CodeStub {
1746 public:
1747 explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { }
1748
1749 private:
1750 bool is_length_;
1751
1752 Major MajorKey() { return ArgumentsAccess; }
1753 int MinorKey() { return is_length_ ? 1 : 0; }
1754 void Generate(MacroAssembler* masm);
1755
1756 const char* GetName() { return "ArgumentsAccessStub"; }
1757
1758#ifdef DEBUG
1759 void Print() {
1760 PrintF("ArgumentsAccessStub (is_length %s)\n",
1761 is_length_ ? "true" : "false");
1762 }
1763#endif
1764};
1765
1766
1767void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
1768 if (is_length_) {
1769 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
1770 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1771 __ Ret();
1772 } else {
1773 // Check that the key is a smi.
1774 Label slow;
1775 __ tst(r0, Operand(kSmiTagMask));
1776 __ b(ne, &slow);
1777
1778 // Get the actual number of arguments passed and do bounds
1779 // check. Use unsigned comparison to get negative check for free.
1780 __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
1781 __ cmp(r0, Operand(r1, LSL, kSmiTagSize));
1782 __ b(hs, &slow);
1783
1784 // Load the argument directly from the stack and return.
1785 __ sub(r1, pp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1786 __ ldr(r0, MemOperand(r1, JavaScriptFrameConstants::kParam0Offset));
1787 __ Ret();
1788
1789 // Slow-case: Handle non-smi or out-of-bounds access to arguments
1790 // by calling the runtime system.
1791 __ bind(&slow);
1792 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001793 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794 }
1795}
1796
1797
1798#undef __
1799#define __ masm_->
1800
1801
1802void ArmCodeGenerator::AccessReferenceProperty(
1803 Expression* key,
1804 CodeGenState::AccessType access) {
1805 Reference::Type type = ref()->type();
1806 ASSERT(type != Reference::ILLEGAL);
1807
1808 // TODO(1241834): Make sure that this is sufficient. If there is a chance
1809 // that reference errors can be thrown below, we must distinguish
1810 // between the 2 kinds of loads (typeof expression loads must not
1811 // throw a reference errror).
1812 bool is_load = (access == CodeGenState::LOAD ||
1813 access == CodeGenState::LOAD_TYPEOF_EXPR);
1814
1815 if (type == Reference::NAMED) {
1816 // Compute the name of the property.
1817 Literal* literal = key->AsLiteral();
1818 Handle<String> name(String::cast(*literal->handle()));
1819
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001820 // Call the appropriate IC code.
1821 if (is_load) {
mads.s.ager31e71382008-08-13 09:32:07 +00001822 // Setup the name register.
1823 __ mov(r2, Operand(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1825 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
1826 if (var != NULL) {
1827 ASSERT(var->is_global());
1828 __ Call(ic, code_target_context);
1829 } else {
1830 __ Call(ic, code_target);
1831 }
mads.s.ager31e71382008-08-13 09:32:07 +00001832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001834 __ pop(r0); // value
1835 // Setup the name register.
1836 __ mov(r2, Operand(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1838 __ Call(ic, code_target);
1839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001841 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001842 // Access keyed property.
1843 ASSERT(type == Reference::KEYED);
1844
1845 if (is_load) {
1846 // TODO(1224671): Implement inline caching for keyed loads as on ia32.
1847 GetPropertyStub stub;
1848 __ CallStub(&stub);
1849
1850 } else {
1851 __ pop(r0); // value
1852 SetPropertyStub stub;
1853 __ CallStub(&stub);
1854 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855 }
mads.s.ager31e71382008-08-13 09:32:07 +00001856 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857}
1858
1859
kasper.lund7276f142008-07-30 08:49:36 +00001860void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
mads.s.ager31e71382008-08-13 09:32:07 +00001861 // sp[0] : y
1862 // sp[1] : x
1863 // result : r0
1864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 // Stub is entered with a call: 'return address' is in lr.
1866 switch (op) {
1867 case Token::ADD: // fall through.
1868 case Token::SUB: // fall through.
1869 case Token::MUL: {
mads.s.ager31e71382008-08-13 09:32:07 +00001870 __ pop(r0); // r0 : y
1871 __ pop(r1); // r1 : x
kasper.lund7276f142008-07-30 08:49:36 +00001872 GenericBinaryOpStub stub(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 __ CallStub(&stub);
1874 break;
1875 }
1876
1877 case Token::DIV: {
mads.s.ager31e71382008-08-13 09:32:07 +00001878 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879 __ InvokeBuiltin("DIV", 1, CALL_JS);
1880 break;
1881 }
1882
1883 case Token::MOD: {
mads.s.ager31e71382008-08-13 09:32:07 +00001884 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001885 __ InvokeBuiltin("MOD", 1, CALL_JS);
1886 break;
1887 }
1888
1889 case Token::BIT_OR:
1890 case Token::BIT_AND:
1891 case Token::BIT_XOR: {
1892 Label slow, exit;
mads.s.ager31e71382008-08-13 09:32:07 +00001893 __ pop(r0); // get y
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894 __ pop(r1); // get x
1895 // tag check
1896 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1897 ASSERT(kSmiTag == 0); // adjust code below
1898 __ tst(r2, Operand(kSmiTagMask));
1899 __ b(ne, &slow);
1900 switch (op) {
1901 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
1902 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
1903 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
1904 default: UNREACHABLE();
1905 }
1906 __ b(&exit);
1907 __ bind(&slow);
1908 __ push(r1); // restore stack
1909 __ push(r0);
1910 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
1911 switch (op) {
1912 case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, CALL_JS); break;
1913 case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, CALL_JS); break;
1914 case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, CALL_JS); break;
1915 default: UNREACHABLE();
1916 }
1917 __ bind(&exit);
1918 break;
1919 }
1920
1921 case Token::SHL:
1922 case Token::SHR:
1923 case Token::SAR: {
1924 Label slow, exit;
mads.s.ager31e71382008-08-13 09:32:07 +00001925 __ pop(r1); // get y
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 __ pop(r0); // get x
1927 // tag check
1928 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
1929 ASSERT(kSmiTag == 0); // adjust code below
1930 __ tst(r2, Operand(kSmiTagMask));
1931 __ b(ne, &slow);
1932 // get copies of operands
1933 __ mov(r3, Operand(r0));
1934 __ mov(r2, Operand(r1));
1935 // remove tags from operands (but keep sign)
1936 __ mov(r3, Operand(r3, ASR, kSmiTagSize));
1937 __ mov(r2, Operand(r2, ASR, kSmiTagSize));
1938 // use only the 5 least significant bits of the shift count
1939 __ and_(r2, r2, Operand(0x1f));
1940 // perform operation
1941 switch (op) {
1942 case Token::SAR:
1943 __ mov(r3, Operand(r3, ASR, r2));
1944 // no checks of result necessary
1945 break;
1946
1947 case Token::SHR:
1948 __ mov(r3, Operand(r3, LSR, r2));
1949 // check that the *unsigned* result fits in a smi
1950 // neither of the two high-order bits can be set:
1951 // - 0x80000000: high bit would be lost when smi tagging
1952 // - 0x40000000: this number would convert to negative when
1953 // smi tagging these two cases can only happen with shifts
1954 // by 0 or 1 when handed a valid smi
1955 __ and_(r2, r3, Operand(0xc0000000), SetCC);
1956 __ b(ne, &slow);
1957 break;
1958
1959 case Token::SHL:
1960 __ mov(r3, Operand(r3, LSL, r2));
1961 // check that the *signed* result fits in a smi
1962 __ add(r2, r3, Operand(0x40000000), SetCC);
1963 __ b(mi, &slow);
1964 break;
1965
1966 default: UNREACHABLE();
1967 }
mads.s.ager31e71382008-08-13 09:32:07 +00001968 // tag result and store it in r0
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 ASSERT(kSmiTag == 0); // adjust code below
1970 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
1971 __ b(&exit);
1972 // slow case
1973 __ bind(&slow);
1974 __ push(r0); // restore stack
mads.s.ager31e71382008-08-13 09:32:07 +00001975 __ push(r1);
1976 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 switch (op) {
1978 case Token::SAR: __ InvokeBuiltin("SAR", 1, CALL_JS); break;
1979 case Token::SHR: __ InvokeBuiltin("SHR", 1, CALL_JS); break;
1980 case Token::SHL: __ InvokeBuiltin("SHL", 1, CALL_JS); break;
1981 default: UNREACHABLE();
1982 }
1983 __ bind(&exit);
1984 break;
1985 }
1986
1987 case Token::COMMA:
mads.s.ager31e71382008-08-13 09:32:07 +00001988 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001989 // simply discard left value
mads.s.ager31e71382008-08-13 09:32:07 +00001990 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 break;
1992
1993 default:
1994 // Other cases should have been handled before this point.
1995 UNREACHABLE();
1996 break;
1997 }
1998}
1999
2000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001void ArmCodeGenerator::SmiOperation(Token::Value op,
2002 Handle<Object> value,
2003 bool reversed) {
2004 // NOTE: This is an attempt to inline (a bit) more of the code for
2005 // some possible smi operations (like + and -) when (at least) one
2006 // of the operands is a literal smi. With this optimization, the
2007 // performance of the system is increased by ~15%, and the generated
2008 // code size is increased by ~1% (measured on a combination of
2009 // different benchmarks).
2010
mads.s.ager31e71382008-08-13 09:32:07 +00002011 // sp[0] : operand
2012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 ASSERT(value->IsSmi());
2014
2015 Label exit;
mads.s.ager31e71382008-08-13 09:32:07 +00002016 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017
2018 switch (op) {
2019 case Token::ADD: {
2020 Label slow;
2021
2022 __ mov(r1, Operand(value));
2023 __ add(r0, r0, Operand(r1), SetCC);
2024 __ b(vs, &slow);
2025 __ tst(r0, Operand(kSmiTagMask));
2026 __ b(eq, &exit);
2027 __ bind(&slow);
2028
2029 SmiOpStub stub(Token::ADD, reversed);
2030 __ CallStub(&stub);
2031 break;
2032 }
2033
2034 case Token::SUB: {
2035 Label slow;
2036
2037 __ mov(r1, Operand(value));
2038 if (!reversed) {
2039 __ sub(r2, r0, Operand(r1), SetCC);
2040 } else {
2041 __ rsb(r2, r0, Operand(r1), SetCC);
2042 }
2043 __ b(vs, &slow);
2044 __ tst(r2, Operand(kSmiTagMask));
2045 __ mov(r0, Operand(r2), LeaveCC, eq); // conditionally set r0 to result
2046 __ b(eq, &exit);
2047
2048 __ bind(&slow);
2049
2050 SmiOpStub stub(Token::SUB, reversed);
2051 __ CallStub(&stub);
2052 break;
2053 }
2054
2055 default:
2056 if (!reversed) {
mads.s.ager31e71382008-08-13 09:32:07 +00002057 __ push(r0);
2058 __ mov(r0, Operand(value));
2059 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 } else {
2061 __ mov(ip, Operand(value));
2062 __ push(ip);
mads.s.ager31e71382008-08-13 09:32:07 +00002063 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 }
kasper.lund7276f142008-07-30 08:49:36 +00002065 GenericBinaryOperation(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002066 break;
2067 }
2068
2069 __ bind(&exit);
2070}
2071
2072
2073void ArmCodeGenerator::Comparison(Condition cc, bool strict) {
mads.s.ager31e71382008-08-13 09:32:07 +00002074 // sp[0] : y
2075 // sp[1] : x
2076 // result : cc register
2077
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 // Strict only makes sense for equality comparisons.
2079 ASSERT(!strict || cc == eq);
2080
2081 Label exit, smi;
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002082 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
2083 if (cc == gt || cc == le) {
2084 cc = ReverseCondition(cc);
mads.s.ager31e71382008-08-13 09:32:07 +00002085 __ pop(r1);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002086 __ pop(r0);
2087 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002088 __ pop(r0);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002089 __ pop(r1);
2090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002091 __ orr(r2, r0, Operand(r1));
2092 __ tst(r2, Operand(kSmiTagMask));
2093 __ b(eq, &smi);
2094
2095 // Perform non-smi comparison by runtime call.
2096 __ push(r1);
2097
2098 // Figure out which native to call and setup the arguments.
2099 const char* native;
2100 int argc;
2101 if (cc == eq) {
2102 native = strict ? "STRICT_EQUALS" : "EQUALS";
2103 argc = 1;
2104 } else {
2105 native = "COMPARE";
2106 int ncr; // NaN compare result
2107 if (cc == lt || cc == le) {
2108 ncr = GREATER;
2109 } else {
2110 ASSERT(cc == gt || cc == ge); // remaining cases
2111 ncr = LESS;
2112 }
mads.s.ager31e71382008-08-13 09:32:07 +00002113 __ push(r0);
2114 __ mov(r0, Operand(Smi::FromInt(ncr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002115 argc = 2;
2116 }
2117
2118 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
2119 // tagged as a small integer.
mads.s.ager31e71382008-08-13 09:32:07 +00002120 __ push(r0);
2121 __ mov(r0, Operand(argc));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002122 __ InvokeBuiltin(native, argc, CALL_JS);
2123 __ cmp(r0, Operand(0));
2124 __ b(&exit);
2125
2126 // test smi equality by pointer comparison.
2127 __ bind(&smi);
2128 __ cmp(r1, Operand(r0));
2129
2130 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002131 cc_reg_ = cc;
2132}
2133
2134
kasper.lund7276f142008-07-30 08:49:36 +00002135class CallFunctionStub: public CodeStub {
2136 public:
2137 explicit CallFunctionStub(int argc) : argc_(argc) {}
2138
2139 void Generate(MacroAssembler* masm);
2140
2141 private:
2142 int argc_;
2143
2144 const char* GetName() { return "CallFuntionStub"; }
2145
2146#if defined(DEBUG)
2147 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
2148#endif // defined(DEBUG)
2149
2150 Major MajorKey() { return CallFunction; }
2151 int MinorKey() { return argc_; }
2152};
2153
2154
2155void CallFunctionStub::Generate(MacroAssembler* masm) {
2156 Label slow;
kasper.lund7276f142008-07-30 08:49:36 +00002157 // Get the function to call from the stack.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002158 // function, receiver [, arguments]
kasper.lund7276f142008-07-30 08:49:36 +00002159 masm->ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
2160
2161 // Check that the function is really a JavaScript function.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002162 // r1: pushed function (to be verified)
kasper.lund7276f142008-07-30 08:49:36 +00002163 masm->tst(r1, Operand(kSmiTagMask));
2164 masm->b(eq, &slow);
2165 // Get the map of the function object.
2166 masm->ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
2167 masm->ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
2168 masm->cmp(r2, Operand(JS_FUNCTION_TYPE));
2169 masm->b(ne, &slow);
2170
2171 // Fast-case: Invoke the function now.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002172 // r1: pushed function
2173 ParameterCount actual(argc_);
2174 masm->InvokeFunction(r1, actual, JUMP_FUNCTION);
kasper.lund7276f142008-07-30 08:49:36 +00002175
2176 // Slow-case: Non-function called.
2177 masm->bind(&slow);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002178 masm->mov(r0, Operand(argc_)); // Setup the number of arguments.
kasper.lund7276f142008-07-30 08:49:36 +00002179 masm->InvokeBuiltin("CALL_NON_FUNCTION", 0, JUMP_JS);
2180}
2181
2182
mads.s.ager31e71382008-08-13 09:32:07 +00002183// Call the function on the stack with the given arguments.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
2185 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 // Push the arguments ("left-to-right") on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002187 for (int i = 0; i < args->length(); i++) {
2188 Load(args->at(i));
2189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190
kasper.lund7276f142008-07-30 08:49:36 +00002191 // Record the position for debugging purposes.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 __ RecordPosition(position);
2193
kasper.lund7276f142008-07-30 08:49:36 +00002194 // Use the shared code stub to call the function.
2195 CallFunctionStub call_function(args->length());
2196 __ CallStub(&call_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197
2198 // Restore context and pop function from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00002200 __ pop(); // discard the TOS
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201}
2202
2203
2204void ArmCodeGenerator::Branch(bool if_true, Label* L) {
2205 ASSERT(has_cc());
2206 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
2207 __ b(cc, L);
2208 cc_reg_ = al;
2209}
2210
2211
2212void ArmCodeGenerator::CheckStack() {
2213 if (FLAG_check_stack) {
2214 Comment cmnt(masm_, "[ check stack");
2215 StackCheckStub stub;
2216 __ CallStub(&stub);
2217 }
2218}
2219
2220
2221void ArmCodeGenerator::VisitBlock(Block* node) {
2222 Comment cmnt(masm_, "[ Block");
2223 if (FLAG_debug_info) RecordStatementPosition(node);
2224 node->set_break_stack_height(break_stack_height_);
2225 VisitStatements(node->statements());
2226 __ bind(node->break_target());
2227}
2228
2229
2230void ArmCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
mads.s.ager31e71382008-08-13 09:32:07 +00002231 __ mov(r0, Operand(pairs));
2232 __ push(r0);
2233 __ push(cp);
2234 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
2235 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002236 __ CallRuntime(Runtime::kDeclareGlobals, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00002237 // The result is discarded.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238}
2239
2240
2241void ArmCodeGenerator::VisitDeclaration(Declaration* node) {
2242 Comment cmnt(masm_, "[ Declaration");
2243 Variable* var = node->proxy()->var();
2244 ASSERT(var != NULL); // must have been resolved
2245 Slot* slot = var->slot();
2246
2247 // If it was not possible to allocate the variable at compile time,
2248 // we need to "declare" it at runtime to make sure it actually
2249 // exists in the local context.
2250 if (slot != NULL && slot->type() == Slot::LOOKUP) {
2251 // Variables with a "LOOKUP" slot were introduced as non-locals
2252 // during variable resolution and must have mode DYNAMIC.
2253 ASSERT(var->mode() == Variable::DYNAMIC);
2254 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00002255 __ push(cp);
2256 __ mov(r0, Operand(var->name()));
2257 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258 // Declaration nodes are always declared in only two modes.
2259 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
2260 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
mads.s.ager31e71382008-08-13 09:32:07 +00002261 __ mov(r0, Operand(Smi::FromInt(attr)));
2262 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002263 // Push initial value, if any.
2264 // Note: For variables we must not push an initial value (such as
2265 // 'undefined') because we may have a (legal) redeclaration and we
2266 // must not destroy the current value.
2267 if (node->mode() == Variable::CONST) {
mads.s.ager31e71382008-08-13 09:32:07 +00002268 __ mov(r0, Operand(Factory::the_hole_value()));
2269 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270 } else if (node->fun() != NULL) {
2271 Load(node->fun());
2272 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002273 __ mov(r0, Operand(0)); // no initial value!
2274 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002275 }
2276 __ CallRuntime(Runtime::kDeclareContextSlot, 5);
mads.s.ager31e71382008-08-13 09:32:07 +00002277 __ push(r0);
2278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002279 return;
2280 }
2281
2282 ASSERT(!var->is_global());
2283
2284 // If we have a function or a constant, we need to initialize the variable.
2285 Expression* val = NULL;
2286 if (node->mode() == Variable::CONST) {
2287 val = new Literal(Factory::the_hole_value());
2288 } else {
2289 val = node->fun(); // NULL if we don't have a function
2290 }
2291
2292 if (val != NULL) {
2293 // Set initial value.
2294 Reference target(this, node->proxy());
2295 Load(val);
2296 SetValue(&target);
2297 // Get rid of the assigned value (declarations are statements).
mads.s.ager31e71382008-08-13 09:32:07 +00002298 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002299 }
2300}
2301
2302
2303void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
2304 Comment cmnt(masm_, "[ ExpressionStatement");
2305 if (FLAG_debug_info) RecordStatementPosition(node);
2306 Expression* expression = node->expression();
2307 expression->MarkAsStatement();
2308 Load(expression);
mads.s.ager31e71382008-08-13 09:32:07 +00002309 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002310}
2311
2312
2313void ArmCodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
2314 Comment cmnt(masm_, "// EmptyStatement");
2315 // nothing to do
2316}
2317
2318
2319void ArmCodeGenerator::VisitIfStatement(IfStatement* node) {
2320 Comment cmnt(masm_, "[ IfStatement");
2321 // Generate different code depending on which
2322 // parts of the if statement are present or not.
2323 bool has_then_stm = node->HasThenStatement();
2324 bool has_else_stm = node->HasElseStatement();
2325
2326 if (FLAG_debug_info) RecordStatementPosition(node);
2327
2328 Label exit;
2329 if (has_then_stm && has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002330 Comment cmnt(masm_, "[ IfThenElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002331 Label then;
2332 Label else_;
2333 // if (cond)
2334 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
2335 Branch(false, &else_);
2336 // then
2337 __ bind(&then);
2338 Visit(node->then_statement());
2339 __ b(&exit);
2340 // else
2341 __ bind(&else_);
2342 Visit(node->else_statement());
2343
2344 } else if (has_then_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002345 Comment cmnt(masm_, "[ IfThen");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 ASSERT(!has_else_stm);
2347 Label then;
2348 // if (cond)
2349 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true);
2350 Branch(false, &exit);
2351 // then
2352 __ bind(&then);
2353 Visit(node->then_statement());
2354
2355 } else if (has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00002356 Comment cmnt(masm_, "[ IfElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002357 ASSERT(!has_then_stm);
2358 Label else_;
2359 // if (!cond)
2360 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true);
2361 Branch(true, &exit);
2362 // else
2363 __ bind(&else_);
2364 Visit(node->else_statement());
2365
2366 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002367 Comment cmnt(masm_, "[ If");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002368 ASSERT(!has_then_stm && !has_else_stm);
2369 // if (cond)
2370 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false);
2371 if (has_cc()) {
2372 cc_reg_ = al;
2373 } else {
2374 __ pop(r0); // __ Pop(no_reg)
2375 }
2376 }
2377
2378 // end
2379 __ bind(&exit);
2380}
2381
2382
2383void ArmCodeGenerator::CleanStack(int num_bytes) {
2384 ASSERT(num_bytes >= 0);
2385 if (num_bytes > 0) {
mads.s.ager31e71382008-08-13 09:32:07 +00002386 __ add(sp, sp, Operand(num_bytes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002387 }
2388}
2389
2390
2391void ArmCodeGenerator::VisitContinueStatement(ContinueStatement* node) {
2392 Comment cmnt(masm_, "[ ContinueStatement");
2393 if (FLAG_debug_info) RecordStatementPosition(node);
2394 CleanStack(break_stack_height_ - node->target()->break_stack_height());
2395 __ b(node->target()->continue_target());
2396}
2397
2398
2399void ArmCodeGenerator::VisitBreakStatement(BreakStatement* node) {
2400 Comment cmnt(masm_, "[ BreakStatement");
2401 if (FLAG_debug_info) RecordStatementPosition(node);
2402 CleanStack(break_stack_height_ - node->target()->break_stack_height());
2403 __ b(node->target()->break_target());
2404}
2405
2406
2407void ArmCodeGenerator::VisitReturnStatement(ReturnStatement* node) {
2408 Comment cmnt(masm_, "[ ReturnStatement");
2409 if (FLAG_debug_info) RecordStatementPosition(node);
2410 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00002411 // Move the function result into r0.
2412 __ pop(r0);
2413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002414 __ b(&function_return_);
2415}
2416
2417
2418void ArmCodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
2419 Comment cmnt(masm_, "[ WithEnterStatement");
2420 if (FLAG_debug_info) RecordStatementPosition(node);
2421 Load(node->expression());
kasper.lund7276f142008-07-30 08:49:36 +00002422 __ CallRuntime(Runtime::kPushContext, 1);
2423 if (kDebug) {
2424 Label verified_true;
2425 __ cmp(r0, Operand(cp));
2426 __ b(eq, &verified_true);
2427 __ stop("PushContext: r0 is expected to be the same as cp");
2428 __ bind(&verified_true);
2429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002430 // Update context local.
2431 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2432}
2433
2434
2435void ArmCodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
2436 Comment cmnt(masm_, "[ WithExitStatement");
2437 // Pop context.
2438 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
2439 // Update context local.
2440 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2441}
2442
2443
2444void ArmCodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
2445 Comment cmnt(masm_, "[ SwitchStatement");
2446 if (FLAG_debug_info) RecordStatementPosition(node);
2447 node->set_break_stack_height(break_stack_height_);
2448
2449 Load(node->tag());
2450
2451 Label next, fall_through, default_case;
2452 ZoneList<CaseClause*>* cases = node->cases();
2453 int length = cases->length();
2454
2455 for (int i = 0; i < length; i++) {
2456 CaseClause* clause = cases->at(i);
2457
2458 Comment cmnt(masm_, "[ case clause");
2459
2460 if (clause->is_default()) {
2461 // Bind the default case label, so we can branch to it when we
2462 // have compared against all other cases.
2463 ASSERT(default_case.is_unused()); // at most one default clause
2464
2465 // If the default case is the first (but not only) case, we have
2466 // to jump past it for now. Once we're done with the remaining
2467 // clauses, we'll branch back here. If it isn't the first case,
2468 // we jump past it by avoiding to chain it into the next chain.
2469 if (length > 1) {
2470 if (i == 0) __ b(&next);
2471 __ bind(&default_case);
2472 }
2473
2474 } else {
2475 __ bind(&next);
2476 next.Unuse();
mads.s.ager31e71382008-08-13 09:32:07 +00002477 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002478 __ push(r0); // duplicate TOS
2479 Load(clause->label());
2480 Comparison(eq, true);
2481 Branch(false, &next);
mads.s.ager31e71382008-08-13 09:32:07 +00002482 // Entering the case statement -> remove the switch value from the stack
2483 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002484 }
2485
2486 // Generate code for the body.
2487 __ bind(&fall_through);
2488 fall_through.Unuse();
2489 VisitStatements(clause->statements());
2490 __ b(&fall_through);
2491 }
2492
2493 __ bind(&next);
mads.s.ager31e71382008-08-13 09:32:07 +00002494 // Reached the end of the case statements -> remove the switch value
2495 // from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496 __ pop(r0); // __ Pop(no_reg)
2497 if (default_case.is_bound()) __ b(&default_case);
2498
2499 __ bind(&fall_through);
2500 __ bind(node->break_target());
2501}
2502
2503
2504void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) {
2505 Comment cmnt(masm_, "[ LoopStatement");
2506 if (FLAG_debug_info) RecordStatementPosition(node);
2507 node->set_break_stack_height(break_stack_height_);
2508
2509 // simple condition analysis
2510 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
2511 if (node->cond() == NULL) {
2512 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2513 info = ALWAYS_TRUE;
2514 } else {
2515 Literal* lit = node->cond()->AsLiteral();
2516 if (lit != NULL) {
2517 if (lit->IsTrue()) {
2518 info = ALWAYS_TRUE;
2519 } else if (lit->IsFalse()) {
2520 info = ALWAYS_FALSE;
2521 }
2522 }
2523 }
2524
2525 Label loop, entry;
2526
2527 // init
2528 if (node->init() != NULL) {
2529 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2530 Visit(node->init());
2531 }
2532 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
2533 __ b(&entry);
2534 }
2535
2536 // body
2537 __ bind(&loop);
2538 Visit(node->body());
2539
2540 // next
2541 __ bind(node->continue_target());
2542 if (node->next() != NULL) {
2543 // Record source position of the statement as this code which is after the
2544 // code for the body actually belongs to the loop statement and not the
2545 // body.
2546 if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
2547 ASSERT(node->type() == LoopStatement::FOR_LOOP);
2548 Visit(node->next());
2549 }
2550
2551 // cond
2552 __ bind(&entry);
2553 switch (info) {
2554 case ALWAYS_TRUE:
2555 CheckStack(); // TODO(1222600): ignore if body contains calls.
2556 __ b(&loop);
2557 break;
2558 case ALWAYS_FALSE:
2559 break;
2560 case DONT_KNOW:
2561 CheckStack(); // TODO(1222600): ignore if body contains calls.
2562 LoadCondition(node->cond(),
2563 CodeGenState::LOAD,
2564 &loop,
2565 node->break_target(),
2566 true);
2567 Branch(true, &loop);
2568 break;
2569 }
2570
2571 // exit
2572 __ bind(node->break_target());
2573}
2574
2575
2576void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) {
2577 Comment cmnt(masm_, "[ ForInStatement");
2578 if (FLAG_debug_info) RecordStatementPosition(node);
2579
2580 // We keep stuff on the stack while the body is executing.
2581 // Record it, so that a break/continue crossing this statement
2582 // can restore the stack.
2583 const int kForInStackSize = 5 * kPointerSize;
2584 break_stack_height_ += kForInStackSize;
2585 node->set_break_stack_height(break_stack_height_);
2586
2587 Label loop, next, entry, cleanup, exit, primitive, jsobject;
2588 Label filter_key, end_del_check, fixed_array, non_string;
2589
2590 // Get the object to enumerate over (converted to JSObject).
2591 Load(node->enumerable());
mads.s.ager31e71382008-08-13 09:32:07 +00002592 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593
2594 // Both SpiderMonkey and kjs ignore null and undefined in contrast
2595 // to the specification. 12.6.4 mandates a call to ToObject.
2596 __ cmp(r0, Operand(Factory::undefined_value()));
2597 __ b(eq, &exit);
2598 __ cmp(r0, Operand(Factory::null_value()));
2599 __ b(eq, &exit);
2600
2601 // Stack layout in body:
2602 // [iteration counter (Smi)]
2603 // [length of array]
2604 // [FixedArray]
2605 // [Map or 0]
2606 // [Object]
2607
2608 // Check if enumerable is already a JSObject
2609 __ tst(r0, Operand(kSmiTagMask));
2610 __ b(eq, &primitive);
2611 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2612 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
2613 __ cmp(r1, Operand(JS_OBJECT_TYPE));
2614 __ b(hs, &jsobject);
2615
2616 __ bind(&primitive);
mads.s.ager31e71382008-08-13 09:32:07 +00002617 __ push(r0);
2618 __ mov(r0, Operand(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 __ InvokeBuiltin("TO_OBJECT", 0, CALL_JS);
2620
2621
2622 __ bind(&jsobject);
2623
2624 // Get the set of properties (as a FixedArray or Map).
2625 __ push(r0); // duplicate the object being enumerated
mads.s.ager31e71382008-08-13 09:32:07 +00002626 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
2628
2629 // If we got a Map, we can do a fast modification check.
2630 // Otherwise, we got a FixedArray, and we have to do a slow check.
2631 __ mov(r2, Operand(r0));
2632 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
2633 __ cmp(r1, Operand(Factory::meta_map()));
2634 __ b(ne, &fixed_array);
2635
2636 // Get enum cache
2637 __ mov(r1, Operand(r0));
2638 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
2639 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
2640 __ ldr(r2,
2641 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
2642
mads.s.ager31e71382008-08-13 09:32:07 +00002643 __ push(r0); // map
2644 __ push(r2); // enum cache bridge cache
2645 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002646 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00002647 __ push(r0);
2648 __ mov(r0, Operand(Smi::FromInt(0)));
2649 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002650 __ b(&entry);
2651
2652
2653 __ bind(&fixed_array);
2654
2655 __ mov(r1, Operand(Smi::FromInt(0)));
2656 __ push(r1); // insert 0 in place of Map
mads.s.ager31e71382008-08-13 09:32:07 +00002657 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002658
2659 // Push the length of the array and the initial index onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002660 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002661 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00002662 __ push(r0);
2663 __ mov(r0, Operand(Smi::FromInt(0))); // init index
2664 __ push(r0);
2665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002666 __ b(&entry);
2667
2668 // Body.
2669 __ bind(&loop);
2670 Visit(node->body());
2671
2672 // Next.
2673 __ bind(node->continue_target());
2674 __ bind(&next);
mads.s.ager31e71382008-08-13 09:32:07 +00002675 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676 __ add(r0, r0, Operand(Smi::FromInt(1)));
mads.s.ager31e71382008-08-13 09:32:07 +00002677 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678
2679 // Condition.
2680 __ bind(&entry);
2681
mads.s.ager31e71382008-08-13 09:32:07 +00002682 // sp[0] : index
2683 // sp[1] : array/enum cache length
2684 // sp[2] : array or enum cache
2685 // sp[3] : 0 or map
2686 // sp[4] : enumerable
2687 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count
2688 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length
2689 __ cmp(r0, Operand(r1)); // compare to the array length
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002690 __ b(hs, &cleanup);
2691
mads.s.ager31e71382008-08-13 09:32:07 +00002692 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694 // Get the i'th entry of the array.
mads.s.ager31e71382008-08-13 09:32:07 +00002695 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002696 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2697 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
2698
2699 // Get Map or 0.
mads.s.ager31e71382008-08-13 09:32:07 +00002700 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 // Check if this (still) matches the map of the enumerable.
2702 // If not, we have to filter the key.
mads.s.ager31e71382008-08-13 09:32:07 +00002703 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002704 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
2705 __ cmp(r1, Operand(r2));
2706 __ b(eq, &end_del_check);
2707
2708 // Convert the entry to a string (or null if it isn't a property anymore).
mads.s.ager31e71382008-08-13 09:32:07 +00002709 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable
2710 __ push(r0);
2711 __ push(r3); // push entry
2712 __ mov(r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713 __ InvokeBuiltin("FILTER_KEY", 1, CALL_JS);
2714 __ mov(r3, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002715
2716 // If the property has been removed while iterating, we just skip it.
2717 __ cmp(r3, Operand(Factory::null_value()));
2718 __ b(eq, &next);
2719
2720
2721 __ bind(&end_del_check);
2722
2723 // Store the entry in the 'each' expression and take another spin in the loop.
mads.s.ager31e71382008-08-13 09:32:07 +00002724 // r3: i'th entry of the enum cache (or string there of)
2725 __ push(r3); // push entry
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726 { Reference each(this, node->each());
2727 if (!each.is_illegal()) {
mads.s.ager31e71382008-08-13 09:32:07 +00002728 if (each.size() > 0) {
2729 __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
2730 __ push(r0);
2731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 SetValue(&each);
mads.s.ager31e71382008-08-13 09:32:07 +00002733 if (each.size() > 0) {
2734 __ pop(r0); // discard the value
2735 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002736 }
2737 }
mads.s.ager31e71382008-08-13 09:32:07 +00002738 __ pop(); // pop the i'th entry pushed above
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002739 CheckStack(); // TODO(1222600): ignore if body contains calls.
2740 __ jmp(&loop);
2741
2742 // Cleanup.
2743 __ bind(&cleanup);
2744 __ bind(node->break_target());
mads.s.ager31e71382008-08-13 09:32:07 +00002745 __ add(sp, sp, Operand(5 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002746
2747 // Exit.
2748 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749
2750 break_stack_height_ -= kForInStackSize;
2751}
2752
2753
2754void ArmCodeGenerator::VisitTryCatch(TryCatch* node) {
2755 Comment cmnt(masm_, "[ TryCatch");
2756
2757 Label try_block, exit;
2758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 __ bl(&try_block);
2760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761 // --- Catch block ---
2762
2763 // Store the caught exception in the catch variable.
mads.s.ager31e71382008-08-13 09:32:07 +00002764 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002765 { Reference ref(this, node->catch_var());
2766 // Load the exception to the top of the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002767 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
2768 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769 SetValue(&ref);
mads.s.ager31e71382008-08-13 09:32:07 +00002770 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771 }
2772
2773 // Remove the exception from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002774 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002775
2776 VisitStatements(node->catch_block()->statements());
2777 __ b(&exit);
2778
2779
2780 // --- Try block ---
2781 __ bind(&try_block);
2782
2783 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
2784
2785 // Introduce shadow labels for all escapes from the try block,
2786 // including returns. We should probably try to unify the escaping
2787 // labels and the return label.
2788 int nof_escapes = node->escaping_labels()->length();
2789 List<LabelShadow*> shadows(1 + nof_escapes);
2790 shadows.Add(new LabelShadow(&function_return_));
2791 for (int i = 0; i < nof_escapes; i++) {
2792 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
2793 }
2794
2795 // Generate code for the statements in the try block.
2796 VisitStatements(node->try_block()->statements());
mads.s.ager31e71382008-08-13 09:32:07 +00002797 __ pop(r0); // Discard the result.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798
2799 // Stop the introduced shadowing and count the number of required unlinks.
2800 int nof_unlinks = 0;
2801 for (int i = 0; i <= nof_escapes; i++) {
2802 shadows[i]->StopShadowing();
2803 if (shadows[i]->is_linked()) nof_unlinks++;
2804 }
2805
2806 // Unlink from try chain.
2807 // TOS contains code slot
2808 const int kNextOffset = StackHandlerConstants::kNextOffset +
2809 StackHandlerConstants::kAddressDisplacement;
2810 __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp
2811 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2812 __ str(r1, MemOperand(r3));
2813 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
2814 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
2815 // Code slot popped.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816 if (nof_unlinks > 0) __ b(&exit);
2817
2818 // Generate unlink code for all used shadow labels.
2819 for (int i = 0; i <= nof_escapes; i++) {
2820 if (shadows[i]->is_linked()) {
mads.s.ager31e71382008-08-13 09:32:07 +00002821 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822 __ bind(shadows[i]);
2823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 // Reload sp from the top handler, because some statements that we
2825 // break from (eg, for...in) may have left stuff on the stack.
2826 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2827 __ ldr(sp, MemOperand(r3));
2828
2829 __ ldr(r1, MemOperand(sp, kNextOffset));
2830 __ str(r1, MemOperand(r3));
2831 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
2832 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
2833 // Code slot popped.
2834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835 __ b(shadows[i]->shadowed());
2836 }
2837 }
2838
2839 __ bind(&exit);
2840}
2841
2842
2843void ArmCodeGenerator::VisitTryFinally(TryFinally* node) {
2844 Comment cmnt(masm_, "[ TryFinally");
2845
2846 // State: Used to keep track of reason for entering the finally
2847 // block. Should probably be extended to hold information for
2848 // break/continue from within the try block.
2849 enum { FALLING, THROWING, JUMPING };
2850
2851 Label exit, unlink, try_block, finally_block;
2852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002853 __ bl(&try_block);
2854
mads.s.ager31e71382008-08-13 09:32:07 +00002855 __ push(r0); // save exception object on the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002856 // In case of thrown exceptions, this is where we continue.
2857 __ mov(r2, Operand(Smi::FromInt(THROWING)));
2858 __ b(&finally_block);
2859
2860
2861 // --- Try block ---
2862 __ bind(&try_block);
2863
2864 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
2865
2866 // Introduce shadow labels for all escapes from the try block,
2867 // including returns. We should probably try to unify the escaping
2868 // labels and the return label.
2869 int nof_escapes = node->escaping_labels()->length();
2870 List<LabelShadow*> shadows(1 + nof_escapes);
2871 shadows.Add(new LabelShadow(&function_return_));
2872 for (int i = 0; i < nof_escapes; i++) {
2873 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
2874 }
2875
2876 // Generate code for the statements in the try block.
2877 VisitStatements(node->try_block()->statements());
2878
2879 // Stop the introduced shadowing and count the number of required
2880 // unlinks.
2881 int nof_unlinks = 0;
2882 for (int i = 0; i <= nof_escapes; i++) {
2883 shadows[i]->StopShadowing();
2884 if (shadows[i]->is_linked()) nof_unlinks++;
2885 }
2886
2887 // Set the state on the stack to FALLING.
mads.s.ager31e71382008-08-13 09:32:07 +00002888 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS
2889 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 __ mov(r2, Operand(Smi::FromInt(FALLING)));
2891 if (nof_unlinks > 0) __ b(&unlink);
2892
2893 // Generate code that sets the state for all used shadow labels.
2894 for (int i = 0; i <= nof_escapes; i++) {
2895 if (shadows[i]->is_linked()) {
2896 __ bind(shadows[i]);
mads.s.ager31e71382008-08-13 09:32:07 +00002897 if (shadows[i]->shadowed() == &function_return_) {
2898 __ push(r0); // Materialize the return value on the stack
2899 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 // Fake TOS for break and continue (not return).
mads.s.ager31e71382008-08-13 09:32:07 +00002901 __ mov(r0, Operand(Factory::undefined_value()));
2902 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903 }
2904 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
2905 __ b(&unlink);
2906 }
2907 }
2908
mads.s.ager31e71382008-08-13 09:32:07 +00002909 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910 __ bind(&unlink);
2911
mads.s.ager31e71382008-08-13 09:32:07 +00002912 __ pop(r0); // Store TOS in r0 across stack manipulation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002913 // Reload sp from the top handler, because some statements that we
2914 // break from (eg, for...in) may have left stuff on the stack.
2915 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
2916 __ ldr(sp, MemOperand(r3));
2917 const int kNextOffset = StackHandlerConstants::kNextOffset +
2918 StackHandlerConstants::kAddressDisplacement;
2919 __ ldr(r1, MemOperand(sp, kNextOffset));
2920 __ str(r1, MemOperand(r3));
2921 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
2922 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
2923 // Code slot popped.
mads.s.ager31e71382008-08-13 09:32:07 +00002924 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925
2926 // --- Finally block ---
2927 __ bind(&finally_block);
2928
2929 // Push the state on the stack. If necessary move the state to a
2930 // local variable to avoid having extra values on the stack while
2931 // evaluating the finally block.
mads.s.ager31e71382008-08-13 09:32:07 +00002932 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933 if (node->finally_var() != NULL) {
2934 Reference target(this, node->finally_var());
2935 SetValue(&target);
2936 ASSERT(target.size() == 0); // no extra stuff on the stack
mads.s.ager31e71382008-08-13 09:32:07 +00002937 __ pop(); // remove the extra avalue that was pushed above
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002938 }
2939
2940 // Generate code for the statements in the finally block.
2941 VisitStatements(node->finally_block()->statements());
2942
mads.s.ager31e71382008-08-13 09:32:07 +00002943 // Get the state from the stack - or the local variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944 if (node->finally_var() != NULL) {
2945 Reference target(this, node->finally_var());
2946 GetValue(&target);
2947 }
mads.s.ager31e71382008-08-13 09:32:07 +00002948 __ pop(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949
mads.s.ager31e71382008-08-13 09:32:07 +00002950 __ pop(r0); // Restore value or faked TOS.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002951 // Generate code that jumps to the right destination for all used
2952 // shadow labels.
2953 for (int i = 0; i <= nof_escapes; i++) {
2954 if (shadows[i]->is_bound()) {
2955 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
2956 if (shadows[i]->shadowed() != &function_return_) {
2957 Label next;
2958 __ b(ne, &next);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959 __ b(shadows[i]->shadowed());
2960 __ bind(&next);
2961 } else {
2962 __ b(eq, shadows[i]->shadowed());
2963 }
2964 }
2965 }
2966
2967 // Check if we need to rethrow the exception.
2968 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
2969 __ b(ne, &exit);
2970
2971 // Rethrow exception.
mads.s.ager31e71382008-08-13 09:32:07 +00002972 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002973 __ CallRuntime(Runtime::kReThrow, 1);
2974
2975 // Done.
2976 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977}
2978
2979
2980void ArmCodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
2981 Comment cmnt(masm_, "[ DebuggerStatament");
2982 if (FLAG_debug_info) RecordStatementPosition(node);
2983 __ CallRuntime(Runtime::kDebugBreak, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00002984 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985}
2986
2987
2988void ArmCodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
2989 ASSERT(boilerplate->IsBoilerplate());
2990
2991 // Push the boilerplate on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002992 __ mov(r0, Operand(boilerplate));
2993 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994
2995 // Create a new closure.
mads.s.ager31e71382008-08-13 09:32:07 +00002996 __ push(cp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002997 __ CallRuntime(Runtime::kNewClosure, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00002998 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999}
3000
3001
3002void ArmCodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
3003 Comment cmnt(masm_, "[ FunctionLiteral");
3004
3005 // Build the function boilerplate and instantiate it.
3006 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
kasper.lund212ac232008-07-16 07:07:30 +00003007 // Check for stack-overflow exception.
3008 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009 InstantiateBoilerplate(boilerplate);
3010}
3011
3012
3013void ArmCodeGenerator::VisitFunctionBoilerplateLiteral(
3014 FunctionBoilerplateLiteral* node) {
3015 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
3016 InstantiateBoilerplate(node->boilerplate());
3017}
3018
3019
3020void ArmCodeGenerator::VisitConditional(Conditional* node) {
3021 Comment cmnt(masm_, "[ Conditional");
3022 Label then, else_, exit;
3023 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true);
3024 Branch(false, &else_);
3025 __ bind(&then);
3026 Load(node->then_expression(), access());
3027 __ b(&exit);
3028 __ bind(&else_);
3029 Load(node->else_expression(), access());
3030 __ bind(&exit);
3031}
3032
3033
3034void ArmCodeGenerator::VisitSlot(Slot* node) {
3035 Comment cmnt(masm_, "[ Slot");
3036
3037 if (node->type() == Slot::LOOKUP) {
3038 ASSERT(node->var()->mode() == Variable::DYNAMIC);
3039
3040 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00003041 __ push(cp);
3042 __ mov(r0, Operand(node->var()->name()));
3043 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003044
3045 switch (access()) {
3046 case CodeGenState::UNDEFINED:
3047 UNREACHABLE();
3048 break;
3049
3050 case CodeGenState::LOAD:
3051 __ CallRuntime(Runtime::kLoadContextSlot, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003052 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053 break;
3054
3055 case CodeGenState::LOAD_TYPEOF_EXPR:
3056 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003057 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058 break;
3059
3060 case CodeGenState::STORE:
3061 // Storing a variable must keep the (new) value on the stack. This
3062 // is necessary for compiling assignment expressions.
3063 __ CallRuntime(Runtime::kStoreContextSlot, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003064 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003065 // result (TOS) is the value that was stored
3066 break;
3067
3068 case CodeGenState::INIT_CONST:
3069 // Same as STORE but ignores attribute (e.g. READ_ONLY) of
3070 // context slot so that we can initialize const properties
3071 // (introduced via eval("const foo = (some expr);")). Also,
3072 // uses the current function context instead of the top
3073 // context.
3074 //
3075 // Note that we must declare the foo upon entry of eval(),
3076 // via a context slot declaration, but we cannot initialize
3077 // it at the same time, because the const declaration may
3078 // be at the end of the eval code (sigh...) and the const
3079 // variable may have been used before (where its value is
3080 // 'undefined'). Thus, we can only do the initialization
3081 // when we actually encounter the expression and when the
3082 // expression operands are defined and valid, and thus we
3083 // need the split into 2 operations: declaration of the
3084 // context slot followed by initialization.
3085 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003086 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 break;
3088 }
3089
3090 } else {
3091 // Note: We would like to keep the assert below, but it fires because
3092 // of some nasty code in LoadTypeofExpression() which should be removed...
3093 // ASSERT(node->var()->mode() != Variable::DYNAMIC);
3094
3095 switch (access()) {
3096 case CodeGenState::UNDEFINED:
3097 UNREACHABLE();
3098 break;
3099
3100 case CodeGenState::LOAD: // fall through
3101 case CodeGenState::LOAD_TYPEOF_EXPR:
3102 // Special handling for locals allocated in registers.
mads.s.ager31e71382008-08-13 09:32:07 +00003103 __ ldr(r0, SlotOperand(node, r2));
3104 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 if (node->var()->mode() == Variable::CONST) {
3106 // Const slots may contain 'the hole' value (the constant hasn't
3107 // been initialized yet) which needs to be converted into the
3108 // 'undefined' value.
3109 Comment cmnt(masm_, "[ Unhole const");
mads.s.ager31e71382008-08-13 09:32:07 +00003110 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003111 __ cmp(r0, Operand(Factory::the_hole_value()));
3112 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
mads.s.ager31e71382008-08-13 09:32:07 +00003113 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 }
3115 break;
3116
3117 case CodeGenState::INIT_CONST: {
3118 ASSERT(node->var()->mode() == Variable::CONST);
3119 // Only the first const initialization must be executed (the slot
3120 // still contains 'the hole' value). When the assignment is executed,
3121 // the code is identical to a normal store (see below).
3122 { Comment cmnt(masm_, "[ Init const");
3123 Label L;
kasper.lund7276f142008-07-30 08:49:36 +00003124 __ ldr(r2, SlotOperand(node, r2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 __ cmp(r2, Operand(Factory::the_hole_value()));
3126 __ b(ne, &L);
3127 // We must execute the store.
kasper.lund7276f142008-07-30 08:49:36 +00003128 // r2 may be loaded with context; used below in RecordWrite.
mads.s.ager31e71382008-08-13 09:32:07 +00003129 __ ldr(r0, MemOperand(sp, 0));
kasper.lund7276f142008-07-30 08:49:36 +00003130 __ str(r0, SlotOperand(node, r2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003131 if (node->type() == Slot::CONTEXT) {
3132 // Skip write barrier if the written value is a smi.
3133 Label exit;
3134 __ tst(r0, Operand(kSmiTagMask));
3135 __ b(eq, &exit);
3136 // r2 is loaded with context when calling SlotOperand above.
3137 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
3138 __ mov(r3, Operand(offset));
3139 __ RecordWrite(r2, r3, r1);
3140 __ bind(&exit);
3141 }
3142 __ bind(&L);
3143 }
3144 break;
3145 }
3146
3147 case CodeGenState::STORE: {
3148 // Storing a variable must keep the (new) value on the stack. This
3149 // is necessary for compiling assignment expressions.
3150 // Special handling for locals allocated in registers.
3151 //
3152 // Note: We will reach here even with node->var()->mode() ==
3153 // Variable::CONST because of const declarations which will
3154 // initialize consts to 'the hole' value and by doing so, end
3155 // up calling this code.
kasper.lund7276f142008-07-30 08:49:36 +00003156 // r2 may be loaded with context; used below in RecordWrite.
mads.s.ager31e71382008-08-13 09:32:07 +00003157 __ pop(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003158 __ str(r0, SlotOperand(node, r2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 if (node->type() == Slot::CONTEXT) {
3160 // Skip write barrier if the written value is a smi.
3161 Label exit;
3162 __ tst(r0, Operand(kSmiTagMask));
3163 __ b(eq, &exit);
3164 // r2 is loaded with context when calling SlotOperand above.
3165 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
3166 __ mov(r3, Operand(offset));
3167 __ RecordWrite(r2, r3, r1);
3168 __ bind(&exit);
3169 }
mads.s.ager31e71382008-08-13 09:32:07 +00003170 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003171 break;
3172 }
3173 }
3174 }
3175}
3176
3177
3178void ArmCodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) {
3179 Comment cmnt(masm_, "[ VariableProxy");
3180 Variable* node = proxy_node->var();
3181
3182 Expression* x = node->rewrite();
3183 if (x != NULL) {
3184 Visit(x);
3185 return;
3186 }
3187
3188 ASSERT(node->is_global());
3189 if (is_referenced()) {
3190 if (node->AsProperty() != NULL) {
3191 __ RecordPosition(node->AsProperty()->position());
3192 }
3193 AccessReferenceProperty(new Literal(node->name()), access());
3194
3195 } else {
3196 // All stores are through references.
3197 ASSERT(access() != CodeGenState::STORE);
3198 Reference property(this, proxy_node);
3199 GetValue(&property);
3200 }
3201}
3202
3203
3204void ArmCodeGenerator::VisitLiteral(Literal* node) {
3205 Comment cmnt(masm_, "[ Literal");
mads.s.ager31e71382008-08-13 09:32:07 +00003206 __ mov(r0, Operand(node->handle()));
3207 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003208}
3209
3210
3211void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
3212 Comment cmnt(masm_, "[ RexExp Literal");
3213
3214 // Retrieve the literal array and check the allocated entry.
3215
3216 // Load the function of this activation.
3217 __ ldr(r1, MemOperand(pp, 0));
3218
3219 // Load the literals array of the function.
3220 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
3221
3222 // Load the literal at the ast saved index.
3223 int literal_offset =
3224 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3225 __ ldr(r2, FieldMemOperand(r1, literal_offset));
3226
3227 Label done;
3228 __ cmp(r2, Operand(Factory::undefined_value()));
3229 __ b(ne, &done);
3230
3231 // If the entry is undefined we call the runtime system to computed
3232 // the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00003233 __ push(r1); // literal array (0)
3234 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
3235 __ push(r0); // literal index (1)
3236 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
3237 __ push(r0);
3238 __ mov(r0, Operand(node->flags())); // RegExp flags (3)
3239 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003240 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003241 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003242
mads.s.ager31e71382008-08-13 09:32:07 +00003243 __ bind(&done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244 // Push the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00003245 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246}
3247
3248
3249// This deferred code stub will be used for creating the boilerplate
3250// by calling Runtime_CreateObjectLiteral.
3251// Each created boilerplate is stored in the JSFunction and they are
3252// therefore context dependent.
3253class ObjectLiteralDeferred: public DeferredCode {
3254 public:
3255 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node)
3256 : DeferredCode(generator), node_(node) {
3257 set_comment("[ ObjectLiteralDeferred");
3258 }
3259 virtual void Generate();
3260 private:
3261 ObjectLiteral* node_;
3262};
3263
3264
3265void ObjectLiteralDeferred::Generate() {
3266 // If the entry is undefined we call the runtime system to computed
3267 // the literal.
3268
3269 // Literal array (0).
mads.s.ager31e71382008-08-13 09:32:07 +00003270 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271 // Literal index (1).
mads.s.ager31e71382008-08-13 09:32:07 +00003272 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
3273 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003274 // Constant properties (2).
mads.s.ager31e71382008-08-13 09:32:07 +00003275 __ mov(r0, Operand(node_->constant_properties()));
3276 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003278 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003279}
3280
3281
3282void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
3283 Comment cmnt(masm_, "[ ObjectLiteral");
3284
3285 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
3286
3287 // Retrieve the literal array and check the allocated entry.
3288
3289 // Load the function of this activation.
3290 __ ldr(r1, MemOperand(pp, 0));
3291
3292 // Load the literals array of the function.
3293 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
3294
3295 // Load the literal at the ast saved index.
3296 int literal_offset =
3297 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
3298 __ ldr(r2, FieldMemOperand(r1, literal_offset));
3299
3300 // Check whether we need to materialize the object literal boilerplate.
3301 // If so, jump to the deferred code.
3302 __ cmp(r2, Operand(Factory::undefined_value()));
3303 __ b(eq, deferred->enter());
3304 __ bind(deferred->exit());
3305
3306 // Push the object literal boilerplate.
mads.s.ager31e71382008-08-13 09:32:07 +00003307 __ push(r2);
3308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309 // Clone the boilerplate object.
3310 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003311 __ push(r0); // save the result
3312 // r0: cloned object literal
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003313
3314 for (int i = 0; i < node->properties()->length(); i++) {
3315 ObjectLiteral::Property* property = node->properties()->at(i);
3316 Literal* key = property->key();
3317 Expression* value = property->value();
3318 switch (property->kind()) {
3319 case ObjectLiteral::Property::CONSTANT: break;
3320 case ObjectLiteral::Property::COMPUTED: // fall through
3321 case ObjectLiteral::Property::PROTOTYPE: {
mads.s.ager31e71382008-08-13 09:32:07 +00003322 __ push(r0); // dup the result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003323 Load(key);
3324 Load(value);
3325 __ CallRuntime(Runtime::kSetProperty, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003326 // restore r0
3327 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003328 break;
3329 }
3330 case ObjectLiteral::Property::SETTER: {
3331 __ push(r0);
3332 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00003333 __ mov(r0, Operand(Smi::FromInt(1)));
3334 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003335 Load(value);
3336 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003337 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003338 break;
3339 }
3340 case ObjectLiteral::Property::GETTER: {
3341 __ push(r0);
3342 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00003343 __ mov(r0, Operand(Smi::FromInt(0)));
3344 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003345 Load(value);
3346 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00003347 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 break;
3349 }
3350 }
3351 }
3352}
3353
3354
3355void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
3356 Comment cmnt(masm_, "[ ArrayLiteral");
3357 // Load the resulting object.
3358 Load(node->result());
3359 for (int i = 0; i < node->values()->length(); i++) {
3360 Expression* value = node->values()->at(i);
3361
3362 // If value is literal the property value is already
3363 // set in the boilerplate object.
3364 if (value->AsLiteral() == NULL) {
3365 // The property must be set by generated code.
3366 Load(value);
mads.s.ager31e71382008-08-13 09:32:07 +00003367 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003368
3369 // Fetch the object literal
3370 __ ldr(r1, MemOperand(sp, 0));
3371 // Get the elements array.
3372 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
3373
3374 // Write to the indexed properties array.
3375 int offset = i * kPointerSize + Array::kHeaderSize;
3376 __ str(r0, FieldMemOperand(r1, offset));
3377
3378 // Update the write barrier for the array address.
3379 __ mov(r3, Operand(offset));
3380 __ RecordWrite(r1, r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381 }
3382 }
3383}
3384
3385
3386void ArmCodeGenerator::VisitAssignment(Assignment* node) {
3387 Comment cmnt(masm_, "[ Assignment");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 if (FLAG_debug_info) RecordStatementPosition(node);
mads.s.ager31e71382008-08-13 09:32:07 +00003389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390 Reference target(this, node->target());
3391 if (target.is_illegal()) return;
3392
3393 if (node->op() == Token::ASSIGN ||
3394 node->op() == Token::INIT_VAR ||
3395 node->op() == Token::INIT_CONST) {
3396 Load(node->value());
3397
3398 } else {
3399 GetValue(&target);
3400 Literal* literal = node->value()->AsLiteral();
3401 if (literal != NULL && literal->handle()->IsSmi()) {
3402 SmiOperation(node->binary_op(), literal->handle(), false);
mads.s.ager31e71382008-08-13 09:32:07 +00003403 __ push(r0);
3404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 } else {
3406 Load(node->value());
kasper.lund7276f142008-07-30 08:49:36 +00003407 GenericBinaryOperation(node->binary_op());
mads.s.ager31e71382008-08-13 09:32:07 +00003408 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 }
3410 }
3411
3412 Variable* var = node->target()->AsVariableProxy()->AsVariable();
3413 if (var != NULL &&
3414 (var->mode() == Variable::CONST) &&
3415 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
3416 // Assignment ignored - leave the value on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 } else {
3419 __ RecordPosition(node->position());
3420 if (node->op() == Token::INIT_CONST) {
3421 // Dynamic constant initializations must use the function context
3422 // and initialize the actual constant declared. Dynamic variable
3423 // initializations are simply assignments and use SetValue.
3424 InitConst(&target);
3425 } else {
3426 SetValue(&target);
3427 }
3428 }
3429}
3430
3431
3432void ArmCodeGenerator::VisitThrow(Throw* node) {
3433 Comment cmnt(masm_, "[ Throw");
3434
3435 Load(node->exception());
3436 __ RecordPosition(node->position());
3437 __ CallRuntime(Runtime::kThrow, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003438 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439}
3440
3441
3442void ArmCodeGenerator::VisitProperty(Property* node) {
3443 Comment cmnt(masm_, "[ Property");
3444 if (is_referenced()) {
3445 __ RecordPosition(node->position());
3446 AccessReferenceProperty(node->key(), access());
mads.s.ager31e71382008-08-13 09:32:07 +00003447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 } else {
3449 // All stores are through references.
3450 ASSERT(access() != CodeGenState::STORE);
3451 Reference property(this, node);
3452 __ RecordPosition(node->position());
3453 GetValue(&property);
3454 }
3455}
3456
3457
3458void ArmCodeGenerator::VisitCall(Call* node) {
3459 Comment cmnt(masm_, "[ Call");
3460
3461 ZoneList<Expression*>* args = node->arguments();
3462
3463 if (FLAG_debug_info) RecordStatementPosition(node);
3464 // Standard function call.
3465
3466 // Check if the function is a variable or a property.
3467 Expression* function = node->expression();
3468 Variable* var = function->AsVariableProxy()->AsVariable();
3469 Property* property = function->AsProperty();
3470
3471 // ------------------------------------------------------------------------
3472 // Fast-case: Use inline caching.
3473 // ---
3474 // According to ECMA-262, section 11.2.3, page 44, the function to call
3475 // must be resolved after the arguments have been evaluated. The IC code
3476 // automatically handles this by loading the arguments before the function
3477 // is resolved in cache misses (this also holds for megamorphic calls).
3478 // ------------------------------------------------------------------------
3479
3480 if (var != NULL && !var->is_this() && var->is_global()) {
3481 // ----------------------------------
3482 // JavaScript example: 'foo(1, 2, 3)' // foo is global
3483 // ----------------------------------
3484
3485 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003486 __ mov(r0, Operand(var->name()));
3487 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 LoadGlobal();
3489
3490 // Load the arguments.
3491 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492
3493 // Setup the receiver register and call the IC initialization code.
3494 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 __ RecordPosition(node->position());
3496 __ Call(stub, code_target_context);
3497 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003498 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003499 __ pop();
3500 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501
3502 } else if (var != NULL && var->slot() != NULL &&
3503 var->slot()->type() == Slot::LOOKUP) {
3504 // ----------------------------------
3505 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
3506 // ----------------------------------
3507
3508 // Load the function
mads.s.ager31e71382008-08-13 09:32:07 +00003509 __ push(cp);
3510 __ mov(r0, Operand(var->name()));
3511 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 __ CallRuntime(Runtime::kLoadContextSlot, 2);
3513 // r0: slot value; r1: receiver
3514
3515 // Load the receiver.
mads.s.ager31e71382008-08-13 09:32:07 +00003516 __ push(r0); // function
3517 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 // Call the function.
3520 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003521 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522
3523 } else if (property != NULL) {
3524 // Check if the key is a literal string.
3525 Literal* literal = property->key()->AsLiteral();
3526
3527 if (literal != NULL && literal->handle()->IsSymbol()) {
3528 // ------------------------------------------------------------------
3529 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
3530 // ------------------------------------------------------------------
3531
3532 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003533 __ mov(r0, Operand(literal->handle()));
3534 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 Load(property->obj());
3536
3537 // Load the arguments.
3538 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539
3540 // Set the receiver register and call the IC initialization code.
3541 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542 __ RecordPosition(node->position());
3543 __ Call(stub, code_target);
3544 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3545
3546 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003547 __ pop();
3548
3549 __ push(r0); // push after get rid of function from the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003550
3551 } else {
3552 // -------------------------------------------
3553 // JavaScript example: 'array[index](1, 2, 3)'
3554 // -------------------------------------------
3555
3556 // Load the function to call from the property through a reference.
3557 Reference ref(this, property);
mads.s.ager31e71382008-08-13 09:32:07 +00003558 GetValue(&ref); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559
3560 // Pass receiver to called function.
mads.s.ager31e71382008-08-13 09:32:07 +00003561 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
3562 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 // Call the function.
3564 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003565 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567
3568 } else {
3569 // ----------------------------------
3570 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
3571 // ----------------------------------
3572
3573 // Load the function.
3574 Load(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575 // Pass the global object as the receiver.
3576 LoadGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577 // Call the function.
3578 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00003579 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 }
3581}
3582
3583
3584void ArmCodeGenerator::VisitCallNew(CallNew* node) {
3585 Comment cmnt(masm_, "[ CallNew");
3586
3587 // According to ECMA-262, section 11.2.2, page 44, the function
3588 // expression in new calls must be evaluated before the
3589 // arguments. This is different from ordinary calls, where the
3590 // actual function to call is resolved after the arguments have been
3591 // evaluated.
3592
3593 // Compute function to call and use the global object as the
3594 // receiver.
3595 Load(node->expression());
3596 LoadGlobal();
3597
3598 // Push the arguments ("left-to-right") on the stack.
3599 ZoneList<Expression*>* args = node->arguments();
3600 for (int i = 0; i < args->length(); i++) Load(args->at(i));
3601
mads.s.ager31e71382008-08-13 09:32:07 +00003602 // r0: the number of arguments.
3603 __ mov(r0, Operand(args->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604
3605 // Call the construct call builtin that handles allocation and
3606 // constructor invocation.
3607 __ RecordPosition(position);
3608 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
3609 js_construct_call);
mads.s.ager31e71382008-08-13 09:32:07 +00003610
3611 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
3612 __ str(r0, MemOperand(sp, 0 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613}
3614
3615
3616void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) {
3617 ASSERT(args->length() == 1);
3618 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003619 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3621}
3622
3623
3624void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) {
3625 ASSERT(args->length() == 0);
mads.s.ager31e71382008-08-13 09:32:07 +00003626 __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3627 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628}
3629
3630
3631void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) {
3632 ASSERT(args->length() == 1);
3633 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003634 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kReceiverOffset));
3636}
3637
3638
3639void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) {
3640 ASSERT(args->length() == 1);
3641 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003642 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
3644 __ str(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003645 __ mov(r0, Operand(Smi::FromInt(0))); // return a meaningful value
3646 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647}
3648
3649
3650void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) {
3651 ASSERT(args->length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
3653 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00003654 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655}
3656
3657
3658void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
3659 ASSERT(args->length() == 1);
3660 Label leave;
3661 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003662 __ pop(r0); // r0 contains object.
3663 // if (object->IsSmi()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 __ tst(r0, Operand(kSmiTagMask));
3665 __ b(eq, &leave);
3666 // It is a heap object - get map.
3667 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3668 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003669 // if (!object->IsJSValue()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 __ cmp(r1, Operand(JS_VALUE_TYPE));
3671 __ b(ne, &leave);
3672 // Load the value.
3673 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
3674 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00003675 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676}
3677
3678
3679void ArmCodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
3680 ASSERT(args->length() == 2);
3681 Label leave;
3682 Load(args->at(0)); // Load the object.
3683 Load(args->at(1)); // Load the value.
mads.s.ager31e71382008-08-13 09:32:07 +00003684 __ pop(r0); // r0 contains value
3685 __ pop(r1); // r1 contains object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686 // if (object->IsSmi()) return object.
3687 __ tst(r1, Operand(kSmiTagMask));
3688 __ b(eq, &leave);
3689 // It is a heap object - get map.
3690 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3691 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3692 // if (!object->IsJSValue()) return object.
3693 __ cmp(r2, Operand(JS_VALUE_TYPE));
3694 __ b(ne, &leave);
3695 // Store the value.
3696 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
3697 // Update the write barrier.
3698 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
3699 __ RecordWrite(r1, r2, r3);
3700 // Leave.
3701 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00003702 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703}
3704
3705
3706void ArmCodeGenerator::GenerateTailCallWithArguments(
3707 ZoneList<Expression*>* args) {
3708 // r0 = number of arguments (smi)
3709 ASSERT(args->length() == 1);
3710 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003711 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
3713
3714 // r1 = new function (previously written to stack)
3715 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3716
3717 // Reset parameter pointer and frame pointer to previous frame
kasper.lund7276f142008-07-30 08:49:36 +00003718 ExitJSFrame(DO_NOT_RETURN);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719
3720 // Jump (tail-call) to the function in register r1.
3721 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
3722 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3723 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
3724 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725}
3726
3727
3728void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) {
3729 ASSERT(args->length() == 3);
mads.s.ager31e71382008-08-13 09:32:07 +00003730 // r0 = args[i]; r1 = i
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 Comment cmnt(masm_, "[ GenerateSetArgument");
mads.s.ager31e71382008-08-13 09:32:07 +00003732 Load(args->at(1)); // args[i] (value)
3733 Load(args->at(0)); // i
3734 __ pop(r1); // i
3735 __ pop(r0); // value
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736#if defined(DEBUG)
3737 { Label L;
mads.s.ager31e71382008-08-13 09:32:07 +00003738 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 __ b(eq, &L);
3740 __ stop("SMI expected");
3741 __ bind(&L);
3742 }
3743#endif // defined(DEBUG)
3744 __ add(r2, pp, Operand(JavaScriptFrameConstants::kParam0Offset));
mads.s.ager31e71382008-08-13 09:32:07 +00003745 __ str(r0,
3746 MemOperand(r2, r1, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset));
3747 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748}
3749
3750
3751void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) {
3752 ASSERT(args->length() == 2);
mads.s.ager31e71382008-08-13 09:32:07 +00003753 Load(args->at(0)); // old number of arguments
3754 Load(args->at(1)); // new number of arguments, r1 > r0
3755 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00003757 __ pop(r1);
3758 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 // r1 = number of words to move stack.
3760 __ sub(r1, r1, Operand(r0));
3761 // r2 is source.
3762 __ add(r2, fp, Operand(StandardFrameConstants::kCallerPCOffset));
3763 // Move down frame pointer fp.
3764 __ add(fp, fp, Operand(r1, LSL, kPointerSizeLog2));
3765 // r1 is destination.
3766 __ add(r1, fp, Operand(StandardFrameConstants::kCallerPCOffset));
3767
3768 Label move;
3769 __ bind(&move);
3770 __ ldr(r3, MemOperand(r2, -kPointerSize, PostIndex));
3771 __ str(r3, MemOperand(r1, -kPointerSize, PostIndex));
3772 __ cmp(r2, Operand(sp));
3773 __ b(ne, &move);
3774 __ ldr(r3, MemOperand(r2));
3775 __ str(r3, MemOperand(r1));
3776
3777 // Move down stack pointer esp.
3778 __ mov(sp, Operand(r1));
mads.s.ager31e71382008-08-13 09:32:07 +00003779 // Put something GC-able in r0.
3780 __ mov(r0, Operand(Smi::FromInt(0)));
3781 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782}
3783
3784
3785void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) {
3786 ASSERT(args->length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 Load(args->at(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003789 __ pop(r0); // new number of arguments
3790 __ pop(r1); // old number of arguments, r1 > r0
3791 __ mov(r1, Operand(r1, LSR, kSmiTagSize));
3792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003793 // r1 = number of words to move stack.
3794 __ sub(r1, r1, Operand(r0, LSR, kSmiTagSize));
3795 Label end_of_expand_frame;
3796 if (FLAG_check_stack) {
3797 Label not_too_big;
3798 __ sub(r2, sp, Operand(r1, LSL, kPointerSizeLog2));
3799 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
3800 __ ldr(ip, MemOperand(ip));
3801 __ cmp(r2, Operand(ip));
3802 __ b(gt, &not_too_big);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 __ mov(r0, Operand(Factory::false_value()));
3804 __ b(&end_of_expand_frame);
3805 __ bind(&not_too_big);
3806 }
3807 // r3 is source.
3808 __ mov(r3, Operand(sp));
3809 // r0 is copy limit + 1 word
3810 __ add(r0, fp,
3811 Operand(StandardFrameConstants::kCallerPCOffset + kPointerSize));
3812 // Move up frame pointer fp.
3813 __ sub(fp, fp, Operand(r1, LSL, kPointerSizeLog2));
3814 // Move up stack pointer sp.
3815 __ sub(sp, sp, Operand(r1, LSL, kPointerSizeLog2));
3816 // r1 is destination (r1 = source - r1).
3817 __ mov(r2, Operand(0));
3818 __ sub(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
3819 __ add(r1, r3, Operand(r2));
3820
3821 Label move;
3822 __ bind(&move);
3823 __ ldr(r2, MemOperand(r3, kPointerSize, PostIndex));
3824 __ str(r2, MemOperand(r1, kPointerSize, PostIndex));
3825 __ cmp(r3, Operand(r0));
3826 __ b(ne, &move);
3827
mads.s.ager31e71382008-08-13 09:32:07 +00003828 // Put success value in top of stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829 __ mov(r0, Operand(Factory::true_value()));
3830 __ bind(&end_of_expand_frame);
mads.s.ager31e71382008-08-13 09:32:07 +00003831 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832}
3833
3834
3835void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
3836 ASSERT(args->length() == 1);
3837 Load(args->at(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 __ pop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003839 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 cc_reg_ = eq;
3841}
3842
3843
kasper.lund7276f142008-07-30 08:49:36 +00003844// This should generate code that performs a charCodeAt() call or returns
3845// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3846// It is not yet implemented on ARM, so it always goes to the slow case.
3847void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
3848 ASSERT(args->length() == 2);
kasper.lund7276f142008-07-30 08:49:36 +00003849 __ mov(r0, Operand(Factory::undefined_value()));
mads.s.ager31e71382008-08-13 09:32:07 +00003850 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003851}
3852
3853
3854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003855// This is used in the implementation of apply on ia32 but it is not
3856// used on ARM yet.
3857void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
kasper.lund7276f142008-07-30 08:49:36 +00003858 __ stop("ArmCodeGenerator::GenerateIsArray");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859 cc_reg_ = eq;
3860}
3861
3862
3863void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
3864 ASSERT(args->length() == 0);
3865
mads.s.ager31e71382008-08-13 09:32:07 +00003866 // Seed the result with the formal parameters count, which will be used
3867 // in case no arguments adaptor frame is found below the current frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003868 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
3869
3870 // Call the shared stub to get to the arguments.length.
3871 ArgumentsAccessStub stub(true);
3872 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003873 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874}
3875
3876
3877void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3878 ASSERT(args->length() == 1);
3879
3880 // Load the key onto the stack and set register r1 to the formal
3881 // parameters count for the currently executing function.
3882 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00003883 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003884 __ mov(r1, Operand(Smi::FromInt(scope_->num_parameters())));
3885
3886 // Call the shared stub to get to arguments[key].
3887 ArgumentsAccessStub stub(false);
3888 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00003889 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890}
3891
3892
3893void ArmCodeGenerator::GenerateShiftDownAndTailCall(
3894 ZoneList<Expression*>* args) {
mads.s.ager31e71382008-08-13 09:32:07 +00003895 // r0 = number of arguments
3896 ASSERT(args->length() == 1);
3897 Load(args->at(0));
3898 __ pop(r0);
3899 __ mov(r0, Operand(r0, LSR, kSmiTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003900
mads.s.ager31e71382008-08-13 09:32:07 +00003901 // Get the 'this' function and exit the frame without returning.
3902 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset));
3903 ExitJSFrame(DO_NOT_RETURN);
3904 // return address in lr
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003905
mads.s.ager31e71382008-08-13 09:32:07 +00003906 // Move arguments one element down the stack.
3907 Label move;
3908 Label moved;
3909 __ sub(r2, r0, Operand(0), SetCC);
3910 __ b(eq, &moved);
3911 __ bind(&move);
3912 __ sub(ip, r2, Operand(1));
3913 __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2));
3914 __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2));
3915 __ sub(r2, r2, Operand(1), SetCC);
3916 __ b(ne, &move);
3917 __ bind(&moved);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918
mads.s.ager31e71382008-08-13 09:32:07 +00003919 // Remove the TOS (copy of last argument)
3920 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003921
mads.s.ager31e71382008-08-13 09:32:07 +00003922 // Jump (tail-call) to the function in register r1.
3923 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
3924 __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
3925 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset));
3926 __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
3927
3928 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929}
3930
3931
3932void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) {
3933 if (CheckForInlineRuntimeCall(node))
3934 return;
3935
3936 ZoneList<Expression*>* args = node->arguments();
3937 Comment cmnt(masm_, "[ CallRuntime");
3938 Runtime::Function* function = node->function();
3939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940 if (function != NULL) {
mads.s.ager31e71382008-08-13 09:32:07 +00003941 // Push the arguments ("left-to-right").
3942 for (int i = 0; i < args->length(); i++) Load(args->at(i));
3943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 // Call the C runtime function.
3945 __ CallRuntime(function, args->length());
mads.s.ager31e71382008-08-13 09:32:07 +00003946 __ push(r0);
3947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00003949 // Prepare stack for calling JS runtime function.
3950 __ mov(r0, Operand(node->name()));
3951 __ push(r0);
3952 // Push the builtins object found in the current global object.
3953 __ ldr(r1, GlobalObject());
3954 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
3955 __ push(r0);
3956
3957 for (int i = 0; i < args->length(); i++) Load(args->at(i));
3958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 // Call the JS runtime function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 Handle<Code> stub = ComputeCallInitialize(args->length());
3961 __ Call(stub, code_target);
3962 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003963 __ pop();
3964 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 }
3966}
3967
3968
3969void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
3970 Comment cmnt(masm_, "[ UnaryOperation");
3971
3972 Token::Value op = node->op();
3973
3974 if (op == Token::NOT) {
3975 LoadCondition(node->expression(),
3976 CodeGenState::LOAD,
3977 false_target(),
3978 true_target(),
3979 true);
3980 cc_reg_ = NegateCondition(cc_reg_);
3981
3982 } else if (op == Token::DELETE) {
3983 Property* property = node->expression()->AsProperty();
mads.s.ager31e71382008-08-13 09:32:07 +00003984 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 if (property != NULL) {
3986 Load(property->obj());
3987 Load(property->key());
mads.s.ager31e71382008-08-13 09:32:07 +00003988 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990
mads.s.ager31e71382008-08-13 09:32:07 +00003991 } else if (variable != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 Slot* slot = variable->slot();
3993 if (variable->is_global()) {
3994 LoadGlobal();
mads.s.ager31e71382008-08-13 09:32:07 +00003995 __ mov(r0, Operand(variable->name()));
3996 __ push(r0);
3997 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999
4000 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
4001 // lookup the context holding the named variable
mads.s.ager31e71382008-08-13 09:32:07 +00004002 __ push(cp);
4003 __ mov(r0, Operand(variable->name()));
4004 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 __ CallRuntime(Runtime::kLookupContext, 2);
4006 // r0: context
mads.s.ager31e71382008-08-13 09:32:07 +00004007 __ push(r0);
4008 __ mov(r0, Operand(variable->name()));
4009 __ push(r0);
4010 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 __ InvokeBuiltin("DELETE", 1, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012
mads.s.ager31e71382008-08-13 09:32:07 +00004013 } else {
4014 // Default: Result of deleting non-global, not dynamically
4015 // introduced variables is false.
4016 __ mov(r0, Operand(Factory::false_value()));
4017 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018
4019 } else {
4020 // Default: Result of deleting expressions is true.
4021 Load(node->expression()); // may have side-effects
mads.s.ager31e71382008-08-13 09:32:07 +00004022 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 __ mov(r0, Operand(Factory::true_value()));
4024 }
mads.s.ager31e71382008-08-13 09:32:07 +00004025 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026
4027 } else if (op == Token::TYPEOF) {
4028 // Special case for loading the typeof expression; see comment on
4029 // LoadTypeofExpression().
4030 LoadTypeofExpression(node->expression());
4031 __ CallRuntime(Runtime::kTypeof, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00004032 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033
4034 } else {
4035 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004036 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 switch (op) {
4038 case Token::NOT:
4039 case Token::DELETE:
4040 case Token::TYPEOF:
4041 UNREACHABLE(); // handled above
4042 break;
4043
4044 case Token::SUB: {
4045 UnarySubStub stub;
4046 __ CallStub(&stub);
4047 break;
4048 }
4049
4050 case Token::BIT_NOT: {
4051 // smi check
4052 Label smi_label;
4053 Label continue_label;
4054 __ tst(r0, Operand(kSmiTagMask));
4055 __ b(eq, &smi_label);
4056
mads.s.ager31e71382008-08-13 09:32:07 +00004057 __ push(r0);
4058 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 __ InvokeBuiltin("BIT_NOT", 0, CALL_JS);
4060
4061 __ b(&continue_label);
4062 __ bind(&smi_label);
4063 __ mvn(r0, Operand(r0));
4064 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
4065 __ bind(&continue_label);
4066 break;
4067 }
4068
4069 case Token::VOID:
4070 // since the stack top is cached in r0, popping and then
4071 // pushing a value can be done by just writing to r0.
4072 __ mov(r0, Operand(Factory::undefined_value()));
4073 break;
4074
4075 case Token::ADD:
mads.s.ager31e71382008-08-13 09:32:07 +00004076 __ push(r0);
4077 __ mov(r0, Operand(0)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 __ InvokeBuiltin("TO_NUMBER", 0, CALL_JS);
4079 break;
4080
4081 default:
4082 UNREACHABLE();
4083 }
mads.s.ager31e71382008-08-13 09:32:07 +00004084 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 }
4086}
4087
4088
4089void ArmCodeGenerator::VisitCountOperation(CountOperation* node) {
4090 Comment cmnt(masm_, "[ CountOperation");
4091
4092 bool is_postfix = node->is_postfix();
4093 bool is_increment = node->op() == Token::INC;
4094
4095 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
4096 bool is_const = (var != NULL && var->mode() == Variable::CONST);
4097
4098 // Postfix: Make room for the result.
mads.s.ager31e71382008-08-13 09:32:07 +00004099 if (is_postfix) {
4100 __ mov(r0, Operand(0));
4101 __ push(r0);
4102 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103
4104 { Reference target(this, node->expression());
4105 if (target.is_illegal()) return;
4106 GetValue(&target);
mads.s.ager31e71382008-08-13 09:32:07 +00004107 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108
4109 Label slow, exit;
4110
4111 // Load the value (1) into register r1.
4112 __ mov(r1, Operand(Smi::FromInt(1)));
4113
4114 // Check for smi operand.
4115 __ tst(r0, Operand(kSmiTagMask));
4116 __ b(ne, &slow);
4117
4118 // Postfix: Store the old value as the result.
4119 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4120
4121 // Perform optimistic increment/decrement.
4122 if (is_increment) {
4123 __ add(r0, r0, Operand(r1), SetCC);
4124 } else {
4125 __ sub(r0, r0, Operand(r1), SetCC);
4126 }
4127
4128 // If the increment/decrement didn't overflow, we're done.
4129 __ b(vc, &exit);
4130
4131 // Revert optimistic increment/decrement.
4132 if (is_increment) {
4133 __ sub(r0, r0, Operand(r1));
4134 } else {
4135 __ add(r0, r0, Operand(r1));
4136 }
4137
4138 // Slow case: Convert to number.
4139 __ bind(&slow);
4140
4141 // Postfix: Convert the operand to a number and store it as the result.
4142 if (is_postfix) {
4143 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
4144 __ CallStub(&stub);
4145 // Store to result (on the stack).
4146 __ str(r0, MemOperand(sp, target.size() * kPointerSize));
4147 }
4148
4149 // Compute the new value by calling the right JavaScript native.
4150 if (is_increment) {
4151 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
4152 __ CallStub(&stub);
4153 } else {
4154 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
4155 __ CallStub(&stub);
4156 }
4157
4158 // Store the new value in the target if not const.
4159 __ bind(&exit);
mads.s.ager31e71382008-08-13 09:32:07 +00004160 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 if (!is_const) SetValue(&target);
4162 }
4163
4164 // Postfix: Discard the new value and use the old.
4165 if (is_postfix) __ pop(r0);
4166}
4167
4168
4169void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
4170 Comment cmnt(masm_, "[ BinaryOperation");
4171 Token::Value op = node->op();
4172
4173 // According to ECMA-262 section 11.11, page 58, the binary logical
4174 // operators must yield the result of one of the two expressions
4175 // before any ToBoolean() conversions. This means that the value
4176 // produced by a && or || operator is not necessarily a boolean.
4177
4178 // NOTE: If the left hand side produces a materialized value (not in
4179 // the CC register), we force the right hand side to do the
4180 // same. This is necessary because we may have to branch to the exit
4181 // after evaluating the left hand side (due to the shortcut
4182 // semantics), but the compiler must (statically) know if the result
4183 // of compiling the binary operation is materialized or not.
4184
4185 if (op == Token::AND) {
4186 Label is_true;
4187 LoadCondition(node->left(),
4188 CodeGenState::LOAD,
4189 &is_true,
4190 false_target(),
4191 false);
4192 if (has_cc()) {
4193 Branch(false, false_target());
4194
4195 // Evaluate right side expression.
4196 __ bind(&is_true);
4197 LoadCondition(node->right(),
4198 CodeGenState::LOAD,
4199 true_target(),
4200 false_target(),
4201 false);
4202
4203 } else {
4204 Label pop_and_continue, exit;
4205
mads.s.ager31e71382008-08-13 09:32:07 +00004206 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
4207 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 // Avoid popping the result if it converts to 'false' using the
4209 // standard ToBoolean() conversion as described in ECMA-262,
4210 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004211 ToBoolean(&pop_and_continue, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 Branch(false, &exit);
4213
4214 // Pop the result of evaluating the first part.
4215 __ bind(&pop_and_continue);
4216 __ pop(r0);
4217
4218 // Evaluate right side expression.
4219 __ bind(&is_true);
4220 Load(node->right());
4221
4222 // Exit (always with a materialized value).
4223 __ bind(&exit);
4224 }
4225
4226 } else if (op == Token::OR) {
4227 Label is_false;
4228 LoadCondition(node->left(),
4229 CodeGenState::LOAD,
4230 true_target(),
4231 &is_false,
4232 false);
4233 if (has_cc()) {
4234 Branch(true, true_target());
4235
4236 // Evaluate right side expression.
4237 __ bind(&is_false);
4238 LoadCondition(node->right(),
4239 CodeGenState::LOAD,
4240 true_target(),
4241 false_target(),
4242 false);
4243
4244 } else {
4245 Label pop_and_continue, exit;
4246
mads.s.ager31e71382008-08-13 09:32:07 +00004247 __ ldr(r0, MemOperand(sp, 0));
4248 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 // Avoid popping the result if it converts to 'true' using the
4250 // standard ToBoolean() conversion as described in ECMA-262,
4251 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00004252 ToBoolean(&exit, &pop_and_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 Branch(true, &exit);
4254
4255 // Pop the result of evaluating the first part.
4256 __ bind(&pop_and_continue);
4257 __ pop(r0);
4258
4259 // Evaluate right side expression.
4260 __ bind(&is_false);
4261 Load(node->right());
4262
4263 // Exit (always with a materialized value).
4264 __ bind(&exit);
4265 }
4266
4267 } else {
4268 // Optimize for the case where (at least) one of the expressions
4269 // is a literal small integer.
4270 Literal* lliteral = node->left()->AsLiteral();
4271 Literal* rliteral = node->right()->AsLiteral();
4272
4273 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
4274 Load(node->left());
4275 SmiOperation(node->op(), rliteral->handle(), false);
4276
4277 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
4278 Load(node->right());
4279 SmiOperation(node->op(), lliteral->handle(), true);
4280
4281 } else {
4282 Load(node->left());
4283 Load(node->right());
kasper.lund7276f142008-07-30 08:49:36 +00004284 GenericBinaryOperation(node->op());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004285 }
mads.s.ager31e71382008-08-13 09:32:07 +00004286 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004287 }
4288}
4289
4290
4291void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) {
mads.s.ager31e71382008-08-13 09:32:07 +00004292 __ ldr(r0, FunctionOperand());
4293 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004294}
4295
4296
4297void ArmCodeGenerator::VisitCompareOperation(CompareOperation* node) {
4298 Comment cmnt(masm_, "[ CompareOperation");
4299
4300 // Get the expressions from the node.
4301 Expression* left = node->left();
4302 Expression* right = node->right();
4303 Token::Value op = node->op();
4304
4305 // NOTE: To make null checks efficient, we check if either left or
4306 // right is the literal 'null'. If so, we optimize the code by
4307 // inlining a null check instead of calling the (very) general
4308 // runtime routine for checking equality.
4309
4310 bool left_is_null =
4311 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
4312 bool right_is_null =
4313 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
4314
4315 if (op == Token::EQ || op == Token::EQ_STRICT) {
4316 // The 'null' value is only equal to 'null' or 'undefined'.
4317 if (left_is_null || right_is_null) {
4318 Load(left_is_null ? right : left);
4319 Label exit, undetectable;
mads.s.ager31e71382008-08-13 09:32:07 +00004320 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 __ cmp(r0, Operand(Factory::null_value()));
4322
4323 // The 'null' value is only equal to 'undefined' if using
4324 // non-strict comparisons.
4325 if (op != Token::EQ_STRICT) {
4326 __ b(eq, &exit);
4327 __ cmp(r0, Operand(Factory::undefined_value()));
4328
4329 // NOTE: it can be undetectable object.
4330 __ b(eq, &exit);
4331 __ tst(r0, Operand(kSmiTagMask));
4332
4333 __ b(ne, &undetectable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 __ b(false_target());
4335
4336 __ bind(&undetectable);
4337 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
4338 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4339 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4340 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4341 }
4342
4343 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344
4345 cc_reg_ = eq;
4346 return;
4347 }
4348 }
4349
4350
4351 // NOTE: To make typeof testing for natives implemented in
4352 // JavaScript really efficient, we generate special code for
4353 // expressions of the form: 'typeof <expression> == <string>'.
4354
4355 UnaryOperation* operation = left->AsUnaryOperation();
4356 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
4357 (operation != NULL && operation->op() == Token::TYPEOF) &&
4358 (right->AsLiteral() != NULL &&
4359 right->AsLiteral()->handle()->IsString())) {
4360 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
4361
mads.s.ager31e71382008-08-13 09:32:07 +00004362 // Load the operand, move it to register r1.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004363 LoadTypeofExpression(operation->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00004364 __ pop(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365
4366 if (check->Equals(Heap::number_symbol())) {
4367 __ tst(r1, Operand(kSmiTagMask));
4368 __ b(eq, true_target());
4369 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4370 __ cmp(r1, Operand(Factory::heap_number_map()));
4371 cc_reg_ = eq;
4372
4373 } else if (check->Equals(Heap::string_symbol())) {
4374 __ tst(r1, Operand(kSmiTagMask));
4375 __ b(eq, false_target());
4376
4377 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4378
4379 // NOTE: it might be an undetectable string object
4380 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4381 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4382 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4383 __ b(eq, false_target());
4384
4385 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4386 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
4387 cc_reg_ = lt;
4388
4389 } else if (check->Equals(Heap::boolean_symbol())) {
4390 __ cmp(r1, Operand(Factory::true_value()));
4391 __ b(eq, true_target());
4392 __ cmp(r1, Operand(Factory::false_value()));
4393 cc_reg_ = eq;
4394
4395 } else if (check->Equals(Heap::undefined_symbol())) {
4396 __ cmp(r1, Operand(Factory::undefined_value()));
4397 __ b(eq, true_target());
4398
4399 __ tst(r1, Operand(kSmiTagMask));
4400 __ b(eq, false_target());
4401
4402 // NOTE: it can be undetectable object.
4403 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4404 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
4405 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
4406 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
4407
4408 cc_reg_ = eq;
4409
4410 } else if (check->Equals(Heap::function_symbol())) {
4411 __ tst(r1, Operand(kSmiTagMask));
4412 __ b(eq, false_target());
4413 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
4414 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
4415 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
4416 cc_reg_ = eq;
4417
4418 } else if (check->Equals(Heap::object_symbol())) {
4419 __ tst(r1, Operand(kSmiTagMask));
4420 __ b(eq, false_target());
4421
4422 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
4423 __ cmp(r1, Operand(Factory::null_value()));
4424 __ b(eq, true_target());
4425
4426 // NOTE: it might be an undetectable object.
4427 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
4428 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
4429 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
4430 __ b(eq, false_target());
4431
4432 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4433 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
4434 __ b(lt, false_target());
4435 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
4436 cc_reg_ = le;
4437
4438 } else {
4439 // Uncommon case: Typeof testing against a string literal that
4440 // is never returned from the typeof operator.
4441 __ b(false_target());
4442 }
4443 return;
4444 }
4445
4446 Load(left);
4447 Load(right);
4448 switch (op) {
4449 case Token::EQ:
4450 Comparison(eq, false);
4451 break;
4452
4453 case Token::LT:
4454 Comparison(lt);
4455 break;
4456
4457 case Token::GT:
4458 Comparison(gt);
4459 break;
4460
4461 case Token::LTE:
4462 Comparison(le);
4463 break;
4464
4465 case Token::GTE:
4466 Comparison(ge);
4467 break;
4468
4469 case Token::EQ_STRICT:
4470 Comparison(eq, true);
4471 break;
4472
4473 case Token::IN:
mads.s.ager31e71382008-08-13 09:32:07 +00004474 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 __ InvokeBuiltin("IN", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004476 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 break;
4478
4479 case Token::INSTANCEOF:
mads.s.ager31e71382008-08-13 09:32:07 +00004480 __ mov(r0, Operand(1)); // not counting receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 __ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00004482 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 break;
4484
4485 default:
4486 UNREACHABLE();
4487 }
4488}
4489
4490
4491void ArmCodeGenerator::RecordStatementPosition(Node* node) {
4492 if (FLAG_debug_info) {
4493 int statement_pos = node->statement_pos();
4494 if (statement_pos == kNoPosition) return;
4495 __ RecordStatementPosition(statement_pos);
4496 }
4497}
4498
4499
kasper.lund7276f142008-07-30 08:49:36 +00004500void ArmCodeGenerator::EnterJSFrame(int argc) {
4501 __ EnterJSFrame(argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502}
4503
4504
kasper.lund7276f142008-07-30 08:49:36 +00004505void ArmCodeGenerator::ExitJSFrame(ExitJSFlag flag) {
4506 JSExitStub stub(flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 __ CallJSExitStub(&stub);
4508}
4509
4510
4511#undef __
4512
4513
4514// -----------------------------------------------------------------------------
4515// CodeGenerator interface
4516
4517// MakeCode() is just a wrapper for CodeGenerator::MakeCode()
4518// so we don't have to expose the entire CodeGenerator class in
4519// the .h file.
4520Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
4521 Handle<Script> script,
4522 bool is_eval) {
4523 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval);
4524 if (!code.is_null()) {
4525 Counters::total_compiled_code_size.Increment(code->instruction_size());
4526 }
4527 return code;
4528}
4529
4530
4531} } // namespace v8::internal