| Index: src/ia32/full-codegen-ia32.cc
 | 
| ===================================================================
 | 
| --- src/ia32/full-codegen-ia32.cc	(revision 9531)
 | 
| +++ src/ia32/full-codegen-ia32.cc	(working copy)
 | 
| @@ -138,7 +138,7 @@
 | 
|    // function calls.
 | 
|    if (info->is_strict_mode() || info->is_native()) {
 | 
|      Label ok;
 | 
| -    __ test(ecx, Operand(ecx));
 | 
| +    __ test(ecx, ecx);
 | 
|      __ j(zero, &ok, Label::kNear);
 | 
|      // +1 for return address.
 | 
|      int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
 | 
| @@ -147,6 +147,11 @@
 | 
|      __ bind(&ok);
 | 
|    }
 | 
|  
 | 
| +  // Open a frame scope to indicate that there is a frame on the stack.  The
 | 
| +  // MANUAL indicates that the scope shouldn't actually generate code to set up
 | 
| +  // the frame (that is done below).
 | 
| +  FrameScope frame_scope(masm_, StackFrame::MANUAL);
 | 
| +
 | 
|    __ push(ebp);  // Caller's frame pointer.
 | 
|    __ mov(ebp, esp);
 | 
|    __ push(esi);  // Callee's context.
 | 
| @@ -200,11 +205,12 @@
 | 
|          // Store it in the context.
 | 
|          int context_offset = Context::SlotOffset(var->index());
 | 
|          __ mov(Operand(esi, context_offset), eax);
 | 
| -        // Update the write barrier. This clobbers all involved
 | 
| -        // registers, so we have use a third register to avoid
 | 
| -        // clobbering esi.
 | 
| -        __ mov(ecx, esi);
 | 
| -        __ RecordWrite(ecx, context_offset, eax, ebx);
 | 
| +        // Update the write barrier. This clobbers eax and ebx.
 | 
| +        __ RecordWriteContextSlot(esi,
 | 
| +                                  context_offset,
 | 
| +                                  eax,
 | 
| +                                  ebx,
 | 
| +                                  kDontSaveFPRegs);
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -365,10 +371,10 @@
 | 
|  
 | 
|  void FullCodeGenerator::verify_stack_height() {
 | 
|    ASSERT(FLAG_verify_stack_height);
 | 
| -  __ sub(Operand(ebp), Immediate(kPointerSize * stack_height()));
 | 
| -  __ cmp(ebp, Operand(esp));
 | 
| +  __ sub(ebp, Immediate(kPointerSize * stack_height()));
 | 
| +  __ cmp(ebp, esp);
 | 
|    __ Assert(equal, "Full codegen stack height not as expected.");
 | 
| -  __ add(Operand(ebp), Immediate(kPointerSize * stack_height()));
 | 
| +  __ add(ebp, Immediate(kPointerSize * stack_height()));
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -597,7 +603,7 @@
 | 
|    ToBooleanStub stub(result_register());
 | 
|    __ push(result_register());
 | 
|    __ CallStub(&stub, condition->test_id());
 | 
| -  __ test(result_register(), Operand(result_register()));
 | 
| +  __ test(result_register(), result_register());
 | 
|    // The stub returns nonzero for true.
 | 
|    Split(not_zero, if_true, if_false, fall_through);
 | 
|  }
 | 
| @@ -661,11 +667,12 @@
 | 
|    ASSERT(!scratch1.is(src));
 | 
|    MemOperand location = VarOperand(var, scratch0);
 | 
|    __ mov(location, src);
 | 
| +
 | 
|    // Emit the write barrier code if the location is in the heap.
 | 
