Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, 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 #ifndef VM_CONSTANTS_DBC_H_ | |
| 6 #define VM_CONSTANTS_DBC_H_ | |
| 7 | |
| 8 #include "platform/globals.h" | |
| 9 #include "platform/assert.h" | |
| 10 #include "platform/utils.h" | |
| 11 | |
| 12 | |
| 13 namespace dart { | |
| 14 | |
| 15 // List of Dart Bytecode instructions. | |
| 16 // | |
| 17 // INTERPRETER STATE | |
| 18 // | |
| 19 // current frame info (see stack_frame_dbc.h for layout) | |
| 20 // v-----^-----v | |
| 21 // ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~ | |
| 22 // ~ | ~ ~ | FP[0] | FP[1] | ~ ~ | SP[-1]| SP[0] | | |
| 23 // ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~ | |
| 24 // ^ ^ | |
| 25 // FP SP | |
| 26 // | |
| 27 // | |
| 28 // The state of execution is captured in few interpreter registers: | |
| 29 // | |
| 30 // FP - base of the cFurrent frame | |
|
zra
2016/04/08 22:37:34
cFurrent -> current
Vyacheslav Egorov (Google)
2016/04/11 10:49:10
Done.
| |
| 31 // SP - top of the stack (TOS) for the current frame | |
| 32 // PP - object pool for the currently execution function | |
| 33 // | |
| 34 // Frame info stored below FP additionally contains pointers to the currently | |
| 35 // executing function and code (see stack_frame_dbc.h for more information). | |
| 36 // | |
| 37 // In the unoptimized code most of bytecodes take operands implicitly from | |
| 38 // stack and store results again on the stack. Constant operands are usually | |
| 39 // taken from the object pool by index. | |
| 40 // | |
| 41 // ENCODING | |
| 42 // | |
| 43 // Each instruction is a 32-bit integer with opcode stored in the least | |
| 44 // significant byte. The following operand encodings are used: | |
| 45 // | |
| 46 // 0........8.......16.......24.......32 | |
| 47 // +--------+--------+--------+--------+ | |
| 48 // | opcode |~~~~~~~~~~~~~~~~~~~~~~~~~~| 0: no operands | |
| 49 // +--------+--------+--------+--------+ | |
| 50 // | |
| 51 // +--------+--------+--------+--------+ | |
| 52 // | opcode | A |~~~~~~~~~~~~~~~~~| A: single unsigned 8-bit operand | |
| 53 // +--------+--------+--------+--------+ | |
| 54 // | |
| 55 // +--------+--------+--------+--------+ | |
| 56 // | opcode | A | D | A_D: unsigned 8-bit operand and | |
| 57 // +--------+--------+--------+--------+ unsigned 16-bit operand | |
| 58 // | |
| 59 // +--------+--------+--------+--------+ | |
| 60 // | opcode | A | X | A_X: unsigned 8-bit operand and | |
| 61 // +--------+--------+--------+--------+ signed 16-bit operand | |
| 62 // | |
| 63 // +--------+--------+--------+--------+ | |
| 64 // | opcode |~~~~~~~~| D | D: unsigned 16-bit operand | |
| 65 // +--------+--------+--------+--------+ | |
| 66 // | |
| 67 // +--------+--------+--------+--------+ | |
| 68 // | opcode |~~~~~~~~| X | X: signed 16-bit operand | |
| 69 // +--------+--------+--------+--------+ | |
| 70 // | |
| 71 // +--------+--------+--------+--------+ | |
| 72 // | opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands | |
| 73 // +--------+--------+--------+--------+ | |
| 74 // | |
| 75 // +--------+--------+--------+--------+ | |
| 76 // | opcode | T | T: signed 24-bit operand | |
| 77 // +--------+--------+--------+--------+ | |
| 78 // | |
| 79 // | |
| 80 // INSTRUCTIONS | |
| 81 // | |
| 82 // - Trap | |
| 83 // | |
| 84 // Unreachable instruction. | |
| 85 // | |
| 86 // - Compile | |
| 87 // | |
| 88 // Compile current function and start executing newly produced code | |
| 89 // (used to implement LazyCompileStub); | |
| 90 // | |
| 91 // - Intrinsic id | |
| 92 // | |
| 93 // Execute intrinsic with the given id. If intrinsic returns true then | |
| 94 // return from the current function to the caller passing value produced | |
| 95 // by the intrinsic as a result; | |
| 96 // | |
| 97 // - Drop1; DropR n; Drop n | |
| 98 // | |
| 99 // Drop 1 or n values from the stack, if instruction is DropR push the first | |
| 100 // dropped value to the stack; | |
| 101 // | |
| 102 // - Jump target | |
| 103 // | |
| 104 // Jump to the given target. Target is specified as offset from the PC of the | |
| 105 // jump instruction. | |
| 106 // | |
| 107 // - Return R; ReturnTOS | |
| 108 // | |
| 109 // Return to the caller using either a value from the given register or a | |
| 110 // value from the top-of-stack as a result. | |
| 111 // | |
| 112 // Note: return instruction knows how many arguments to remove from the | |
| 113 // stack because it can look at the call instruction at caller's PC and | |
| 114 // take argument count from it. | |
| 115 // | |
| 116 // - Move rA, rX | |
| 117 // | |
| 118 // FP[rA] <- FP[rX] | |
| 119 // Note: rX is singed so it can be used to address parameters which are | |
| 120 // at negative indices with respect to FP. | |
| 121 // | |
| 122 // - Push rX | |
| 123 // | |
| 124 // Push FP[rX] to the stack. | |
| 125 // | |
| 126 // - LoadConstant rA, D; PushConstant D | |
| 127 // | |
| 128 // Load value at index D from constant pool into rA or push it onto the | |
|
zra
2016/04/08 22:37:34
FP[rA]?
Vyacheslav Egorov (Google)
2016/04/11 10:49:10
Done.
| |
| 129 // stack. | |
| 130 // | |
| 131 // - StoreLocal rX; PopLocal rX | |
| 132 // | |
| 133 // Store top of the stack into FP[rX] and pop it if needed. | |
| 134 // | |
| 135 // - StaticCall ArgC, D | |
| 136 // | |
| 137 // Invoke function in SP[0] with arguments SP[-(1+ArgC)], ..., SP[-1] and | |
| 138 // argument descriptor PP[D]. | |
| 139 // | |
| 140 // - InstanceCall ArgC, D; InstanceCall2 ArgC, D; InstanceCall3 ArgC, D | |
| 141 // | |
| 142 // Lookup and invoke method using ICData in PP[D] with arguments | |
| 143 // SP[-(1+ArgC)], ..., SP[-1]. | |
| 144 // | |
| 145 // - NativeCall, NativeBootstrapCall | |
| 146 // | |
| 147 // Invoke native function SP[-1] with argc_tag SP[0]. | |
| 148 // | |
| 149 // - AddTOS; SubTOS; MulTOS; BitOrTOS; BitAndTOS; EqualTOS; LessThanTOS; | |
| 150 // GreaterThanTOS; | |
| 151 // | |
| 152 // Smi fast-path for a corresponding method. Checks if SP[0] and SP[-1] are | |
| 153 // both smis and result of SP[0] <op> SP[-1] is a smi - if this is true | |
| 154 // then pops operands and pushes result on the stack and skips the next | |
| 155 // instruction (which implements a slow path fallback). | |
| 156 // | |
| 157 // - StoreStaticTOS D | |
| 158 // | |
| 159 // Stores TOS into the static field PP[D]. | |
| 160 // | |
| 161 // - PushStatic | |
| 162 // | |
| 163 // Pushes value of the static field PP[D] on to the stack. | |
| 164 // | |
| 165 // - InitStaticTOS | |
| 166 // | |
| 167 // Takes static field from TOS and ensures that it is initialized. | |
| 168 // | |
| 169 // - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS | |
|
zra
2016/04/08 22:37:34
What does Strict mean here? Will there be non-Stri
Vyacheslav Egorov (Google)
2016/04/11 10:49:10
Strict means the same it means in Token::kEQ_STRIC
| |
| 170 // | |
| 171 // Skips the next instruction unless the given condition holds. 'Num' | |
| 172 // variants perform number check while non-Num variants just compare | |
| 173 // RawObject pointers. | |
| 174 // | |
| 175 // Used to implement conditional jump: | |
| 176 // | |
| 177 // IfNeStrictTOS | |
| 178 // Jump T ;; jump if not equal | |
| 179 // | |
| 180 // - CreateArrayTOS | |
| 181 // | |
| 182 // Allocate array of length SP[0] with type arguments SP[-1]. | |
| 183 // | |
| 184 // - Allocate D | |
| 185 // | |
| 186 // Allocate object of class PP[D] with no type arguments. | |
| 187 // | |
| 188 // - AllocateT | |
| 189 // | |
| 190 // Allocate object of class SP[0] with type arguments SP[-1]. | |
| 191 // | |
| 192 // - StoreIndexedTOS | |
| 193 // | |
| 194 // Store SP[0] into array SP[-2] at index SP[-1]. No typechecking is done. | |
| 195 // SP[-2] is assumed to be a RawArray, SP[-1] to be a smi. | |
| 196 // | |
| 197 // - StoreField rA, B, rC | |
| 198 // | |
| 199 // Store value FP[rC] into object FP[rA] at offset (in words) B. | |
| 200 // | |
| 201 // - StoreFieldTOS D | |
| 202 // | |
| 203 // Store value SP[0] into object SP[-1] at offset (in words) D. | |
| 204 // | |
| 205 // - LoadField rA, rB, C | |
| 206 // | |
| 207 // Load value at offset (in words) C from object FP[rB] into FP[rA]. | |
| 208 // | |
| 209 // - LoadFieldTOS D | |
| 210 // | |
| 211 // Push value at offset (in words) D from object SP[0]. | |
| 212 // | |
| 213 // - BooleanNegateTOS | |
| 214 // | |
| 215 // SP[0] = !SP[0] | |
| 216 // | |
| 217 // - Throw A | |
| 218 // | |
| 219 // Throw (Rethrow if A != 0) exception. Exception object and stack object | |
| 220 // are taken from TOS. | |
| 221 // | |
| 222 // - Entry A, B, rC | |
| 223 // | |
| 224 // Function prologue for the function with no optional or named arguments: | |
| 225 // A - expected number of positional arguments; | |
| 226 // B - number of local slots to reserve; | |
| 227 // rC - specifies context register to initialize with empty context. | |
| 228 // | |
| 229 // - EntryOpt A, B, C | |
| 230 // | |
| 231 // Function prologue for the function with optional or named arguments: | |
| 232 // A - expected number of positional arguments; | |
| 233 // B - number of optional arguments; | |
| 234 // C - number of named arguments; | |
| 235 // | |
| 236 // Only one of B and C can be not 0. | |
| 237 // | |
| 238 // If B is not 0 then EntryOpt bytecode is followed by B LoadConstant | |
| 239 // bytecodes specifying default values for optional arguments. | |
| 240 // | |
| 241 // If C is not 0 then EntryOpt is followed by 2 * B LoadConstant bytecodes. | |
| 242 // Bytecode at 2 * i specifies name of the i-th named argument and at | |
| 243 // 2 * i + 1 default value. rA part of the LoadConsant bytecode specifies | |
| 244 // the location of the parameter on the stack. Here named arguments are | |
| 245 // sorted alphabetically to enable linear matching similar to how function | |
| 246 // prologues are implemented on other architectures. | |
| 247 // | |
| 248 // Note: Unlike Entry bytecode EntryOpt does not setup the frame for | |
| 249 // local variables this is done by a separate bytecode Frame. | |
| 250 // | |
| 251 // - Frame D | |
| 252 // | |
| 253 // Reserve and initialize with null space for D local variables. | |
| 254 // | |
| 255 // - SetFrame A | |
| 256 // | |
| 257 // Reinitialize SP assuming that current frame has size A. | |
| 258 // Used to drop temporaries from the stack in the exception handler. | |
| 259 // | |
| 260 // - AllocateContext D | |
| 261 // | |
| 262 // Allocate Context object assuming for D context variables. | |
| 263 // | |
| 264 // - CloneContext | |
| 265 // | |
| 266 // Clone context stored in TOS. | |
| 267 // | |
| 268 // - MoveSpecial rA, D | |
| 269 // | |
| 270 // Copy special values from inside interpreter to FP[rA]. Currently only | |
| 271 // used to pass exception object (D = 0) and stack trace object (D = 1) to | |
| 272 // catch handler. | |
| 273 // | |
| 274 // - InstantiateType D | |
| 275 // | |
| 276 // Instantiate type PP[D] with instantiator type arguments SP[0]. | |
| 277 // | |
| 278 // - InstantiateTypeArgumentsTOS D | |
| 279 // | |
| 280 // Instantiate type arguments PP[D] with instantiator SP[0]. | |
| 281 // | |
| 282 // - AssertAssignable D | |
| 283 // | |
| 284 // Assert that SP[-3] is assignable to variable named SP[0] of type | |
| 285 // SP[-1] with type arguments SP[-2] using SubtypeTestCache PP[D]. | |
| 286 // | |
| 287 // - AssertBoolean A | |
| 288 // | |
| 289 // Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0). | |
| 290 // | |
| 291 // - CheckStack | |
| 292 // | |
| 293 // Compare SP against isolate stack limit and call StackOverflow handler if | |
| 294 // necessary. | |
| 295 // | |
| 296 // - DebugStep, DebugBreak A | |
| 297 // | |
| 298 // Debugger support. DebugBreak is bytecode that can be patched into the | |
| 299 // instruction stream to trigger in place breakpoint. | |
| 300 // | |
| 301 // When patching instance or static call with DebugBreak we set A to | |
| 302 // match patched call's argument count so that Return instructions continue | |
| 303 // to work. | |
| 304 // | |
| 305 // TODO(vegorov) the way we replace calls with DebugBreak does not work | |
| 306 // with our smi fast paths because DebugBreak is simply skipped. | |
| 307 // | |
| 308 // BYTECODE LIST FORMAT | |
| 309 // | |
| 310 // Bytecode list below is specified using the following format: | |
| 311 // | |
| 312 // V(BytecodeName, OperandForm, Op1, Op2, Op3) | |
| 313 // | |
| 314 // - OperandForm specifies operand encoding and should be one of 0, A, T, A_D, | |
| 315 // A_X, X, D (see ENCODING section above). | |
| 316 // | |
| 317 // - Op1, Op2, Op2 specify operand meaning. Possible values: | |
| 318 // | |
| 319 // ___ ignored / non-existent operand | |
| 320 // num immediate operand | |
| 321 // lit constant literal from object pool | |
| 322 // reg register (unsigned FP relative local) | |
| 323 // xeg x-register (signed FP relative local) | |
| 324 // | |
| 325 #define BYTECODES_LIST(V) \ | |
| 326 V(Trap, 0, ___, ___, ___) \ | |
| 327 V(Compile, 0, ___, ___, ___) \ | |
| 328 V(Intrinsic, A, num, ___, ___) \ | |
| 329 V(Drop1, 0, ___, ___, ___) \ | |
| 330 V(DropR, A, num, ___, ___) \ | |
| 331 V(Drop, A, num, ___, ___) \ | |
| 332 V(Jump, T, tgt, ___, ___) \ | |
|
zra
2016/04/08 22:37:34
tgt is not in the key above.
Vyacheslav Egorov (Google)
2016/04/11 10:49:10
Done.
| |
| 333 V(Return, A, num, ___, ___) \ | |
| 334 V(ReturnTOS, 0, ___, ___, ___) \ | |
| 335 V(Move, A_X, reg, xeg, ___) \ | |
| 336 V(Push, X, xeg, ___, ___) \ | |
| 337 V(LoadConstant, A_D, reg, lit, ___) \ | |
| 338 V(PushConstant, D, lit, ___, ___) \ | |
| 339 V(StoreLocal, X, xeg, ___, ___) \ | |
| 340 V(PopLocal, X, xeg, ___, ___) \ | |
| 341 V(StaticCall, A_D, num, num, ___) \ | |
| 342 V(InstanceCall, A_D, num, num, ___) \ | |
| 343 V(InstanceCall2, A_D, num, num, ___) \ | |
| 344 V(InstanceCall3, A_D, num, num, ___) \ | |
| 345 V(NativeCall, 0, ___, ___, ___) \ | |
| 346 V(NativeBootstrapCall, 0, ___, ___, ___) \ | |
| 347 V(AddTOS, 0, ___, ___, ___) \ | |
| 348 V(SubTOS, 0, ___, ___, ___) \ | |
| 349 V(MulTOS, 0, ___, ___, ___) \ | |
| 350 V(BitOrTOS, 0, ___, ___, ___) \ | |
| 351 V(BitAndTOS, 0, ___, ___, ___) \ | |
| 352 V(EqualTOS, 0, ___, ___, ___) \ | |
| 353 V(LessThanTOS, 0, ___, ___, ___) \ | |
| 354 V(GreaterThanTOS, 0, ___, ___, ___) \ | |
| 355 V(StoreStaticTOS, D, lit, ___, ___) \ | |
| 356 V(PushStatic, D, lit, ___, ___) \ | |
| 357 V(InitStaticTOS, 0, ___, ___, ___) \ | |
| 358 V(IfNeStrictTOS, 0, ___, ___, ___) \ | |
| 359 V(IfEqStrictTOS, 0, ___, ___, ___) \ | |
| 360 V(IfNeStrictNumTOS, 0, ___, ___, ___) \ | |
| 361 V(IfEqStrictNumTOS, 0, ___, ___, ___) \ | |
| 362 V(CreateArrayTOS, 0, ___, ___, ___) \ | |
| 363 V(Allocate, D, lit, ___, ___) \ | |
| 364 V(AllocateT, 0, ___, ___, ___) \ | |
| 365 V(StoreIndexedTOS, 0, ___, ___, ___) \ | |
| 366 V(StoreField, A_B_C, reg, reg, reg) \ | |
| 367 V(StoreFieldTOS, D, num, ___, ___) \ | |
| 368 V(LoadField, A_B_C, reg, reg, reg) \ | |
| 369 V(LoadFieldTOS, D, num, ___, ___) \ | |
| 370 V(BooleanNegateTOS, 0, ___, ___, ___) \ | |
| 371 V(Throw, A, num, ___, ___) \ | |
| 372 V(Entry, A_B_C, num, num, num) \ | |
| 373 V(EntryOpt, A_B_C, num, num, num) \ | |
| 374 V(Frame, D, num, ___, ___) \ | |
| 375 V(SetFrame, A, num, ___, num) \ | |
| 376 V(AllocateContext, D, num, ___, ___) \ | |
| 377 V(CloneContext, 0, ___, ___, ___) \ | |
| 378 V(MoveSpecial, A_D, reg, num, ___) \ | |
| 379 V(InstantiateType, D, lit, ___, ___) \ | |
| 380 V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \ | |
| 381 V(AssertAssignable, D, num, lit, ___) \ | |
| 382 V(AssertBoolean, A, num, ___, ___) \ | |
| 383 V(CheckStack, 0, ___, ___, ___) \ | |
| 384 V(DebugStep, 0, ___, ___, ___) \ | |
| 385 V(DebugBreak, A, num, ___, ___) \ | |
| 386 | |
| 387 class Bytecode { | |
| 388 public: | |
| 389 enum Opcode { | |
| 390 #define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name, | |
| 391 BYTECODES_LIST(DECLARE_BYTECODE) | |
| 392 #undef DECLARE_BYTECODE | |
| 393 }; | |
| 394 | |
| 395 static uint32_t Encode(Opcode op, uintptr_t a, uintptr_t b, uintptr_t c) { | |
| 396 ASSERT((a & 0xFF) == a); | |
| 397 ASSERT((b & 0xFF) == b); | |
| 398 ASSERT((c & 0xFF) == c); | |
| 399 return op | (a << 8) | (b << 16) | (c << 24); | |
| 400 } | |
| 401 | |
| 402 static uint32_t Encode(Opcode op, uintptr_t a, uintptr_t d) { | |
| 403 ASSERT((a & 0x00FF) == a); | |
| 404 ASSERT((d & 0xFFFF) == d); | |
| 405 return op | (a << 8) | (d << 16); | |
| 406 } | |
| 407 | |
| 408 static uint32_t Encode(Opcode op, uint32_t abc) { | |
| 409 return op | (abc << 8); | |
| 410 } | |
| 411 | |
| 412 static uint32_t EncodeSigned(Opcode op, uintptr_t a, intptr_t x) { | |
| 413 ASSERT((a & 0x00FF) == a); | |
| 414 ASSERT((x << 16) >> 16 == x); | |
| 415 return op | (a << 8) | (x << 16); | |
| 416 } | |
| 417 | |
| 418 static uint32_t EncodeSigned(Opcode op, intptr_t x) { | |
| 419 ASSERT((x << 8) >> 8 == x); | |
| 420 return op | (x << 8); | |
| 421 } | |
| 422 | |
| 423 static uint32_t Encode(Opcode op) { | |
| 424 return op; | |
| 425 } | |
| 426 | |
| 427 DART_FORCE_INLINE static Opcode DecodeOpcode(uint32_t bc) { | |
| 428 return static_cast<Opcode>(bc & 0xFF); | |
| 429 } | |
| 430 | |
| 431 DART_FORCE_INLINE static uint8_t DecodeArgc(uint32_t call) { | |
| 432 #if defined(DEBUG) | |
| 433 const Opcode op = DecodeOpcode(call); | |
| 434 ASSERT(op == Bytecode::kStaticCall || | |
|
zra
2016/04/08 22:37:34
parens around each 'a == b'
Vyacheslav Egorov (Google)
2016/04/11 10:49:10
Done.
| |
| 435 op == Bytecode::kInstanceCall || | |
| 436 op == Bytecode::kInstanceCall2 || | |
| 437 op == Bytecode::kInstanceCall3 || | |
| 438 op == Bytecode::kDebugBreak); | |
| 439 #endif | |
| 440 return (call >> 8) & 0xFF; | |
| 441 } | |
| 442 }; | |
| 443 | |
| 444 // Various dummy declarations to make shared code compile. | |
| 445 // TODO(vegorov) we need to prune away as much dead code as possible instead | |
| 446 // of just making it compile. | |
| 447 typedef int16_t Register; | |
| 448 | |
| 449 const int16_t FPREG = 0; | |
| 450 const int16_t SPREG = 1; | |
| 451 const intptr_t kNumberOfCpuRegisters = 20; | |
| 452 const intptr_t kDartAvailableCpuRegs = 0; | |
| 453 const intptr_t kNoRegister = -1; | |
| 454 const intptr_t kReservedCpuRegisters = 0; | |
| 455 const intptr_t ARGS_DESC_REG = 0; | |
| 456 const intptr_t CODE_REG = 0; | |
| 457 const intptr_t kExceptionObjectReg = 0; | |
| 458 const intptr_t kStackTraceObjectReg = 0; | |
| 459 const intptr_t CTX = 0; | |
| 460 | |
| 461 enum FpuRegister { kNoFpuRegister = -1, kFakeFpuRegister }; | |
| 462 const FpuRegister FpuTMP = kFakeFpuRegister; | |
| 463 const intptr_t kNumberOfFpuRegisters = 1; | |
| 464 | |
| 465 enum Condition { EQ, NE }; | |
| 466 | |
| 467 class Instr { }; | |
| 468 | |
| 469 } // namespace dart | |
| 470 | |
| 471 #endif // VM_CONSTANTS_DBC_H_ | |
| OLD | NEW |