Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/deopt_instructions.h" | 5 #include "vm/deopt_instructions.h" |
| 6 | 6 |
| 7 #include "vm/assembler_macros.h" | 7 #include "vm/assembler_macros.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/locations.h" | 9 #include "vm/locations.h" |
| 10 #include "vm/parser.h" | 10 #include "vm/parser.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 // 'from_index' represents the slot index of the frame (0 being first argument) | 54 // 'from_index' represents the slot index of the frame (0 being first argument) |
| 55 // and accounts for saved return address, frame pointer and pc marker. | 55 // and accounts for saved return address, frame pointer and pc marker. |
| 56 class DeoptStackSlotInstr : public DeoptInstr { | 56 class DeoptStackSlotInstr : public DeoptInstr { |
| 57 public: | 57 public: |
| 58 explicit DeoptStackSlotInstr(intptr_t from_index) | 58 explicit DeoptStackSlotInstr(intptr_t from_index) |
| 59 : stack_slot_index_(from_index) { | 59 : stack_slot_index_(from_index) { |
| 60 ASSERT(stack_slot_index_ >= 0); | 60 ASSERT(stack_slot_index_ >= 0); |
| 61 } | 61 } |
| 62 | 62 |
| 63 virtual intptr_t from_index() const { return stack_slot_index_; } | 63 virtual intptr_t from_index() const { return stack_slot_index_; } |
| 64 virtual DeoptInstr::Kind kind() const { return kCopyStackSlot; } | 64 virtual DeoptInstr::Kind kind() const { return kStackSlot; } |
| 65 | 65 |
| 66 virtual const char* ToCString() const { | 66 virtual const char* ToCString() const { |
| 67 const char* format = "s%"Pd""; | 67 const char* format = "s%"Pd""; |
| 68 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 68 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
| 69 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 69 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 70 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 70 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
| 71 return chars; | 71 return chars; |
| 72 } | 72 } |
| 73 | 73 |
| 74 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 74 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 87 | 87 |
| 88 | 88 |
| 89 class DeoptDoubleStackSlotInstr : public DeoptInstr { | 89 class DeoptDoubleStackSlotInstr : public DeoptInstr { |
| 90 public: | 90 public: |
| 91 explicit DeoptDoubleStackSlotInstr(intptr_t from_index) | 91 explicit DeoptDoubleStackSlotInstr(intptr_t from_index) |
| 92 : stack_slot_index_(from_index) { | 92 : stack_slot_index_(from_index) { |
| 93 ASSERT(stack_slot_index_ >= 0); | 93 ASSERT(stack_slot_index_ >= 0); |
| 94 } | 94 } |
| 95 | 95 |
| 96 virtual intptr_t from_index() const { return stack_slot_index_; } | 96 virtual intptr_t from_index() const { return stack_slot_index_; } |
| 97 virtual DeoptInstr::Kind kind() const { return kCopyDoubleStackSlot; } | 97 virtual DeoptInstr::Kind kind() const { return kDoubleStackSlot; } |
| 98 | 98 |
| 99 virtual const char* ToCString() const { | 99 virtual const char* ToCString() const { |
| 100 const char* format = "ds%"Pd""; | 100 const char* format = "ds%"Pd""; |
| 101 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 101 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
| 102 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 102 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 103 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 103 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
| 104 return chars; | 104 return chars; |
| 105 } | 105 } |
| 106 | 106 |
| 107 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 107 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 123 | 123 |
| 124 | 124 |
| 125 class DeoptInt64StackSlotInstr : public DeoptInstr { | 125 class DeoptInt64StackSlotInstr : public DeoptInstr { |
| 126 public: | 126 public: |
| 127 explicit DeoptInt64StackSlotInstr(intptr_t from_index) | 127 explicit DeoptInt64StackSlotInstr(intptr_t from_index) |
| 128 : stack_slot_index_(from_index) { | 128 : stack_slot_index_(from_index) { |
| 129 ASSERT(stack_slot_index_ >= 0); | 129 ASSERT(stack_slot_index_ >= 0); |
| 130 } | 130 } |
| 131 | 131 |
| 132 virtual intptr_t from_index() const { return stack_slot_index_; } | 132 virtual intptr_t from_index() const { return stack_slot_index_; } |
| 133 virtual DeoptInstr::Kind kind() const { return kCopyInt64StackSlot; } | 133 virtual DeoptInstr::Kind kind() const { return kInt64StackSlot; } |
| 134 | 134 |
| 135 virtual const char* ToCString() const { | 135 virtual const char* ToCString() const { |
| 136 const char* format = "ms%"Pd""; | 136 const char* format = "ms%"Pd""; |
| 137 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 137 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
| 138 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 138 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 139 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 139 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
| 140 return chars; | 140 return chars; |
| 141 } | 141 } |
| 142 | 142 |
| 143 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 143 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 159 private: | 159 private: |
| 160 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. | 160 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. |
| 161 | 161 |
| 162 DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotInstr); | 162 DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotInstr); |
| 163 }; | 163 }; |
| 164 | 164 |
| 165 | 165 |
| 166 // Deoptimization instruction creating return address using function and | 166 // Deoptimization instruction creating return address using function and |
| 167 // deopt-id stored at 'object_table_index'. Uses the deopt-after | 167 // deopt-id stored at 'object_table_index'. Uses the deopt-after |
| 168 // continuation point. | 168 // continuation point. |
| 169 class DeoptRetAddrAfterInstr : public DeoptInstr { | 169 class DeoptRetAfterAddressInstr : public DeoptInstr { |
| 170 public: | 170 public: |
| 171 DeoptRetAddrAfterInstr(intptr_t object_table_index, intptr_t deopt_id) | 171 DeoptRetAfterAddressInstr(intptr_t object_table_index, intptr_t deopt_id) |
| 172 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | 172 : object_table_index_(object_table_index), deopt_id_(deopt_id) { |
| 173 ASSERT(object_table_index >= 0); | 173 ASSERT(object_table_index >= 0); |
| 174 ASSERT(deopt_id >= 0); | 174 ASSERT(deopt_id >= 0); |
| 175 } | 175 } |
| 176 | 176 |
| 177 explicit DeoptRetAddrAfterInstr(intptr_t from_index) | 177 explicit DeoptRetAfterAddressInstr(intptr_t from_index) |
| 178 : object_table_index_(ObjectTableIndex::decode(from_index)), | 178 : object_table_index_(ObjectTableIndex::decode(from_index)), |
| 179 deopt_id_(DeoptId::decode(from_index)) { | 179 deopt_id_(DeoptId::decode(from_index)) { |
| 180 } | 180 } |
| 181 | 181 |
| 182 virtual intptr_t from_index() const { | 182 virtual intptr_t from_index() const { |
| 183 return ObjectTableIndex::encode(object_table_index_) | | 183 return ObjectTableIndex::encode(object_table_index_) | |
| 184 DeoptId::encode(deopt_id_); | 184 DeoptId::encode(deopt_id_); |
| 185 } | 185 } |
| 186 virtual DeoptInstr::Kind kind() const { return kSetRetAfterAddress; } | 186 virtual DeoptInstr::Kind kind() const { return kRetAfterAddress; } |
| 187 | 187 |
| 188 virtual const char* ToCString() const { | 188 virtual const char* ToCString() const { |
| 189 const char* format = "ret aft oti:%"Pd"(%"Pd")"; | 189 const char* format = "ret aft oti:%"Pd"(%"Pd")"; |
| 190 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | 190 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); |
| 191 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 191 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 192 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | 192 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); |
| 193 return chars; | 193 return chars; |
| 194 } | 194 } |
| 195 | 195 |
| 196 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 196 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 197 Function& function = Function::Handle(deopt_context->isolate()); | 197 Function& function = Function::Handle(deopt_context->isolate()); |
| 198 function ^= deopt_context->ObjectAt(object_table_index_); | 198 function ^= deopt_context->ObjectAt(object_table_index_); |
| 199 const Code& code = | 199 const Code& code = |
| 200 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | 200 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); |
| 201 uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_); | 201 uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_); |
| 202 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 202 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 203 *to_addr = continue_at_pc; | 203 *to_addr = continue_at_pc; |
| 204 } | 204 } |
| 205 | 205 |
| 206 private: | 206 private: |
| 207 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 207 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
| 208 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 208 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
| 209 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 209 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
| 210 | 210 |
| 211 const intptr_t object_table_index_; | 211 const intptr_t object_table_index_; |
| 212 const intptr_t deopt_id_; | 212 const intptr_t deopt_id_; |
| 213 | 213 |
| 214 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddrAfterInstr); | 214 DISALLOW_COPY_AND_ASSIGN(DeoptRetAfterAddressInstr); |
| 215 }; | 215 }; |
| 216 | 216 |
| 217 | 217 |
| 218 // Deoptimization instruction creating return address using function and | 218 // Deoptimization instruction creating return address using function and |
| 219 // deopt-id stored at 'object_table_index'. Uses the deopt-before | 219 // deopt-id stored at 'object_table_index'. Uses the deopt-before |
| 220 // continuation point. | 220 // continuation point. |
| 221 class DeoptRetAddrBeforeInstr : public DeoptInstr { | 221 class DeoptRetBeforeAddressInstr : public DeoptInstr { |
| 222 public: | 222 public: |
| 223 DeoptRetAddrBeforeInstr(intptr_t object_table_index, intptr_t deopt_id) | 223 DeoptRetBeforeAddressInstr(intptr_t object_table_index, intptr_t deopt_id) |
| 224 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | 224 : object_table_index_(object_table_index), deopt_id_(deopt_id) { |
| 225 ASSERT(object_table_index >= 0); | 225 ASSERT(object_table_index >= 0); |
| 226 ASSERT(deopt_id_ >= 0); | 226 ASSERT(deopt_id >= 0); |
| 227 } | 227 } |
| 228 | 228 |
| 229 explicit DeoptRetAddrBeforeInstr(intptr_t from_index) | 229 explicit DeoptRetBeforeAddressInstr(intptr_t from_index) |
| 230 : object_table_index_(ObjectTableIndex::decode(from_index)), | 230 : object_table_index_(ObjectTableIndex::decode(from_index)), |
| 231 deopt_id_(DeoptId::decode(from_index)) { | 231 deopt_id_(DeoptId::decode(from_index)) { |
| 232 } | 232 } |
| 233 | 233 |
| 234 virtual intptr_t from_index() const { | 234 virtual intptr_t from_index() const { |
| 235 return ObjectTableIndex::encode(object_table_index_) | | 235 return ObjectTableIndex::encode(object_table_index_) | |
| 236 DeoptId::encode(deopt_id_); | 236 DeoptId::encode(deopt_id_); |
| 237 } | 237 } |
| 238 virtual DeoptInstr::Kind kind() const { return kSetRetBeforeAddress; } | 238 virtual DeoptInstr::Kind kind() const { return kRetBeforeAddress; } |
| 239 | 239 |
| 240 virtual const char* ToCString() const { | 240 virtual const char* ToCString() const { |
| 241 const char* format = "ret bef oti:%"Pd"(%"Pd")"; | 241 const char* format = "ret bef oti:%"Pd"(%"Pd")"; |
| 242 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | 242 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); |
| 243 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 243 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 244 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | 244 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); |
| 245 return chars; | 245 return chars; |
| 246 } | 246 } |
| 247 | 247 |
| 248 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 248 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 249 Function& function = Function::Handle(deopt_context->isolate()); | 249 Function& function = Function::Handle(deopt_context->isolate()); |
| 250 function ^= deopt_context->ObjectAt(object_table_index_); | 250 function ^= deopt_context->ObjectAt(object_table_index_); |
| 251 const Code& code = | 251 const Code& code = |
| 252 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | 252 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); |
| 253 uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_); | 253 uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_); |
| 254 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 254 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 255 *to_addr = continue_at_pc; | 255 *to_addr = continue_at_pc; |
| 256 } | 256 } |
| 257 | 257 |
| 258 private: | 258 private: |
| 259 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 259 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
| 260 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 260 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
| 261 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 261 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
| 262 | 262 |
| 263 const intptr_t object_table_index_; | 263 const intptr_t object_table_index_; |
| 264 const intptr_t deopt_id_; | 264 const intptr_t deopt_id_; |
| 265 | 265 |
| 266 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddrBeforeInstr); | 266 DISALLOW_COPY_AND_ASSIGN(DeoptRetBeforeAddressInstr); |
| 267 }; | 267 }; |
| 268 | 268 |
| 269 | 269 |
| 270 // Deoptimization instruction moving a constant stored at 'object_table_index'. | 270 // Deoptimization instruction moving a constant stored at 'object_table_index'. |
| 271 class DeoptConstantInstr : public DeoptInstr { | 271 class DeoptConstantInstr : public DeoptInstr { |
| 272 public: | 272 public: |
| 273 explicit DeoptConstantInstr(intptr_t object_table_index) | 273 explicit DeoptConstantInstr(intptr_t object_table_index) |
| 274 : object_table_index_(object_table_index) { | 274 : object_table_index_(object_table_index) { |
| 275 ASSERT(object_table_index >= 0); | 275 ASSERT(object_table_index >= 0); |
| 276 } | 276 } |
| 277 | 277 |
| 278 virtual intptr_t from_index() const { return object_table_index_; } | 278 virtual intptr_t from_index() const { return object_table_index_; } |
| 279 virtual DeoptInstr::Kind kind() const { return kCopyConstant; } | 279 virtual DeoptInstr::Kind kind() const { return kConstant; } |
| 280 | 280 |
| 281 virtual const char* ToCString() const { | 281 virtual const char* ToCString() const { |
| 282 const char* format = "const oti:%"Pd""; | 282 const char* format = "const oti:%"Pd""; |
| 283 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); | 283 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); |
| 284 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 284 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 285 OS::SNPrint(chars, len + 1, format, object_table_index_); | 285 OS::SNPrint(chars, len + 1, format, object_table_index_); |
| 286 return chars; | 286 return chars; |
| 287 } | 287 } |
| 288 | 288 |
| 289 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 289 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 301 }; | 301 }; |
| 302 | 302 |
| 303 | 303 |
| 304 // Deoptimization instruction moving a CPU register. | 304 // Deoptimization instruction moving a CPU register. |
| 305 class DeoptRegisterInstr: public DeoptInstr { | 305 class DeoptRegisterInstr: public DeoptInstr { |
| 306 public: | 306 public: |
| 307 explicit DeoptRegisterInstr(intptr_t reg_as_int) | 307 explicit DeoptRegisterInstr(intptr_t reg_as_int) |
| 308 : reg_(static_cast<Register>(reg_as_int)) {} | 308 : reg_(static_cast<Register>(reg_as_int)) {} |
| 309 | 309 |
| 310 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 310 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
| 311 virtual DeoptInstr::Kind kind() const { return kCopyRegister; } | 311 virtual DeoptInstr::Kind kind() const { return kRegister; } |
| 312 | 312 |
| 313 virtual const char* ToCString() const { | 313 virtual const char* ToCString() const { |
| 314 return Assembler::RegisterName(reg_); | 314 return Assembler::RegisterName(reg_); |
| 315 } | 315 } |
| 316 | 316 |
| 317 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 317 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 318 intptr_t value = deopt_context->RegisterValue(reg_); | 318 intptr_t value = deopt_context->RegisterValue(reg_); |
| 319 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 319 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 320 *to_addr = value; | 320 *to_addr = value; |
| 321 } | 321 } |
| 322 | 322 |
| 323 private: | 323 private: |
| 324 const Register reg_; | 324 const Register reg_; |
| 325 | 325 |
| 326 DISALLOW_COPY_AND_ASSIGN(DeoptRegisterInstr); | 326 DISALLOW_COPY_AND_ASSIGN(DeoptRegisterInstr); |
| 327 }; | 327 }; |
| 328 | 328 |
| 329 | 329 |
| 330 // Deoptimization instruction moving an XMM register. | 330 // Deoptimization instruction moving an XMM register. |
| 331 class DeoptXmmRegisterInstr: public DeoptInstr { | 331 class DeoptXmmRegisterInstr: public DeoptInstr { |
| 332 public: | 332 public: |
| 333 explicit DeoptXmmRegisterInstr(intptr_t reg_as_int) | 333 explicit DeoptXmmRegisterInstr(intptr_t reg_as_int) |
| 334 : reg_(static_cast<XmmRegister>(reg_as_int)) {} | 334 : reg_(static_cast<XmmRegister>(reg_as_int)) {} |
| 335 | 335 |
| 336 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 336 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
| 337 virtual DeoptInstr::Kind kind() const { return kCopyXmmRegister; } | 337 virtual DeoptInstr::Kind kind() const { return kXmmRegister; } |
| 338 | 338 |
| 339 virtual const char* ToCString() const { | 339 virtual const char* ToCString() const { |
| 340 return Assembler::XmmRegisterName(reg_); | 340 return Assembler::XmmRegisterName(reg_); |
| 341 } | 341 } |
| 342 | 342 |
| 343 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 343 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 344 double value = deopt_context->XmmRegisterValue(reg_); | 344 double value = deopt_context->XmmRegisterValue(reg_); |
| 345 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 345 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 346 *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0); | 346 *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0); |
| 347 Isolate::Current()->DeferDoubleMaterialization( | 347 Isolate::Current()->DeferDoubleMaterialization( |
| 348 value, reinterpret_cast<RawDouble**>(to_addr)); | 348 value, reinterpret_cast<RawDouble**>(to_addr)); |
| 349 } | 349 } |
| 350 | 350 |
| 351 private: | 351 private: |
| 352 const XmmRegister reg_; | 352 const XmmRegister reg_; |
| 353 | 353 |
| 354 DISALLOW_COPY_AND_ASSIGN(DeoptXmmRegisterInstr); | 354 DISALLOW_COPY_AND_ASSIGN(DeoptXmmRegisterInstr); |
| 355 }; | 355 }; |
| 356 | 356 |
| 357 | 357 |
| 358 class DeoptInt64XmmRegisterInstr: public DeoptInstr { | 358 class DeoptInt64XmmRegisterInstr: public DeoptInstr { |
| 359 public: | 359 public: |
| 360 explicit DeoptInt64XmmRegisterInstr(intptr_t reg_as_int) | 360 explicit DeoptInt64XmmRegisterInstr(intptr_t reg_as_int) |
| 361 : reg_(static_cast<XmmRegister>(reg_as_int)) {} | 361 : reg_(static_cast<XmmRegister>(reg_as_int)) {} |
| 362 | 362 |
| 363 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 363 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
| 364 virtual DeoptInstr::Kind kind() const { return kCopyInt64XmmRegister; } | 364 virtual DeoptInstr::Kind kind() const { return kInt64XmmRegister; } |
| 365 | 365 |
| 366 virtual const char* ToCString() const { | 366 virtual const char* ToCString() const { |
| 367 const char* format = "%s(m)"; | 367 const char* format = "%s(m)"; |
| 368 intptr_t len = | 368 intptr_t len = |
| 369 OS::SNPrint(NULL, 0, format, Assembler::XmmRegisterName(reg_)); | 369 OS::SNPrint(NULL, 0, format, Assembler::XmmRegisterName(reg_)); |
| 370 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 370 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 371 OS::SNPrint(chars, len + 1, format, Assembler::XmmRegisterName(reg_)); | 371 OS::SNPrint(chars, len + 1, format, Assembler::XmmRegisterName(reg_)); |
| 372 return chars; | 372 return chars; |
| 373 } | 373 } |
| 374 | 374 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 395 // Deoptimization instruction creating a PC marker for the code of | 395 // Deoptimization instruction creating a PC marker for the code of |
| 396 // function at 'object_table_index'. | 396 // function at 'object_table_index'. |
| 397 class DeoptPcMarkerInstr : public DeoptInstr { | 397 class DeoptPcMarkerInstr : public DeoptInstr { |
| 398 public: | 398 public: |
| 399 explicit DeoptPcMarkerInstr(intptr_t object_table_index) | 399 explicit DeoptPcMarkerInstr(intptr_t object_table_index) |
| 400 : object_table_index_(object_table_index) { | 400 : object_table_index_(object_table_index) { |
| 401 ASSERT(object_table_index >= 0); | 401 ASSERT(object_table_index >= 0); |
| 402 } | 402 } |
| 403 | 403 |
| 404 virtual intptr_t from_index() const { return object_table_index_; } | 404 virtual intptr_t from_index() const { return object_table_index_; } |
| 405 virtual DeoptInstr::Kind kind() const { return kSetPcMarker; } | 405 virtual DeoptInstr::Kind kind() const { return kPcMarker; } |
| 406 | 406 |
| 407 virtual const char* ToCString() const { | 407 virtual const char* ToCString() const { |
| 408 const char* format = "pcmark oti:%"Pd""; | 408 const char* format = "pcmark oti:%"Pd""; |
| 409 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); | 409 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); |
| 410 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 410 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 411 OS::SNPrint(chars, len + 1, format, object_table_index_); | 411 OS::SNPrint(chars, len + 1, format, object_table_index_); |
| 412 return chars; | 412 return chars; |
| 413 } | 413 } |
| 414 | 414 |
| 415 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 415 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 436 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); | 436 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); |
| 437 }; | 437 }; |
| 438 | 438 |
| 439 | 439 |
| 440 // Deoptimization instruction copying the caller saved FP from optimized frame. | 440 // Deoptimization instruction copying the caller saved FP from optimized frame. |
| 441 class DeoptCallerFpInstr : public DeoptInstr { | 441 class DeoptCallerFpInstr : public DeoptInstr { |
| 442 public: | 442 public: |
| 443 DeoptCallerFpInstr() {} | 443 DeoptCallerFpInstr() {} |
| 444 | 444 |
| 445 virtual intptr_t from_index() const { return 0; } | 445 virtual intptr_t from_index() const { return 0; } |
| 446 virtual DeoptInstr::Kind kind() const { return kSetCallerFp; } | 446 virtual DeoptInstr::Kind kind() const { return kCallerFp; } |
| 447 | 447 |
| 448 virtual const char* ToCString() const { | 448 virtual const char* ToCString() const { |
| 449 return "callerfp"; | 449 return "callerfp"; |
| 450 } | 450 } |
| 451 | 451 |
| 452 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 452 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 453 intptr_t from = deopt_context->GetCallerFp(); | 453 intptr_t from = deopt_context->GetCallerFp(); |
| 454 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 454 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 455 *to_addr = from; | 455 *to_addr = from; |
| 456 deopt_context->SetCallerFp(reinterpret_cast<intptr_t>(to_addr)); | 456 deopt_context->SetCallerFp(reinterpret_cast<intptr_t>(to_addr)); |
| 457 } | 457 } |
| 458 | 458 |
| 459 private: | 459 private: |
| 460 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr); | 460 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr); |
| 461 }; | 461 }; |
| 462 | 462 |
| 463 | 463 |
| 464 // Deoptimization instruction copying the caller return address from optimized | 464 // Deoptimization instruction copying the caller return address from optimized |
| 465 // frame. | 465 // frame. |
| 466 class DeoptCallerPcInstr : public DeoptInstr { | 466 class DeoptCallerPcInstr : public DeoptInstr { |
| 467 public: | 467 public: |
| 468 DeoptCallerPcInstr() {} | 468 DeoptCallerPcInstr() {} |
| 469 | 469 |
| 470 virtual intptr_t from_index() const { return 0; } | 470 virtual intptr_t from_index() const { return 0; } |
| 471 virtual DeoptInstr::Kind kind() const { return kSetCallerPc; } | 471 virtual DeoptInstr::Kind kind() const { return kCallerPc; } |
| 472 | 472 |
| 473 virtual const char* ToCString() const { | 473 virtual const char* ToCString() const { |
| 474 return "callerpc"; | 474 return "callerpc"; |
| 475 } | 475 } |
| 476 | 476 |
| 477 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 477 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 478 intptr_t from = deopt_context->GetFromPc(); | 478 intptr_t from = deopt_context->GetFromPc(); |
| 479 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 479 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 480 *to_addr = from; | 480 *to_addr = from; |
| 481 } | 481 } |
| 482 | 482 |
| 483 private: | 483 private: |
| 484 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr); | 484 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr); |
| 485 }; | 485 }; |
| 486 | 486 |
| 487 | 487 |
| 488 class DeoptSuffixInstr : public DeoptInstr { | |
|
srdjan
2012/10/08 16:37:58
Add brief comment about the class.
| |
| 489 public: | |
| 490 DeoptSuffixInstr(intptr_t info_number, intptr_t suffix_length) | |
| 491 : info_number_(info_number), suffix_length_(suffix_length) { | |
| 492 ASSERT(info_number >= 0); | |
| 493 ASSERT(suffix_length >= 0); | |
| 494 } | |
| 495 | |
| 496 explicit DeoptSuffixInstr(intptr_t from_index) | |
| 497 : info_number_(InfoNumber::decode(from_index)), | |
| 498 suffix_length_(SuffixLength::decode(from_index)) { | |
| 499 } | |
| 500 | |
| 501 virtual intptr_t from_index() const { | |
| 502 return InfoNumber::encode(info_number_) | | |
| 503 SuffixLength::encode(suffix_length_); | |
| 504 } | |
| 505 virtual DeoptInstr::Kind kind() const { return kSuffix; } | |
| 506 | |
| 507 virtual const char* ToCString() const { | |
| 508 const char* format = "suffix %"Pd":%"Pd; | |
| 509 intptr_t len = OS::SNPrint(NULL, 0, format, info_number_, suffix_length_); | |
| 510 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | |
| 511 OS::SNPrint(chars, len + 1, format, info_number_, suffix_length_); | |
| 512 return chars; | |
| 513 } | |
| 514 | |
| 515 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | |
| 516 UNREACHABLE(); | |
|
Kevin Millikin (Google)
2012/10/05 14:31:55
Notice. The strategy is to 'uncompress' the entry
| |
| 517 } | |
| 518 | |
| 519 private: | |
| 520 friend class DeoptInstr; | |
| 521 | |
| 522 static const intptr_t kFieldWidth = kBitsPerWord / 2; | |
| 523 class InfoNumber : public BitField<intptr_t, 0, kFieldWidth> { }; | |
| 524 class SuffixLength : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | |
| 525 | |
| 526 const intptr_t info_number_; | |
| 527 const intptr_t suffix_length_; | |
| 528 | |
| 529 DISALLOW_COPY_AND_ASSIGN(DeoptSuffixInstr); | |
| 530 }; | |
| 531 | |
| 532 | |
| 533 intptr_t DeoptInstr::DecodeSuffix(intptr_t from_index, intptr_t* info_number) { | |
| 534 *info_number = DeoptSuffixInstr::InfoNumber::decode(from_index); | |
| 535 return DeoptSuffixInstr::SuffixLength::decode(from_index); | |
| 536 } | |
| 537 | |
| 538 | |
| 488 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { | 539 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { |
| 489 Kind kind = static_cast<Kind>(kind_as_int); | 540 Kind kind = static_cast<Kind>(kind_as_int); |
| 490 switch (kind) { | 541 switch (kind) { |
| 491 case kCopyStackSlot: return new DeoptStackSlotInstr(from_index); | 542 case kStackSlot: return new DeoptStackSlotInstr(from_index); |
| 492 case kCopyDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); | 543 case kDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); |
| 493 case kCopyInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); | 544 case kInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); |
| 494 case kSetRetAfterAddress: return new DeoptRetAddrAfterInstr(from_index); | 545 case kRetAfterAddress: return new DeoptRetAfterAddressInstr(from_index); |
| 495 case kSetRetBeforeAddress: return new DeoptRetAddrBeforeInstr(from_index); | 546 case kRetBeforeAddress: return new DeoptRetBeforeAddressInstr(from_index); |
| 496 case kCopyConstant: return new DeoptConstantInstr(from_index); | 547 case kConstant: return new DeoptConstantInstr(from_index); |
| 497 case kCopyRegister: return new DeoptRegisterInstr(from_index); | 548 case kRegister: return new DeoptRegisterInstr(from_index); |
| 498 case kCopyXmmRegister: return new DeoptXmmRegisterInstr(from_index); | 549 case kXmmRegister: return new DeoptXmmRegisterInstr(from_index); |
| 499 case kCopyInt64XmmRegister: | 550 case kInt64XmmRegister: return new DeoptInt64XmmRegisterInstr(from_index); |
| 500 return new DeoptInt64XmmRegisterInstr(from_index); | 551 case kPcMarker: return new DeoptPcMarkerInstr(from_index); |
| 501 case kSetPcMarker: return new DeoptPcMarkerInstr(from_index); | 552 case kCallerFp: return new DeoptCallerFpInstr(); |
| 502 case kSetCallerFp: return new DeoptCallerFpInstr(); | 553 case kCallerPc: return new DeoptCallerPcInstr(); |
| 503 case kSetCallerPc: return new DeoptCallerPcInstr(); | 554 case kSuffix: return new DeoptSuffixInstr(from_index); |
| 504 } | 555 } |
| 505 UNREACHABLE(); | 556 UNREACHABLE(); |
| 506 return NULL; | 557 return NULL; |
| 507 } | 558 } |
| 508 | 559 |
| 509 | 560 |
| 561 class DeoptInfoBuilder::TrieNode : public ZoneAllocated { | |
| 562 public: | |
| 563 // Construct the root node representing the implicit "shared" terminator | |
| 564 // at the end of each deopt info. | |
| 565 TrieNode() : instruction_(NULL), info_number_(-1), children_(16) { } | |
| 566 | |
| 567 // Construct a node representing a written instruction. | |
| 568 TrieNode(DeoptInstr* instruction, intptr_t info_number) | |
| 569 : instruction_(instruction), info_number_(info_number), children_(4) { } | |
| 570 | |
| 571 intptr_t info_number() const { return info_number_; } | |
| 572 | |
| 573 void AddChild(TrieNode* child) { | |
| 574 if (child != NULL) children_.Add(child); | |
|
srdjan
2012/10/08 16:37:58
When can you call this with child==NULL ?
| |
| 575 } | |
| 576 | |
| 577 TrieNode* FindChild(const DeoptInstr& instruction) { | |
| 578 for (intptr_t i = 0; i < children_.length(); ++i) { | |
| 579 TrieNode* child = children_[i]; | |
| 580 if (child->instruction_->Equals(instruction)) return child; | |
| 581 } | |
| 582 return NULL; | |
| 583 } | |
| 584 | |
| 585 private: | |
| 586 const DeoptInstr* instruction_; // Istruction that was written. | |
|
srdjan
2012/10/08 16:37:58
s/Istruction/Instruction/
| |
| 587 const intptr_t info_number_; // Index of the deopt info it was written to. | |
| 588 | |
| 589 GrowableArray<TrieNode*> children_; | |
| 590 }; | |
| 591 | |
| 592 | |
| 593 DeoptInfoBuilder::DeoptInfoBuilder(const intptr_t num_args) | |
| 594 : instructions_(), | |
| 595 object_table_(GrowableObjectArray::Handle(GrowableObjectArray::New())), | |
| 596 num_args_(num_args), | |
| 597 trie_root_(new TrieNode()), | |
| 598 current_info_number_(0) { | |
| 599 } | |
| 600 | |
| 601 | |
| 510 intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const { | 602 intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const { |
| 511 for (intptr_t i = 0; i < object_table_.Length(); i++) { | 603 for (intptr_t i = 0; i < object_table_.Length(); i++) { |
| 512 if (object_table_.At(i) == obj.raw()) { | 604 if (object_table_.At(i) == obj.raw()) { |
| 513 return i; | 605 return i; |
| 514 } | 606 } |
| 515 } | 607 } |
| 516 // Add object. | 608 // Add object. |
| 517 const intptr_t result = object_table_.Length(); | 609 const intptr_t result = object_table_.Length(); |
| 518 object_table_.Add(obj); | 610 object_table_.Add(obj); |
| 519 return result; | 611 return result; |
| 520 } | 612 } |
| 521 | 613 |
| 522 | 614 |
| 523 void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function, | 615 void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function, |
| 524 intptr_t deopt_id, | 616 intptr_t deopt_id, |
| 525 intptr_t to_index) { | 617 intptr_t to_index) { |
| 526 const intptr_t object_table_index = FindOrAddObjectInTable(function); | 618 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 527 ASSERT(to_index == instructions_.length()); | 619 ASSERT(to_index == instructions_.length()); |
| 528 instructions_.Add(new DeoptRetAddrBeforeInstr(object_table_index, deopt_id)); | 620 instructions_.Add(new DeoptRetBeforeAddressInstr(object_table_index, |
| 621 deopt_id)); | |
| 529 } | 622 } |
| 530 | 623 |
| 531 | 624 |
| 532 void DeoptInfoBuilder::AddReturnAddressAfter(const Function& function, | 625 void DeoptInfoBuilder::AddReturnAddressAfter(const Function& function, |
| 533 intptr_t deopt_id, | 626 intptr_t deopt_id, |
| 534 intptr_t to_index) { | 627 intptr_t to_index) { |
| 535 const intptr_t object_table_index = FindOrAddObjectInTable(function); | 628 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 536 ASSERT(to_index == instructions_.length()); | 629 ASSERT(to_index == instructions_.length()); |
| 537 instructions_.Add(new DeoptRetAddrAfterInstr(object_table_index, deopt_id)); | 630 instructions_.Add(new DeoptRetAfterAddressInstr(object_table_index, |
| 631 deopt_id)); | |
| 538 } | 632 } |
| 539 | 633 |
| 540 | 634 |
| 541 void DeoptInfoBuilder::AddPcMarker(const Function& function, | 635 void DeoptInfoBuilder::AddPcMarker(const Function& function, |
| 542 intptr_t to_index) { | 636 intptr_t to_index) { |
| 543 // Function object was already added by AddReturnAddress, find it. | 637 // Function object was already added by AddReturnAddress, find it. |
| 544 intptr_t from_index = FindOrAddObjectInTable(function); | 638 intptr_t from_index = FindOrAddObjectInTable(function); |
| 545 ASSERT(to_index == instructions_.length()); | 639 ASSERT(to_index == instructions_.length()); |
| 546 instructions_.Add(new DeoptPcMarkerInstr(from_index)); | 640 instructions_.Add(new DeoptPcMarkerInstr(from_index)); |
| 547 } | 641 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 instructions_.Add(new DeoptCallerFpInstr()); | 687 instructions_.Add(new DeoptCallerFpInstr()); |
| 594 } | 688 } |
| 595 | 689 |
| 596 | 690 |
| 597 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) { | 691 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) { |
| 598 ASSERT(to_index == instructions_.length()); | 692 ASSERT(to_index == instructions_.length()); |
| 599 instructions_.Add(new DeoptCallerPcInstr()); | 693 instructions_.Add(new DeoptCallerPcInstr()); |
| 600 } | 694 } |
| 601 | 695 |
| 602 | 696 |
| 603 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() const { | 697 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() { |
| 604 const intptr_t len = instructions_.length(); | 698 intptr_t length = instructions_.length(); |
| 605 const DeoptInfo& deopt_info = DeoptInfo::Handle(DeoptInfo::New(len)); | 699 |
| 606 for (intptr_t i = 0; i < len; i++) { | 700 // Count the number of instructions that are a shared suffix of some deopt |
| 701 // info already written. | |
| 702 TrieNode* suffix = trie_root_; | |
| 703 intptr_t suffix_length = 0; | |
| 704 for (intptr_t i = length - 1; i >= 0; --i) { | |
| 705 TrieNode* node = suffix->FindChild(*instructions_[i]); | |
| 706 if (node == NULL) break; | |
| 707 suffix = node; | |
| 708 ++suffix_length; | |
| 709 } | |
| 710 | |
| 711 // Allocate space for the translation. If the shared suffix is longer | |
| 712 // than one instruction, we replace it with a single suffix instruction. | |
| 713 if (suffix_length > 1) length -= (suffix_length - 1); | |
| 714 const DeoptInfo& deopt_info = DeoptInfo::Handle(DeoptInfo::New(length)); | |
| 715 | |
| 716 // Write the unshared instructions and build their sub-tree. | |
| 717 TrieNode* node = NULL; | |
| 718 intptr_t write_count = (suffix_length > 1) ? length - 1 : length; | |
| 719 for (intptr_t i = 0; i < write_count; ++i) { | |
| 607 DeoptInstr* instr = instructions_[i]; | 720 DeoptInstr* instr = instructions_[i]; |
| 608 deopt_info.SetAt(i, instr->kind(), instr->from_index()); | 721 deopt_info.SetAt(i, instr->kind(), instr->from_index()); |
| 722 TrieNode* child = node; | |
| 723 node = new TrieNode(instr, current_info_number_); | |
| 724 node->AddChild(child); | |
| 609 } | 725 } |
| 726 suffix->AddChild(node); | |
| 727 | |
| 728 if (suffix_length > 1) { | |
| 729 DeoptInstr* instr = | |
| 730 new DeoptSuffixInstr(suffix->info_number(), suffix_length); | |
| 731 deopt_info.SetAt(length - 1, instr->kind(), instr->from_index()); | |
| 732 } | |
| 733 | |
| 734 instructions_.Clear(); | |
| 735 ++current_info_number_; | |
| 610 return deopt_info.raw(); | 736 return deopt_info.raw(); |
| 611 } | 737 } |
| 612 | 738 |
| 613 | 739 |
| 614 intptr_t DeoptTable::SizeFor(intptr_t length) { | 740 intptr_t DeoptTable::SizeFor(intptr_t length) { |
| 615 return length * kEntrySize; | 741 return length * kEntrySize; |
| 616 } | 742 } |
| 617 | 743 |
| 618 void DeoptTable::SetEntry(const Array& table, | 744 void DeoptTable::SetEntry(const Array& table, |
| 619 intptr_t index, | 745 intptr_t index, |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 639 Smi* offset, | 765 Smi* offset, |
| 640 DeoptInfo* info, | 766 DeoptInfo* info, |
| 641 Smi* reason) { | 767 Smi* reason) { |
| 642 intptr_t i = index * kEntrySize; | 768 intptr_t i = index * kEntrySize; |
| 643 *offset ^= table.At(i); | 769 *offset ^= table.At(i); |
| 644 *info ^= table.At(i + 1); | 770 *info ^= table.At(i + 1); |
| 645 *reason ^= table.At(i + 2); | 771 *reason ^= table.At(i + 2); |
| 646 } | 772 } |
| 647 | 773 |
| 648 } // namespace dart | 774 } // namespace dart |
| OLD | NEW |