|    if (var->IsContextSlot()) {
 | 
|      int offset = Context::SlotOffset(var->index());
 | 
|      ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
 | 
| -    __ RecordWrite(scratch0, offset, src, scratch1);
 | 
| +    __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -738,9 +745,14 @@
 | 
|          Comment cmnt(masm_, "[ Declaration");
 | 
|          VisitForAccumulatorValue(function);
 | 
|          __ mov(ContextOperand(esi, variable->index()), result_register());
 | 
| -        int offset = Context::SlotOffset(variable->index());
 | 
| -        __ mov(ebx, esi);
 | 
| -        __ RecordWrite(ebx, offset, result_register(), ecx);
 | 
| +        // We know that we have written a function, which is not a smi.
 | 
| +        __ RecordWriteContextSlot(esi,
 | 
| +                                  Context::SlotOffset(variable->index()),
 | 
| +                                  result_register(),
 | 
| +                                  ecx,
 | 
| +                                  kDontSaveFPRegs,
 | 
| +                                  EMIT_REMEMBERED_SET,
 | 
| +                                  OMIT_SMI_CHECK);
 | 
|          PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
 | 
|        } else if (mode == Variable::CONST || mode == Variable::LET) {
 | 
|          Comment cmnt(masm_, "[ Declaration");
 | 
| @@ -835,10 +847,10 @@
 | 
|      if (inline_smi_code) {
 | 
|        Label slow_case;
 | 
|        __ mov(ecx, edx);
 | 
| -      __ or_(ecx, Operand(eax));
 | 
| +      __ or_(ecx, eax);
 | 
|        patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
 | 
|  
 | 
| -      __ cmp(edx, Operand(eax));
 | 
| +      __ cmp(edx, eax);
 | 
|        __ j(not_equal, &next_test);
 | 
|        __ Drop(1);  // Switch value is no longer needed.
 | 
|        __ jmp(clause->body_target());
 | 
| @@ -850,7 +862,7 @@
 | 
|      Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
 | 
|      __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
 | 
|      patch_site.EmitPatchInfo();
 | 
| -    __ test(eax, Operand(eax));
 | 
| +    __ test(eax, eax);
 | 
|      __ j(not_equal, &next_test);
 | 
|      __ Drop(1);  // Switch value is no longer needed.
 | 
|      __ jmp(clause->body_target());
 | 
| @@ -939,7 +951,7 @@
 | 
|  
 | 
|    // For all objects but the receiver, check that the cache is empty.
 | 
|    Label check_prototype;
 | 
| -  __ cmp(ecx, Operand(eax));
 | 
| +  __ cmp(ecx, eax);
 | 
|    __ j(equal, &check_prototype, Label::kNear);
 | 
|    __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset));
 | 
|    __ cmp(edx, isolate()->factory()->empty_fixed_array());
 | 
| @@ -1021,9 +1033,9 @@
 | 
|    __ push(ecx);  // Enumerable.
 | 
|    __ push(ebx);  // Current entry.
 | 
|    __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
 | 
| -  __ test(eax, Operand(eax));
 | 
| +  __ test(eax, eax);
 | 
|    __ j(equal, loop_statement.continue_label());
 | 
| -  __ mov(ebx, Operand(eax));
 | 
| +  __ mov(ebx, eax);
 | 
|  
 | 
|    // Update the 'each' property or variable from the possibly filtered
 | 
|    // entry in register ebx.
 | 
| @@ -1047,7 +1059,7 @@
 | 
|  
 | 
|    // Remove the pointers stored on the stack.
 | 
|    __ bind(loop_statement.break_label());
 | 
| -  __ add(Operand(esp), Immediate(5 * kPointerSize));
 | 
| +  __ add(esp, Immediate(5 * kPointerSize));
 | 
|  
 | 
|    decrement_stack_height(ForIn::kElementCount);
 | 
|    // Exit and decrement the loop depth.
 | 
| @@ -1480,8 +1492,20 @@
 | 
|      int offset = FixedArray::kHeaderSize + (i * kPointerSize);
 | 
|      __ mov(FieldOperand(ebx, offset), result_register());
 | 
|  
 | 
| +    Label no_map_change;
 | 
| +    __ JumpIfSmi(result_register(), &no_map_change);
 | 
|      // Update the write barrier for the array store.
 | 
| -    __ RecordWrite(ebx, offset, result_register(), ecx);
 | 
| +    __ RecordWriteField(ebx, offset, result_register(), ecx,
 | 
| +                        kDontSaveFPRegs,
 | 
| +                        EMIT_REMEMBERED_SET,
 | 
| +                        OMIT_SMI_CHECK);
 | 
| +    if (FLAG_smi_only_arrays) {
 | 
| +      __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
 | 
| +      __ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear);
 | 
| +      __ push(Operand(esp, 0));
 | 
| +      __ CallRuntime(Runtime::kNonSmiElementStored, 1);
 | 
| +    }
 | 
| +    __ bind(&no_map_change);
 | 
|  
 | 
|      PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
 | 
|    }
 | 
| @@ -1641,7 +1665,7 @@
 | 
|    __ pop(edx);
 | 
