| Index: src/ia32/lithium-codegen-ia32.cc
 | 
| ===================================================================
 | 
| --- src/ia32/lithium-codegen-ia32.cc	(revision 9531)
 | 
| +++ src/ia32/lithium-codegen-ia32.cc	(working copy)
 | 
| @@ -70,6 +70,17 @@
 | 
|    ASSERT(is_unused());
 | 
|    status_ = GENERATING;
 | 
|    CpuFeatures::Scope scope(SSE2);
 | 
| +
 | 
| +  CodeStub::GenerateFPStubs();
 | 
| +
 | 
| +  // 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 in GeneratePrologue).
 | 
| +  FrameScope frame_scope(masm_, StackFrame::MANUAL);
 | 
| +
 | 
| +  dynamic_frame_alignment_ = chunk()->num_double_slots() > 2 ||
 | 
| +                             info()->osr_ast_id() != AstNode::kNoNumber;
 | 
| +
 | 
|    return GeneratePrologue() &&
 | 
|        GenerateBody() &&
 | 
|        GenerateDeferredCode() &&
 | 
| @@ -144,6 +155,29 @@
 | 
|      __ bind(&ok);
 | 
|    }
 | 
|  
 | 
| +  if (dynamic_frame_alignment_) {
 | 
| +    Label do_not_pad, align_loop;
 | 
| +    STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
 | 
| +    // Align esp to a multiple of 2 * kPointerSize.
 | 
| +    __ test(esp, Immediate(kPointerSize));
 | 
| +    __ j(zero, &do_not_pad, Label::kNear);
 | 
| +    __ push(Immediate(0));
 | 
| +    __ mov(ebx, esp);
 | 
| +    // Copy arguments, receiver, and return address.
 | 
| +    __ mov(ecx, Immediate(scope()->num_parameters() + 2));
 | 
| +
 | 
| +    __ bind(&align_loop);
 | 
| +    __ mov(eax, Operand(ebx, 1 * kPointerSize));
 | 
| +    __ mov(Operand(ebx, 0), eax);
 | 
| +    __ add(Operand(ebx), Immediate(kPointerSize));
 | 
| +    __ dec(ecx);
 | 
| +    __ j(not_zero, &align_loop, Label::kNear);
 | 
| +    __ mov(Operand(ebx, 0),
 | 
| +           Immediate(isolate()->factory()->frame_alignment_marker()));
 | 
| +
 | 
| +    __ bind(&do_not_pad);
 | 
| +  }
 | 
| +
 | 
|    __ push(ebp);  // Caller's frame pointer.
 | 
|    __ mov(ebp, esp);
 | 
|    __ push(esi);  // Callee's context.
 | 
| @@ -204,11 +238,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 to 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);
 | 
|        }
 | 
|      }
 | 
|      Comment(";;; End allocate local context");
 | 
| @@ -260,6 +295,9 @@
 | 
|      for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
 | 
|        LDeferredCode* code = deferred_[i];
 | 
|        __ bind(code->entry());
 | 
| +      Comment(";;; Deferred code @%d: %s.",
 | 
| +              code->instruction_index(),
 | 
| +              code->instr()->Mnemonic());
 | 
|        code->Generate();
 | 
|        __ jmp(code->exit());
 | 
|      }
 | 
| @@ -481,14 +519,18 @@
 | 
|                                         int argc,
 | 
|                                         LInstruction* instr,
 | 
|                                         LOperand* context) {
 | 
| -  ASSERT(context->IsRegister() || context->IsStackSlot());
 | 
|    if (context->IsRegister()) {
 | 
|      if (!ToRegister(context).is(esi)) {
 | 
|        __ mov(esi, ToRegister(context));
 | 
|      }
 | 
| +  } else if (context->IsStackSlot()) {
 | 
| +    __ mov(esi, ToOperand(context));
 | 
| +  } else if (context->IsConstantOperand()) {
 | 
| +    Handle<Object> literal =
 | 
| +        chunk_->LookupLiteral(LConstantOperand::cast(context));
 | 
| +    LoadHeapObject(esi, Handle<Context>::cast(literal));
 | 
|    } else {
 | 
| -    // Context is stack slot.
 | 
| -    __ mov(esi, ToOperand(context));
 | 
| +    UNREACHABLE();
 | 
|    }
 | 
|  
 | 
|    __ CallRuntimeSaveDoubles(id);
 | 
| @@ -669,7 +711,7 @@
 | 
|      int arguments,
 | 
|      int deoptimization_index) {
 | 
|    ASSERT(kind == expected_safepoint_kind_);
 | 
| -  const ZoneList<LOperand*>* operands = pointers->operands();
 | 
| +  const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
 | 
|    Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
 | 
|        kind, arguments, deoptimization_index);
 | 
