| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "vm/deopt_instructions.h" |
| 6 |
| 7 #include "vm/intermediate_language.h" |
| 8 #include "vm/locations.h" |
| 9 #include "vm/parser.h" |
| 10 |
| 11 namespace dart { |
| 12 |
| 13 // Deoptimization instruction moving value from optimized frame at |
| 14 // 'from_index' to specified slots in the unoptimized frame. |
| 15 // 'from_index' represents the local count >= 0, first |
| 16 // argument being 0. |
| 17 class DeoptStackSlotInstr : public DeoptInstr { |
| 18 public: |
| 19 explicit DeoptStackSlotInstr(intptr_t from_index) |
| 20 : stack_slot_index_(from_index) { |
| 21 ASSERT(stack_slot_index_ >= 0); |
| 22 } |
| 23 |
| 24 virtual intptr_t from_index() const { return stack_slot_index_; } |
| 25 virtual DeoptInstr::Kind kind() const { return kCopyStackSlot; } |
| 26 |
| 27 virtual const char* ToCString() const { |
| 28 intptr_t len = OS::SNPrint(NULL, 0, "s%d", stack_slot_index_); |
| 29 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 30 OS::SNPrint(chars, len + 1, "s%d", stack_slot_index_); |
| 31 return chars; |
| 32 } |
| 33 |
| 34 private: |
| 35 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. |
| 36 |
| 37 DISALLOW_COPY_AND_ASSIGN(DeoptStackSlotInstr); |
| 38 }; |
| 39 |
| 40 |
| 41 // Deoptimization instruction creating return address using function and |
| 42 // deopt-id stored at 'object_table_index'. |
| 43 class DeoptRetAddrInstr : public DeoptInstr { |
| 44 public: |
| 45 explicit DeoptRetAddrInstr(intptr_t object_table_index) |
| 46 : object_table_index_(object_table_index) { |
| 47 ASSERT(object_table_index >= 0); |
| 48 } |
| 49 |
| 50 virtual intptr_t from_index() const { return object_table_index_; } |
| 51 virtual DeoptInstr::Kind kind() const { return kSetRetAddress; } |
| 52 |
| 53 virtual const char* ToCString() const { |
| 54 intptr_t len = OS::SNPrint(NULL, 0, "ret oti:%d", object_table_index_); |
| 55 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 56 OS::SNPrint(chars, len + 1, "ret oti:%d", object_table_index_); |
| 57 return chars; |
| 58 } |
| 59 |
| 60 private: |
| 61 const intptr_t object_table_index_; |
| 62 |
| 63 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddrInstr); |
| 64 }; |
| 65 |
| 66 |
| 67 // Deoptimization instruction moving a constant stored at 'object_table_index'. |
| 68 class DeoptConstantInstr : public DeoptInstr { |
| 69 public: |
| 70 explicit DeoptConstantInstr(intptr_t object_table_index) |
| 71 : object_table_index_(object_table_index) { |
| 72 ASSERT(object_table_index >= 0); |
| 73 } |
| 74 |
| 75 virtual intptr_t from_index() const { return object_table_index_; } |
| 76 virtual DeoptInstr::Kind kind() const { return kCopyConstant; } |
| 77 |
| 78 virtual const char* ToCString() const { |
| 79 intptr_t len = OS::SNPrint(NULL, 0, "const oti:%d", object_table_index_); |
| 80 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 81 OS::SNPrint(chars, len + 1, "const oti:%d", object_table_index_); |
| 82 return chars; |
| 83 } |
| 84 |
| 85 private: |
| 86 const intptr_t object_table_index_; |
| 87 |
| 88 DISALLOW_COPY_AND_ASSIGN(DeoptConstantInstr); |
| 89 }; |
| 90 |
| 91 |
| 92 // Deoptimization instruction moving a register. |
| 93 class DeoptRegisterInstr: public DeoptInstr { |
| 94 public: |
| 95 explicit DeoptRegisterInstr(intptr_t reg_as_int) |
| 96 : reg_(static_cast<Register>(reg_as_int)) {} |
| 97 |
| 98 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
| 99 virtual DeoptInstr::Kind kind() const { return kCopyRegister; } |
| 100 |
| 101 virtual const char* ToCString() const { |
| 102 return Assembler::RegisterName(reg_); |
| 103 } |
| 104 |
| 105 private: |
| 106 const Register reg_; |
| 107 |
| 108 DISALLOW_COPY_AND_ASSIGN(DeoptRegisterInstr); |
| 109 }; |
| 110 |
| 111 |
| 112 // Deoptimization instruction creating a PC marker for the code of |
| 113 // function at 'object_table_index'. |
| 114 class DeoptPcMarkerInstr : public DeoptInstr { |
| 115 public: |
| 116 explicit DeoptPcMarkerInstr(intptr_t object_table_index) |
| 117 : object_table_index_(object_table_index) { |
| 118 ASSERT(object_table_index >= 0); |
| 119 } |
| 120 |
| 121 virtual intptr_t from_index() const { return object_table_index_; } |
| 122 virtual DeoptInstr::Kind kind() const { return kSetPcMarker; } |
| 123 |
| 124 virtual const char* ToCString() const { |
| 125 intptr_t len = OS::SNPrint(NULL, 0, "pcmark oti:%d", object_table_index_); |
| 126 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 127 OS::SNPrint(chars, len + 1, "pcmark oti:%d", object_table_index_); |
| 128 return chars; |
| 129 } |
| 130 |
| 131 private: |
| 132 intptr_t object_table_index_; |
| 133 |
| 134 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); |
| 135 }; |
| 136 |
| 137 |
| 138 // Deoptimization instruction copying the caller saved FP from optimized frame. |
| 139 class DeoptCallerFpInstr : public DeoptInstr { |
| 140 public: |
| 141 DeoptCallerFpInstr() {} |
| 142 |
| 143 virtual intptr_t from_index() const { return 0; } |
| 144 virtual DeoptInstr::Kind kind() const { return kSetCallerFp; } |
| 145 |
| 146 virtual const char* ToCString() const { return "callerfp"; } |
| 147 |
| 148 private: |
| 149 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr); |
| 150 }; |
| 151 |
| 152 |
| 153 // Deoptimization instruction copying the caller return address from optimzied |
| 154 // frame. |
| 155 class DeoptCallerPcInstr : public DeoptInstr { |
| 156 public: |
| 157 DeoptCallerPcInstr() {} |
| 158 |
| 159 virtual intptr_t from_index() const { return 0; } |
| 160 virtual DeoptInstr::Kind kind() const { return kSetCallerFp; } |
| 161 |
| 162 virtual const char* ToCString() const { return "callerpc"; } |
| 163 |
| 164 private: |
| 165 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr); |
| 166 }; |
| 167 |
| 168 |
| 169 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { |
| 170 Kind kind = static_cast<Kind>(kind_as_int); |
| 171 switch (kind) { |
| 172 case kCopyStackSlot: return new DeoptStackSlotInstr(from_index); |
| 173 case kSetRetAddress: return new DeoptRetAddrInstr(from_index); |
| 174 case kCopyConstant: return new DeoptConstantInstr(from_index); |
| 175 case kCopyRegister: return new DeoptRegisterInstr(from_index); |
| 176 case kSetPcMarker: return new DeoptPcMarkerInstr(from_index); |
| 177 case kSetCallerFp: return new DeoptCallerFpInstr(); |
| 178 case kSetCallerPc: return new DeoptCallerPcInstr(); |
| 179 } |
| 180 UNREACHABLE(); |
| 181 return NULL; |
| 182 } |
| 183 |
| 184 |
| 185 intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const { |
| 186 for (intptr_t i = 0; i < object_table_.Length(); i++) { |
| 187 if (object_table_.At(i) == obj.raw()) { |
| 188 return i; |
| 189 } |
| 190 } |
| 191 // Add object. |
| 192 const intptr_t result = object_table_.Length(); |
| 193 object_table_.Add(obj); |
| 194 return result; |
| 195 } |
| 196 |
| 197 |
| 198 // Will be neeeded for inlined functions, currently trivial. |
| 199 void DeoptInfoBuilder::AddReturnAddress(const Function& function, |
| 200 intptr_t deopt_id, |
| 201 intptr_t to_index) { |
| 202 const intptr_t object_table_index = object_table_.Length(); |
| 203 object_table_.Add(function); |
| 204 object_table_.Add(Smi::ZoneHandle(Smi::New(deopt_id))); |
| 205 ASSERT(to_index == instructions_.length()); |
| 206 instructions_.Add(new DeoptRetAddrInstr(object_table_index)); |
| 207 } |
| 208 |
| 209 |
| 210 void DeoptInfoBuilder::AddPcMarker(const Function& function, |
| 211 intptr_t to_index) { |
| 212 // Function object was already added by AddReturnAddress, find it. |
| 213 intptr_t from_index = FindOrAddObjectInTable(function); |
| 214 ASSERT(to_index == instructions_.length()); |
| 215 instructions_.Add(new DeoptPcMarkerInstr(from_index)); |
| 216 } |
| 217 |
| 218 |
| 219 void DeoptInfoBuilder::AddCopy(const Location& from_loc, |
| 220 const Value& from_value, |
| 221 const intptr_t to_index) { |
| 222 DeoptInstr* deopt_instr = NULL; |
| 223 if (from_loc.IsConstant()) { |
| 224 intptr_t object_table_index = FindOrAddObjectInTable(from_loc.constant()); |
| 225 deopt_instr = new DeoptConstantInstr(object_table_index); |
| 226 } else if (from_loc.IsRegister()) { |
| 227 deopt_instr = new DeoptRegisterInstr(from_loc.reg()); |
| 228 } else if (from_loc.IsStackSlot()) { |
| 229 deopt_instr = new DeoptStackSlotInstr(from_loc.stack_index() + num_args_); |
| 230 } else if (from_loc.IsInvalid()) { |
| 231 ASSERT(from_value.IsConstant()); |
| 232 const Object& obj = from_value.AsConstant()->value(); |
| 233 intptr_t object_table_index = FindOrAddObjectInTable(obj); |
| 234 deopt_instr = new DeoptConstantInstr(object_table_index); |
| 235 } else { |
| 236 UNREACHABLE(); |
| 237 } |
| 238 ASSERT(to_index == instructions_.length()); |
| 239 instructions_.Add(deopt_instr); |
| 240 } |
| 241 |
| 242 |
| 243 void DeoptInfoBuilder::AddCallerFp(intptr_t to_index) { |
| 244 ASSERT(to_index == instructions_.length()); |
| 245 instructions_.Add(new DeoptCallerFpInstr()); |
| 246 } |
| 247 |
| 248 |
| 249 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) { |
| 250 ASSERT(to_index == instructions_.length()); |
| 251 instructions_.Add(new DeoptCallerPcInstr()); |
| 252 } |
| 253 |
| 254 |
| 255 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() const { |
| 256 const intptr_t len = instructions_.length(); |
| 257 const DeoptInfo& deopt_info = DeoptInfo::Handle(DeoptInfo::New(len)); |
| 258 for (intptr_t i = 0; i < len; i++) { |
| 259 DeoptInstr* instr = instructions_[i]; |
| 260 deopt_info.SetAt(i, instr->kind(), instr->from_index()); |
| 261 } |
| 262 return deopt_info.raw(); |
| 263 } |
| 264 |
| 265 } // namespace dart |
| OLD | NEW |