|    decrement_stack_height();
 | 
|    __ mov(ecx, eax);
 | 
| -  __ or_(eax, Operand(edx));
 | 
| +  __ or_(eax, edx);
 | 
|    JumpPatchSite patch_site(masm_);
 | 
|    patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
 | 
|  
 | 
| @@ -1691,32 +1715,32 @@
 | 
|        break;
 | 
|      }
 | 
|      case Token::ADD:
 | 
| -      __ add(eax, Operand(ecx));
 | 
| +      __ add(eax, ecx);
 | 
|        __ j(overflow, &stub_call);
 | 
|        break;
 | 
|      case Token::SUB:
 | 
| -      __ sub(eax, Operand(ecx));
 | 
| +      __ sub(eax, ecx);
 | 
|        __ j(overflow, &stub_call);
 | 
|        break;
 | 
|      case Token::MUL: {
 | 
|        __ SmiUntag(eax);
 | 
| -      __ imul(eax, Operand(ecx));
 | 
| +      __ imul(eax, ecx);
 | 
|        __ j(overflow, &stub_call);
 | 
| -      __ test(eax, Operand(eax));
 | 
| +      __ test(eax, eax);
 | 
|        __ j(not_zero, &done, Label::kNear);
 | 
|        __ mov(ebx, edx);
 | 
| -      __ or_(ebx, Operand(ecx));
 | 
| +      __ or_(ebx, ecx);
 | 
|        __ j(negative, &stub_call);
 | 
|        break;
 | 
|      }
 | 
|      case Token::BIT_OR:
 | 
| -      __ or_(eax, Operand(ecx));
 | 
| +      __ or_(eax, ecx);
 | 
|        break;
 | 
|      case Token::BIT_AND:
 | 
| -      __ and_(eax, Operand(ecx));
 | 
| +      __ and_(eax, ecx);
 | 
|        break;
 | 
|      case Token::BIT_XOR:
 | 
| -      __ xor_(eax, Operand(ecx));
 | 
| +      __ xor_(eax, ecx);
 | 
|        break;
 | 
|      default:
 | 
|        UNREACHABLE();
 | 
| @@ -1859,7 +1883,8 @@
 | 
|        __ mov(location, eax);
 | 
|        if (var->IsContextSlot()) {
 | 
|          __ mov(edx, eax);
 | 
| -        __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
 | 
| +        int offset = Context::SlotOffset(var->index());
 | 
| +        __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
 | 
|        }
 | 
|      }
 | 
|  
 | 
| @@ -1877,7 +1902,8 @@
 | 
|        __ mov(location, eax);
 | 
|        if (var->IsContextSlot()) {
 | 
|          __ mov(edx, eax);
 | 
| -        __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
 | 
| +        int offset = Context::SlotOffset(var->index());
 | 
| +        __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
 | 
|        }
 | 
|      } else {
 | 
|        ASSERT(var->IsLookupSlot());
 | 
| @@ -2069,8 +2095,29 @@
 | 
|    }
 | 
|    // Record source position for debugger.
 | 
|    SetSourcePosition(expr->position());
 | 
| +
 | 
| +  // Record call targets in unoptimized code, but not in the snapshot.
 | 
| +  bool record_call_target = !Serializer::enabled();
 | 
| +  if (record_call_target) {
 | 
| +    flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
 | 
| +  }
 | 
|    CallFunctionStub stub(arg_count, flags);
 | 
|    __ CallStub(&stub);
 | 
| +  if (record_call_target) {
 | 
| +    // There is a one element cache in the instruction stream.
 | 
| +#ifdef DEBUG
 | 
| +    int return_site_offset = masm()->pc_offset();
 | 
| +#endif
 | 
| +    Handle<Object> uninitialized =
 | 
| +        CallFunctionStub::UninitializedSentinel(isolate());
 | 
| +    Handle<JSGlobalPropertyCell> cell =
 | 
| +        isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
 | 
| +    __ test(eax, Immediate(cell));
 | 
| +    // Patching code in the stub assumes the opcode is 1 byte and there is
 | 
| +    // word for a pointer in the operand.
 | 
| +    ASSERT(masm()->pc_offset() - return_site_offset >= 1 + kPointerSize);
 | 
| +  }
 | 
| +
 | 
|    RecordJSReturnSite(expr);
 | 
|    // Restore context register.
 | 