|    for (int i = 0; i < operands->length(); i++) {
 | 
| @@ -1200,8 +1242,13 @@
 | 
|  
 | 
|  
 | 
|  void LCodeGen::DoConstantT(LConstantT* instr) {
 | 
| -  ASSERT(instr->result()->IsRegister());
 | 
| -  __ Set(ToRegister(instr->result()), Immediate(instr->value()));
 | 
| +  Register reg = ToRegister(instr->result());
 | 
| +  Handle<Object> handle = instr->value();
 | 
| +  if (handle->IsHeapObject()) {
 | 
| +    LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
 | 
| +  } else {
 | 
| +    __ Set(reg, Immediate(handle));
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1577,23 +1624,33 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
 | 
| +void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
 | 
|    Register reg = ToRegister(instr->InputAt(0));
 | 
| +  int false_block = chunk_->LookupDestination(instr->false_block_id());
 | 
|  
 | 
| -  // TODO(fsc): If the expression is known to be a smi, then it's
 | 
| -  // definitely not null. Jump to the false block.
 | 
| +  // If the expression is known to be untagged or a smi, then it's definitely
 | 
| +  // not null, and it can't be a an undetectable object.
 | 
| +  if (instr->hydrogen()->representation().IsSpecialization() ||
 | 
| +      instr->hydrogen()->type().IsSmi()) {
 | 
| +    EmitGoto(false_block);
 | 
| +    return;
 | 
| +  }
 | 
|  
 | 
|    int true_block = chunk_->LookupDestination(instr->true_block_id());
 | 
| -  int false_block = chunk_->LookupDestination(instr->false_block_id());
 | 
| -
 | 
| -  __ cmp(reg, factory()->null_value());
 | 
| -  if (instr->is_strict()) {
 | 
| +  Handle<Object> nil_value = instr->nil() == kNullValue ?
 | 
| +      factory()->null_value() :
 | 
| +      factory()->undefined_value();
 | 
| +  __ cmp(reg, nil_value);
 | 
| +  if (instr->kind() == kStrictEquality) {
 | 
|      EmitBranch(true_block, false_block, equal);
 | 
|    } else {
 | 
| +    Handle<Object> other_nil_value = instr->nil() == kNullValue ?
 | 
| +        factory()->undefined_value() :
 | 
| +        factory()->null_value();
 | 
|      Label* true_label = chunk_->GetAssemblyLabel(true_block);
 | 
|      Label* false_label = chunk_->GetAssemblyLabel(false_block);
 | 
|      __ j(equal, true_label);
 | 
| -    __ cmp(reg, factory()->undefined_value());
 | 
| +    __ cmp(reg, other_nil_value);
 | 
|      __ j(equal, true_label);
 | 
|      __ JumpIfSmi(reg, false_label);
 | 
|      // Check for undetectable objects by looking in the bit field in
 | 
| @@ -1745,28 +1802,36 @@
 | 
|    ASSERT(!input.is(temp));
 | 
|    ASSERT(!temp.is(temp2));  // But input and temp2 may be the same register.
 | 
|    __ JumpIfSmi(input, is_false);
 | 
| -  __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
 | 
| -  __ j(below, is_false);
 | 
|  
 | 
| -  // Map is now in temp.
 | 
| -  // Functions have class 'Function'.
 | 
| -  __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
 | 
|    if (class_name->IsEqualTo(CStrVector("Function"))) {
 | 
| -    __ j(above_equal, is_true);
 | 
| +    // Assuming the following assertions, we can use the same compares to test
 | 
| +    // for both being a function type and being in the object type range.
 | 
| +    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
 | 
| +    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 | 
| +                  FIRST_SPEC_OBJECT_TYPE + 1);
 | 
| +    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 | 
| +                  LAST_SPEC_OBJECT_TYPE - 1);
 | 
| +    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
 | 
| +    __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
 | 
| +    __ j(below, is_false);
 | 
| +    __ j(equal, is_true);
 | 
| +    __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
 | 
| +    __ j(equal, is_true);
 | 
|    } else {
 | 
| -    __ j(above_equal, is_false);
 | 
| +    // Faster code path to avoid two compares: subtract lower bound from the
 | 
| +    // actual type and do a signed compare with the width of the type range.
 | 
| +    __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
 | 
| +    __ mov(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
 | 
| +    __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
 | 
| +    __ cmpb(Operand(temp2),
 | 
| +            static_cast<int8_t>(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
 | 
| +                                FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
 | 
| +    __ j(above, is_false);
 | 
|    }
 | 
|  
 | 
| +  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
 | 
|    // Check if the constructor in the map is a function.
 | 
|    __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
 | 
| -
 | 
| -  // 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);
 | 
| -
 | 
|    // Objects with a non-function constructor have class 'Object'.
 | 
|    __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
 | 
|    if (class_name->IsEqualTo(CStrVector("Object"))) {
 | 
| @@ -1851,9 +1916,8 @@
 | 
|      virtual void Generate() {
 | 
|        codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
 | 
|      }
 | 
| -
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|      Label* map_check() { return &map_check_; }
 | 
| -
 | 
|     private:
 | 
|      LInstanceOfKnownGlobal* instr_;
 | 
|      Label map_check_;
 | 
| @@ -1991,6 +2055,17 @@
 | 
|    }
 | 
|    __ mov(esp, ebp);
 | 
|    __ pop(ebp);
 | 
| +  if (dynamic_frame_alignment_) {
 | 
| +    Label aligned;
 | 
| +    // Frame alignment marker (padding) is below arguments,
 | 
| +    // and receiver, so its return-address-relative offset is
 | 
| +    // (num_arguments + 2) words.
 | 
| +    __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
 | 
| +           Immediate(factory()->frame_alignment_marker()));
 | 
| +    __ j(not_equal, &aligned);
 | 
| +    __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
 | 
| +    __ bind(&aligned);
 | 
| +  }
 | 
|    __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
 | 
|  }
 | 
|  
 | 
| @@ -1998,7 +2073,7 @@
 | 
|  void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 | 
|    Register result = ToRegister(instr->result());
 | 
|    __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
 | 
| -  if (instr->hydrogen()->check_hole_value()) {
 | 
| +  if (instr->hydrogen()->RequiresHoleCheck()) {
 | 
|      __ cmp(result, factory()->the_hole_value());
 | 
|      DeoptimizeIf(equal, instr->environment());
 | 
|    }
 | 
| @@ -2019,20 +2094,34 @@
 | 
|  
 | 
|  
 | 
|  void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
 | 
| +  Register object = ToRegister(instr->TempAt(0));
 | 
| +  Register address = ToRegister(instr->TempAt(1));
 | 
|    Register value = ToRegister(instr->InputAt(0));
 | 
| -  Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
 | 
| +  ASSERT(!value.is(object));
 | 
| +  Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell());
 | 
|  
 | 
| +  int offset = JSGlobalPropertyCell::kValueOffset;
 | 
| +  __ mov(object, Immediate(cell_handle));
 | 
| +
 | 
|    // If the cell we are storing to contains the hole it could have
 | 
|    // been deleted from the property dictionary. In that case, we need
 | 
|    // to update the property details in the property dictionary to mark
 | 
|    // it as no longer deleted. We deoptimize in that case.
 | 
| -  if (instr->hydrogen()->check_hole_value()) {
 | 
| -    __ cmp(cell_operand, factory()->the_hole_value());
 | 
| +  if (instr->hydrogen()->RequiresHoleCheck()) {
 | 
| +    __ cmp(FieldOperand(object, offset), factory()->the_hole_value());
 | 
|      DeoptimizeIf(equal, instr->environment());
 | 
|    }
 | 
|  
 | 
|    // Store the value.
 | 
| -  __ mov(cell_operand, value);
 | 
| +  __ mov(FieldOperand(object, offset), value);
 | 
| +
 | 
| +  // Cells are always in the remembered set.
 | 
| +  __ RecordWriteField(object,
 | 
| +                      offset,
 | 
| +                      value,
 | 
| +                      address,
 | 
| +                      kSaveFPRegs,
 | 
| +                      OMIT_REMEMBERED_SET);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -2063,7 +2152,7 @@
 | 
|    if (instr->needs_write_barrier()) {
 | 
|      Register temp = ToRegister(instr->TempAt(0));
 | 
|      int offset = Context::SlotOffset(instr->slot_index());
 | 
| -    __ RecordWrite(context, offset, value, temp);
 | 
| +    __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -2280,16 +2369,14 @@
 | 
|      LLoadKeyedFastDoubleElement* instr) {
 | 
|    XMMRegister result = ToDoubleRegister(instr->result());
 | 
|  
 | 
| -  if (instr->hydrogen()->RequiresHoleCheck()) {
 | 
| -    int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
 | 
| -        sizeof(kHoleNanLower32);
 | 
| -    Operand hole_check_operand = BuildFastArrayOperand(
 | 
| -        instr->elements(), instr->key(),
 | 
| -        FAST_DOUBLE_ELEMENTS,
 | 
| -        offset);
 | 
| -    __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
 | 
| -    DeoptimizeIf(equal, instr->environment());
 | 
| -  }
 | 
| +  int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
 | 
| +      sizeof(kHoleNanLower32);
 | 
| +  Operand hole_check_operand = BuildFastArrayOperand(
 | 
| +      instr->elements(), instr->key(),
 | 
| +      FAST_DOUBLE_ELEMENTS,
 | 
| +      offset);
 | 
| +  __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
 | 
| +  DeoptimizeIf(equal, instr->environment());
 | 
|  
 | 
|    Operand double_load_operand = BuildFastArrayOperand(
 | 
|        instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
 | 
| @@ -2359,6 +2446,7 @@
 | 
|          break;
 | 
|        case EXTERNAL_FLOAT_ELEMENTS:
 | 
|        case EXTERNAL_DOUBLE_ELEMENTS:
 | 
| +      case FAST_SMI_ONLY_ELEMENTS:
 | 
|        case FAST_ELEMENTS:
 | 
|        case FAST_DOUBLE_ELEMENTS:
 | 
|        case DICTIONARY_ELEMENTS:
 | 
| @@ -2680,6 +2768,7 @@
 | 
|      virtual void Generate() {
 | 
|        codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
 | 
|      }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LUnaryMathOperation* instr_;
 | 
|    };
 | 
| @@ -3005,7 +3094,7 @@
 | 
|    ASSERT(ToRegister(instr->result()).is(eax));
 | 
|  
 | 
|    int arity = instr->arity();
 | 
| -  CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
 | 
| +  CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
 | 
|    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 | 
|    __ Drop(1);
 | 
|  }
 | 
| @@ -3062,7 +3151,7 @@
 | 
|      if (instr->needs_write_barrier()) {
 | 
|        Register temp = ToRegister(instr->TempAt(0));
 | 
|        // Update the write barrier for the object for in-object properties.
 | 
| -      __ RecordWrite(object, offset, value, temp);
 | 
| +      __ RecordWriteField(object, offset, value, temp, kSaveFPRegs);
 | 
|      }
 | 
|    } else {
 | 
|      Register temp = ToRegister(instr->TempAt(0));
 | 
| @@ -3071,7 +3160,7 @@
 | 
|      if (instr->needs_write_barrier()) {
 | 
|        // Update the write barrier for the properties array.
 | 
|        // object is used as a scratch register.
 | 
| -      __ RecordWrite(temp, offset, value, object);
 | 
| +      __ RecordWriteField(temp, offset, value, object, kSaveFPRegs);
 | 
|      }
 | 
|    }
 | 
|  }
 | 
| @@ -3130,6 +3219,7 @@
 | 
|          break;
 | 
|        case EXTERNAL_FLOAT_ELEMENTS:
 | 
|        case EXTERNAL_DOUBLE_ELEMENTS:
 | 
| +      case FAST_SMI_ONLY_ELEMENTS:
 | 
|        case FAST_ELEMENTS:
 | 
|        case FAST_DOUBLE_ELEMENTS:
 | 
|        case DICTIONARY_ELEMENTS:
 | 
| @@ -3146,6 +3236,13 @@
 | 
|    Register elements = ToRegister(instr->object());
 | 
|    Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
 | 
|  
 | 
| +  // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
 | 
| +  // conversion, so it deopts in that case.
 | 
| +  if (instr->hydrogen()->ValueNeedsSmiCheck()) {
 | 
| +    __ test(value, Immediate(kSmiTagMask));
 | 
| +    DeoptimizeIf(not_zero, instr->environment());
 | 
| +  }
 | 
| +
 | 
|    // Do the store.
 | 
|    if (instr->key()->IsConstantOperand()) {
 | 
|      ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
 | 
| @@ -3168,7 +3265,7 @@
 | 
|                          key,
 | 
|                          times_pointer_size,
 | 
|                          FixedArray::kHeaderSize));
 | 
| -    __ RecordWrite(elements, key, value);
 | 
| +    __ RecordWrite(elements, key, value, kSaveFPRegs);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -3212,6 +3309,7 @@
 | 
|      DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
 | 
|          : LDeferredCode(codegen), instr_(instr) { }
 | 
|      virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LStringCharCodeAt* instr_;
 | 
|    };
 | 
| @@ -3334,6 +3432,7 @@
 | 
|      DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
 | 
|          : LDeferredCode(codegen), instr_(instr) { }
 | 
|      virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LStringCharFromCode* instr_;
 | 
|    };
 | 
