| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 8 #if defined(TARGET_ARCH_MIPS) | 8 #if defined(TARGET_ARCH_MIPS) |
| 9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
| 10 #include "vm/instructions.h" | 10 #include "vm/instructions.h" |
| 11 | 11 |
| 12 namespace dart { | 12 namespace dart { |
| 13 | 13 |
| 14 #ifndef PRODUCT | 14 #ifndef PRODUCT |
| 15 | 15 |
| 16 class MIPSDecoder : public ValueObject { | 16 class MIPSDecoder : public ValueObject { |
| 17 public: | 17 public: |
| 18 MIPSDecoder(char* buffer, size_t buffer_size) | 18 MIPSDecoder(char* buffer, size_t buffer_size) |
| 19 : buffer_(buffer), | 19 : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { |
| 20 buffer_size_(buffer_size), | |
| 21 buffer_pos_(0) { | |
| 22 buffer_[buffer_pos_] = '\0'; | 20 buffer_[buffer_pos_] = '\0'; |
| 23 } | 21 } |
| 24 | 22 |
| 25 ~MIPSDecoder() {} | 23 ~MIPSDecoder() {} |
| 26 | 24 |
| 27 // Writes one disassembled instruction into 'buffer' (0-terminated). | 25 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 28 // Returns true if the instruction was successfully decoded, false otherwise. | 26 // Returns true if the instruction was successfully decoded, false otherwise. |
| 29 void InstructionDecode(Instr* instr); | 27 void InstructionDecode(Instr* instr); |
| 30 | 28 |
| 31 private: | 29 private: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 46 void DecodeSpecial(Instr* instr); | 44 void DecodeSpecial(Instr* instr); |
| 47 void DecodeSpecial2(Instr* instr); | 45 void DecodeSpecial2(Instr* instr); |
| 48 void DecodeRegImm(Instr* instr); | 46 void DecodeRegImm(Instr* instr); |
| 49 void DecodeCop1(Instr* instr); | 47 void DecodeCop1(Instr* instr); |
| 50 | 48 |
| 51 // Convenience functions. | 49 // Convenience functions. |
| 52 char* get_buffer() const { return buffer_; } | 50 char* get_buffer() const { return buffer_; } |
| 53 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 51 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 54 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 52 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 55 | 53 |
| 56 char* buffer_; // Decode instructions into this buffer. | 54 char* buffer_; // Decode instructions into this buffer. |
| 57 size_t buffer_size_; // The size of the character buffer. | 55 size_t buffer_size_; // The size of the character buffer. |
| 58 size_t buffer_pos_; // Current character position in buffer. | 56 size_t buffer_pos_; // Current character position in buffer. |
| 59 | 57 |
| 60 DISALLOW_ALLOCATION(); | 58 DISALLOW_ALLOCATION(); |
| 61 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); | 59 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); |
| 62 }; | 60 }; |
| 63 | 61 |
| 64 | 62 |
| 65 // Support for assertions in the MIPSDecoder formatting functions. | 63 // Support for assertions in the MIPSDecoder formatting functions. |
| 66 #define STRING_STARTS_WITH(string, compare_string) \ | 64 #define STRING_STARTS_WITH(string, compare_string) \ |
| 67 (strncmp(string, compare_string, strlen(compare_string)) == 0) | 65 (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| 68 | 66 |
| 69 | 67 |
| 70 // Append the str to the output buffer. | 68 // Append the str to the output buffer. |
| 71 void MIPSDecoder::Print(const char* str) { | 69 void MIPSDecoder::Print(const char* str) { |
| 72 char cur = *str++; | 70 char cur = *str++; |
| 73 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { | 71 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
| 74 buffer_[buffer_pos_++] = cur; | 72 buffer_[buffer_pos_++] = cur; |
| 75 cur = *str++; | 73 cur = *str++; |
| 76 } | 74 } |
| 77 buffer_[buffer_pos_] = '\0'; | 75 buffer_[buffer_pos_] = '\0'; |
| 78 } | 76 } |
| 79 | 77 |
| 80 | 78 |
| 81 static const char* reg_names[kNumberOfCpuRegisters] = { | 79 static const char* reg_names[kNumberOfCpuRegisters] = { |
| 82 "zr", "at", "v0", "v1" , "a0", "a1", "a2", "a3", | 80 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", |
| 83 "t0", "t1", "t2", "t3" , "t4", "t5", "t6", "t7", | 81 "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "thr", "s4", "s5", |
| 84 "s0", "s1", "s2", "thr", "s4", "s5", "s6", "pp", | 82 "s6", "pp", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", |
| 85 "t8", "t9", "k0", "k1" , "gp", "sp", "fp", "ra", | |
| 86 }; | 83 }; |
| 87 | 84 |
| 88 | 85 |
| 89 static const char* freg_names[kNumberOfFRegisters] = { | 86 static const char* freg_names[kNumberOfFRegisters] = { |
| 90 "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , | 87 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", |
| 91 "f8" , "f9" , "f10", "f11", "f12", "f13", "f14", "f15", | 88 "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", |
| 92 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", | 89 "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
| 93 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", | |
| 94 }; | 90 }; |
| 95 | 91 |
| 96 | 92 |
| 97 void MIPSDecoder::PrintRegister(Register reg) { | 93 void MIPSDecoder::PrintRegister(Register reg) { |
| 98 ASSERT(0 <= reg); | 94 ASSERT(0 <= reg); |
| 99 ASSERT(reg < kNumberOfCpuRegisters); | 95 ASSERT(reg < kNumberOfCpuRegisters); |
| 100 Print(reg_names[reg]); | 96 Print(reg_names[reg]); |
| 101 } | 97 } |
| 102 | 98 |
| 103 | 99 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 case 'd': { // 'fd: Fd register | 141 case 'd': { // 'fd: Fd register |
| 146 PrintFRegister(instr->FdField()); | 142 PrintFRegister(instr->FdField()); |
| 147 return 2; | 143 return 2; |
| 148 } | 144 } |
| 149 } | 145 } |
| 150 UNREACHABLE(); | 146 UNREACHABLE(); |
| 151 return -1; | 147 return -1; |
| 152 } | 148 } |
| 153 | 149 |
| 154 | 150 |
| 155 void MIPSDecoder::PrintFormat(Instr *instr) { | 151 void MIPSDecoder::PrintFormat(Instr* instr) { |
| 156 switch (instr->FormatField()) { | 152 switch (instr->FormatField()) { |
| 157 case FMT_S: { | 153 case FMT_S: { |
| 158 Print("s"); | 154 Print("s"); |
| 159 break; | 155 break; |
| 160 } | 156 } |
| 161 case FMT_D: { | 157 case FMT_D: { |
| 162 Print("d"); | 158 Print("d"); |
| 163 break; | 159 break; |
| 164 } | 160 } |
| 165 case FMT_W: { | 161 case FMT_W: { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 184 | 180 |
| 185 // FormatOption takes a formatting string and interprets it based on | 181 // FormatOption takes a formatting string and interprets it based on |
| 186 // the current instructions. The format string points to the first | 182 // the current instructions. The format string points to the first |
| 187 // character of the option string (the option escape has already been | 183 // character of the option string (the option escape has already been |
| 188 // consumed by the caller.) FormatOption returns the number of | 184 // consumed by the caller.) FormatOption returns the number of |
| 189 // characters that were consumed from the formatting string. | 185 // characters that were consumed from the formatting string. |
| 190 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | 186 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
| 191 switch (format[0]) { | 187 switch (format[0]) { |
| 192 case 'c': { | 188 case 'c': { |
| 193 ASSERT(STRING_STARTS_WITH(format, "code")); | 189 ASSERT(STRING_STARTS_WITH(format, "code")); |
| 194 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 190 buffer_pos_ += |
| 195 remaining_size_in_buffer(), | 191 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
| 196 "0x%x", | 192 "0x%x", instr->BreakCodeField()); |
| 197 instr->BreakCodeField()); | |
| 198 return 4; | 193 return 4; |
| 199 } | 194 } |
| 200 case 'h': { | 195 case 'h': { |
| 201 ASSERT(STRING_STARTS_WITH(format, "hint")); | 196 ASSERT(STRING_STARTS_WITH(format, "hint")); |
| 202 if (instr->SaField() == 0x10) { | 197 if (instr->SaField() == 0x10) { |
| 203 // The high bit of the SA field is the only one that means something for | 198 // The high bit of the SA field is the only one that means something for |
| 204 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. | 199 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. |
| 205 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 200 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 206 remaining_size_in_buffer(), | 201 remaining_size_in_buffer(), ".hb"); |
| 207 ".hb"); | |
| 208 } else if (instr->SaField() != 0) { | 202 } else if (instr->SaField() != 0) { |
| 209 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 203 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 210 remaining_size_in_buffer(), | 204 remaining_size_in_buffer(), ".unknown"); |
| 211 ".unknown"); | |
| 212 } | 205 } |
| 213 return 4; | 206 return 4; |
| 214 } | 207 } |
| 215 case 'd': { | 208 case 'd': { |
| 216 ASSERT(STRING_STARTS_WITH(format, "dest")); | 209 ASSERT(STRING_STARTS_WITH(format, "dest")); |
| 217 int off = instr->SImmField() << 2; | 210 int off = instr->SImmField() << 2; |
| 218 uword destination = | 211 uword destination = |
| 219 reinterpret_cast<uword>(instr) + off + Instr::kInstrSize; | 212 reinterpret_cast<uword>(instr) + off + Instr::kInstrSize; |
| 220 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 213 buffer_pos_ += |
| 221 remaining_size_in_buffer(), | 214 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
| 222 "%#" Px "", | 215 "%#" Px "", destination); |
| 223 destination); | |
| 224 return 4; | 216 return 4; |
| 225 } | 217 } |
| 226 case 'i': { | 218 case 'i': { |
| 227 ASSERT(STRING_STARTS_WITH(format, "imm")); | 219 ASSERT(STRING_STARTS_WITH(format, "imm")); |
| 228 if (format[3] == 'u') { | 220 if (format[3] == 'u') { |
| 229 int32_t imm = instr->UImmField(); | 221 int32_t imm = instr->UImmField(); |
| 230 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 222 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 231 remaining_size_in_buffer(), | 223 remaining_size_in_buffer(), "0x%x", imm); |
| 232 "0x%x", | |
| 233 imm); | |
| 234 } else { | 224 } else { |
| 235 ASSERT(STRING_STARTS_WITH(format, "imms")); | 225 ASSERT(STRING_STARTS_WITH(format, "imms")); |
| 236 int32_t imm = instr->SImmField(); | 226 int32_t imm = instr->SImmField(); |
| 237 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 227 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 238 remaining_size_in_buffer(), | 228 remaining_size_in_buffer(), "%d", imm); |
| 239 "%d", | |
| 240 imm); | |
| 241 } | 229 } |
| 242 return 4; | 230 return 4; |
| 243 } | 231 } |
| 244 case 'r': { | 232 case 'r': { |
| 245 return FormatRegister(instr, format); | 233 return FormatRegister(instr, format); |
| 246 } | 234 } |
| 247 case 'f': { | 235 case 'f': { |
| 248 if (format[1] == 'm') { | 236 if (format[1] == 'm') { |
| 249 ASSERT(STRING_STARTS_WITH(format, "fmt")); | 237 ASSERT(STRING_STARTS_WITH(format, "fmt")); |
| 250 PrintFormat(instr); | 238 PrintFormat(instr); |
| 251 return 3; | 239 return 3; |
| 252 } else { | 240 } else { |
| 253 return FormatFRegister(instr, format); | 241 return FormatFRegister(instr, format); |
| 254 } | 242 } |
| 255 } | 243 } |
| 256 case 's': { | 244 case 's': { |
| 257 ASSERT(STRING_STARTS_WITH(format, "sa")); | 245 ASSERT(STRING_STARTS_WITH(format, "sa")); |
| 258 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 246 buffer_pos_ += |
| 259 remaining_size_in_buffer(), | 247 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
| 260 "%d", | 248 "%d", instr->SaField()); |
| 261 instr->SaField()); | |
| 262 return 2; | 249 return 2; |
| 263 } | 250 } |
| 264 default: { | 251 default: { UNREACHABLE(); } |
| 265 UNREACHABLE(); | |
| 266 } | |
| 267 } | 252 } |
| 268 UNREACHABLE(); | 253 UNREACHABLE(); |
| 269 return -1; | 254 return -1; |
| 270 } | 255 } |
| 271 | 256 |
| 272 | 257 |
| 273 // Format takes a formatting string for a whole instruction and prints it into | 258 // Format takes a formatting string for a whole instruction and prints it into |
| 274 // the output buffer. All escaped options are handed to FormatOption to be | 259 // the output buffer. All escaped options are handed to FormatOption to be |
| 275 // parsed further. | 260 // parsed further. |
| 276 void MIPSDecoder::Format(Instr* instr, const char* format) { | 261 void MIPSDecoder::Format(Instr* instr, const char* format) { |
| 277 char cur = *format++; | 262 char cur = *format++; |
| 278 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { | 263 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
| 279 if (cur == '\'') { // Single quote is used as the formatting escape. | 264 if (cur == '\'') { // Single quote is used as the formatting escape. |
| 280 format += FormatOption(instr, format); | 265 format += FormatOption(instr, format); |
| 281 } else { | 266 } else { |
| 282 buffer_[buffer_pos_++] = cur; | 267 buffer_[buffer_pos_++] = cur; |
| 283 } | 268 } |
| 284 cur = *format++; | 269 cur = *format++; |
| 285 } | 270 } |
| 286 buffer_[buffer_pos_] = '\0'; | 271 buffer_[buffer_pos_] = '\0'; |
| 287 } | 272 } |
| 288 | 273 |
| 289 | 274 |
| 290 // For currently unimplemented decodings the disassembler calls Unknown(instr) | 275 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
| 291 // which will just print "unknown" of the instruction bits. | 276 // which will just print "unknown" of the instruction bits. |
| 292 void MIPSDecoder::Unknown(Instr* instr) { | 277 void MIPSDecoder::Unknown(Instr* instr) { |
| 293 Format(instr, "unknown"); | 278 Format(instr, "unknown"); |
| 294 } | 279 } |
| 295 | 280 |
| 296 | 281 |
| 297 void MIPSDecoder::DecodeSpecial(Instr* instr) { | 282 void MIPSDecoder::DecodeSpecial(Instr* instr) { |
| 298 ASSERT(instr->OpcodeField() == SPECIAL); | 283 ASSERT(instr->OpcodeField() == SPECIAL); |
| 299 switch (instr->FunctionField()) { | 284 switch (instr->FunctionField()) { |
| 300 case ADDU: { | 285 case ADDU: { |
| 301 Format(instr, "addu 'rd, 'rs, 'rt"); | 286 Format(instr, "addu 'rd, 'rs, 'rt"); |
| 302 break; | 287 break; |
| 303 } | 288 } |
| 304 case AND: { | 289 case AND: { |
| 305 Format(instr, "and 'rd, 'rs, 'rt"); | 290 Format(instr, "and 'rd, 'rs, 'rt"); |
| 306 break; | 291 break; |
| 307 } | 292 } |
| 308 case BREAK: { | 293 case BREAK: { |
| 309 Format(instr, "break 'code"); | 294 Format(instr, "break 'code"); |
| 310 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | 295 if (instr->BreakCodeField() == Instr::kStopMessageCode) { |
| 311 const char* message = *reinterpret_cast<const char**>( | 296 const char* message = *reinterpret_cast<const char**>( |
| 312 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | 297 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
| 313 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 298 buffer_pos_ += |
| 314 remaining_size_in_buffer(), | 299 OS::SNPrint(current_position_in_buffer(), |
| 315 " ; \"%s\"", | 300 remaining_size_in_buffer(), " ; \"%s\"", message); |
| 316 message); | |
| 317 } | 301 } |
| 318 break; | 302 break; |
| 319 } | 303 } |
| 320 case DIV: { | 304 case DIV: { |
| 321 Format(instr, "div 'rs, 'rt"); | 305 Format(instr, "div 'rs, 'rt"); |
| 322 break; | 306 break; |
| 323 } | 307 } |
| 324 case DIVU: { | 308 case DIVU: { |
| 325 Format(instr, "divu 'rs, 'rt"); | 309 Format(instr, "divu 'rs, 'rt"); |
| 326 break; | 310 break; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 } else if (instr->RsField() == R0) { | 367 } else if (instr->RsField() == R0) { |
| 384 Format(instr, "mov 'rd, 'rt"); | 368 Format(instr, "mov 'rd, 'rt"); |
| 385 } else if (instr->RtField() == R0) { | 369 } else if (instr->RtField() == R0) { |
| 386 Format(instr, "mov 'rd, 'rs"); | 370 Format(instr, "mov 'rd, 'rs"); |
| 387 } else { | 371 } else { |
| 388 Format(instr, "or 'rd, 'rs, 'rt"); | 372 Format(instr, "or 'rd, 'rs, 'rt"); |
| 389 } | 373 } |
| 390 break; | 374 break; |
| 391 } | 375 } |
| 392 case SLL: { | 376 case SLL: { |
| 393 if ((instr->RdField() == R0) && | 377 if ((instr->RdField() == R0) && (instr->RtField() == R0) && |
| 394 (instr->RtField() == R0) && | |
| 395 (instr->SaField() == 0)) { | 378 (instr->SaField() == 0)) { |
| 396 Format(instr, "nop"); | 379 Format(instr, "nop"); |
| 397 } else { | 380 } else { |
| 398 Format(instr, "sll 'rd, 'rt, 'sa"); | 381 Format(instr, "sll 'rd, 'rt, 'sa"); |
| 399 } | 382 } |
| 400 break; | 383 break; |
| 401 } | 384 } |
| 402 case SLLV: { | 385 case SLLV: { |
| 403 Format(instr, "sllv 'rd, 'rt, 'rs"); | 386 Format(instr, "sllv 'rd, 'rt, 'rs"); |
| 404 break; | 387 break; |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 break; | 753 break; |
| 771 } | 754 } |
| 772 default: { | 755 default: { |
| 773 Unknown(instr); | 756 Unknown(instr); |
| 774 break; | 757 break; |
| 775 } | 758 } |
| 776 } | 759 } |
| 777 } | 760 } |
| 778 | 761 |
| 779 | 762 |
| 780 void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 763 void Disassembler::DecodeInstruction(char* hex_buffer, |
| 781 char* human_buffer, intptr_t human_size, | 764 intptr_t hex_size, |
| 782 int* out_instr_len, const Code& code, | 765 char* human_buffer, |
| 783 Object** object, uword pc) { | 766 intptr_t human_size, |
| 767 int* out_instr_len, |
| 768 const Code& code, |
| 769 Object** object, |
| 770 uword pc) { |
| 784 MIPSDecoder decoder(human_buffer, human_size); | 771 MIPSDecoder decoder(human_buffer, human_size); |
| 785 Instr* instr = Instr::At(pc); | 772 Instr* instr = Instr::At(pc); |
| 786 decoder.InstructionDecode(instr); | 773 decoder.InstructionDecode(instr); |
| 787 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); | 774 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
| 788 if (out_instr_len) { | 775 if (out_instr_len) { |
| 789 *out_instr_len = Instr::kInstrSize; | 776 *out_instr_len = Instr::kInstrSize; |
| 790 } | 777 } |
| 791 | 778 |
| 792 *object = NULL; | 779 *object = NULL; |
| 793 if (!code.IsNull()) { | 780 if (!code.IsNull()) { |
| 794 *object = &Object::Handle(); | 781 *object = &Object::Handle(); |
| 795 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { | 782 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { |
| 796 *object = NULL; | 783 *object = NULL; |
| 797 } | 784 } |
| 798 } | 785 } |
| 799 } | 786 } |
| 800 | 787 |
| 801 #endif // !PRODUCT | 788 #endif // !PRODUCT |
| 802 | 789 |
| 803 } // namespace dart | 790 } // namespace dart |
| 804 | 791 |
| 805 #endif // defined TARGET_ARCH_MIPS | 792 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |