| Index: runtime/vm/code_patcher_ia32.cc
 | 
| diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
 | 
| index e1f54839c44a723a23eb81fb46670aded5a5d961..95d64e08e59c73a8175017f3b67af494df5627e5 100644
 | 
| --- a/runtime/vm/code_patcher_ia32.cc
 | 
| +++ b/runtime/vm/code_patcher_ia32.cc
 | 
| @@ -18,38 +18,52 @@ namespace dart {
 | 
|  
 | 
|  // The expected pattern of a Dart unoptimized call (static and instance):
 | 
|  //  mov ECX, ic-data
 | 
| -//  mov EDI, target-code-object
 | 
|  //  call target_address (stub)
 | 
|  //  <- return address
 | 
|  class UnoptimizedCall : public ValueObject {
 | 
|   public:
 | 
|    explicit UnoptimizedCall(uword return_address)
 | 
| -      : start_(return_address - kPatternSize) {
 | 
| -    ASSERT(IsValid());
 | 
| +      : start_(return_address - (kNumInstructions * kInstructionSize)) {
 | 
| +    ASSERT(IsValid(return_address));
 | 
| +    ASSERT(kInstructionSize == Assembler::kCallExternalLabelSize);
 | 
| +  }
 | 
| +
 | 
| +  static bool IsValid(uword return_address) {
 | 
| +    uint8_t* code_bytes =
 | 
| +        reinterpret_cast<uint8_t*>(
 | 
| +            return_address - (kNumInstructions * kInstructionSize));
 | 
| +    return (code_bytes[0] == 0xB9) &&
 | 
| +           (code_bytes[1 * kInstructionSize] == 0xE8);
 | 
| +  }
 | 
| +
 | 
| +  uword target() const {
 | 
| +    const uword offset = *reinterpret_cast<uword*>(call_address() + 1);
 | 
| +    return return_address() + offset;
 | 
| +  }
 | 
| +
 | 
| +  void set_target(uword target) const {
 | 
| +    uword* target_addr = reinterpret_cast<uword*>(call_address() + 1);
 | 
| +    uword offset = target - return_address();
 | 
| +    WritableInstructionsScope writable(reinterpret_cast<uword>(target_addr),
 | 
| +                                       sizeof(offset));
 | 
| +    *target_addr = offset;
 | 
| +    CPU::FlushICache(call_address(), kInstructionSize);
 | 
|    }
 | 
|  
 | 
|    RawObject* ic_data() const {
 | 
|      return *reinterpret_cast<RawObject**>(start_ + 1);
 | 
|    }
 | 
|  
 | 
| -  static const int kMovInstructionSize = 5;
 | 
| -  static const int kCallInstructionSize = 3;
 | 
| -  static const int kPatternSize =
 | 
| -      2 * kMovInstructionSize + kCallInstructionSize;
 | 
| +  static const int kNumInstructions = 2;
 | 
| +  static const int kInstructionSize = 5;  // All instructions have same length.
 | 
|  
 | 
|   private:
 | 
| -  bool IsValid() {
 | 
| -    uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_);
 | 
| -    return (code_bytes[0] == 0xB9) &&
 | 
| -           (code_bytes[2 * kMovInstructionSize] == 0xFF);
 | 
| -  }
 | 
| -
 | 
|    uword return_address() const {
 | 
| -    return start_ + kPatternSize;
 | 
| +    return start_ + kNumInstructions * kInstructionSize;
 | 
|    }
 | 
|  
 | 
|    uword call_address() const {
 | 
| -    return start_ + 2 * kMovInstructionSize;
 | 
| +    return start_ + 1 * kInstructionSize;
 | 
|    }
 | 
|  
 | 
|   protected:
 | 
| @@ -113,43 +127,45 @@ class UnoptimizedStaticCall : public UnoptimizedCall {
 | 
|  
 | 
|  // The expected pattern of a dart static call:
 | 
|  //  mov EDX, arguments_descriptor_array (optional in polymorphic calls)
 | 
| -//  mov EDI, Immediate(code_object)
 | 
| -//  call [EDI + entry_point_offset]
 | 
| +//  call target_address
 | 
|  //  <- return address
 | 
|  class StaticCall : public ValueObject {
 | 
|   public:
 | 
|    explicit StaticCall(uword return_address)
 | 
| -      : start_(return_address - (kMovInstructionSize + kCallInstructionSize)) {
 | 
| -    ASSERT(IsValid());
 | 
| +      : start_(return_address - (kNumInstructions * kInstructionSize)) {
 | 
| +    ASSERT(IsValid(return_address));
 | 
| +    ASSERT(kInstructionSize == Assembler::kCallExternalLabelSize);
 | 
|    }
 | 
|  
 | 
| -  bool IsValid() {
 | 
| -    uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_);
 | 
| -    return (code_bytes[0] == 0xBF) && (code_bytes[5] == 0xFF);
 | 
| +  static bool IsValid(uword return_address) {
 | 
| +    uint8_t* code_bytes =
 | 
| +        reinterpret_cast<uint8_t*>(
 | 
| +            return_address - (kNumInstructions * kInstructionSize));
 | 
| +    return (code_bytes[0] == 0xE8);
 | 
|    }
 | 
|  
 | 
| -  RawCode* target() const {
 | 
| -    const uword imm = *reinterpret_cast<uword*>(start_ + 1);
 | 
| -    return reinterpret_cast<RawCode*>(imm);
 | 
| +  uword target() const {
 | 
| +    const uword offset = *reinterpret_cast<uword*>(call_address() + 1);
 | 
| +    return return_address() + offset;
 | 
|    }
 | 
|  
 | 
| -  void set_target(const Code& target) const {
 | 
| -    uword* target_addr = reinterpret_cast<uword*>(start_ + 1);
 | 
| -    uword imm = reinterpret_cast<uword>(target.raw());
 | 
| -    *target_addr = imm;
 | 
| -    CPU::FlushICache(start_ + 1, sizeof(imm));
 | 
| +  void set_target(uword target) const {
 | 
| +    uword* target_addr = reinterpret_cast<uword*>(call_address() + 1);
 | 
| +    uword offset = target - return_address();
 | 
| +    *target_addr = offset;
 | 
| +    CPU::FlushICache(call_address(), kInstructionSize);
 | 
|    }
 | 
|  
 | 
| -  static const int kMovInstructionSize = 5;
 | 
| -  static const int kCallInstructionSize = 3;
 | 
| +  static const int kNumInstructions = 1;
 | 
| +  static const int kInstructionSize = 5;  // All instructions have same length.
 | 
|  
 | 
|   private:
 | 
|    uword return_address() const {
 | 
| -    return start_ + kMovInstructionSize +  kCallInstructionSize;
 | 
| +    return start_ + kNumInstructions * kInstructionSize;
 | 
|    }
 | 
|  
 | 
|    uword call_address() const {
 | 
| -    return start_ + kMovInstructionSize;
 | 
| +    return start_;
 | 
|    }
 | 
|  
 | 
|    uword start_;
 | 
| @@ -158,8 +174,8 @@ class StaticCall : public ValueObject {
 | 
|  };
 | 
|  
 | 
|  
 | 
| -RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
 | 
| -                                            const Code& code) {
 | 
| +uword CodePatcher::GetStaticCallTargetAt(uword return_address,
 | 
| +                                         const Code& code) {
 | 
|    ASSERT(code.ContainsInstructionAt(return_address));
 | 
|    StaticCall call(return_address);
 | 
|    return call.target();
 | 
| @@ -168,16 +184,23 @@ RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
 | 
|  
 | 
|  void CodePatcher::PatchStaticCallAt(uword return_address,
 | 
|                                      const Code& code,
 | 
| -                                    const Code& new_target) {
 | 
| -  const Instructions& instrs = Instructions::Handle(code.instructions());
 | 
| -  WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size());
 | 
| +                                    uword new_target) {
 | 
|    ASSERT(code.ContainsInstructionAt(return_address));
 | 
|    StaticCall call(return_address);
 | 
|    call.set_target(new_target);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) {
 | 
| +void CodePatcher::PatchInstanceCallAt(uword return_address,
 | 
| +                                      const Code& code,
 | 
| +                                      uword new_target) {
 | 
| +  ASSERT(code.ContainsInstructionAt(return_address));
 | 
| +  InstanceCall call(return_address);
 | 
| +  call.set_target(new_target);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void CodePatcher::InsertCallAt(uword start, uword target) {
 | 
|    // The inserted call should not overlap the lazy deopt jump code.
 | 
|    ASSERT(start + CallPattern::pattern_length_in_bytes() <= target);
 | 
|    *reinterpret_cast<uint8_t*>(start) = 0xE8;
 | 
| @@ -187,14 +210,14 @@ void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -RawCode* CodePatcher::GetInstanceCallAt(
 | 
| +uword CodePatcher::GetInstanceCallAt(
 | 
|      uword return_address, const Code& code, ICData* ic_data) {
 | 
|    ASSERT(code.ContainsInstructionAt(return_address));
 | 
|    InstanceCall call(return_address);
 | 
|    if (ic_data != NULL) {
 | 
|      *ic_data ^= call.ic_data();
 | 
|    }
 | 
| -  return Code::null();
 | 
| +  return call.target();
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -215,21 +238,26 @@ void CodePatcher::PatchNativeCallAt(uword return_address,
 | 
|                                      const Code& code,
 | 
|                                      NativeFunction target,
 | 
|                                      const Code& trampoline) {
 | 
| -  UNREACHABLE();
 | 
| +  ASSERT(code.ContainsInstructionAt(return_address));
 | 
| +  NativeCall call(return_address);
 | 
| +  call.set_target(trampoline.EntryPoint());
 | 
| +  call.set_native_function(target);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -RawCode* CodePatcher::GetNativeCallAt(uword return_address,
 | 
| -                                      const Code& code,
 | 
| -                                      NativeFunction* target) {
 | 
| -  UNREACHABLE();
 | 
| -  return NULL;
 | 
| +uword CodePatcher::GetNativeCallAt(uword return_address,
 | 
| +                                   const Code& code,
 | 
| +                                   NativeFunction* target) {
 | 
| +  ASSERT(code.ContainsInstructionAt(return_address));
 | 
| +  NativeCall call(return_address);
 | 
| +  *target = call.native_function();
 | 
| +  return call.target();
 | 
|  }
 | 
|  
 | 
|  
 | 
|  
 | 
|  intptr_t CodePatcher::InstanceCallSizeInBytes() {
 | 
| -  return InstanceCall::kPatternSize;
 | 
| +  return InstanceCall::kNumInstructions * InstanceCall::kInstructionSize;
 | 
|  }
 | 
|  
 | 
|  
 | 
| 
 |