Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/codegen-arm.cc

Issue 10829: Finish porting jump target changes to the ARM platform. The v8 test... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-arm.h ('k') | src/codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 14 matching lines...) Expand all
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h" 28 #include "v8.h"
29 29
30 #include "bootstrapper.h" 30 #include "bootstrapper.h"
31 #include "codegen-inl.h" 31 #include "codegen-inl.h"
32 #include "debug.h" 32 #include "debug.h"
33 #include "scopes.h" 33 #include "scopes.h"
34 #include "runtime.h" 34 #include "runtime.h"
35 #include "virtual-frame-arm-inl.h"
36 35
37 namespace v8 { namespace internal { 36 namespace v8 { namespace internal {
38 37
39 #define __ masm_-> 38 #define __ masm_->
40 39
41 // ------------------------------------------------------------------------- 40 // -------------------------------------------------------------------------
42 // CodeGenState implementation. 41 // CodeGenState implementation.
43 42
44 CodeGenState::CodeGenState(CodeGenerator* owner) 43 CodeGenState::CodeGenState(CodeGenerator* owner)
45 : owner_(owner), 44 : owner_(owner),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 // pp: caller's parameter pointer 93 // pp: caller's parameter pointer
95 // cp: callee's context 94 // cp: callee's context
96 95
97 void CodeGenerator::GenCode(FunctionLiteral* fun) { 96 void CodeGenerator::GenCode(FunctionLiteral* fun) {
98 ZoneList<Statement*>* body = fun->body(); 97 ZoneList<Statement*>* body = fun->body();
99 98
100 // Initialize state. 99 // Initialize state.
101 ASSERT(scope_ == NULL); 100 ASSERT(scope_ == NULL);
102 scope_ = fun->scope(); 101 scope_ = fun->scope();
103 ASSERT(frame_ == NULL); 102 ASSERT(frame_ == NULL);
104 VirtualFrame virtual_frame(this); 103 set_frame(new VirtualFrame(this));
105 frame_ = &virtual_frame;
106 cc_reg_ = al; 104 cc_reg_ = al;
107 function_return_.set_code_generator(this); 105 function_return_.set_code_generator(this);
108 { 106 {
109 CodeGenState state(this); 107 CodeGenState state(this);
110 108
111 // Entry 109 // Entry
112 // stack: function, receiver, arguments, return address 110 // stack: function, receiver, arguments, return address
113 // r0: number of arguments 111 // r0: number of arguments
114 // sp: stack pointer 112 // sp: stack pointer
115 // fp: frame pointer 113 // fp: frame pointer
116 // pp: caller's parameter pointer 114 // pp: caller's parameter pointer
117 // cp: callee's context 115 // cp: callee's context
118 116
119 frame_->Enter(); 117 frame_->Enter();
120 // tos: code slot 118 // tos: code slot
121 #ifdef DEBUG 119 #ifdef DEBUG
122 if (strlen(FLAG_stop_at) > 0 && 120 if (strlen(FLAG_stop_at) > 0 &&
123 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { 121 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
124 __ stop("stop-at"); 122 __ stop("stop-at");
125 } 123 }
126 #endif 124 #endif
127 125
128 // Allocate space for locals and initialize them. 126 // Allocate space for locals and initialize them.
129 frame_->AllocateLocals(); 127 frame_->AllocateStackSlots(scope_->num_stack_slots());
130 128
131 if (scope_->num_heap_slots() > 0) { 129 if (scope_->num_heap_slots() > 0) {
132 // Allocate local context. 130 // Allocate local context.
133 // Get outer context and create a new context based on it. 131 // Get outer context and create a new context based on it.
134 __ ldr(r0, frame_->Function()); 132 __ ldr(r0, frame_->Function());
135 frame_->Push(r0); 133 frame_->Push(r0);
136 __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result 134 frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
137 135
138 if (kDebug) { 136 if (kDebug) {
139 Label verified_true; 137 JumpTarget verified_true(this);
140 __ cmp(r0, Operand(cp)); 138 __ cmp(r0, Operand(cp));
141 __ b(eq, &verified_true); 139 verified_true.Branch(eq);
142 __ stop("NewContext: r0 is expected to be the same as cp"); 140 __ stop("NewContext: r0 is expected to be the same as cp");
143 __ bind(&verified_true); 141 verified_true.Bind();
144 } 142 }
145 // Update context local. 143 // Update context local.
146 __ str(cp, frame_->Context()); 144 __ str(cp, frame_->Context());
147 } 145 }
148 146
149 // TODO(1241774): Improve this code: 147 // TODO(1241774): Improve this code:
150 // 1) only needed if we have a context 148 // 1) only needed if we have a context
151 // 2) no need to recompute context ptr every single time 149 // 2) no need to recompute context ptr every single time
152 // 3) don't copy parameter operand code from SlotOperand! 150 // 3) don't copy parameter operand code from SlotOperand!
153 { 151 {
154 Comment cmnt2(masm_, "[ copy context parameters into .context"); 152 Comment cmnt2(masm_, "[ copy context parameters into .context");
155 153
156 // Note that iteration order is relevant here! If we have the same 154 // Note that iteration order is relevant here! If we have the same
157 // parameter twice (e.g., function (x, y, x)), and that parameter 155 // parameter twice (e.g., function (x, y, x)), and that parameter
158 // needs to be copied into the context, it must be the last argument 156 // needs to be copied into the context, it must be the last argument
159 // passed to the parameter that needs to be copied. This is a rare 157 // passed to the parameter that needs to be copied. This is a rare
160 // case so we don't check for it, instead we rely on the copying 158 // case so we don't check for it, instead we rely on the copying
161 // order: such a parameter is copied repeatedly into the same 159 // order: such a parameter is copied repeatedly into the same
162 // context location and thus the last value is what is seen inside 160 // context location and thus the last value is what is seen inside
163 // the function. 161 // the function.
164 for (int i = 0; i < scope_->num_parameters(); i++) { 162 for (int i = 0; i < scope_->num_parameters(); i++) {
165 Variable* par = scope_->parameter(i); 163 Variable* par = scope_->parameter(i);
166 Slot* slot = par->slot(); 164 Slot* slot = par->slot();
167 if (slot != NULL && slot->type() == Slot::CONTEXT) { 165 if (slot != NULL && slot->type() == Slot::CONTEXT) {
168 ASSERT(!scope_->is_global_scope()); // no parameters in global scope 166 ASSERT(!scope_->is_global_scope()); // no parameters in global scope
169 __ ldr(r1, frame_->Parameter(i)); 167 __ ldr(r1, frame_->ParameterAt(i));
170 // Loads r2 with context; used below in RecordWrite. 168 // Loads r2 with context; used below in RecordWrite.
171 __ str(r1, SlotOperand(slot, r2)); 169 __ str(r1, SlotOperand(slot, r2));
172 // Load the offset into r3. 170 // Load the offset into r3.
173 int slot_offset = 171 int slot_offset =
174 FixedArray::kHeaderSize + slot->index() * kPointerSize; 172 FixedArray::kHeaderSize + slot->index() * kPointerSize;
175 __ mov(r3, Operand(slot_offset)); 173 __ mov(r3, Operand(slot_offset));
176 __ RecordWrite(r2, r3, r1); 174 __ RecordWrite(r2, r3, r1);
177 } 175 }
178 } 176 }
179 } 177 }
180 178
181 // Store the arguments object. This must happen after context 179 // Store the arguments object. This must happen after context
182 // initialization because the arguments object may be stored in the 180 // initialization because the arguments object may be stored in the
183 // context. 181 // context.
184 if (scope_->arguments() != NULL) { 182 if (scope_->arguments() != NULL) {
185 ASSERT(scope_->arguments_shadow() != NULL); 183 ASSERT(scope_->arguments_shadow() != NULL);
186 Comment cmnt(masm_, "[ allocate arguments object"); 184 Comment cmnt(masm_, "[ allocate arguments object");
187 { Reference shadow_ref(this, scope_->arguments_shadow()); 185 { Reference shadow_ref(this, scope_->arguments_shadow());
188 { Reference arguments_ref(this, scope_->arguments()); 186 { Reference arguments_ref(this, scope_->arguments());
189 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 187 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
190 __ ldr(r2, frame_->Function()); 188 __ ldr(r2, frame_->Function());
191 // The receiver is below the arguments, the return address, 189 // The receiver is below the arguments, the return address,
192 // and the frame pointer on the stack. 190 // and the frame pointer on the stack.
193 const int kReceiverDisplacement = 2 + scope_->num_parameters(); 191 const int kReceiverDisplacement = 2 + scope_->num_parameters();
194 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); 192 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
195 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); 193 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
194 frame_->Adjust(3);
196 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); 195 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
197 __ CallStub(&stub); 196 frame_->CallStub(&stub, 3);
198 frame_->Push(r0); 197 frame_->Push(r0);
199 arguments_ref.SetValue(NOT_CONST_INIT); 198 arguments_ref.SetValue(NOT_CONST_INIT);
200 } 199 }
201 shadow_ref.SetValue(NOT_CONST_INIT); 200 shadow_ref.SetValue(NOT_CONST_INIT);
202 } 201 }
203 frame_->Pop(); // Value is no longer needed. 202 frame_->Drop(); // Value is no longer needed.
204 } 203 }
205 204
206 // Generate code to 'execute' declarations and initialize functions 205 // Generate code to 'execute' declarations and initialize functions
207 // (source elements). In case of an illegal redeclaration we need to 206 // (source elements). In case of an illegal redeclaration we need to
208 // handle that instead of processing the declarations. 207 // handle that instead of processing the declarations.
209 if (scope_->HasIllegalRedeclaration()) { 208 if (scope_->HasIllegalRedeclaration()) {
210 Comment cmnt(masm_, "[ illegal redeclarations"); 209 Comment cmnt(masm_, "[ illegal redeclarations");
211 scope_->VisitIllegalRedeclaration(this); 210 scope_->VisitIllegalRedeclaration(this);
212 } else { 211 } else {
213 Comment cmnt(masm_, "[ declarations"); 212 Comment cmnt(masm_, "[ declarations");
214 ProcessDeclarations(scope_->declarations()); 213 ProcessDeclarations(scope_->declarations());
215 // Bail out if a stack-overflow exception occurred when processing 214 // Bail out if a stack-overflow exception occurred when processing
216 // declarations. 215 // declarations.
217 if (HasStackOverflow()) return; 216 if (HasStackOverflow()) return;
218 } 217 }
219 218
220 if (FLAG_trace) { 219 if (FLAG_trace) {
221 __ CallRuntime(Runtime::kTraceEnter, 0); 220 frame_->CallRuntime(Runtime::kTraceEnter, 0);
222 // Ignore the return value. 221 // Ignore the return value.
223 } 222 }
224 CheckStack(); 223 CheckStack();
225 224
226 // Compile the body of the function in a vanilla state. Don't 225 // Compile the body of the function in a vanilla state. Don't
227 // bother compiling all the code if the scope has an illegal 226 // bother compiling all the code if the scope has an illegal
228 // redeclaration. 227 // redeclaration.
229 if (!scope_->HasIllegalRedeclaration()) { 228 if (!scope_->HasIllegalRedeclaration()) {
230 Comment cmnt(masm_, "[ function body"); 229 Comment cmnt(masm_, "[ function body");
231 #ifdef DEBUG 230 #ifdef DEBUG
232 bool is_builtin = Bootstrapper::IsActive(); 231 bool is_builtin = Bootstrapper::IsActive();
233 bool should_trace = 232 bool should_trace =
234 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; 233 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
235 if (should_trace) { 234 if (should_trace) {
236 __ CallRuntime(Runtime::kDebugTrace, 0); 235 frame_->CallRuntime(Runtime::kDebugTrace, 0);
237 // Ignore the return value. 236 // Ignore the return value.
238 } 237 }
239 #endif 238 #endif
240 VisitStatements(body); 239 VisitStatements(body);
241 } 240 }
242 } 241 }
243 242
244 // exit 243 // Generate the return sequence if necessary.
245 // r0: result 244 if (frame_ != NULL || function_return_.is_linked()) {
246 // sp: stack pointer 245 // exit
247 // fp: frame pointer 246 // r0: result
248 // pp: parameter pointer 247 // sp: stack pointer
249 // cp: callee's context 248 // fp: frame pointer
250 __ mov(r0, Operand(Factory::undefined_value())); 249 // pp: parameter pointer
250 // cp: callee's context
251 __ mov(r0, Operand(Factory::undefined_value()));
251 252
252 function_return_.Bind(); 253 function_return_.Bind();
253 if (FLAG_trace) { 254 if (FLAG_trace) {
254 // Push the return value on the stack as the parameter. 255 // Push the return value on the stack as the parameter.
255 // Runtime::TraceExit returns the parameter as it is. 256 // Runtime::TraceExit returns the parameter as it is.
256 frame_->Push(r0); 257 frame_->Push(r0);
257 __ CallRuntime(Runtime::kTraceExit, 1); 258 frame_->CallRuntime(Runtime::kTraceExit, 1);
259 }
260
261 // Tear down the frame which will restore the caller's frame pointer and
262 // the link register.
263 frame_->Exit();
264
265 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
266 __ mov(pc, lr);
258 } 267 }
259 268
260 // Tear down the frame which will restore the caller's frame pointer and the
261 // link register.
262 frame_->Exit();
263
264 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
265 __ mov(pc, lr);
266
267 // Code generation state must be reset. 269 // Code generation state must be reset.
268 scope_ = NULL; 270 scope_ = NULL;
269 frame_ = NULL; 271 frame_ = NULL;
270 ASSERT(!has_cc()); 272 ASSERT(!has_cc());
271 ASSERT(state_ == NULL); 273 ASSERT(state_ == NULL);
272 } 274 }
273 275
274 276
275 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { 277 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
276 // Currently, this assertion will fail if we try to assign to 278 // Currently, this assertion will fail if we try to assign to
277 // a constant variable that is constant because it is read-only 279 // a constant variable that is constant because it is read-only
278 // (such as the variable referring to a named function expression). 280 // (such as the variable referring to a named function expression).
279 // We need to implement assignments to read-only variables. 281 // We need to implement assignments to read-only variables.
280 // Ideally, we should do this during AST generation (by converting 282 // Ideally, we should do this during AST generation (by converting
281 // such assignments into expression statements); however, in general 283 // such assignments into expression statements); however, in general
282 // we may not be able to make the decision until past AST generation, 284 // we may not be able to make the decision until past AST generation,
283 // that is when the entire program is known. 285 // that is when the entire program is known.
284 ASSERT(slot != NULL); 286 ASSERT(slot != NULL);
285 int index = slot->index(); 287 int index = slot->index();
286 switch (slot->type()) { 288 switch (slot->type()) {
287 case Slot::PARAMETER: 289 case Slot::PARAMETER:
288 return frame_->Parameter(index); 290 return frame_->ParameterAt(index);
289 291
290 case Slot::LOCAL: 292 case Slot::LOCAL:
291 return frame_->Local(index); 293 return frame_->LocalAt(index);
292 294
293 case Slot::CONTEXT: { 295 case Slot::CONTEXT: {
294 // Follow the context chain if necessary. 296 // Follow the context chain if necessary.
295 ASSERT(!tmp.is(cp)); // do not overwrite context register 297 ASSERT(!tmp.is(cp)); // do not overwrite context register
296 Register context = cp; 298 Register context = cp;
297 int chain_length = scope()->ContextChainLength(slot->var()->scope()); 299 int chain_length = scope()->ContextChainLength(slot->var()->scope());
298 for (int i = chain_length; i-- > 0;) { 300 for (int i = chain_length; i-- > 0;) {
299 // Load the closure. 301 // Load the closure.
300 // (All contexts, even 'with' contexts, have a closure, 302 // (All contexts, even 'with' contexts, have a closure,
301 // and it is the same for all contexts inside a function. 303 // and it is the same for all contexts inside a function.
(...skipping 30 matching lines...) Expand all
332 void CodeGenerator::LoadCondition(Expression* x, 334 void CodeGenerator::LoadCondition(Expression* x,
333 TypeofState typeof_state, 335 TypeofState typeof_state,
334 JumpTarget* true_target, 336 JumpTarget* true_target,
335 JumpTarget* false_target, 337 JumpTarget* false_target,
336 bool force_cc) { 338 bool force_cc) {
337 ASSERT(!has_cc()); 339 ASSERT(!has_cc());
338 340
339 { CodeGenState new_state(this, typeof_state, true_target, false_target); 341 { CodeGenState new_state(this, typeof_state, true_target, false_target);
340 Visit(x); 342 Visit(x);
341 } 343 }
342 if (force_cc && !has_cc()) { 344 if (force_cc && frame_ != NULL && !has_cc()) {
343 // Convert the TOS value to a boolean in the condition code register. 345 // Convert the TOS value to a boolean in the condition code register.
344 // Visiting an expression may possibly choose neither (a) to leave a
345 // value in the condition code register nor (b) to leave a value in TOS
346 // (eg, by compiling to only jumps to the targets). In that case the
347 // code generated by ToBoolean is wrong because it assumes the value of
348 // the expression in TOS. So long as there is always a value in TOS or
349 // the condition code register when control falls through to here (there
350 // is), the code generated by ToBoolean is dead and therefore safe.
351 ToBoolean(true_target, false_target); 346 ToBoolean(true_target, false_target);
352 } 347 }
353 ASSERT(has_cc() || !force_cc); 348 ASSERT(!force_cc || frame_ == NULL || has_cc());
354 } 349 }
355 350
356 351
357 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { 352 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
358 JumpTarget true_target(this); 353 JumpTarget true_target(this);
359 JumpTarget false_target(this); 354 JumpTarget false_target(this);
360 LoadCondition(x, typeof_state, &true_target, &false_target, false); 355 LoadCondition(x, typeof_state, &true_target, &false_target, false);
361 356
362 if (has_cc()) { 357 if (has_cc()) {
363 // convert cc_reg_ into a bool 358 // Convert cc_reg_ into a boolean value.
364 Label loaded, materialize_true; 359 JumpTarget loaded(this);
365 __ b(cc_reg_, &materialize_true); 360 JumpTarget materialize_true(this);
361 materialize_true.Branch(cc_reg_);
366 __ mov(r0, Operand(Factory::false_value())); 362 __ mov(r0, Operand(Factory::false_value()));
367 frame_->Push(r0); 363 frame_->Push(r0);
368 __ b(&loaded); 364 loaded.Jump();
369 __ bind(&materialize_true); 365 materialize_true.Bind();
370 __ mov(r0, Operand(Factory::true_value())); 366 __ mov(r0, Operand(Factory::true_value()));
371 frame_->Push(r0); 367 frame_->Push(r0);
372 __ bind(&loaded); 368 loaded.Bind();
373 cc_reg_ = al; 369 cc_reg_ = al;
374 } 370 }
375 371
376 if (true_target.is_linked() || false_target.is_linked()) { 372 if (true_target.is_linked() || false_target.is_linked()) {
377 // we have at least one condition value 373 // We have at least one condition value that has been "translated"
378 // that has been "translated" into a branch, 374 // into a branch, thus it needs to be loaded explicitly.
379 // thus it needs to be loaded explicitly again 375 JumpTarget loaded(this);
380 Label loaded; 376 if (frame_ != NULL) {
381 __ b(&loaded); // don't lose current TOS 377 loaded.Jump(); // Don't lose the current TOS.
378 }
382 bool both = true_target.is_linked() && false_target.is_linked(); 379 bool both = true_target.is_linked() && false_target.is_linked();
383 // reincarnate "true", if necessary 380 // Load "true" if necessary.
384 if (true_target.is_linked()) { 381 if (true_target.is_linked()) {
385 true_target.Bind(); 382 true_target.Bind();
386 __ mov(r0, Operand(Factory::true_value())); 383 __ mov(r0, Operand(Factory::true_value()));
387 frame_->Push(r0); 384 frame_->Push(r0);
388 } 385 }
389 // if both "true" and "false" need to be reincarnated, 386 // If both "true" and "false" need to be loaded jump across the code for
390 // jump across code for "false" 387 // "false".
391 if (both) 388 if (both) {
392 __ b(&loaded); 389 loaded.Jump();
393 // reincarnate "false", if necessary 390 }
391 // Load "false" if necessary.
394 if (false_target.is_linked()) { 392 if (false_target.is_linked()) {
395 false_target.Bind(); 393 false_target.Bind();
396 __ mov(r0, Operand(Factory::false_value())); 394 __ mov(r0, Operand(Factory::false_value()));
397 frame_->Push(r0); 395 frame_->Push(r0);
398 } 396 }
399 // everything is loaded at this point 397 // A value is loaded on all paths reaching this point.
400 __ bind(&loaded); 398 loaded.Bind();
401 } 399 }
400 ASSERT(frame_ != NULL);
402 ASSERT(!has_cc()); 401 ASSERT(!has_cc());
403 } 402 }
404 403
405 404
406 void CodeGenerator::LoadGlobal() { 405 void CodeGenerator::LoadGlobal() {
407 __ ldr(r0, GlobalObject()); 406 __ ldr(r0, GlobalObject());
408 frame_->Push(r0); 407 frame_->Push(r0);
409 } 408 }
410 409
411 410
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 if (var->is_global()) { 478 if (var->is_global()) {
480 LoadGlobal(); 479 LoadGlobal();
481 ref->set_type(Reference::NAMED); 480 ref->set_type(Reference::NAMED);
482 } else { 481 } else {
483 ASSERT(var->slot() != NULL); 482 ASSERT(var->slot() != NULL);
484 ref->set_type(Reference::SLOT); 483 ref->set_type(Reference::SLOT);
485 } 484 }
486 } else { 485 } else {
487 // Anything else is a runtime error. 486 // Anything else is a runtime error.
488 Load(e); 487 Load(e);
489 __ CallRuntime(Runtime::kThrowReferenceError, 1); 488 frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
490 } 489 }
491 } 490 }
492 491
493 492
494 void CodeGenerator::UnloadReference(Reference* ref) { 493 void CodeGenerator::UnloadReference(Reference* ref) {
495 // Pop a reference from the stack while preserving TOS. 494 // Pop a reference from the stack while preserving TOS.
496 Comment cmnt(masm_, "[ UnloadReference"); 495 Comment cmnt(masm_, "[ UnloadReference");
497 int size = ref->size(); 496 int size = ref->size();
498 if (size > 0) { 497 if (size > 0) {
499 frame_->Pop(r0); 498 frame_->Pop(r0);
(...skipping 27 matching lines...) Expand all
527 false_target->Branch(eq); 526 false_target->Branch(eq);
528 527
529 // Check if the value is a smi. 528 // Check if the value is a smi.
530 __ cmp(r0, Operand(Smi::FromInt(0))); 529 __ cmp(r0, Operand(Smi::FromInt(0)));
531 false_target->Branch(eq); 530 false_target->Branch(eq);
532 __ tst(r0, Operand(kSmiTagMask)); 531 __ tst(r0, Operand(kSmiTagMask));
533 true_target->Branch(eq); 532 true_target->Branch(eq);
534 533
535 // Slow case: call the runtime. 534 // Slow case: call the runtime.
536 frame_->Push(r0); 535 frame_->Push(r0);
537 __ CallRuntime(Runtime::kToBool, 1); 536 frame_->CallRuntime(Runtime::kToBool, 1);
538 // Convert the result (r0) to a condition code. 537 // Convert the result (r0) to a condition code.
539 __ cmp(r0, Operand(Factory::false_value())); 538 __ cmp(r0, Operand(Factory::false_value()));
540 539
541 cc_reg_ = ne; 540 cc_reg_ = ne;
542 } 541 }
543 542
544 543
545 class GetPropertyStub : public CodeStub { 544 class GetPropertyStub : public CodeStub {
546 public: 545 public:
547 GetPropertyStub() { } 546 GetPropertyStub() { }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 case Token::MUL: 631 case Token::MUL:
633 case Token::BIT_OR: 632 case Token::BIT_OR:
634 case Token::BIT_AND: 633 case Token::BIT_AND:
635 case Token::BIT_XOR: 634 case Token::BIT_XOR:
636 case Token::SHL: 635 case Token::SHL:
637 case Token::SHR: 636 case Token::SHR:
638 case Token::SAR: { 637 case Token::SAR: {
639 frame_->Pop(r0); // r0 : y 638 frame_->Pop(r0); // r0 : y
640 frame_->Pop(r1); // r1 : x 639 frame_->Pop(r1); // r1 : x
641 GenericBinaryOpStub stub(op); 640 GenericBinaryOpStub stub(op);
642 __ CallStub(&stub); 641 frame_->CallStub(&stub, 0);
643 break; 642 break;
644 } 643 }
645 644
646 case Token::DIV: { 645 case Token::DIV: {
647 __ mov(r0, Operand(1)); 646 __ mov(r0, Operand(1));
648 __ InvokeBuiltin(Builtins::DIV, CALL_JS); 647 frame_->InvokeBuiltin(Builtins::DIV, CALL_JS, 2);
649 break; 648 break;
650 } 649 }
651 650
652 case Token::MOD: { 651 case Token::MOD: {
653 __ mov(r0, Operand(1)); 652 __ mov(r0, Operand(1));
654 __ InvokeBuiltin(Builtins::MOD, CALL_JS); 653 frame_->InvokeBuiltin(Builtins::MOD, CALL_JS, 2);
655 break; 654 break;
656 } 655 }
657 656
658 case Token::COMMA: 657 case Token::COMMA:
659 frame_->Pop(r0); 658 frame_->Pop(r0);
660 // simply discard left value 659 // simply discard left value
661 frame_->Pop(); 660 frame_->Drop();
662 break; 661 break;
663 662
664 default: 663 default:
665 // Other cases should have been handled before this point. 664 // Other cases should have been handled before this point.
666 UNREACHABLE(); 665 UNREACHABLE();
667 break; 666 break;
668 } 667 }
669 } 668 }
670 669
671 670
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 // some possible smi operations (like + and -) when (at least) one 751 // some possible smi operations (like + and -) when (at least) one
753 // of the operands is a literal smi. With this optimization, the 752 // of the operands is a literal smi. With this optimization, the
754 // performance of the system is increased by ~15%, and the generated 753 // performance of the system is increased by ~15%, and the generated
755 // code size is increased by ~1% (measured on a combination of 754 // code size is increased by ~1% (measured on a combination of
756 // different benchmarks). 755 // different benchmarks).
757 756
758 // sp[0] : operand 757 // sp[0] : operand
759 758
760 int int_value = Smi::cast(*value)->value(); 759 int int_value = Smi::cast(*value)->value();
761 760
762 Label exit; 761 JumpTarget exit(this);
763 frame_->Pop(r0); 762 frame_->Pop(r0);
764 763
765 switch (op) { 764 switch (op) {
766 case Token::ADD: { 765 case Token::ADD: {
767 DeferredCode* deferred = 766 DeferredCode* deferred =
768 new DeferredInlinedSmiOperation(this, op, int_value, reversed); 767 new DeferredInlinedSmiOperation(this, op, int_value, reversed);
769 768
770 __ add(r0, r0, Operand(value), SetCC); 769 __ add(r0, r0, Operand(value), SetCC);
771 __ b(vs, deferred->enter()); 770 __ b(vs, deferred->enter());
772 __ tst(r0, Operand(kSmiTagMask)); 771 __ tst(r0, Operand(kSmiTagMask));
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 frame_->Push(r0); 868 frame_->Push(r0);
870 } else { 869 } else {
871 __ mov(ip, Operand(value)); 870 __ mov(ip, Operand(value));
872 frame_->Push(ip); 871 frame_->Push(ip);
873 frame_->Push(r0); 872 frame_->Push(r0);
874 } 873 }
875 GenericBinaryOperation(op); 874 GenericBinaryOperation(op);
876 break; 875 break;
877 } 876 }
878 877
879 __ bind(&exit); 878 exit.Bind();
880 } 879 }
881 880
882 881
883 void CodeGenerator::Comparison(Condition cc, bool strict) { 882 void CodeGenerator::Comparison(Condition cc, bool strict) {
884 // sp[0] : y 883 // sp[0] : y
885 // sp[1] : x 884 // sp[1] : x
886 // result : cc register 885 // result : cc register
887 886
888 // Strict only makes sense for equality comparisons. 887 // Strict only makes sense for equality comparisons.
889 ASSERT(!strict || cc == eq); 888 ASSERT(!strict || cc == eq);
890 889
891 Label exit, smi; 890 JumpTarget exit(this);
891 JumpTarget smi(this);
892 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 892 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
893 if (cc == gt || cc == le) { 893 if (cc == gt || cc == le) {
894 cc = ReverseCondition(cc); 894 cc = ReverseCondition(cc);
895 frame_->Pop(r1); 895 frame_->Pop(r1);
896 frame_->Pop(r0); 896 frame_->Pop(r0);
897 } else { 897 } else {
898 frame_->Pop(r0); 898 frame_->Pop(r0);
899 frame_->Pop(r1); 899 frame_->Pop(r1);
900 } 900 }
901 __ orr(r2, r0, Operand(r1)); 901 __ orr(r2, r0, Operand(r1));
902 __ tst(r2, Operand(kSmiTagMask)); 902 __ tst(r2, Operand(kSmiTagMask));
903 __ b(eq, &smi); 903 smi.Branch(eq);
904 904
905 // Perform non-smi comparison by runtime call. 905 // Perform non-smi comparison by runtime call.
906 frame_->Push(r1); 906 frame_->Push(r1);
907 907
908 // Figure out which native to call and setup the arguments. 908 // Figure out which native to call and setup the arguments.
909 Builtins::JavaScript native; 909 Builtins::JavaScript native;
910 int argc; 910 int arg_count = 1;
911 if (cc == eq) { 911 if (cc == eq) {
912 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 912 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
913 argc = 1;
914 } else { 913 } else {
915 native = Builtins::COMPARE; 914 native = Builtins::COMPARE;
916 int ncr; // NaN compare result 915 int ncr; // NaN compare result
917 if (cc == lt || cc == le) { 916 if (cc == lt || cc == le) {
918 ncr = GREATER; 917 ncr = GREATER;
919 } else { 918 } else {
920 ASSERT(cc == gt || cc == ge); // remaining cases 919 ASSERT(cc == gt || cc == ge); // remaining cases
921 ncr = LESS; 920 ncr = LESS;
922 } 921 }
923 frame_->Push(r0); 922 frame_->Push(r0);
923 arg_count++;
924 __ mov(r0, Operand(Smi::FromInt(ncr))); 924 __ mov(r0, Operand(Smi::FromInt(ncr)));
925 argc = 2;
926 } 925 }
927 926
928 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 927 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
929 // tagged as a small integer. 928 // tagged as a small integer.
930 frame_->Push(r0); 929 frame_->Push(r0);
931 __ mov(r0, Operand(argc)); 930 __ mov(r0, Operand(arg_count));
932 __ InvokeBuiltin(native, CALL_JS); 931 frame_->InvokeBuiltin(native, CALL_JS, arg_count + 1);
933 __ cmp(r0, Operand(0)); 932 __ cmp(r0, Operand(0));
934 __ b(&exit); 933 exit.Jump();
935 934
936 // test smi equality by pointer comparison. 935 // test smi equality by pointer comparison.
937 __ bind(&smi); 936 smi.Bind();
938 __ cmp(r1, Operand(r0)); 937 __ cmp(r1, Operand(r0));
939 938
940 __ bind(&exit); 939 exit.Bind();
941 cc_reg_ = cc; 940 cc_reg_ = cc;
942 } 941 }
943 942
944 943
945 class CallFunctionStub: public CodeStub { 944 class CallFunctionStub: public CodeStub {
946 public: 945 public:
947 explicit CallFunctionStub(int argc) : argc_(argc) {} 946 explicit CallFunctionStub(int argc) : argc_(argc) {}
948 947
949 void Generate(MacroAssembler* masm); 948 void Generate(MacroAssembler* masm);
950 949
951 private: 950 private:
952 int argc_; 951 int argc_;
953 952
954 #if defined(DEBUG) 953 #if defined(DEBUG)
955 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); } 954 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
956 #endif // defined(DEBUG) 955 #endif // defined(DEBUG)
957 956
958 Major MajorKey() { return CallFunction; } 957 Major MajorKey() { return CallFunction; }
959 int MinorKey() { return argc_; } 958 int MinorKey() { return argc_; }
960 }; 959 };
961 960
962 961
963 // Call the function on the stack with the given arguments. 962 // Call the function on the stack with the given arguments.
964 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, 963 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
965 int position) { 964 int position) {
966 // Push the arguments ("left-to-right") on the stack. 965 // Push the arguments ("left-to-right") on the stack.
967 for (int i = 0; i < args->length(); i++) { 966 int arg_count = args->length();
967 for (int i = 0; i < arg_count; i++) {
968 Load(args->at(i)); 968 Load(args->at(i));
969 } 969 }
970 970
971 // Record the position for debugging purposes. 971 // Record the position for debugging purposes.
972 __ RecordPosition(position); 972 __ RecordPosition(position);
973 973
974 // Use the shared code stub to call the function. 974 // Use the shared code stub to call the function.
975 CallFunctionStub call_function(args->length()); 975 CallFunctionStub call_function(arg_count);
976 __ CallStub(&call_function); 976 frame_->CallStub(&call_function, arg_count + 1);
977 977
978 // Restore context and pop function from the stack. 978 // Restore context and pop function from the stack.
979 __ ldr(cp, frame_->Context()); 979 __ ldr(cp, frame_->Context());
980 frame_->Pop(); // discard the TOS 980 frame_->Drop(); // discard the TOS
981 } 981 }
982 982
983 983
984 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { 984 void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
985 ASSERT(has_cc()); 985 ASSERT(has_cc());
986 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); 986 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
987 target->Branch(cc); 987 target->Branch(cc);
988 cc_reg_ = al; 988 cc_reg_ = al;
989 } 989 }
990 990
991 991
992 void CodeGenerator::CheckStack() { 992 void CodeGenerator::CheckStack() {
993 if (FLAG_check_stack) { 993 if (FLAG_check_stack) {
994 Comment cmnt(masm_, "[ check stack"); 994 Comment cmnt(masm_, "[ check stack");
995 StackCheckStub stub; 995 StackCheckStub stub;
996 __ CallStub(&stub); 996 frame_->CallStub(&stub, 0);
997 }
998 }
999
1000
1001 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
1002 for (int i = 0; frame_ != NULL && i < statements->length(); i++) {
1003 Visit(statements->at(i));
997 } 1004 }
998 } 1005 }
999 1006
1000 1007
1001 void CodeGenerator::VisitBlock(Block* node) { 1008 void CodeGenerator::VisitBlock(Block* node) {
1002 Comment cmnt(masm_, "[ Block"); 1009 Comment cmnt(masm_, "[ Block");
1003 if (FLAG_debug_info) RecordStatementPosition(node); 1010 if (FLAG_debug_info) RecordStatementPosition(node);
1004 node->set_break_stack_height(break_stack_height_); 1011 node->set_break_stack_height(break_stack_height_);
1005 node->break_target()->set_code_generator(this); 1012 node->break_target()->set_code_generator(this);
1006 VisitStatements(node->statements()); 1013 VisitStatements(node->statements());
1007 node->break_target()->Bind(); 1014 if (node->break_target()->is_linked()) {
1015 node->break_target()->Bind();
1016 }
1008 } 1017 }
1009 1018
1010 1019
1011 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 1020 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
1012 __ mov(r0, Operand(pairs)); 1021 __ mov(r0, Operand(pairs));
1013 frame_->Push(r0); 1022 frame_->Push(r0);
1014 frame_->Push(cp); 1023 frame_->Push(cp);
1015 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); 1024 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
1016 frame_->Push(r0); 1025 frame_->Push(r0);
1017 __ CallRuntime(Runtime::kDeclareGlobals, 3); 1026 frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
1018 // The result is discarded. 1027 // The result is discarded.
1019 } 1028 }
1020 1029
1021 1030
1022 void CodeGenerator::VisitDeclaration(Declaration* node) { 1031 void CodeGenerator::VisitDeclaration(Declaration* node) {
1023 Comment cmnt(masm_, "[ Declaration"); 1032 Comment cmnt(masm_, "[ Declaration");
1024 Variable* var = node->proxy()->var(); 1033 Variable* var = node->proxy()->var();
1025 ASSERT(var != NULL); // must have been resolved 1034 ASSERT(var != NULL); // must have been resolved
1026 Slot* slot = var->slot(); 1035 Slot* slot = var->slot();
1027 1036
(...skipping 19 matching lines...) Expand all
1047 // must not destroy the current value. 1056 // must not destroy the current value.
1048 if (node->mode() == Variable::CONST) { 1057 if (node->mode() == Variable::CONST) {
1049 __ mov(r0, Operand(Factory::the_hole_value())); 1058 __ mov(r0, Operand(Factory::the_hole_value()));
1050 frame_->Push(r0); 1059 frame_->Push(r0);
1051 } else if (node->fun() != NULL) { 1060 } else if (node->fun() != NULL) {
1052 Load(node->fun()); 1061 Load(node->fun());
1053 } else { 1062 } else {
1054 __ mov(r0, Operand(0)); // no initial value! 1063 __ mov(r0, Operand(0)); // no initial value!
1055 frame_->Push(r0); 1064 frame_->Push(r0);
1056 } 1065 }
1057 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 1066 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
1058 // Ignore the return value (declarations are statements). 1067 // Ignore the return value (declarations are statements).
1059 return; 1068 return;
1060 } 1069 }
1061 1070
1062 ASSERT(!var->is_global()); 1071 ASSERT(!var->is_global());
1063 1072
1064 // If we have a function or a constant, we need to initialize the variable. 1073 // If we have a function or a constant, we need to initialize the variable.
1065 Expression* val = NULL; 1074 Expression* val = NULL;
1066 if (node->mode() == Variable::CONST) { 1075 if (node->mode() == Variable::CONST) {
1067 val = new Literal(Factory::the_hole_value()); 1076 val = new Literal(Factory::the_hole_value());
1068 } else { 1077 } else {
1069 val = node->fun(); // NULL if we don't have a function 1078 val = node->fun(); // NULL if we don't have a function
1070 } 1079 }
1071 1080
1072 if (val != NULL) { 1081 if (val != NULL) {
1073 // Set initial value. 1082 // Set initial value.
1074 Reference target(this, node->proxy()); 1083 Reference target(this, node->proxy());
1075 ASSERT(target.is_slot()); 1084 ASSERT(target.is_slot());
1076 Load(val); 1085 Load(val);
1077 target.SetValue(NOT_CONST_INIT); 1086 target.SetValue(NOT_CONST_INIT);
1078 // Get rid of the assigned value (declarations are statements). It's 1087 // Get rid of the assigned value (declarations are statements). It's
1079 // safe to pop the value lying on top of the reference before unloading 1088 // safe to pop the value lying on top of the reference before unloading
1080 // the reference itself (which preserves the top of stack) because we 1089 // the reference itself (which preserves the top of stack) because we
1081 // know it is a zero-sized reference. 1090 // know it is a zero-sized reference.
1082 frame_->Pop(); 1091 frame_->Drop();
1083 } 1092 }
1084 } 1093 }
1085 1094
1086 1095
1087 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { 1096 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
1088 Comment cmnt(masm_, "[ ExpressionStatement"); 1097 Comment cmnt(masm_, "[ ExpressionStatement");
1089 if (FLAG_debug_info) RecordStatementPosition(node); 1098 if (FLAG_debug_info) RecordStatementPosition(node);
1090 Expression* expression = node->expression(); 1099 Expression* expression = node->expression();
1091 expression->MarkAsStatement(); 1100 expression->MarkAsStatement();
1092 Load(expression); 1101 Load(expression);
1093 frame_->Pop(); 1102 frame_->Drop();
1094 } 1103 }
1095 1104
1096 1105
1097 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { 1106 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
1098 Comment cmnt(masm_, "// EmptyStatement"); 1107 Comment cmnt(masm_, "// EmptyStatement");
1099 // nothing to do 1108 // nothing to do
1100 } 1109 }
1101 1110
1102 1111
1103 void CodeGenerator::VisitIfStatement(IfStatement* node) { 1112 void CodeGenerator::VisitIfStatement(IfStatement* node) {
1104 Comment cmnt(masm_, "[ IfStatement"); 1113 Comment cmnt(masm_, "[ IfStatement");
1105 // Generate different code depending on which 1114 // Generate different code depending on which parts of the if statement
1106 // parts of the if statement are present or not. 1115 // are present or not.
1107 bool has_then_stm = node->HasThenStatement(); 1116 bool has_then_stm = node->HasThenStatement();
1108 bool has_else_stm = node->HasElseStatement(); 1117 bool has_else_stm = node->HasElseStatement();
1109 1118
1110 if (FLAG_debug_info) RecordStatementPosition(node); 1119 if (FLAG_debug_info) RecordStatementPosition(node);
1111 1120
1112 JumpTarget exit(this); 1121 JumpTarget exit(this);
1113 if (has_then_stm && has_else_stm) { 1122 if (has_then_stm && has_else_stm) {
1114 Comment cmnt(masm_, "[ IfThenElse"); 1123 Comment cmnt(masm_, "[ IfThenElse");
1115 JumpTarget then(this); 1124 JumpTarget then(this);
1116 JumpTarget else_(this); 1125 JumpTarget else_(this);
1117 // if (cond) 1126 // if (cond)
1118 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 1127 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
1119 Branch(false, &else_); 1128 if (frame_ != NULL) {
1129 Branch(false, &else_);
1130 }
1120 // then 1131 // then
1121 then.Bind(); 1132 if (frame_ != NULL || then.is_linked()) {
1122 Visit(node->then_statement()); 1133 then.Bind();
1123 exit.Jump(); 1134 Visit(node->then_statement());
1135 }
1136 if (frame_ != NULL) {
1137 exit.Jump();
1138 }
1124 // else 1139 // else
1125 else_.Bind(); 1140 if (else_.is_linked()) {
1126 Visit(node->else_statement()); 1141 else_.Bind();
1142 Visit(node->else_statement());
1143 }
1127 1144
1128 } else if (has_then_stm) { 1145 } else if (has_then_stm) {
1129 Comment cmnt(masm_, "[ IfThen"); 1146 Comment cmnt(masm_, "[ IfThen");
1130 ASSERT(!has_else_stm); 1147 ASSERT(!has_else_stm);
1131 JumpTarget then(this); 1148 JumpTarget then(this);
1132 // if (cond) 1149 // if (cond)
1133 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); 1150 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
1134 Branch(false, &exit); 1151 if (frame_ != NULL) {
1152 Branch(false, &exit);
1153 }
1135 // then 1154 // then
1136 then.Bind(); 1155 if (frame_ != NULL || then.is_linked()) {
1137 Visit(node->then_statement()); 1156 then.Bind();
1157 Visit(node->then_statement());
1158 }
1138 1159
1139 } else if (has_else_stm) { 1160 } else if (has_else_stm) {
1140 Comment cmnt(masm_, "[ IfElse"); 1161 Comment cmnt(masm_, "[ IfElse");
1141 ASSERT(!has_then_stm); 1162 ASSERT(!has_then_stm);
1142 JumpTarget else_(this); 1163 JumpTarget else_(this);
1143 // if (!cond) 1164 // if (!cond)
1144 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); 1165 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
1145 Branch(true, &exit); 1166 if (frame_ != NULL) {
1167 Branch(true, &exit);
1168 }
1146 // else 1169 // else
1147 else_.Bind(); 1170 if (frame_ != NULL || else_.is_linked()) {
1148 Visit(node->else_statement()); 1171 else_.Bind();
1172 Visit(node->else_statement());
1173 }
1149 1174
1150 } else { 1175 } else {
1151 Comment cmnt(masm_, "[ If"); 1176 Comment cmnt(masm_, "[ If");
1152 ASSERT(!has_then_stm && !has_else_stm); 1177 ASSERT(!has_then_stm && !has_else_stm);
1153 // if (cond) 1178 // if (cond)
1154 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); 1179 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
1155 if (has_cc()) { 1180 if (frame_ != NULL) {
1156 cc_reg_ = al; 1181 if (has_cc()) {
1157 } else { 1182 cc_reg_ = al;
1158 frame_->Pop(); 1183 } else {
1184 frame_->Drop();
1185 }
1159 } 1186 }
1160 } 1187 }
1161 1188
1162 // end 1189 // end
1163 exit.Bind(); 1190 if (exit.is_linked()) {
1191 exit.Bind();
1192 }
1164 } 1193 }
1165 1194
1166 1195
1167 void CodeGenerator::CleanStack(int num_bytes) { 1196 void CodeGenerator::CleanStack(int num_bytes) {
1168 ASSERT(num_bytes % kPointerSize == 0); 1197 ASSERT(num_bytes % kPointerSize == 0);
1169 frame_->Drop(num_bytes / kPointerSize); 1198 frame_->Drop(num_bytes / kPointerSize);
1170 } 1199 }
1171 1200
1172 1201
1173 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { 1202 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
(...skipping 20 matching lines...) Expand all
1194 frame_->Pop(r0); 1223 frame_->Pop(r0);
1195 1224
1196 function_return_.Jump(); 1225 function_return_.Jump();
1197 } 1226 }
1198 1227
1199 1228
1200 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { 1229 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
1201 Comment cmnt(masm_, "[ WithEnterStatement"); 1230 Comment cmnt(masm_, "[ WithEnterStatement");
1202 if (FLAG_debug_info) RecordStatementPosition(node); 1231 if (FLAG_debug_info) RecordStatementPosition(node);
1203 Load(node->expression()); 1232 Load(node->expression());
1204 __ CallRuntime(Runtime::kPushContext, 1); 1233 frame_->CallRuntime(Runtime::kPushContext, 1);
1205 if (kDebug) { 1234 if (kDebug) {
1206 Label verified_true; 1235 JumpTarget verified_true(this);
1207 __ cmp(r0, Operand(cp)); 1236 __ cmp(r0, Operand(cp));
1208 __ b(eq, &verified_true); 1237 verified_true.Branch(eq);
1209 __ stop("PushContext: r0 is expected to be the same as cp"); 1238 __ stop("PushContext: r0 is expected to be the same as cp");
1210 __ bind(&verified_true); 1239 verified_true.Bind();
1211 } 1240 }
1212 // Update context local. 1241 // Update context local.
1213 __ str(cp, frame_->Context()); 1242 __ str(cp, frame_->Context());
1214 } 1243 }
1215 1244
1216 1245
1217 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { 1246 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
1218 Comment cmnt(masm_, "[ WithExitStatement"); 1247 Comment cmnt(masm_, "[ WithExitStatement");
1219 // Pop context. 1248 // Pop context.
1220 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); 1249 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
(...skipping 17 matching lines...) Expand all
1238 int range, 1267 int range,
1239 JumpTarget* fail_label, 1268 JumpTarget* fail_label,
1240 Vector<JumpTarget*> case_targets, 1269 Vector<JumpTarget*> case_targets,
1241 Vector<JumpTarget> case_labels) { 1270 Vector<JumpTarget> case_labels) {
1242 1271
1243 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); 1272 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
1244 1273
1245 frame_->Pop(r0); 1274 frame_->Pop(r0);
1246 1275
1247 // Test for a Smi value in a HeapNumber. 1276 // Test for a Smi value in a HeapNumber.
1248 Label is_smi; 1277 JumpTarget is_smi(this);
1249 __ tst(r0, Operand(kSmiTagMask)); 1278 __ tst(r0, Operand(kSmiTagMask));
1250 __ b(eq, &is_smi); 1279 is_smi.Branch(eq);
1251 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag)); 1280 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
1252 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); 1281 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
1253 __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); 1282 __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
1254 fail_label->Branch(ne); 1283 fail_label->Branch(ne);
1255 frame_->Push(r0); 1284 frame_->Push(r0);
1256 __ CallRuntime(Runtime::kNumberToSmi, 1); 1285 frame_->CallRuntime(Runtime::kNumberToSmi, 1);
1257 __ bind(&is_smi); 1286 is_smi.Bind();
1258 1287
1259 if (min_index != 0) { 1288 if (min_index != 0) {
1260 // Small positive numbers can be immediate operands. 1289 // Small positive numbers can be immediate operands.
1261 if (min_index < 0) { 1290 if (min_index < 0) {
1262 // If min_index is Smi::kMinValue, -min_index is not a Smi. 1291 // If min_index is Smi::kMinValue, -min_index is not a Smi.
1263 if (Smi::IsValid(-min_index)) { 1292 if (Smi::IsValid(-min_index)) {
1264 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); 1293 __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
1265 } else { 1294 } else {
1266 __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1))); 1295 __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1)));
1267 __ add(r0, r0, Operand(Smi::FromInt(1))); 1296 __ add(r0, r0, Operand(Smi::FromInt(1)));
1268 } 1297 }
1269 } else { 1298 } else {
1270 __ sub(r0, r0, Operand(Smi::FromInt(min_index))); 1299 __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
1271 } 1300 }
1272 } 1301 }
1273 __ tst(r0, Operand(0x80000000 | kSmiTagMask)); 1302 __ tst(r0, Operand(0x80000000 | kSmiTagMask));
1274 fail_label->Branch(ne); 1303 fail_label->Branch(ne);
1275 __ cmp(r0, Operand(Smi::FromInt(range))); 1304 __ cmp(r0, Operand(Smi::FromInt(range)));
1276 fail_label->Branch(ge); 1305 fail_label->Branch(ge);
1277 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize)); 1306 __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize));
1278 // One extra instruction offsets the table, so the table's start address is 1307 // One extra instruction offsets the table, so the table's start address is
1279 // the pc-register at the above add. 1308 // the pc-register at the above add.
1280 __ stop("Unreachable: Switch table alignment"); 1309 __ stop("Unreachable: Switch table alignment");
1281 1310
1282 JumpTarget table_start(this); 1311 JumpTarget table_start(this);
1283 table_start.Bind(); 1312 table_start.Bind();
1284 // Table containing branch operations. 1313 // Table containing branch operations.
1285 for (int i = 0; i < range; i++) { 1314 for (int i = 0; i < range; i++) {
1286 case_targets[i]->Jump(); 1315 case_targets[i]->Jump();
1316 frame_ = new VirtualFrame(table_start.expected_frame());
1287 } 1317 }
1288 1318
1289 GenerateFastCaseSwitchCases(node, case_labels, &table_start); 1319 GenerateFastCaseSwitchCases(node, case_labels, &table_start);
1290 } 1320 }
1291 1321
1292 1322
1293 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { 1323 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
1294 Comment cmnt(masm_, "[ SwitchStatement"); 1324 Comment cmnt(masm_, "[ SwitchStatement");
1295 if (FLAG_debug_info) RecordStatementPosition(node); 1325 if (FLAG_debug_info) RecordStatementPosition(node);
1296 node->set_break_stack_height(break_stack_height_); 1326 node->set_break_stack_height(break_stack_height_);
1297 node->break_target()->set_code_generator(this); 1327 node->break_target()->set_code_generator(this);
1298 1328
1299 Load(node->tag()); 1329 Load(node->tag());
1300 1330
1301 if (TryGenerateFastCaseSwitchStatement(node)) { 1331 if (TryGenerateFastCaseSwitchStatement(node)) {
1302 return; 1332 return;
1303 } 1333 }
1304 1334
1305 JumpTarget next(this); 1335 JumpTarget next_test(this);
1306 Label fall_through, default_case; 1336 JumpTarget fall_through(this);
1337 JumpTarget default_entry(this);
1338 JumpTarget default_exit(this);
1307 ZoneList<CaseClause*>* cases = node->cases(); 1339 ZoneList<CaseClause*>* cases = node->cases();
1308 int length = cases->length(); 1340 int length = cases->length();
1341 CaseClause* default_clause = NULL;
1309 1342
1310 for (int i = 0; i < length; i++) { 1343 for (int i = 0; i < length; i++) {
1311 CaseClause* clause = cases->at(i); 1344 CaseClause* clause = cases->at(i);
1312
1313 Comment cmnt(masm_, "[ case clause");
1314
1315 if (clause->is_default()) { 1345 if (clause->is_default()) {
1316 // Continue matching cases. The program will execute the default case's 1346 // Remember the default clause and compile it at the end.
1317 // statements if it does not match any of the cases. 1347 default_clause = clause;
1318 next.Jump(); 1348 continue;
1319
1320 // Bind the default case label, so we can branch to it when we
1321 // have compared against all other cases.
1322 ASSERT(default_case.is_unused()); // at most one default clause
1323 __ bind(&default_case);
1324 } else {
1325 next.Bind();
1326 next.Unuse();
1327 __ ldr(r0, frame_->Top());
1328 frame_->Push(r0); // duplicate TOS
1329 Load(clause->label());
1330 Comparison(eq, true);
1331 Branch(false, &next);
1332 } 1349 }
1333 1350
1334 // Entering the case statement for the first time. Remove the switch value 1351 Comment cmnt(masm_, "[ Case clause");
1335 // from the stack. 1352 // Compile the test.
1336 frame_->Pop(); 1353 next_test.Bind();
1354 next_test.Unuse();
1355 // Duplicate TOS.
1356 __ ldr(r0, frame_->Top());
1357 frame_->Push(r0);
1358 Load(clause->label());
1359 Comparison(eq, true);
1360 Branch(false, &next_test);
1337 1361
1338 // Generate code for the body. 1362 // Before entering the body from the test, remove the switch value from
1339 // This is also the target for the fall through from the previous case's 1363 // the stack.
1340 // statements which has to skip over the matching code and the popping of 1364 frame_->Drop();
1341 // the switch value. 1365
1342 __ bind(&fall_through); 1366 // Label the body so that fall through is enabled.
1343 fall_through.Unuse(); 1367 if (i > 0 && cases->at(i - 1)->is_default()) {
1368 default_exit.Bind();
1369 } else {
1370 fall_through.Bind();
1371 fall_through.Unuse();
1372 }
1344 VisitStatements(clause->statements()); 1373 VisitStatements(clause->statements());
1345 __ b(&fall_through); 1374
1375 // If control flow can fall through from the body, jump to the next body
1376 // or the end of the statement.
1377 if (frame_ != NULL) {
1378 if (i < length - 1 && cases->at(i + 1)->is_default()) {
1379 default_entry.Jump();
1380 } else {
1381 fall_through.Jump();
1382 }
1383 }
1346 } 1384 }
1347 1385
1348 next.Bind(); 1386 // The final "test" removes the switch value.
1349 // Reached the end of the case statements without matching any of the cases. 1387 next_test.Bind();
1350 if (default_case.is_bound()) { 1388 frame_->Drop();
1351 // A default case exists -> execute its statements. 1389
1352 __ b(&default_case); 1390 // If there is a default clause, compile it.
1353 } else { 1391 if (default_clause != NULL) {
1354 // Remove the switch value from the stack. 1392 Comment cmnt(masm_, "[ Default clause");
1355 frame_->Pop(); 1393 default_entry.Bind();
1394 VisitStatements(default_clause->statements());
1395 // If control flow can fall out of the default and there is a case after
1396 // it, jup to that case's body.
1397 if (frame_ != NULL && default_exit.is_bound()) {
1398 default_exit.Jump();
1399 }
1356 } 1400 }
1357 1401
1358 __ bind(&fall_through); 1402 if (fall_through.is_linked()) {
1359 node->break_target()->Bind(); 1403 fall_through.Bind();
1404 }
1405
1406 if (node->break_target()->is_linked()) {
1407 node->break_target()->Bind();
1408 }
1360 } 1409 }
1361 1410
1362 1411
1363 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { 1412 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
1364 Comment cmnt(masm_, "[ LoopStatement"); 1413 Comment cmnt(masm_, "[ LoopStatement");
1365 if (FLAG_debug_info) RecordStatementPosition(node); 1414 if (FLAG_debug_info) RecordStatementPosition(node);
1366 node->set_break_stack_height(break_stack_height_); 1415 node->set_break_stack_height(break_stack_height_);
1367 node->break_target()->set_code_generator(this); 1416 node->break_target()->set_code_generator(this);
1368 node->continue_target()->set_code_generator(this); 1417 node->continue_target()->set_code_generator(this);
1369 1418
1370 // simple condition analysis 1419 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
1420 // known result for the test expression, with no side effects.
1371 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; 1421 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
1372 if (node->cond() == NULL) { 1422 if (node->cond() == NULL) {
1373 ASSERT(node->type() == LoopStatement::FOR_LOOP); 1423 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1374 info = ALWAYS_TRUE; 1424 info = ALWAYS_TRUE;
1375 } else { 1425 } else {
1376 Literal* lit = node->cond()->AsLiteral(); 1426 Literal* lit = node->cond()->AsLiteral();
1377 if (lit != NULL) { 1427 if (lit != NULL) {
1378 if (lit->IsTrue()) { 1428 if (lit->IsTrue()) {
1379 info = ALWAYS_TRUE; 1429 info = ALWAYS_TRUE;
1380 } else if (lit->IsFalse()) { 1430 } else if (lit->IsFalse()) {
1381 info = ALWAYS_FALSE; 1431 info = ALWAYS_FALSE;
1382 } 1432 }
1383 } 1433 }
1384 } 1434 }
1385 1435
1386 JumpTarget loop(this); 1436 switch (node->type()) {
1387 Label entry; 1437 case LoopStatement::DO_LOOP: {
1438 JumpTarget body(this);
1439 // Label the body.
1440 if (info == ALWAYS_TRUE) {
1441 node->continue_target()->Bind();
1442 } else if (info == ALWAYS_FALSE) {
1443 // There is no need, we will never jump back.
1444 } else {
1445 ASSERT(info == DONT_KNOW);
1446 body.Bind();
1447 }
1448 CheckStack(); // TODO(1222600): ignore if body contains calls.
1449 Visit(node->body());
1388 1450
1389 // init 1451 // Compile the "test".
1390 if (node->init() != NULL) { 1452 if (info == ALWAYS_TRUE) {
1391 ASSERT(node->type() == LoopStatement::FOR_LOOP); 1453 if (frame_ != NULL) {
1392 Visit(node->init()); 1454 // If control can fall off the end of the body, jump back to the
1393 } 1455 // top.
1394 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { 1456 node->continue_target()->Jump();
1395 __ b(&entry); 1457 }
1458 } else if (info == ALWAYS_FALSE) {
1459 // If we have a continue in the body, we only have to bind its jump
1460 // target.
1461 if (node->continue_target()->is_linked()) {
1462 node->continue_target()->Bind();
1463 }
1464 } else {
1465 ASSERT(info == DONT_KNOW);
1466 // We have to compile the test expression if it can be reached by
1467 // control flow falling out of the body or via continue.
1468 if (frame_ != NULL || node->continue_target()->is_linked()) {
1469 node->continue_target()->Bind();
1470 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1471 &body, node->break_target(), true);
1472 if (frame_ != NULL) {
1473 // A NULL frame here indicates that control did not fall out of
1474 // the test expression.
1475 Branch(true, &body);
1476 }
1477 }
1478 }
1479 break;
1480 }
1481
1482 case LoopStatement::WHILE_LOOP: {
1483 JumpTarget body(this);
1484 // Generate the loop header.
1485 if (info == ALWAYS_TRUE) {
1486 // Merely label the body with the continue target.
1487 node->continue_target()->Bind();
1488 } else if (info == ALWAYS_FALSE) {
1489 // There is no need to even compile the test or body.
1490 break;
1491 } else {
1492 // Compile the test labeled with the continue target and label the
1493 // body with the body target.
1494 ASSERT(info == DONT_KNOW);
1495 node->continue_target()->Bind();
1496 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1497 &body, node->break_target(), true);
1498 if (frame_ != NULL) {
1499 // A NULL frame indicates that control did not fall out of the
1500 // test expression.
1501 Branch(false, node->break_target());
1502 }
1503 if (frame_ != NULL || body.is_linked()) {
1504 body.Bind();
1505 }
1506 }
1507 if (frame_ != NULL) {
1508 CheckStack(); // TODO(1222600): ignore if body contains calls.
1509 Visit(node->body());
1510
1511 // If control flow can fall out of the body, jump back to the top.
1512 if (frame_ != NULL) {
1513 node->continue_target()->Jump();
1514 }
1515 }
1516 break;
1517 }
1518
1519 case LoopStatement::FOR_LOOP: {
1520 JumpTarget loop(this);
1521 JumpTarget body(this);
1522 if (node->init() != NULL) {
1523 Visit(node->init());
1524 }
1525
1526 // There is no need to compile the test or body.
1527 if (info == ALWAYS_FALSE) break;
1528
1529 // If there is no update statement, label the top of the loop with the
1530 // continue target, otherwise with the loop target.
1531 if (node->next() == NULL) {
1532 node->continue_target()->Bind();
1533 } else {
1534 loop.Bind();
1535 }
1536
1537 // If the test is always true, there is no need to compile it.
1538 if (info == DONT_KNOW) {
1539 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1540 &body, node->break_target(), true);
1541 if (frame_ != NULL) {
1542 Branch(false, node->break_target());
1543 }
1544 if (frame_ != NULL || body.is_linked()) {
1545 body.Bind();
1546 }
1547 }
1548
1549 if (frame_ != NULL) {
1550 CheckStack(); // TODO(1222600): ignore if body contains calls.
1551 Visit(node->body());
1552
1553 if (node->next() == NULL) {
1554 // If there is no update statement and control flow can fall out
1555 // of the loop, jump directly to the continue label.
1556 if (frame_ != NULL) {
1557 node->continue_target()->Jump();
1558 }
1559 } else {
1560 // If there is an update statement and control flow can reach it
1561 // via falling out of the body of the loop or continuing, we
1562 // compile the update statement.
1563 if (frame_ != NULL || node->continue_target()->is_linked()) {
1564 node->continue_target()->Bind();
1565 // Record source position of the statement as this code which is
1566 // after the code for the body actually belongs to the loop
1567 // statement and not the body.
1568 RecordStatementPosition(node);
1569 __ RecordPosition(node->statement_pos());
1570 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1571 Visit(node->next());
1572 loop.Jump();
1573 }
1574 }
1575 }
1576 break;
1577 }
1396 } 1578 }
1397 1579
1398 // body 1580 if (node->break_target()->is_linked()) {
1399 loop.Bind(); 1581 node->break_target()->Bind();
1400 Visit(node->body());
1401
1402 // next
1403 node->continue_target()->Bind();
1404 if (node->next() != NULL) {
1405 // Record source position of the statement as this code which is after the
1406 // code for the body actually belongs to the loop statement and not the
1407 // body.
1408 if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
1409 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1410 Visit(node->next());
1411 } 1582 }
1412
1413 // cond
1414 __ bind(&entry);
1415 switch (info) {
1416 case ALWAYS_TRUE:
1417 CheckStack(); // TODO(1222600): ignore if body contains calls.
1418 loop.Jump();
1419 break;
1420 case ALWAYS_FALSE:
1421 break;
1422 case DONT_KNOW:
1423 CheckStack(); // TODO(1222600): ignore if body contains calls.
1424 LoadCondition(node->cond(),
1425 NOT_INSIDE_TYPEOF,
1426 &loop,
1427 node->break_target(),
1428 true);
1429 Branch(true, &loop);
1430 break;
1431 }
1432
1433 // exit
1434 node->break_target()->Bind();
1435 } 1583 }
1436 1584
1437 1585
1438 void CodeGenerator::VisitForInStatement(ForInStatement* node) { 1586 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
1439 Comment cmnt(masm_, "[ ForInStatement"); 1587 Comment cmnt(masm_, "[ ForInStatement");
1440 if (FLAG_debug_info) RecordStatementPosition(node); 1588 if (FLAG_debug_info) RecordStatementPosition(node);
1441 1589
1442 // We keep stuff on the stack while the body is executing. 1590 // We keep stuff on the stack while the body is executing.
1443 // Record it, so that a break/continue crossing this statement 1591 // Record it, so that a break/continue crossing this statement
1444 // can restore the stack. 1592 // can restore the stack.
1445 const int kForInStackSize = 5 * kPointerSize; 1593 const int kForInStackSize = 5 * kPointerSize;
1446 break_stack_height_ += kForInStackSize; 1594 break_stack_height_ += kForInStackSize;
1447 node->set_break_stack_height(break_stack_height_); 1595 node->set_break_stack_height(break_stack_height_);
1448 node->break_target()->set_code_generator(this); 1596 node->break_target()->set_code_generator(this);
1449 node->continue_target()->set_code_generator(this); 1597 node->continue_target()->set_code_generator(this);
1450 1598
1451 Label loop, next, entry, cleanup, exit, primitive, jsobject; 1599 JumpTarget primitive(this);
1452 Label filter_key, end_del_check, fixed_array, non_string; 1600 JumpTarget jsobject(this);
1601 JumpTarget fixed_array(this);
1602 JumpTarget entry(this);
1603 JumpTarget end_del_check(this);
1604 JumpTarget cleanup(this);
1605 JumpTarget exit(this);
1453 1606
1454 // Get the object to enumerate over (converted to JSObject). 1607 // Get the object to enumerate over (converted to JSObject).
1455 Load(node->enumerable()); 1608 Load(node->enumerable());
1456 frame_->Pop(r0);
1457 1609
1458 // Both SpiderMonkey and kjs ignore null and undefined in contrast 1610 // Both SpiderMonkey and kjs ignore null and undefined in contrast
1459 // to the specification. 12.6.4 mandates a call to ToObject. 1611 // to the specification. 12.6.4 mandates a call to ToObject.
1612 frame_->Pop(r0);
1460 __ cmp(r0, Operand(Factory::undefined_value())); 1613 __ cmp(r0, Operand(Factory::undefined_value()));
1461 __ b(eq, &exit); 1614 exit.Branch(eq);
1462 __ cmp(r0, Operand(Factory::null_value())); 1615 __ cmp(r0, Operand(Factory::null_value()));
1463 __ b(eq, &exit); 1616 exit.Branch(eq);
1464 1617
1465 // Stack layout in body: 1618 // Stack layout in body:
1466 // [iteration counter (Smi)] 1619 // [iteration counter (Smi)]
1467 // [length of array] 1620 // [length of array]
1468 // [FixedArray] 1621 // [FixedArray]
1469 // [Map or 0] 1622 // [Map or 0]
1470 // [Object] 1623 // [Object]
1471 1624
1472 // Check if enumerable is already a JSObject 1625 // Check if enumerable is already a JSObject
1473 __ tst(r0, Operand(kSmiTagMask)); 1626 __ tst(r0, Operand(kSmiTagMask));
1474 __ b(eq, &primitive); 1627 primitive.Branch(eq);
1475 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 1628 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
1476 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); 1629 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
1477 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); 1630 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
1478 __ b(hs, &jsobject); 1631 jsobject.Branch(hs);
1479 1632
1480 __ bind(&primitive); 1633 primitive.Bind();
1481 frame_->Push(r0); 1634 frame_->Push(r0);
1482 __ mov(r0, Operand(0)); 1635 __ mov(r0, Operand(0));
1483 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 1636 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS, 1);
1484 1637
1485 1638
1486 __ bind(&jsobject); 1639 jsobject.Bind();
1487 1640
1488 // Get the set of properties (as a FixedArray or Map). 1641 // Get the set of properties (as a FixedArray or Map).
1489 frame_->Push(r0); // duplicate the object being enumerated 1642 frame_->Push(r0); // duplicate the object being enumerated
1490 frame_->Push(r0); 1643 frame_->Push(r0);
1491 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 1644 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1492 1645
1493 // If we got a Map, we can do a fast modification check. 1646 // If we got a Map, we can do a fast modification check.
1494 // Otherwise, we got a FixedArray, and we have to do a slow check. 1647 // Otherwise, we got a FixedArray, and we have to do a slow check.
1495 __ mov(r2, Operand(r0)); 1648 __ mov(r2, Operand(r0));
1496 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 1649 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
1497 __ cmp(r1, Operand(Factory::meta_map())); 1650 __ cmp(r1, Operand(Factory::meta_map()));
1498 __ b(ne, &fixed_array); 1651 fixed_array.Branch(ne);
1499 1652
1500 // Get enum cache 1653 // Get enum cache
1501 __ mov(r1, Operand(r0)); 1654 __ mov(r1, Operand(r0));
1502 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset)); 1655 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
1503 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); 1656 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
1504 __ ldr(r2, 1657 __ ldr(r2,
1505 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1658 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
1506 1659
1507 frame_->Push(r0); // map 1660 frame_->Push(r0); // map
1508 frame_->Push(r2); // enum cache bridge cache 1661 frame_->Push(r2); // enum cache bridge cache
1509 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset)); 1662 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
1510 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 1663 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1511 frame_->Push(r0); 1664 frame_->Push(r0);
1512 __ mov(r0, Operand(Smi::FromInt(0))); 1665 __ mov(r0, Operand(Smi::FromInt(0)));
1513 frame_->Push(r0); 1666 frame_->Push(r0);
1514 __ b(&entry); 1667 entry.Jump();
1515 1668
1516 1669
1517 __ bind(&fixed_array); 1670 fixed_array.Bind();
1518 1671
1519 __ mov(r1, Operand(Smi::FromInt(0))); 1672 __ mov(r1, Operand(Smi::FromInt(0)));
1520 frame_->Push(r1); // insert 0 in place of Map 1673 frame_->Push(r1); // insert 0 in place of Map
1521 frame_->Push(r0); 1674 frame_->Push(r0);
1522 1675
1523 // Push the length of the array and the initial index onto the stack. 1676 // Push the length of the array and the initial index onto the stack.
1524 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset)); 1677 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
1525 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); 1678 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
1526 frame_->Push(r0); 1679 frame_->Push(r0);
1527 __ mov(r0, Operand(Smi::FromInt(0))); // init index 1680 __ mov(r0, Operand(Smi::FromInt(0))); // init index
1528 frame_->Push(r0); 1681 frame_->Push(r0);
1529 1682
1530 __ b(&entry);
1531
1532 // Body.
1533 __ bind(&loop);
1534 Visit(node->body());
1535
1536 // Next.
1537 node->continue_target()->Bind();
1538 __ bind(&next);
1539 frame_->Pop(r0);
1540 __ add(r0, r0, Operand(Smi::FromInt(1)));
1541 frame_->Push(r0);
1542
1543 // Condition. 1683 // Condition.
1544 __ bind(&entry); 1684 entry.Bind();
1545 1685
1546 // sp[0] : index 1686 // sp[0] : index
1547 // sp[1] : array/enum cache length 1687 // sp[1] : array/enum cache length
1548 // sp[2] : array or enum cache 1688 // sp[2] : array or enum cache
1549 // sp[3] : 0 or map 1689 // sp[3] : 0 or map
1550 // sp[4] : enumerable 1690 // sp[4] : enumerable
1551 __ ldr(r0, frame_->Element(0)); // load the current count 1691 __ ldr(r0, frame_->ElementAt(0)); // load the current count
1552 __ ldr(r1, frame_->Element(1)); // load the length 1692 __ ldr(r1, frame_->ElementAt(1)); // load the length
1553 __ cmp(r0, Operand(r1)); // compare to the array length 1693 __ cmp(r0, Operand(r1)); // compare to the array length
1554 __ b(hs, &cleanup); 1694 cleanup.Branch(hs);
1555 1695
1556 __ ldr(r0, frame_->Element(0)); 1696 __ ldr(r0, frame_->ElementAt(0));
1557 1697
1558 // Get the i'th entry of the array. 1698 // Get the i'th entry of the array.
1559 __ ldr(r2, frame_->Element(2)); 1699 __ ldr(r2, frame_->ElementAt(2));
1560 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); 1700 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1561 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); 1701 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1562 1702
1563 // Get Map or 0. 1703 // Get Map or 0.
1564 __ ldr(r2, frame_->Element(3)); 1704 __ ldr(r2, frame_->ElementAt(3));
1565 // Check if this (still) matches the map of the enumerable. 1705 // Check if this (still) matches the map of the enumerable.
1566 // If not, we have to filter the key. 1706 // If not, we have to filter the key.
1567 __ ldr(r1, frame_->Element(4)); 1707 __ ldr(r1, frame_->ElementAt(4));
1568 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); 1708 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
1569 __ cmp(r1, Operand(r2)); 1709 __ cmp(r1, Operand(r2));
1570 __ b(eq, &end_del_check); 1710 end_del_check.Branch(eq);
1571 1711
1572 // Convert the entry to a string (or null if it isn't a property anymore). 1712 // Convert the entry to a string (or null if it isn't a property anymore).
1573 __ ldr(r0, frame_->Element(4)); // push enumerable 1713 __ ldr(r0, frame_->ElementAt(4)); // push enumerable
1574 frame_->Push(r0); 1714 frame_->Push(r0);
1575 frame_->Push(r3); // push entry 1715 frame_->Push(r3); // push entry
1576 __ mov(r0, Operand(1)); 1716 __ mov(r0, Operand(1));
1577 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); 1717 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS, 2);
1578 __ mov(r3, Operand(r0)); 1718 __ mov(r3, Operand(r0));
1579 1719
1580 // If the property has been removed while iterating, we just skip it. 1720 // If the property has been removed while iterating, we just skip it.
1581 __ cmp(r3, Operand(Factory::null_value())); 1721 __ cmp(r3, Operand(Factory::null_value()));
1582 __ b(eq, &next); 1722 node->continue_target()->Branch(eq);
1583 1723
1584 1724 end_del_check.Bind();
1585 __ bind(&end_del_check); 1725 // Store the entry in the 'each' expression and take another spin in the
1586 1726 // loop. r3: i'th entry of the enum cache (or string there of)
1587 // Store the entry in the 'each' expression and take another spin in the loop.
1588 // r3: i'th entry of the enum cache (or string there of)
1589 frame_->Push(r3); // push entry 1727 frame_->Push(r3); // push entry
1590 { Reference each(this, node->each()); 1728 { Reference each(this, node->each());
1591 if (!each.is_illegal()) { 1729 if (!each.is_illegal()) {
1592 if (each.size() > 0) { 1730 if (each.size() > 0) {
1593 __ ldr(r0, frame_->Element(each.size())); 1731 __ ldr(r0, frame_->ElementAt(each.size()));
1594 frame_->Push(r0); 1732 frame_->Push(r0);
1595 } 1733 }
1596 // If the reference was to a slot we rely on the convenient property 1734 // If the reference was to a slot we rely on the convenient property
1597 // that it doesn't matter whether a value (eg, r3 pushed above) is 1735 // that it doesn't matter whether a value (eg, r3 pushed above) is
1598 // right on top of or right underneath a zero-sized reference. 1736 // right on top of or right underneath a zero-sized reference.
1599 each.SetValue(NOT_CONST_INIT); 1737 each.SetValue(NOT_CONST_INIT);
1600 if (each.size() > 0) { 1738 if (each.size() > 0) {
1601 // It's safe to pop the value lying on top of the reference before 1739 // It's safe to pop the value lying on top of the reference before
1602 // unloading the reference itself (which preserves the top of stack, 1740 // unloading the reference itself (which preserves the top of stack,
1603 // ie, now the topmost value of the non-zero sized reference), since 1741 // ie, now the topmost value of the non-zero sized reference), since
1604 // we will discard the top of stack after unloading the reference 1742 // we will discard the top of stack after unloading the reference
1605 // anyway. 1743 // anyway.
1606 frame_->Pop(r0); 1744 frame_->Pop(r0);
1607 } 1745 }
1608 } 1746 }
1609 } 1747 }
1610 // Discard the i'th entry pushed above or else the remainder of the 1748 // Discard the i'th entry pushed above or else the remainder of the
1611 // reference, whichever is currently on top of the stack. 1749 // reference, whichever is currently on top of the stack.
1612 frame_->Pop(); 1750 frame_->Drop();
1751
1752 // Body.
1613 CheckStack(); // TODO(1222600): ignore if body contains calls. 1753 CheckStack(); // TODO(1222600): ignore if body contains calls.
1614 __ jmp(&loop); 1754 Visit(node->body());
1755
1756 // Next.
1757 node->continue_target()->Bind();
1758 frame_->Pop(r0);
1759 __ add(r0, r0, Operand(Smi::FromInt(1)));
1760 frame_->Push(r0);
1761 entry.Jump();
1615 1762
1616 // Cleanup. 1763 // Cleanup.
1617 __ bind(&cleanup); 1764 cleanup.Bind();
1618 node->break_target()->Bind(); 1765 node->break_target()->Bind();
1619 frame_->Drop(5); 1766 frame_->Drop(5);
1620 1767
1621 // Exit. 1768 // Exit.
1622 __ bind(&exit); 1769 exit.Bind();
1623 1770
1624 break_stack_height_ -= kForInStackSize; 1771 break_stack_height_ -= kForInStackSize;
1625 } 1772 }
1626 1773
1627 1774
1628 void CodeGenerator::VisitTryCatch(TryCatch* node) { 1775 void CodeGenerator::VisitTryCatch(TryCatch* node) {
1629 Comment cmnt(masm_, "[ TryCatch"); 1776 Comment cmnt(masm_, "[ TryCatch");
1630 1777
1631 Label try_block, exit; 1778 JumpTarget try_block(this);
1779 JumpTarget exit(this);
1632 1780
1633 __ bl(&try_block); 1781 try_block.Call();
1634 // --- Catch block --- 1782 // --- Catch block ---
1635 frame_->Push(r0); 1783 frame_->Push(r0);
1636 1784
1637 // Store the caught exception in the catch variable. 1785 // Store the caught exception in the catch variable.
1638 { Reference ref(this, node->catch_var()); 1786 { Reference ref(this, node->catch_var());
1639 ASSERT(ref.is_slot()); 1787 ASSERT(ref.is_slot());
1640 // Here we make use of the convenient property that it doesn't matter 1788 // Here we make use of the convenient property that it doesn't matter
1641 // whether a value is immediately on top of or underneath a zero-sized 1789 // whether a value is immediately on top of or underneath a zero-sized
1642 // reference. 1790 // reference.
1643 ref.SetValue(NOT_CONST_INIT); 1791 ref.SetValue(NOT_CONST_INIT);
1644 } 1792 }
1645 1793
1646 // Remove the exception from the stack. 1794 // Remove the exception from the stack.
1647 frame_->Pop(); 1795 frame_->Drop();
1648 1796
1649 VisitStatements(node->catch_block()->statements()); 1797 VisitStatements(node->catch_block()->statements());
1650 __ b(&exit); 1798 if (frame_ != NULL) {
1799 exit.Jump();
1800 }
1651 1801
1652 1802
1653 // --- Try block --- 1803 // --- Try block ---
1654 __ bind(&try_block); 1804 try_block.Bind();
1655 1805
1656 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); 1806 frame_->PushTryHandler(TRY_CATCH_HANDLER);
1807 int handler_height = frame_->height();
1657 1808
1658 // Shadow the labels for all escapes from the try block, including 1809 // Shadow the labels for all escapes from the try block, including
1659 // returns. During shadowing, the original label is hidden as the 1810 // returns. During shadowing, the original label is hidden as the
1660 // LabelShadow and operations on the original actually affect the 1811 // LabelShadow and operations on the original actually affect the
1661 // shadowing label. 1812 // shadowing label.
1662 // 1813 //
1663 // We should probably try to unify the escaping labels and the return 1814 // We should probably try to unify the escaping labels and the return
1664 // label. 1815 // label.
1665 int nof_escapes = node->escaping_targets()->length(); 1816 int nof_escapes = node->escaping_targets()->length();
1666 List<ShadowTarget*> shadows(1 + nof_escapes); 1817 List<ShadowTarget*> shadows(1 + nof_escapes);
1667 shadows.Add(new ShadowTarget(&function_return_)); 1818 shadows.Add(new ShadowTarget(&function_return_));
1668 for (int i = 0; i < nof_escapes; i++) { 1819 for (int i = 0; i < nof_escapes; i++) {
1669 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 1820 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
1670 } 1821 }
1671 1822
1672 // Generate code for the statements in the try block. 1823 // Generate code for the statements in the try block.
1673 VisitStatements(node->try_block()->statements()); 1824 VisitStatements(node->try_block()->statements());
1674 frame_->Pop(); // Discard the result. 1825 if (frame_ != NULL) {
1826 frame_->Drop(); // Discard the result.
1827 }
1675 1828
1676 // Stop the introduced shadowing and count the number of required unlinks. 1829 // Stop the introduced shadowing and count the number of required unlinks.
1677 // After shadowing stops, the original labels are unshadowed and the 1830 // After shadowing stops, the original labels are unshadowed and the
1678 // LabelShadows represent the formerly shadowing labels. 1831 // LabelShadows represent the formerly shadowing labels.
1679 int nof_unlinks = 0; 1832 int nof_unlinks = 0;
1680 for (int i = 0; i <= nof_escapes; i++) { 1833 for (int i = 0; i <= nof_escapes; i++) {
1681 shadows[i]->StopShadowing(); 1834 shadows[i]->StopShadowing();
1682 if (shadows[i]->is_linked()) nof_unlinks++; 1835 if (shadows[i]->is_linked()) nof_unlinks++;
1683 } 1836 }
1684 1837
1685 // Unlink from try chain.
1686 // TOS contains code slot
1687 const int kNextIndex = (StackHandlerConstants::kNextOffset 1838 const int kNextIndex = (StackHandlerConstants::kNextOffset
1688 + StackHandlerConstants::kAddressDisplacement) 1839 + StackHandlerConstants::kAddressDisplacement)
1689 / kPointerSize; 1840 / kPointerSize;
1690 __ ldr(r1, frame_->Element(kNextIndex)); // read next_sp 1841 // If we can fall off the end of the try block, unlink from try chain.
1691 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); 1842 if (frame_ != NULL) {
1692 __ str(r1, MemOperand(r3)); 1843 __ ldr(r1, frame_->ElementAt(kNextIndex)); // read next_sp
1693 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code 1844 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1694 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 1845 __ str(r1, MemOperand(r3));
1695 // Code slot popped. 1846 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1696 if (nof_unlinks > 0) __ b(&exit); 1847 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
1848 // Code slot popped.
1849 if (nof_unlinks > 0) {
1850 exit.Jump();
1851 }
1852 }
1697 1853
1698 // Generate unlink code for the (formerly) shadowing labels that have been 1854 // Generate unlink code for the (formerly) shadowing labels that have been
1699 // jumped to. 1855 // jumped to.
1700 for (int i = 0; i <= nof_escapes; i++) { 1856 for (int i = 0; i <= nof_escapes; i++) {
1701 if (shadows[i]->is_linked()) { 1857 if (shadows[i]->is_linked()) {
1702 // Unlink from try chain; 1858 // Unlink from try chain;
1703 shadows[i]->Bind(); 1859 shadows[i]->Bind();
1704 1860
1705 // Reload sp from the top handler, because some statements that we 1861 // Reload sp from the top handler, because some statements that we
1706 // break from (eg, for...in) may have left stuff on the stack. 1862 // break from (eg, for...in) may have left stuff on the stack.
1707 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); 1863 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1708 __ ldr(sp, MemOperand(r3)); 1864 __ ldr(sp, MemOperand(r3));
1865 frame_->Forget(frame_->height() - handler_height);
1709 1866
1710 __ ldr(r1, frame_->Element(kNextIndex)); 1867 __ ldr(r1, frame_->ElementAt(kNextIndex));
1711 __ str(r1, MemOperand(r3)); 1868 __ str(r1, MemOperand(r3));
1712 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code 1869 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1713 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 1870 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
1714 // Code slot popped. 1871 // Code slot popped.
1715 1872 frame_->Forget(1);
1716 shadows[i]->original_target()->Jump(); 1873 shadows[i]->original_target()->Jump();
1717 } 1874 }
1718 } 1875 }
1719 1876
1720 __ bind(&exit); 1877 exit.Bind();
1721 } 1878 }
1722 1879
1723 1880
1724 void CodeGenerator::VisitTryFinally(TryFinally* node) { 1881 void CodeGenerator::VisitTryFinally(TryFinally* node) {
1725 Comment cmnt(masm_, "[ TryFinally"); 1882 Comment cmnt(masm_, "[ TryFinally");
1726 1883
1727 // State: Used to keep track of reason for entering the finally 1884 // State: Used to keep track of reason for entering the finally
1728 // block. Should probably be extended to hold information for 1885 // block. Should probably be extended to hold information for
1729 // break/continue from within the try block. 1886 // break/continue from within the try block.
1730 enum { FALLING, THROWING, JUMPING }; 1887 enum { FALLING, THROWING, JUMPING };
1731 1888
1732 Label exit, unlink, try_block, finally_block; 1889 JumpTarget unlink(this);
1890 JumpTarget try_block(this);
1891 JumpTarget finally_block(this);
1733 1892
1734 __ bl(&try_block); 1893 try_block.Call();
1735 1894
1736 frame_->Push(r0); // save exception object on the stack 1895 frame_->Push(r0); // save exception object on the stack
1737 // In case of thrown exceptions, this is where we continue. 1896 // In case of thrown exceptions, this is where we continue.
1738 __ mov(r2, Operand(Smi::FromInt(THROWING))); 1897 __ mov(r2, Operand(Smi::FromInt(THROWING)));
1739 __ b(&finally_block); 1898 finally_block.Jump();
1740 1899
1741 1900
1742 // --- Try block --- 1901 // --- Try block ---
1743 __ bind(&try_block); 1902 try_block.Bind();
1744 1903
1745 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); 1904 frame_->PushTryHandler(TRY_FINALLY_HANDLER);
1905 int handler_height = frame_->height();
1746 1906
1747 // Shadow the labels for all escapes from the try block, including 1907 // Shadow the labels for all escapes from the try block, including
1748 // returns. Shadowing hides the original label as the LabelShadow and 1908 // returns. Shadowing hides the original label as the LabelShadow and
1749 // operations on the original actually affect the shadowing label. 1909 // operations on the original actually affect the shadowing label.
1750 // 1910 //
1751 // We should probably try to unify the escaping labels and the return 1911 // We should probably try to unify the escaping labels and the return
1752 // label. 1912 // label.
1753 int nof_escapes = node->escaping_targets()->length(); 1913 int nof_escapes = node->escaping_targets()->length();
1754 List<ShadowTarget*> shadows(1 + nof_escapes); 1914 List<ShadowTarget*> shadows(1 + nof_escapes);
1755 shadows.Add(new ShadowTarget(&function_return_)); 1915 shadows.Add(new ShadowTarget(&function_return_));
1756 for (int i = 0; i < nof_escapes; i++) { 1916 for (int i = 0; i < nof_escapes; i++) {
1757 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); 1917 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
1758 } 1918 }
1759 1919
1760 // Generate code for the statements in the try block. 1920 // Generate code for the statements in the try block.
1761 VisitStatements(node->try_block()->statements()); 1921 VisitStatements(node->try_block()->statements());
1762 1922
1763 // Stop the introduced shadowing and count the number of required unlinks. 1923 // Stop the introduced shadowing and count the number of required unlinks.
1764 // After shadowing stops, the original labels are unshadowed and the 1924 // After shadowing stops, the original labels are unshadowed and the
1765 // LabelShadows represent the formerly shadowing labels. 1925 // LabelShadows represent the formerly shadowing labels.
1766 int nof_unlinks = 0; 1926 int nof_unlinks = 0;
1767 for (int i = 0; i <= nof_escapes; i++) { 1927 for (int i = 0; i <= nof_escapes; i++) {
1768 shadows[i]->StopShadowing(); 1928 shadows[i]->StopShadowing();
1769 if (shadows[i]->is_linked()) nof_unlinks++; 1929 if (shadows[i]->is_linked()) nof_unlinks++;
1770 } 1930 }
1771 1931
1772 // Set the state on the stack to FALLING. 1932 // If we can fall off the end of the try block, set the state on the stack
1773 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS 1933 // to FALLING.
1774 frame_->Push(r0); 1934 if (frame_ != NULL) {
1775 __ mov(r2, Operand(Smi::FromInt(FALLING))); 1935 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS
1776 if (nof_unlinks > 0) __ b(&unlink); 1936 frame_->Push(r0);
1937 __ mov(r2, Operand(Smi::FromInt(FALLING)));
1938 if (nof_unlinks > 0) {
1939 unlink.Jump();
1940 }
1941 }
1777 1942
1778 // Generate code to set the state for the (formerly) shadowing labels that 1943 // Generate code to set the state for the (formerly) shadowing labels that
1779 // have been jumped to. 1944 // have been jumped to.
1780 for (int i = 0; i <= nof_escapes; i++) { 1945 for (int i = 0; i <= nof_escapes; i++) {
1781 if (shadows[i]->is_linked()) { 1946 if (shadows[i]->is_linked()) {
1782 shadows[i]->Bind(); 1947 shadows[i]->Bind();
1783 if (shadows[i]->original_target() == &function_return_) { 1948 if (shadows[i]->original_target() == &function_return_) {
1784 // If this label shadowed the function return, materialize the 1949 // If this label shadowed the function return, materialize the
1785 // return value on the stack. 1950 // return value on the stack.
1786 frame_->Push(r0); 1951 frame_->Push(r0);
1787 } else { 1952 } else {
1788 // Fake TOS for labels that shadowed breaks and continues. 1953 // Fake TOS for labels that shadowed breaks and continues.
1789 __ mov(r0, Operand(Factory::undefined_value())); 1954 __ mov(r0, Operand(Factory::undefined_value()));
1790 frame_->Push(r0); 1955 frame_->Push(r0);
1791 } 1956 }
1792 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); 1957 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
1793 __ b(&unlink); 1958 unlink.Jump();
1794 } 1959 }
1795 } 1960 }
1796 1961
1797 // Unlink from try chain; 1962 // Unlink from try chain;
1798 __ bind(&unlink); 1963 unlink.Bind();
1799 1964
1800 frame_->Pop(r0); // Store TOS in r0 across stack manipulation 1965 frame_->Pop(r0); // Store TOS in r0 across stack manipulation
1801 // Reload sp from the top handler, because some statements that we 1966 // Reload sp from the top handler, because some statements that we
1802 // break from (eg, for...in) may have left stuff on the stack. 1967 // break from (eg, for...in) may have left stuff on the stack.
1803 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); 1968 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
1804 __ ldr(sp, MemOperand(r3)); 1969 __ ldr(sp, MemOperand(r3));
1970 frame_->Forget(frame_->height() - handler_height);
1805 const int kNextIndex = (StackHandlerConstants::kNextOffset 1971 const int kNextIndex = (StackHandlerConstants::kNextOffset
1806 + StackHandlerConstants::kAddressDisplacement) 1972 + StackHandlerConstants::kAddressDisplacement)
1807 / kPointerSize; 1973 / kPointerSize;
1808 __ ldr(r1, frame_->Element(kNextIndex)); 1974 __ ldr(r1, frame_->ElementAt(kNextIndex));
1809 __ str(r1, MemOperand(r3)); 1975 __ str(r1, MemOperand(r3));
1810 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code 1976 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code
1811 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 1977 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
1812 // Code slot popped. 1978 // Code slot popped.
1979 frame_->Forget(1);
1813 frame_->Push(r0); 1980 frame_->Push(r0);
1814 1981
1815 // --- Finally block --- 1982 // --- Finally block ---
1816 __ bind(&finally_block); 1983 finally_block.Bind();
1817 1984
1818 // Push the state on the stack. 1985 // Push the state on the stack.
1819 frame_->Push(r2); 1986 frame_->Push(r2);
1820 1987
1821 // We keep two elements on the stack - the (possibly faked) result 1988 // We keep two elements on the stack - the (possibly faked) result
1822 // and the state - while evaluating the finally block. Record it, so 1989 // and the state - while evaluating the finally block. Record it, so
1823 // that a break/continue crossing this statement can restore the 1990 // that a break/continue crossing this statement can restore the
1824 // stack. 1991 // stack.
1825 const int kFinallyStackSize = 2 * kPointerSize; 1992 const int kFinallyStackSize = 2 * kPointerSize;
1826 break_stack_height_ += kFinallyStackSize; 1993 break_stack_height_ += kFinallyStackSize;
1827 1994
1828 // Generate code for the statements in the finally block. 1995 // Generate code for the statements in the finally block.
1829 VisitStatements(node->finally_block()->statements()); 1996 VisitStatements(node->finally_block()->statements());
1830 1997
1831 // Restore state and return value or faked TOS.
1832 frame_->Pop(r2);
1833 frame_->Pop(r0);
1834 break_stack_height_ -= kFinallyStackSize; 1998 break_stack_height_ -= kFinallyStackSize;
1999 if (frame_ != NULL) {
2000 JumpTarget exit(this);
2001 // Restore state and return value or faked TOS.
2002 frame_->Pop(r2);
2003 frame_->Pop(r0);
1835 2004
1836 // Generate code to jump to the right destination for all used (formerly) 2005 // Generate code to jump to the right destination for all used (formerly)
1837 // shadowing labels. 2006 // shadowing labels.
1838 for (int i = 0; i <= nof_escapes; i++) { 2007 for (int i = 0; i <= nof_escapes; i++) {
1839 if (shadows[i]->is_bound()) { 2008 if (shadows[i]->is_bound()) {
1840 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); 2009 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
1841 if (shadows[i]->original_target() != &function_return_) { 2010 if (shadows[i]->original_target() != &function_return_) {
1842 Label next; 2011 JumpTarget next(this);
1843 __ b(ne, &next); 2012 next.Branch(ne);
1844 shadows[i]->original_target()->Jump(); 2013 shadows[i]->original_target()->Jump();
1845 __ bind(&next); 2014 next.Bind();
1846 } else { 2015 } else {
1847 shadows[i]->original_target()->Branch(eq); 2016 shadows[i]->original_target()->Branch(eq);
2017 }
1848 } 2018 }
1849 } 2019 }
2020
2021 // Check if we need to rethrow the exception.
2022 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
2023 exit.Branch(ne);
2024
2025 // Rethrow exception.
2026 frame_->Push(r0);
2027 frame_->CallRuntime(Runtime::kReThrow, 1);
2028
2029 // Done.
2030 exit.Bind();
1850 } 2031 }
1851
1852 // Check if we need to rethrow the exception.
1853 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
1854 __ b(ne, &exit);
1855
1856 // Rethrow exception.
1857 frame_->Push(r0);
1858 __ CallRuntime(Runtime::kReThrow, 1);
1859
1860 // Done.
1861 __ bind(&exit);
1862 } 2032 }
1863 2033
1864 2034
1865 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { 2035 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
1866 Comment cmnt(masm_, "[ DebuggerStatament"); 2036 Comment cmnt(masm_, "[ DebuggerStatament");
1867 if (FLAG_debug_info) RecordStatementPosition(node); 2037 if (FLAG_debug_info) RecordStatementPosition(node);
1868 __ CallRuntime(Runtime::kDebugBreak, 0); 2038 frame_->CallRuntime(Runtime::kDebugBreak, 0);
1869 // Ignore the return value. 2039 // Ignore the return value.
1870 } 2040 }
1871 2041
1872 2042
1873 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { 2043 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
1874 ASSERT(boilerplate->IsBoilerplate()); 2044 ASSERT(boilerplate->IsBoilerplate());
1875 2045
1876 // Push the boilerplate on the stack. 2046 // Push the boilerplate on the stack.
1877 __ mov(r0, Operand(boilerplate)); 2047 __ mov(r0, Operand(boilerplate));
1878 frame_->Push(r0); 2048 frame_->Push(r0);
1879 2049
1880 // Create a new closure. 2050 // Create a new closure.
1881 frame_->Push(cp); 2051 frame_->Push(cp);
1882 __ CallRuntime(Runtime::kNewClosure, 2); 2052 frame_->CallRuntime(Runtime::kNewClosure, 2);
1883 frame_->Push(r0); 2053 frame_->Push(r0);
1884 } 2054 }
1885 2055
1886 2056
1887 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { 2057 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
1888 Comment cmnt(masm_, "[ FunctionLiteral"); 2058 Comment cmnt(masm_, "[ FunctionLiteral");
1889 2059
1890 // Build the function boilerplate and instantiate it. 2060 // Build the function boilerplate and instantiate it.
1891 Handle<JSFunction> boilerplate = BuildBoilerplate(node); 2061 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
1892 // Check for stack-overflow exception. 2062 // Check for stack-overflow exception.
1893 if (HasStackOverflow()) return; 2063 if (HasStackOverflow()) return;
1894 InstantiateBoilerplate(boilerplate); 2064 InstantiateBoilerplate(boilerplate);
1895 } 2065 }
1896 2066
1897 2067
1898 void CodeGenerator::VisitFunctionBoilerplateLiteral( 2068 void CodeGenerator::VisitFunctionBoilerplateLiteral(
1899 FunctionBoilerplateLiteral* node) { 2069 FunctionBoilerplateLiteral* node) {
1900 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); 2070 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
1901 InstantiateBoilerplate(node->boilerplate()); 2071 InstantiateBoilerplate(node->boilerplate());
1902 } 2072 }
1903 2073
1904 2074
1905 void CodeGenerator::VisitConditional(Conditional* node) { 2075 void CodeGenerator::VisitConditional(Conditional* node) {
1906 Comment cmnt(masm_, "[ Conditional"); 2076 Comment cmnt(masm_, "[ Conditional");
1907 JumpTarget then(this); 2077 JumpTarget then(this);
1908 JumpTarget else_(this); 2078 JumpTarget else_(this);
1909 Label exit; 2079 JumpTarget exit(this);
1910 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 2080 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
1911 Branch(false, &else_); 2081 Branch(false, &else_);
1912 then.Bind(); 2082 then.Bind();
1913 Load(node->then_expression(), typeof_state()); 2083 Load(node->then_expression(), typeof_state());
1914 __ b(&exit); 2084 exit.Jump();
1915 else_.Bind(); 2085 else_.Bind();
1916 Load(node->else_expression(), typeof_state()); 2086 Load(node->else_expression(), typeof_state());
1917 __ bind(&exit); 2087 exit.Bind();
1918 } 2088 }
1919 2089
1920 2090
1921 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2091 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
1922 if (slot->type() == Slot::LOOKUP) { 2092 if (slot->type() == Slot::LOOKUP) {
1923 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2093 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
1924 2094
1925 // For now, just do a runtime call. 2095 // For now, just do a runtime call.
1926 frame_->Push(cp); 2096 frame_->Push(cp);
1927 __ mov(r0, Operand(slot->var()->name())); 2097 __ mov(r0, Operand(slot->var()->name()));
1928 frame_->Push(r0); 2098 frame_->Push(r0);
1929 2099
1930 if (typeof_state == INSIDE_TYPEOF) { 2100 if (typeof_state == INSIDE_TYPEOF) {
1931 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 2101 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
1932 } else { 2102 } else {
1933 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2103 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
1934 } 2104 }
1935 frame_->Push(r0); 2105 frame_->Push(r0);
1936 2106
1937 } else { 2107 } else {
1938 // Note: We would like to keep the assert below, but it fires because of 2108 // Note: We would like to keep the assert below, but it fires because of
1939 // some nasty code in LoadTypeofExpression() which should be removed... 2109 // some nasty code in LoadTypeofExpression() which should be removed...
1940 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); 2110 // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
1941 2111
1942 // Special handling for locals allocated in registers. 2112 // Special handling for locals allocated in registers.
1943 __ ldr(r0, SlotOperand(slot, r2)); 2113 __ ldr(r0, SlotOperand(slot, r2));
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1993 __ ldr(r1, frame_->Function()); 2163 __ ldr(r1, frame_->Function());
1994 2164
1995 // Load the literals array of the function. 2165 // Load the literals array of the function.
1996 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); 2166 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
1997 2167
1998 // Load the literal at the ast saved index. 2168 // Load the literal at the ast saved index.
1999 int literal_offset = 2169 int literal_offset =
2000 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; 2170 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2001 __ ldr(r2, FieldMemOperand(r1, literal_offset)); 2171 __ ldr(r2, FieldMemOperand(r1, literal_offset));
2002 2172
2003 Label done; 2173 JumpTarget done(this);
2004 __ cmp(r2, Operand(Factory::undefined_value())); 2174 __ cmp(r2, Operand(Factory::undefined_value()));
2005 __ b(ne, &done); 2175 done.Branch(ne);
2006 2176
2007 // If the entry is undefined we call the runtime system to computed 2177 // If the entry is undefined we call the runtime system to computed
2008 // the literal. 2178 // the literal.
2009 frame_->Push(r1); // literal array (0) 2179 frame_->Push(r1); // literal array (0)
2010 __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); 2180 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
2011 frame_->Push(r0); // literal index (1) 2181 frame_->Push(r0); // literal index (1)
2012 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) 2182 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
2013 frame_->Push(r0); 2183 frame_->Push(r0);
2014 __ mov(r0, Operand(node->flags())); // RegExp flags (3) 2184 __ mov(r0, Operand(node->flags())); // RegExp flags (3)
2015 frame_->Push(r0); 2185 frame_->Push(r0);
2016 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 2186 frame_->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
2017 __ mov(r2, Operand(r0)); 2187 __ mov(r2, Operand(r0));
2018 2188
2019 __ bind(&done); 2189 done.Bind();
2020 // Push the literal. 2190 // Push the literal.
2021 frame_->Push(r2); 2191 frame_->Push(r2);
2022 } 2192 }
2023 2193
2024 2194
2025 // This deferred code stub will be used for creating the boilerplate 2195 // This deferred code stub will be used for creating the boilerplate
2026 // by calling Runtime_CreateObjectLiteral. 2196 // by calling Runtime_CreateObjectLiteral.
2027 // Each created boilerplate is stored in the JSFunction and they are 2197 // Each created boilerplate is stored in the JSFunction and they are
2028 // therefore context dependent. 2198 // therefore context dependent.
2029 class ObjectLiteralDeferred: public DeferredCode { 2199 class ObjectLiteralDeferred: public DeferredCode {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
2076 // Check whether we need to materialize the object literal boilerplate. 2246 // Check whether we need to materialize the object literal boilerplate.
2077 // If so, jump to the deferred code. 2247 // If so, jump to the deferred code.
2078 __ cmp(r2, Operand(Factory::undefined_value())); 2248 __ cmp(r2, Operand(Factory::undefined_value()));
2079 __ b(eq, deferred->enter()); 2249 __ b(eq, deferred->enter());
2080 __ bind(deferred->exit()); 2250 __ bind(deferred->exit());
2081 2251
2082 // Push the object literal boilerplate. 2252 // Push the object literal boilerplate.
2083 frame_->Push(r2); 2253 frame_->Push(r2);
2084 2254
2085 // Clone the boilerplate object. 2255 // Clone the boilerplate object.
2086 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); 2256 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
2087 frame_->Push(r0); // save the result 2257 frame_->Push(r0); // save the result
2088 // r0: cloned object literal 2258 // r0: cloned object literal
2089 2259
2090 for (int i = 0; i < node->properties()->length(); i++) { 2260 for (int i = 0; i < node->properties()->length(); i++) {
2091 ObjectLiteral::Property* property = node->properties()->at(i); 2261 ObjectLiteral::Property* property = node->properties()->at(i);
2092 Literal* key = property->key(); 2262 Literal* key = property->key();
2093 Expression* value = property->value(); 2263 Expression* value = property->value();
2094 switch (property->kind()) { 2264 switch (property->kind()) {
2095 case ObjectLiteral::Property::CONSTANT: break; 2265 case ObjectLiteral::Property::CONSTANT: break;
2096 case ObjectLiteral::Property::COMPUTED: // fall through 2266 case ObjectLiteral::Property::COMPUTED: // fall through
2097 case ObjectLiteral::Property::PROTOTYPE: { 2267 case ObjectLiteral::Property::PROTOTYPE: {
2098 frame_->Push(r0); // dup the result 2268 frame_->Push(r0); // dup the result
2099 Load(key); 2269 Load(key);
2100 Load(value); 2270 Load(value);
2101 __ CallRuntime(Runtime::kSetProperty, 3); 2271 frame_->CallRuntime(Runtime::kSetProperty, 3);
2102 // restore r0 2272 // restore r0
2103 __ ldr(r0, frame_->Top()); 2273 __ ldr(r0, frame_->Top());
2104 break; 2274 break;
2105 } 2275 }
2106 case ObjectLiteral::Property::SETTER: { 2276 case ObjectLiteral::Property::SETTER: {
2107 frame_->Push(r0); 2277 frame_->Push(r0);
2108 Load(key); 2278 Load(key);
2109 __ mov(r0, Operand(Smi::FromInt(1))); 2279 __ mov(r0, Operand(Smi::FromInt(1)));
2110 frame_->Push(r0); 2280 frame_->Push(r0);
2111 Load(value); 2281 Load(value);
2112 __ CallRuntime(Runtime::kDefineAccessor, 4); 2282 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2113 __ ldr(r0, frame_->Top()); 2283 __ ldr(r0, frame_->Top());
2114 break; 2284 break;
2115 } 2285 }
2116 case ObjectLiteral::Property::GETTER: { 2286 case ObjectLiteral::Property::GETTER: {
2117 frame_->Push(r0); 2287 frame_->Push(r0);
2118 Load(key); 2288 Load(key);
2119 __ mov(r0, Operand(Smi::FromInt(0))); 2289 __ mov(r0, Operand(Smi::FromInt(0)));
2120 frame_->Push(r0); 2290 frame_->Push(r0);
2121 Load(value); 2291 Load(value);
2122 __ CallRuntime(Runtime::kDefineAccessor, 4); 2292 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2123 __ ldr(r0, frame_->Top()); 2293 __ ldr(r0, frame_->Top());
2124 break; 2294 break;
2125 } 2295 }
2126 } 2296 }
2127 } 2297 }
2128 } 2298 }
2129 2299
2130 2300
2131 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { 2301 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
2132 Comment cmnt(masm_, "[ ArrayLiteral"); 2302 Comment cmnt(masm_, "[ ArrayLiteral");
2133 2303
2134 // Call runtime to create the array literal. 2304 // Call runtime to create the array literal.
2135 __ mov(r0, Operand(node->literals())); 2305 __ mov(r0, Operand(node->literals()));
2136 frame_->Push(r0); 2306 frame_->Push(r0);
2137 // Load the function of this frame. 2307 // Load the function of this frame.
2138 __ ldr(r0, frame_->Function()); 2308 __ ldr(r0, frame_->Function());
2139 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); 2309 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
2140 frame_->Push(r0); 2310 frame_->Push(r0);
2141 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); 2311 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
2142 2312
2143 // Push the resulting array literal on the stack. 2313 // Push the resulting array literal on the stack.
2144 frame_->Push(r0); 2314 frame_->Push(r0);
2145 2315
2146 // Generate code to set the elements in the array that are not 2316 // Generate code to set the elements in the array that are not
2147 // literals. 2317 // literals.
2148 for (int i = 0; i < node->values()->length(); i++) { 2318 for (int i = 0; i < node->values()->length(); i++) {
2149 Expression* value = node->values()->at(i); 2319 Expression* value = node->values()->at(i);
2150 2320
2151 // If value is literal the property value is already 2321 // If value is literal the property value is already
(...skipping 18 matching lines...) Expand all
2170 } 2340 }
2171 } 2341 }
2172 } 2342 }
2173 2343
2174 2344
2175 void CodeGenerator::VisitAssignment(Assignment* node) { 2345 void CodeGenerator::VisitAssignment(Assignment* node) {
2176 Comment cmnt(masm_, "[ Assignment"); 2346 Comment cmnt(masm_, "[ Assignment");
2177 if (FLAG_debug_info) RecordStatementPosition(node); 2347 if (FLAG_debug_info) RecordStatementPosition(node);
2178 2348
2179 Reference target(this, node->target()); 2349 Reference target(this, node->target());
2180 if (target.is_illegal()) return; 2350 if (target.is_illegal()) {
2351 // Fool the virtual frame into thinking that we left the assignment's
2352 // value on the frame.
2353 __ mov(r0, Operand(Smi::FromInt(0)));
2354 frame_->Push(r0);
2355 return;
2356 }
2181 2357
2182 if (node->op() == Token::ASSIGN || 2358 if (node->op() == Token::ASSIGN ||
2183 node->op() == Token::INIT_VAR || 2359 node->op() == Token::INIT_VAR ||
2184 node->op() == Token::INIT_CONST) { 2360 node->op() == Token::INIT_CONST) {
2185 Load(node->value()); 2361 Load(node->value());
2186 2362
2187 } else { 2363 } else {
2188 target.GetValue(NOT_INSIDE_TYPEOF); 2364 target.GetValue(NOT_INSIDE_TYPEOF);
2189 Literal* literal = node->value()->AsLiteral(); 2365 Literal* literal = node->value()->AsLiteral();
2190 if (literal != NULL && literal->handle()->IsSmi()) { 2366 if (literal != NULL && literal->handle()->IsSmi()) {
(...skipping 25 matching lines...) Expand all
2216 } 2392 }
2217 } 2393 }
2218 } 2394 }
2219 2395
2220 2396
2221 void CodeGenerator::VisitThrow(Throw* node) { 2397 void CodeGenerator::VisitThrow(Throw* node) {
2222 Comment cmnt(masm_, "[ Throw"); 2398 Comment cmnt(masm_, "[ Throw");
2223 2399
2224 Load(node->exception()); 2400 Load(node->exception());
2225 __ RecordPosition(node->position()); 2401 __ RecordPosition(node->position());
2226 __ CallRuntime(Runtime::kThrow, 1); 2402 frame_->CallRuntime(Runtime::kThrow, 1);
2227 frame_->Push(r0); 2403 frame_->Push(r0);
2228 } 2404 }
2229 2405
2230 2406
2231 void CodeGenerator::VisitProperty(Property* node) { 2407 void CodeGenerator::VisitProperty(Property* node) {
2232 Comment cmnt(masm_, "[ Property"); 2408 Comment cmnt(masm_, "[ Property");
2233 2409
2234 Reference property(this, node); 2410 Reference property(this, node);
2235 property.GetValue(typeof_state()); 2411 property.GetValue(typeof_state());
2236 } 2412 }
(...skipping 29 matching lines...) Expand all
2266 // Push the name of the function and the receiver onto the stack. 2442 // Push the name of the function and the receiver onto the stack.
2267 __ mov(r0, Operand(var->name())); 2443 __ mov(r0, Operand(var->name()));
2268 frame_->Push(r0); 2444 frame_->Push(r0);
2269 2445
2270 // Pass the global object as the receiver and let the IC stub 2446 // Pass the global object as the receiver and let the IC stub
2271 // patch the stack to use the global proxy as 'this' in the 2447 // patch the stack to use the global proxy as 'this' in the
2272 // invoked function. 2448 // invoked function.
2273 LoadGlobal(); 2449 LoadGlobal();
2274 2450
2275 // Load the arguments. 2451 // Load the arguments.
2276 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2452 int arg_count = args->length();
2453 for (int i = 0; i < arg_count; i++) {
2454 Load(args->at(i));
2455 }
2277 2456
2278 // Setup the receiver register and call the IC initialization code. 2457 // Setup the receiver register and call the IC initialization code.
2279 Handle<Code> stub = ComputeCallInitialize(args->length()); 2458 Handle<Code> stub = ComputeCallInitialize(arg_count);
2280 __ RecordPosition(node->position()); 2459 __ RecordPosition(node->position());
2281 __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT); 2460 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
2461 arg_count + 1);
2282 __ ldr(cp, frame_->Context()); 2462 __ ldr(cp, frame_->Context());
2283 // Remove the function from the stack. 2463 // Remove the function from the stack.
2284 frame_->Pop(); 2464 frame_->Drop();
2285 frame_->Push(r0); 2465 frame_->Push(r0);
2286 2466
2287 } else if (var != NULL && var->slot() != NULL && 2467 } else if (var != NULL && var->slot() != NULL &&
2288 var->slot()->type() == Slot::LOOKUP) { 2468 var->slot()->type() == Slot::LOOKUP) {
2289 // ---------------------------------- 2469 // ----------------------------------
2290 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj 2470 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
2291 // ---------------------------------- 2471 // ----------------------------------
2292 2472
2293 // Load the function 2473 // Load the function
2294 frame_->Push(cp); 2474 frame_->Push(cp);
2295 __ mov(r0, Operand(var->name())); 2475 __ mov(r0, Operand(var->name()));
2296 frame_->Push(r0); 2476 frame_->Push(r0);
2297 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2477 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2298 // r0: slot value; r1: receiver 2478 // r0: slot value; r1: receiver
2299 2479
2300 // Load the receiver. 2480 // Load the receiver.
2301 frame_->Push(r0); // function 2481 frame_->Push(r0); // function
2302 frame_->Push(r1); // receiver 2482 frame_->Push(r1); // receiver
2303 2483
2304 // Call the function. 2484 // Call the function.
2305 CallWithArguments(args, node->position()); 2485 CallWithArguments(args, node->position());
2306 frame_->Push(r0); 2486 frame_->Push(r0);
2307 2487
2308 } else if (property != NULL) { 2488 } else if (property != NULL) {
2309 // Check if the key is a literal string. 2489 // Check if the key is a literal string.
2310 Literal* literal = property->key()->AsLiteral(); 2490 Literal* literal = property->key()->AsLiteral();
2311 2491
2312 if (literal != NULL && literal->handle()->IsSymbol()) { 2492 if (literal != NULL && literal->handle()->IsSymbol()) {
2313 // ------------------------------------------------------------------ 2493 // ------------------------------------------------------------------
2314 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' 2494 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
2315 // ------------------------------------------------------------------ 2495 // ------------------------------------------------------------------
2316 2496
2317 // Push the name of the function and the receiver onto the stack. 2497 // Push the name of the function and the receiver onto the stack.
2318 __ mov(r0, Operand(literal->handle())); 2498 __ mov(r0, Operand(literal->handle()));
2319 frame_->Push(r0); 2499 frame_->Push(r0);
2320 Load(property->obj()); 2500 Load(property->obj());
2321 2501
2322 // Load the arguments. 2502 // Load the arguments.
2323 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2503 int arg_count = args->length();
2504 for (int i = 0; i < arg_count; i++) {
2505 Load(args->at(i));
2506 }
2324 2507
2325 // Set the receiver register and call the IC initialization code. 2508 // Set the receiver register and call the IC initialization code.
2326 Handle<Code> stub = ComputeCallInitialize(args->length()); 2509 Handle<Code> stub = ComputeCallInitialize(arg_count);
2327 __ RecordPosition(node->position()); 2510 __ RecordPosition(node->position());
2328 __ Call(stub, RelocInfo::CODE_TARGET); 2511 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
2329 __ ldr(cp, frame_->Context()); 2512 __ ldr(cp, frame_->Context());
2330 2513
2331 // Remove the function from the stack. 2514 // Remove the function from the stack.
2332 frame_->Pop(); 2515 frame_->Drop();
2333 2516
2334 frame_->Push(r0); // push after get rid of function from the stack 2517 frame_->Push(r0); // push after get rid of function from the stack
2335 2518
2336 } else { 2519 } else {
2337 // ------------------------------------------- 2520 // -------------------------------------------
2338 // JavaScript example: 'array[index](1, 2, 3)' 2521 // JavaScript example: 'array[index](1, 2, 3)'
2339 // ------------------------------------------- 2522 // -------------------------------------------
2340 2523
2341 // Load the function to call from the property through a reference. 2524 // Load the function to call from the property through a reference.
2342 Reference ref(this, property); 2525 Reference ref(this, property);
2343 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver 2526 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver
2344 2527
2345 // Pass receiver to called function. 2528 // Pass receiver to called function.
2346 __ ldr(r0, frame_->Element(ref.size())); 2529 __ ldr(r0, frame_->ElementAt(ref.size()));
2347 frame_->Push(r0); 2530 frame_->Push(r0);
2348 // Call the function. 2531 // Call the function.
2349 CallWithArguments(args, node->position()); 2532 CallWithArguments(args, node->position());
2350 frame_->Push(r0); 2533 frame_->Push(r0);
2351 } 2534 }
2352 2535
2353 } else { 2536 } else {
2354 // ---------------------------------- 2537 // ----------------------------------
2355 // JavaScript example: 'foo(1, 2, 3)' // foo is not global 2538 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
2356 // ---------------------------------- 2539 // ----------------------------------
(...skipping 21 matching lines...) Expand all
2378 // evaluated. 2561 // evaluated.
2379 2562
2380 // Compute function to call and use the global object as the 2563 // Compute function to call and use the global object as the
2381 // receiver. There is no need to use the global proxy here because 2564 // receiver. There is no need to use the global proxy here because
2382 // it will always be replaced with a newly allocated object. 2565 // it will always be replaced with a newly allocated object.
2383 Load(node->expression()); 2566 Load(node->expression());
2384 LoadGlobal(); 2567 LoadGlobal();
2385 2568
2386 // Push the arguments ("left-to-right") on the stack. 2569 // Push the arguments ("left-to-right") on the stack.
2387 ZoneList<Expression*>* args = node->arguments(); 2570 ZoneList<Expression*>* args = node->arguments();
2388 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2571 int arg_count = args->length();
2572 for (int i = 0; i < arg_count; i++) {
2573 Load(args->at(i));
2574 }
2389 2575
2390 // r0: the number of arguments. 2576 // r0: the number of arguments.
2391 __ mov(r0, Operand(args->length())); 2577 __ mov(r0, Operand(arg_count));
2392 2578
2393 // Load the function into r1 as per calling convention. 2579 // Load the function into r1 as per calling convention.
2394 __ ldr(r1, frame_->Element(args->length() + 1)); 2580 __ ldr(r1, frame_->ElementAt(arg_count + 1));
2395 2581
2396 // Call the construct call builtin that handles allocation and 2582 // Call the construct call builtin that handles allocation and
2397 // constructor invocation. 2583 // constructor invocation.
2398 __ RecordPosition(RelocInfo::POSITION); 2584 __ RecordPosition(RelocInfo::POSITION);
2399 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), 2585 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
2400 RelocInfo::CONSTRUCT_CALL); 2586 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1);
2401 2587
2402 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). 2588 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
2403 __ str(r0, frame_->Top()); 2589 __ str(r0, frame_->Top());
2404 } 2590 }
2405 2591
2406 2592
2407 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { 2593 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
2408 ASSERT(args->length() == 1); 2594 ASSERT(args->length() == 1);
2409 Label leave; 2595 JumpTarget leave(this);
2410 Load(args->at(0)); 2596 Load(args->at(0));
2411 frame_->Pop(r0); // r0 contains object. 2597 frame_->Pop(r0); // r0 contains object.
2412 // if (object->IsSmi()) return the object. 2598 // if (object->IsSmi()) return the object.
2413 __ tst(r0, Operand(kSmiTagMask)); 2599 __ tst(r0, Operand(kSmiTagMask));
2414 __ b(eq, &leave); 2600 leave.Branch(eq);
2415 // It is a heap object - get map. 2601 // It is a heap object - get map.
2416 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 2602 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2417 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); 2603 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
2418 // if (!object->IsJSValue()) return the object. 2604 // if (!object->IsJSValue()) return the object.
2419 __ cmp(r1, Operand(JS_VALUE_TYPE)); 2605 __ cmp(r1, Operand(JS_VALUE_TYPE));
2420 __ b(ne, &leave); 2606 leave.Branch(ne);
2421 // Load the value. 2607 // Load the value.
2422 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); 2608 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
2423 __ bind(&leave); 2609 leave.Bind();
2424 frame_->Push(r0); 2610 frame_->Push(r0);
2425 } 2611 }
2426 2612
2427 2613
2428 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { 2614 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
2429 ASSERT(args->length() == 2); 2615 ASSERT(args->length() == 2);
2430 Label leave; 2616 JumpTarget leave(this);
2431 Load(args->at(0)); // Load the object. 2617 Load(args->at(0)); // Load the object.
2432 Load(args->at(1)); // Load the value. 2618 Load(args->at(1)); // Load the value.
2433 frame_->Pop(r0); // r0 contains value 2619 frame_->Pop(r0); // r0 contains value
2434 frame_->Pop(r1); // r1 contains object 2620 frame_->Pop(r1); // r1 contains object
2435 // if (object->IsSmi()) return object. 2621 // if (object->IsSmi()) return object.
2436 __ tst(r1, Operand(kSmiTagMask)); 2622 __ tst(r1, Operand(kSmiTagMask));
2437 __ b(eq, &leave); 2623 leave.Branch(eq);
2438 // It is a heap object - get map. 2624 // It is a heap object - get map.
2439 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); 2625 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
2440 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); 2626 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
2441 // if (!object->IsJSValue()) return object. 2627 // if (!object->IsJSValue()) return object.
2442 __ cmp(r2, Operand(JS_VALUE_TYPE)); 2628 __ cmp(r2, Operand(JS_VALUE_TYPE));
2443 __ b(ne, &leave); 2629 leave.Branch(ne);
2444 // Store the value. 2630 // Store the value.
2445 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); 2631 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
2446 // Update the write barrier. 2632 // Update the write barrier.
2447 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); 2633 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
2448 __ RecordWrite(r1, r2, r3); 2634 __ RecordWrite(r1, r2, r3);
2449 // Leave. 2635 // Leave.
2450 __ bind(&leave); 2636 leave.Bind();
2451 frame_->Push(r0); 2637 frame_->Push(r0);
2452 } 2638 }
2453 2639
2454 2640
2455 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { 2641 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
2456 ASSERT(args->length() == 1); 2642 ASSERT(args->length() == 1);
2457 Load(args->at(0)); 2643 Load(args->at(0));
2458 frame_->Pop(r0); 2644 frame_->Pop(r0);
2459 __ tst(r0, Operand(kSmiTagMask)); 2645 __ tst(r0, Operand(kSmiTagMask));
2460 cc_reg_ = eq; 2646 cc_reg_ = eq;
(...skipping 15 matching lines...) Expand all
2476 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 2662 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
2477 ASSERT(args->length() == 2); 2663 ASSERT(args->length() == 2);
2478 __ mov(r0, Operand(Factory::undefined_value())); 2664 __ mov(r0, Operand(Factory::undefined_value()));
2479 frame_->Push(r0); 2665 frame_->Push(r0);
2480 } 2666 }
2481 2667
2482 2668
2483 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { 2669 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
2484 ASSERT(args->length() == 1); 2670 ASSERT(args->length() == 1);
2485 Load(args->at(0)); 2671 Load(args->at(0));
2486 Label answer; 2672 JumpTarget answer(this);
2487 // We need the CC bits to come out as not_equal in the case where the 2673 // We need the CC bits to come out as not_equal in the case where the
2488 // object is a smi. This can't be done with the usual test opcode so 2674 // object is a smi. This can't be done with the usual test opcode so
2489 // we use XOR to get the right CC bits. 2675 // we use XOR to get the right CC bits.
2490 frame_->Pop(r0); 2676 frame_->Pop(r0);
2491 __ and_(r1, r0, Operand(kSmiTagMask)); 2677 __ and_(r1, r0, Operand(kSmiTagMask));
2492 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); 2678 __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
2493 __ b(ne, &answer); 2679 answer.Branch(ne);
2494 // It is a heap object - get the map. 2680 // It is a heap object - get the map.
2495 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 2681 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2496 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); 2682 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
2497 // Check if the object is a JS array or not. 2683 // Check if the object is a JS array or not.
2498 __ cmp(r1, Operand(JS_ARRAY_TYPE)); 2684 __ cmp(r1, Operand(JS_ARRAY_TYPE));
2499 __ bind(&answer); 2685 answer.Bind();
2500 cc_reg_ = eq; 2686 cc_reg_ = eq;
2501 } 2687 }
2502 2688
2503 2689
2504 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 2690 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
2505 ASSERT(args->length() == 0); 2691 ASSERT(args->length() == 0);
2506 2692
2507 // Seed the result with the formal parameters count, which will be used 2693 // Seed the result with the formal parameters count, which will be used
2508 // in case no arguments adaptor frame is found below the current frame. 2694 // in case no arguments adaptor frame is found below the current frame.
2509 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); 2695 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
2510 2696
2511 // Call the shared stub to get to the arguments.length. 2697 // Call the shared stub to get to the arguments.length.
2512 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); 2698 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
2513 __ CallStub(&stub); 2699 frame_->CallStub(&stub, 0);
2514 frame_->Push(r0); 2700 frame_->Push(r0);
2515 } 2701 }
2516 2702
2517 2703
2518 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { 2704 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
2519 ASSERT(args->length() == 1); 2705 ASSERT(args->length() == 1);
2520 2706
2521 // Satisfy contract with ArgumentsAccessStub: 2707 // Satisfy contract with ArgumentsAccessStub:
2522 // Load the key into r1 and the formal parameters count into r0. 2708 // Load the key into r1 and the formal parameters count into r0.
2523 Load(args->at(0)); 2709 Load(args->at(0));
2524 frame_->Pop(r1); 2710 frame_->Pop(r1);
2525 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); 2711 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
2526 2712
2527 // Call the shared stub to get to arguments[key]. 2713 // Call the shared stub to get to arguments[key].
2528 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 2714 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2529 __ CallStub(&stub); 2715 frame_->CallStub(&stub, 0);
2530 frame_->Push(r0); 2716 frame_->Push(r0);
2531 } 2717 }
2532 2718
2533 2719
2534 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { 2720 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
2535 ASSERT(args->length() == 2); 2721 ASSERT(args->length() == 2);
2536 2722
2537 // Load the two objects into registers and perform the comparison. 2723 // Load the two objects into registers and perform the comparison.
2538 Load(args->at(0)); 2724 Load(args->at(0));
2539 Load(args->at(1)); 2725 Load(args->at(1));
2540 frame_->Pop(r0); 2726 frame_->Pop(r0);
2541 frame_->Pop(r1); 2727 frame_->Pop(r1);
2542 __ cmp(r0, Operand(r1)); 2728 __ cmp(r0, Operand(r1));
2543 cc_reg_ = eq; 2729 cc_reg_ = eq;
2544 } 2730 }
2545 2731
2546 2732
2547 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { 2733 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
2548 if (CheckForInlineRuntimeCall(node)) return; 2734 if (CheckForInlineRuntimeCall(node)) {
2735 return;
2736 }
2549 2737
2550 ZoneList<Expression*>* args = node->arguments(); 2738 ZoneList<Expression*>* args = node->arguments();
2551 Comment cmnt(masm_, "[ CallRuntime"); 2739 Comment cmnt(masm_, "[ CallRuntime");
2552 Runtime::Function* function = node->function(); 2740 Runtime::Function* function = node->function();
2553 2741
2554 if (function != NULL) { 2742 if (function != NULL) {
2555 // Push the arguments ("left-to-right"). 2743 // Push the arguments ("left-to-right").
2556 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2744 int arg_count = args->length();
2745 for (int i = 0; i < arg_count; i++) {
2746 Load(args->at(i));
2747 }
2557 2748
2558 // Call the C runtime function. 2749 // Call the C runtime function.
2559 __ CallRuntime(function, args->length()); 2750 frame_->CallRuntime(function, arg_count);
2560 frame_->Push(r0); 2751 frame_->Push(r0);
2561 2752
2562 } else { 2753 } else {
2563 // Prepare stack for calling JS runtime function. 2754 // Prepare stack for calling JS runtime function.
2564 __ mov(r0, Operand(node->name())); 2755 __ mov(r0, Operand(node->name()));
2565 frame_->Push(r0); 2756 frame_->Push(r0);
2566 // Push the builtins object found in the current global object. 2757 // Push the builtins object found in the current global object.
2567 __ ldr(r1, GlobalObject()); 2758 __ ldr(r1, GlobalObject());
2568 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); 2759 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
2569 frame_->Push(r0); 2760 frame_->Push(r0);
2570 2761
2571 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2762 int arg_count = args->length();
2763 for (int i = 0; i < arg_count; i++) {
2764 Load(args->at(i));
2765 }
2572 2766
2573 // Call the JS runtime function. 2767 // Call the JS runtime function.
2574 Handle<Code> stub = ComputeCallInitialize(args->length()); 2768 Handle<Code> stub = ComputeCallInitialize(args->length());
2575 __ Call(stub, RelocInfo::CODE_TARGET); 2769 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
2576 __ ldr(cp, frame_->Context()); 2770 __ ldr(cp, frame_->Context());
2577 frame_->Pop(); 2771 frame_->Drop();
2578 frame_->Push(r0); 2772 frame_->Push(r0);
2579 } 2773 }
2580 } 2774 }
2581 2775
2582 2776
2583 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { 2777 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
2584 Comment cmnt(masm_, "[ UnaryOperation"); 2778 Comment cmnt(masm_, "[ UnaryOperation");
2585 2779
2586 Token::Value op = node->op(); 2780 Token::Value op = node->op();
2587 2781
2588 if (op == Token::NOT) { 2782 if (op == Token::NOT) {
2589 LoadCondition(node->expression(), 2783 LoadCondition(node->expression(),
2590 NOT_INSIDE_TYPEOF, 2784 NOT_INSIDE_TYPEOF,
2591 false_target(), 2785 false_target(),
2592 true_target(), 2786 true_target(),
2593 true); 2787 true);
2594 cc_reg_ = NegateCondition(cc_reg_); 2788 cc_reg_ = NegateCondition(cc_reg_);
2595 2789
2596 } else if (op == Token::DELETE) { 2790 } else if (op == Token::DELETE) {
2597 Property* property = node->expression()->AsProperty(); 2791 Property* property = node->expression()->AsProperty();
2598 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); 2792 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
2599 if (property != NULL) { 2793 if (property != NULL) {
2600 Load(property->obj()); 2794 Load(property->obj());
2601 Load(property->key()); 2795 Load(property->key());
2602 __ mov(r0, Operand(1)); // not counting receiver 2796 __ mov(r0, Operand(1)); // not counting receiver
2603 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 2797 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2);
2604 2798
2605 } else if (variable != NULL) { 2799 } else if (variable != NULL) {
2606 Slot* slot = variable->slot(); 2800 Slot* slot = variable->slot();
2607 if (variable->is_global()) { 2801 if (variable->is_global()) {
2608 LoadGlobal(); 2802 LoadGlobal();
2609 __ mov(r0, Operand(variable->name())); 2803 __ mov(r0, Operand(variable->name()));
2610 frame_->Push(r0); 2804 frame_->Push(r0);
2611 __ mov(r0, Operand(1)); // not counting receiver 2805 __ mov(r0, Operand(1)); // not counting receiver
2612 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 2806 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2);
2613 2807
2614 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 2808 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
2615 // lookup the context holding the named variable 2809 // lookup the context holding the named variable
2616 frame_->Push(cp); 2810 frame_->Push(cp);
2617 __ mov(r0, Operand(variable->name())); 2811 __ mov(r0, Operand(variable->name()));
2618 frame_->Push(r0); 2812 frame_->Push(r0);
2619 __ CallRuntime(Runtime::kLookupContext, 2); 2813 frame_->CallRuntime(Runtime::kLookupContext, 2);
2620 // r0: context 2814 // r0: context
2621 frame_->Push(r0); 2815 frame_->Push(r0);
2622 __ mov(r0, Operand(variable->name())); 2816 __ mov(r0, Operand(variable->name()));
2623 frame_->Push(r0); 2817 frame_->Push(r0);
2624 __ mov(r0, Operand(1)); // not counting receiver 2818 __ mov(r0, Operand(1)); // not counting receiver
2625 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 2819 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, 2);
2626 2820
2627 } else { 2821 } else {
2628 // Default: Result of deleting non-global, not dynamically 2822 // Default: Result of deleting non-global, not dynamically
2629 // introduced variables is false. 2823 // introduced variables is false.
2630 __ mov(r0, Operand(Factory::false_value())); 2824 __ mov(r0, Operand(Factory::false_value()));
2631 } 2825 }
2632 2826
2633 } else { 2827 } else {
2634 // Default: Result of deleting expressions is true. 2828 // Default: Result of deleting expressions is true.
2635 Load(node->expression()); // may have side-effects 2829 Load(node->expression()); // may have side-effects
2636 frame_->Pop(); 2830 frame_->Drop();
2637 __ mov(r0, Operand(Factory::true_value())); 2831 __ mov(r0, Operand(Factory::true_value()));
2638 } 2832 }
2639 frame_->Push(r0); 2833 frame_->Push(r0);
2640 2834
2641 } else if (op == Token::TYPEOF) { 2835 } else if (op == Token::TYPEOF) {
2642 // Special case for loading the typeof expression; see comment on 2836 // Special case for loading the typeof expression; see comment on
2643 // LoadTypeofExpression(). 2837 // LoadTypeofExpression().
2644 LoadTypeofExpression(node->expression()); 2838 LoadTypeofExpression(node->expression());
2645 __ CallRuntime(Runtime::kTypeof, 1); 2839 frame_->CallRuntime(Runtime::kTypeof, 1);
2646 frame_->Push(r0); // r0 has result 2840 frame_->Push(r0); // r0 has result
2647 2841
2648 } else { 2842 } else {
2649 Load(node->expression()); 2843 Load(node->expression());
2650 frame_->Pop(r0); 2844 frame_->Pop(r0);
2651 switch (op) { 2845 switch (op) {
2652 case Token::NOT: 2846 case Token::NOT:
2653 case Token::DELETE: 2847 case Token::DELETE:
2654 case Token::TYPEOF: 2848 case Token::TYPEOF:
2655 UNREACHABLE(); // handled above 2849 UNREACHABLE(); // handled above
2656 break; 2850 break;
2657 2851
2658 case Token::SUB: { 2852 case Token::SUB: {
2659 UnarySubStub stub; 2853 UnarySubStub stub;
2660 __ CallStub(&stub); 2854 frame_->CallStub(&stub, 0);
2661 break; 2855 break;
2662 } 2856 }
2663 2857
2664 case Token::BIT_NOT: { 2858 case Token::BIT_NOT: {
2665 // smi check 2859 // smi check
2666 Label smi_label; 2860 JumpTarget smi_label(this);
2667 Label continue_label; 2861 JumpTarget continue_label(this);
2668 __ tst(r0, Operand(kSmiTagMask)); 2862 __ tst(r0, Operand(kSmiTagMask));
2669 __ b(eq, &smi_label); 2863 smi_label.Branch(eq);
2670 2864
2671 frame_->Push(r0); 2865 frame_->Push(r0);
2672 __ mov(r0, Operand(0)); // not counting receiver 2866 __ mov(r0, Operand(0)); // not counting receiver
2673 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); 2867 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, 1);
2674 2868
2675 __ b(&continue_label); 2869 continue_label.Jump();
2676 __ bind(&smi_label); 2870 smi_label.Bind();
2677 __ mvn(r0, Operand(r0)); 2871 __ mvn(r0, Operand(r0));
2678 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag 2872 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
2679 __ bind(&continue_label); 2873 continue_label.Bind();
2680 break; 2874 break;
2681 } 2875 }
2682 2876
2683 case Token::VOID: 2877 case Token::VOID:
2684 // since the stack top is cached in r0, popping and then 2878 // since the stack top is cached in r0, popping and then
2685 // pushing a value can be done by just writing to r0. 2879 // pushing a value can be done by just writing to r0.
2686 __ mov(r0, Operand(Factory::undefined_value())); 2880 __ mov(r0, Operand(Factory::undefined_value()));
2687 break; 2881 break;
2688 2882
2689 case Token::ADD: { 2883 case Token::ADD: {
2690 // Smi check. 2884 // Smi check.
2691 Label continue_label; 2885 JumpTarget continue_label(this);
2692 __ tst(r0, Operand(kSmiTagMask)); 2886 __ tst(r0, Operand(kSmiTagMask));
2693 __ b(eq, &continue_label); 2887 continue_label.Branch(eq);
2694 frame_->Push(r0); 2888 frame_->Push(r0);
2695 __ mov(r0, Operand(0)); // not counting receiver 2889 __ mov(r0, Operand(0)); // not counting receiver
2696 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); 2890 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
2697 __ bind(&continue_label); 2891 continue_label.Bind();
2698 break; 2892 break;
2699 } 2893 }
2700 default: 2894 default:
2701 UNREACHABLE(); 2895 UNREACHABLE();
2702 } 2896 }
2703 frame_->Push(r0); // r0 has result 2897 frame_->Push(r0); // r0 has result
2704 } 2898 }
2705 } 2899 }
2706 2900
2707 2901
2708 void CodeGenerator::VisitCountOperation(CountOperation* node) { 2902 void CodeGenerator::VisitCountOperation(CountOperation* node) {
2709 Comment cmnt(masm_, "[ CountOperation"); 2903 Comment cmnt(masm_, "[ CountOperation");
2710 2904
2711 bool is_postfix = node->is_postfix(); 2905 bool is_postfix = node->is_postfix();
2712 bool is_increment = node->op() == Token::INC; 2906 bool is_increment = node->op() == Token::INC;
2713 2907
2714 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); 2908 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
2715 bool is_const = (var != NULL && var->mode() == Variable::CONST); 2909 bool is_const = (var != NULL && var->mode() == Variable::CONST);
2716 2910
2717 // Postfix: Make room for the result. 2911 // Postfix: Make room for the result.
2718 if (is_postfix) { 2912 if (is_postfix) {
2719 __ mov(r0, Operand(0)); 2913 __ mov(r0, Operand(0));
2720 frame_->Push(r0); 2914 frame_->Push(r0);
2721 } 2915 }
2722 2916
2723 { Reference target(this, node->expression()); 2917 { Reference target(this, node->expression());
2724 if (target.is_illegal()) return; 2918 if (target.is_illegal()) {
2919 // Spoof the virtual frame to have the expected height (one higher
2920 // than on entry).
2921 if (!is_postfix) {
2922 __ mov(r0, Operand(Smi::FromInt(0)));
2923 frame_->Push(r0);
2924 }
2925 return;
2926 }
2725 target.GetValue(NOT_INSIDE_TYPEOF); 2927 target.GetValue(NOT_INSIDE_TYPEOF);
2726 frame_->Pop(r0); 2928 frame_->Pop(r0);
2727 2929
2728 Label slow, exit; 2930 JumpTarget slow(this);
2931 JumpTarget exit(this);
2729 2932
2730 // Load the value (1) into register r1. 2933 // Load the value (1) into register r1.
2731 __ mov(r1, Operand(Smi::FromInt(1))); 2934 __ mov(r1, Operand(Smi::FromInt(1)));
2732 2935
2733 // Check for smi operand. 2936 // Check for smi operand.
2734 __ tst(r0, Operand(kSmiTagMask)); 2937 __ tst(r0, Operand(kSmiTagMask));
2735 __ b(ne, &slow); 2938 slow.Branch(ne);
2736 2939
2737 // Postfix: Store the old value as the result. 2940 // Postfix: Store the old value as the result.
2738 if (is_postfix) { 2941 if (is_postfix) {
2739 __ str(r0, frame_->Element(target.size())); 2942 __ str(r0, frame_->ElementAt(target.size()));
2740 } 2943 }
2741 2944
2742 // Perform optimistic increment/decrement. 2945 // Perform optimistic increment/decrement.
2743 if (is_increment) { 2946 if (is_increment) {
2744 __ add(r0, r0, Operand(r1), SetCC); 2947 __ add(r0, r0, Operand(r1), SetCC);
2745 } else { 2948 } else {
2746 __ sub(r0, r0, Operand(r1), SetCC); 2949 __ sub(r0, r0, Operand(r1), SetCC);
2747 } 2950 }
2748 2951
2749 // If the increment/decrement didn't overflow, we're done. 2952 // If the increment/decrement didn't overflow, we're done.
2750 __ b(vc, &exit); 2953 exit.Branch(vc);
2751 2954
2752 // Revert optimistic increment/decrement. 2955 // Revert optimistic increment/decrement.
2753 if (is_increment) { 2956 if (is_increment) {
2754 __ sub(r0, r0, Operand(r1)); 2957 __ sub(r0, r0, Operand(r1));
2755 } else { 2958 } else {
2756 __ add(r0, r0, Operand(r1)); 2959 __ add(r0, r0, Operand(r1));
2757 } 2960 }
2758 2961
2759 // Slow case: Convert to number. 2962 // Slow case: Convert to number.
2760 __ bind(&slow); 2963 slow.Bind();
2761 2964
2762 // Postfix: Convert the operand to a number and store it as the result. 2965 // Postfix: Convert the operand to a number and store it as the result.
2763 if (is_postfix) { 2966 if (is_postfix) {
2764 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2); 2967 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
2765 __ CallStub(&stub); 2968 frame_->CallStub(&stub, 0);
2766 // Store to result (on the stack). 2969 // Store to result (on the stack).
2767 __ str(r0, frame_->Element(target.size())); 2970 __ str(r0, frame_->ElementAt(target.size()));
2768 } 2971 }
2769 2972
2770 // Compute the new value by calling the right JavaScript native. 2973 // Compute the new value by calling the right JavaScript native.
2771 if (is_increment) { 2974 if (is_increment) {
2772 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1); 2975 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
2773 __ CallStub(&stub); 2976 frame_->CallStub(&stub, 0);
2774 } else { 2977 } else {
2775 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1); 2978 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
2776 __ CallStub(&stub); 2979 frame_->CallStub(&stub, 0);
2777 } 2980 }
2778 2981
2779 // Store the new value in the target if not const. 2982 // Store the new value in the target if not const.
2780 __ bind(&exit); 2983 exit.Bind();
2781 frame_->Push(r0); 2984 frame_->Push(r0);
2782 if (!is_const) target.SetValue(NOT_CONST_INIT); 2985 if (!is_const) target.SetValue(NOT_CONST_INIT);
2783 } 2986 }
2784 2987
2785 // Postfix: Discard the new value and use the old. 2988 // Postfix: Discard the new value and use the old.
2786 if (is_postfix) frame_->Pop(r0); 2989 if (is_postfix) frame_->Pop(r0);
2787 } 2990 }
2788 2991
2789 2992
2790 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { 2993 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
2931 // runtime routine for checking equality. 3134 // runtime routine for checking equality.
2932 3135
2933 if (op == Token::EQ || op == Token::EQ_STRICT) { 3136 if (op == Token::EQ || op == Token::EQ_STRICT) {
2934 bool left_is_null = 3137 bool left_is_null =
2935 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); 3138 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
2936 bool right_is_null = 3139 bool right_is_null =
2937 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); 3140 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
2938 // The 'null' value is only equal to 'null' or 'undefined'. 3141 // The 'null' value is only equal to 'null' or 'undefined'.
2939 if (left_is_null || right_is_null) { 3142 if (left_is_null || right_is_null) {
2940 Load(left_is_null ? right : left); 3143 Load(left_is_null ? right : left);
2941 Label exit, undetectable; 3144 JumpTarget exit(this);
3145 JumpTarget undetectable(this);
2942 frame_->Pop(r0); 3146 frame_->Pop(r0);
2943 __ cmp(r0, Operand(Factory::null_value())); 3147 __ cmp(r0, Operand(Factory::null_value()));
2944 3148
2945 // The 'null' value is only equal to 'undefined' if using 3149 // The 'null' value is only equal to 'undefined' if using
2946 // non-strict comparisons. 3150 // non-strict comparisons.
2947 if (op != Token::EQ_STRICT) { 3151 if (op != Token::EQ_STRICT) {
2948 __ b(eq, &exit); 3152 exit.Branch(eq);
2949 __ cmp(r0, Operand(Factory::undefined_value())); 3153 __ cmp(r0, Operand(Factory::undefined_value()));
2950 3154
2951 // NOTE: it can be undetectable object. 3155 // NOTE: it can be undetectable object.
2952 __ b(eq, &exit); 3156 exit.Branch(eq);
2953 __ tst(r0, Operand(kSmiTagMask)); 3157 __ tst(r0, Operand(kSmiTagMask));
2954 3158
2955 __ b(ne, &undetectable); 3159 undetectable.Branch(ne);
2956 false_target()->Jump(); 3160 false_target()->Jump();
2957 3161
2958 __ bind(&undetectable); 3162 undetectable.Bind();
2959 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); 3163 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2960 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); 3164 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
2961 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); 3165 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
2962 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); 3166 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
2963 } 3167 }
2964 3168
2965 __ bind(&exit); 3169 exit.Bind();
2966 3170
2967 cc_reg_ = eq; 3171 cc_reg_ = eq;
2968 return; 3172 return;
2969 } 3173 }
2970 } 3174 }
2971 3175
2972 3176
2973 // NOTE: To make typeof testing for natives implemented in 3177 // NOTE: To make typeof testing for natives implemented in
2974 // JavaScript really efficient, we generate special code for 3178 // JavaScript really efficient, we generate special code for
2975 // expressions of the form: 'typeof <expression> == <string>'. 3179 // expressions of the form: 'typeof <expression> == <string>'.
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
3087 case Token::GTE: 3291 case Token::GTE:
3088 Comparison(ge); 3292 Comparison(ge);
3089 break; 3293 break;
3090 3294
3091 case Token::EQ_STRICT: 3295 case Token::EQ_STRICT:
3092 Comparison(eq, true); 3296 Comparison(eq, true);
3093 break; 3297 break;
3094 3298
3095 case Token::IN: 3299 case Token::IN:
3096 __ mov(r0, Operand(1)); // not counting receiver 3300 __ mov(r0, Operand(1)); // not counting receiver
3097 __ InvokeBuiltin(Builtins::IN, CALL_JS); 3301 frame_->InvokeBuiltin(Builtins::IN, CALL_JS, 2);
3098 frame_->Push(r0); 3302 frame_->Push(r0);
3099 break; 3303 break;
3100 3304
3101 case Token::INSTANCEOF: 3305 case Token::INSTANCEOF:
3102 __ mov(r0, Operand(1)); // not counting receiver 3306 __ mov(r0, Operand(1)); // not counting receiver
3103 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS); 3307 frame_->InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS, 2);
3104 __ tst(r0, Operand(r0)); 3308 __ tst(r0, Operand(r0));
3105 cc_reg_ = eq; 3309 cc_reg_ = eq;
3106 break; 3310 break;
3107 3311
3108 default: 3312 default:
3109 UNREACHABLE(); 3313 UNREACHABLE();
3110 } 3314 }
3111 } 3315 }
3112 3316
3113 3317
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3167 // loads must not throw a reference error). 3371 // loads must not throw a reference error).
3168 Comment cmnt(masm, "[ Load from named Property"); 3372 Comment cmnt(masm, "[ Load from named Property");
3169 // Setup the name register. 3373 // Setup the name register.
3170 Handle<String> name(GetName()); 3374 Handle<String> name(GetName());
3171 __ mov(r2, Operand(name)); 3375 __ mov(r2, Operand(name));
3172 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 3376 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3173 3377
3174 Variable* var = expression_->AsVariableProxy()->AsVariable(); 3378 Variable* var = expression_->AsVariableProxy()->AsVariable();
3175 if (var != NULL) { 3379 if (var != NULL) {
3176 ASSERT(var->is_global()); 3380 ASSERT(var->is_global());
3177 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); 3381 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
3178 } else { 3382 } else {
3179 __ Call(ic, RelocInfo::CODE_TARGET); 3383 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
3180 } 3384 }
3181 frame->Push(r0); 3385 frame->Push(r0);
3182 break; 3386 break;
3183 } 3387 }
3184 3388
3185 case KEYED: { 3389 case KEYED: {
3186 // TODO(1241834): Make sure that this it is safe to ignore the 3390 // TODO(1241834): Make sure that this it is safe to ignore the
3187 // distinction between expressions in a typeof and not in a typeof. 3391 // distinction between expressions in a typeof and not in a typeof.
3188 Comment cmnt(masm, "[ Load from keyed Property"); 3392 Comment cmnt(masm, "[ Load from keyed Property");
3189 ASSERT(property != NULL); 3393 ASSERT(property != NULL);
3190 // TODO(1224671): Implement inline caching for keyed loads as on ia32. 3394 // TODO(1224671): Implement inline caching for keyed loads as on ia32.
3191 GetPropertyStub stub; 3395 GetPropertyStub stub;
3192 __ CallStub(&stub); 3396 frame->CallStub(&stub, 0);
3193 frame->Push(r0); 3397 frame->Push(r0);
3194 break; 3398 break;
3195 } 3399 }
3196 3400
3197 default: 3401 default:
3198 UNREACHABLE(); 3402 UNREACHABLE();
3199 } 3403 }
3200 } 3404 }
3201 3405
3202 3406
(...skipping 29 matching lines...) Expand all
3232 // 3436 //
3233 // Note that we must declare the foo upon entry of eval(), via a 3437 // Note that we must declare the foo upon entry of eval(), via a
3234 // context slot declaration, but we cannot initialize it at the 3438 // context slot declaration, but we cannot initialize it at the
3235 // same time, because the const declaration may be at the end of 3439 // same time, because the const declaration may be at the end of
3236 // the eval code (sigh...) and the const variable may have been 3440 // the eval code (sigh...) and the const variable may have been
3237 // used before (where its value is 'undefined'). Thus, we can only 3441 // used before (where its value is 'undefined'). Thus, we can only
3238 // do the initialization when we actually encounter the expression 3442 // do the initialization when we actually encounter the expression
3239 // and when the expression operands are defined and valid, and 3443 // and when the expression operands are defined and valid, and
3240 // thus we need the split into 2 operations: declaration of the 3444 // thus we need the split into 2 operations: declaration of the
3241 // context slot followed by initialization. 3445 // context slot followed by initialization.
3242 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); 3446 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
3243 } else { 3447 } else {
3244 __ CallRuntime(Runtime::kStoreContextSlot, 3); 3448 frame->CallRuntime(Runtime::kStoreContextSlot, 3);
3245 } 3449 }
3246 // Storing a variable must keep the (new) value on the expression 3450 // Storing a variable must keep the (new) value on the expression
3247 // stack. This is necessary for compiling assignment expressions. 3451 // stack. This is necessary for compiling assignment expressions.
3248 frame->Push(r0); 3452 frame->Push(r0);
3249 3453
3250 } else { 3454 } else {
3251 ASSERT(slot->var()->mode() != Variable::DYNAMIC); 3455 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
3252 3456
3253 Label exit; 3457 JumpTarget exit(cgen_);
3254 if (init_state == CONST_INIT) { 3458 if (init_state == CONST_INIT) {
3255 ASSERT(slot->var()->mode() == Variable::CONST); 3459 ASSERT(slot->var()->mode() == Variable::CONST);
3256 // Only the first const initialization must be executed (the slot 3460 // Only the first const initialization must be executed (the slot
3257 // still contains 'the hole' value). When the assignment is 3461 // still contains 'the hole' value). When the assignment is
3258 // executed, the code is identical to a normal store (see below). 3462 // executed, the code is identical to a normal store (see below).
3259 Comment cmnt(masm, "[ Init const"); 3463 Comment cmnt(masm, "[ Init const");
3260 __ ldr(r2, cgen_->SlotOperand(slot, r2)); 3464 __ ldr(r2, cgen_->SlotOperand(slot, r2));
3261 __ cmp(r2, Operand(Factory::the_hole_value())); 3465 __ cmp(r2, Operand(Factory::the_hole_value()));
3262 __ b(ne, &exit); 3466 exit.Branch(ne);
3263 } 3467 }
3264 3468
3265 // We must execute the store. Storing a variable must keep the 3469 // We must execute the store. Storing a variable must keep the
3266 // (new) value on the stack. This is necessary for compiling 3470 // (new) value on the stack. This is necessary for compiling
3267 // assignment expressions. 3471 // assignment expressions.
3268 // 3472 //
3269 // Note: We will reach here even with slot->var()->mode() == 3473 // Note: We will reach here even with slot->var()->mode() ==
3270 // Variable::CONST because of const declarations which will 3474 // Variable::CONST because of const declarations which will
3271 // initialize consts to 'the hole' value and by doing so, end up 3475 // 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 3476 // calling this code. r2 may be loaded with context; used below in
3273 // RecordWrite. 3477 // RecordWrite.
3274 frame->Pop(r0); 3478 frame->Pop(r0);
3275 __ str(r0, cgen_->SlotOperand(slot, r2)); 3479 __ str(r0, cgen_->SlotOperand(slot, r2));
3276 frame->Push(r0); 3480 frame->Push(r0);
3277 if (slot->type() == Slot::CONTEXT) { 3481 if (slot->type() == Slot::CONTEXT) {
3278 // Skip write barrier if the written value is a smi. 3482 // Skip write barrier if the written value is a smi.
3279 __ tst(r0, Operand(kSmiTagMask)); 3483 __ tst(r0, Operand(kSmiTagMask));
3280 __ b(eq, &exit); 3484 exit.Branch(eq);
3281 // r2 is loaded with context when calling SlotOperand above. 3485 // r2 is loaded with context when calling SlotOperand above.
3282 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 3486 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
3283 __ mov(r3, Operand(offset)); 3487 __ mov(r3, Operand(offset));
3284 __ RecordWrite(r2, r3, r1); 3488 __ RecordWrite(r2, r3, r1);
3285 } 3489 }
3286 // If we definitely did not jump over the assignment, we do not need 3490 // If we definitely did not jump over the assignment, we do not need
3287 // to bind the exit label. Doing so can defeat peephole 3491 // to bind the exit label. Doing so can defeat peephole
3288 // optimization. 3492 // optimization.
3289 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { 3493 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
3290 __ bind(&exit); 3494 exit.Bind();
3291 } 3495 }
3292 } 3496 }
3293 break; 3497 break;
3294 } 3498 }
3295 3499
3296 case NAMED: { 3500 case NAMED: {
3297 Comment cmnt(masm, "[ Store to named Property"); 3501 Comment cmnt(masm, "[ Store to named Property");
3298 // Call the appropriate IC code. 3502 // Call the appropriate IC code.
3299 frame->Pop(r0); // value 3503 frame->Pop(r0); // value
3300 // Setup the name register. 3504 // Setup the name register.
3301 Handle<String> name(GetName()); 3505 Handle<String> name(GetName());
3302 __ mov(r2, Operand(name)); 3506 __ mov(r2, Operand(name));
3303 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 3507 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3304 __ Call(ic, RelocInfo::CODE_TARGET); 3508 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
3305 frame->Push(r0); 3509 frame->Push(r0);
3306 break; 3510 break;
3307 } 3511 }
3308 3512
3309 case KEYED: { 3513 case KEYED: {
3310 Comment cmnt(masm, "[ Store to keyed Property"); 3514 Comment cmnt(masm, "[ Store to keyed Property");
3311 Property* property = expression_->AsProperty(); 3515 Property* property = expression_->AsProperty();
3312 ASSERT(property != NULL); 3516 ASSERT(property != NULL);
3313 __ RecordPosition(property->position()); 3517 __ RecordPosition(property->position());
3314 frame->Pop(r0); // value 3518 frame->Pop(r0); // value
3315 SetPropertyStub stub; 3519 SetPropertyStub stub;
3316 __ CallStub(&stub); 3520 frame->CallStub(&stub, 0);
3317 frame->Push(r0); 3521 frame->Push(r0);
3318 break; 3522 break;
3319 } 3523 }
3320 3524
3321 default: 3525 default:
3322 UNREACHABLE(); 3526 UNREACHABLE();
3323 } 3527 }
3324 } 3528 }
3325 3529
3326 3530
(...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after
4226 __ mov(r2, Operand(0)); 4430 __ mov(r2, Operand(0));
4227 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 4431 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
4228 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), 4432 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
4229 RelocInfo::CODE_TARGET); 4433 RelocInfo::CODE_TARGET);
4230 } 4434 }
4231 4435
4232 4436
4233 #undef __ 4437 #undef __
4234 4438
4235 } } // namespace v8::internal 4439 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.h ('k') | src/codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698