|    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 | 
| @@ -2438,9 +2485,9 @@
 | 
|    STATIC_ASSERT(kPointerSize == 4);
 | 
|    __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
 | 
|    // Calculate location of the first key name.
 | 
| -  __ add(Operand(ebx),
 | 
| -           Immediate(FixedArray::kHeaderSize +
 | 
| -                     DescriptorArray::kFirstIndex * kPointerSize));
 | 
| +  __ add(ebx,
 | 
| +         Immediate(FixedArray::kHeaderSize +
 | 
| +                   DescriptorArray::kFirstIndex * kPointerSize));
 | 
|    // Loop through all the keys in the descriptor array. If one of these is the
 | 
|    // symbol valueOf the result is false.
 | 
|    Label entry, loop;
 | 
| @@ -2449,9 +2496,9 @@
 | 
|    __ mov(edx, FieldOperand(ebx, 0));
 | 
|    __ cmp(edx, FACTORY->value_of_symbol());
 | 
|    __ j(equal, if_false);
 | 
| -  __ add(Operand(ebx), Immediate(kPointerSize));
 | 
| +  __ add(ebx, Immediate(kPointerSize));
 | 
|    __ bind(&entry);
 | 
| -  __ cmp(ebx, Operand(ecx));
 | 
| +  __ cmp(ebx, ecx);
 | 
|    __ j(not_equal, &loop);
 | 
|  
 | 
|    // Reload map as register ebx was used as temporary above.
 | 
| @@ -2591,7 +2638,7 @@
 | 
|  
 | 
|    __ pop(ebx);
 | 
|    decrement_stack_height();
 | 
| -  __ cmp(eax, Operand(ebx));
 | 
| +  __ cmp(eax, ebx);
 | 
|    PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 | 
|    Split(equal, if_true, if_false, fall_through);
 | 
|  
 | 
| @@ -2647,20 +2694,24 @@
 | 
|  
 | 
|    // Check that the object is a JS object but take special care of JS
 | 
|    // functions to make sure they have 'Function' as their class.
 | 
| +  // Assume that there are only two callable types, and one of them is at
 | 
| +  // either end of the type range for JS object types. Saves extra comparisons.
 | 
| +  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
 | 
|    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
 | 
|    // Map is now in eax.
 | 
|    __ j(below, &null);
 | 
| +  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 | 
| +                FIRST_SPEC_OBJECT_TYPE + 1);
 | 
| +  __ j(equal, &function);
 | 
|  
 | 
| -  // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
 | 
| -  // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
 | 
| -  // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
 | 
| -  STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
 | 
| -  STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
 | 
| -                LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
 | 
| -  __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
 | 
| -  __ j(above_equal, &function);
 | 
| +  __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
 | 
| +  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 | 
| +                LAST_SPEC_OBJECT_TYPE - 1);
 | 
| +  __ j(equal, &function);
 | 
| +  // Assume that there is no larger type.
 | 
| +  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 | 
|  
 | 
| -  // Check if the constructor in the map is a function.
 | 
| +  // Check if the constructor in the map is a JS function.
 | 
|    __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
 | 
|    __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
 | 
|    __ j(not_equal, &non_function_constructor);
 | 
| @@ -2741,8 +2792,8 @@
 | 
