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 current frame | |
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 signed 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 FP[rA] or push it onto the | |
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 | |
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 LoadConstant 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 // tgt jump target relative to the PC of the current instruction | |
325 // | |
326 // TODO(vegorov) jump targets should be encoded relative to PC of the next | |
327 // instruction because PC is incremeted immediately after fetch | |
328 // and before decoding. | |
329 // | |
330 #define BYTECODES_LIST(V) \ | |
zra
2016/04/14 18:27:47
Maybe DBC_BYTECODES_LIST.
Vyacheslav Egorov (Google)
2016/04/18 15:56:40
I think it's obvious that it's DBC bytecodes.
| |
331 V(Trap, 0, ___, ___, ___) \ | |
332 V(Compile, 0, ___, ___, ___) \ | |
333 V(Intrinsic, A, num, ___, ___) \ | |
334 V(Drop1, 0, ___, ___, ___) \ | |
335 V(DropR, A, num, ___, ___) \ | |
336 V(Drop, A, num, ___, ___) \ | |
337 V(Jump, T, tgt, ___, ___) \ | |
338 V(Return, A, num, ___, ___) \ | |
339 V(ReturnTOS, 0, ___, ___, ___) \ | |
340 V(Move, A_X, reg, xeg, ___) \ | |
341 V(Push, X, xeg, ___, ___) \ | |
342 V(LoadConstant, A_D, reg, lit, ___) \ | |
343 V(PushConstant, D, lit, ___, ___) \ | |
344 V(StoreLocal, X, xeg, ___, ___) \ | |
345 V(PopLocal, X, xeg, ___, ___) \ | |
346 V(StaticCall, A_D, num, num, ___) \ | |
347 V(InstanceCall, A_D, num, num, ___) \ | |
348 V(InstanceCall2, A_D, num, num, ___) \ | |
349 V(InstanceCall3, A_D, num, num, ___) \ | |
350 V(NativeCall, 0, ___, ___, ___) \ | |
351 V(NativeBootstrapCall, 0, ___, ___, ___) \ | |
352 V(AddTOS, 0, ___, ___, ___) \ | |
353 V(SubTOS, 0, ___, ___, ___) \ | |
354 V(MulTOS, 0, ___, ___, ___) \ | |
355 V(BitOrTOS, 0, ___, ___, ___) \ | |
356 V(BitAndTOS, 0, ___, ___, ___) \ | |
357 V(EqualTOS, 0, ___, ___, ___) \ | |
358 V(LessThanTOS, 0, ___, ___, ___) \ | |
359 V(GreaterThanTOS, 0, ___, ___, ___) \ | |
360 V(StoreStaticTOS, D, lit, ___, ___) \ | |
361 V(PushStatic, D, lit, ___, ___) \ | |
362 V(InitStaticTOS, 0, ___, ___, ___) \ | |
363 V(IfNeStrictTOS, 0, ___, ___, ___) \ | |
364 V(IfEqStrictTOS, 0, ___, ___, ___) \ | |
365 V(IfNeStrictNumTOS, 0, ___, ___, ___) \ | |
366 V(IfEqStrictNumTOS, 0, ___, ___, ___) \ | |
367 V(CreateArrayTOS, 0, ___, ___, ___) \ | |
368 V(Allocate, D, lit, ___, ___) \ | |
369 V(AllocateT, 0, ___, ___, ___) \ | |
370 V(StoreIndexedTOS, 0, ___, ___, ___) \ | |
371 V(StoreField, A_B_C, reg, reg, reg) \ | |
372 V(StoreFieldTOS, D, num, ___, ___) \ | |
373 V(LoadField, A_B_C, reg, reg, reg) \ | |
374 V(LoadFieldTOS, D, num, ___, ___) \ | |
375 V(BooleanNegateTOS, 0, ___, ___, ___) \ | |
376 V(Throw, A, num, ___, ___) \ | |
377 V(Entry, A_B_C, num, num, num) \ | |
378 V(EntryOpt, A_B_C, num, num, num) \ | |
379 V(Frame, D, num, ___, ___) \ | |
380 V(SetFrame, A, num, ___, num) \ | |
381 V(AllocateContext, D, num, ___, ___) \ | |
382 V(CloneContext, 0, ___, ___, ___) \ | |
383 V(MoveSpecial, A_D, reg, num, ___) \ | |
384 V(InstantiateType, D, lit, ___, ___) \ | |
385 V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \ | |
386 V(AssertAssignable, D, num, lit, ___) \ | |
387 V(AssertBoolean, A, num, ___, ___) \ | |
388 V(CheckStack, 0, ___, ___, ___) \ | |
389 V(DebugStep, 0, ___, ___, ___) \ | |
390 V(DebugBreak, A, num, ___, ___) \ | |
391 | |
392 typedef uint32_t Instr; | |
393 | |
394 class Bytecode { | |
395 public: | |
396 enum Opcode { | |
397 #define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name, | |
398 BYTECODES_LIST(DECLARE_BYTECODE) | |
399 #undef DECLARE_BYTECODE | |
400 }; | |
401 | |
402 static Instr Encode(Opcode op, uintptr_t a, uintptr_t b, uintptr_t c) { | |
403 ASSERT((a & 0xFF) == a); | |
404 ASSERT((b & 0xFF) == b); | |
405 ASSERT((c & 0xFF) == c); | |
406 return op | (a << 8) | (b << 16) | (c << 24); | |
407 } | |
408 | |
409 static Instr Encode(Opcode op, uintptr_t a, uintptr_t d) { | |
410 ASSERT((a & 0x00FF) == a); | |
411 ASSERT((d & 0xFFFF) == d); | |
412 return op | (a << 8) | (d << 16); | |
413 } | |
414 | |
415 static Instr EncodeSigned(Opcode op, uintptr_t a, intptr_t x) { | |
416 ASSERT((a & 0x00FF) == a); | |
417 ASSERT((x << 16) >> 16 == x); | |
418 return op | (a << 8) | (x << 16); | |
419 } | |
420 | |
421 static Instr EncodeSigned(Opcode op, intptr_t x) { | |
422 ASSERT((x << 8) >> 8 == x); | |
423 return op | (x << 8); | |
424 } | |
425 | |
426 static Instr Encode(Opcode op) { | |
427 return op; | |
428 } | |
429 | |
430 DART_FORCE_INLINE static Opcode DecodeOpcode(Instr bc) { | |
431 return static_cast<Opcode>(bc & 0xFF); | |
432 } | |
433 | |
434 DART_FORCE_INLINE static uint8_t DecodeArgc(Instr call) { | |
435 #if defined(DEBUG) | |
436 const Opcode op = DecodeOpcode(call); | |
437 ASSERT((op == Bytecode::kStaticCall) || | |
438 (op == Bytecode::kInstanceCall) || | |
439 (op == Bytecode::kInstanceCall2) || | |
440 (op == Bytecode::kInstanceCall3) || | |
441 (op == Bytecode::kDebugBreak)); | |
442 #endif | |
443 return (call >> 8) & 0xFF; | |
444 } | |
445 }; | |
446 | |
447 // Various dummy declarations to make shared code compile. | |
448 // TODO(vegorov) we need to prune away as much dead code as possible instead | |
449 // of just making it compile. | |
450 typedef int16_t Register; | |
451 | |
452 const int16_t FPREG = 0; | |
453 const int16_t SPREG = 1; | |
454 const intptr_t kNumberOfCpuRegisters = 20; | |
455 const intptr_t kDartAvailableCpuRegs = 0; | |
456 const intptr_t kNoRegister = -1; | |
457 const intptr_t kReservedCpuRegisters = 0; | |
458 const intptr_t ARGS_DESC_REG = 0; | |
459 const intptr_t CODE_REG = 0; | |
460 const intptr_t kExceptionObjectReg = 0; | |
461 const intptr_t kStackTraceObjectReg = 0; | |
462 const intptr_t CTX = 0; | |
463 | |
464 enum FpuRegister { kNoFpuRegister = -1, kFakeFpuRegister }; | |
465 const FpuRegister FpuTMP = kFakeFpuRegister; | |
466 const intptr_t kNumberOfFpuRegisters = 1; | |
467 | |
468 enum Condition { EQ, NE }; | |
469 | |
470 } // namespace dart | |
471 | |
472 #endif // VM_CONSTANTS_DBC_H_ | |
OLD | NEW |