blob: 74f1ea74b754a30b4adf90aaac4ad8ed60dad972 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "scopes.h"
34#include "runtime.h"
35
36namespace v8 { namespace internal {
37
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000038// -------------------------------------------------------------------------
39// CodeGenState implementation.
40
ager@chromium.org7c537e22008-10-16 08:43:32 +000041CodeGenState::CodeGenState(CodeGenerator* owner)
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000042 : owner_(owner),
ager@chromium.org7c537e22008-10-16 08:43:32 +000043 typeof_state_(NOT_INSIDE_TYPEOF),
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000044 true_target_(NULL),
45 false_target_(NULL),
46 previous_(NULL) {
47 owner_->set_state(this);
48}
49
50
ager@chromium.org7c537e22008-10-16 08:43:32 +000051CodeGenState::CodeGenState(CodeGenerator* owner,
52 TypeofState typeof_state,
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000053 Label* true_target,
54 Label* false_target)
55 : owner_(owner),
ager@chromium.org7c537e22008-10-16 08:43:32 +000056 typeof_state_(typeof_state),
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000057 true_target_(true_target),
58 false_target_(false_target),
59 previous_(owner->state()) {
60 owner_->set_state(this);
61}
62
63
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000064CodeGenState::~CodeGenState() {
65 ASSERT(owner_->state() == this);
66 owner_->set_state(previous_);
67}
68
69
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070// -----------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +000071// CodeGenerator implementation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000073#define __ masm_->
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
ager@chromium.org7c537e22008-10-16 08:43:32 +000075CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
76 bool is_eval)
77 : is_eval_(is_eval),
78 script_(script),
79 deferred_(8),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000080 masm_(new MacroAssembler(NULL, buffer_size)),
81 scope_(NULL),
82 cc_reg_(al),
83 state_(NULL),
84 break_stack_height_(0) {
85}
86
87
88// Calling conventions:
89
mads.s.ager31e71382008-08-13 09:32:07 +000090// r0: the number of arguments
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// fp: frame pointer
92// sp: stack pointer
93// pp: caller's parameter pointer
94// cp: callee's context
95
ager@chromium.org7c537e22008-10-16 08:43:32 +000096void CodeGenerator::GenCode(FunctionLiteral* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 Scope* scope = fun->scope();
98 ZoneList<Statement*>* body = fun->body();
99
100 // Initialize state.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000101 { CodeGenState state(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102 scope_ = scope;
103 cc_reg_ = al;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
105 // Entry
106 // stack: function, receiver, arguments, return address
107 // r0: number of arguments
108 // sp: stack pointer
109 // fp: frame pointer
110 // pp: caller's parameter pointer
111 // cp: callee's context
112
113 { Comment cmnt(masm_, "[ enter JS frame");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000114 EnterJSFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 }
116 // tos: code slot
117#ifdef DEBUG
118 if (strlen(FLAG_stop_at) > 0 &&
119 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
kasper.lund7276f142008-07-30 08:49:36 +0000120 __ stop("stop-at");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 }
122#endif
123
124 // Allocate space for locals and initialize them.
kasper.lund7276f142008-07-30 08:49:36 +0000125 if (scope->num_stack_slots() > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 Comment cmnt(masm_, "[ allocate space for locals");
mads.s.ager31e71382008-08-13 09:32:07 +0000127 // Initialize stack slots with 'undefined' value.
128 __ mov(ip, Operand(Factory::undefined_value()));
129 for (int i = 0; i < scope->num_stack_slots(); i++) {
130 __ push(ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 }
132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133
134 if (scope->num_heap_slots() > 0) {
135 // Allocate local context.
136 // Get outer context and create a new context based on it.
mads.s.ager31e71382008-08-13 09:32:07 +0000137 __ ldr(r0, FunctionOperand());
138 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +0000139 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
140
141 if (kDebug) {
142 Label verified_true;
143 __ cmp(r0, Operand(cp));
144 __ b(eq, &verified_true);
145 __ stop("NewContext: r0 is expected to be the same as cp");
146 __ bind(&verified_true);
147 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148 // Update context local.
149 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
150 }
151
152 // TODO(1241774): Improve this code!!!
153 // 1) only needed if we have a context
154 // 2) no need to recompute context ptr every single time
155 // 3) don't copy parameter operand code from SlotOperand!
156 {
157 Comment cmnt2(masm_, "[ copy context parameters into .context");
158
159 // Note that iteration order is relevant here! If we have the same
160 // parameter twice (e.g., function (x, y, x)), and that parameter
161 // needs to be copied into the context, it must be the last argument
162 // passed to the parameter that needs to be copied. This is a rare
163 // case so we don't check for it, instead we rely on the copying
164 // order: such a parameter is copied repeatedly into the same
165 // context location and thus the last value is what is seen inside
166 // the function.
167 for (int i = 0; i < scope->num_parameters(); i++) {
168 Variable* par = scope->parameter(i);
169 Slot* slot = par->slot();
170 if (slot != NULL && slot->type() == Slot::CONTEXT) {
171 ASSERT(!scope->is_global_scope()); // no parameters in global scope
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000172 __ ldr(r1, ParameterOperand(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 // Loads r2 with context; used below in RecordWrite.
174 __ str(r1, SlotOperand(slot, r2));
175 // Load the offset into r3.
176 int slot_offset =
177 FixedArray::kHeaderSize + slot->index() * kPointerSize;
178 __ mov(r3, Operand(slot_offset));
179 __ RecordWrite(r2, r3, r1);
180 }
181 }
182 }
183
184 // Store the arguments object.
185 // This must happen after context initialization because
186 // the arguments array may be stored in the context!
187 if (scope->arguments() != NULL) {
188 ASSERT(scope->arguments_shadow() != NULL);
189 Comment cmnt(masm_, "[ allocate arguments object");
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000190 { Reference shadow_ref(this, scope->arguments_shadow());
191 { Reference arguments_ref(this, scope->arguments());
192 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
193 __ ldr(r2, FunctionOperand());
194 // The receiver is below the arguments, the return address,
195 // and the frame pointer on the stack.
196 const int kReceiverDisplacement = 2 + scope->num_parameters();
197 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
198 __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
199 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
200 __ CallStub(&stub);
201 __ push(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000202 arguments_ref.SetValue(NOT_CONST_INIT);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000203 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000204 shadow_ref.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000206 __ pop(r0); // Value is no longer needed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000207 }
208
209 // Generate code to 'execute' declarations and initialize
210 // functions (source elements). In case of an illegal
211 // redeclaration we need to handle that instead of processing the
212 // declarations.
213 if (scope->HasIllegalRedeclaration()) {
214 Comment cmnt(masm_, "[ illegal redeclarations");
215 scope->VisitIllegalRedeclaration(this);
216 } else {
217 Comment cmnt(masm_, "[ declarations");
mads.s.ager31e71382008-08-13 09:32:07 +0000218 // ProcessDeclarations calls DeclareGlobals indirectly
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 ProcessDeclarations(scope->declarations());
mads.s.ager31e71382008-08-13 09:32:07 +0000220
v8.team.kasperl727e9952008-09-02 14:56:44 +0000221 // Bail out if a stack-overflow exception occurred when
kasper.lund212ac232008-07-16 07:07:30 +0000222 // processing declarations.
223 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 }
225
mads.s.ager31e71382008-08-13 09:32:07 +0000226 if (FLAG_trace) {
227 // Push a valid value as the parameter. The runtime call only uses
228 // it as the return value to indicate non-failure.
229 __ mov(r0, Operand(Smi::FromInt(0)));
230 __ push(r0);
231 __ CallRuntime(Runtime::kTraceEnter, 1);
232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 CheckStack();
234
235 // Compile the body of the function in a vanilla state. Don't
236 // bother compiling all the code if the scope has an illegal
237 // redeclaration.
238 if (!scope->HasIllegalRedeclaration()) {
239 Comment cmnt(masm_, "[ function body");
240#ifdef DEBUG
241 bool is_builtin = Bootstrapper::IsActive();
242 bool should_trace =
243 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
mads.s.ager31e71382008-08-13 09:32:07 +0000244 if (should_trace) {
245 // Push a valid value as the parameter. The runtime call only uses
246 // it as the return value to indicate non-failure.
247 __ mov(r0, Operand(Smi::FromInt(0)));
248 __ push(r0);
249 __ CallRuntime(Runtime::kDebugTrace, 1);
250 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251#endif
252 VisitStatements(body);
253 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 }
255
256 // exit
257 // r0: result
258 // sp: stack pointer
259 // fp: frame pointer
260 // pp: parameter pointer
261 // cp: callee's context
mads.s.ager31e71382008-08-13 09:32:07 +0000262 __ mov(r0, Operand(Factory::undefined_value()));
263
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 __ bind(&function_return_);
mads.s.ager31e71382008-08-13 09:32:07 +0000265 if (FLAG_trace) {
266 // Push the return value on the stack as the parameter.
267 // Runtime::TraceExit returns the parameter as it is.
268 __ push(r0);
269 __ CallRuntime(Runtime::kTraceExit, 1);
270 }
271
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000272 // Tear down the frame which will restore the caller's frame pointer and the
273 // link register.
kasper.lund7276f142008-07-30 08:49:36 +0000274 ExitJSFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000276 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
277 __ mov(pc, lr);
278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279 // Code generation state must be reset.
280 scope_ = NULL;
281 ASSERT(!has_cc());
282 ASSERT(state_ == NULL);
283}
284
285
ager@chromium.org7c537e22008-10-16 08:43:32 +0000286MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
287 // Currently, this assertion will fail if we try to assign to
288 // a constant variable that is constant because it is read-only
289 // (such as the variable referring to a named function expression).
290 // We need to implement assignments to read-only variables.
291 // Ideally, we should do this during AST generation (by converting
292 // such assignments into expression statements); however, in general
293 // we may not be able to make the decision until past AST generation,
294 // that is when the entire program is known.
295 ASSERT(slot != NULL);
296 int index = slot->index();
297 switch (slot->type()) {
298 case Slot::PARAMETER:
299 return ParameterOperand(index);
300
301 case Slot::LOCAL: {
302 ASSERT(0 <= index && index < scope()->num_stack_slots());
303 const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
304 return MemOperand(fp, kLocalOffset - index * kPointerSize);
305 }
306
307 case Slot::CONTEXT: {
308 // Follow the context chain if necessary.
309 ASSERT(!tmp.is(cp)); // do not overwrite context register
310 Register context = cp;
311 int chain_length = scope()->ContextChainLength(slot->var()->scope());
312 for (int i = chain_length; i-- > 0;) {
313 // Load the closure.
314 // (All contexts, even 'with' contexts, have a closure,
315 // and it is the same for all contexts inside a function.
316 // There is no need to go to the function context first.)
317 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
318 // Load the function context (which is the incoming, outer context).
319 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
320 context = tmp;
321 }
322 // We may have a 'with' context now. Get the function context.
323 // (In fact this mov may never be the needed, since the scope analysis
324 // may not permit a direct context access in this case and thus we are
325 // always at a function context. However it is safe to dereference be-
326 // cause the function context of a function context is itself. Before
327 // deleting this mov we should try to create a counter-example first,
328 // though...)
329 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
330 return ContextOperand(tmp, index);
331 }
332
333 default:
334 UNREACHABLE();
335 return MemOperand(r0, 0);
336 }
337}
338
339
mads.s.ager31e71382008-08-13 09:32:07 +0000340// Loads a value on the stack. If it is a boolean value, the result may have
341// been (partially) translated into branches, or it may have set the condition
342// code register. If force_cc is set, the value is forced to set the condition
343// code register and no value is pushed. If the condition code register was set,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000345void CodeGenerator::LoadCondition(Expression* x,
346 TypeofState typeof_state,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 Label* true_target,
348 Label* false_target,
349 bool force_cc) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000350 ASSERT(!has_cc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351
ager@chromium.org7c537e22008-10-16 08:43:32 +0000352 { CodeGenState new_state(this, typeof_state, true_target, false_target);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000353 Visit(x);
354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 if (force_cc && !has_cc()) {
mads.s.ager31e71382008-08-13 09:32:07 +0000356 // Convert the TOS value to a boolean in the condition code register.
357 ToBoolean(true_target, false_target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 }
359 ASSERT(has_cc() || !force_cc);
360}
361
362
ager@chromium.org7c537e22008-10-16 08:43:32 +0000363void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 Label true_target;
365 Label false_target;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000366 LoadCondition(x, typeof_state, &true_target, &false_target, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
368 if (has_cc()) {
369 // convert cc_reg_ into a bool
370 Label loaded, materialize_true;
371 __ b(cc_reg_, &materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000372 __ mov(r0, Operand(Factory::false_value()));
373 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 __ b(&loaded);
375 __ bind(&materialize_true);
mads.s.ager31e71382008-08-13 09:32:07 +0000376 __ mov(r0, Operand(Factory::true_value()));
377 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 __ bind(&loaded);
379 cc_reg_ = al;
380 }
381
382 if (true_target.is_linked() || false_target.is_linked()) {
383 // we have at least one condition value
384 // that has been "translated" into a branch,
385 // thus it needs to be loaded explicitly again
386 Label loaded;
387 __ b(&loaded); // don't lose current TOS
388 bool both = true_target.is_linked() && false_target.is_linked();
389 // reincarnate "true", if necessary
390 if (true_target.is_linked()) {
391 __ bind(&true_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000392 __ mov(r0, Operand(Factory::true_value()));
393 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 }
395 // if both "true" and "false" need to be reincarnated,
396 // jump across code for "false"
397 if (both)
398 __ b(&loaded);
399 // reincarnate "false", if necessary
400 if (false_target.is_linked()) {
401 __ bind(&false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000402 __ mov(r0, Operand(Factory::false_value()));
403 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 }
405 // everything is loaded at this point
406 __ bind(&loaded);
407 }
408 ASSERT(!has_cc());
409}
410
411
ager@chromium.org7c537e22008-10-16 08:43:32 +0000412void CodeGenerator::LoadGlobal() {
mads.s.ager31e71382008-08-13 09:32:07 +0000413 __ ldr(r0, GlobalObject());
414 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415}
416
417
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000418void CodeGenerator::LoadGlobalReceiver(Register s) {
419 __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
420 __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
421 __ push(s);
422}
423
424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425// TODO(1241834): Get rid of this function in favor of just using Load, now
ager@chromium.org7c537e22008-10-16 08:43:32 +0000426// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
427// variables w/o reference errors elsewhere.
428void CodeGenerator::LoadTypeofExpression(Expression* x) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 Variable* variable = x->AsVariableProxy()->AsVariable();
430 if (variable != NULL && !variable->is_this() && variable->is_global()) {
431 // NOTE: This is somewhat nasty. We force the compiler to load
432 // the variable as if through '<global>.<variable>' to make sure we
433 // do not get reference errors.
434 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
435 Literal key(variable->name());
436 // TODO(1241834): Fetch the position from the variable instead of using
437 // no position.
ager@chromium.org236ad962008-09-25 09:45:57 +0000438 Property property(&global, &key, RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 Load(&property);
440 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000441 Load(x, INSIDE_TYPEOF);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 }
443}
444
445
ager@chromium.org7c537e22008-10-16 08:43:32 +0000446Reference::Reference(CodeGenerator* cgen, Expression* expression)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
448 cgen->LoadReference(this);
449}
450
451
452Reference::~Reference() {
453 cgen_->UnloadReference(this);
454}
455
456
ager@chromium.org7c537e22008-10-16 08:43:32 +0000457void CodeGenerator::LoadReference(Reference* ref) {
458 Comment cmnt(masm_, "[ LoadReference");
459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000460 Expression* e = ref->expression();
461 Property* property = e->AsProperty();
462 Variable* var = e->AsVariableProxy()->AsVariable();
463
464 if (property != NULL) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000465 // The expression is either a property or a variable proxy that rewrites
466 // to a property.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467 Load(property->obj());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000468 // We use a named reference if the key is a literal symbol, unless it is
469 // a string that can be legally parsed as an integer. This is because
470 // otherwise we will not get into the slow case code that handles [] on
471 // String objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472 Literal* literal = property->key()->AsLiteral();
473 uint32_t dummy;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000474 if (literal != NULL &&
475 literal->handle()->IsSymbol() &&
476 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 ref->set_type(Reference::NAMED);
478 } else {
479 Load(property->key());
480 ref->set_type(Reference::KEYED);
481 }
482 } else if (var != NULL) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000483 // The expression is a variable proxy that does not rewrite to a
484 // property. Global variables are treated as named property references.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 if (var->is_global()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 LoadGlobal();
487 ref->set_type(Reference::NAMED);
488 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000489 ASSERT(var->slot() != NULL);
490 ref->set_type(Reference::SLOT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491 }
492 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000493 // Anything else is a runtime error.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494 Load(e);
495 __ CallRuntime(Runtime::kThrowReferenceError, 1);
496 }
497}
498
499
ager@chromium.org7c537e22008-10-16 08:43:32 +0000500void CodeGenerator::UnloadReference(Reference* ref) {
501 Comment cmnt(masm_, "[ UnloadReference");
502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000503 int size = ref->size();
504 if (size <= 0) {
505 // Do nothing. No popping is necessary.
506 } else {
mads.s.ager31e71382008-08-13 09:32:07 +0000507 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 __ add(sp, sp, Operand(size * kPointerSize));
mads.s.ager31e71382008-08-13 09:32:07 +0000509 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 }
511}
512
513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
515// register to a boolean in the condition code register. The code
516// may jump to 'false_target' in case the register converts to 'false'.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000517void CodeGenerator::ToBoolean(Label* true_target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 Label* false_target) {
mads.s.ager31e71382008-08-13 09:32:07 +0000519 // Note: The generated code snippet does not change stack variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520 // Only the condition code should be set.
mads.s.ager31e71382008-08-13 09:32:07 +0000521 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
523 // Fast case checks
524
mads.s.ager31e71382008-08-13 09:32:07 +0000525 // Check if the value is 'false'.
526 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 __ b(eq, false_target);
528
mads.s.ager31e71382008-08-13 09:32:07 +0000529 // Check if the value is 'true'.
530 __ cmp(r0, Operand(Factory::true_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 __ b(eq, true_target);
532
mads.s.ager31e71382008-08-13 09:32:07 +0000533 // Check if the value is 'undefined'.
534 __ cmp(r0, Operand(Factory::undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 __ b(eq, false_target);
536
mads.s.ager31e71382008-08-13 09:32:07 +0000537 // Check if the value is a smi.
538 __ cmp(r0, Operand(Smi::FromInt(0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 __ b(eq, false_target);
mads.s.ager31e71382008-08-13 09:32:07 +0000540 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 __ b(eq, true_target);
542
543 // Slow case: call the runtime.
544 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +0000545 __ CallRuntime(Runtime::kToBool, 1);
546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 // Convert result (r0) to condition code
548 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549
550 cc_reg_ = ne;
551}
552
553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554class GetPropertyStub : public CodeStub {
555 public:
556 GetPropertyStub() { }
557
558 private:
559 Major MajorKey() { return GetProperty; }
560 int MinorKey() { return 0; }
561 void Generate(MacroAssembler* masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562};
563
564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565class SetPropertyStub : public CodeStub {
566 public:
567 SetPropertyStub() { }
568
569 private:
570 Major MajorKey() { return SetProperty; }
571 int MinorKey() { return 0; }
572 void Generate(MacroAssembler* masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573};
574
575
kasper.lund7276f142008-07-30 08:49:36 +0000576class GenericBinaryOpStub : public CodeStub {
577 public:
578 explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
579
580 private:
581 Token::Value op_;
582
583 Major MajorKey() { return GenericBinaryOp; }
584 int MinorKey() { return static_cast<int>(op_); }
585 void Generate(MacroAssembler* masm);
586
587 const char* GetName() {
588 switch (op_) {
589 case Token::ADD: return "GenericBinaryOpStub_ADD";
590 case Token::SUB: return "GenericBinaryOpStub_SUB";
591 case Token::MUL: return "GenericBinaryOpStub_MUL";
592 case Token::DIV: return "GenericBinaryOpStub_DIV";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000593 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
594 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
595 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
596 case Token::SAR: return "GenericBinaryOpStub_SAR";
597 case Token::SHL: return "GenericBinaryOpStub_SHL";
598 case Token::SHR: return "GenericBinaryOpStub_SHR";
kasper.lund7276f142008-07-30 08:49:36 +0000599 default: return "GenericBinaryOpStub";
600 }
601 }
602
603#ifdef DEBUG
604 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
605#endif
606};
607
608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609class InvokeBuiltinStub : public CodeStub {
610 public:
611 enum Kind { Inc, Dec, ToNumber };
612 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
613
614 private:
615 Kind kind_;
616 int argc_;
617
618 Major MajorKey() { return InvokeBuiltin; }
619 int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
620 void Generate(MacroAssembler* masm);
621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622#ifdef DEBUG
623 void Print() {
624 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
625 static_cast<int>(kind_),
626 argc_);
627 }
628#endif
629};
630
631
ager@chromium.org7c537e22008-10-16 08:43:32 +0000632void CodeGenerator::GenericBinaryOperation(Token::Value op) {
mads.s.ager31e71382008-08-13 09:32:07 +0000633 // sp[0] : y
634 // sp[1] : x
635 // result : r0
636
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 // Stub is entered with a call: 'return address' is in lr.
638 switch (op) {
639 case Token::ADD: // fall through.
640 case Token::SUB: // fall through.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000641 case Token::MUL:
642 case Token::BIT_OR:
643 case Token::BIT_AND:
644 case Token::BIT_XOR:
645 case Token::SHL:
646 case Token::SHR:
647 case Token::SAR: {
mads.s.ager31e71382008-08-13 09:32:07 +0000648 __ pop(r0); // r0 : y
649 __ pop(r1); // r1 : x
kasper.lund7276f142008-07-30 08:49:36 +0000650 GenericBinaryOpStub stub(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 __ CallStub(&stub);
652 break;
653 }
654
655 case Token::DIV: {
mads.s.ager31e71382008-08-13 09:32:07 +0000656 __ mov(r0, Operand(1));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000657 __ InvokeBuiltin(Builtins::DIV, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658 break;
659 }
660
661 case Token::MOD: {
mads.s.ager31e71382008-08-13 09:32:07 +0000662 __ mov(r0, Operand(1));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000663 __ InvokeBuiltin(Builtins::MOD, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 break;
665 }
666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 case Token::COMMA:
mads.s.ager31e71382008-08-13 09:32:07 +0000668 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669 // simply discard left value
mads.s.ager31e71382008-08-13 09:32:07 +0000670 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 break;
672
673 default:
674 // Other cases should have been handled before this point.
675 UNREACHABLE();
676 break;
677 }
678}
679
680
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000681class DeferredInlinedSmiOperation: public DeferredCode {
682 public:
683 DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
684 int value, bool reversed) :
685 DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
686 set_comment("[ DeferredInlinedSmiOperation");
687 }
688
689 virtual void Generate() {
690 switch (op_) {
691 case Token::ADD: {
692 if (reversed_) {
693 // revert optimistic add
694 __ sub(r0, r0, Operand(Smi::FromInt(value_)));
695 __ mov(r1, Operand(Smi::FromInt(value_))); // x
696 } else {
697 // revert optimistic add
698 __ sub(r1, r0, Operand(Smi::FromInt(value_)));
699 __ mov(r0, Operand(Smi::FromInt(value_)));
700 }
701 break;
702 }
703
704 case Token::SUB: {
705 if (reversed_) {
706 // revert optimistic sub
707 __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
708 __ mov(r1, Operand(Smi::FromInt(value_)));
709 } else {
710 __ add(r1, r0, Operand(Smi::FromInt(value_)));
711 __ mov(r0, Operand(Smi::FromInt(value_)));
712 }
713 break;
714 }
715
716 case Token::BIT_OR:
717 case Token::BIT_XOR:
718 case Token::BIT_AND: {
719 if (reversed_) {
720 __ mov(r1, Operand(Smi::FromInt(value_)));
721 } else {
722 __ mov(r1, Operand(r0));
723 __ mov(r0, Operand(Smi::FromInt(value_)));
724 }
725 break;
726 }
727
728 case Token::SHL:
729 case Token::SHR:
730 case Token::SAR: {
731 if (!reversed_) {
732 __ mov(r1, Operand(r0));
733 __ mov(r0, Operand(Smi::FromInt(value_)));
734 } else {
735 UNREACHABLE(); // should have been handled in SmiOperation
736 }
737 break;
738 }
739
740 default:
741 // other cases should have been handled before this point.
742 UNREACHABLE();
743 break;
744 }
745
746 GenericBinaryOpStub igostub(op_);
747 __ CallStub(&igostub);
748 }
749
750 private:
751 Token::Value op_;
752 int value_;
753 bool reversed_;
754};
755
756
ager@chromium.org7c537e22008-10-16 08:43:32 +0000757void CodeGenerator::SmiOperation(Token::Value op,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758 Handle<Object> value,
759 bool reversed) {
760 // NOTE: This is an attempt to inline (a bit) more of the code for
761 // some possible smi operations (like + and -) when (at least) one
762 // of the operands is a literal smi. With this optimization, the
763 // performance of the system is increased by ~15%, and the generated
764 // code size is increased by ~1% (measured on a combination of
765 // different benchmarks).
766
mads.s.ager31e71382008-08-13 09:32:07 +0000767 // sp[0] : operand
768
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000769 int int_value = Smi::cast(*value)->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770
771 Label exit;
mads.s.ager31e71382008-08-13 09:32:07 +0000772 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773
774 switch (op) {
775 case Token::ADD: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776 DeferredCode* deferred =
777 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000779 __ add(r0, r0, Operand(value), SetCC);
780 __ b(vs, deferred->enter());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 __ tst(r0, Operand(kSmiTagMask));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782 __ b(ne, deferred->enter());
783 __ bind(deferred->exit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 break;
785 }
786
787 case Token::SUB: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000788 DeferredCode* deferred =
789 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 if (!reversed) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000792 __ sub(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 __ rsb(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000796 __ b(vs, deferred->enter());
797 __ tst(r0, Operand(kSmiTagMask));
798 __ b(ne, deferred->enter());
799 __ bind(deferred->exit());
800 break;
801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000803 case Token::BIT_OR:
804 case Token::BIT_XOR:
805 case Token::BIT_AND: {
806 DeferredCode* deferred =
807 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
808 __ tst(r0, Operand(kSmiTagMask));
809 __ b(ne, deferred->enter());
810 switch (op) {
811 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
812 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
813 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
814 default: UNREACHABLE();
815 }
816 __ bind(deferred->exit());
817 break;
818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000820 case Token::SHL:
821 case Token::SHR:
822 case Token::SAR: {
823 if (reversed) {
824 __ mov(ip, Operand(value));
825 __ push(ip);
826 __ push(r0);
827 GenericBinaryOperation(op);
828
829 } else {
830 int shift_value = int_value & 0x1f; // least significant 5 bits
831 DeferredCode* deferred =
832 new DeferredInlinedSmiOperation(this, op, shift_value, false);
833 __ tst(r0, Operand(kSmiTagMask));
834 __ b(ne, deferred->enter());
835 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
836 switch (op) {
837 case Token::SHL: {
838 __ mov(r2, Operand(r2, LSL, shift_value));
839 // check that the *unsigned* result fits in a smi
840 __ add(r3, r2, Operand(0x40000000), SetCC);
841 __ b(mi, deferred->enter());
842 break;
843 }
844 case Token::SHR: {
845 // LSR by immediate 0 means shifting 32 bits.
846 if (shift_value != 0) {
847 __ mov(r2, Operand(r2, LSR, shift_value));
848 }
849 // check that the *unsigned* result fits in a smi
850 // neither of the two high-order bits can be set:
851 // - 0x80000000: high bit would be lost when smi tagging
852 // - 0x40000000: this number would convert to negative when
853 // smi tagging these two cases can only happen with shifts
854 // by 0 or 1 when handed a valid smi
855 __ and_(r3, r2, Operand(0xc0000000), SetCC);
856 __ b(ne, deferred->enter());
857 break;
858 }
859 case Token::SAR: {
860 if (shift_value != 0) {
861 // ASR by immediate 0 means shifting 32 bits.
862 __ mov(r2, Operand(r2, ASR, shift_value));
863 }
864 break;
865 }
866 default: UNREACHABLE();
867 }
868 __ mov(r0, Operand(r2, LSL, kSmiTagSize));
869 __ bind(deferred->exit());
870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 break;
872 }
873
874 default:
875 if (!reversed) {
mads.s.ager31e71382008-08-13 09:32:07 +0000876 __ push(r0);
877 __ mov(r0, Operand(value));
878 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 } else {
880 __ mov(ip, Operand(value));
881 __ push(ip);
mads.s.ager31e71382008-08-13 09:32:07 +0000882 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 }
kasper.lund7276f142008-07-30 08:49:36 +0000884 GenericBinaryOperation(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 break;
886 }
887
888 __ bind(&exit);
889}
890
891
ager@chromium.org7c537e22008-10-16 08:43:32 +0000892void CodeGenerator::Comparison(Condition cc, bool strict) {
mads.s.ager31e71382008-08-13 09:32:07 +0000893 // sp[0] : y
894 // sp[1] : x
895 // result : cc register
896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 // Strict only makes sense for equality comparisons.
898 ASSERT(!strict || cc == eq);
899
900 Label exit, smi;
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000901 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
902 if (cc == gt || cc == le) {
903 cc = ReverseCondition(cc);
mads.s.ager31e71382008-08-13 09:32:07 +0000904 __ pop(r1);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000905 __ pop(r0);
906 } else {
mads.s.ager31e71382008-08-13 09:32:07 +0000907 __ pop(r0);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000908 __ pop(r1);
909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 __ orr(r2, r0, Operand(r1));
911 __ tst(r2, Operand(kSmiTagMask));
912 __ b(eq, &smi);
913
914 // Perform non-smi comparison by runtime call.
915 __ push(r1);
916
917 // Figure out which native to call and setup the arguments.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000918 Builtins::JavaScript native;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 int argc;
920 if (cc == eq) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000921 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922 argc = 1;
923 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000924 native = Builtins::COMPARE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 int ncr; // NaN compare result
926 if (cc == lt || cc == le) {
927 ncr = GREATER;
928 } else {
929 ASSERT(cc == gt || cc == ge); // remaining cases
930 ncr = LESS;
931 }
mads.s.ager31e71382008-08-13 09:32:07 +0000932 __ push(r0);
933 __ mov(r0, Operand(Smi::FromInt(ncr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 argc = 2;
935 }
936
937 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
938 // tagged as a small integer.
mads.s.ager31e71382008-08-13 09:32:07 +0000939 __ push(r0);
940 __ mov(r0, Operand(argc));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000941 __ InvokeBuiltin(native, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 __ cmp(r0, Operand(0));
943 __ b(&exit);
944
945 // test smi equality by pointer comparison.
946 __ bind(&smi);
947 __ cmp(r1, Operand(r0));
948
949 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000950 cc_reg_ = cc;
951}
952
953
kasper.lund7276f142008-07-30 08:49:36 +0000954class CallFunctionStub: public CodeStub {
955 public:
956 explicit CallFunctionStub(int argc) : argc_(argc) {}
957
958 void Generate(MacroAssembler* masm);
959
960 private:
961 int argc_;
962
kasper.lund7276f142008-07-30 08:49:36 +0000963#if defined(DEBUG)
964 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
965#endif // defined(DEBUG)
966
967 Major MajorKey() { return CallFunction; }
968 int MinorKey() { return argc_; }
969};
970
971
mads.s.ager31e71382008-08-13 09:32:07 +0000972// Call the function on the stack with the given arguments.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000973void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975 // Push the arguments ("left-to-right") on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +0000976 for (int i = 0; i < args->length(); i++) {
977 Load(args->at(i));
978 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979
kasper.lund7276f142008-07-30 08:49:36 +0000980 // Record the position for debugging purposes.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 __ RecordPosition(position);
982
kasper.lund7276f142008-07-30 08:49:36 +0000983 // Use the shared code stub to call the function.
984 CallFunctionStub call_function(args->length());
985 __ CallStub(&call_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000986
987 // Restore context and pop function from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +0000989 __ pop(); // discard the TOS
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990}
991
992
ager@chromium.org7c537e22008-10-16 08:43:32 +0000993void CodeGenerator::Branch(bool if_true, Label* L) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 ASSERT(has_cc());
995 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
996 __ b(cc, L);
997 cc_reg_ = al;
998}
999
1000
ager@chromium.org7c537e22008-10-16 08:43:32 +00001001void CodeGenerator::CheckStack() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 if (FLAG_check_stack) {
1003 Comment cmnt(masm_, "[ check stack");
1004 StackCheckStub stub;
1005 __ CallStub(&stub);
1006 }
1007}
1008
1009
ager@chromium.org7c537e22008-10-16 08:43:32 +00001010void CodeGenerator::VisitBlock(Block* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 Comment cmnt(masm_, "[ Block");
1012 if (FLAG_debug_info) RecordStatementPosition(node);
1013 node->set_break_stack_height(break_stack_height_);
1014 VisitStatements(node->statements());
1015 __ bind(node->break_target());
1016}
1017
1018
ager@chromium.org7c537e22008-10-16 08:43:32 +00001019void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
mads.s.ager31e71382008-08-13 09:32:07 +00001020 __ mov(r0, Operand(pairs));
1021 __ push(r0);
1022 __ push(cp);
1023 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
1024 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 __ CallRuntime(Runtime::kDeclareGlobals, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00001026 // The result is discarded.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
ager@chromium.org7c537e22008-10-16 08:43:32 +00001030void CodeGenerator::VisitDeclaration(Declaration* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 Comment cmnt(masm_, "[ Declaration");
1032 Variable* var = node->proxy()->var();
1033 ASSERT(var != NULL); // must have been resolved
1034 Slot* slot = var->slot();
1035
1036 // If it was not possible to allocate the variable at compile time,
1037 // we need to "declare" it at runtime to make sure it actually
1038 // exists in the local context.
1039 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1040 // Variables with a "LOOKUP" slot were introduced as non-locals
1041 // during variable resolution and must have mode DYNAMIC.
1042 ASSERT(var->mode() == Variable::DYNAMIC);
1043 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00001044 __ push(cp);
1045 __ mov(r0, Operand(var->name()));
1046 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 // Declaration nodes are always declared in only two modes.
1048 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1049 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
mads.s.ager31e71382008-08-13 09:32:07 +00001050 __ mov(r0, Operand(Smi::FromInt(attr)));
1051 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 // Push initial value, if any.
1053 // Note: For variables we must not push an initial value (such as
1054 // 'undefined') because we may have a (legal) redeclaration and we
1055 // must not destroy the current value.
1056 if (node->mode() == Variable::CONST) {
mads.s.ager31e71382008-08-13 09:32:07 +00001057 __ mov(r0, Operand(Factory::the_hole_value()));
1058 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 } else if (node->fun() != NULL) {
1060 Load(node->fun());
1061 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001062 __ mov(r0, Operand(0)); // no initial value!
1063 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001065 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
1066 // Ignore the return value (declarations are statements).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 return;
1068 }
1069
1070 ASSERT(!var->is_global());
1071
1072 // If we have a function or a constant, we need to initialize the variable.
1073 Expression* val = NULL;
1074 if (node->mode() == Variable::CONST) {
1075 val = new Literal(Factory::the_hole_value());
1076 } else {
1077 val = node->fun(); // NULL if we don't have a function
1078 }
1079
1080 if (val != NULL) {
1081 // Set initial value.
1082 Reference target(this, node->proxy());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001083 ASSERT(target.is_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 Load(val);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001085 target.SetValue(NOT_CONST_INIT);
1086 // Get rid of the assigned value (declarations are statements). It's
1087 // safe to pop the value lying on top of the reference before unloading
1088 // the reference itself (which preserves the top of stack) because we
1089 // know it is a zero-sized reference.
mads.s.ager31e71382008-08-13 09:32:07 +00001090 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 }
1092}
1093
1094
ager@chromium.org7c537e22008-10-16 08:43:32 +00001095void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001096 Comment cmnt(masm_, "[ ExpressionStatement");
1097 if (FLAG_debug_info) RecordStatementPosition(node);
1098 Expression* expression = node->expression();
1099 expression->MarkAsStatement();
1100 Load(expression);
mads.s.ager31e71382008-08-13 09:32:07 +00001101 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102}
1103
1104
ager@chromium.org7c537e22008-10-16 08:43:32 +00001105void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 Comment cmnt(masm_, "// EmptyStatement");
1107 // nothing to do
1108}
1109
1110
ager@chromium.org7c537e22008-10-16 08:43:32 +00001111void CodeGenerator::VisitIfStatement(IfStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 Comment cmnt(masm_, "[ IfStatement");
1113 // Generate different code depending on which
1114 // parts of the if statement are present or not.
1115 bool has_then_stm = node->HasThenStatement();
1116 bool has_else_stm = node->HasElseStatement();
1117
1118 if (FLAG_debug_info) RecordStatementPosition(node);
1119
1120 Label exit;
1121 if (has_then_stm && has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001122 Comment cmnt(masm_, "[ IfThenElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 Label then;
1124 Label else_;
1125 // if (cond)
ager@chromium.org7c537e22008-10-16 08:43:32 +00001126 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 Branch(false, &else_);
1128 // then
1129 __ bind(&then);
1130 Visit(node->then_statement());
1131 __ b(&exit);
1132 // else
1133 __ bind(&else_);
1134 Visit(node->else_statement());
1135
1136 } else if (has_then_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001137 Comment cmnt(masm_, "[ IfThen");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 ASSERT(!has_else_stm);
1139 Label then;
1140 // if (cond)
ager@chromium.org7c537e22008-10-16 08:43:32 +00001141 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 Branch(false, &exit);
1143 // then
1144 __ bind(&then);
1145 Visit(node->then_statement());
1146
1147 } else if (has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001148 Comment cmnt(masm_, "[ IfElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 ASSERT(!has_then_stm);
1150 Label else_;
1151 // if (!cond)
ager@chromium.org7c537e22008-10-16 08:43:32 +00001152 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153 Branch(true, &exit);
1154 // else
1155 __ bind(&else_);
1156 Visit(node->else_statement());
1157
1158 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001159 Comment cmnt(masm_, "[ If");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160 ASSERT(!has_then_stm && !has_else_stm);
1161 // if (cond)
ager@chromium.org7c537e22008-10-16 08:43:32 +00001162 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 if (has_cc()) {
1164 cc_reg_ = al;
1165 } else {
1166 __ pop(r0); // __ Pop(no_reg)
1167 }
1168 }
1169
1170 // end
1171 __ bind(&exit);
1172}
1173
1174
ager@chromium.org7c537e22008-10-16 08:43:32 +00001175void CodeGenerator::CleanStack(int num_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 ASSERT(num_bytes >= 0);
1177 if (num_bytes > 0) {
mads.s.ager31e71382008-08-13 09:32:07 +00001178 __ add(sp, sp, Operand(num_bytes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 }
1180}
1181
1182
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 Comment cmnt(masm_, "[ ContinueStatement");
1185 if (FLAG_debug_info) RecordStatementPosition(node);
1186 CleanStack(break_stack_height_ - node->target()->break_stack_height());
1187 __ b(node->target()->continue_target());
1188}
1189
1190
ager@chromium.org7c537e22008-10-16 08:43:32 +00001191void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 Comment cmnt(masm_, "[ BreakStatement");
1193 if (FLAG_debug_info) RecordStatementPosition(node);
1194 CleanStack(break_stack_height_ - node->target()->break_stack_height());
1195 __ b(node->target()->break_target());
1196}
1197
1198
ager@chromium.org7c537e22008-10-16 08:43:32 +00001199void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 Comment cmnt(masm_, "[ ReturnStatement");
1201 if (FLAG_debug_info) RecordStatementPosition(node);
1202 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00001203 // Move the function result into r0.
1204 __ pop(r0);
1205
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 __ b(&function_return_);
1207}
1208
1209
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211 Comment cmnt(masm_, "[ WithEnterStatement");
1212 if (FLAG_debug_info) RecordStatementPosition(node);
1213 Load(node->expression());
kasper.lund7276f142008-07-30 08:49:36 +00001214 __ CallRuntime(Runtime::kPushContext, 1);
1215 if (kDebug) {
1216 Label verified_true;
1217 __ cmp(r0, Operand(cp));
1218 __ b(eq, &verified_true);
1219 __ stop("PushContext: r0 is expected to be the same as cp");
1220 __ bind(&verified_true);
1221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 // Update context local.
1223 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1224}
1225
1226
ager@chromium.org7c537e22008-10-16 08:43:32 +00001227void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 Comment cmnt(masm_, "[ WithExitStatement");
1229 // Pop context.
1230 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
1231 // Update context local.
1232 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1233}
1234
1235
ager@chromium.org7c537e22008-10-16 08:43:32 +00001236int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
1237 return kFastSwitchMaxOverheadFactor;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001238}
1239
ager@chromium.org7c537e22008-10-16 08:43:32 +00001240int CodeGenerator::FastCaseSwitchMinCaseCount() {
1241 return kFastSwitchMinCaseCount;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001242}
1243
1244
ager@chromium.org7c537e22008-10-16 08:43:32 +00001245void CodeGenerator::GenerateFastCaseSwitchJumpTable(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001246 SwitchStatement* node,
1247 int min_index,
1248 int range,
1249 Label* fail_label,
1250 Vector<Label*> case_targets,
1251 Vector<Label> case_labels) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001252
1253 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
1254
1255 __ pop(r0);
1256 if (min_index != 0) {
1257 // small positive numbers can be immediate operands.
1258 if (min_index < 0) {
1259 __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
1260 } else {
1261 __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
1262 }
1263 }
1264 __ tst(r0, Operand(0x80000000 | kSmiTagMask));
1265 __ b(ne, fail_label);
1266 __ cmp(r0, Operand(Smi::FromInt(range)));
1267 __ b(ge, fail_label);
1268 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize));
1269 // One extra instruction offsets the table, so the table's start address is
1270 // the pc-register at the above add.
1271 __ stop("Unreachable: Switch table alignment");
1272
1273 // table containing branch operations.
1274 for (int i = 0; i < range; i++) {
1275 __ b(case_targets[i]);
1276 }
1277
1278 GenerateFastCaseSwitchCases(node, case_labels);
1279}
1280
1281
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 Comment cmnt(masm_, "[ SwitchStatement");
1284 if (FLAG_debug_info) RecordStatementPosition(node);
1285 node->set_break_stack_height(break_stack_height_);
1286
1287 Load(node->tag());
1288
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001289 if (TryGenerateFastCaseSwitchStatement(node)) {
1290 return;
1291 }
1292
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 Label next, fall_through, default_case;
1294 ZoneList<CaseClause*>* cases = node->cases();
1295 int length = cases->length();
1296
1297 for (int i = 0; i < length; i++) {
1298 CaseClause* clause = cases->at(i);
1299
1300 Comment cmnt(masm_, "[ case clause");
1301
1302 if (clause->is_default()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001303 // Continue matching cases. The program will execute the default case's
1304 // statements if it does not match any of the cases.
1305 __ b(&next);
1306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // Bind the default case label, so we can branch to it when we
1308 // have compared against all other cases.
1309 ASSERT(default_case.is_unused()); // at most one default clause
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001310 __ bind(&default_case);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 } else {
1312 __ bind(&next);
1313 next.Unuse();
mads.s.ager31e71382008-08-13 09:32:07 +00001314 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 __ push(r0); // duplicate TOS
1316 Load(clause->label());
1317 Comparison(eq, true);
1318 Branch(false, &next);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 }
1320
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001321 // Entering the case statement for the first time. Remove the switch value
1322 // from the stack.
1323 __ pop(r0);
1324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // Generate code for the body.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001326 // This is also the target for the fall through from the previous case's
1327 // statements which has to skip over the matching code and the popping of
1328 // the switch value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 __ bind(&fall_through);
1330 fall_through.Unuse();
1331 VisitStatements(clause->statements());
1332 __ b(&fall_through);
1333 }
1334
1335 __ bind(&next);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001336 // Reached the end of the case statements without matching any of the cases.
1337 if (default_case.is_bound()) {
1338 // A default case exists -> execute its statements.
1339 __ b(&default_case);
1340 } else {
1341 // Remove the switch value from the stack.
1342 __ pop(r0);
1343 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 __ bind(&fall_through);
1346 __ bind(node->break_target());
1347}
1348
1349
ager@chromium.org7c537e22008-10-16 08:43:32 +00001350void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 Comment cmnt(masm_, "[ LoopStatement");
1352 if (FLAG_debug_info) RecordStatementPosition(node);
1353 node->set_break_stack_height(break_stack_height_);
1354
1355 // simple condition analysis
1356 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
1357 if (node->cond() == NULL) {
1358 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1359 info = ALWAYS_TRUE;
1360 } else {
1361 Literal* lit = node->cond()->AsLiteral();
1362 if (lit != NULL) {
1363 if (lit->IsTrue()) {
1364 info = ALWAYS_TRUE;
1365 } else if (lit->IsFalse()) {
1366 info = ALWAYS_FALSE;
1367 }
1368 }
1369 }
1370
1371 Label loop, entry;
1372
1373 // init
1374 if (node->init() != NULL) {
1375 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1376 Visit(node->init());
1377 }
1378 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
1379 __ b(&entry);
1380 }
1381
1382 // body
1383 __ bind(&loop);
1384 Visit(node->body());
1385
1386 // next
1387 __ bind(node->continue_target());
1388 if (node->next() != NULL) {
1389 // Record source position of the statement as this code which is after the
1390 // code for the body actually belongs to the loop statement and not the
1391 // body.
1392 if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
1393 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1394 Visit(node->next());
1395 }
1396
1397 // cond
1398 __ bind(&entry);
1399 switch (info) {
1400 case ALWAYS_TRUE:
1401 CheckStack(); // TODO(1222600): ignore if body contains calls.
1402 __ b(&loop);
1403 break;
1404 case ALWAYS_FALSE:
1405 break;
1406 case DONT_KNOW:
1407 CheckStack(); // TODO(1222600): ignore if body contains calls.
1408 LoadCondition(node->cond(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00001409 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 &loop,
1411 node->break_target(),
1412 true);
1413 Branch(true, &loop);
1414 break;
1415 }
1416
1417 // exit
1418 __ bind(node->break_target());
1419}
1420
1421
ager@chromium.org7c537e22008-10-16 08:43:32 +00001422void CodeGenerator::VisitForInStatement(ForInStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 Comment cmnt(masm_, "[ ForInStatement");
1424 if (FLAG_debug_info) RecordStatementPosition(node);
1425
1426 // We keep stuff on the stack while the body is executing.
1427 // Record it, so that a break/continue crossing this statement
1428 // can restore the stack.
1429 const int kForInStackSize = 5 * kPointerSize;
1430 break_stack_height_ += kForInStackSize;
1431 node->set_break_stack_height(break_stack_height_);
1432
1433 Label loop, next, entry, cleanup, exit, primitive, jsobject;
1434 Label filter_key, end_del_check, fixed_array, non_string;
1435
1436 // Get the object to enumerate over (converted to JSObject).
1437 Load(node->enumerable());
mads.s.ager31e71382008-08-13 09:32:07 +00001438 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
1440 // Both SpiderMonkey and kjs ignore null and undefined in contrast
1441 // to the specification. 12.6.4 mandates a call to ToObject.
1442 __ cmp(r0, Operand(Factory::undefined_value()));
1443 __ b(eq, &exit);
1444 __ cmp(r0, Operand(Factory::null_value()));
1445 __ b(eq, &exit);
1446
1447 // Stack layout in body:
1448 // [iteration counter (Smi)]
1449 // [length of array]
1450 // [FixedArray]
1451 // [Map or 0]
1452 // [Object]
1453
1454 // Check if enumerable is already a JSObject
1455 __ tst(r0, Operand(kSmiTagMask));
1456 __ b(eq, &primitive);
1457 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
1458 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00001459 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460 __ b(hs, &jsobject);
1461
1462 __ bind(&primitive);
mads.s.ager31e71382008-08-13 09:32:07 +00001463 __ push(r0);
1464 __ mov(r0, Operand(0));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001465 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466
1467
1468 __ bind(&jsobject);
1469
1470 // Get the set of properties (as a FixedArray or Map).
1471 __ push(r0); // duplicate the object being enumerated
mads.s.ager31e71382008-08-13 09:32:07 +00001472 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1474
1475 // If we got a Map, we can do a fast modification check.
1476 // Otherwise, we got a FixedArray, and we have to do a slow check.
1477 __ mov(r2, Operand(r0));
1478 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
1479 __ cmp(r1, Operand(Factory::meta_map()));
1480 __ b(ne, &fixed_array);
1481
1482 // Get enum cache
1483 __ mov(r1, Operand(r0));
1484 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
1485 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
1486 __ ldr(r2,
1487 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
1488
mads.s.ager31e71382008-08-13 09:32:07 +00001489 __ push(r0); // map
1490 __ push(r2); // enum cache bridge cache
1491 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00001493 __ push(r0);
1494 __ mov(r0, Operand(Smi::FromInt(0)));
1495 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 __ b(&entry);
1497
1498
1499 __ bind(&fixed_array);
1500
1501 __ mov(r1, Operand(Smi::FromInt(0)));
1502 __ push(r1); // insert 0 in place of Map
mads.s.ager31e71382008-08-13 09:32:07 +00001503 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504
1505 // Push the length of the array and the initial index onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00001506 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
mads.s.ager31e71382008-08-13 09:32:07 +00001508 __ push(r0);
1509 __ mov(r0, Operand(Smi::FromInt(0))); // init index
1510 __ push(r0);
1511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512 __ b(&entry);
1513
1514 // Body.
1515 __ bind(&loop);
1516 Visit(node->body());
1517
1518 // Next.
1519 __ bind(node->continue_target());
1520 __ bind(&next);
mads.s.ager31e71382008-08-13 09:32:07 +00001521 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 __ add(r0, r0, Operand(Smi::FromInt(1)));
mads.s.ager31e71382008-08-13 09:32:07 +00001523 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 // Condition.
1526 __ bind(&entry);
1527
mads.s.ager31e71382008-08-13 09:32:07 +00001528 // sp[0] : index
1529 // sp[1] : array/enum cache length
1530 // sp[2] : array or enum cache
1531 // sp[3] : 0 or map
1532 // sp[4] : enumerable
1533 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count
1534 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length
1535 __ cmp(r0, Operand(r1)); // compare to the array length
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 __ b(hs, &cleanup);
1537
mads.s.ager31e71382008-08-13 09:32:07 +00001538 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
1539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 // Get the i'th entry of the array.
mads.s.ager31e71382008-08-13 09:32:07 +00001541 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1543 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1544
1545 // Get Map or 0.
mads.s.ager31e71382008-08-13 09:32:07 +00001546 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 // Check if this (still) matches the map of the enumerable.
1548 // If not, we have to filter the key.
mads.s.ager31e71382008-08-13 09:32:07 +00001549 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
1551 __ cmp(r1, Operand(r2));
1552 __ b(eq, &end_del_check);
1553
1554 // Convert the entry to a string (or null if it isn't a property anymore).
mads.s.ager31e71382008-08-13 09:32:07 +00001555 __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable
1556 __ push(r0);
1557 __ push(r3); // push entry
1558 __ mov(r0, Operand(1));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001559 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 __ mov(r3, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
1562 // If the property has been removed while iterating, we just skip it.
1563 __ cmp(r3, Operand(Factory::null_value()));
1564 __ b(eq, &next);
1565
1566
1567 __ bind(&end_del_check);
1568
1569 // Store the entry in the 'each' expression and take another spin in the loop.
mads.s.ager31e71382008-08-13 09:32:07 +00001570 // r3: i'th entry of the enum cache (or string there of)
1571 __ push(r3); // push entry
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 { Reference each(this, node->each());
1573 if (!each.is_illegal()) {
mads.s.ager31e71382008-08-13 09:32:07 +00001574 if (each.size() > 0) {
1575 __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
1576 __ push(r0);
1577 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001578 // If the reference was to a slot we rely on the convenient property
1579 // that it doesn't matter whether a value (eg, r3 pushed above) is
1580 // right on top of or right underneath a zero-sized reference.
1581 each.SetValue(NOT_CONST_INIT);
mads.s.ager31e71382008-08-13 09:32:07 +00001582 if (each.size() > 0) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001583 // It's safe to pop the value lying on top of the reference before
1584 // unloading the reference itself (which preserves the top of stack,
1585 // ie, now the topmost value of the non-zero sized reference), since
1586 // we will discard the top of stack after unloading the reference
1587 // anyway.
1588 __ pop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001592 // Discard the i'th entry pushed above or else the remainder of the
1593 // reference, whichever is currently on top of the stack.
1594 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 CheckStack(); // TODO(1222600): ignore if body contains calls.
1596 __ jmp(&loop);
1597
1598 // Cleanup.
1599 __ bind(&cleanup);
1600 __ bind(node->break_target());
mads.s.ager31e71382008-08-13 09:32:07 +00001601 __ add(sp, sp, Operand(5 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
1603 // Exit.
1604 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
1606 break_stack_height_ -= kForInStackSize;
1607}
1608
1609
ager@chromium.org7c537e22008-10-16 08:43:32 +00001610void CodeGenerator::VisitTryCatch(TryCatch* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 Comment cmnt(masm_, "[ TryCatch");
1612
1613 Label try_block, exit;
1614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 __ bl(&try_block);
1616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 // --- Catch block ---
1618
1619 // Store the caught exception in the catch variable.
mads.s.ager31e71382008-08-13 09:32:07 +00001620 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 { Reference ref(this, node->catch_var());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001622 ASSERT(ref.is_slot());
1623 // Here we make use of the convenient property that it doesn't matter
1624 // whether a value is immediately on top of or underneath a zero-sized
1625 // reference.
1626 ref.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 }
1628
1629 // Remove the exception from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00001630 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631
1632 VisitStatements(node->catch_block()->statements());
1633 __ b(&exit);
1634
1635
1636 // --- Try block ---
1637 __ bind(&try_block);
1638
1639 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
1640
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001641 // Shadow the labels for all escapes from the try block, including
1642 // returns. During shadowing, the original label is hidden as the
1643 // LabelShadow and operations on the original actually affect the
1644 // shadowing label.
1645 //
1646 // We should probably try to unify the escaping labels and the return
1647 // label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648 int nof_escapes = node->escaping_labels()->length();
1649 List<LabelShadow*> shadows(1 + nof_escapes);
1650 shadows.Add(new LabelShadow(&function_return_));
1651 for (int i = 0; i < nof_escapes; i++) {
1652 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
1653 }
1654
1655 // Generate code for the statements in the try block.
1656 VisitStatements(node->try_block()->statements());
mads.s.ager31e71382008-08-13 09:32:07 +00001657 __ pop(r0); // Discard the result.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658
1659 // Stop the introduced shadowing and count the number of required unlinks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001660 // After shadowing stops, the original labels are unshadowed and the
1661 // LabelShadows represent the formerly shadowing labels.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662 int nof_unlinks = 0;
1663 for (int i = 0; i <= nof_escapes; i++) {
1664 shadows[i]->StopShadowing();
1665 if (shadows[i]->is_linked()) nof_unlinks++;
1666 }
1667
1668 // Unlink from try chain.
1669 // TOS contains code slot
1670 const int kNextOffset = StackHandlerConstants::kNextOffset +
1671 StackHandlerConstants::kAddressDisplacement;
1672 __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp
1673 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1674 __ str(r1, MemOperand(r3));
1675 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1676 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
1677 // Code slot popped.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001678 if (nof_unlinks > 0) __ b(&exit);
1679
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001680 // Generate unlink code for the (formerly) shadowing labels that have been
1681 // jumped to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 for (int i = 0; i <= nof_escapes; i++) {
1683 if (shadows[i]->is_linked()) {
mads.s.ager31e71382008-08-13 09:32:07 +00001684 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 __ bind(shadows[i]);
1686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 // Reload sp from the top handler, because some statements that we
1688 // break from (eg, for...in) may have left stuff on the stack.
1689 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1690 __ ldr(sp, MemOperand(r3));
1691
1692 __ ldr(r1, MemOperand(sp, kNextOffset));
1693 __ str(r1, MemOperand(r3));
1694 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1695 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
1696 // Code slot popped.
1697
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001698 __ b(shadows[i]->original_label());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 }
1700 }
1701
1702 __ bind(&exit);
1703}
1704
1705
ager@chromium.org7c537e22008-10-16 08:43:32 +00001706void CodeGenerator::VisitTryFinally(TryFinally* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 Comment cmnt(masm_, "[ TryFinally");
1708
1709 // State: Used to keep track of reason for entering the finally
1710 // block. Should probably be extended to hold information for
1711 // break/continue from within the try block.
1712 enum { FALLING, THROWING, JUMPING };
1713
1714 Label exit, unlink, try_block, finally_block;
1715
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 __ bl(&try_block);
1717
mads.s.ager31e71382008-08-13 09:32:07 +00001718 __ push(r0); // save exception object on the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 // In case of thrown exceptions, this is where we continue.
1720 __ mov(r2, Operand(Smi::FromInt(THROWING)));
1721 __ b(&finally_block);
1722
1723
1724 // --- Try block ---
1725 __ bind(&try_block);
1726
1727 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
1728
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001729 // Shadow the labels for all escapes from the try block, including
1730 // returns. Shadowing hides the original label as the LabelShadow and
1731 // operations on the original actually affect the shadowing label.
1732 //
1733 // We should probably try to unify the escaping labels and the return
1734 // label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 int nof_escapes = node->escaping_labels()->length();
1736 List<LabelShadow*> shadows(1 + nof_escapes);
1737 shadows.Add(new LabelShadow(&function_return_));
1738 for (int i = 0; i < nof_escapes; i++) {
1739 shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
1740 }
1741
1742 // Generate code for the statements in the try block.
1743 VisitStatements(node->try_block()->statements());
1744
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001745 // Stop the introduced shadowing and count the number of required unlinks.
1746 // After shadowing stops, the original labels are unshadowed and the
1747 // LabelShadows represent the formerly shadowing labels.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 int nof_unlinks = 0;
1749 for (int i = 0; i <= nof_escapes; i++) {
1750 shadows[i]->StopShadowing();
1751 if (shadows[i]->is_linked()) nof_unlinks++;
1752 }
1753
1754 // Set the state on the stack to FALLING.
mads.s.ager31e71382008-08-13 09:32:07 +00001755 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS
1756 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001757 __ mov(r2, Operand(Smi::FromInt(FALLING)));
1758 if (nof_unlinks > 0) __ b(&unlink);
1759
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001760 // Generate code to set the state for the (formerly) shadowing labels that
1761 // have been jumped to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 for (int i = 0; i <= nof_escapes; i++) {
1763 if (shadows[i]->is_linked()) {
1764 __ bind(shadows[i]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001765 if (shadows[i]->original_label() == &function_return_) {
1766 // If this label shadowed the function return, materialize the
1767 // return value on the stack.
1768 __ push(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001769 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001770 // Fake TOS for labels that shadowed breaks and continues.
mads.s.ager31e71382008-08-13 09:32:07 +00001771 __ mov(r0, Operand(Factory::undefined_value()));
1772 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773 }
1774 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
1775 __ b(&unlink);
1776 }
1777 }
1778
mads.s.ager31e71382008-08-13 09:32:07 +00001779 // Unlink from try chain;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001780 __ bind(&unlink);
1781
mads.s.ager31e71382008-08-13 09:32:07 +00001782 __ pop(r0); // Store TOS in r0 across stack manipulation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001783 // Reload sp from the top handler, because some statements that we
1784 // break from (eg, for...in) may have left stuff on the stack.
1785 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1786 __ ldr(sp, MemOperand(r3));
1787 const int kNextOffset = StackHandlerConstants::kNextOffset +
1788 StackHandlerConstants::kAddressDisplacement;
1789 __ ldr(r1, MemOperand(sp, kNextOffset));
1790 __ str(r1, MemOperand(r3));
1791 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1792 __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
1793 // Code slot popped.
mads.s.ager31e71382008-08-13 09:32:07 +00001794 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795
1796 // --- Finally block ---
1797 __ bind(&finally_block);
1798
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001799 // Push the state on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00001800 __ push(r2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001801
1802 // We keep two elements on the stack - the (possibly faked) result
1803 // and the state - while evaluating the finally block. Record it, so
1804 // that a break/continue crossing this statement can restore the
1805 // stack.
1806 const int kFinallyStackSize = 2 * kPointerSize;
1807 break_stack_height_ += kFinallyStackSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808
1809 // Generate code for the statements in the finally block.
1810 VisitStatements(node->finally_block()->statements());
1811
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001812 // Restore state and return value or faked TOS.
mads.s.ager31e71382008-08-13 09:32:07 +00001813 __ pop(r2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001814 __ pop(r0);
1815 break_stack_height_ -= kFinallyStackSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001817 // Generate code to jump to the right destination for all used (formerly)
1818 // shadowing labels.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 for (int i = 0; i <= nof_escapes; i++) {
1820 if (shadows[i]->is_bound()) {
1821 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001822 if (shadows[i]->original_label() != &function_return_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 Label next;
1824 __ b(ne, &next);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001825 __ b(shadows[i]->original_label());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 __ bind(&next);
1827 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001828 __ b(eq, shadows[i]->original_label());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 }
1830 }
1831 }
1832
1833 // Check if we need to rethrow the exception.
1834 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
1835 __ b(ne, &exit);
1836
1837 // Rethrow exception.
mads.s.ager31e71382008-08-13 09:32:07 +00001838 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 __ CallRuntime(Runtime::kReThrow, 1);
1840
1841 // Done.
1842 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843}
1844
1845
ager@chromium.org7c537e22008-10-16 08:43:32 +00001846void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001847 Comment cmnt(masm_, "[ DebuggerStatament");
1848 if (FLAG_debug_info) RecordStatementPosition(node);
1849 __ CallRuntime(Runtime::kDebugBreak, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00001850 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851}
1852
1853
ager@chromium.org7c537e22008-10-16 08:43:32 +00001854void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855 ASSERT(boilerplate->IsBoilerplate());
1856
1857 // Push the boilerplate on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00001858 __ mov(r0, Operand(boilerplate));
1859 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860
1861 // Create a new closure.
mads.s.ager31e71382008-08-13 09:32:07 +00001862 __ push(cp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863 __ CallRuntime(Runtime::kNewClosure, 2);
mads.s.ager31e71382008-08-13 09:32:07 +00001864 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865}
1866
1867
ager@chromium.org7c537e22008-10-16 08:43:32 +00001868void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 Comment cmnt(masm_, "[ FunctionLiteral");
1870
1871 // Build the function boilerplate and instantiate it.
1872 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
kasper.lund212ac232008-07-16 07:07:30 +00001873 // Check for stack-overflow exception.
1874 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875 InstantiateBoilerplate(boilerplate);
1876}
1877
1878
ager@chromium.org7c537e22008-10-16 08:43:32 +00001879void CodeGenerator::VisitFunctionBoilerplateLiteral(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001880 FunctionBoilerplateLiteral* node) {
1881 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
1882 InstantiateBoilerplate(node->boilerplate());
1883}
1884
1885
ager@chromium.org7c537e22008-10-16 08:43:32 +00001886void CodeGenerator::VisitConditional(Conditional* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001887 Comment cmnt(masm_, "[ Conditional");
1888 Label then, else_, exit;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001889 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 Branch(false, &else_);
1891 __ bind(&then);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001892 Load(node->then_expression(), typeof_state());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 __ b(&exit);
1894 __ bind(&else_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001895 Load(node->else_expression(), typeof_state());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 __ bind(&exit);
1897}
1898
1899
ager@chromium.org7c537e22008-10-16 08:43:32 +00001900void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
1901 if (slot->type() == Slot::LOOKUP) {
1902 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903
1904 // For now, just do a runtime call.
mads.s.ager31e71382008-08-13 09:32:07 +00001905 __ push(cp);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001906 __ mov(r0, Operand(slot->var()->name()));
mads.s.ager31e71382008-08-13 09:32:07 +00001907 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908
ager@chromium.org7c537e22008-10-16 08:43:32 +00001909 if (typeof_state == INSIDE_TYPEOF) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001910 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001911 } else {
1912 __ CallRuntime(Runtime::kLoadContextSlot, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001914 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915
1916 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001917 // Note: We would like to keep the assert below, but it fires because of
1918 // some nasty code in LoadTypeofExpression() which should be removed...
ager@chromium.org7c537e22008-10-16 08:43:32 +00001919 // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001921 // Special handling for locals allocated in registers.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001922 __ ldr(r0, SlotOperand(slot, r2));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001923 __ push(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001924 if (slot->var()->mode() == Variable::CONST) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001925 // Const slots may contain 'the hole' value (the constant hasn't been
1926 // initialized yet) which needs to be converted into the 'undefined'
1927 // value.
1928 Comment cmnt(masm_, "[ Unhole const");
1929 __ pop(r0);
1930 __ cmp(r0, Operand(Factory::the_hole_value()));
1931 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
1932 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 }
1934 }
1935}
1936
1937
ager@chromium.org7c537e22008-10-16 08:43:32 +00001938void CodeGenerator::VisitSlot(Slot* node) {
1939 Comment cmnt(masm_, "[ Slot");
1940 LoadFromSlot(node, typeof_state());
1941}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942
ager@chromium.org7c537e22008-10-16 08:43:32 +00001943
1944void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
1945 Comment cmnt(masm_, "[ VariableProxy");
1946
1947 Variable* var = node->var();
1948 Expression* expr = var->rewrite();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001949 if (expr != NULL) {
1950 Visit(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001952 ASSERT(var->is_global());
1953 Reference ref(this, node);
1954 ref.GetValue(typeof_state());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001955 }
1956}
1957
1958
ager@chromium.org7c537e22008-10-16 08:43:32 +00001959void CodeGenerator::VisitLiteral(Literal* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 Comment cmnt(masm_, "[ Literal");
mads.s.ager31e71382008-08-13 09:32:07 +00001961 __ mov(r0, Operand(node->handle()));
1962 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963}
1964
1965
ager@chromium.org7c537e22008-10-16 08:43:32 +00001966void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 Comment cmnt(masm_, "[ RexExp Literal");
1968
1969 // Retrieve the literal array and check the allocated entry.
1970
1971 // Load the function of this activation.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001972 __ ldr(r1, FunctionOperand());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973
1974 // Load the literals array of the function.
1975 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
1976
1977 // Load the literal at the ast saved index.
1978 int literal_offset =
1979 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
1980 __ ldr(r2, FieldMemOperand(r1, literal_offset));
1981
1982 Label done;
1983 __ cmp(r2, Operand(Factory::undefined_value()));
1984 __ b(ne, &done);
1985
1986 // If the entry is undefined we call the runtime system to computed
1987 // the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00001988 __ push(r1); // literal array (0)
1989 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
1990 __ push(r0); // literal index (1)
1991 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
1992 __ push(r0);
1993 __ mov(r0, Operand(node->flags())); // RegExp flags (3)
1994 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00001996 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997
mads.s.ager31e71382008-08-13 09:32:07 +00001998 __ bind(&done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 // Push the literal.
mads.s.ager31e71382008-08-13 09:32:07 +00002000 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001}
2002
2003
2004// This deferred code stub will be used for creating the boilerplate
2005// by calling Runtime_CreateObjectLiteral.
2006// Each created boilerplate is stored in the JSFunction and they are
2007// therefore context dependent.
2008class ObjectLiteralDeferred: public DeferredCode {
2009 public:
2010 ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node)
2011 : DeferredCode(generator), node_(node) {
2012 set_comment("[ ObjectLiteralDeferred");
2013 }
2014 virtual void Generate();
2015 private:
2016 ObjectLiteral* node_;
2017};
2018
2019
2020void ObjectLiteralDeferred::Generate() {
2021 // If the entry is undefined we call the runtime system to computed
2022 // the literal.
2023
2024 // Literal array (0).
mads.s.ager31e71382008-08-13 09:32:07 +00002025 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026 // Literal index (1).
mads.s.ager31e71382008-08-13 09:32:07 +00002027 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
2028 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 // Constant properties (2).
mads.s.ager31e71382008-08-13 09:32:07 +00002030 __ mov(r0, Operand(node_->constant_properties()));
2031 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002032 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00002033 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034}
2035
2036
ager@chromium.org7c537e22008-10-16 08:43:32 +00002037void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002038 Comment cmnt(masm_, "[ ObjectLiteral");
2039
2040 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
2041
2042 // Retrieve the literal array and check the allocated entry.
2043
2044 // Load the function of this activation.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002045 __ ldr(r1, FunctionOperand());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046
2047 // Load the literals array of the function.
2048 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
2049
2050 // Load the literal at the ast saved index.
2051 int literal_offset =
2052 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2053 __ ldr(r2, FieldMemOperand(r1, literal_offset));
2054
2055 // Check whether we need to materialize the object literal boilerplate.
2056 // If so, jump to the deferred code.
2057 __ cmp(r2, Operand(Factory::undefined_value()));
2058 __ b(eq, deferred->enter());
2059 __ bind(deferred->exit());
2060
2061 // Push the object literal boilerplate.
mads.s.ager31e71382008-08-13 09:32:07 +00002062 __ push(r2);
2063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 // Clone the boilerplate object.
2065 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00002066 __ push(r0); // save the result
2067 // r0: cloned object literal
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068
2069 for (int i = 0; i < node->properties()->length(); i++) {
2070 ObjectLiteral::Property* property = node->properties()->at(i);
2071 Literal* key = property->key();
2072 Expression* value = property->value();
2073 switch (property->kind()) {
2074 case ObjectLiteral::Property::CONSTANT: break;
2075 case ObjectLiteral::Property::COMPUTED: // fall through
2076 case ObjectLiteral::Property::PROTOTYPE: {
mads.s.ager31e71382008-08-13 09:32:07 +00002077 __ push(r0); // dup the result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 Load(key);
2079 Load(value);
2080 __ CallRuntime(Runtime::kSetProperty, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00002081 // restore r0
2082 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083 break;
2084 }
2085 case ObjectLiteral::Property::SETTER: {
2086 __ push(r0);
2087 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00002088 __ mov(r0, Operand(Smi::FromInt(1)));
2089 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002090 Load(value);
2091 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00002092 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002093 break;
2094 }
2095 case ObjectLiteral::Property::GETTER: {
2096 __ push(r0);
2097 Load(key);
mads.s.ager31e71382008-08-13 09:32:07 +00002098 __ mov(r0, Operand(Smi::FromInt(0)));
2099 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002100 Load(value);
2101 __ CallRuntime(Runtime::kDefineAccessor, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00002102 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002103 break;
2104 }
2105 }
2106 }
2107}
2108
2109
ager@chromium.org7c537e22008-10-16 08:43:32 +00002110void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111 Comment cmnt(masm_, "[ ArrayLiteral");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002112
2113 // Call runtime to create the array literal.
2114 __ mov(r0, Operand(node->literals()));
2115 __ push(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002116 // Load the function of this frame.
2117 __ ldr(r0, FunctionOperand());
2118 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002119 __ push(r0);
2120 __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
2121
2122 // Push the resulting array literal on the stack.
2123 __ push(r0);
2124
2125 // Generate code to set the elements in the array that are not
2126 // literals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127 for (int i = 0; i < node->values()->length(); i++) {
2128 Expression* value = node->values()->at(i);
2129
2130 // If value is literal the property value is already
2131 // set in the boilerplate object.
2132 if (value->AsLiteral() == NULL) {
2133 // The property must be set by generated code.
2134 Load(value);
mads.s.ager31e71382008-08-13 09:32:07 +00002135 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002136
2137 // Fetch the object literal
2138 __ ldr(r1, MemOperand(sp, 0));
2139 // Get the elements array.
2140 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
2141
2142 // Write to the indexed properties array.
2143 int offset = i * kPointerSize + Array::kHeaderSize;
2144 __ str(r0, FieldMemOperand(r1, offset));
2145
2146 // Update the write barrier for the array address.
2147 __ mov(r3, Operand(offset));
2148 __ RecordWrite(r1, r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149 }
2150 }
2151}
2152
2153
ager@chromium.org7c537e22008-10-16 08:43:32 +00002154void CodeGenerator::VisitAssignment(Assignment* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 Comment cmnt(masm_, "[ Assignment");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 if (FLAG_debug_info) RecordStatementPosition(node);
mads.s.ager31e71382008-08-13 09:32:07 +00002157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 Reference target(this, node->target());
2159 if (target.is_illegal()) return;
2160
2161 if (node->op() == Token::ASSIGN ||
2162 node->op() == Token::INIT_VAR ||
2163 node->op() == Token::INIT_CONST) {
2164 Load(node->value());
2165
2166 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002167 target.GetValue(NOT_INSIDE_TYPEOF);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 Literal* literal = node->value()->AsLiteral();
2169 if (literal != NULL && literal->handle()->IsSmi()) {
2170 SmiOperation(node->binary_op(), literal->handle(), false);
mads.s.ager31e71382008-08-13 09:32:07 +00002171 __ push(r0);
2172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 } else {
2174 Load(node->value());
kasper.lund7276f142008-07-30 08:49:36 +00002175 GenericBinaryOperation(node->binary_op());
mads.s.ager31e71382008-08-13 09:32:07 +00002176 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 }
2178 }
2179
2180 Variable* var = node->target()->AsVariableProxy()->AsVariable();
2181 if (var != NULL &&
2182 (var->mode() == Variable::CONST) &&
2183 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2184 // Assignment ignored - leave the value on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 } else {
2187 __ RecordPosition(node->position());
2188 if (node->op() == Token::INIT_CONST) {
2189 // Dynamic constant initializations must use the function context
2190 // and initialize the actual constant declared. Dynamic variable
2191 // initializations are simply assignments and use SetValue.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002192 target.SetValue(CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002193 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002194 target.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 }
2196 }
2197}
2198
2199
ager@chromium.org7c537e22008-10-16 08:43:32 +00002200void CodeGenerator::VisitThrow(Throw* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201 Comment cmnt(masm_, "[ Throw");
2202
2203 Load(node->exception());
2204 __ RecordPosition(node->position());
2205 __ CallRuntime(Runtime::kThrow, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00002206 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207}
2208
2209
ager@chromium.org7c537e22008-10-16 08:43:32 +00002210void CodeGenerator::VisitProperty(Property* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 Comment cmnt(masm_, "[ Property");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002212
ager@chromium.org7c537e22008-10-16 08:43:32 +00002213 Reference property(this, node);
2214 property.GetValue(typeof_state());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002215}
2216
2217
ager@chromium.org7c537e22008-10-16 08:43:32 +00002218void CodeGenerator::VisitCall(Call* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 Comment cmnt(masm_, "[ Call");
2220
2221 ZoneList<Expression*>* args = node->arguments();
2222
2223 if (FLAG_debug_info) RecordStatementPosition(node);
2224 // Standard function call.
2225
2226 // Check if the function is a variable or a property.
2227 Expression* function = node->expression();
2228 Variable* var = function->AsVariableProxy()->AsVariable();
2229 Property* property = function->AsProperty();
2230
2231 // ------------------------------------------------------------------------
2232 // Fast-case: Use inline caching.
2233 // ---
2234 // According to ECMA-262, section 11.2.3, page 44, the function to call
2235 // must be resolved after the arguments have been evaluated. The IC code
2236 // automatically handles this by loading the arguments before the function
2237 // is resolved in cache misses (this also holds for megamorphic calls).
2238 // ------------------------------------------------------------------------
2239
2240 if (var != NULL && !var->is_this() && var->is_global()) {
2241 // ----------------------------------
2242 // JavaScript example: 'foo(1, 2, 3)' // foo is global
2243 // ----------------------------------
2244
2245 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002246 __ mov(r0, Operand(var->name()));
2247 __ push(r0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002248
2249 // TODO(120): use JSGlobalObject for function lookup and inline cache,
2250 // and use global proxy as 'this' for invocation.
2251 LoadGlobalReceiver(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252
2253 // Load the arguments.
2254 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255
2256 // Setup the receiver register and call the IC initialization code.
2257 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258 __ RecordPosition(node->position());
ager@chromium.org236ad962008-09-25 09:45:57 +00002259 __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002260 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002261 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002262 __ pop();
2263 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264
2265 } else if (var != NULL && var->slot() != NULL &&
2266 var->slot()->type() == Slot::LOOKUP) {
2267 // ----------------------------------
2268 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
2269 // ----------------------------------
2270
2271 // Load the function
mads.s.ager31e71382008-08-13 09:32:07 +00002272 __ push(cp);
2273 __ mov(r0, Operand(var->name()));
2274 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002275 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2276 // r0: slot value; r1: receiver
2277
2278 // Load the receiver.
mads.s.ager31e71382008-08-13 09:32:07 +00002279 __ push(r0); // function
2280 __ push(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281
2282 // Call the function.
2283 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00002284 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002285
2286 } else if (property != NULL) {
2287 // Check if the key is a literal string.
2288 Literal* literal = property->key()->AsLiteral();
2289
2290 if (literal != NULL && literal->handle()->IsSymbol()) {
2291 // ------------------------------------------------------------------
2292 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
2293 // ------------------------------------------------------------------
2294
2295 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002296 __ mov(r0, Operand(literal->handle()));
2297 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002298 Load(property->obj());
2299
2300 // Load the arguments.
2301 for (int i = 0; i < args->length(); i++) Load(args->at(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302
2303 // Set the receiver register and call the IC initialization code.
2304 Handle<Code> stub = ComputeCallInitialize(args->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002305 __ RecordPosition(node->position());
ager@chromium.org236ad962008-09-25 09:45:57 +00002306 __ Call(stub, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002307 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2308
2309 // Remove the function from the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002310 __ pop();
2311
2312 __ push(r0); // push after get rid of function from the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313
2314 } else {
2315 // -------------------------------------------
2316 // JavaScript example: 'array[index](1, 2, 3)'
2317 // -------------------------------------------
2318
2319 // Load the function to call from the property through a reference.
2320 Reference ref(this, property);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002321 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002322
2323 // Pass receiver to called function.
mads.s.ager31e71382008-08-13 09:32:07 +00002324 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
2325 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002326 // Call the function.
2327 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00002328 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002329 }
2330
2331 } else {
2332 // ----------------------------------
2333 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
2334 // ----------------------------------
2335
2336 // Load the function.
2337 Load(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338 // Pass the global object as the receiver.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002339
2340 // TODO(120): use JSGlobalObject for function lookup and inline cache,
2341 // and use global proxy as 'this' for invocation.
2342 LoadGlobalReceiver(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002343 // Call the function.
2344 CallWithArguments(args, node->position());
mads.s.ager31e71382008-08-13 09:32:07 +00002345 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 }
2347}
2348
2349
ager@chromium.org7c537e22008-10-16 08:43:32 +00002350void CodeGenerator::VisitCallNew(CallNew* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002351 Comment cmnt(masm_, "[ CallNew");
2352
2353 // According to ECMA-262, section 11.2.2, page 44, the function
2354 // expression in new calls must be evaluated before the
2355 // arguments. This is different from ordinary calls, where the
2356 // actual function to call is resolved after the arguments have been
2357 // evaluated.
2358
2359 // Compute function to call and use the global object as the
2360 // receiver.
2361 Load(node->expression());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002362 LoadGlobalReceiver(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363
2364 // Push the arguments ("left-to-right") on the stack.
2365 ZoneList<Expression*>* args = node->arguments();
2366 for (int i = 0; i < args->length(); i++) Load(args->at(i));
2367
mads.s.ager31e71382008-08-13 09:32:07 +00002368 // r0: the number of arguments.
2369 __ mov(r0, Operand(args->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002371 // Load the function into r1 as per calling convention.
2372 __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
2373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002374 // Call the construct call builtin that handles allocation and
2375 // constructor invocation.
ager@chromium.org236ad962008-09-25 09:45:57 +00002376 __ RecordPosition(RelocInfo::POSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002377 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
ager@chromium.org236ad962008-09-25 09:45:57 +00002378 RelocInfo::CONSTRUCT_CALL);
mads.s.ager31e71382008-08-13 09:32:07 +00002379
2380 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
2381 __ str(r0, MemOperand(sp, 0 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002382}
2383
2384
ager@chromium.org7c537e22008-10-16 08:43:32 +00002385void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002386 ASSERT(args->length() == 1);
2387 Label leave;
2388 Load(args->at(0));
mads.s.ager31e71382008-08-13 09:32:07 +00002389 __ pop(r0); // r0 contains object.
2390 // if (object->IsSmi()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002391 __ tst(r0, Operand(kSmiTagMask));
2392 __ b(eq, &leave);
2393 // It is a heap object - get map.
2394 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2395 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00002396 // if (!object->IsJSValue()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002397 __ cmp(r1, Operand(JS_VALUE_TYPE));
2398 __ b(ne, &leave);
2399 // Load the value.
2400 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
2401 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00002402 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002403}
2404
2405
ager@chromium.org7c537e22008-10-16 08:43:32 +00002406void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002407 ASSERT(args->length() == 2);
2408 Label leave;
2409 Load(args->at(0)); // Load the object.
2410 Load(args->at(1)); // Load the value.
mads.s.ager31e71382008-08-13 09:32:07 +00002411 __ pop(r0); // r0 contains value
2412 __ pop(r1); // r1 contains object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002413 // if (object->IsSmi()) return object.
2414 __ tst(r1, Operand(kSmiTagMask));
2415 __ b(eq, &leave);
2416 // It is a heap object - get map.
2417 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
2418 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
2419 // if (!object->IsJSValue()) return object.
2420 __ cmp(r2, Operand(JS_VALUE_TYPE));
2421 __ b(ne, &leave);
2422 // Store the value.
2423 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
2424 // Update the write barrier.
2425 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
2426 __ RecordWrite(r1, r2, r3);
2427 // Leave.
2428 __ bind(&leave);
mads.s.ager31e71382008-08-13 09:32:07 +00002429 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002430}
2431
2432
ager@chromium.org7c537e22008-10-16 08:43:32 +00002433void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002434 ASSERT(args->length() == 1);
2435 Load(args->at(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436 __ pop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00002437 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002438 cc_reg_ = eq;
2439}
2440
2441
ager@chromium.org7c537e22008-10-16 08:43:32 +00002442void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00002443 ASSERT(args->length() == 1);
2444 Load(args->at(0));
2445 __ pop(r0);
2446 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
2447 cc_reg_ = eq;
2448}
2449
2450
kasper.lund7276f142008-07-30 08:49:36 +00002451// This should generate code that performs a charCodeAt() call or returns
2452// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
2453// It is not yet implemented on ARM, so it always goes to the slow case.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002454void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
kasper.lund7276f142008-07-30 08:49:36 +00002455 ASSERT(args->length() == 2);
kasper.lund7276f142008-07-30 08:49:36 +00002456 __ mov(r0, Operand(Factory::undefined_value()));
mads.s.ager31e71382008-08-13 09:32:07 +00002457 __ push(r0);
kasper.lund7276f142008-07-30 08:49:36 +00002458}
2459
2460
ager@chromium.org7c537e22008-10-16 08:43:32 +00002461void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002462 ASSERT(args->length() == 1);
2463 Load(args->at(0));
2464 Label answer;
2465 // We need the CC bits to come out as not_equal in the case where the
2466 // object is a smi. This can't be done with the usual test opcode so
2467 // we use XOR to get the right CC bits.
2468 __ pop(r0);
2469 __ and_(r1, r0, Operand(kSmiTagMask));
2470 __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
2471 __ b(ne, &answer);
2472 // It is a heap object - get the map.
2473 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2474 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
2475 // Check if the object is a JS array or not.
2476 __ cmp(r1, Operand(JS_ARRAY_TYPE));
2477 __ bind(&answer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002478 cc_reg_ = eq;
2479}
2480
2481
ager@chromium.org7c537e22008-10-16 08:43:32 +00002482void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483 ASSERT(args->length() == 0);
2484
mads.s.ager31e71382008-08-13 09:32:07 +00002485 // Seed the result with the formal parameters count, which will be used
2486 // in case no arguments adaptor frame is found below the current frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002487 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
2488
2489 // Call the shared stub to get to the arguments.length.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002490 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002491 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00002492 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002493}
2494
2495
ager@chromium.org7c537e22008-10-16 08:43:32 +00002496void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002497 ASSERT(args->length() == 1);
2498
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002499 // Satisfy contract with ArgumentsAccessStub:
2500 // Load the key into r1 and the formal parameters count into r0.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002501 Load(args->at(0));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002502 __ pop(r1);
2503 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504
2505 // Call the shared stub to get to arguments[key].
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002506 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002507 __ CallStub(&stub);
mads.s.ager31e71382008-08-13 09:32:07 +00002508 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509}
2510
2511
ager@chromium.org7c537e22008-10-16 08:43:32 +00002512void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002513 ASSERT(args->length() == 2);
2514
2515 // Load the two objects into registers and perform the comparison.
2516 Load(args->at(0));
2517 Load(args->at(1));
2518 __ pop(r0);
2519 __ pop(r1);
2520 __ cmp(r0, Operand(r1));
2521 cc_reg_ = eq;
2522}
2523
2524
ager@chromium.org7c537e22008-10-16 08:43:32 +00002525void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002526 if (CheckForInlineRuntimeCall(node)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002527
2528 ZoneList<Expression*>* args = node->arguments();
2529 Comment cmnt(masm_, "[ CallRuntime");
2530 Runtime::Function* function = node->function();
2531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002532 if (function != NULL) {
mads.s.ager31e71382008-08-13 09:32:07 +00002533 // Push the arguments ("left-to-right").
2534 for (int i = 0; i < args->length(); i++) Load(args->at(i));
2535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002536 // Call the C runtime function.
2537 __ CallRuntime(function, args->length());
mads.s.ager31e71382008-08-13 09:32:07 +00002538 __ push(r0);
2539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002540 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00002541 // Prepare stack for calling JS runtime function.
2542 __ mov(r0, Operand(node->name()));
2543 __ push(r0);
2544 // Push the builtins object found in the current global object.
2545 __ ldr(r1, GlobalObject());
2546 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
2547 __ push(r0);
2548
2549 for (int i = 0; i < args->length(); i++) Load(args->at(i));
2550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 // Call the JS runtime function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 Handle<Code> stub = ComputeCallInitialize(args->length());
ager@chromium.org236ad962008-09-25 09:45:57 +00002553 __ Call(stub, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002554 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00002555 __ pop();
2556 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002557 }
2558}
2559
2560
ager@chromium.org7c537e22008-10-16 08:43:32 +00002561void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002562 Comment cmnt(masm_, "[ UnaryOperation");
2563
2564 Token::Value op = node->op();
2565
2566 if (op == Token::NOT) {
2567 LoadCondition(node->expression(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00002568 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002569 false_target(),
2570 true_target(),
2571 true);
2572 cc_reg_ = NegateCondition(cc_reg_);
2573
2574 } else if (op == Token::DELETE) {
2575 Property* property = node->expression()->AsProperty();
mads.s.ager31e71382008-08-13 09:32:07 +00002576 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002577 if (property != NULL) {
2578 Load(property->obj());
2579 Load(property->key());
mads.s.ager31e71382008-08-13 09:32:07 +00002580 __ mov(r0, Operand(1)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002581 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002582
mads.s.ager31e71382008-08-13 09:32:07 +00002583 } else if (variable != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002584 Slot* slot = variable->slot();
2585 if (variable->is_global()) {
2586 LoadGlobal();
mads.s.ager31e71382008-08-13 09:32:07 +00002587 __ mov(r0, Operand(variable->name()));
2588 __ push(r0);
2589 __ mov(r0, Operand(1)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002590 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002591
2592 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
2593 // lookup the context holding the named variable
mads.s.ager31e71382008-08-13 09:32:07 +00002594 __ push(cp);
2595 __ mov(r0, Operand(variable->name()));
2596 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597 __ CallRuntime(Runtime::kLookupContext, 2);
2598 // r0: context
mads.s.ager31e71382008-08-13 09:32:07 +00002599 __ push(r0);
2600 __ mov(r0, Operand(variable->name()));
2601 __ push(r0);
2602 __ mov(r0, Operand(1)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002603 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002604
mads.s.ager31e71382008-08-13 09:32:07 +00002605 } else {
2606 // Default: Result of deleting non-global, not dynamically
2607 // introduced variables is false.
2608 __ mov(r0, Operand(Factory::false_value()));
2609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002610
2611 } else {
2612 // Default: Result of deleting expressions is true.
2613 Load(node->expression()); // may have side-effects
mads.s.ager31e71382008-08-13 09:32:07 +00002614 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002615 __ mov(r0, Operand(Factory::true_value()));
2616 }
mads.s.ager31e71382008-08-13 09:32:07 +00002617 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002618
2619 } else if (op == Token::TYPEOF) {
2620 // Special case for loading the typeof expression; see comment on
2621 // LoadTypeofExpression().
2622 LoadTypeofExpression(node->expression());
2623 __ CallRuntime(Runtime::kTypeof, 1);
mads.s.ager31e71382008-08-13 09:32:07 +00002624 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002625
2626 } else {
2627 Load(node->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00002628 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002629 switch (op) {
2630 case Token::NOT:
2631 case Token::DELETE:
2632 case Token::TYPEOF:
2633 UNREACHABLE(); // handled above
2634 break;
2635
2636 case Token::SUB: {
2637 UnarySubStub stub;
2638 __ CallStub(&stub);
2639 break;
2640 }
2641
2642 case Token::BIT_NOT: {
2643 // smi check
2644 Label smi_label;
2645 Label continue_label;
2646 __ tst(r0, Operand(kSmiTagMask));
2647 __ b(eq, &smi_label);
2648
mads.s.ager31e71382008-08-13 09:32:07 +00002649 __ push(r0);
2650 __ mov(r0, Operand(0)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002651 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002652
2653 __ b(&continue_label);
2654 __ bind(&smi_label);
2655 __ mvn(r0, Operand(r0));
2656 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
2657 __ bind(&continue_label);
2658 break;
2659 }
2660
2661 case Token::VOID:
2662 // since the stack top is cached in r0, popping and then
2663 // pushing a value can be done by just writing to r0.
2664 __ mov(r0, Operand(Factory::undefined_value()));
2665 break;
2666
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002667 case Token::ADD: {
2668 // Smi check.
2669 Label continue_label;
2670 __ tst(r0, Operand(kSmiTagMask));
2671 __ b(eq, &continue_label);
mads.s.ager31e71382008-08-13 09:32:07 +00002672 __ push(r0);
2673 __ mov(r0, Operand(0)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002674 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002675 __ bind(&continue_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678 default:
2679 UNREACHABLE();
2680 }
mads.s.ager31e71382008-08-13 09:32:07 +00002681 __ push(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682 }
2683}
2684
2685
ager@chromium.org7c537e22008-10-16 08:43:32 +00002686void CodeGenerator::VisitCountOperation(CountOperation* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002687 Comment cmnt(masm_, "[ CountOperation");
2688
2689 bool is_postfix = node->is_postfix();
2690 bool is_increment = node->op() == Token::INC;
2691
2692 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
2693 bool is_const = (var != NULL && var->mode() == Variable::CONST);
2694
2695 // Postfix: Make room for the result.
mads.s.ager31e71382008-08-13 09:32:07 +00002696 if (is_postfix) {
2697 __ mov(r0, Operand(0));
2698 __ push(r0);
2699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700
2701 { Reference target(this, node->expression());
2702 if (target.is_illegal()) return;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002703 target.GetValue(NOT_INSIDE_TYPEOF);
mads.s.ager31e71382008-08-13 09:32:07 +00002704 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705
2706 Label slow, exit;
2707
2708 // Load the value (1) into register r1.
2709 __ mov(r1, Operand(Smi::FromInt(1)));
2710
2711 // Check for smi operand.
2712 __ tst(r0, Operand(kSmiTagMask));
2713 __ b(ne, &slow);
2714
2715 // Postfix: Store the old value as the result.
2716 if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
2717
2718 // Perform optimistic increment/decrement.
2719 if (is_increment) {
2720 __ add(r0, r0, Operand(r1), SetCC);
2721 } else {
2722 __ sub(r0, r0, Operand(r1), SetCC);
2723 }
2724
2725 // If the increment/decrement didn't overflow, we're done.
2726 __ b(vc, &exit);
2727
2728 // Revert optimistic increment/decrement.
2729 if (is_increment) {
2730 __ sub(r0, r0, Operand(r1));
2731 } else {
2732 __ add(r0, r0, Operand(r1));
2733 }
2734
2735 // Slow case: Convert to number.
2736 __ bind(&slow);
2737
2738 // Postfix: Convert the operand to a number and store it as the result.
2739 if (is_postfix) {
2740 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
2741 __ CallStub(&stub);
2742 // Store to result (on the stack).
2743 __ str(r0, MemOperand(sp, target.size() * kPointerSize));
2744 }
2745
2746 // Compute the new value by calling the right JavaScript native.
2747 if (is_increment) {
2748 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
2749 __ CallStub(&stub);
2750 } else {
2751 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
2752 __ CallStub(&stub);
2753 }
2754
2755 // Store the new value in the target if not const.
2756 __ bind(&exit);
mads.s.ager31e71382008-08-13 09:32:07 +00002757 __ push(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002758 if (!is_const) target.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 }
2760
2761 // Postfix: Discard the new value and use the old.
2762 if (is_postfix) __ pop(r0);
2763}
2764
2765
ager@chromium.org7c537e22008-10-16 08:43:32 +00002766void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767 Comment cmnt(masm_, "[ BinaryOperation");
2768 Token::Value op = node->op();
2769
2770 // According to ECMA-262 section 11.11, page 58, the binary logical
2771 // operators must yield the result of one of the two expressions
2772 // before any ToBoolean() conversions. This means that the value
2773 // produced by a && or || operator is not necessarily a boolean.
2774
2775 // NOTE: If the left hand side produces a materialized value (not in
2776 // the CC register), we force the right hand side to do the
2777 // same. This is necessary because we may have to branch to the exit
2778 // after evaluating the left hand side (due to the shortcut
2779 // semantics), but the compiler must (statically) know if the result
2780 // of compiling the binary operation is materialized or not.
2781
2782 if (op == Token::AND) {
2783 Label is_true;
2784 LoadCondition(node->left(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00002785 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786 &is_true,
2787 false_target(),
2788 false);
2789 if (has_cc()) {
2790 Branch(false, false_target());
2791
2792 // Evaluate right side expression.
2793 __ bind(&is_true);
2794 LoadCondition(node->right(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00002795 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796 true_target(),
2797 false_target(),
2798 false);
2799
2800 } else {
2801 Label pop_and_continue, exit;
2802
mads.s.ager31e71382008-08-13 09:32:07 +00002803 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top
2804 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805 // Avoid popping the result if it converts to 'false' using the
2806 // standard ToBoolean() conversion as described in ECMA-262,
2807 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00002808 ToBoolean(&pop_and_continue, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809 Branch(false, &exit);
2810
2811 // Pop the result of evaluating the first part.
2812 __ bind(&pop_and_continue);
2813 __ pop(r0);
2814
2815 // Evaluate right side expression.
2816 __ bind(&is_true);
2817 Load(node->right());
2818
2819 // Exit (always with a materialized value).
2820 __ bind(&exit);
2821 }
2822
2823 } else if (op == Token::OR) {
2824 Label is_false;
2825 LoadCondition(node->left(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00002826 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002827 true_target(),
2828 &is_false,
2829 false);
2830 if (has_cc()) {
2831 Branch(true, true_target());
2832
2833 // Evaluate right side expression.
2834 __ bind(&is_false);
2835 LoadCondition(node->right(),
ager@chromium.org7c537e22008-10-16 08:43:32 +00002836 NOT_INSIDE_TYPEOF,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002837 true_target(),
2838 false_target(),
2839 false);
2840
2841 } else {
2842 Label pop_and_continue, exit;
2843
mads.s.ager31e71382008-08-13 09:32:07 +00002844 __ ldr(r0, MemOperand(sp, 0));
2845 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002846 // Avoid popping the result if it converts to 'true' using the
2847 // standard ToBoolean() conversion as described in ECMA-262,
2848 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00002849 ToBoolean(&exit, &pop_and_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002850 Branch(true, &exit);
2851
2852 // Pop the result of evaluating the first part.
2853 __ bind(&pop_and_continue);
2854 __ pop(r0);
2855
2856 // Evaluate right side expression.
2857 __ bind(&is_false);
2858 Load(node->right());
2859
2860 // Exit (always with a materialized value).
2861 __ bind(&exit);
2862 }
2863
2864 } else {
2865 // Optimize for the case where (at least) one of the expressions
2866 // is a literal small integer.
2867 Literal* lliteral = node->left()->AsLiteral();
2868 Literal* rliteral = node->right()->AsLiteral();
2869
2870 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
2871 Load(node->left());
2872 SmiOperation(node->op(), rliteral->handle(), false);
2873
2874 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
2875 Load(node->right());
2876 SmiOperation(node->op(), lliteral->handle(), true);
2877
2878 } else {
2879 Load(node->left());
2880 Load(node->right());
kasper.lund7276f142008-07-30 08:49:36 +00002881 GenericBinaryOperation(node->op());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 }
mads.s.ager31e71382008-08-13 09:32:07 +00002883 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884 }
2885}
2886
2887
ager@chromium.org7c537e22008-10-16 08:43:32 +00002888void CodeGenerator::VisitThisFunction(ThisFunction* node) {
mads.s.ager31e71382008-08-13 09:32:07 +00002889 __ ldr(r0, FunctionOperand());
2890 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891}
2892
2893
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895 Comment cmnt(masm_, "[ CompareOperation");
2896
2897 // Get the expressions from the node.
2898 Expression* left = node->left();
2899 Expression* right = node->right();
2900 Token::Value op = node->op();
2901
2902 // NOTE: To make null checks efficient, we check if either left or
2903 // right is the literal 'null'. If so, we optimize the code by
2904 // inlining a null check instead of calling the (very) general
2905 // runtime routine for checking equality.
2906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 if (op == Token::EQ || op == Token::EQ_STRICT) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002908 bool left_is_null =
2909 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
2910 bool right_is_null =
2911 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002912 // The 'null' value is only equal to 'null' or 'undefined'.
2913 if (left_is_null || right_is_null) {
2914 Load(left_is_null ? right : left);
2915 Label exit, undetectable;
mads.s.ager31e71382008-08-13 09:32:07 +00002916 __ pop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917 __ cmp(r0, Operand(Factory::null_value()));
2918
2919 // The 'null' value is only equal to 'undefined' if using
2920 // non-strict comparisons.
2921 if (op != Token::EQ_STRICT) {
2922 __ b(eq, &exit);
2923 __ cmp(r0, Operand(Factory::undefined_value()));
2924
2925 // NOTE: it can be undetectable object.
2926 __ b(eq, &exit);
2927 __ tst(r0, Operand(kSmiTagMask));
2928
2929 __ b(ne, &undetectable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930 __ b(false_target());
2931
2932 __ bind(&undetectable);
2933 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2934 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
2935 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
2936 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
2937 }
2938
2939 __ bind(&exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002940
2941 cc_reg_ = eq;
2942 return;
2943 }
2944 }
2945
2946
2947 // NOTE: To make typeof testing for natives implemented in
2948 // JavaScript really efficient, we generate special code for
2949 // expressions of the form: 'typeof <expression> == <string>'.
2950
2951 UnaryOperation* operation = left->AsUnaryOperation();
2952 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
2953 (operation != NULL && operation->op() == Token::TYPEOF) &&
2954 (right->AsLiteral() != NULL &&
2955 right->AsLiteral()->handle()->IsString())) {
2956 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
2957
mads.s.ager31e71382008-08-13 09:32:07 +00002958 // Load the operand, move it to register r1.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959 LoadTypeofExpression(operation->expression());
mads.s.ager31e71382008-08-13 09:32:07 +00002960 __ pop(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002961
2962 if (check->Equals(Heap::number_symbol())) {
2963 __ tst(r1, Operand(kSmiTagMask));
2964 __ b(eq, true_target());
2965 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
2966 __ cmp(r1, Operand(Factory::heap_number_map()));
2967 cc_reg_ = eq;
2968
2969 } else if (check->Equals(Heap::string_symbol())) {
2970 __ tst(r1, Operand(kSmiTagMask));
2971 __ b(eq, false_target());
2972
2973 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
2974
2975 // NOTE: it might be an undetectable string object
2976 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
2977 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
2978 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
2979 __ b(eq, false_target());
2980
2981 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
2982 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
2983 cc_reg_ = lt;
2984
2985 } else if (check->Equals(Heap::boolean_symbol())) {
2986 __ cmp(r1, Operand(Factory::true_value()));
2987 __ b(eq, true_target());
2988 __ cmp(r1, Operand(Factory::false_value()));
2989 cc_reg_ = eq;
2990
2991 } else if (check->Equals(Heap::undefined_symbol())) {
2992 __ cmp(r1, Operand(Factory::undefined_value()));
2993 __ b(eq, true_target());
2994
2995 __ tst(r1, Operand(kSmiTagMask));
2996 __ b(eq, false_target());
2997
2998 // NOTE: it can be undetectable object.
2999 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3000 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
3001 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
3002 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
3003
3004 cc_reg_ = eq;
3005
3006 } else if (check->Equals(Heap::function_symbol())) {
3007 __ tst(r1, Operand(kSmiTagMask));
3008 __ b(eq, false_target());
3009 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3010 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3011 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
3012 cc_reg_ = eq;
3013
3014 } else if (check->Equals(Heap::object_symbol())) {
3015 __ tst(r1, Operand(kSmiTagMask));
3016 __ b(eq, false_target());
3017
3018 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3019 __ cmp(r1, Operand(Factory::null_value()));
3020 __ b(eq, true_target());
3021
3022 // NOTE: it might be an undetectable object.
3023 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
3024 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
3025 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
3026 __ b(eq, false_target());
3027
3028 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3029 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
3030 __ b(lt, false_target());
3031 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
3032 cc_reg_ = le;
3033
3034 } else {
3035 // Uncommon case: Typeof testing against a string literal that
3036 // is never returned from the typeof operator.
3037 __ b(false_target());
3038 }
3039 return;
3040 }
3041
3042 Load(left);
3043 Load(right);
3044 switch (op) {
3045 case Token::EQ:
3046 Comparison(eq, false);
3047 break;
3048
3049 case Token::LT:
3050 Comparison(lt);
3051 break;
3052
3053 case Token::GT:
3054 Comparison(gt);
3055 break;
3056
3057 case Token::LTE:
3058 Comparison(le);
3059 break;
3060
3061 case Token::GTE:
3062 Comparison(ge);
3063 break;
3064
3065 case Token::EQ_STRICT:
3066 Comparison(eq, true);
3067 break;
3068
3069 case Token::IN:
mads.s.ager31e71382008-08-13 09:32:07 +00003070 __ mov(r0, Operand(1)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003071 __ InvokeBuiltin(Builtins::IN, CALL_JS);
mads.s.ager31e71382008-08-13 09:32:07 +00003072 __ push(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 break;
3074
3075 case Token::INSTANCEOF:
mads.s.ager31e71382008-08-13 09:32:07 +00003076 __ mov(r0, Operand(1)); // not counting receiver
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003077 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003078 __ tst(r0, Operand(r0));
3079 cc_reg_ = eq;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003080 break;
3081
3082 default:
3083 UNREACHABLE();
3084 }
3085}
3086
3087
ager@chromium.org7c537e22008-10-16 08:43:32 +00003088void CodeGenerator::RecordStatementPosition(Node* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003089 if (FLAG_debug_info) {
3090 int statement_pos = node->statement_pos();
ager@chromium.org236ad962008-09-25 09:45:57 +00003091 if (statement_pos == RelocInfo::kNoPosition) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 __ RecordStatementPosition(statement_pos);
3093 }
3094}
3095
3096
ager@chromium.org7c537e22008-10-16 08:43:32 +00003097void CodeGenerator::EnterJSFrame() {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003098#if defined(DEBUG)
3099 { Label done, fail;
3100 __ tst(r1, Operand(kSmiTagMask));
3101 __ b(eq, &fail);
3102 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3103 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3104 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
3105 __ b(eq, &done);
3106 __ bind(&fail);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003107 __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003108 __ bind(&done);
3109 }
3110#endif // DEBUG
3111
3112 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
3113 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114}
3115
3116
ager@chromium.org7c537e22008-10-16 08:43:32 +00003117void CodeGenerator::ExitJSFrame() {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003118 // Drop the execution stack down to the frame pointer and restore the caller
3119 // frame pointer and return address.
3120 __ mov(sp, fp);
3121 __ ldm(ia_w, sp, fp.bit() | lr.bit());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122}
3123
3124
3125#undef __
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003126#define __ masm->
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127
ager@chromium.org7c537e22008-10-16 08:43:32 +00003128Handle<String> Reference::GetName() {
3129 ASSERT(type_ == NAMED);
3130 Property* property = expression_->AsProperty();
3131 if (property == NULL) {
3132 // Global variable reference treated as a named property reference.
3133 VariableProxy* proxy = expression_->AsVariableProxy();
3134 ASSERT(proxy->AsVariable() != NULL);
3135 ASSERT(proxy->AsVariable()->is_global());
3136 return proxy->name();
3137 } else {
3138 Literal* raw_name = property->key()->AsLiteral();
3139 ASSERT(raw_name != NULL);
3140 return Handle<String>(String::cast(*raw_name->handle()));
3141 }
3142}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003143
ager@chromium.org7c537e22008-10-16 08:43:32 +00003144
3145void Reference::GetValue(TypeofState typeof_state) {
3146 ASSERT(!is_illegal());
3147 ASSERT(!cgen_->has_cc());
3148 MacroAssembler* masm = cgen_->masm();
3149 Property* property = expression_->AsProperty();
3150 if (property != NULL) {
3151 __ RecordPosition(property->position());
3152 }
3153
3154 switch (type_) {
3155 case SLOT: {
3156 Comment cmnt(masm, "[ Load from Slot");
3157 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
3158 ASSERT(slot != NULL);
3159 cgen_->LoadFromSlot(slot, typeof_state);
3160 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003161 }
3162
ager@chromium.org7c537e22008-10-16 08:43:32 +00003163 case NAMED: {
3164 // TODO(1241834): Make sure that this it is safe to ignore the
3165 // distinction between expressions in a typeof and not in a typeof. If
3166 // there is a chance that reference errors can be thrown below, we
3167 // must distinguish between the two kinds of loads (typeof expression
3168 // loads must not throw a reference error).
3169 Comment cmnt(masm, "[ Load from named Property");
3170 // Setup the name register.
3171 Handle<String> name(GetName());
3172 __ mov(r2, Operand(name));
3173 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3174
3175 Variable* var = expression_->AsVariableProxy()->AsVariable();
3176 if (var != NULL) {
3177 ASSERT(var->is_global());
3178 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
3179 } else {
3180 __ Call(ic, RelocInfo::CODE_TARGET);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003181 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003182 __ push(r0);
3183 break;
3184 }
3185
3186 case KEYED: {
3187 // TODO(1241834): Make sure that this it is safe to ignore the
3188 // distinction between expressions in a typeof and not in a typeof.
3189 Comment cmnt(masm, "[ Load from keyed Property");
3190 ASSERT(property != NULL);
3191 // TODO(1224671): Implement inline caching for keyed loads as on ia32.
3192 GetPropertyStub stub;
3193 __ CallStub(&stub);
3194 __ push(r0);
3195 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003196 }
3197
3198 default:
3199 UNREACHABLE();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003200 }
3201}
3202
3203
ager@chromium.org7c537e22008-10-16 08:43:32 +00003204void Reference::SetValue(InitState init_state) {
3205 ASSERT(!is_illegal());
3206 ASSERT(!cgen_->has_cc());
3207 MacroAssembler* masm = cgen_->masm();
3208 Property* property = expression_->AsProperty();
3209 if (property != NULL) {
3210 __ RecordPosition(property->position());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003211 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003212
ager@chromium.org7c537e22008-10-16 08:43:32 +00003213 switch (type_) {
3214 case SLOT: {
3215 Comment cmnt(masm, "[ Store to Slot");
3216 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
3217 ASSERT(slot != NULL);
3218 if (slot->type() == Slot::LOOKUP) {
3219 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003220
ager@chromium.org7c537e22008-10-16 08:43:32 +00003221 // For now, just do a runtime call.
3222 __ push(cp);
3223 __ mov(r0, Operand(slot->var()->name()));
3224 __ push(r0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003225
ager@chromium.org7c537e22008-10-16 08:43:32 +00003226 if (init_state == CONST_INIT) {
3227 // Same as the case for a normal store, but ignores attribute
3228 // (e.g. READ_ONLY) of context slot so that we can initialize
3229 // const properties (introduced via eval("const foo = (some
3230 // expr);")). Also, uses the current function context instead of
3231 // the top context.
3232 //
3233 // Note that we must declare the foo upon entry of eval(), via a
3234 // context slot declaration, but we cannot initialize it at the
3235 // same time, because the const declaration may be at the end of
3236 // the eval code (sigh...) and the const variable may have been
3237 // used before (where its value is 'undefined'). Thus, we can only
3238 // do the initialization when we actually encounter the expression
3239 // and when the expression operands are defined and valid, and
3240 // thus we need the split into 2 operations: declaration of the
3241 // context slot followed by initialization.
3242 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
3243 } else {
3244 __ CallRuntime(Runtime::kStoreContextSlot, 3);
3245 }
3246 // Storing a variable must keep the (new) value on the expression
3247 // stack. This is necessary for compiling assignment expressions.
3248 __ push(r0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003249
ager@chromium.org7c537e22008-10-16 08:43:32 +00003250 } else {
3251 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003252
ager@chromium.org7c537e22008-10-16 08:43:32 +00003253 Label exit;
3254 if (init_state == CONST_INIT) {
3255 ASSERT(slot->var()->mode() == Variable::CONST);
3256 // Only the first const initialization must be executed (the slot
3257 // still contains 'the hole' value). When the assignment is
3258 // executed, the code is identical to a normal store (see below).
3259 Comment cmnt(masm, "[ Init const");
3260 __ ldr(r2, cgen_->SlotOperand(slot, r2));
3261 __ cmp(r2, Operand(Factory::the_hole_value()));
3262 __ b(ne, &exit);
3263 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003264
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265 // We must execute the store. Storing a variable must keep the
3266 // (new) value on the stack. This is necessary for compiling
3267 // assignment expressions.
3268 //
3269 // Note: We will reach here even with slot->var()->mode() ==
3270 // Variable::CONST because of const declarations which will
3271 // initialize consts to 'the hole' value and by doing so, end up
3272 // calling this code. r2 may be loaded with context; used below in
3273 // RecordWrite.
3274 __ pop(r0);
3275 __ str(r0, cgen_->SlotOperand(slot, r2));
3276 __ push(r0);
3277 if (slot->type() == Slot::CONTEXT) {
3278 // Skip write barrier if the written value is a smi.
3279 __ tst(r0, Operand(kSmiTagMask));
3280 __ b(eq, &exit);
3281 // r2 is loaded with context when calling SlotOperand above.
3282 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
3283 __ mov(r3, Operand(offset));
3284 __ RecordWrite(r2, r3, r1);
3285 }
3286 // If we definitely did not jump over the assignment, we do not need
3287 // to bind the exit label. Doing so can defeat peephole
3288 // optimization.
3289 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
3290 __ bind(&exit);
3291 }
3292 }
3293 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003294 }
3295
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296 case NAMED: {
3297 Comment cmnt(masm, "[ Store to named Property");
3298 // Call the appropriate IC code.
3299 __ pop(r0); // value
3300 // Setup the name register.
3301 Handle<String> name(GetName());
3302 __ mov(r2, Operand(name));
3303 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3304 __ Call(ic, RelocInfo::CODE_TARGET);
3305 __ push(r0);
3306 break;
3307 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003308
ager@chromium.org7c537e22008-10-16 08:43:32 +00003309 case KEYED: {
3310 Comment cmnt(masm, "[ Store to keyed Property");
3311 Property* property = expression_->AsProperty();
3312 ASSERT(property != NULL);
3313 __ RecordPosition(property->position());
3314 __ pop(r0); // value
3315 SetPropertyStub stub;
3316 __ CallStub(&stub);
3317 __ push(r0);
3318 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003319 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003320
3321 default:
3322 UNREACHABLE();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003323 }
3324}
3325
3326
3327void GetPropertyStub::Generate(MacroAssembler* masm) {
3328 // sp[0]: key
3329 // sp[1]: receiver
3330 Label slow, fast;
3331 // Get the key and receiver object from the stack.
3332 __ ldm(ia, sp, r0.bit() | r1.bit());
3333 // Check that the key is a smi.
3334 __ tst(r0, Operand(kSmiTagMask));
3335 __ b(ne, &slow);
3336 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
3337 // Check that the object isn't a smi.
3338 __ tst(r1, Operand(kSmiTagMask));
3339 __ b(eq, &slow);
3340
3341 // Check that the object is some kind of JS object EXCEPT JS Value type.
3342 // In the case that the object is a value-wrapper object,
3343 // we enter the runtime system to make sure that indexing into string
3344 // objects work as intended.
3345 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
3346 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3347 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3348 __ cmp(r2, Operand(JS_OBJECT_TYPE));
3349 __ b(lt, &slow);
3350
3351 // Get the elements array of the object.
3352 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
3353 // Check that the object is in fast mode (not dictionary).
3354 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
3355 __ cmp(r3, Operand(Factory::hash_table_map()));
3356 __ b(eq, &slow);
3357 // Check that the key (index) is within bounds.
3358 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
3359 __ cmp(r0, Operand(r3));
3360 __ b(lo, &fast);
3361
3362 // Slow case: Push extra copies of the arguments (2).
3363 __ bind(&slow);
3364 __ ldm(ia, sp, r0.bit() | r1.bit());
3365 __ stm(db_w, sp, r0.bit() | r1.bit());
3366 // Do tail-call to runtime routine.
3367 __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
3368
3369 // Fast case: Do the load.
3370 __ bind(&fast);
3371 __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
3372 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
3373 __ cmp(r0, Operand(Factory::the_hole_value()));
3374 // In case the loaded value is the_hole we have to consult GetProperty
3375 // to ensure the prototype chain is searched.
3376 __ b(eq, &slow);
3377
3378 __ StubReturn(1);
3379}
3380
3381
3382void SetPropertyStub::Generate(MacroAssembler* masm) {
3383 // r0 : value
3384 // sp[0] : key
3385 // sp[1] : receiver
3386
3387 Label slow, fast, array, extra, exit;
3388 // Get the key and the object from the stack.
3389 __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
3390 // Check that the key is a smi.
3391 __ tst(r1, Operand(kSmiTagMask));
3392 __ b(ne, &slow);
3393 // Check that the object isn't a smi.
3394 __ tst(r3, Operand(kSmiTagMask));
3395 __ b(eq, &slow);
3396 // Get the type of the object from its map.
3397 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
3398 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3399 // Check if the object is a JS array or not.
3400 __ cmp(r2, Operand(JS_ARRAY_TYPE));
3401 __ b(eq, &array);
3402 // Check that the object is some kind of JS object.
3403 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
3404 __ b(lt, &slow);
3405
3406
3407 // Object case: Check key against length in the elements array.
3408 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
3409 // Check that the object is in fast mode (not dictionary).
3410 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
3411 __ cmp(r2, Operand(Factory::hash_table_map()));
3412 __ b(eq, &slow);
3413 // Untag the key (for checking against untagged length in the fixed array).
3414 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
3415 // Compute address to store into and check array bounds.
3416 __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
3417 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
3418 __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
3419 __ cmp(r1, Operand(ip));
3420 __ b(lo, &fast);
3421
3422
3423 // Slow case: Push extra copies of the arguments (3).
3424 __ bind(&slow);
3425 __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
3426 __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
3427 // Do tail-call to runtime routine.
3428 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
3429
3430
3431 // Extra capacity case: Check if there is extra capacity to
3432 // perform the store and update the length. Used for adding one
3433 // element to the array by writing to array[array.length].
3434 // r0 == value, r1 == key, r2 == elements, r3 == object
3435 __ bind(&extra);
3436 __ b(ne, &slow); // do not leave holes in the array
3437 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag
3438 __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
3439 __ cmp(r1, Operand(ip));
3440 __ b(hs, &slow);
3441 __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag
3442 __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment
3443 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
3444 __ mov(r3, Operand(r2));
3445 // NOTE: Computing the address to store into must take the fact
3446 // that the key has been incremented into account.
3447 int displacement = Array::kHeaderSize - kHeapObjectTag -
3448 ((1 << kSmiTagSize) * 2);
3449 __ add(r2, r2, Operand(displacement));
3450 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
3451 __ b(&fast);
3452
3453
3454 // Array case: Get the length and the elements array from the JS
3455 // array. Check that the array is in fast mode; if it is the
3456 // length is always a smi.
3457 // r0 == value, r3 == object
3458 __ bind(&array);
3459 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
3460 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
3461 __ cmp(r1, Operand(Factory::hash_table_map()));
3462 __ b(eq, &slow);
3463
3464 // Check the key against the length in the array, compute the
3465 // address to store into and fall through to fast case.
3466 __ ldr(r1, MemOperand(sp));
3467 // r0 == value, r1 == key, r2 == elements, r3 == object.
3468 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
3469 __ cmp(r1, Operand(ip));
3470 __ b(hs, &extra);
3471 __ mov(r3, Operand(r2));
3472 __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
3473 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
3474
3475
3476 // Fast case: Do the store.
3477 // r0 == value, r2 == address to store into, r3 == elements
3478 __ bind(&fast);
3479 __ str(r0, MemOperand(r2));
3480 // Skip write barrier if the written value is a smi.
3481 __ tst(r0, Operand(kSmiTagMask));
3482 __ b(eq, &exit);
3483 // Update write barrier for the elements array address.
3484 __ sub(r1, r2, Operand(r3));
3485 __ RecordWrite(r3, r1, r2);
3486 __ bind(&exit);
3487 __ StubReturn(1);
3488}
3489
3490
3491void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
3492 // r1 : x
3493 // r0 : y
3494 // result : r0
3495
3496 switch (op_) {
3497 case Token::ADD: {
3498 Label slow, exit;
3499 // fast path
3500 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
3501 __ add(r0, r1, Operand(r0), SetCC); // add y optimistically
3502 // go slow-path in case of overflow
3503 __ b(vs, &slow);
3504 // go slow-path in case of non-smi operands
3505 ASSERT(kSmiTag == 0); // adjust code below
3506 __ tst(r2, Operand(kSmiTagMask));
3507 __ b(eq, &exit);
3508 // slow path
3509 __ bind(&slow);
3510 __ sub(r0, r0, Operand(r1)); // revert optimistic add
3511 __ push(r1);
3512 __ push(r0);
3513 __ mov(r0, Operand(1)); // set number of arguments
3514 __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
3515 // done
3516 __ bind(&exit);
3517 break;
3518 }
3519
3520 case Token::SUB: {
3521 Label slow, exit;
3522 // fast path
3523 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
3524 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
3525 // go slow-path in case of overflow
3526 __ b(vs, &slow);
3527 // go slow-path in case of non-smi operands
3528 ASSERT(kSmiTag == 0); // adjust code below
3529 __ tst(r2, Operand(kSmiTagMask));
3530 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result
3531 __ b(eq, &exit);
3532 // slow path
3533 __ bind(&slow);
3534 __ push(r1);
3535 __ push(r0);
3536 __ mov(r0, Operand(1)); // set number of arguments
3537 __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
3538 // done
3539 __ bind(&exit);
3540 break;
3541 }
3542
3543 case Token::MUL: {
3544 Label slow, exit;
3545 // tag check
3546 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
3547 ASSERT(kSmiTag == 0); // adjust code below
3548 __ tst(r2, Operand(kSmiTagMask));
3549 __ b(ne, &slow);
3550 // remove tag from one operand (but keep sign), so that result is smi
3551 __ mov(ip, Operand(r0, ASR, kSmiTagSize));
3552 // do multiplication
3553 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1
3554 // go slow on overflows (overflow bit is not set)
3555 __ mov(ip, Operand(r3, ASR, 31));
3556 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical
3557 __ b(ne, &slow);
3558 // go slow on zero result to handle -0
3559 __ tst(r3, Operand(r3));
3560 __ mov(r0, Operand(r3), LeaveCC, ne);
3561 __ b(ne, &exit);
3562 // slow case
3563 __ bind(&slow);
3564 __ push(r1);
3565 __ push(r0);
3566 __ mov(r0, Operand(1)); // set number of arguments
3567 __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
3568 // done
3569 __ bind(&exit);
3570 break;
3571 }
3572
3573 case Token::BIT_OR:
3574 case Token::BIT_AND:
3575 case Token::BIT_XOR: {
3576 Label slow, exit;
3577 // tag check
3578 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
3579 ASSERT(kSmiTag == 0); // adjust code below
3580 __ tst(r2, Operand(kSmiTagMask));
3581 __ b(ne, &slow);
3582 switch (op_) {
3583 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
3584 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
3585 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
3586 default: UNREACHABLE();
3587 }
3588 __ b(&exit);
3589 __ bind(&slow);
3590 __ push(r1); // restore stack
3591 __ push(r0);
3592 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
3593 switch (op_) {
3594 case Token::BIT_OR:
3595 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
3596 break;
3597 case Token::BIT_AND:
3598 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
3599 break;
3600 case Token::BIT_XOR:
3601 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
3602 break;
3603 default:
3604 UNREACHABLE();
3605 }
3606 __ bind(&exit);
3607 break;
3608 }
3609
3610 case Token::SHL:
3611 case Token::SHR:
3612 case Token::SAR: {
3613 Label slow, exit;
3614 // tag check
3615 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
3616 ASSERT(kSmiTag == 0); // adjust code below
3617 __ tst(r2, Operand(kSmiTagMask));
3618 __ b(ne, &slow);
3619 // remove tags from operands (but keep sign)
3620 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
3621 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
3622 // use only the 5 least significant bits of the shift count
3623 __ and_(r2, r2, Operand(0x1f));
3624 // perform operation
3625 switch (op_) {
3626 case Token::SAR:
3627 __ mov(r3, Operand(r3, ASR, r2));
3628 // no checks of result necessary
3629 break;
3630
3631 case Token::SHR:
3632 __ mov(r3, Operand(r3, LSR, r2));
3633 // check that the *unsigned* result fits in a smi
3634 // neither of the two high-order bits can be set:
3635 // - 0x80000000: high bit would be lost when smi tagging
3636 // - 0x40000000: this number would convert to negative when
3637 // smi tagging these two cases can only happen with shifts
3638 // by 0 or 1 when handed a valid smi
3639 __ and_(r2, r3, Operand(0xc0000000), SetCC);
3640 __ b(ne, &slow);
3641 break;
3642
3643 case Token::SHL:
3644 __ mov(r3, Operand(r3, LSL, r2));
3645 // check that the *signed* result fits in a smi
3646 __ add(r2, r3, Operand(0x40000000), SetCC);
3647 __ b(mi, &slow);
3648 break;
3649
3650 default: UNREACHABLE();
3651 }
3652 // tag result and store it in r0
3653 ASSERT(kSmiTag == 0); // adjust code below
3654 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
3655 __ b(&exit);
3656 // slow case
3657 __ bind(&slow);
3658 __ push(r1); // restore stack
3659 __ push(r0);
3660 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
3661 switch (op_) {
3662 case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break;
3663 case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break;
3664 case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
3665 default: UNREACHABLE();
3666 }
3667 __ bind(&exit);
3668 break;
3669 }
3670
3671 default: UNREACHABLE();
3672 }
3673 __ Ret();
3674}
3675
3676
3677void StackCheckStub::Generate(MacroAssembler* masm) {
3678 Label within_limit;
3679 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
3680 __ ldr(ip, MemOperand(ip));
3681 __ cmp(sp, Operand(ip));
3682 __ b(hs, &within_limit);
3683 // Do tail-call to runtime routine.
3684 __ push(r0);
3685 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
3686 __ bind(&within_limit);
3687
3688 __ StubReturn(1);
3689}
3690
3691
3692void UnarySubStub::Generate(MacroAssembler* masm) {
3693 Label undo;
3694 Label slow;
3695 Label done;
3696
3697 // Enter runtime system if the value is not a smi.
3698 __ tst(r0, Operand(kSmiTagMask));
3699 __ b(ne, &slow);
3700
3701 // Enter runtime system if the value of the expression is zero
3702 // to make sure that we switch between 0 and -0.
3703 __ cmp(r0, Operand(0));
3704 __ b(eq, &slow);
3705
3706 // The value of the expression is a smi that is not zero. Try
3707 // optimistic subtraction '0 - value'.
3708 __ rsb(r1, r0, Operand(0), SetCC);
3709 __ b(vs, &slow);
3710
3711 // If result is a smi we are done.
3712 __ tst(r1, Operand(kSmiTagMask));
3713 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result
3714 __ b(eq, &done);
3715
3716 // Enter runtime system.
3717 __ bind(&slow);
3718 __ push(r0);
3719 __ mov(r0, Operand(0)); // set number of arguments
3720 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
3721
3722 __ bind(&done);
3723 __ StubReturn(1);
3724}
3725
3726
3727void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
3728 __ push(r0);
3729 __ mov(r0, Operand(0)); // set number of arguments
3730 switch (kind_) {
3731 case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break;
3732 case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break;
3733 case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break;
3734 default: UNREACHABLE();
3735 }
3736 __ StubReturn(argc_);
3737}
3738
3739
3740void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
3741 // r0 holds exception
3742 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
3743 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
3744 __ ldr(sp, MemOperand(r3));
3745 __ pop(r2); // pop next in chain
3746 __ str(r2, MemOperand(r3));
3747 // restore parameter- and frame-pointer and pop state.
3748 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
3749 // Before returning we restore the context from the frame pointer if not NULL.
3750 // The frame pointer is NULL in the exception handler of a JS entry frame.
3751 __ cmp(fp, Operand(0));
3752 // Set cp to NULL if fp is NULL.
3753 __ mov(cp, Operand(0), LeaveCC, eq);
3754 // Restore cp otherwise.
3755 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
3756 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
3757 __ pop(pc);
3758}
3759
3760
3761void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
3762 // Fetch top stack handler.
3763 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
3764 __ ldr(r3, MemOperand(r3));
3765
3766 // Unwind the handlers until the ENTRY handler is found.
3767 Label loop, done;
3768 __ bind(&loop);
3769 // Load the type of the current stack handler.
3770 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
3771 StackHandlerConstants::kStateOffset;
3772 __ ldr(r2, MemOperand(r3, kStateOffset));
3773 __ cmp(r2, Operand(StackHandler::ENTRY));
3774 __ b(eq, &done);
3775 // Fetch the next handler in the list.
3776 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
3777 StackHandlerConstants::kNextOffset;
3778 __ ldr(r3, MemOperand(r3, kNextOffset));
3779 __ jmp(&loop);
3780 __ bind(&done);
3781
3782 // Set the top handler address to next handler past the current ENTRY handler.
3783 __ ldr(r0, MemOperand(r3, kNextOffset));
3784 __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
3785 __ str(r0, MemOperand(r2));
3786
3787 // Set external caught exception to false.
3788 __ mov(r0, Operand(false));
3789 ExternalReference external_caught(Top::k_external_caught_exception_address);
3790 __ mov(r2, Operand(external_caught));
3791 __ str(r0, MemOperand(r2));
3792
3793 // Set pending exception and r0 to out of memory exception.
3794 Failure* out_of_memory = Failure::OutOfMemoryException();
3795 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
3796 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
3797 __ str(r0, MemOperand(r2));
3798
3799 // Restore the stack to the address of the ENTRY handler
3800 __ mov(sp, Operand(r3));
3801
3802 // restore parameter- and frame-pointer and pop state.
3803 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
3804 // Before returning we restore the context from the frame pointer if not NULL.
3805 // The frame pointer is NULL in the exception handler of a JS entry frame.
3806 __ cmp(fp, Operand(0));
3807 // Set cp to NULL if fp is NULL.
3808 __ mov(cp, Operand(0), LeaveCC, eq);
3809 // Restore cp otherwise.
3810 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
3811 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
3812 __ pop(pc);
3813}
3814
3815
3816void CEntryStub::GenerateCore(MacroAssembler* masm,
3817 Label* throw_normal_exception,
3818 Label* throw_out_of_memory_exception,
3819 StackFrame::Type frame_type,
3820 bool do_gc) {
3821 // r0: result parameter for PerformGC, if any
3822 // r4: number of arguments including receiver (C callee-saved)
3823 // r5: pointer to builtin function (C callee-saved)
3824 // r6: pointer to the first argument (C callee-saved)
3825
3826 if (do_gc) {
3827 // Passing r0.
3828 __ Call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
3829 }
3830
3831 // Call C built-in.
3832 // r0 = argc, r1 = argv
3833 __ mov(r0, Operand(r4));
3834 __ mov(r1, Operand(r6));
3835
3836 // TODO(1242173): To let the GC traverse the return address of the exit
3837 // frames, we need to know where the return address is. Right now,
3838 // we push it on the stack to be able to find it again, but we never
3839 // restore from it in case of changes, which makes it impossible to
3840 // support moving the C entry code stub. This should be fixed, but currently
3841 // this is OK because the CEntryStub gets generated so early in the V8 boot
3842 // sequence that it is not moving ever.
3843 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4
3844 __ push(lr);
3845#if !defined(__arm__)
3846 // Notify the simulator of the transition to C code.
3847 __ swi(assembler::arm::call_rt_r5);
3848#else /* !defined(__arm__) */
3849 __ mov(pc, Operand(r5));
3850#endif /* !defined(__arm__) */
3851 // result is in r0 or r0:r1 - do not destroy these registers!
3852
3853 // check for failure result
3854 Label failure_returned;
3855 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
3856 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
3857 __ add(r2, r0, Operand(1));
3858 __ tst(r2, Operand(kFailureTagMask));
3859 __ b(eq, &failure_returned);
3860
3861 // Exit C frame and return.
3862 // r0:r1: result
3863 // sp: stack pointer
3864 // fp: frame pointer
3865 // pp: caller's parameter pointer pp (restored as C callee-saved)
3866 __ LeaveExitFrame(frame_type);
3867
3868 // check if we should retry or throw exception
3869 Label retry;
3870 __ bind(&failure_returned);
3871 ASSERT(Failure::RETRY_AFTER_GC == 0);
3872 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
3873 __ b(eq, &retry);
3874
3875 Label continue_exception;
3876 // If the returned failure is EXCEPTION then promote Top::pending_exception().
3877 __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
3878 __ b(ne, &continue_exception);
3879
3880 // Retrieve the pending exception and clear the variable.
3881 __ mov(ip, Operand(Factory::the_hole_value().location()));
3882 __ ldr(r3, MemOperand(ip));
3883 __ mov(ip, Operand(Top::pending_exception_address()));
3884 __ ldr(r0, MemOperand(ip));
3885 __ str(r3, MemOperand(ip));
3886
3887 __ bind(&continue_exception);
3888 // Special handling of out of memory exception.
3889 Failure* out_of_memory = Failure::OutOfMemoryException();
3890 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
3891 __ b(eq, throw_out_of_memory_exception);
3892
3893 // Handle normal exception.
3894 __ jmp(throw_normal_exception);
3895
3896 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
3897}
3898
3899
3900void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
3901 // Called from JavaScript; parameters are on stack as if calling JS function
3902 // r0: number of arguments including receiver
3903 // r1: pointer to builtin function
3904 // fp: frame pointer (restored after C call)
3905 // sp: stack pointer (restored as callee's pp after C call)
3906 // cp: current context (C callee-saved)
3907 // pp: caller's parameter pointer pp (C callee-saved)
3908
3909 // NOTE: Invocations of builtins may return failure objects
3910 // instead of a proper result. The builtin entry handles
3911 // this by performing a garbage collection and retrying the
3912 // builtin once.
3913
3914 StackFrame::Type frame_type = is_debug_break
3915 ? StackFrame::EXIT_DEBUG
3916 : StackFrame::EXIT;
3917
3918 // Enter the exit frame that transitions from JavaScript to C++.
3919 __ EnterExitFrame(frame_type);
3920
3921 // r4: number of arguments (C callee-saved)
3922 // r5: pointer to builtin function (C callee-saved)
3923 // r6: pointer to first argument (C callee-saved)
3924
3925 Label throw_out_of_memory_exception;
3926 Label throw_normal_exception;
3927
3928#ifdef DEBUG
3929 if (FLAG_gc_greedy) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003930 Failure* failure = Failure::RetryAfterGC(0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003931 __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
3932 }
3933 GenerateCore(masm,
3934 &throw_normal_exception,
3935 &throw_out_of_memory_exception,
3936 frame_type,
3937 FLAG_gc_greedy);
3938#else
3939 GenerateCore(masm,
3940 &throw_normal_exception,
3941 &throw_out_of_memory_exception,
3942 frame_type,
3943 false);
3944#endif
3945 GenerateCore(masm,
3946 &throw_normal_exception,
3947 &throw_out_of_memory_exception,
3948 frame_type,
3949 true);
3950
3951 __ bind(&throw_out_of_memory_exception);
3952 GenerateThrowOutOfMemory(masm);
3953 // control flow for generated will not return.
3954
3955 __ bind(&throw_normal_exception);
3956 GenerateThrowTOS(masm);
3957}
3958
3959
3960void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
3961 // r0: code entry
3962 // r1: function
3963 // r2: receiver
3964 // r3: argc
3965 // [sp+0]: argv
3966
3967 Label invoke, exit;
3968
3969 // Called from C, so do not pop argc and args on exit (preserve sp)
3970 // No need to save register-passed args
3971 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr
3972 __ stm(db_w, sp, kCalleeSaved | lr.bit());
3973
3974 // Get address of argv, see stm above.
3975 // r0: code entry
3976 // r1: function
3977 // r2: receiver
3978 // r3: argc
3979 __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize));
3980 __ ldr(r4, MemOperand(r4)); // argv
3981
3982 // Push a frame with special values setup to mark it as an entry frame.
3983 // r0: code entry
3984 // r1: function
3985 // r2: receiver
3986 // r3: argc
3987 // r4: argv
3988 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
3989 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used.
3990 __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL));
3991 __ mov(r6, Operand(Smi::FromInt(marker)));
3992 __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address)));
3993 __ ldr(r5, MemOperand(r5));
3994 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit());
3995
3996 // Setup frame pointer for the frame to be pushed.
3997 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
3998
3999 // Call a faked try-block that does the invoke.
4000 __ bl(&invoke);
4001
4002 // Caught exception: Store result (exception) in the pending
4003 // exception field in the JSEnv and return a failure sentinel.
4004 // Coming in here the fp will be invalid because the PushTryHandler below
4005 // sets it to 0 to signal the existence of the JSEntry frame.
4006 __ mov(ip, Operand(Top::pending_exception_address()));
4007 __ str(r0, MemOperand(ip));
4008 __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
4009 __ b(&exit);
4010
4011 // Invoke: Link this frame into the handler chain.
4012 __ bind(&invoke);
4013 // Must preserve r0-r4, r5-r7 are available.
4014 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
4015 // If an exception not caught by another handler occurs, this handler returns
4016 // control to the code after the bl(&invoke) above, which restores all
4017 // kCalleeSaved registers (including cp, pp and fp) to their saved values
4018 // before returning a failure to C.
4019
4020 // Clear any pending exceptions.
4021 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
4022 __ ldr(r5, MemOperand(ip));
4023 __ mov(ip, Operand(Top::pending_exception_address()));
4024 __ str(r5, MemOperand(ip));
4025
4026 // Invoke the function by calling through JS entry trampoline builtin.
4027 // Notice that we cannot store a reference to the trampoline code directly in
4028 // this stub, because runtime stubs are not traversed when doing GC.
4029
4030 // Expected registers by Builtins::JSEntryTrampoline
4031 // r0: code entry
4032 // r1: function
4033 // r2: receiver
4034 // r3: argc
4035 // r4: argv
4036 if (is_construct) {
4037 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
4038 __ mov(ip, Operand(construct_entry));
4039 } else {
4040 ExternalReference entry(Builtins::JSEntryTrampoline);
4041 __ mov(ip, Operand(entry));
4042 }
4043 __ ldr(ip, MemOperand(ip)); // deref address
4044
4045 // Branch and link to JSEntryTrampoline
4046 __ mov(lr, Operand(pc));
4047 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
4048
4049 // Unlink this frame from the handler chain. When reading the
4050 // address of the next handler, there is no need to use the address
4051 // displacement since the current stack pointer (sp) points directly
4052 // to the stack handler.
4053 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
4054 __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
4055 __ str(r3, MemOperand(ip));
4056 // No need to restore registers
4057 __ add(sp, sp, Operand(StackHandlerConstants::kSize));
4058
4059 __ bind(&exit); // r0 holds result
4060 // Restore the top frame descriptors from the stack.
4061 __ pop(r3);
4062 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
4063 __ str(r3, MemOperand(ip));
4064
4065 // Reset the stack to the callee saved registers.
4066 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
4067
4068 // Restore callee-saved registers and return.
4069#ifdef DEBUG
4070 if (FLAG_debug_code) __ mov(lr, Operand(pc));
4071#endif
4072 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
4073}
4074
4075
ager@chromium.org7c537e22008-10-16 08:43:32 +00004076void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004077 // Check if the calling frame is an arguments adaptor frame.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004078 Label adaptor;
4079 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4080 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
4081 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
ager@chromium.org7c537e22008-10-16 08:43:32 +00004082 __ b(eq, &adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004083
ager@chromium.org7c537e22008-10-16 08:43:32 +00004084 // Nothing to do: The formal number of parameters has already been
4085 // passed in register r0 by calling function. Just return it.
4086 __ mov(pc, lr);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004087
ager@chromium.org7c537e22008-10-16 08:43:32 +00004088 // Arguments adaptor case: Read the arguments length from the
4089 // adaptor frame and return it.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004090 __ bind(&adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004091 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +00004092 __ mov(pc, lr);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004093}
4094
4095
ager@chromium.org7c537e22008-10-16 08:43:32 +00004096void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
4097 // The displacement is the offset of the last parameter (if any)
4098 // relative to the frame pointer.
4099 static const int kDisplacement =
4100 StandardFrameConstants::kCallerSPOffset - kPointerSize;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004101
ager@chromium.org7c537e22008-10-16 08:43:32 +00004102 // Check that the key is a smi.
4103 Label slow;
4104 __ tst(r1, Operand(kSmiTagMask));
4105 __ b(ne, &slow);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004106
ager@chromium.org7c537e22008-10-16 08:43:32 +00004107 // Check if the calling frame is an arguments adaptor frame.
4108 Label adaptor;
4109 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4110 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
4111 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
4112 __ b(eq, &adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113
ager@chromium.org7c537e22008-10-16 08:43:32 +00004114 // Check index against formal parameters count limit passed in
4115 // through register eax. Use unsigned comparison to get negative
4116 // check for free.
4117 __ cmp(r1, r0);
4118 __ b(cs, &slow);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004119
ager@chromium.org7c537e22008-10-16 08:43:32 +00004120 // Read the argument from the stack and return it.
4121 __ sub(r3, r0, r1);
4122 __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
4123 __ ldr(r0, MemOperand(r3, kDisplacement));
4124 __ mov(pc, lr);
4125
4126 // Arguments adaptor case: Check index against actual arguments
4127 // limit found in the arguments adaptor frame. Use unsigned
4128 // comparison to get negative check for free.
4129 __ bind(&adaptor);
4130 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
4131 __ cmp(r1, r0);
4132 __ b(cs, &slow);
4133
4134 // Read the argument from the adaptor frame and return it.
4135 __ sub(r3, r0, r1);
4136 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
4137 __ ldr(r0, MemOperand(r3, kDisplacement));
4138 __ mov(pc, lr);
4139
4140 // Slow-case: Handle non-smi or out-of-bounds access to arguments
4141 // by calling the runtime system.
4142 __ bind(&slow);
4143 __ push(r1);
4144 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
4145}
4146
4147
4148void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
4149 // Check if the calling frame is an arguments adaptor frame.
4150 Label runtime;
4151 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4152 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
4153 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
4154 __ b(ne, &runtime);
4155
4156 // Patch the arguments.length and the parameters pointer.
4157 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
4158 __ str(r0, MemOperand(sp, 0 * kPointerSize));
4159 __ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
4160 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
4161 __ str(r3, MemOperand(sp, 1 * kPointerSize));
4162
4163 // Do the runtime call to allocate the arguments object.
4164 __ bind(&runtime);
4165 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004166}
4167
4168
4169void CallFunctionStub::Generate(MacroAssembler* masm) {
4170 Label slow;
4171 // Get the function to call from the stack.
4172 // function, receiver [, arguments]
4173 __ ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
4174
4175 // Check that the function is really a JavaScript function.
4176 // r1: pushed function (to be verified)
4177 __ tst(r1, Operand(kSmiTagMask));
4178 __ b(eq, &slow);
4179 // Get the map of the function object.
4180 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
4181 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4182 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
4183 __ b(ne, &slow);
4184
4185 // Fast-case: Invoke the function now.
4186 // r1: pushed function
4187 ParameterCount actual(argc_);
4188 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
4189
4190 // Slow-case: Non-function called.
4191 __ bind(&slow);
4192 __ mov(r0, Operand(argc_)); // Setup the number of arguments.
4193 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS);
4194}
4195
4196
4197#undef __
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199} } // namespace v8::internal