OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // mode 1 instruction where there are restrictions on which immediate values | 207 // mode 1 instruction where there are restrictions on which immediate values |
208 // can be encoded in the instruction and which immediate values requires | 208 // can be encoded in the instruction and which immediate values requires |
209 // use of an additional instruction for moving the immediate to a temporary | 209 // use of an additional instruction for moving the immediate to a temporary |
210 // register. | 210 // register. |
211 ASSERT_EQ(return_sequence_length, | 211 ASSERT_EQ(return_sequence_length, |
212 masm_->InstructionsGeneratedSince(&check_exit_codesize)); | 212 masm_->InstructionsGeneratedSince(&check_exit_codesize)); |
213 } | 213 } |
214 } | 214 } |
215 | 215 |
216 | 216 |
217 void FastCodeGenerator::Apply(Expression::Context context, | 217 void FastCodeGenerator::Apply(Expression::Context context, Register reg) { |
218 Slot* slot, | 218 switch (context) { |
219 Register scratch) { | 219 case Expression::kUninitialized: |
| 220 UNREACHABLE(); |
| 221 |
| 222 case Expression::kEffect: |
| 223 // Nothing to do. |
| 224 break; |
| 225 |
| 226 case Expression::kValue: |
| 227 // Move value into place. |
| 228 switch (location_) { |
| 229 case kAccumulator: |
| 230 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 231 break; |
| 232 case kStack: |
| 233 __ push(reg); |
| 234 break; |
| 235 } |
| 236 break; |
| 237 |
| 238 case Expression::kValueTest: |
| 239 case Expression::kTestValue: |
| 240 // Push an extra copy of the value in case it's needed. |
| 241 __ push(reg); |
| 242 // Fall through. |
| 243 |
| 244 case Expression::kTest: |
| 245 // We always call the runtime on ARM, so push the value as argument. |
| 246 __ push(reg); |
| 247 DoTest(context); |
| 248 break; |
| 249 } |
| 250 } |
| 251 |
| 252 |
| 253 void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) { |
220 switch (context) { | 254 switch (context) { |
221 case Expression::kUninitialized: | 255 case Expression::kUninitialized: |
222 UNREACHABLE(); | 256 UNREACHABLE(); |
223 case Expression::kEffect: | 257 case Expression::kEffect: |
| 258 // Nothing to do. |
224 break; | 259 break; |
225 case Expression::kValue: | 260 case Expression::kValue: |
226 case Expression::kTest: | 261 case Expression::kTest: |
227 case Expression::kValueTest: | 262 case Expression::kValueTest: |
228 case Expression::kTestValue: | 263 case Expression::kTestValue: |
229 Move(scratch, slot); | 264 // On ARM we have to move the value into a register to do anything |
230 Apply(context, scratch); | 265 // with it. |
| 266 Move(result_register(), slot); |
| 267 Apply(context, result_register()); |
231 break; | 268 break; |
232 } | 269 } |
233 } | 270 } |
234 | 271 |
235 | 272 |
236 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { | 273 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { |
237 switch (context) { | 274 switch (context) { |
238 case Expression::kUninitialized: | 275 case Expression::kUninitialized: |
239 UNREACHABLE(); | 276 UNREACHABLE(); |
240 case Expression::kEffect: | 277 case Expression::kEffect: |
241 break; | 278 break; |
| 279 // Nothing to do. |
242 case Expression::kValue: | 280 case Expression::kValue: |
243 case Expression::kTest: | 281 case Expression::kTest: |
244 case Expression::kValueTest: | 282 case Expression::kValueTest: |
245 case Expression::kTestValue: | 283 case Expression::kTestValue: |
246 __ mov(ip, Operand(lit->handle())); | 284 // On ARM we have to move the value into a register to do anything |
247 Apply(context, ip); | 285 // with it. |
| 286 __ mov(result_register(), Operand(lit->handle())); |
| 287 Apply(context, result_register()); |
248 break; | 288 break; |
249 } | 289 } |
250 } | 290 } |
251 | 291 |
252 | 292 |
253 void FastCodeGenerator::ApplyTOS(Expression::Context context) { | 293 void FastCodeGenerator::ApplyTOS(Expression::Context context) { |
254 switch (context) { | 294 switch (context) { |
255 case Expression::kUninitialized: | 295 case Expression::kUninitialized: |
256 UNREACHABLE(); | 296 UNREACHABLE(); |
| 297 |
257 case Expression::kEffect: | 298 case Expression::kEffect: |
258 __ Drop(1); | 299 __ Drop(1); |
259 break; | 300 break; |
| 301 |
260 case Expression::kValue: | 302 case Expression::kValue: |
| 303 switch (location_) { |
| 304 case kAccumulator: |
| 305 __ pop(result_register()); |
| 306 break; |
| 307 case kStack: |
| 308 break; |
| 309 } |
261 break; | 310 break; |
| 311 |
| 312 case Expression::kValueTest: |
| 313 case Expression::kTestValue: |
| 314 // Duplicate the value on the stack in case it's needed. |
| 315 __ ldr(ip, MemOperand(sp)); |
| 316 __ push(ip); |
| 317 // Fall through. |
| 318 |
262 case Expression::kTest: | 319 case Expression::kTest: |
263 __ pop(r0); | 320 DoTest(context); |
264 TestAndBranch(r0, true_label_, false_label_); | |
265 break; | 321 break; |
266 case Expression::kValueTest: { | |
267 Label discard; | |
268 __ ldr(r0, MemOperand(sp, 0)); | |
269 TestAndBranch(r0, true_label_, &discard); | |
270 __ bind(&discard); | |
271 __ Drop(1); | |
272 __ jmp(false_label_); | |
273 break; | |
274 } | |
275 case Expression::kTestValue: { | |
276 Label discard; | |
277 __ ldr(r0, MemOperand(sp, 0)); | |
278 TestAndBranch(r0, &discard, false_label_); | |
279 __ bind(&discard); | |
280 __ Drop(1); | |
281 __ jmp(true_label_); | |
282 } | |
283 } | 322 } |
284 } | 323 } |
285 | 324 |
286 | 325 |
287 void FastCodeGenerator::DropAndApply(int count, | 326 void FastCodeGenerator::DropAndApply(int count, |
288 Expression::Context context, | 327 Expression::Context context, |
289 Register reg) { | 328 Register reg) { |
290 ASSERT(count > 0); | 329 ASSERT(count > 0); |
291 ASSERT(!reg.is(sp)); | 330 ASSERT(!reg.is(sp)); |
292 switch (context) { | 331 switch (context) { |
293 case Expression::kUninitialized: | 332 case Expression::kUninitialized: |
294 UNREACHABLE(); | 333 UNREACHABLE(); |
| 334 |
295 case Expression::kEffect: | 335 case Expression::kEffect: |
296 __ Drop(count); | 336 __ Drop(count); |
297 break; | 337 break; |
| 338 |
298 case Expression::kValue: | 339 case Expression::kValue: |
| 340 switch (location_) { |
| 341 case kAccumulator: |
| 342 __ Drop(count); |
| 343 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 344 break; |
| 345 case kStack: |
| 346 if (count > 1) __ Drop(count - 1); |
| 347 __ str(reg, MemOperand(sp)); |
| 348 break; |
| 349 } |
| 350 break; |
| 351 |
| 352 case Expression::kTest: |
299 if (count > 1) __ Drop(count - 1); | 353 if (count > 1) __ Drop(count - 1); |
300 __ str(reg, MemOperand(sp)); | 354 __ str(reg, MemOperand(sp)); |
| 355 DoTest(context); |
301 break; | 356 break; |
| 357 |
| 358 case Expression::kValueTest: |
| 359 case Expression::kTestValue: |
| 360 if (count == 1) { |
| 361 __ str(reg, MemOperand(sp)); |
| 362 __ push(reg); |
| 363 } else { // count > 1 |
| 364 __ Drop(count - 2); |
| 365 __ str(reg, MemOperand(sp, kPointerSize)); |
| 366 __ str(reg, MemOperand(sp)); |
| 367 } |
| 368 DoTest(context); |
| 369 break; |
| 370 } |
| 371 } |
| 372 |
| 373 |
| 374 void FastCodeGenerator::Apply(Expression::Context context, |
| 375 Label* materialize_true, |
| 376 Label* materialize_false) { |
| 377 switch (context) { |
| 378 case Expression::kUninitialized: |
| 379 |
| 380 case Expression::kEffect: |
| 381 ASSERT_EQ(materialize_true, materialize_false); |
| 382 __ bind(materialize_true); |
| 383 break; |
| 384 |
| 385 case Expression::kValue: { |
| 386 Label done; |
| 387 __ bind(materialize_true); |
| 388 __ mov(result_register(), Operand(Factory::true_value())); |
| 389 __ jmp(&done); |
| 390 __ bind(materialize_false); |
| 391 __ mov(result_register(), Operand(Factory::false_value())); |
| 392 __ bind(&done); |
| 393 switch (location_) { |
| 394 case kAccumulator: |
| 395 break; |
| 396 case kStack: |
| 397 __ push(result_register()); |
| 398 break; |
| 399 } |
| 400 break; |
| 401 } |
| 402 |
302 case Expression::kTest: | 403 case Expression::kTest: |
303 __ Drop(count); | |
304 TestAndBranch(reg, true_label_, false_label_); | |
305 break; | 404 break; |
| 405 |
| 406 case Expression::kValueTest: |
| 407 __ bind(materialize_true); |
| 408 __ mov(result_register(), Operand(Factory::true_value())); |
| 409 switch (location_) { |
| 410 case kAccumulator: |
| 411 break; |
| 412 case kStack: |
| 413 __ push(result_register()); |
| 414 break; |
| 415 } |
| 416 __ jmp(true_label_); |
| 417 break; |
| 418 |
| 419 case Expression::kTestValue: |
| 420 __ bind(materialize_false); |
| 421 __ mov(result_register(), Operand(Factory::false_value())); |
| 422 switch (location_) { |
| 423 case kAccumulator: |
| 424 break; |
| 425 case kStack: |
| 426 __ push(result_register()); |
| 427 break; |
| 428 } |
| 429 __ jmp(false_label_); |
| 430 break; |
| 431 } |
| 432 } |
| 433 |
| 434 |
| 435 void FastCodeGenerator::DoTest(Expression::Context context) { |
| 436 // The value to test is pushed on the stack, and duplicated on the stack |
| 437 // if necessary (for value/test and test/value contexts). |
| 438 ASSERT_NE(NULL, true_label_); |
| 439 ASSERT_NE(NULL, false_label_); |
| 440 |
| 441 // Call the runtime to find the boolean value of the source and then |
| 442 // translate it into control flow to the pair of labels. |
| 443 __ CallRuntime(Runtime::kToBool, 1); |
| 444 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 445 __ cmp(r0, ip); |
| 446 |
| 447 // Complete based on the context. |
| 448 switch (context) { |
| 449 case Expression::kUninitialized: |
| 450 case Expression::kEffect: |
| 451 case Expression::kValue: |
| 452 UNREACHABLE(); |
| 453 |
| 454 case Expression::kTest: |
| 455 __ b(eq, true_label_); |
| 456 __ jmp(false_label_); |
| 457 break; |
| 458 |
306 case Expression::kValueTest: { | 459 case Expression::kValueTest: { |
307 Label discard; | 460 Label discard; |
308 if (count > 1) __ Drop(count - 1); | 461 switch (location_) { |
309 __ str(reg, MemOperand(sp)); | 462 case kAccumulator: |
310 TestAndBranch(reg, true_label_, &discard); | 463 __ b(ne, &discard); |
| 464 __ pop(result_register()); |
| 465 __ jmp(true_label_); |
| 466 break; |
| 467 case kStack: |
| 468 __ b(eq, true_label_); |
| 469 break; |
| 470 } |
311 __ bind(&discard); | 471 __ bind(&discard); |
312 __ Drop(1); | 472 __ Drop(1); |
313 __ jmp(false_label_); | 473 __ jmp(false_label_); |
314 break; | 474 break; |
315 } | 475 } |
| 476 |
316 case Expression::kTestValue: { | 477 case Expression::kTestValue: { |
317 Label discard; | 478 Label discard; |
318 if (count > 1) __ Drop(count - 1); | 479 switch (location_) { |
319 __ str(reg, MemOperand(sp)); | 480 case kAccumulator: |
320 TestAndBranch(reg, &discard, false_label_); | 481 __ b(eq, &discard); |
| 482 __ pop(result_register()); |
| 483 __ jmp(false_label_); |
| 484 break; |
| 485 case kStack: |
| 486 __ b(ne, false_label_); |
| 487 break; |
| 488 } |
321 __ bind(&discard); | 489 __ bind(&discard); |
322 __ Drop(1); | 490 __ Drop(1); |
323 __ jmp(true_label_); | 491 __ jmp(true_label_); |
324 break; | 492 break; |
325 } | 493 } |
326 } | 494 } |
327 } | 495 } |
328 | 496 |
329 | 497 |
330 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 498 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
(...skipping 10 matching lines...) Expand all Loading... |
341 case Slot::LOOKUP: | 509 case Slot::LOOKUP: |
342 UNREACHABLE(); | 510 UNREACHABLE(); |
343 } | 511 } |
344 UNREACHABLE(); | 512 UNREACHABLE(); |
345 return MemOperand(r0, 0); | 513 return MemOperand(r0, 0); |
346 } | 514 } |
347 | 515 |
348 | 516 |
349 void FastCodeGenerator::Move(Register destination, Slot* source) { | 517 void FastCodeGenerator::Move(Register destination, Slot* source) { |
350 // Use destination as scratch. | 518 // Use destination as scratch. |
351 MemOperand location = EmitSlotSearch(source, destination); | 519 MemOperand slot_operand = EmitSlotSearch(source, destination); |
352 __ ldr(destination, location); | 520 __ ldr(destination, slot_operand); |
353 } | 521 } |
354 | 522 |
355 | 523 |
356 | |
357 void FastCodeGenerator::Move(Slot* dst, | 524 void FastCodeGenerator::Move(Slot* dst, |
358 Register src, | 525 Register src, |
359 Register scratch1, | 526 Register scratch1, |
360 Register scratch2) { | 527 Register scratch2) { |
361 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 528 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
362 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 529 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
363 MemOperand location = EmitSlotSearch(dst, scratch1); | 530 MemOperand location = EmitSlotSearch(dst, scratch1); |
364 __ str(src, location); | 531 __ str(src, location); |
365 // Emit the write barrier code if the location is in the heap. | 532 // Emit the write barrier code if the location is in the heap. |
366 if (dst->type() == Slot::CONTEXT) { | 533 if (dst->type() == Slot::CONTEXT) { |
367 __ mov(scratch2, Operand(Context::SlotOffset(dst->index()))); | 534 __ mov(scratch2, Operand(Context::SlotOffset(dst->index()))); |
368 __ RecordWrite(scratch1, scratch2, src); | 535 __ RecordWrite(scratch1, scratch2, src); |
369 } | 536 } |
370 } | 537 } |
371 | 538 |
372 | 539 |
373 | |
374 void FastCodeGenerator::TestAndBranch(Register source, | |
375 Label* true_label, | |
376 Label* false_label) { | |
377 ASSERT_NE(NULL, true_label); | |
378 ASSERT_NE(NULL, false_label); | |
379 // Call the runtime to find the boolean value of the source and then | |
380 // translate it into control flow to the pair of labels. | |
381 __ push(source); | |
382 __ CallRuntime(Runtime::kToBool, 1); | |
383 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
384 __ cmp(r0, ip); | |
385 __ b(eq, true_label); | |
386 __ jmp(false_label); | |
387 } | |
388 | |
389 | |
390 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | 540 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
391 Comment cmnt(masm_, "[ Declaration"); | 541 Comment cmnt(masm_, "[ Declaration"); |
392 Variable* var = decl->proxy()->var(); | 542 Variable* var = decl->proxy()->var(); |
393 ASSERT(var != NULL); // Must have been resolved. | 543 ASSERT(var != NULL); // Must have been resolved. |
394 Slot* slot = var->slot(); | 544 Slot* slot = var->slot(); |
395 Property* prop = var->AsProperty(); | 545 Property* prop = var->AsProperty(); |
396 | 546 |
397 if (slot != NULL) { | 547 if (slot != NULL) { |
398 switch (slot->type()) { | 548 switch (slot->type()) { |
399 case Slot::PARAMETER: | 549 case Slot::PARAMETER: |
400 case Slot::LOCAL: | 550 case Slot::LOCAL: |
401 if (decl->mode() == Variable::CONST) { | 551 if (decl->mode() == Variable::CONST) { |
402 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 552 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
403 __ str(ip, MemOperand(fp, SlotOffset(slot))); | 553 __ str(ip, MemOperand(fp, SlotOffset(slot))); |
404 } else if (decl->fun() != NULL) { | 554 } else if (decl->fun() != NULL) { |
405 Visit(decl->fun()); | 555 VisitForValue(decl->fun(), kAccumulator); |
406 __ pop(ip); | 556 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); |
407 __ str(ip, MemOperand(fp, SlotOffset(slot))); | |
408 } | 557 } |
409 break; | 558 break; |
410 | 559 |
411 case Slot::CONTEXT: | 560 case Slot::CONTEXT: |
412 // We bypass the general EmitSlotSearch because we know more about | 561 // We bypass the general EmitSlotSearch because we know more about |
413 // this specific context. | 562 // this specific context. |
414 | 563 |
415 // The variable in the decl always resides in the current context. | 564 // The variable in the decl always resides in the current context. |
416 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 565 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
417 if (FLAG_debug_code) { | 566 if (FLAG_debug_code) { |
418 // Check if we have the correct context pointer. | 567 // Check if we have the correct context pointer. |
419 __ ldr(r1, | 568 __ ldr(r1, |
420 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); | 569 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); |
421 __ cmp(r1, cp); | 570 __ cmp(r1, cp); |
422 __ Check(eq, "Unexpected declaration in current context."); | 571 __ Check(eq, "Unexpected declaration in current context."); |
423 } | 572 } |
424 if (decl->mode() == Variable::CONST) { | 573 if (decl->mode() == Variable::CONST) { |
425 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 574 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
426 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index())); | 575 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index())); |
427 // No write barrier since the_hole_value is in old space. | 576 // No write barrier since the_hole_value is in old space. |
428 } else if (decl->fun() != NULL) { | 577 } else if (decl->fun() != NULL) { |
429 Visit(decl->fun()); | 578 VisitForValue(decl->fun(), kAccumulator); |
430 __ pop(r0); | 579 __ str(result_register(), |
431 __ str(r0, CodeGenerator::ContextOperand(cp, slot->index())); | 580 CodeGenerator::ContextOperand(cp, slot->index())); |
432 int offset = Context::SlotOffset(slot->index()); | 581 int offset = Context::SlotOffset(slot->index()); |
433 __ mov(r2, Operand(offset)); | 582 __ mov(r2, Operand(offset)); |
434 // We know that we have written a function, which is not a smi. | 583 // We know that we have written a function, which is not a smi. |
435 __ RecordWrite(cp, r2, r0); | 584 __ RecordWrite(cp, r2, result_register()); |
436 } | 585 } |
437 break; | 586 break; |
438 | 587 |
439 case Slot::LOOKUP: { | 588 case Slot::LOOKUP: { |
440 __ mov(r2, Operand(var->name())); | 589 __ mov(r2, Operand(var->name())); |
441 // Declaration nodes are always introduced in one of two modes. | 590 // Declaration nodes are always introduced in one of two modes. |
442 ASSERT(decl->mode() == Variable::VAR || | 591 ASSERT(decl->mode() == Variable::VAR || |
443 decl->mode() == Variable::CONST); | 592 decl->mode() == Variable::CONST); |
444 PropertyAttributes attr = | 593 PropertyAttributes attr = |
445 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; | 594 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; |
446 __ mov(r1, Operand(Smi::FromInt(attr))); | 595 __ mov(r1, Operand(Smi::FromInt(attr))); |
447 // Push initial value, if any. | 596 // Push initial value, if any. |
448 // Note: For variables we must not push an initial value (such as | 597 // Note: For variables we must not push an initial value (such as |
449 // 'undefined') because we may have a (legal) redeclaration and we | 598 // 'undefined') because we may have a (legal) redeclaration and we |
450 // must not destroy the current value. | 599 // must not destroy the current value. |
451 if (decl->mode() == Variable::CONST) { | 600 if (decl->mode() == Variable::CONST) { |
452 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 601 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
453 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit()); | 602 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit()); |
454 } else if (decl->fun() != NULL) { | 603 } else if (decl->fun() != NULL) { |
455 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit()); | 604 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit()); |
456 Visit(decl->fun()); // Initial value for function decl. | 605 // Push initial value for function declaration. |
| 606 VisitForValue(decl->fun(), kStack); |
457 } else { | 607 } else { |
458 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! | 608 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! |
459 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit()); | 609 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit()); |
460 } | 610 } |
461 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 611 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
462 break; | 612 break; |
463 } | 613 } |
464 } | 614 } |
465 | 615 |
466 } else if (prop != NULL) { | 616 } else if (prop != NULL) { |
467 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 617 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
468 // We are declaring a function or constant that rewrites to a | 618 // We are declaring a function or constant that rewrites to a |
469 // property. Use (keyed) IC to set the initial value. | 619 // property. Use (keyed) IC to set the initial value. |
470 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | 620 VisitForValue(prop->obj(), kStack); |
471 Visit(prop->obj()); | 621 VisitForValue(prop->key(), kStack); |
472 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
473 Visit(prop->key()); | |
474 | 622 |
475 if (decl->fun() != NULL) { | 623 if (decl->fun() != NULL) { |
476 ASSERT_EQ(Expression::kValue, decl->fun()->context()); | 624 VisitForValue(decl->fun(), kAccumulator); |
477 Visit(decl->fun()); | |
478 __ pop(r0); | |
479 } else { | 625 } else { |
480 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 626 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); |
481 } | 627 } |
482 | 628 |
483 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 629 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
484 __ Call(ic, RelocInfo::CODE_TARGET); | 630 __ Call(ic, RelocInfo::CODE_TARGET); |
485 | 631 |
486 // Value in r0 is ignored (declarations are statements). Receiver | 632 // Value in r0 is ignored (declarations are statements). Receiver |
487 // and key on stack are discarded. | 633 // and key on stack are discarded. |
488 __ Drop(2); | 634 __ Drop(2); |
489 } | 635 } |
490 } | 636 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 } | 697 } |
552 case Slot::CONTEXT: { | 698 case Slot::CONTEXT: { |
553 Comment cmnt(masm_, "Context slot"); | 699 Comment cmnt(masm_, "Context slot"); |
554 break; | 700 break; |
555 } | 701 } |
556 case Slot::LOOKUP: | 702 case Slot::LOOKUP: |
557 UNIMPLEMENTED(); | 703 UNIMPLEMENTED(); |
558 break; | 704 break; |
559 } | 705 } |
560 } | 706 } |
561 Apply(context, slot, r0); | 707 Apply(context, slot); |
562 } else { | 708 } else { |
563 Comment cmnt(masm_, "Variable rewritten to property"); | 709 Comment cmnt(masm_, "Variable rewritten to property"); |
564 // A variable has been rewritten into an explicit access to an object | 710 // A variable has been rewritten into an explicit access to an object |
565 // property. | 711 // property. |
566 Property* property = rewrite->AsProperty(); | 712 Property* property = rewrite->AsProperty(); |
567 ASSERT_NOT_NULL(property); | 713 ASSERT_NOT_NULL(property); |
568 | 714 |
569 // The only property expressions that can occur are of the form | 715 // The only property expressions that can occur are of the form |
570 // "slot[literal]". | 716 // "slot[literal]". |
571 | 717 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); | 778 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); |
633 __ mov(r1, Operand(Smi::FromInt(expr->literal_index()))); | 779 __ mov(r1, Operand(Smi::FromInt(expr->literal_index()))); |
634 __ mov(r0, Operand(expr->constant_properties())); | 780 __ mov(r0, Operand(expr->constant_properties())); |
635 __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit()); | 781 __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit()); |
636 if (expr->depth() > 1) { | 782 if (expr->depth() > 1) { |
637 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); | 783 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); |
638 } else { | 784 } else { |
639 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 785 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
640 } | 786 } |
641 | 787 |
642 // If result_saved == true: The result is saved on top of the | 788 // If result_saved is true the result is on top of the stack. If |
643 // stack and in r0. | 789 // result_saved is false the result is in r0. |
644 // If result_saved == false: The result not on the stack, just in r0. | |
645 bool result_saved = false; | 790 bool result_saved = false; |
646 | 791 |
647 for (int i = 0; i < expr->properties()->length(); i++) { | 792 for (int i = 0; i < expr->properties()->length(); i++) { |
648 ObjectLiteral::Property* property = expr->properties()->at(i); | 793 ObjectLiteral::Property* property = expr->properties()->at(i); |
649 if (property->IsCompileTimeValue()) continue; | 794 if (property->IsCompileTimeValue()) continue; |
650 | 795 |
651 Literal* key = property->key(); | 796 Literal* key = property->key(); |
652 Expression* value = property->value(); | 797 Expression* value = property->value(); |
653 if (!result_saved) { | 798 if (!result_saved) { |
654 __ push(r0); // Save result on stack | 799 __ push(r0); // Save result on stack |
655 result_saved = true; | 800 result_saved = true; |
656 } | 801 } |
657 switch (property->kind()) { | 802 switch (property->kind()) { |
658 case ObjectLiteral::Property::CONSTANT: | 803 case ObjectLiteral::Property::CONSTANT: |
659 UNREACHABLE(); | 804 UNREACHABLE(); |
660 | 805 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
661 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through. | |
662 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); | 806 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 807 // Fall through. |
663 case ObjectLiteral::Property::COMPUTED: | 808 case ObjectLiteral::Property::COMPUTED: |
664 if (key->handle()->IsSymbol()) { | 809 if (key->handle()->IsSymbol()) { |
665 Visit(value); | 810 VisitForValue(value, kAccumulator); |
666 ASSERT_EQ(Expression::kValue, value->context()); | |
667 __ pop(r0); | |
668 __ mov(r2, Operand(key->handle())); | 811 __ mov(r2, Operand(key->handle())); |
669 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 812 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
670 __ Call(ic, RelocInfo::CODE_TARGET); | 813 __ Call(ic, RelocInfo::CODE_TARGET); |
671 // StoreIC leaves the receiver on the stack. | 814 // StoreIC leaves the receiver on the stack. |
672 __ ldr(r0, MemOperand(sp)); // Restore result into r0. | |
673 break; | 815 break; |
674 } | 816 } |
675 // Fall through. | 817 // Fall through. |
676 | |
677 case ObjectLiteral::Property::PROTOTYPE: | 818 case ObjectLiteral::Property::PROTOTYPE: |
| 819 // Duplicate receiver on stack. |
| 820 __ ldr(r0, MemOperand(sp)); |
678 __ push(r0); | 821 __ push(r0); |
679 Visit(key); | 822 VisitForValue(key, kStack); |
680 ASSERT_EQ(Expression::kValue, key->context()); | 823 VisitForValue(value, kStack); |
681 Visit(value); | |
682 ASSERT_EQ(Expression::kValue, value->context()); | |
683 __ CallRuntime(Runtime::kSetProperty, 3); | 824 __ CallRuntime(Runtime::kSetProperty, 3); |
684 __ ldr(r0, MemOperand(sp)); // Restore result into r0. | |
685 break; | 825 break; |
686 | |
687 case ObjectLiteral::Property::GETTER: | 826 case ObjectLiteral::Property::GETTER: |
688 case ObjectLiteral::Property::SETTER: | 827 case ObjectLiteral::Property::SETTER: |
| 828 // Duplicate receiver on stack. |
| 829 __ ldr(r0, MemOperand(sp)); |
689 __ push(r0); | 830 __ push(r0); |
690 Visit(key); | 831 VisitForValue(key, kStack); |
691 ASSERT_EQ(Expression::kValue, key->context()); | |
692 __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ? | 832 __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ? |
693 Smi::FromInt(1) : | 833 Smi::FromInt(1) : |
694 Smi::FromInt(0))); | 834 Smi::FromInt(0))); |
695 __ push(r1); | 835 __ push(r1); |
696 Visit(value); | 836 VisitForValue(value, kStack); |
697 ASSERT_EQ(Expression::kValue, value->context()); | |
698 __ CallRuntime(Runtime::kDefineAccessor, 4); | 837 __ CallRuntime(Runtime::kDefineAccessor, 4); |
699 __ ldr(r0, MemOperand(sp)); // Restore result into r0 | |
700 break; | 838 break; |
701 } | 839 } |
702 } | 840 } |
703 switch (expr->context()) { | 841 |
704 case Expression::kUninitialized: | 842 if (result_saved) { |
705 UNREACHABLE(); | 843 ApplyTOS(expr->context()); |
706 case Expression::kEffect: | 844 } else { |
707 if (result_saved) __ Drop(1); | 845 Apply(expr->context(), r0); |
708 break; | |
709 case Expression::kValue: | |
710 if (!result_saved) __ push(r0); | |
711 break; | |
712 case Expression::kTest: | |
713 if (result_saved) __ pop(r0); | |
714 TestAndBranch(r0, true_label_, false_label_); | |
715 break; | |
716 case Expression::kValueTest: { | |
717 Label discard; | |
718 if (!result_saved) __ push(r0); | |
719 TestAndBranch(r0, true_label_, &discard); | |
720 __ bind(&discard); | |
721 __ Drop(1); | |
722 __ jmp(false_label_); | |
723 break; | |
724 } | |
725 case Expression::kTestValue: { | |
726 Label discard; | |
727 if (!result_saved) __ push(r0); | |
728 TestAndBranch(r0, &discard, false_label_); | |
729 __ bind(&discard); | |
730 __ Drop(1); | |
731 __ jmp(true_label_); | |
732 break; | |
733 } | |
734 } | 846 } |
735 } | 847 } |
736 | 848 |
737 | 849 |
738 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 850 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
739 Comment cmnt(masm_, "[ ArrayLiteral"); | 851 Comment cmnt(masm_, "[ ArrayLiteral"); |
740 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 852 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
741 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); | 853 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
742 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); | 854 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); |
743 __ mov(r1, Operand(expr->constant_elements())); | 855 __ mov(r1, Operand(expr->constant_elements())); |
(...skipping 15 matching lines...) Expand all Loading... |
759 // is already set in the cloned array. | 871 // is already set in the cloned array. |
760 if (subexpr->AsLiteral() != NULL || | 872 if (subexpr->AsLiteral() != NULL || |
761 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 873 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
762 continue; | 874 continue; |
763 } | 875 } |
764 | 876 |
765 if (!result_saved) { | 877 if (!result_saved) { |
766 __ push(r0); | 878 __ push(r0); |
767 result_saved = true; | 879 result_saved = true; |
768 } | 880 } |
769 Visit(subexpr); | 881 VisitForValue(subexpr, kAccumulator); |
770 ASSERT_EQ(Expression::kValue, subexpr->context()); | |
771 | 882 |
772 // Store the subexpression value in the array's elements. | 883 // Store the subexpression value in the array's elements. |
773 __ pop(r0); // Subexpression value. | |
774 __ ldr(r1, MemOperand(sp)); // Copy of array literal. | 884 __ ldr(r1, MemOperand(sp)); // Copy of array literal. |
775 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 885 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
776 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 886 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
777 __ str(r0, FieldMemOperand(r1, offset)); | 887 __ str(result_register(), FieldMemOperand(r1, offset)); |
778 | 888 |
779 // Update the write barrier for the array store with r0 as the scratch | 889 // Update the write barrier for the array store with r0 as the scratch |
780 // register. | 890 // register. |
781 __ mov(r2, Operand(offset)); | 891 __ mov(r2, Operand(offset)); |
782 __ RecordWrite(r1, r2, r0); | 892 __ RecordWrite(r1, r2, result_register()); |
783 } | 893 } |
784 | 894 |
785 switch (expr->context()) { | 895 if (result_saved) { |
786 case Expression::kUninitialized: | 896 ApplyTOS(expr->context()); |
787 UNREACHABLE(); | 897 } else { |
788 case Expression::kEffect: | 898 Apply(expr->context(), r0); |
789 if (result_saved) __ Drop(1); | |
790 break; | |
791 case Expression::kValue: | |
792 if (!result_saved) __ push(r0); | |
793 break; | |
794 case Expression::kTest: | |
795 if (result_saved) __ pop(r0); | |
796 TestAndBranch(r0, true_label_, false_label_); | |
797 break; | |
798 case Expression::kValueTest: { | |
799 Label discard; | |
800 if (!result_saved) __ push(r0); | |
801 TestAndBranch(r0, true_label_, &discard); | |
802 __ bind(&discard); | |
803 __ Drop(1); | |
804 __ jmp(false_label_); | |
805 break; | |
806 } | |
807 case Expression::kTestValue: { | |
808 Label discard; | |
809 if (!result_saved) __ push(r0); | |
810 TestAndBranch(r0, &discard, false_label_); | |
811 __ bind(&discard); | |
812 __ Drop(1); | |
813 __ jmp(true_label_); | |
814 break; | |
815 } | |
816 } | 899 } |
817 } | 900 } |
818 | 901 |
819 | 902 |
820 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 903 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
821 SetSourcePosition(prop->position()); | 904 SetSourcePosition(prop->position()); |
822 Literal* key = prop->key()->AsLiteral(); | 905 Literal* key = prop->key()->AsLiteral(); |
823 __ mov(r2, Operand(key->handle())); | 906 __ mov(r2, Operand(key->handle())); |
824 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 907 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
825 __ Call(ic, RelocInfo::CODE_TARGET); | 908 __ Call(ic, RelocInfo::CODE_TARGET); |
826 } | 909 } |
827 | 910 |
828 | 911 |
829 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 912 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
830 SetSourcePosition(prop->position()); | 913 SetSourcePosition(prop->position()); |
831 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 914 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
832 __ Call(ic, RelocInfo::CODE_TARGET); | 915 __ Call(ic, RelocInfo::CODE_TARGET); |
833 } | 916 } |
834 | 917 |
835 | 918 |
836 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 919 void FastCodeGenerator::EmitBinaryOp(Token::Value op, |
837 Expression::Context context) { | 920 Expression::Context context) { |
838 __ pop(r0); | |
839 __ pop(r1); | 921 __ pop(r1); |
840 GenericBinaryOpStub stub(op, | 922 GenericBinaryOpStub stub(op, NO_OVERWRITE); |
841 NO_OVERWRITE); | |
842 __ CallStub(&stub); | 923 __ CallStub(&stub); |
843 Apply(context, r0); | 924 Apply(context, r0); |
844 } | 925 } |
845 | 926 |
846 | 927 |
847 void FastCodeGenerator::EmitVariableAssignment(Variable* var, | 928 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
848 Expression::Context context) { | 929 Expression::Context context) { |
849 ASSERT(var != NULL); | 930 ASSERT(var != NULL); |
850 ASSERT(var->is_global() || var->slot() != NULL); | 931 ASSERT(var->is_global() || var->slot() != NULL); |
851 if (var->is_global()) { | 932 if (var->is_global()) { |
852 // Assignment to a global variable. Use inline caching for the | 933 // Assignment to a global variable. Use inline caching for the |
853 // assignment. Right-hand-side value is passed in r0, variable name in | 934 // assignment. Right-hand-side value is passed in r0, variable name in |
854 // r2, and the global object on the stack. | 935 // r2, and the global object on the stack. |
855 __ pop(r0); | |
856 __ mov(r2, Operand(var->name())); | 936 __ mov(r2, Operand(var->name())); |
857 __ ldr(ip, CodeGenerator::GlobalObject()); | 937 __ ldr(ip, CodeGenerator::GlobalObject()); |
858 __ push(ip); | 938 __ push(ip); |
859 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 939 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
860 __ Call(ic, RelocInfo::CODE_TARGET); | 940 __ Call(ic, RelocInfo::CODE_TARGET); |
861 // Overwrite the global object on the stack with the result if needed. | 941 // Overwrite the global object on the stack with the result if needed. |
862 DropAndApply(1, context, r0); | 942 DropAndApply(1, context, r0); |
863 | 943 |
864 } else if (var->slot() != NULL) { | 944 } else if (var->slot() != NULL) { |
865 Slot* slot = var->slot(); | 945 Slot* slot = var->slot(); |
866 switch (slot->type()) { | 946 switch (slot->type()) { |
867 case Slot::LOCAL: | 947 case Slot::LOCAL: |
868 case Slot::PARAMETER: { | 948 case Slot::PARAMETER: |
869 MemOperand target = MemOperand(fp, SlotOffset(slot)); | 949 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); |
870 switch (context) { | 950 break; |
871 case Expression::kUninitialized: | 951 |
872 UNREACHABLE(); | 952 case Slot::CONTEXT: { |
873 case Expression::kEffect: | 953 MemOperand target = EmitSlotSearch(slot, r1); |
874 // Perform assignment and discard value. | 954 __ str(result_register(), target); |
875 __ pop(r0); | 955 |
876 __ str(r0, target); | 956 // RecordWrite may destroy all its register arguments. |
877 break; | 957 __ mov(r3, result_register()); |
878 case Expression::kValue: | 958 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
879 // Perform assignment and preserve value. | 959 |
880 __ ldr(r0, MemOperand(sp)); | 960 __ mov(r2, Operand(offset)); |
881 __ str(r0, target); | 961 __ RecordWrite(r1, r2, r3); |
882 break; | |
883 case Expression::kTest: | |
884 // Perform assignment and test (and discard) value. | |
885 __ pop(r0); | |
886 __ str(r0, target); | |
887 TestAndBranch(r0, true_label_, false_label_); | |
888 break; | |
889 case Expression::kValueTest: { | |
890 Label discard; | |
891 __ ldr(r0, MemOperand(sp)); | |
892 __ str(r0, target); | |
893 TestAndBranch(r0, true_label_, &discard); | |
894 __ bind(&discard); | |
895 __ Drop(1); | |
896 __ jmp(false_label_); | |
897 break; | |
898 } | |
899 case Expression::kTestValue: { | |
900 Label discard; | |
901 __ ldr(r0, MemOperand(sp)); | |
902 __ str(r0, target); | |
903 TestAndBranch(r0, &discard, false_label_); | |
904 __ bind(&discard); | |
905 __ Drop(1); | |
906 __ jmp(true_label_); | |
907 break; | |
908 } | |
909 } | |
910 break; | 962 break; |
911 } | 963 } |
912 | 964 |
913 case Slot::CONTEXT: { | |
914 MemOperand target = EmitSlotSearch(slot, r1); | |
915 __ pop(r0); | |
916 __ str(r0, target); | |
917 | |
918 // RecordWrite may destroy all its register arguments. | |
919 if (context == Expression::kValue) { | |
920 __ push(r0); | |
921 } else if (context != Expression::kEffect) { | |
922 __ mov(r3, r0); | |
923 } | |
924 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
925 | |
926 // Update the write barrier for the array store with r0 as the scratch | |
927 // register. Skip the write barrier if the value written (r1) is a smi. | |
928 // The smi test is part of RecordWrite on other platforms, not on arm. | |
929 Label exit; | |
930 __ tst(r0, Operand(kSmiTagMask)); | |
931 __ b(eq, &exit); | |
932 | |
933 __ mov(r2, Operand(offset)); | |
934 __ RecordWrite(r1, r2, r0); | |
935 __ bind(&exit); | |
936 if (context != Expression::kEffect && context != Expression::kValue) { | |
937 Apply(context, r3); | |
938 } | |
939 break; | |
940 } | |
941 | |
942 case Slot::LOOKUP: | 965 case Slot::LOOKUP: |
943 UNREACHABLE(); | 966 UNREACHABLE(); |
944 break; | 967 break; |
945 } | 968 } |
| 969 Apply(context, result_register()); |
946 } else { | 970 } else { |
947 // Variables rewritten as properties are not treated as variables in | 971 // Variables rewritten as properties are not treated as variables in |
948 // assignments. | 972 // assignments. |
949 UNREACHABLE(); | 973 UNREACHABLE(); |
950 } | 974 } |
951 } | 975 } |
952 | 976 |
953 | 977 |
954 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 978 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
955 // Assignment to a property, using a named store IC. | 979 // Assignment to a property, using a named store IC. |
956 Property* prop = expr->target()->AsProperty(); | 980 Property* prop = expr->target()->AsProperty(); |
957 ASSERT(prop != NULL); | 981 ASSERT(prop != NULL); |
958 ASSERT(prop->key()->AsLiteral() != NULL); | 982 ASSERT(prop->key()->AsLiteral() != NULL); |
959 | 983 |
960 // If the assignment starts a block of assignments to the same object, | 984 // If the assignment starts a block of assignments to the same object, |
961 // change to slow case to avoid the quadratic behavior of repeatedly | 985 // change to slow case to avoid the quadratic behavior of repeatedly |
962 // adding fast properties. | 986 // adding fast properties. |
963 if (expr->starts_initialization_block()) { | 987 if (expr->starts_initialization_block()) { |
964 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. | 988 __ push(result_register()); |
| 989 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value. |
965 __ push(ip); | 990 __ push(ip); |
966 __ CallRuntime(Runtime::kToSlowProperties, 1); | 991 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 992 __ pop(result_register()); |
967 } | 993 } |
968 | 994 |
969 // Record source code position before IC call. | 995 // Record source code position before IC call. |
970 SetSourcePosition(expr->position()); | 996 SetSourcePosition(expr->position()); |
971 | |
972 __ pop(r0); | |
973 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); | 997 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); |
974 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 998 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
975 __ Call(ic, RelocInfo::CODE_TARGET); | 999 __ Call(ic, RelocInfo::CODE_TARGET); |
976 | 1000 |
977 // If the assignment ends an initialization block, revert to fast case. | 1001 // If the assignment ends an initialization block, revert to fast case. |
978 if (expr->ends_initialization_block()) { | 1002 if (expr->ends_initialization_block()) { |
979 __ push(r0); // Result of assignment, saved even if not needed. | 1003 __ push(r0); // Result of assignment, saved even if not needed. |
980 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. | 1004 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value. |
981 __ push(ip); | 1005 __ push(ip); |
982 __ CallRuntime(Runtime::kToFastProperties, 1); | 1006 __ CallRuntime(Runtime::kToFastProperties, 1); |
983 __ pop(r0); | 1007 __ pop(r0); |
984 } | 1008 } |
985 | 1009 |
986 DropAndApply(1, expr->context(), r0); | 1010 DropAndApply(1, expr->context(), r0); |
987 } | 1011 } |
988 | 1012 |
989 | 1013 |
990 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1014 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
991 // Assignment to a property, using a keyed store IC. | 1015 // Assignment to a property, using a keyed store IC. |
992 | 1016 |
993 // If the assignment starts a block of assignments to the same object, | 1017 // If the assignment starts a block of assignments to the same object, |
994 // change to slow case to avoid the quadratic behavior of repeatedly | 1018 // change to slow case to avoid the quadratic behavior of repeatedly |
995 // adding fast properties. | 1019 // adding fast properties. |
996 if (expr->starts_initialization_block()) { | 1020 if (expr->starts_initialization_block()) { |
997 // Receiver is under the key and value. | 1021 __ push(result_register()); |
| 1022 // Receiver is now under the key and value. |
998 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); | 1023 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); |
999 __ push(ip); | 1024 __ push(ip); |
1000 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1025 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1026 __ pop(result_register()); |
1001 } | 1027 } |
1002 | 1028 |
1003 // Record source code position before IC call. | 1029 // Record source code position before IC call. |
1004 SetSourcePosition(expr->position()); | 1030 SetSourcePosition(expr->position()); |
1005 | |
1006 __ pop(r0); | |
1007 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1031 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1008 __ Call(ic, RelocInfo::CODE_TARGET); | 1032 __ Call(ic, RelocInfo::CODE_TARGET); |
1009 | 1033 |
1010 // If the assignment ends an initialization block, revert to fast case. | 1034 // If the assignment ends an initialization block, revert to fast case. |
1011 if (expr->ends_initialization_block()) { | 1035 if (expr->ends_initialization_block()) { |
1012 __ push(r0); // Result of assignment, saved even if not needed. | 1036 __ push(r0); // Result of assignment, saved even if not needed. |
1013 // Reciever is under the key and value. | 1037 // Receiver is under the key and value. |
1014 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); | 1038 __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); |
1015 __ push(ip); | 1039 __ push(ip); |
1016 __ CallRuntime(Runtime::kToFastProperties, 1); | 1040 __ CallRuntime(Runtime::kToFastProperties, 1); |
1017 __ pop(r0); | 1041 __ pop(r0); |
1018 } | 1042 } |
1019 | 1043 |
1020 // Receiver and key are still on stack. | 1044 // Receiver and key are still on stack. |
1021 DropAndApply(2, expr->context(), r0); | 1045 DropAndApply(2, expr->context(), r0); |
1022 } | 1046 } |
1023 | 1047 |
1024 | 1048 |
1025 void FastCodeGenerator::VisitProperty(Property* expr) { | 1049 void FastCodeGenerator::VisitProperty(Property* expr) { |
1026 Comment cmnt(masm_, "[ Property"); | 1050 Comment cmnt(masm_, "[ Property"); |
1027 Expression* key = expr->key(); | 1051 Expression* key = expr->key(); |
1028 | 1052 |
1029 // Evaluate receiver. | 1053 // Evaluate receiver. |
1030 Visit(expr->obj()); | 1054 VisitForValue(expr->obj(), kStack); |
1031 | 1055 |
1032 if (key->IsPropertyName()) { | 1056 if (key->IsPropertyName()) { |
1033 EmitNamedPropertyLoad(expr); | 1057 EmitNamedPropertyLoad(expr); |
1034 // Drop receiver left on the stack by IC. | 1058 // Drop receiver left on the stack by IC. |
1035 DropAndApply(1, expr->context(), r0); | 1059 DropAndApply(1, expr->context(), r0); |
1036 } else { | 1060 } else { |
1037 Visit(expr->key()); | 1061 VisitForValue(expr->key(), kStack); |
1038 EmitKeyedPropertyLoad(expr); | 1062 EmitKeyedPropertyLoad(expr); |
1039 // Drop key and receiver left on the stack by IC. | 1063 // Drop key and receiver left on the stack by IC. |
1040 DropAndApply(2, expr->context(), r0); | 1064 DropAndApply(2, expr->context(), r0); |
1041 } | 1065 } |
1042 } | 1066 } |
1043 | 1067 |
1044 void FastCodeGenerator::EmitCallWithIC(Call* expr, | 1068 void FastCodeGenerator::EmitCallWithIC(Call* expr, |
1045 Handle<Object> ignored, | 1069 Handle<Object> ignored, |
1046 RelocInfo::Mode mode) { | 1070 RelocInfo::Mode mode) { |
1047 // Code common for calls using the IC. | 1071 // Code common for calls using the IC. |
1048 ZoneList<Expression*>* args = expr->arguments(); | 1072 ZoneList<Expression*>* args = expr->arguments(); |
1049 int arg_count = args->length(); | 1073 int arg_count = args->length(); |
1050 for (int i = 0; i < arg_count; i++) { | 1074 for (int i = 0; i < arg_count; i++) { |
1051 Visit(args->at(i)); | 1075 VisitForValue(args->at(i), kStack); |
1052 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1053 } | 1076 } |
1054 // Record source position for debugger. | 1077 // Record source position for debugger. |
1055 SetSourcePosition(expr->position()); | 1078 SetSourcePosition(expr->position()); |
1056 // Call the IC initialization code. | 1079 // Call the IC initialization code. |
1057 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1080 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1058 NOT_IN_LOOP); | 1081 NOT_IN_LOOP); |
1059 __ Call(ic, mode); | 1082 __ Call(ic, mode); |
1060 // Restore context register. | 1083 // Restore context register. |
1061 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1084 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1062 // Discard the function left on TOS. | 1085 // Discard the function left on TOS. |
1063 DropAndApply(1, expr->context(), r0); | 1086 DropAndApply(1, expr->context(), r0); |
1064 } | 1087 } |
1065 | 1088 |
1066 | 1089 |
1067 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 1090 void FastCodeGenerator::EmitCallWithStub(Call* expr) { |
1068 // Code common for calls using the call stub. | 1091 // Code common for calls using the call stub. |
1069 ZoneList<Expression*>* args = expr->arguments(); | 1092 ZoneList<Expression*>* args = expr->arguments(); |
1070 int arg_count = args->length(); | 1093 int arg_count = args->length(); |
1071 for (int i = 0; i < arg_count; i++) { | 1094 for (int i = 0; i < arg_count; i++) { |
1072 Visit(args->at(i)); | 1095 VisitForValue(args->at(i), kStack); |
1073 } | 1096 } |
1074 // Record source position for debugger. | 1097 // Record source position for debugger. |
1075 SetSourcePosition(expr->position()); | 1098 SetSourcePosition(expr->position()); |
1076 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); | 1099 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); |
1077 __ CallStub(&stub); | 1100 __ CallStub(&stub); |
1078 // Restore context register. | 1101 // Restore context register. |
1079 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1102 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1080 // Discard the function left on TOS. | 1103 // Discard the function left on TOS. |
1081 DropAndApply(1, expr->context(), r0); | 1104 DropAndApply(1, expr->context(), r0); |
1082 } | 1105 } |
(...skipping 19 matching lines...) Expand all Loading... |
1102 // Call to a lookup slot. | 1125 // Call to a lookup slot. |
1103 UNREACHABLE(); | 1126 UNREACHABLE(); |
1104 } else if (fun->AsProperty() != NULL) { | 1127 } else if (fun->AsProperty() != NULL) { |
1105 // Call to an object property. | 1128 // Call to an object property. |
1106 Property* prop = fun->AsProperty(); | 1129 Property* prop = fun->AsProperty(); |
1107 Literal* key = prop->key()->AsLiteral(); | 1130 Literal* key = prop->key()->AsLiteral(); |
1108 if (key != NULL && key->handle()->IsSymbol()) { | 1131 if (key != NULL && key->handle()->IsSymbol()) { |
1109 // Call to a named property, use call IC. | 1132 // Call to a named property, use call IC. |
1110 __ mov(r0, Operand(key->handle())); | 1133 __ mov(r0, Operand(key->handle())); |
1111 __ push(r0); | 1134 __ push(r0); |
1112 Visit(prop->obj()); | 1135 VisitForValue(prop->obj(), kStack); |
1113 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1136 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
1114 } else { | 1137 } else { |
1115 // Call to a keyed property, use keyed load IC followed by function | 1138 // Call to a keyed property, use keyed load IC followed by function |
1116 // call. | 1139 // call. |
1117 Visit(prop->obj()); | 1140 VisitForValue(prop->obj(), kStack); |
1118 Visit(prop->key()); | 1141 VisitForValue(prop->key(), kStack); |
1119 // Record source code position for IC call. | 1142 // Record source code position for IC call. |
1120 SetSourcePosition(prop->position()); | 1143 SetSourcePosition(prop->position()); |
1121 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1144 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1122 __ Call(ic, RelocInfo::CODE_TARGET); | 1145 __ Call(ic, RelocInfo::CODE_TARGET); |
1123 // Load receiver object into r1. | 1146 // Load receiver object into r1. |
1124 if (prop->is_synthetic()) { | 1147 if (prop->is_synthetic()) { |
1125 __ ldr(r1, CodeGenerator::GlobalObject()); | 1148 __ ldr(r1, CodeGenerator::GlobalObject()); |
1126 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 1149 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
1127 } else { | 1150 } else { |
1128 __ ldr(r1, MemOperand(sp, kPointerSize)); | 1151 __ ldr(r1, MemOperand(sp, kPointerSize)); |
1129 } | 1152 } |
1130 // Overwrite (object, key) with (function, receiver). | 1153 // Overwrite (object, key) with (function, receiver). |
1131 __ str(r0, MemOperand(sp, kPointerSize)); | 1154 __ str(r0, MemOperand(sp, kPointerSize)); |
1132 __ str(r1, MemOperand(sp)); | 1155 __ str(r1, MemOperand(sp)); |
1133 EmitCallWithStub(expr); | 1156 EmitCallWithStub(expr); |
1134 } | 1157 } |
1135 } else { | 1158 } else { |
1136 // Call to some other expression. If the expression is an anonymous | 1159 // Call to some other expression. If the expression is an anonymous |
1137 // function literal not called in a loop, mark it as one that should | 1160 // function literal not called in a loop, mark it as one that should |
1138 // also use the fast code generator. | 1161 // also use the fast code generator. |
1139 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 1162 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
1140 if (lit != NULL && | 1163 if (lit != NULL && |
1141 lit->name()->Equals(Heap::empty_string()) && | 1164 lit->name()->Equals(Heap::empty_string()) && |
1142 loop_depth() == 0) { | 1165 loop_depth() == 0) { |
1143 lit->set_try_fast_codegen(true); | 1166 lit->set_try_fast_codegen(true); |
1144 } | 1167 } |
1145 Visit(fun); | 1168 VisitForValue(fun, kStack); |
1146 // Load global receiver object. | 1169 // Load global receiver object. |
1147 __ ldr(r1, CodeGenerator::GlobalObject()); | 1170 __ ldr(r1, CodeGenerator::GlobalObject()); |
1148 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 1171 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
1149 __ push(r1); | 1172 __ push(r1); |
1150 // Emit function call. | 1173 // Emit function call. |
1151 EmitCallWithStub(expr); | 1174 EmitCallWithStub(expr); |
1152 } | 1175 } |
1153 } | 1176 } |
1154 | 1177 |
1155 | 1178 |
1156 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 1179 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
1157 Comment cmnt(masm_, "[ CallNew"); | 1180 Comment cmnt(masm_, "[ CallNew"); |
1158 // According to ECMA-262, section 11.2.2, page 44, the function | 1181 // According to ECMA-262, section 11.2.2, page 44, the function |
1159 // expression in new calls must be evaluated before the | 1182 // expression in new calls must be evaluated before the |
1160 // arguments. | 1183 // arguments. |
1161 // Push function on the stack. | 1184 // Push function on the stack. |
1162 Visit(expr->expression()); | 1185 VisitForValue(expr->expression(), kStack); |
1163 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | |
1164 | 1186 |
1165 // Push global object (receiver). | 1187 // Push global object (receiver). |
1166 __ ldr(r0, CodeGenerator::GlobalObject()); | 1188 __ ldr(r0, CodeGenerator::GlobalObject()); |
1167 __ push(r0); | 1189 __ push(r0); |
1168 // Push the arguments ("left-to-right") on the stack. | 1190 // Push the arguments ("left-to-right") on the stack. |
1169 ZoneList<Expression*>* args = expr->arguments(); | 1191 ZoneList<Expression*>* args = expr->arguments(); |
1170 int arg_count = args->length(); | 1192 int arg_count = args->length(); |
1171 for (int i = 0; i < arg_count; i++) { | 1193 for (int i = 0; i < arg_count; i++) { |
1172 Visit(args->at(i)); | 1194 VisitForValue(args->at(i), kStack); |
1173 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1174 // If location is value, it is already on the stack, | |
1175 // so nothing to do here. | |
1176 } | 1195 } |
1177 | 1196 |
1178 // Call the construct call builtin that handles allocation and | 1197 // Call the construct call builtin that handles allocation and |
1179 // constructor invocation. | 1198 // constructor invocation. |
1180 SetSourcePosition(expr->position()); | 1199 SetSourcePosition(expr->position()); |
1181 | 1200 |
1182 // Load function, arg_count into r1 and r0. | 1201 // Load function, arg_count into r1 and r0. |
1183 __ mov(r0, Operand(arg_count)); | 1202 __ mov(r0, Operand(arg_count)); |
1184 // Function is in sp[arg_count + 1]. | 1203 // Function is in sp[arg_count + 1]. |
1185 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 1204 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
(...skipping 14 matching lines...) Expand all Loading... |
1200 // Prepare for calling JS runtime function. | 1219 // Prepare for calling JS runtime function. |
1201 __ mov(r1, Operand(expr->name())); | 1220 __ mov(r1, Operand(expr->name())); |
1202 __ ldr(r0, CodeGenerator::GlobalObject()); | 1221 __ ldr(r0, CodeGenerator::GlobalObject()); |
1203 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); | 1222 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); |
1204 __ stm(db_w, sp, r1.bit() | r0.bit()); | 1223 __ stm(db_w, sp, r1.bit() | r0.bit()); |
1205 } | 1224 } |
1206 | 1225 |
1207 // Push the arguments ("left-to-right"). | 1226 // Push the arguments ("left-to-right"). |
1208 int arg_count = args->length(); | 1227 int arg_count = args->length(); |
1209 for (int i = 0; i < arg_count; i++) { | 1228 for (int i = 0; i < arg_count; i++) { |
1210 Visit(args->at(i)); | 1229 VisitForValue(args->at(i), kStack); |
1211 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1212 } | 1230 } |
1213 | 1231 |
1214 if (expr->is_jsruntime()) { | 1232 if (expr->is_jsruntime()) { |
1215 // Call the JS runtime function. | 1233 // Call the JS runtime function. |
1216 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 1234 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
1217 NOT_IN_LOOP); | 1235 NOT_IN_LOOP); |
1218 __ Call(ic, RelocInfo::CODE_TARGET); | 1236 __ Call(ic, RelocInfo::CODE_TARGET); |
1219 // Restore context register. | 1237 // Restore context register. |
1220 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1238 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1221 // Discard the function left on TOS. | 1239 // Discard the function left on TOS. |
1222 DropAndApply(1, expr->context(), r0); | 1240 DropAndApply(1, expr->context(), r0); |
1223 } else { | 1241 } else { |
1224 // Call the C runtime function. | 1242 // Call the C runtime function. |
1225 __ CallRuntime(expr->function(), arg_count); | 1243 __ CallRuntime(expr->function(), arg_count); |
1226 Apply(expr->context(), r0); | 1244 Apply(expr->context(), r0); |
1227 } | 1245 } |
1228 } | 1246 } |
1229 | 1247 |
1230 | 1248 |
1231 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1249 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
1232 switch (expr->op()) { | 1250 switch (expr->op()) { |
1233 case Token::VOID: { | 1251 case Token::VOID: { |
1234 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1252 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 1253 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); |
1235 Visit(expr->expression()); | 1254 Visit(expr->expression()); |
1236 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); | |
1237 switch (expr->context()) { | 1255 switch (expr->context()) { |
1238 case Expression::kUninitialized: | 1256 case Expression::kUninitialized: |
1239 UNREACHABLE(); | 1257 UNREACHABLE(); |
1240 break; | 1258 break; |
1241 case Expression::kEffect: | 1259 case Expression::kEffect: |
1242 break; | 1260 break; |
1243 case Expression::kValue: | 1261 case Expression::kValue: |
1244 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1262 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
1245 __ push(ip); | 1263 switch (location_) { |
| 1264 case kAccumulator: |
| 1265 break; |
| 1266 case kStack: |
| 1267 __ push(result_register()); |
| 1268 break; |
| 1269 } |
1246 break; | 1270 break; |
1247 case Expression::kTestValue: | 1271 case Expression::kTestValue: |
1248 // Value is false so it's needed. | 1272 // Value is false so it's needed. |
1249 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1273 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); |
1250 __ push(ip); | 1274 switch (location_) { |
| 1275 case kAccumulator: |
| 1276 break; |
| 1277 case kStack: |
| 1278 __ push(result_register()); |
| 1279 break; |
| 1280 } |
| 1281 // Fall through. |
1251 case Expression::kTest: | 1282 case Expression::kTest: |
1252 case Expression::kValueTest: | 1283 case Expression::kValueTest: |
1253 __ jmp(false_label_); | 1284 __ jmp(false_label_); |
1254 break; | 1285 break; |
1255 } | 1286 } |
1256 break; | 1287 break; |
1257 } | 1288 } |
1258 | 1289 |
1259 case Token::NOT: { | 1290 case Token::NOT: { |
1260 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 1291 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
1261 ASSERT_EQ(Expression::kTest, expr->expression()->context()); | 1292 ASSERT_EQ(Expression::kTest, expr->expression()->context()); |
1262 | 1293 |
1263 Label push_true, push_false, done; | 1294 Label materialize_true, materialize_false, done; |
| 1295 // Initially assume a pure test context. Notice that the labels are |
| 1296 // swapped. |
| 1297 Label* if_true = false_label_; |
| 1298 Label* if_false = true_label_; |
1264 switch (expr->context()) { | 1299 switch (expr->context()) { |
1265 case Expression::kUninitialized: | 1300 case Expression::kUninitialized: |
1266 UNREACHABLE(); | 1301 UNREACHABLE(); |
1267 break; | 1302 break; |
1268 | |
1269 case Expression::kEffect: | 1303 case Expression::kEffect: |
1270 VisitForControl(expr->expression(), &done, &done); | 1304 if_true = &done; |
1271 __ bind(&done); | 1305 if_false = &done; |
1272 break; | 1306 break; |
1273 | |
1274 case Expression::kValue: | 1307 case Expression::kValue: |
1275 VisitForControl(expr->expression(), &push_false, &push_true); | 1308 if_true = &materialize_false; |
1276 __ bind(&push_true); | 1309 if_false = &materialize_true; |
1277 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
1278 __ push(ip); | |
1279 __ jmp(&done); | |
1280 __ bind(&push_false); | |
1281 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | |
1282 __ push(ip); | |
1283 __ bind(&done); | |
1284 break; | 1310 break; |
1285 | |
1286 case Expression::kTest: | 1311 case Expression::kTest: |
1287 VisitForControl(expr->expression(), false_label_, true_label_); | |
1288 break; | 1312 break; |
1289 | |
1290 case Expression::kValueTest: | 1313 case Expression::kValueTest: |
1291 VisitForControl(expr->expression(), false_label_, &push_true); | 1314 if_false = &materialize_true; |
1292 __ bind(&push_true); | |
1293 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
1294 __ push(ip); | |
1295 __ jmp(true_label_); | |
1296 break; | 1315 break; |
1297 | |
1298 case Expression::kTestValue: | 1316 case Expression::kTestValue: |
1299 VisitForControl(expr->expression(), &push_false, true_label_); | 1317 if_true = &materialize_false; |
1300 __ bind(&push_false); | |
1301 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | |
1302 __ push(ip); | |
1303 __ jmp(false_label_); | |
1304 break; | 1318 break; |
1305 } | 1319 } |
| 1320 VisitForControl(expr->expression(), if_true, if_false); |
| 1321 Apply(expr->context(), if_false, if_true); // Labels swapped. |
1306 break; | 1322 break; |
1307 } | 1323 } |
1308 | 1324 |
1309 case Token::TYPEOF: { | 1325 case Token::TYPEOF: { |
1310 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 1326 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
1311 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 1327 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
1312 | 1328 |
1313 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 1329 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
1314 if (proxy != NULL && | 1330 if (proxy != NULL && |
1315 !proxy->var()->is_this() && | 1331 !proxy->var()->is_this() && |
1316 proxy->var()->is_global()) { | 1332 proxy->var()->is_global()) { |
1317 Comment cmnt(masm_, "Global variable"); | 1333 Comment cmnt(masm_, "Global variable"); |
1318 __ ldr(r0, CodeGenerator::GlobalObject()); | 1334 __ ldr(r0, CodeGenerator::GlobalObject()); |
1319 __ push(r0); | 1335 __ push(r0); |
1320 __ mov(r2, Operand(proxy->name())); | 1336 __ mov(r2, Operand(proxy->name())); |
1321 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1337 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1322 // Use a regular load, not a contextual load, to avoid a reference | 1338 // Use a regular load, not a contextual load, to avoid a reference |
1323 // error. | 1339 // error. |
1324 __ Call(ic, RelocInfo::CODE_TARGET); | 1340 __ Call(ic, RelocInfo::CODE_TARGET); |
1325 __ str(r0, MemOperand(sp)); | 1341 __ str(r0, MemOperand(sp)); |
1326 } else if (proxy != NULL && | 1342 } else if (proxy != NULL && |
1327 proxy->var()->slot() != NULL && | 1343 proxy->var()->slot() != NULL && |
1328 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1344 proxy->var()->slot()->type() == Slot::LOOKUP) { |
1329 __ mov(r0, Operand(proxy->name())); | 1345 __ mov(r0, Operand(proxy->name())); |
1330 __ stm(db_w, sp, cp.bit() | r0.bit()); | 1346 __ stm(db_w, sp, cp.bit() | r0.bit()); |
1331 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1347 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1332 __ push(r0); | 1348 __ push(r0); |
1333 } else { | 1349 } else { |
1334 // This expression cannot throw a reference error at the top level. | 1350 // This expression cannot throw a reference error at the top level. |
1335 Visit(expr->expression()); | 1351 VisitForValue(expr->expression(), kStack); |
1336 } | 1352 } |
1337 | 1353 |
1338 __ CallRuntime(Runtime::kTypeof, 1); | 1354 __ CallRuntime(Runtime::kTypeof, 1); |
1339 Apply(expr->context(), r0); | 1355 Apply(expr->context(), r0); |
1340 break; | 1356 break; |
1341 } | 1357 } |
1342 | 1358 |
1343 default: | 1359 default: |
1344 UNREACHABLE(); | 1360 UNREACHABLE(); |
1345 } | 1361 } |
(...skipping 12 matching lines...) Expand all Loading... |
1358 // of the key to detect a named property. | 1374 // of the key to detect a named property. |
1359 if (prop != NULL) { | 1375 if (prop != NULL) { |
1360 assign_type = (prop->key()->context() == Expression::kUninitialized) | 1376 assign_type = (prop->key()->context() == Expression::kUninitialized) |
1361 ? NAMED_PROPERTY | 1377 ? NAMED_PROPERTY |
1362 : KEYED_PROPERTY; | 1378 : KEYED_PROPERTY; |
1363 } | 1379 } |
1364 | 1380 |
1365 // Evaluate expression and get value. | 1381 // Evaluate expression and get value. |
1366 if (assign_type == VARIABLE) { | 1382 if (assign_type == VARIABLE) { |
1367 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 1383 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1384 Location saved_location = location_; |
| 1385 location_ = kStack; |
1368 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 1386 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
1369 Expression::kValue); | 1387 Expression::kValue); |
| 1388 location_ = saved_location; |
1370 } else { | 1389 } else { |
1371 // Reserve space for result of postfix operation. | 1390 // Reserve space for result of postfix operation. |
1372 if (expr->is_postfix() && expr->context() != Expression::kEffect) { | 1391 if (expr->is_postfix() && expr->context() != Expression::kEffect) { |
1373 ASSERT(expr->context() != Expression::kUninitialized); | 1392 ASSERT(expr->context() != Expression::kUninitialized); |
1374 __ mov(ip, Operand(Smi::FromInt(0))); | 1393 __ mov(ip, Operand(Smi::FromInt(0))); |
1375 __ push(ip); | 1394 __ push(ip); |
1376 } | 1395 } |
1377 Visit(prop->obj()); | 1396 VisitForValue(prop->obj(), kStack); |
1378 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | |
1379 if (assign_type == NAMED_PROPERTY) { | 1397 if (assign_type == NAMED_PROPERTY) { |
1380 EmitNamedPropertyLoad(prop); | 1398 EmitNamedPropertyLoad(prop); |
1381 } else { | 1399 } else { |
1382 Visit(prop->key()); | 1400 VisitForValue(prop->key(), kStack); |
1383 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
1384 EmitKeyedPropertyLoad(prop); | 1401 EmitKeyedPropertyLoad(prop); |
1385 } | 1402 } |
1386 __ push(r0); | 1403 __ push(r0); |
1387 } | 1404 } |
1388 | 1405 |
1389 // Convert to number. | 1406 // Convert to number. |
1390 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); | 1407 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
1391 | 1408 |
1392 // Save result for postfix expressions. | 1409 // Save result for postfix expressions. |
1393 if (expr->is_postfix()) { | 1410 if (expr->is_postfix()) { |
1394 switch (expr->context()) { | 1411 switch (expr->context()) { |
1395 case Expression::kUninitialized: | 1412 case Expression::kUninitialized: |
1396 UNREACHABLE(); | 1413 UNREACHABLE(); |
1397 case Expression::kEffect: | 1414 case Expression::kEffect: |
1398 // Do not save result. | 1415 // Do not save result. |
1399 break; | 1416 break; |
1400 case Expression::kValue: | 1417 case Expression::kValue: |
1401 case Expression::kTest: | 1418 case Expression::kTest: |
| 1419 case Expression::kValueTest: |
1402 case Expression::kTestValue: | 1420 case Expression::kTestValue: |
1403 case Expression::kValueTest: | |
1404 // Save the result on the stack. If we have a named or keyed property | 1421 // Save the result on the stack. If we have a named or keyed property |
1405 // we store the result under the receiver that is currently on top | 1422 // we store the result under the receiver that is currently on top |
1406 // of the stack. | 1423 // of the stack. |
1407 switch (assign_type) { | 1424 switch (assign_type) { |
1408 case VARIABLE: | 1425 case VARIABLE: |
1409 __ push(r0); | 1426 __ push(r0); |
1410 break; | 1427 break; |
1411 case NAMED_PROPERTY: | 1428 case NAMED_PROPERTY: |
1412 __ str(r0, MemOperand(sp, kPointerSize)); | 1429 __ str(r0, MemOperand(sp, kPointerSize)); |
1413 break; | 1430 break; |
1414 case KEYED_PROPERTY: | 1431 case KEYED_PROPERTY: |
1415 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 1432 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
1416 break; | 1433 break; |
1417 } | 1434 } |
1418 break; | 1435 break; |
1419 } | 1436 } |
1420 } | 1437 } |
1421 | 1438 |
1422 // Call stub for +1/-1. | 1439 // Call stub for +1/-1. |
1423 __ mov(r1, Operand(expr->op() == Token::INC | 1440 __ mov(r1, Operand(expr->op() == Token::INC |
1424 ? Smi::FromInt(1) | 1441 ? Smi::FromInt(1) |
1425 : Smi::FromInt(-1))); | 1442 : Smi::FromInt(-1))); |
1426 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE); | 1443 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE); |
1427 __ CallStub(&stub); | 1444 __ CallStub(&stub); |
1428 | 1445 |
1429 // Store the value returned in r0. | 1446 // Store the value returned in r0. |
1430 switch (assign_type) { | 1447 switch (assign_type) { |
1431 case VARIABLE: | 1448 case VARIABLE: |
1432 __ push(r0); | |
1433 if (expr->is_postfix()) { | 1449 if (expr->is_postfix()) { |
1434 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1450 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
1435 Expression::kEffect); | 1451 Expression::kEffect); |
1436 // For all contexts except kEffect: We have the result on | 1452 // For all contexts except kEffect: We have the result on |
1437 // top of the stack. | 1453 // top of the stack. |
1438 if (expr->context() != Expression::kEffect) { | 1454 if (expr->context() != Expression::kEffect) { |
1439 ApplyTOS(expr->context()); | 1455 ApplyTOS(expr->context()); |
1440 } | 1456 } |
1441 } else { | 1457 } else { |
1442 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1458 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1492 case Token::ADD: | 1508 case Token::ADD: |
1493 case Token::SUB: | 1509 case Token::SUB: |
1494 case Token::DIV: | 1510 case Token::DIV: |
1495 case Token::MOD: | 1511 case Token::MOD: |
1496 case Token::MUL: | 1512 case Token::MUL: |
1497 case Token::BIT_OR: | 1513 case Token::BIT_OR: |
1498 case Token::BIT_AND: | 1514 case Token::BIT_AND: |
1499 case Token::BIT_XOR: | 1515 case Token::BIT_XOR: |
1500 case Token::SHL: | 1516 case Token::SHL: |
1501 case Token::SHR: | 1517 case Token::SHR: |
1502 case Token::SAR: { | 1518 case Token::SAR: |
1503 ASSERT_EQ(Expression::kValue, expr->left()->context()); | 1519 VisitForValue(expr->left(), kStack); |
1504 ASSERT_EQ(Expression::kValue, expr->right()->context()); | 1520 VisitForValue(expr->right(), kAccumulator); |
| 1521 EmitBinaryOp(expr->op(), expr->context()); |
| 1522 break; |
1505 | 1523 |
1506 Visit(expr->left()); | |
1507 Visit(expr->right()); | |
1508 __ pop(r0); | |
1509 __ pop(r1); | |
1510 GenericBinaryOpStub stub(expr->op(), | |
1511 NO_OVERWRITE); | |
1512 __ CallStub(&stub); | |
1513 Apply(expr->context(), r0); | |
1514 | |
1515 break; | |
1516 } | |
1517 default: | 1524 default: |
1518 UNREACHABLE(); | 1525 UNREACHABLE(); |
1519 } | 1526 } |
1520 } | 1527 } |
1521 | 1528 |
1522 | 1529 |
1523 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1530 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
1524 Comment cmnt(masm_, "[ CompareOperation"); | 1531 Comment cmnt(masm_, "[ CompareOperation"); |
1525 ASSERT_EQ(Expression::kValue, expr->left()->context()); | |
1526 ASSERT_EQ(Expression::kValue, expr->right()->context()); | |
1527 Visit(expr->left()); | |
1528 Visit(expr->right()); | |
1529 | 1532 |
1530 // Always perform the comparison for its control flow. Pack the result | 1533 // Always perform the comparison for its control flow. Pack the result |
1531 // into the expression's context after the comparison is performed. | 1534 // into the expression's context after the comparison is performed. |
1532 Label push_true, push_false, done; | 1535 Label materialize_true, materialize_false, done; |
1533 // Initially assume we are in a test context. | 1536 // Initially assume we are in a test context. |
1534 Label* if_true = true_label_; | 1537 Label* if_true = true_label_; |
1535 Label* if_false = false_label_; | 1538 Label* if_false = false_label_; |
1536 switch (expr->context()) { | 1539 switch (expr->context()) { |
1537 case Expression::kUninitialized: | 1540 case Expression::kUninitialized: |
1538 UNREACHABLE(); | 1541 UNREACHABLE(); |
1539 break; | 1542 break; |
1540 case Expression::kEffect: | 1543 case Expression::kEffect: |
1541 if_true = &done; | 1544 if_true = &done; |
1542 if_false = &done; | 1545 if_false = &done; |
1543 break; | 1546 break; |
1544 case Expression::kValue: | 1547 case Expression::kValue: |
1545 if_true = &push_true; | 1548 if_true = &materialize_true; |
1546 if_false = &push_false; | 1549 if_false = &materialize_false; |
1547 break; | 1550 break; |
1548 case Expression::kTest: | 1551 case Expression::kTest: |
1549 break; | 1552 break; |
1550 case Expression::kValueTest: | 1553 case Expression::kValueTest: |
1551 if_true = &push_true; | 1554 if_true = &materialize_true; |
1552 break; | 1555 break; |
1553 case Expression::kTestValue: | 1556 case Expression::kTestValue: |
1554 if_false = &push_false; | 1557 if_false = &materialize_false; |
1555 break; | 1558 break; |
1556 } | 1559 } |
1557 | 1560 |
| 1561 VisitForValue(expr->left(), kStack); |
1558 switch (expr->op()) { | 1562 switch (expr->op()) { |
1559 case Token::IN: { | 1563 case Token::IN: |
| 1564 VisitForValue(expr->right(), kStack); |
1560 __ InvokeBuiltin(Builtins::IN, CALL_JS); | 1565 __ InvokeBuiltin(Builtins::IN, CALL_JS); |
1561 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1566 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
1562 __ cmp(r0, ip); | 1567 __ cmp(r0, ip); |
1563 __ b(eq, if_true); | 1568 __ b(eq, if_true); |
1564 __ jmp(if_false); | 1569 __ jmp(if_false); |
1565 break; | 1570 break; |
1566 } | |
1567 | 1571 |
1568 case Token::INSTANCEOF: { | 1572 case Token::INSTANCEOF: { |
| 1573 VisitForValue(expr->right(), kStack); |
1569 InstanceofStub stub; | 1574 InstanceofStub stub; |
1570 __ CallStub(&stub); | 1575 __ CallStub(&stub); |
1571 __ tst(r0, r0); | 1576 __ tst(r0, r0); |
1572 __ b(eq, if_true); // The stub returns 0 for true. | 1577 __ b(eq, if_true); // The stub returns 0 for true. |
1573 __ jmp(if_false); | 1578 __ jmp(if_false); |
1574 break; | 1579 break; |
1575 } | 1580 } |
1576 | 1581 |
1577 default: { | 1582 default: { |
| 1583 VisitForValue(expr->right(), kAccumulator); |
1578 Condition cc = eq; | 1584 Condition cc = eq; |
1579 bool strict = false; | 1585 bool strict = false; |
1580 switch (expr->op()) { | 1586 switch (expr->op()) { |
1581 case Token::EQ_STRICT: | 1587 case Token::EQ_STRICT: |
1582 strict = true; | 1588 strict = true; |
1583 // Fall through | 1589 // Fall through |
1584 case Token::EQ: | 1590 case Token::EQ: |
1585 cc = eq; | 1591 cc = eq; |
1586 __ pop(r0); | |
1587 __ pop(r1); | 1592 __ pop(r1); |
1588 break; | 1593 break; |
1589 case Token::LT: | 1594 case Token::LT: |
1590 cc = lt; | 1595 cc = lt; |
1591 __ pop(r0); | |
1592 __ pop(r1); | 1596 __ pop(r1); |
1593 break; | 1597 break; |
1594 case Token::GT: | 1598 case Token::GT: |
1595 // Reverse left and right sides to obtain ECMA-262 conversion order. | 1599 // Reverse left and right sides to obtain ECMA-262 conversion order. |
1596 cc = lt; | 1600 cc = lt; |
1597 __ pop(r1); | 1601 __ mov(r1, result_register()); |
1598 __ pop(r0); | 1602 __ pop(r0); |
1599 break; | 1603 break; |
1600 case Token::LTE: | 1604 case Token::LTE: |
1601 // Reverse left and right sides to obtain ECMA-262 conversion order. | 1605 // Reverse left and right sides to obtain ECMA-262 conversion order. |
1602 cc = ge; | 1606 cc = ge; |
1603 __ pop(r1); | 1607 __ mov(r1, result_register()); |
1604 __ pop(r0); | 1608 __ pop(r0); |
1605 break; | 1609 break; |
1606 case Token::GTE: | 1610 case Token::GTE: |
1607 cc = ge; | 1611 cc = ge; |
1608 __ pop(r0); | |
1609 __ pop(r1); | 1612 __ pop(r1); |
1610 break; | 1613 break; |
1611 case Token::IN: | 1614 case Token::IN: |
1612 case Token::INSTANCEOF: | 1615 case Token::INSTANCEOF: |
1613 default: | 1616 default: |
1614 UNREACHABLE(); | 1617 UNREACHABLE(); |
1615 } | 1618 } |
1616 | 1619 |
1617 // The comparison stub expects the smi vs. smi case to be handled | 1620 // The comparison stub expects the smi vs. smi case to be handled |
1618 // before it is called. | 1621 // before it is called. |
1619 Label slow_case; | 1622 Label slow_case; |
1620 __ orr(r2, r0, Operand(r1)); | 1623 __ orr(r2, r0, Operand(r1)); |
1621 __ tst(r2, Operand(kSmiTagMask)); | 1624 __ tst(r2, Operand(kSmiTagMask)); |
1622 __ b(ne, &slow_case); | 1625 __ b(ne, &slow_case); |
1623 __ cmp(r1, r0); | 1626 __ cmp(r1, r0); |
1624 __ b(cc, if_true); | 1627 __ b(cc, if_true); |
1625 __ jmp(if_false); | 1628 __ jmp(if_false); |
1626 | 1629 |
1627 __ bind(&slow_case); | 1630 __ bind(&slow_case); |
1628 CompareStub stub(cc, strict); | 1631 CompareStub stub(cc, strict); |
1629 __ CallStub(&stub); | 1632 __ CallStub(&stub); |
1630 __ cmp(r0, Operand(0)); | 1633 __ cmp(r0, Operand(0)); |
1631 __ b(cc, if_true); | 1634 __ b(cc, if_true); |
1632 __ jmp(if_false); | 1635 __ jmp(if_false); |
1633 } | 1636 } |
1634 } | 1637 } |
1635 | 1638 |
1636 // Convert the result of the comparison into one expected for this | 1639 // Convert the result of the comparison into one expected for this |
1637 // expression's context. | 1640 // expression's context. |
1638 switch (expr->context()) { | 1641 Apply(expr->context(), if_true, if_false); |
1639 case Expression::kUninitialized: | |
1640 UNREACHABLE(); | |
1641 break; | |
1642 | |
1643 case Expression::kEffect: | |
1644 __ bind(&done); | |
1645 break; | |
1646 | |
1647 case Expression::kValue: | |
1648 __ bind(&push_true); | |
1649 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
1650 __ push(ip); | |
1651 __ jmp(&done); | |
1652 __ bind(&push_false); | |
1653 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | |
1654 __ push(ip); | |
1655 __ bind(&done); | |
1656 break; | |
1657 | |
1658 case Expression::kTest: | |
1659 break; | |
1660 | |
1661 case Expression::kValueTest: | |
1662 __ bind(&push_true); | |
1663 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
1664 __ push(ip); | |
1665 __ jmp(true_label_); | |
1666 break; | |
1667 | |
1668 case Expression::kTestValue: | |
1669 __ bind(&push_false); | |
1670 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | |
1671 __ push(ip); | |
1672 __ jmp(false_label_); | |
1673 break; | |
1674 } | |
1675 } | 1642 } |
1676 | 1643 |
1677 | 1644 |
1678 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1645 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
1679 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1646 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
1680 Apply(expr->context(), r0); | 1647 Apply(expr->context(), r0); |
1681 } | 1648 } |
1682 | 1649 |
1683 | 1650 |
1684 Register FastCodeGenerator::result_register() { return r0; } | 1651 Register FastCodeGenerator::result_register() { return r0; } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1722 __ pop(result_register()); | 1689 __ pop(result_register()); |
1723 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 1690 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
1724 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 1691 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
1725 __ add(pc, r1, Operand(masm_->CodeObject())); | 1692 __ add(pc, r1, Operand(masm_->CodeObject())); |
1726 } | 1693 } |
1727 | 1694 |
1728 | 1695 |
1729 #undef __ | 1696 #undef __ |
1730 | 1697 |
1731 } } // namespace v8::internal | 1698 } } // namespace v8::internal |
OLD | NEW |