|    if (CpuFeatures::IsSupported(SSE2)) {
 | 
|      CpuFeatures::Scope fscope(SSE2);
 | 
|      __ mov(ebx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
 | 
| -    __ movd(xmm1, Operand(ebx));
 | 
| -    __ movd(xmm0, Operand(eax));
 | 
| +    __ movd(xmm1, ebx);
 | 
| +    __ movd(xmm0, eax);
 | 
|      __ cvtss2sd(xmm1, xmm1);
 | 
|      __ xorps(xmm0, xmm1);
 | 
|      __ subsd(xmm0, xmm1);
 | 
| @@ -2843,10 +2894,11 @@
 | 
|  
 | 
|    // Store the value.
 | 
|    __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
 | 
| +
 | 
|    // Update the write barrier.  Save the value as it will be
 | 
|    // overwritten by the write barrier code and is needed afterward.
 | 
|    __ mov(edx, eax);
 | 
| -  __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
 | 
| +  __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
 | 
|  
 | 
|    __ bind(&done);
 | 
|    context()->Plug(eax);
 | 
| @@ -3119,14 +3171,14 @@
 | 
|    __ mov(index_1, Operand(esp, 1 * kPointerSize));
 | 
|    __ mov(index_2, Operand(esp, 0));
 | 
|    __ mov(temp, index_1);
 | 
| -  __ or_(temp, Operand(index_2));
 | 
| +  __ or_(temp, index_2);
 | 
|    __ JumpIfNotSmi(temp, &slow_case);
 | 
|  
 | 
|    // Check that both indices are valid.
 | 
|    __ mov(temp, FieldOperand(object, JSArray::kLengthOffset));
 | 
| -  __ cmp(temp, Operand(index_1));
 | 
| +  __ cmp(temp, index_1);
 | 
|    __ j(below_equal, &slow_case);
 | 
| -  __ cmp(temp, Operand(index_2));
 | 
| +  __ cmp(temp, index_2);
 | 
|    __ j(below_equal, &slow_case);
 | 
|  
 | 
|    // Bring addresses into index1 and index2.
 | 
| @@ -3139,16 +3191,35 @@
 | 
|    __ mov(Operand(index_2, 0), object);
 | 
|    __ mov(Operand(index_1, 0), temp);
 | 
|  
 | 
| -  Label new_space;
 | 
| -  __ InNewSpace(elements, temp, equal, &new_space);
 | 
| +  Label no_remembered_set;
 | 
| +  __ CheckPageFlag(elements,
 | 
| +                   temp,
 | 
| +                   1 << MemoryChunk::SCAN_ON_SCAVENGE,
 | 
| +                   not_zero,
 | 
| +                   &no_remembered_set,
 | 
| +                   Label::kNear);
 | 
| +  // Possible optimization: do a check that both values are Smis
 | 
| +  // (or them and test against Smi mask.)
 | 
|  
 | 
| -  __ mov(object, elements);
 | 
| -  __ RecordWriteHelper(object, index_1, temp);
 | 
| -  __ RecordWriteHelper(elements, index_2, temp);
 | 
| +  // We are swapping two objects in an array and the incremental marker never
 | 
| +  // pauses in the middle of scanning a single object.  Therefore the
 | 
| +  // incremental marker is not disturbed, so we don't need to call the
 | 
| +  // RecordWrite stub that notifies the incremental marker.
 | 
| +  __ RememberedSetHelper(elements,
 | 
| +                         index_1,
 | 
| +                         temp,
 | 
| +                         kDontSaveFPRegs,
 | 
| +                         MacroAssembler::kFallThroughAtEnd);
 | 
| +  __ RememberedSetHelper(elements,
 | 
| +                         index_2,
 | 
| +                         temp,
 | 
| +                         kDontSaveFPRegs,
 | 
| +                         MacroAssembler::kFallThroughAtEnd);
 | 
|  
 | 
| -  __ bind(&new_space);
 | 
| +  __ bind(&no_remembered_set);
 | 
| +
 | 
|    // We are done. Drop elements from the stack, and return undefined.
 | 
| -  __ add(Operand(esp), Immediate(3 * kPointerSize));
 | 
| +  __ add(esp, Immediate(3 * kPointerSize));
 | 
|    __ mov(eax, isolate()->factory()->undefined_value());
 | 
|    __ jmp(&done);
 | 
|  
 | 
| @@ -3221,11 +3292,11 @@
 | 
|    __ pop(left);
 | 
|  
 | 
|    Label done, fail, ok;
 | 
| -  __ cmp(left, Operand(right));
 | 
| +  __ cmp(left, right);
 | 
|    __ j(equal, &ok);
 | 
|    // Fail if either is a non-HeapObject.
 | 
|    __ mov(tmp, left);
 | 
| -  __ and_(Operand(tmp), right);
 | 
| +  __ and_(tmp, right);
 | 
|    __ JumpIfSmi(tmp, &fail);
 | 
|    __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset));
 | 
|    __ CmpInstanceType(tmp, JS_REGEXP_TYPE);
 | 
| @@ -3316,7 +3387,7 @@
 | 
|    Operand separator_operand = Operand(esp, 2 * kPointerSize);
 | 
|    Operand result_operand = Operand(esp, 1 * kPointerSize);
 | 
|    Operand array_length_operand = Operand(esp, 0);
 | 
| -  __ sub(Operand(esp), Immediate(2 * kPointerSize));
 | 
| +  __ sub(esp, Immediate(2 * kPointerSize));
 | 
|    __ cld();
 | 