| @@ -3413,6 +3512,7 @@
 | 
|      DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
 | 
|          : LDeferredCode(codegen), instr_(instr) { }
 | 
|      virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LNumberTagI* instr_;
 | 
|    };
 | 
| @@ -3480,6 +3580,7 @@
 | 
|      DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
 | 
|          : LDeferredCode(codegen), instr_(instr) { }
 | 
|      virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LNumberTagD* instr_;
 | 
|    };
 | 
| @@ -3581,16 +3682,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -class DeferredTaggedToI: public LDeferredCode {
 | 
| - public:
 | 
| -  DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
 | 
| -      : LDeferredCode(codegen), instr_(instr) { }
 | 
| -  virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
 | 
| - private:
 | 
| -  LTaggedToI* instr_;
 | 
| -};
 | 
| -
 | 
| -
 | 
|  void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
 | 
|    Label done, heap_number;
 | 
|    Register input_reg = ToRegister(instr->InputAt(0));
 | 
| @@ -3672,6 +3763,16 @@
 | 
|  
 | 
|  
 | 
|  void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
 | 
| +  class DeferredTaggedToI: public LDeferredCode {
 | 
| +   public:
 | 
| +    DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
 | 
| +        : LDeferredCode(codegen), instr_(instr) { }
 | 
| +    virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
| +   private:
 | 
| +    LTaggedToI* instr_;
 | 
| +  };
 | 
