| 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 |