|    // Check that the array is a JSArray
 | 
|    __ JumpIfSmi(array, &bailout);
 | 
| @@ -3352,7 +3423,7 @@
 | 
|    // Live loop registers: index, array_length, string,
 | 
|    //                      scratch, string_length, elements.
 | 
|    if (FLAG_debug_code) {
 | 
| -    __ cmp(index, Operand(array_length));
 | 
| +    __ cmp(index, array_length);
 | 
|      __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
 | 
|    }
 | 
|    __ bind(&loop);
 | 
| @@ -3370,8 +3441,8 @@
 | 
|    __ add(string_length,
 | 
|           FieldOperand(string, SeqAsciiString::kLengthOffset));
 | 
|    __ j(overflow, &bailout);
 | 
| -  __ add(Operand(index), Immediate(1));
 | 
| -  __ cmp(index, Operand(array_length));
 | 
| +  __ add(index, Immediate(1));
 | 
| +  __ cmp(index, array_length);
 | 
|    __ j(less, &loop);
 | 
|  
 | 
|    // If array_length is 1, return elements[0], a string.
 | 
| @@ -3405,10 +3476,10 @@
 | 
|    // to string_length.
 | 
|    __ mov(scratch, separator_operand);
 | 
|    __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset));
 | 
| -  __ sub(string_length, Operand(scratch));  // May be negative, temporarily.
 | 
| +  __ sub(string_length, scratch);  // May be negative, temporarily.
 | 
|    __ imul(scratch, array_length_operand);
 | 
|    __ j(overflow, &bailout);
 | 
| -  __ add(string_length, Operand(scratch));
 | 
| +  __ add(string_length, scratch);
 | 
|    __ j(overflow, &bailout);
 | 
|  
 | 
|    __ shr(string_length, 1);
 | 
| @@ -3449,7 +3520,7 @@
 | 
|    __ lea(string,
 | 
|           FieldOperand(string, SeqAsciiString::kHeaderSize));
 | 
|    __ CopyBytes(string, result_pos, string_length, scratch);
 | 
| -  __ add(Operand(index), Immediate(1));
 | 
| +  __ add(index, Immediate(1));
 | 
|    __ bind(&loop_1_condition);
 | 
|    __ cmp(index, array_length_operand);
 | 
|    __ j(less, &loop_1);  // End while (index < length).
 | 
| @@ -3490,7 +3561,7 @@
 | 
|    __ lea(string,
 | 
|           FieldOperand(string, SeqAsciiString::kHeaderSize));
 | 
|    __ CopyBytes(string, result_pos, string_length, scratch);
 | 
| -  __ add(Operand(index), Immediate(1));
 | 
| +  __ add(index, Immediate(1));
 | 
|  
 | 
|    __ cmp(index, array_length_operand);
 | 
|    __ j(less, &loop_2);  // End while (index < length).
 | 
| @@ -3531,7 +3602,7 @@
 | 
|    __ lea(string,
 | 
|           FieldOperand(string, SeqAsciiString::kHeaderSize));
 | 
|    __ CopyBytes(string, result_pos, string_length, scratch);
 | 
| -  __ add(Operand(index), Immediate(1));
 | 
| +  __ add(index, Immediate(1));
 | 
|  
 | 
|    __ cmp(index, array_length_operand);
 | 
|    __ j(less, &loop_3);  // End while (index < length).
 | 
| @@ -3543,7 +3614,7 @@
 | 
|    __ bind(&done);
 | 
|    __ mov(eax, result_operand);
 | 
|    // Drop temp values from the stack, and restore context register.
 | 
| -  __ add(Operand(esp), Immediate(3 * kPointerSize));
 | 
| +  __ add(esp, Immediate(3 * kPointerSize));
 | 
|  
 | 
|    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 | 
|    decrement_stack_height();
 | 
| @@ -3823,9 +3894,9 @@
 | 
|  
 | 
