Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(487)

Side by Side Diff: pkg/fletchc/lib/src/bytecode_assembler.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/fletchc/lib/program_info.dart ('k') | pkg/fletchc/lib/src/class_debug_info.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino 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.md file.
4
5 library fletchc.bytecode_assembler;
6
7 import '../bytecodes.dart';
8
9 const int IMPLICIT_STACK_OVERFLOW_LIMIT = 32;
10 const int frameDescriptorSize = 3;
11
12 class BytecodeLabel {
13 int position = -1;
14 final List<int> usage = <int>[];
15
16 void addUsage(int bytecodePosition) {
17 usage.add(bytecodePosition);
18 }
19
20 void forEach(f(int index)) {
21 usage.forEach(f);
22 }
23
24 int get lastIndex {
25 if (usage.isEmpty) return -1;
26 return usage.last;
27 }
28
29 void removeLastUsage() {
30 usage.removeLast();
31 }
32
33 void bind(int value) {
34 position = value;
35 usage.clear();
36 }
37
38 bool get isBound => position != -1;
39
40 bool get isUsed => usage.isNotEmpty;
41 }
42
43 class BytecodeAssembler {
44 final List<Bytecode> bytecodes = <Bytecode>[];
45 final List<int> catchRanges = <int>[];
46
47 final int functionArity;
48
49 int byteSize = 0;
50 int stackSize = 0;
51 int maxStackSize = 0;
52
53 // A bind after a terminator will still look like the last bytecode
54 // is a terminator, however, due to the bind it's not.
55 bool hasBindAfterTerminator = false;
56
57 // A bind after a pop will still look like the last bytecode is a
58 // pop, however, due to the bind we cannot collapse more pops
59 // together.
60 bool hasBindAfterPop = false;
61
62 BytecodeAssembler(this.functionArity);
63
64 int computeParameterSlot(int parameter) {
65 assert(parameter >= 0 && parameter < functionArity);
66 return parameter - frameDescriptorSize - functionArity;
67 }
68
69 void reuse() {
70 bytecodes.clear();
71 catchRanges.clear();
72 byteSize = 0;
73 stackSize = 0;
74 maxStackSize = 0;
75 }
76
77 /**
78 * Apply a fix to the currently known stack size.
79 */
80 void applyStackSizeFix(int diff) {
81 stackSize += diff;
82 if (stackSize > maxStackSize) maxStackSize = stackSize;
83 }
84
85 void addCatchFrameRange(int start, int end) {
86 catchRanges
87 ..add(start)
88 ..add(end)
89 ..add(stackSize);
90 }
91
92 void loadConst(int id) {
93 internalAdd(new LoadConst(id));
94 }
95
96 void loadLocal(int offset) {
97 assert(offset < stackSize);
98 loadLocalHelper(offset);
99 }
100
101 void loadLocalHelper(int offset) {
102 assert(offset >= 0);
103 Bytecode bytecode;
104 switch (offset) {
105 case 0:
106 bytecode = const LoadLocal0();
107 break;
108 case 1:
109 bytecode = const LoadLocal1();
110 break;
111 case 2:
112 bytecode = const LoadLocal2();
113 break;
114 case 3:
115 bytecode = const LoadLocal3();
116 break;
117 case 4:
118 bytecode = const LoadLocal4();
119 break;
120 case 5:
121 bytecode = const LoadLocal5();
122 break;
123 default:
124 if (offset >= 256) {
125 bytecode = new LoadLocalWide(offset);
126 } else {
127 bytecode = new LoadLocal(offset);
128 }
129 break;
130 }
131 internalAdd(bytecode);
132 }
133
134 void loadBoxed(int offset) {
135 assert(offset < stackSize);
136 loadBoxedHelper(offset);
137 }
138
139 void loadBoxedHelper(int offset) {
140 assert(offset >= 0 && offset <= 255);
141 internalAdd(new LoadBoxed(offset));
142 }
143
144 void dup() {
145 loadLocal(0);
146 }
147
148 /**
149 * A 'slot' is an artificial indexing, that are frame relative. That means
150 * the current frame is indexed by where 0 .. frameSize-1, -1 is the return
151 * address and -1 - functionArity is the first argument, -2 is the last
152 * argument.
153 *
154 * This kind of indexing are sometimes easier to use than stack-relative,
155 * as locals and parameters have a fixed value.
156 */
157 void loadSlot(int slot) {
158 int offset = stackSize - slot - 1;
159 loadLocal(offset);
160 }
161
162 void loadBoxedSlot(int slot) {
163 int offset = stackSize - slot - 1;
164 loadBoxed(offset);
165 }
166
167 int computeParameterOffset(int parameter) {
168 return frameDescriptorSize + stackSize + functionArity - parameter - 1;
169 }
170
171 void loadParameter(int parameter) {
172 assert(parameter >= 0 && parameter < functionArity);
173 loadLocalHelper(computeParameterOffset(parameter));
174 }
175
176 void loadBoxedParameter(int parameter) {
177 assert(parameter >= 0 && parameter < functionArity);
178 loadBoxedHelper(computeParameterOffset(parameter));
179 }
180
181 void loadParameterSlot(int parameterSlot) {
182 int offset = stackSize - parameterSlot - 1;
183 loadLocalHelper(offset);
184 }
185
186 void loadBoxedParameterSlot(int parameterSlot) {
187 int offset = stackSize - parameterSlot - 1;
188 loadBoxedHelper(offset);
189 }
190
191 void loadStatic(int index) {
192 internalAdd(new LoadStatic(index));
193 }
194
195 void loadStaticInit(int index) {
196 internalAdd(new LoadStaticInit(index));
197 }
198
199 void loadField(int index) {
200 if (index >= 256) {
201 internalAdd(new LoadFieldWide(index));
202 } else {
203 internalAdd(new LoadField(index));
204 }
205 }
206
207 void loadLiteralNull() {
208 internalAdd(new LoadLiteralNull());
209 }
210
211 void loadLiteralTrue() {
212 internalAdd(new LoadLiteralTrue());
213 }
214
215 void loadLiteralFalse() {
216 internalAdd(new LoadLiteralFalse());
217 }
218
219 void loadLiteral(int value) {
220 if (value == 0) {
221 internalAdd(const LoadLiteral0());
222 } else if (value == 1) {
223 internalAdd(const LoadLiteral1());
224 } else if (value < 256) {
225 internalAdd(new LoadLiteral(value));
226 } else {
227 internalAdd(new LoadLiteralWide(value));
228 }
229 }
230
231 void storeLocal(int offset) {
232 assert(offset < stackSize);
233 storeLocalHelper(offset);
234 }
235
236 void storeLocalHelper(int offset) {
237 assert(offset >= 0 && offset <= 255);
238 internalAdd(new StoreLocal(offset));
239 }
240
241 void storeBoxed(int offset) {
242 assert(offset < stackSize);
243 storeBoxedHelper(offset);
244 }
245
246 void storeBoxedHelper(int offset) {
247 assert(offset >= 0 && offset <= 255);
248 internalAdd(new StoreBoxed(offset));
249 }
250
251 /**
252 * See loadSlot for information about 'slots'.
253 */
254 void storeSlot(int slot) {
255 int offset = stackSize - slot - 1;
256 storeLocal(offset);
257 }
258
259 void storeBoxedSlot(int slot) {
260 int offset = stackSize - slot - 1;
261 storeBoxed(offset);
262 }
263
264 void storeParameter(int parameter) {
265 assert(parameter >= 0 && parameter < functionArity);
266 storeLocalHelper(computeParameterOffset(parameter));
267 }
268
269 void storeBoxedParameter(int parameter) {
270 assert(parameter >= 0 && parameter < functionArity);
271 storeBoxedHelper(computeParameterOffset(parameter));
272 }
273
274 void storeParameterSlot(int parameterSlot) {
275 int offset = stackSize - parameterSlot - 1;
276 storeLocalHelper(offset);
277 }
278
279 void storeBoxedParameterSlot(int parameterSlot) {
280 int offset = stackSize - parameterSlot - 1;
281 storeBoxedHelper(offset);
282 }
283
284 void storeStatic(int index) {
285 internalAdd(new StoreStatic(index));
286 }
287
288 void storeField(int index) {
289 if (index >= 256) {
290 internalAdd(new StoreFieldWide(index));
291 } else {
292 internalAdd(new StoreField(index));
293 }
294 }
295
296 void invokeStatic(int id, int arity) {
297 internalAddStackPointerDifference(
298 new InvokeStatic(id),
299 1 - arity);
300 }
301
302 void invokeFactory(int id, int arity) {
303 internalAddStackPointerDifference(
304 new InvokeFactory(id),
305 1 - arity);
306 }
307
308 void invokeMethod(int selector, int arity, [String name]) {
309 var bytecode;
310 switch (name) {
311 case '==':
312 bytecode = new InvokeEqUnfold(selector);
313 break;
314
315 case '<':
316 bytecode = new InvokeLtUnfold(selector);
317 break;
318
319 case '<=':
320 bytecode = new InvokeLeUnfold(selector);
321 break;
322
323 case '>':
324 bytecode = new InvokeGtUnfold(selector);
325 break;
326
327 case '>=':
328 bytecode = new InvokeGeUnfold(selector);
329 break;
330
331 case '+':
332 bytecode = new InvokeAddUnfold(selector);
333 break;
334
335 case '-':
336 bytecode = new InvokeSubUnfold(selector);
337 break;
338
339 case '*':
340 bytecode = new InvokeMulUnfold(selector);
341 break;
342
343 case '~/':
344 bytecode = new InvokeTruncDivUnfold(selector);
345 break;
346
347 case '%':
348 bytecode = new InvokeModUnfold(selector);
349 break;
350
351 case '~':
352 bytecode = new InvokeBitNotUnfold(selector);
353 break;
354
355 case '&':
356 bytecode = new InvokeBitAndUnfold(selector);
357 break;
358
359 case '|':
360 bytecode = new InvokeBitOrUnfold(selector);
361 break;
362
363 case '^':
364 bytecode = new InvokeBitXorUnfold(selector);
365 break;
366
367 case '<<':
368 bytecode = new InvokeBitShlUnfold(selector);
369 break;
370
371 case '>>':
372 bytecode = new InvokeBitShrUnfold(selector);
373 break;
374
375 default:
376 bytecode = new InvokeMethodUnfold(selector);
377 break;
378 }
379 internalAddStackPointerDifference(bytecode, -arity);
380 }
381
382 void invokeTest(int selector, int arity) {
383 internalAddStackPointerDifference(new InvokeTestUnfold(selector), -arity);
384 }
385
386 void invokeSelector(int slot) {
387 internalAddStackPointerDifference(new InvokeSelector(slot), 0);
388 }
389
390 void pop() {
391 if (hasBindAfterPop) {
392 internalAdd(new Pop());
393 hasBindAfterPop = false;
394 return;
395 }
396 Bytecode last = bytecodes.last;
397 if (last.opcode == Opcode.Drop) {
398 Drop drop = last;
399 int amount = drop.uint8Argument0 + 1;
400 if (amount <= 255) {
401 bytecodes[bytecodes.length - 1] = new Drop(amount);
402 applyStackSizeFix(-1);
403 } else {
404 internalAdd(new Pop());
405 }
406 } else if (last.opcode == Opcode.Pop) {
407 bytecodes[bytecodes.length - 1] = new Drop(2);
408 byteSize += 1;
409 applyStackSizeFix(-1);
410 } else {
411 internalAdd(new Pop());
412 }
413
414 }
415
416 void popMany(int count) {
417 while (count > 255) {
418 internalAddStackPointerDifference(new Drop(255), -255);
419 count -= 255;
420 }
421 if (count > 1) {
422 internalAddStackPointerDifference(new Drop(count), -count);
423 } else if (count == 1) {
424 internalAdd(new Pop());
425 }
426 hasBindAfterPop = false;
427 }
428
429 void ret() {
430 hasBindAfterTerminator = false;
431 if (stackSize <= 0) throw "Bad stackSize for return bytecode: $stackSize";
432 internalAdd(const Return());
433 }
434
435 void returnNull() {
436 hasBindAfterTerminator = false;
437 internalAdd(const ReturnNull());
438 }
439
440 void identical() {
441 internalAdd(const Identical());
442 }
443
444 void identicalNonNumeric() {
445 internalAdd(const IdenticalNonNumeric());
446 }
447
448 void negate() {
449 internalAdd(const Negate());
450 }
451
452 void bind(BytecodeLabel label) {
453 internalBind(label, false);
454 }
455
456 void internalBind(BytecodeLabel label, bool isSubroutineReturn) {
457 if (label.isUsed) hasBindAfterTerminator = true;
458 hasBindAfterPop = true;
459 assert(label.position == -1);
460 // TODO(ajohnsen): If the previous bytecode is a branch to this label,
461 // consider popping it - if no other binds has happened at this bytecode
462 // index.
463 int position = byteSize;
464 label.forEach((int index) {
465 var bytecode = bytecodes[index];
466 switch (bytecode.opcode) {
467 case Opcode.BranchIfTrueWide:
468 int offset = position - bytecode.uint32Argument0;
469 bytecodes[index] = new BranchIfTrueWide(offset);
470 break;
471
472 case Opcode.BranchIfFalseWide:
473 int offset = position - bytecode.uint32Argument0;
474 bytecodes[index] = new BranchIfFalseWide(offset);
475 break;
476
477 case Opcode.BranchWide:
478 int offset = position - bytecode.uint32Argument0;
479 bytecodes[index] = new BranchWide(offset);
480 break;
481
482 case Opcode.PopAndBranchWide:
483 int offset = position - bytecode.uint32Argument1;
484 bytecodes[index] = new PopAndBranchWide(
485 bytecode.uint8Argument0,
486 offset);
487 break;
488
489 case Opcode.EnterNoSuchMethod:
490 int offset = position - bytecode.uint8Argument0;
491 bytecodes[index] = new EnterNoSuchMethod(offset);
492 break;
493
494 case Opcode.SubroutineCall:
495 if (isSubroutineReturn) {
496 int offset = position - bytecode.uint32Argument1;
497 offset -= bytecode.size;
498 bytecodes[index] = new SubroutineCall(
499 bytecode.uint32Argument0,
500 offset);
501 } else {
502 int offset = position - bytecode.uint32Argument0;
503 bytecodes[index] = new SubroutineCall(
504 offset,
505 bytecode.uint32Argument1);
506 }
507 break;
508
509 default:
510 throw "Unhandled bind bytecode: $bytecode";
511 }
512 });
513 label.bind(position);
514 }
515
516 void branchIfTrue(BytecodeLabel label) {
517 if (label.isBound) {
518 internalBranchBack(
519 label,
520 (v) => new BranchBackIfTrue(v),
521 (v) => new BranchBackIfTrueWide(v));
522 } else {
523 label.addUsage(bytecodes.length);
524 internalAdd(new BranchIfTrueWide(byteSize));
525 }
526 }
527
528 void branchIfFalse(BytecodeLabel label) {
529 if (label.isBound) {
530 internalBranchBack(
531 label,
532 (v) => new BranchBackIfFalse(v),
533 (v) => new BranchBackIfFalseWide(v));
534 } else {
535 label.addUsage(bytecodes.length);
536 internalAdd(new BranchIfFalseWide(byteSize));
537 }
538 }
539
540 void branch(BytecodeLabel label) {
541 if (label.isBound) {
542 internalBranchBack(
543 label,
544 (v) => new BranchBack(v),
545 (v) => new BranchBackWide(v));
546 } else {
547 label.addUsage(bytecodes.length);
548 internalAdd(new BranchWide(byteSize));
549 }
550 }
551
552 void popAndBranch(int diff, BytecodeLabel label) {
553 assert(diff >= 0 && diff <= 255);
554 if (label.isBound) {
555 internalBranchBack(
556 label,
557 (v) => new PopAndBranchBackWide(diff, v),
558 (v) => new PopAndBranchBackWide(diff, v));
559 } else {
560 label.addUsage(bytecodes.length);
561 internalAdd(new PopAndBranchWide(diff, byteSize));
562 }
563 }
564
565 void internalBranchBack(
566 BytecodeLabel label,
567 Bytecode short(int offset),
568 Bytecode long(int offset)) {
569 int offset = byteSize - label.position;
570 if (offset < 255) {
571 internalAdd(short(offset));
572 } else {
573 internalAdd(long(offset));
574 }
575 }
576
577 void allocate(int classId, int fields, {bool immutable: false}) {
578 var instruction = immutable ?
579 new AllocateImmutable(classId) : new Allocate(classId);
580 internalAddStackPointerDifference(instruction, 1 - fields);
581 }
582
583 void allocateBoxed() {
584 internalAdd(const AllocateBoxed());
585 }
586
587 void subroutineCall(BytecodeLabel label, BytecodeLabel returnLabel) {
588 assert(!label.isBound);
589 assert(!returnLabel.isBound);
590 label.addUsage(bytecodes.length);
591 returnLabel.addUsage(bytecodes.length);
592 internalAddStackPointerDifference(
593 new SubroutineCall(byteSize, byteSize),
594 0);
595 }
596
597 void subroutineReturn(BytecodeLabel returnLabel) {
598 internalBind(returnLabel, true);
599 internalAdd(const SubroutineReturn());
600 }
601
602 bool get endsWithTerminator {
603 if (bytecodes.isEmpty) return false;
604 if (hasBindAfterTerminator) return false;
605 Opcode opcode = bytecodes.last.opcode;
606 return opcode == Opcode.Return || opcode == Opcode.Throw;
607 }
608
609 void enterNoSuchMethod(BytecodeLabel skipGetterLabel) {
610 assert(!skipGetterLabel.isBound);
611 skipGetterLabel.addUsage(bytecodes.length);
612 internalAddStackPointerDifference(new EnterNoSuchMethod(byteSize), 0);
613 }
614
615 void exitNoSuchMethod() {
616 internalAdd(const ExitNoSuchMethod());
617 }
618
619 void methodEnd() {
620 if (maxStackSize > IMPLICIT_STACK_OVERFLOW_LIMIT) {
621 var bytecode = new StackOverflowCheck(
622 maxStackSize - IMPLICIT_STACK_OVERFLOW_LIMIT);
623 bytecodes.insert(0, bytecode);
624 byteSize += bytecode.size;
625 }
626 int value = (byteSize << 1) | (catchRanges.isNotEmpty ? 1 : 0);
627 internalAdd(new MethodEnd(value));
628 }
629
630 void processYield() {
631 internalAdd(const ProcessYield());
632 }
633
634 void coroutineChange() {
635 internalAdd(const CoroutineChange());
636 }
637
638 void internalAdd(Bytecode bytecode) {
639 internalAddStackPointerDifference(
640 bytecode,
641 bytecode.stackPointerDifference);
642 }
643
644 void internalAddStackPointerDifference(
645 Bytecode bytecode,
646 int stackPointerDifference) {
647 assert(stackPointerDifference != VAR_DIFF);
648 assert(bytecodes.isEmpty || bytecodes.last.opcode != Opcode.MethodEnd);
649 bytecodes.add(bytecode);
650 byteSize += bytecode.size;
651 applyStackSizeFix(stackPointerDifference);
652 }
653
654 void invokeNative(int arity, int index) {
655 internalAdd(new InvokeNative(arity, index));
656 }
657
658 void invokeDetachableNative(int arity, int index) {
659 internalAdd(new InvokeDetachableNative(arity, index));
660 }
661
662 void invokeNativeYield(int arity, int index) {
663 internalAdd(new InvokeNativeYield(arity, index));
664 }
665
666 void emitThrow() {
667 hasBindAfterTerminator = false;
668 internalAdd(const Throw());
669 }
670 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/program_info.dart ('k') | pkg/fletchc/lib/src/class_debug_info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698