| Index: src/arm/codegen-arm.cc | 
| =================================================================== | 
| --- src/arm/codegen-arm.cc	(revision 4574) | 
| +++ src/arm/codegen-arm.cc	(working copy) | 
| @@ -4507,6 +4507,28 @@ | 
| } | 
|  | 
|  | 
| +class DeferredSwapElements: public DeferredCode { | 
| + public: | 
| +  DeferredSwapElements(Register object, Register index1, Register index2) | 
| +      : object_(object), index1_(index1), index2_(index2) { | 
| +    set_comment("[ DeferredSwapElements"); | 
| +  } | 
| + | 
| +  virtual void Generate(); | 
| + | 
| + private: | 
| +  Register object_, index1_, index2_; | 
| +}; | 
| + | 
| + | 
| +void DeferredSwapElements::Generate() { | 
| +  __ push(object_); | 
| +  __ push(index1_); | 
| +  __ push(index2_); | 
| +  __ CallRuntime(Runtime::kSwapElements, 3); | 
| +} | 
| + | 
| + | 
| void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) { | 
| Comment cmnt(masm_, "[ GenerateSwapElements"); | 
|  | 
| @@ -4516,8 +4538,76 @@ | 
| Load(args->at(1)); | 
| Load(args->at(2)); | 
|  | 
| -  frame_->CallRuntime(Runtime::kSwapElements, 3); | 
| -  frame_->EmitPush(r0); | 
| +  Register index2 = r2; | 
| +  Register index1 = r1; | 
| +  Register object = r0; | 
| +  Register tmp1 = r3; | 
| +  Register tmp2 = r4; | 
| + | 
| +  frame_->EmitPop(index2); | 
| +  frame_->EmitPop(index1); | 
| +  frame_->EmitPop(object); | 
| + | 
| +  DeferredSwapElements* deferred = | 
| +      new DeferredSwapElements(object, index1, index2); | 
| + | 
| +  // Fetch the map and check if array is in fast case. | 
| +  // Check that object doesn't require security checks and | 
| +  // has no indexed interceptor. | 
| +  __ CompareObjectType(object, tmp1, tmp2, FIRST_JS_OBJECT_TYPE); | 
| +  deferred->Branch(lt); | 
| +  __ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset)); | 
| +  __ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); | 
| +  deferred->Branch(nz); | 
| + | 
| +  // Check the object's elements are in fast case. | 
| +  __ ldr(tmp1, FieldMemOperand(object, JSObject::kElementsOffset)); | 
| +  __ ldr(tmp2, FieldMemOperand(tmp1, HeapObject::kMapOffset)); | 
| +  __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 
| +  __ cmp(tmp2, ip); | 
| +  deferred->Branch(ne); | 
| + | 
| +  // Smi-tagging is equivalent to multiplying by 2. | 
| +  STATIC_ASSERT(kSmiTag == 0); | 
| +  STATIC_ASSERT(kSmiTagSize == 1); | 
| + | 
| +  // Check that both indices are smis. | 
| +  __ mov(tmp2, index1); | 
| +  __ orr(tmp2, tmp2, index2); | 
| +  __ tst(tmp2, Operand(kSmiTagMask)); | 
| +  deferred->Branch(nz); | 
| + | 
| +  // Bring the offsets into the fixed array in tmp1 into index1 and | 
| +  // index2. | 
| +  __ mov(tmp2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 
| +  __ add(index1, tmp2, Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize)); | 
| +  __ add(index2, tmp2, Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); | 
| + | 
| +  // Swap elements. | 
| +  Register tmp3 = object; | 
| +  object = no_reg; | 
| +  __ ldr(tmp3, MemOperand(tmp1, index1)); | 
| +  __ ldr(tmp2, MemOperand(tmp1, index2)); | 
| +  __ str(tmp3, MemOperand(tmp1, index2)); | 
| +  __ str(tmp2, MemOperand(tmp1, index1)); | 
| + | 
| +  Label done; | 
| +  __ InNewSpace(tmp1, tmp2, eq, &done); | 
| +  // Possible optimization: do a check that both values are Smis | 
| +  // (or them and test against Smi mask.) | 
| + | 
| +  __ mov(tmp2, tmp1); | 
| +  RecordWriteStub recordWrite1(tmp1, index1, tmp3); | 
| +  __ CallStub(&recordWrite1); | 
| + | 
| +  RecordWriteStub recordWrite2(tmp2, index2, tmp3); | 
| +  __ CallStub(&recordWrite2); | 
| + | 
| +  __ bind(&done); | 
| + | 
| +  deferred->BindExit(); | 
| +  __ LoadRoot(tmp1, Heap::kUndefinedValueRootIndex); | 
| +  frame_->EmitPush(tmp1); | 
| } | 
|  | 
|  | 
| @@ -6503,6 +6593,12 @@ | 
| } | 
|  | 
|  | 
| +void RecordWriteStub::Generate(MacroAssembler* masm) { | 
| +  __ RecordWriteHelper(object_, offset_, scratch_); | 
| +  __ Ret(); | 
| +} | 
| + | 
| + | 
| // On entry r0 (rhs) and r1 (lhs) are the values to be compared. | 
| // On exit r0 is 0, positive or negative to indicate the result of | 
| // the comparison. | 
|  |