|    if (ShouldInlineSmiCase(expr->op())) {
 | 
|      if (expr->op() == Token::INC) {
 | 
| -      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
 | 
| +      __ add(eax, Immediate(Smi::FromInt(1)));
 | 
|      } else {
 | 
| -      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
 | 
| +      __ sub(eax, Immediate(Smi::FromInt(1)));
 | 
|      }
 | 
|      __ j(overflow, &stub_call, Label::kNear);
 | 
|      // We could eliminate this smi check if we split the code at
 | 
| @@ -3835,9 +3906,9 @@
 | 
|      __ bind(&stub_call);
 | 
|      // Call stub. Undo operation first.
 | 
|      if (expr->op() == Token::INC) {
 | 
| -      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
 | 
| +      __ sub(eax, Immediate(Smi::FromInt(1)));
 | 
|      } else {
 | 
| -      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
 | 
| +      __ add(eax, Immediate(Smi::FromInt(1)));
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -3956,10 +4027,14 @@
 | 
|  
 | 
|  
 | 
|  void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
 | 
| -                                                 Handle<String> check,
 | 
| -                                                 Label* if_true,
 | 
| -                                                 Label* if_false,
 | 
| -                                                 Label* fall_through) {
 | 
| +                                                 Handle<String> check) {
 | 
| +  Label materialize_true, materialize_false;
 | 
| +  Label* if_true = NULL;
 | 
| +  Label* if_false = NULL;
 | 
| +  Label* fall_through = NULL;
 | 
| +  context()->PrepareTest(&materialize_true, &materialize_false,
 | 
| +                         &if_true, &if_false, &fall_through);
 | 
| +
 | 
|    { AccumulatorValueContext context(this);
 | 
|      VisitForTypeofValue(expr);
 | 
|    }
 | 
| @@ -3998,8 +4073,11 @@
 | 
|      Split(not_zero, if_true, if_false, fall_through);
 | 
|    } else if (check->Equals(isolate()->heap()->function_symbol())) {
 | 
|      __ JumpIfSmi(eax, if_false);
 | 
| -    __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx);
 | 
| -    Split(above_equal, if_true, if_false, fall_through);
 | 
| +    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
 | 
| +    __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
 | 
| +    __ j(equal, if_true);
 | 
| +    __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
 | 
| +    Split(equal, if_true, if_false, fall_through);
 | 
|    } else if (check->Equals(isolate()->heap()->object_symbol())) {
 | 
|      __ JumpIfSmi(eax, if_false);
 | 
|      if (!FLAG_harmony_typeof) {
 | 
| @@ -4017,28 +4095,20 @@
 | 
|    } else {
 | 
|      if (if_false != fall_through) __ jmp(if_false);
 | 
|    }
 | 
| +  context()->Plug(if_true, if_false);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
 | 
| -                                                    Label* if_true,
 | 
| -                                                    Label* if_false,
 | 
| -                                                    Label* fall_through) {
 | 
| -  VisitForAccumulatorValue(expr);
 | 
| -  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 | 
| -
 | 
| -  __ cmp(eax, isolate()->factory()->undefined_value());
 | 
| -  Split(equal, if_true, if_false, fall_through);
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
 | 
|    Comment cmnt(masm_, "[ CompareOperation");
 | 
|    SetSourcePosition(expr->position());
 | 
|  
 | 
| +  // First we try a fast inlined version of the compare when one of
 | 
| +  // the operands is a literal.
 | 
| +  if (TryLiteralCompare(expr)) return;
 | 
| +
 | 
|    // Always perform the comparison for its control flow.  Pack the result
 | 
|    // into the expression's context after the comparison is performed.
 | 
| -
 | 
|    Label materialize_true, materialize_false;
 | 
|    Label* if_true = NULL;
 | 
|    Label* if_false = NULL;
 | 
| @@ -4046,16 +4116,9 @@
 | 
|    context()->PrepareTest(&materialize_true, &materialize_false,
 | 
|                           &if_true, &if_false, &fall_through);
 | 
|  
 | 
| -  // First we try a fast inlined version of the compare when one of
 | 
| -  // the operands is a literal.
 | 
| -  if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
 | 
| -    context()->Plug(if_true, if_false);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
|    Token::Value op = expr->op();
 | 
|    VisitForStackValue(expr->left());
 | 
| -  switch (expr->op()) {
 | 
| +  switch (op) {
 | 
|      case Token::IN:
 | 
|        VisitForStackValue(expr->right());
 | 
|        __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
 | 
| @@ -4071,7 +4134,7 @@
 | 
|        __ CallStub(&stub);
 | 
|        decrement_stack_height(2);
 | 
|        PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 | 
| -      __ test(eax, Operand(eax));
 | 
| +      __ test(eax, eax);
 | 
|        // The stub returns 0 for true.
 | 
|        Split(zero, if_true, if_false, fall_through);
 | 
|        break;
 | 
| @@ -4080,11 +4143,8 @@
 | 
|      default: {
 | 
|        VisitForAccumulatorValue(expr->right());
 | 
|        Condition cc = no_condition;
 | 
| -      bool strict = false;
 | 
|        switch (op) {
 | 
|          case Token::EQ_STRICT:
 | 
| -          strict = true;
 | 
| -          // Fall through
 | 
|          case Token::EQ:
 | 
|            cc = equal;
 | 
|            __ pop(edx);
 | 
| @@ -4120,10 +4180,10 @@
 | 
|        JumpPatchSite patch_site(masm_);
 | 
|        if (inline_smi_code) {
 | 
|          Label slow_case;
 | 
| -        __ mov(ecx, Operand(edx));
 | 
| -        __ or_(ecx, Operand(eax));
 | 
| +        __ mov(ecx, edx);
 | 
| +        __ or_(ecx, eax);
 | 
|          patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
 | 
| -        __ cmp(edx, Operand(eax));
 | 
| +        __ cmp(edx, eax);
 | 
|          Split(cc, if_true, if_false, NULL);
 | 
|          __ bind(&slow_case);
 | 
|        }
 | 
| @@ -4135,7 +4195,7 @@
 | 
|        patch_site.EmitPatchInfo();
 | 
|  
 | 
|        PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 | 
| -      __ test(eax, Operand(eax));
 | 
| +      __ test(eax, eax);
 | 
|        Split(cc, if_true, if_false, fall_through);
 | 
|      }
 | 
|    }
 | 
| @@ -4146,7 +4206,9 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
 | 
| +void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
 | 
| +                                              Expression* sub_expr,
 | 
| +                                              NilValue nil) {
 | 
|    Label materialize_true, materialize_false;
 | 
|    Label* if_true = NULL;
 | 
|    Label* if_false = NULL;
 | 
| @@ -4154,15 +4216,20 @@
 | 
|    context()->PrepareTest(&materialize_true, &materialize_false,
 | 
|                           &if_true, &if_false, &fall_through);
 | 
|  
 | 
| -  VisitForAccumulatorValue(expr->expression());
 | 
| +  VisitForAccumulatorValue(sub_expr);
 | 
|    PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 | 
| -
 | 
| -  __ cmp(eax, isolate()->factory()->null_value());
 | 
| -  if (expr->is_strict()) {
 | 
| +  Handle<Object> nil_value = nil == kNullValue ?
 | 
| +      isolate()->factory()->null_value() :
 | 
| +      isolate()->factory()->undefined_value();
 | 
| +  __ cmp(eax, nil_value);
 | 
| +  if (expr->op() == Token::EQ_STRICT) {
 | 
|      Split(equal, if_true, if_false, fall_through);
 | 
|    } else {
 | 
| +    Handle<Object> other_nil_value = nil == kNullValue ?
 | 
| +        isolate()->factory()->undefined_value() :
 | 
| +        isolate()->factory()->null_value();
 | 
|      __ j(equal, if_true);
 | 
| -    __ cmp(eax, isolate()->factory()->undefined_value());
 | 
| +    __ cmp(eax, other_nil_value);
 | 
|      __ j(equal, if_true);
 | 
|      __ JumpIfSmi(eax, if_false);
 | 
|      // It can be an undetectable object.
 | 
| @@ -4229,7 +4296,7 @@
 | 
|    // Cook return address on top of stack (smi encoded Code* delta)
 | 
|    ASSERT(!result_register().is(edx));
 | 
|    __ pop(edx);
 | 
| -  __ sub(Operand(edx), Immediate(masm_->CodeObject()));
 | 
| +  __ sub(edx, Immediate(masm_->CodeObject()));
 | 
|    STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
 | 
|    STATIC_ASSERT(kSmiTag == 0);
 | 
|    __ SmiTag(edx);
 | 
| @@ -4245,8 +4312,8 @@
 | 
|    // Uncook return address.
 | 
|    __ pop(edx);
 | 
|    __ SmiUntag(edx);
 | 
| -  __ add(Operand(edx), Immediate(masm_->CodeObject()));
 | 
| -  __ jmp(Operand(edx));
 | 
| +  __ add(edx, Immediate(masm_->CodeObject()));
 | 
| +  __ jmp(edx);
 | 
|  }
 | 
|  
 | 
|  
 | 
| 
 |