1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_DEX_INSTRUCTION_H_ 18 #define ART_RUNTIME_DEX_INSTRUCTION_H_ 19 20 #include "base/logging.h" 21 #include "base/macros.h" 22 #include "globals.h" 23 24 typedef uint8_t uint4_t; 25 typedef int8_t int4_t; 26 27 namespace art { 28 29 class DexFile; 30 31 enum { 32 kNumPackedOpcodes = 0x100 33 }; 34 35 class Instruction { 36 public: 37 // NOP-encoded switch-statement signatures. 38 enum Signatures { 39 kPackedSwitchSignature = 0x0100, 40 kSparseSwitchSignature = 0x0200, 41 kArrayDataSignature = 0x0300, 42 }; 43 44 struct PACKED(4) PackedSwitchPayload { 45 const uint16_t ident; 46 const uint16_t case_count; 47 const int32_t first_key; 48 const int32_t targets[]; 49 50 private: 51 DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload); 52 }; 53 54 struct PACKED(4) SparseSwitchPayload { 55 const uint16_t ident; 56 const uint16_t case_count; 57 const int32_t keys_and_targets[]; 58 59 public: GetKeysSparseSwitchPayload60 const int32_t* GetKeys() const { 61 return keys_and_targets; 62 } 63 GetTargetsSparseSwitchPayload64 const int32_t* GetTargets() const { 65 return keys_and_targets + case_count; 66 } 67 68 private: 69 DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload); 70 }; 71 72 struct PACKED(4) ArrayDataPayload { 73 const uint16_t ident; 74 const uint16_t element_width; 75 const uint32_t element_count; 76 const uint8_t data[]; 77 78 private: 79 DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload); 80 }; 81 82 enum Code { // private marker to avoid generate-operator-out.py from processing. 83 #define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode, 84 #include "dex_instruction_list.h" 85 DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) 86 #undef DEX_INSTRUCTION_LIST 87 #undef INSTRUCTION_ENUM 88 RSUB_INT_LIT16 = RSUB_INT, 89 }; 90 91 enum Format { 92 k10x, // op 93 k12x, // op vA, vB 94 k11n, // op vA, #+B 95 k11x, // op vAA 96 k10t, // op +AA 97 k20t, // op +AAAA 98 k22x, // op vAA, vBBBB 99 k21t, // op vAA, +BBBB 100 k21s, // op vAA, #+BBBB 101 k21h, // op vAA, #+BBBB00000[00000000] 102 k21c, // op vAA, thing@BBBB 103 k23x, // op vAA, vBB, vCC 104 k22b, // op vAA, vBB, #+CC 105 k22t, // op vA, vB, +CCCC 106 k22s, // op vA, vB, #+CCCC 107 k22c, // op vA, vB, thing@CCCC 108 k32x, // op vAAAA, vBBBB 109 k30t, // op +AAAAAAAA 110 k31t, // op vAA, +BBBBBBBB 111 k31i, // op vAA, #+BBBBBBBB 112 k31c, // op vAA, thing@BBBBBBBB 113 k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG) 114 k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB 115 k51l, // op vAA, #+BBBBBBBBBBBBBBBB 116 }; 117 118 enum Flags { 119 kBranch = 0x000001, // conditional or unconditional branch 120 kContinue = 0x000002, // flow can continue to next statement 121 kSwitch = 0x000004, // switch statement 122 kThrow = 0x000008, // could cause an exception to be thrown 123 kReturn = 0x000010, // returns, no additional statements 124 kInvoke = 0x000020, // a flavor of invoke 125 kUnconditional = 0x000040, // unconditional branch 126 kAdd = 0x000080, // addition 127 kSubtract = 0x000100, // subtract 128 kMultiply = 0x000200, // multiply 129 kDivide = 0x000400, // division 130 kRemainder = 0x000800, // remainder 131 kAnd = 0x001000, // and 132 kOr = 0x002000, // or 133 kXor = 0x004000, // xor 134 kShl = 0x008000, // shl 135 kShr = 0x010000, // shr 136 kUshr = 0x020000, // ushr 137 kCast = 0x040000, // cast 138 kStore = 0x080000, // store opcode 139 kLoad = 0x100000, // load opcode 140 kClobber = 0x200000, // clobbers memory in a big way (not just a write) 141 kRegCFieldOrConstant = 0x400000, // is the third virtual register a field or literal constant (vC) 142 kRegBFieldOrConstant = 0x800000, // is the second virtual register a field or literal constant (vB) 143 }; 144 145 enum VerifyFlag { 146 kVerifyNone = 0x000000, 147 kVerifyRegA = 0x000001, 148 kVerifyRegAWide = 0x000002, 149 kVerifyRegB = 0x000004, 150 kVerifyRegBField = 0x000008, 151 kVerifyRegBMethod = 0x000010, 152 kVerifyRegBNewInstance = 0x000020, 153 kVerifyRegBString = 0x000040, 154 kVerifyRegBType = 0x000080, 155 kVerifyRegBWide = 0x000100, 156 kVerifyRegC = 0x000200, 157 kVerifyRegCField = 0x000400, 158 kVerifyRegCNewArray = 0x000800, 159 kVerifyRegCType = 0x001000, 160 kVerifyRegCWide = 0x002000, 161 kVerifyArrayData = 0x004000, 162 kVerifyBranchTarget = 0x008000, 163 kVerifySwitchTargets = 0x010000, 164 kVerifyVarArg = 0x020000, 165 kVerifyVarArgNonZero = 0x040000, 166 kVerifyVarArgRange = 0x080000, 167 kVerifyVarArgRangeNonZero = 0x100000, 168 kVerifyRuntimeOnly = 0x200000, 169 kVerifyError = 0x400000, 170 }; 171 172 static constexpr uint32_t kMaxVarArgRegs = 5; 173 174 // Returns the size (in 2 byte code units) of this instruction. SizeInCodeUnits()175 size_t SizeInCodeUnits() const { 176 int result = kInstructionSizeInCodeUnits[Opcode()]; 177 if (UNLIKELY(result < 0)) { 178 return SizeInCodeUnitsComplexOpcode(); 179 } else { 180 return static_cast<size_t>(result); 181 } 182 } 183 184 // Reads an instruction out of the stream at the specified address. At(const uint16_t * code)185 static const Instruction* At(const uint16_t* code) { 186 DCHECK(code != nullptr); 187 return reinterpret_cast<const Instruction*>(code); 188 } 189 190 // Reads an instruction out of the stream from the current address plus an offset. RelativeAt(int32_t offset)191 const Instruction* RelativeAt(int32_t offset) const WARN_UNUSED { 192 return At(reinterpret_cast<const uint16_t*>(this) + offset); 193 } 194 195 // Returns a pointer to the next instruction in the stream. Next()196 const Instruction* Next() const { 197 return RelativeAt(SizeInCodeUnits()); 198 } 199 200 // Returns a pointer to the instruction after this 1xx instruction in the stream. Next_1xx()201 const Instruction* Next_1xx() const { 202 DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t); 203 return RelativeAt(1); 204 } 205 206 // Returns a pointer to the instruction after this 2xx instruction in the stream. Next_2xx()207 const Instruction* Next_2xx() const { 208 DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c); 209 return RelativeAt(2); 210 } 211 212 // Returns a pointer to the instruction after this 3xx instruction in the stream. Next_3xx()213 const Instruction* Next_3xx() const { 214 DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc); 215 return RelativeAt(3); 216 } 217 218 // Returns a pointer to the instruction after this 51l instruction in the stream. Next_51l()219 const Instruction* Next_51l() const { 220 DCHECK(FormatOf(Opcode()) == k51l); 221 return RelativeAt(5); 222 } 223 224 // Returns the name of this instruction's opcode. Name()225 const char* Name() const { 226 return Instruction::Name(Opcode()); 227 } 228 229 // Returns the name of the given opcode. Name(Code opcode)230 static const char* Name(Code opcode) { 231 return kInstructionNames[opcode]; 232 } 233 234 // VRegA 235 bool HasVRegA() const; 236 int32_t VRegA() const; 237 VRegA_10t()238 int8_t VRegA_10t() const { 239 return VRegA_10t(Fetch16(0)); 240 } VRegA_10x()241 uint8_t VRegA_10x() const { 242 return VRegA_10x(Fetch16(0)); 243 } VRegA_11n()244 uint4_t VRegA_11n() const { 245 return VRegA_11n(Fetch16(0)); 246 } VRegA_11x()247 uint8_t VRegA_11x() const { 248 return VRegA_11x(Fetch16(0)); 249 } VRegA_12x()250 uint4_t VRegA_12x() const { 251 return VRegA_12x(Fetch16(0)); 252 } 253 int16_t VRegA_20t() const; VRegA_21c()254 uint8_t VRegA_21c() const { 255 return VRegA_21c(Fetch16(0)); 256 } VRegA_21h()257 uint8_t VRegA_21h() const { 258 return VRegA_21h(Fetch16(0)); 259 } VRegA_21s()260 uint8_t VRegA_21s() const { 261 return VRegA_21s(Fetch16(0)); 262 } VRegA_21t()263 uint8_t VRegA_21t() const { 264 return VRegA_21t(Fetch16(0)); 265 } VRegA_22b()266 uint8_t VRegA_22b() const { 267 return VRegA_22b(Fetch16(0)); 268 } VRegA_22c()269 uint4_t VRegA_22c() const { 270 return VRegA_22c(Fetch16(0)); 271 } VRegA_22s()272 uint4_t VRegA_22s() const { 273 return VRegA_22s(Fetch16(0)); 274 } VRegA_22t()275 uint4_t VRegA_22t() const { 276 return VRegA_22t(Fetch16(0)); 277 } VRegA_22x()278 uint8_t VRegA_22x() const { 279 return VRegA_22x(Fetch16(0)); 280 } VRegA_23x()281 uint8_t VRegA_23x() const { 282 return VRegA_23x(Fetch16(0)); 283 } 284 int32_t VRegA_30t() const; VRegA_31c()285 uint8_t VRegA_31c() const { 286 return VRegA_31c(Fetch16(0)); 287 } VRegA_31i()288 uint8_t VRegA_31i() const { 289 return VRegA_31i(Fetch16(0)); 290 } VRegA_31t()291 uint8_t VRegA_31t() const { 292 return VRegA_31t(Fetch16(0)); 293 } 294 uint16_t VRegA_32x() const; VRegA_35c()295 uint4_t VRegA_35c() const { 296 return VRegA_35c(Fetch16(0)); 297 } VRegA_3rc()298 uint8_t VRegA_3rc() const { 299 return VRegA_3rc(Fetch16(0)); 300 } VRegA_51l()301 uint8_t VRegA_51l() const { 302 return VRegA_51l(Fetch16(0)); 303 } 304 305 // The following methods return the vA operand for various instruction formats. The "inst_data" 306 // parameter holds the first 16 bits of instruction which the returned value is decoded from. 307 int8_t VRegA_10t(uint16_t inst_data) const; 308 uint8_t VRegA_10x(uint16_t inst_data) const; 309 uint4_t VRegA_11n(uint16_t inst_data) const; 310 uint8_t VRegA_11x(uint16_t inst_data) const; 311 uint4_t VRegA_12x(uint16_t inst_data) const; 312 uint8_t VRegA_21c(uint16_t inst_data) const; 313 uint8_t VRegA_21h(uint16_t inst_data) const; 314 uint8_t VRegA_21s(uint16_t inst_data) const; 315 uint8_t VRegA_21t(uint16_t inst_data) const; 316 uint8_t VRegA_22b(uint16_t inst_data) const; 317 uint4_t VRegA_22c(uint16_t inst_data) const; 318 uint4_t VRegA_22s(uint16_t inst_data) const; 319 uint4_t VRegA_22t(uint16_t inst_data) const; 320 uint8_t VRegA_22x(uint16_t inst_data) const; 321 uint8_t VRegA_23x(uint16_t inst_data) const; 322 uint8_t VRegA_31c(uint16_t inst_data) const; 323 uint8_t VRegA_31i(uint16_t inst_data) const; 324 uint8_t VRegA_31t(uint16_t inst_data) const; 325 uint4_t VRegA_35c(uint16_t inst_data) const; 326 uint8_t VRegA_3rc(uint16_t inst_data) const; 327 uint8_t VRegA_51l(uint16_t inst_data) const; 328 329 // VRegB 330 bool HasVRegB() const; 331 int32_t VRegB() const; 332 333 bool HasWideVRegB() const; 334 uint64_t WideVRegB() const; 335 VRegB_11n()336 int4_t VRegB_11n() const { 337 return VRegB_11n(Fetch16(0)); 338 } VRegB_12x()339 uint4_t VRegB_12x() const { 340 return VRegB_12x(Fetch16(0)); 341 } 342 uint16_t VRegB_21c() const; 343 uint16_t VRegB_21h() const; 344 int16_t VRegB_21s() const; 345 int16_t VRegB_21t() const; 346 uint8_t VRegB_22b() const; VRegB_22c()347 uint4_t VRegB_22c() const { 348 return VRegB_22c(Fetch16(0)); 349 } VRegB_22s()350 uint4_t VRegB_22s() const { 351 return VRegB_22s(Fetch16(0)); 352 } VRegB_22t()353 uint4_t VRegB_22t() const { 354 return VRegB_22t(Fetch16(0)); 355 } 356 uint16_t VRegB_22x() const; 357 uint8_t VRegB_23x() const; 358 uint32_t VRegB_31c() const; 359 int32_t VRegB_31i() const; 360 int32_t VRegB_31t() const; 361 uint16_t VRegB_32x() const; 362 uint16_t VRegB_35c() const; 363 uint16_t VRegB_3rc() const; 364 uint64_t VRegB_51l() const; // vB_wide 365 366 // The following methods return the vB operand for all instruction formats where it is encoded in 367 // the first 16 bits of instruction. The "inst_data" parameter holds these 16 bits. The returned 368 // value is decoded from it. 369 int4_t VRegB_11n(uint16_t inst_data) const; 370 uint4_t VRegB_12x(uint16_t inst_data) const; 371 uint4_t VRegB_22c(uint16_t inst_data) const; 372 uint4_t VRegB_22s(uint16_t inst_data) const; 373 uint4_t VRegB_22t(uint16_t inst_data) const; 374 375 // VRegC 376 bool HasVRegC() const; 377 int32_t VRegC() const; 378 379 int8_t VRegC_22b() const; 380 uint16_t VRegC_22c() const; 381 int16_t VRegC_22s() const; 382 int16_t VRegC_22t() const; 383 uint8_t VRegC_23x() const; 384 uint4_t VRegC_35c() const; 385 uint16_t VRegC_3rc() const; 386 387 // Fills the given array with the 'arg' array of the instruction. 388 bool HasVarArgs() const; 389 void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const; GetVarArgs(uint32_t args[kMaxVarArgRegs])390 void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const { 391 return GetVarArgs(args, Fetch16(0)); 392 } 393 394 // Returns the opcode field of the instruction. The given "inst_data" parameter must be the first 395 // 16 bits of instruction. Opcode(uint16_t inst_data)396 Code Opcode(uint16_t inst_data) const { 397 DCHECK_EQ(inst_data, Fetch16(0)); 398 return static_cast<Code>(inst_data & 0xFF); 399 } 400 401 // Returns the opcode field of the instruction from the first 16 bits of instruction. Opcode()402 Code Opcode() const { 403 return Opcode(Fetch16(0)); 404 } 405 SetOpcode(Code opcode)406 void SetOpcode(Code opcode) { 407 DCHECK_LT(static_cast<uint16_t>(opcode), 256u); 408 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 409 insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode); 410 } 411 SetVRegA_10x(uint8_t val)412 void SetVRegA_10x(uint8_t val) { 413 DCHECK(FormatOf(Opcode()) == k10x); 414 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 415 insns[0] = (val << 8) | (insns[0] & 0x00ff); 416 } 417 SetVRegB_3rc(uint16_t val)418 void SetVRegB_3rc(uint16_t val) { 419 DCHECK(FormatOf(Opcode()) == k3rc); 420 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 421 insns[1] = val; 422 } 423 SetVRegB_35c(uint16_t val)424 void SetVRegB_35c(uint16_t val) { 425 DCHECK(FormatOf(Opcode()) == k35c); 426 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 427 insns[1] = val; 428 } 429 SetVRegC_22c(uint16_t val)430 void SetVRegC_22c(uint16_t val) { 431 DCHECK(FormatOf(Opcode()) == k22c); 432 uint16_t* insns = reinterpret_cast<uint16_t*>(this); 433 insns[1] = val; 434 } 435 436 // Returns the format of the given opcode. FormatOf(Code opcode)437 static Format FormatOf(Code opcode) { 438 return kInstructionFormats[opcode]; 439 } 440 441 // Returns the flags for the given opcode. FlagsOf(Code opcode)442 static int FlagsOf(Code opcode) { 443 return kInstructionFlags[opcode]; 444 } 445 446 // Return the verify flags for the given opcode. VerifyFlagsOf(Code opcode)447 static int VerifyFlagsOf(Code opcode) { 448 return kInstructionVerifyFlags[opcode]; 449 } 450 451 // Returns true if this instruction is a branch. IsBranch()452 bool IsBranch() const { 453 return (kInstructionFlags[Opcode()] & kBranch) != 0; 454 } 455 456 // Returns true if this instruction is a unconditional branch. IsUnconditional()457 bool IsUnconditional() const { 458 return (kInstructionFlags[Opcode()] & kUnconditional) != 0; 459 } 460 461 // Returns the branch offset if this instruction is a branch. 462 int32_t GetTargetOffset() const; 463 464 // Returns true if the instruction allows control flow to go to the following instruction. 465 bool CanFlowThrough() const; 466 467 // Returns true if this instruction is a switch. IsSwitch()468 bool IsSwitch() const { 469 return (kInstructionFlags[Opcode()] & kSwitch) != 0; 470 } 471 472 // Returns true if this instruction can throw. IsThrow()473 bool IsThrow() const { 474 return (kInstructionFlags[Opcode()] & kThrow) != 0; 475 } 476 477 // Determine if the instruction is any of 'return' instructions. IsReturn()478 bool IsReturn() const { 479 return (kInstructionFlags[Opcode()] & kReturn) != 0; 480 } 481 482 // Determine if this instruction ends execution of its basic block. IsBasicBlockEnd()483 bool IsBasicBlockEnd() const { 484 return IsBranch() || IsReturn() || Opcode() == THROW; 485 } 486 487 // Determine if this instruction is an invoke. IsInvoke()488 bool IsInvoke() const { 489 return (kInstructionFlags[Opcode()] & kInvoke) != 0; 490 } 491 GetVerifyTypeArgumentA()492 int GetVerifyTypeArgumentA() const { 493 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide)); 494 } 495 GetVerifyTypeArgumentB()496 int GetVerifyTypeArgumentB() const { 497 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | 498 kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | 499 kVerifyRegBWide)); 500 } 501 GetVerifyTypeArgumentC()502 int GetVerifyTypeArgumentC() const { 503 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField | 504 kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide)); 505 } 506 GetVerifyExtraFlags()507 int GetVerifyExtraFlags() const { 508 return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget | 509 kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero | kVerifyVarArgRange | 510 kVerifyVarArgRangeNonZero | kVerifyError)); 511 } 512 GetVerifyIsRuntimeOnly()513 bool GetVerifyIsRuntimeOnly() const { 514 return (kInstructionVerifyFlags[Opcode()] & kVerifyRuntimeOnly) != 0; 515 } 516 517 // Get the dex PC of this instruction as a offset in code units from the beginning of insns. GetDexPc(const uint16_t * insns)518 uint32_t GetDexPc(const uint16_t* insns) const { 519 return (reinterpret_cast<const uint16_t*>(this) - insns); 520 } 521 522 // Dump decoded version of instruction 523 std::string DumpString(const DexFile*) const; 524 525 // Dump code_units worth of this instruction, padding to code_units for shorter instructions 526 std::string DumpHex(size_t code_units) const; 527 528 // Little-endian dump code_units worth of this instruction, padding to code_units for 529 // shorter instructions 530 std::string DumpHexLE(size_t instr_code_units) const; 531 Fetch16(size_t offset)532 uint16_t Fetch16(size_t offset) const { 533 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 534 return insns[offset]; 535 } 536 537 private: 538 size_t SizeInCodeUnitsComplexOpcode() const; 539 Fetch32(size_t offset)540 uint32_t Fetch32(size_t offset) const { 541 return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16)); 542 } 543 InstA()544 uint4_t InstA() const { 545 return InstA(Fetch16(0)); 546 } 547 InstB()548 uint4_t InstB() const { 549 return InstB(Fetch16(0)); 550 } 551 InstAA()552 uint8_t InstAA() const { 553 return InstAA(Fetch16(0)); 554 } 555 InstA(uint16_t inst_data)556 uint4_t InstA(uint16_t inst_data) const { 557 DCHECK_EQ(inst_data, Fetch16(0)); 558 return static_cast<uint4_t>((inst_data >> 8) & 0x0f); 559 } 560 InstB(uint16_t inst_data)561 uint4_t InstB(uint16_t inst_data) const { 562 DCHECK_EQ(inst_data, Fetch16(0)); 563 return static_cast<uint4_t>(inst_data >> 12); 564 } 565 InstAA(uint16_t inst_data)566 uint8_t InstAA(uint16_t inst_data) const { 567 DCHECK_EQ(inst_data, Fetch16(0)); 568 return static_cast<uint8_t>(inst_data >> 8); 569 } 570 571 static const char* const kInstructionNames[]; 572 static Format const kInstructionFormats[]; 573 static int const kInstructionFlags[]; 574 static int const kInstructionVerifyFlags[]; 575 static int const kInstructionSizeInCodeUnits[]; 576 DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); 577 }; 578 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code); 579 std::ostream& operator<<(std::ostream& os, const Instruction::Format& format); 580 std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags); 581 std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags); 582 583 } // namespace art 584 585 #endif // ART_RUNTIME_DEX_INSTRUCTION_H_ 586