| +
 | 
|    LOperand* input = instr->InputAt(0);
 | 
|    ASSERT(input->IsRegister());
 | 
|    ASSERT(input->Equals(instr->result()));
 | 
| @@ -3882,9 +3983,16 @@
 | 
|  
 | 
|  
 | 
|  void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
 | 
| -  ASSERT(instr->InputAt(0)->IsRegister());
 | 
| -  Operand operand = ToOperand(instr->InputAt(0));
 | 
| -  __ cmp(operand, instr->hydrogen()->target());
 | 
| +  Handle<JSFunction> target = instr->hydrogen()->target();
 | 
| +  if (isolate()->heap()->InNewSpace(*target)) {
 | 
| +    Register reg = ToRegister(instr->value());
 | 
| +    Handle<JSGlobalPropertyCell> cell =
 | 
| +        isolate()->factory()->NewJSGlobalPropertyCell(target);
 | 
| +    __ cmp(reg, Operand::Cell(cell));
 | 
| +  } else {
 | 
| +    Operand operand = ToOperand(instr->value());
 | 
| +    __ cmp(operand, instr->hydrogen()->target());
 | 
| +  }
 | 
|    DeoptimizeIf(not_equal, instr->environment());
 | 
|  }
 | 
|  
 | 
| @@ -4188,10 +4296,12 @@
 | 
|      final_branch_condition = not_zero;
 | 
|  
 | 
|    } else if (type_name->Equals(heap()->function_symbol())) {
 | 
| -    STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
 | 
| +    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
 | 
|      __ JumpIfSmi(input, false_label);
 | 
| -    __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input);
 | 
| -    final_branch_condition = above_equal;
 | 
| +    __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
 | 
| +    __ j(equal, true_label);
 | 
| +    __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
 | 
| +    final_branch_condition = equal;
 | 
|  
 | 
|    } else if (type_name->Equals(heap()->object_symbol())) {
 | 
|      __ JumpIfSmi(input, false_label);
 | 
| @@ -4303,6 +4413,7 @@
 | 
|      DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
 | 
|          : LDeferredCode(codegen), instr_(instr) { }
 | 
|      virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
 | 
| +    virtual LInstruction* instr() { return instr_; }
 | 
|     private:
 | 
|      LStackCheck* instr_;
 | 
|    };
 | 
| 
 |