1 // [AsmJit]
2 // Machine Code Generation for C++.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6
7 #define ASMJIT_EXPORTS
8
9 #include "../core/build.h"
10 #ifndef ASMJIT_NO_BUILDER
11
12 #include "../core/builder.h"
13 #include "../core/logging.h"
14 #include "../core/support.h"
15
16 ASMJIT_BEGIN_NAMESPACE
17
18 // ============================================================================
19 // [asmjit::PostponedErrorHandler (Internal)]
20 // ============================================================================
21
22 //! Postponed error handler that never throws. Used as a temporal error handler
23 //! to run passes. If error occurs, the caller is notified and will call the
24 //! real error handler, that can throw.
25 class PostponedErrorHandler : public ErrorHandler {
26 public:
handleError(Error err,const char * message,BaseEmitter * origin)27 void handleError(Error err, const char* message, BaseEmitter* origin) override {
28 ASMJIT_UNUSED(err);
29 ASMJIT_UNUSED(origin);
30
31 _message.assignString(message);
32 }
33
34 StringTmp<128> _message;
35 };
36
37 // ============================================================================
38 // [asmjit::BaseBuilder - Construction / Destruction]
39 // ============================================================================
40
BaseBuilder()41 BaseBuilder::BaseBuilder() noexcept
42 : BaseEmitter(kTypeBuilder),
43 _codeZone(32768 - Zone::kBlockOverhead),
44 _dataZone(16384 - Zone::kBlockOverhead),
45 _passZone(65536 - Zone::kBlockOverhead),
46 _allocator(&_codeZone),
47 _passes(),
48 _labelNodes(),
49 _cursor(nullptr),
50 _firstNode(nullptr),
51 _lastNode(nullptr),
52 _nodeFlags(0) {}
~BaseBuilder()53 BaseBuilder::~BaseBuilder() noexcept {}
54
55 // ============================================================================
56 // [asmjit::BaseBuilder - Node Management]
57 // ============================================================================
58
newLabelNode()59 LabelNode* BaseBuilder::newLabelNode() noexcept {
60 LabelNode* node = newNodeT<LabelNode>();
61 if (!node || registerLabelNode(node) != kErrorOk)
62 return nullptr;
63 return node;
64 }
65
newAlignNode(uint32_t alignMode,uint32_t alignment)66 AlignNode* BaseBuilder::newAlignNode(uint32_t alignMode, uint32_t alignment) noexcept {
67 return newNodeT<AlignNode>(alignMode, alignment);
68 }
69
newEmbedDataNode(const void * data,uint32_t size)70 EmbedDataNode* BaseBuilder::newEmbedDataNode(const void* data, uint32_t size) noexcept {
71 if (size > EmbedDataNode::kInlineBufferSize) {
72 void* cloned = _dataZone.alloc(size);
73 if (ASMJIT_UNLIKELY(!cloned))
74 return nullptr;
75
76 if (data)
77 memcpy(cloned, data, size);
78 data = cloned;
79 }
80
81 return newNodeT<EmbedDataNode>(const_cast<void*>(data), size);
82 }
83
newConstPoolNode()84 ConstPoolNode* BaseBuilder::newConstPoolNode() noexcept {
85 ConstPoolNode* node = newNodeT<ConstPoolNode>();
86 if (!node || registerLabelNode(node) != kErrorOk)
87 return nullptr;
88 return node;
89 }
90
newCommentNode(const char * data,size_t size)91 CommentNode* BaseBuilder::newCommentNode(const char* data, size_t size) noexcept {
92 if (data) {
93 if (size == SIZE_MAX)
94 size = strlen(data);
95
96 if (size > 0) {
97 data = static_cast<char*>(_dataZone.dup(data, size, true));
98 if (!data) return nullptr;
99 }
100 }
101
102 return newNodeT<CommentNode>(data);
103 }
104
newInstNode(uint32_t instId,uint32_t instOptions,const Operand_ & o0)105 InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0) noexcept {
106 uint32_t opCount = 1;
107 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
108 ASMJIT_ASSERT(opCapacity >= 4);
109
110 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
111 if (ASMJIT_UNLIKELY(!node))
112 return nullptr;
113
114 node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
115 node->setOp(0, o0);
116 for (uint32_t i = opCount; i < opCapacity; i++) node->resetOp(i);
117 return node;
118 }
119
newInstNode(uint32_t instId,uint32_t instOptions,const Operand_ & o0,const Operand_ & o1)120 InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1) noexcept {
121 uint32_t opCount = 2;
122 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
123 ASMJIT_ASSERT(opCapacity >= 4);
124
125 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
126 if (ASMJIT_UNLIKELY(!node))
127 return nullptr;
128
129 node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
130 node->setOp(0, o0);
131 node->setOp(1, o1);
132 for (uint32_t i = opCount; i < opCapacity; i++) node->resetOp(i);
133 return node;
134 }
135
newInstNode(uint32_t instId,uint32_t instOptions,const Operand_ & o0,const Operand_ & o1,const Operand_ & o2)136 InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept {
137 uint32_t opCount = 3;
138 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
139 ASMJIT_ASSERT(opCapacity >= 4);
140
141 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
142 if (ASMJIT_UNLIKELY(!node))
143 return nullptr;
144
145 node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
146 node->setOp(0, o0);
147 node->setOp(1, o1);
148 node->setOp(2, o2);
149 for (uint32_t i = opCount; i < opCapacity; i++) node->resetOp(i);
150 return node;
151 }
152
newInstNode(uint32_t instId,uint32_t instOptions,const Operand_ & o0,const Operand_ & o1,const Operand_ & o2,const Operand_ & o3)153 InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept {
154 uint32_t opCount = 4;
155 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
156 ASMJIT_ASSERT(opCapacity >= 4);
157
158 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
159 if (ASMJIT_UNLIKELY(!node))
160 return nullptr;
161
162 node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
163 node->setOp(0, o0);
164 node->setOp(1, o1);
165 node->setOp(2, o2);
166 node->setOp(3, o3);
167 for (uint32_t i = opCount; i < opCapacity; i++) node->resetOp(i);
168 return node;
169 }
170
newInstNodeRaw(uint32_t instId,uint32_t instOptions,uint32_t opCount)171 InstNode* BaseBuilder::newInstNodeRaw(uint32_t instId, uint32_t instOptions, uint32_t opCount) noexcept {
172 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
173 ASMJIT_ASSERT(opCapacity >= 4);
174
175 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
176 if (ASMJIT_UNLIKELY(!node))
177 return nullptr;
178 return new(node) InstNode(this, instId, instOptions, opCount, opCapacity);
179 }
180
addNode(BaseNode * node)181 BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept {
182 ASMJIT_ASSERT(node);
183 ASMJIT_ASSERT(!node->_prev);
184 ASMJIT_ASSERT(!node->_next);
185 ASMJIT_ASSERT(!node->isActive());
186
187 if (!_cursor) {
188 if (!_firstNode) {
189 _firstNode = node;
190 _lastNode = node;
191 }
192 else {
193 node->_next = _firstNode;
194 _firstNode->_prev = node;
195 _firstNode = node;
196 }
197 }
198 else {
199 BaseNode* prev = _cursor;
200 BaseNode* next = _cursor->next();
201
202 node->_prev = prev;
203 node->_next = next;
204
205 prev->_next = node;
206 if (next)
207 next->_prev = node;
208 else
209 _lastNode = node;
210 }
211
212 node->addFlags(BaseNode::kFlagIsActive);
213 if (node->isSection())
214 _dirtySectionLinks = true;
215
216 _cursor = node;
217 return node;
218 }
219
addAfter(BaseNode * node,BaseNode * ref)220 BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept {
221 ASMJIT_ASSERT(node);
222 ASMJIT_ASSERT(ref);
223
224 ASMJIT_ASSERT(!node->_prev);
225 ASMJIT_ASSERT(!node->_next);
226
227 BaseNode* prev = ref;
228 BaseNode* next = ref->next();
229
230 node->_prev = prev;
231 node->_next = next;
232
233 node->addFlags(BaseNode::kFlagIsActive);
234 if (node->isSection())
235 _dirtySectionLinks = true;
236
237 prev->_next = node;
238 if (next)
239 next->_prev = node;
240 else
241 _lastNode = node;
242
243 return node;
244 }
245
addBefore(BaseNode * node,BaseNode * ref)246 BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept {
247 ASMJIT_ASSERT(node != nullptr);
248 ASMJIT_ASSERT(!node->_prev);
249 ASMJIT_ASSERT(!node->_next);
250 ASMJIT_ASSERT(!node->isActive());
251 ASMJIT_ASSERT(ref != nullptr);
252 ASMJIT_ASSERT(ref->isActive());
253
254 BaseNode* prev = ref->prev();
255 BaseNode* next = ref;
256
257 node->_prev = prev;
258 node->_next = next;
259
260 node->addFlags(BaseNode::kFlagIsActive);
261 if (node->isSection())
262 _dirtySectionLinks = true;
263
264 next->_prev = node;
265 if (prev)
266 prev->_next = node;
267 else
268 _firstNode = node;
269
270 return node;
271 }
272
removeNode(BaseNode * node)273 BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept {
274 if (!node->isActive())
275 return node;
276
277 BaseNode* prev = node->prev();
278 BaseNode* next = node->next();
279
280 if (_firstNode == node)
281 _firstNode = next;
282 else
283 prev->_next = next;
284
285 if (_lastNode == node)
286 _lastNode = prev;
287 else
288 next->_prev = prev;
289
290 node->_prev = nullptr;
291 node->_next = nullptr;
292 node->clearFlags(BaseNode::kFlagIsActive);
293 if (node->isSection())
294 _dirtySectionLinks = true;
295
296 if (_cursor == node)
297 _cursor = prev;
298
299 return node;
300 }
301
removeNodes(BaseNode * first,BaseNode * last)302 void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept {
303 if (first == last) {
304 removeNode(first);
305 return;
306 }
307
308 if (!first->isActive())
309 return;
310
311 BaseNode* prev = first->prev();
312 BaseNode* next = last->next();
313
314 if (_firstNode == first)
315 _firstNode = next;
316 else
317 prev->_next = next;
318
319 if (_lastNode == last)
320 _lastNode = prev;
321 else
322 next->_prev = prev;
323
324 BaseNode* node = first;
325 uint32_t didRemoveSection = false;
326
327 for (;;) {
328 next = node->next();
329 ASMJIT_ASSERT(next != nullptr);
330
331 node->_prev = nullptr;
332 node->_next = nullptr;
333 node->clearFlags(BaseNode::kFlagIsActive);
334 didRemoveSection |= uint32_t(node->isSection());
335
336 if (_cursor == node)
337 _cursor = prev;
338
339 if (node == last)
340 break;
341 node = next;
342 }
343
344 if (didRemoveSection)
345 _dirtySectionLinks = true;
346 }
347
setCursor(BaseNode * node)348 BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept {
349 BaseNode* old = _cursor;
350 _cursor = node;
351 return old;
352 }
353
354 // ============================================================================
355 // [asmjit::BaseBuilder - Section]
356 // ============================================================================
357
sectionNodeOf(SectionNode ** pOut,uint32_t sectionId)358 Error BaseBuilder::sectionNodeOf(SectionNode** pOut, uint32_t sectionId) noexcept {
359 if (ASMJIT_UNLIKELY(!_code))
360 return DebugUtils::errored(kErrorNotInitialized);
361
362 if (ASMJIT_UNLIKELY(!_code->isSectionValid(sectionId)))
363 return DebugUtils::errored(kErrorInvalidSection);
364
365 if (sectionId >= _sectionNodes.size())
366 ASMJIT_PROPAGATE(_sectionNodes.resize(&_allocator, sectionId + 1));
367
368 SectionNode* node = _sectionNodes[sectionId];
369 if (!node) {
370 node = newNodeT<SectionNode>(sectionId);
371 if (ASMJIT_UNLIKELY(!node))
372 return DebugUtils::errored(kErrorOutOfMemory);
373 _sectionNodes[sectionId] = node;
374 }
375
376 *pOut = node;
377 return kErrorOk;
378 }
379
section(Section * section)380 Error BaseBuilder::section(Section* section) {
381 SectionNode* node;
382 Error err = sectionNodeOf(&node, section->id());
383
384 if (ASMJIT_UNLIKELY(err))
385 return reportError(err);
386
387 if (!node->isActive()) {
388 // Insert the section at the end if it was not part of the code.
389 addAfter(node, lastNode());
390 _cursor = node;
391 }
392 else {
393 // This is a bit tricky. We cache section links to make sure that
394 // switching sections doesn't involve traversal in linked-list unless
395 // the position of the section has changed.
396 if (hasDirtySectionLinks())
397 updateSectionLinks();
398
399 if (node->_nextSection)
400 _cursor = node->_nextSection->_prev;
401 else
402 _cursor = _lastNode;
403 }
404
405 return kErrorOk;
406 }
407
updateSectionLinks()408 void BaseBuilder::updateSectionLinks() noexcept {
409 if (!_dirtySectionLinks)
410 return;
411
412 BaseNode* node_ = _firstNode;
413 SectionNode* currentSection = nullptr;
414
415 while (node_) {
416 if (node_->isSection()) {
417 if (currentSection)
418 currentSection->_nextSection = node_->as<SectionNode>();
419 currentSection = node_->as<SectionNode>();
420 }
421 node_ = node_->next();
422 }
423
424 if (currentSection)
425 currentSection->_nextSection = nullptr;
426
427 _dirtySectionLinks = false;
428 }
429
430 // ============================================================================
431 // [asmjit::BaseBuilder - Labels]
432 // ============================================================================
433
labelNodeOf(LabelNode ** pOut,uint32_t labelId)434 Error BaseBuilder::labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept {
435 if (ASMJIT_UNLIKELY(!_code))
436 return DebugUtils::errored(kErrorNotInitialized);
437
438 uint32_t index = labelId;
439 if (ASMJIT_UNLIKELY(index >= _code->labelCount()))
440 return DebugUtils::errored(kErrorInvalidLabel);
441
442 if (index >= _labelNodes.size())
443 ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, index + 1));
444
445 LabelNode* node = _labelNodes[index];
446 if (!node) {
447 node = newNodeT<LabelNode>(labelId);
448 if (ASMJIT_UNLIKELY(!node))
449 return DebugUtils::errored(kErrorOutOfMemory);
450 _labelNodes[index] = node;
451 }
452
453 *pOut = node;
454 return kErrorOk;
455 }
456
registerLabelNode(LabelNode * node)457 Error BaseBuilder::registerLabelNode(LabelNode* node) noexcept {
458 if (ASMJIT_UNLIKELY(!_code))
459 return DebugUtils::errored(kErrorNotInitialized);
460
461 // Don't call `reportError()` from here, we are noexcept and we are called
462 // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well.
463 LabelEntry* le;
464 ASMJIT_PROPAGATE(_code->newLabelEntry(&le));
465 uint32_t labelId = le->id();
466
467 // We just added one label so it must be true.
468 ASMJIT_ASSERT(_labelNodes.size() < labelId + 1);
469 ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, labelId + 1));
470
471 _labelNodes[labelId] = node;
472 node->_id = labelId;
473
474 return kErrorOk;
475 }
476
BaseBuilder_newLabelInternal(BaseBuilder * self,uint32_t labelId)477 static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) noexcept {
478 ASMJIT_ASSERT(self->_labelNodes.size() < labelId + 1);
479 LabelNode* node = self->newNodeT<LabelNode>(labelId);
480
481 if (ASMJIT_UNLIKELY(!node))
482 return DebugUtils::errored(kErrorOutOfMemory);
483
484 ASMJIT_PROPAGATE(self->_labelNodes.resize(&self->_allocator, labelId + 1));
485 self->_labelNodes[labelId] = node;
486 node->_id = labelId;
487 return kErrorOk;
488 }
489
newLabel()490 Label BaseBuilder::newLabel() {
491 uint32_t labelId = Globals::kInvalidId;
492 if (_code) {
493 LabelEntry* le;
494 Error err = _code->newLabelEntry(&le);
495 if (ASMJIT_UNLIKELY(err)) {
496 reportError(err);
497 }
498 else {
499 err = BaseBuilder_newLabelInternal(this, le->id());
500 if (ASMJIT_UNLIKELY(err))
501 reportError(err);
502 else
503 labelId = le->id();
504 }
505 }
506 return Label(labelId);
507 }
508
newNamedLabel(const char * name,size_t nameSize,uint32_t type,uint32_t parentId)509 Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) {
510 uint32_t labelId = Globals::kInvalidId;
511 if (_code) {
512 LabelEntry* le;
513 Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId);
514 if (ASMJIT_UNLIKELY(err)) {
515 reportError(err);
516 }
517 else {
518 err = BaseBuilder_newLabelInternal(this, le->id());
519 if (ASMJIT_UNLIKELY(err))
520 reportError(err);
521 else
522 labelId = le->id();
523 }
524 }
525 return Label(labelId);
526 }
527
bind(const Label & label)528 Error BaseBuilder::bind(const Label& label) {
529 LabelNode* node;
530 Error err = labelNodeOf(&node, label);
531
532 if (ASMJIT_UNLIKELY(err))
533 return reportError(err);
534
535 addNode(node);
536 return kErrorOk;
537 }
538
539 // ============================================================================
540 // [asmjit::BaseBuilder - Passes]
541 // ============================================================================
542
passByName(const char * name) const543 ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept {
544 for (Pass* pass : _passes)
545 if (strcmp(pass->name(), name) == 0)
546 return pass;
547 return nullptr;
548 }
549
addPass(Pass * pass)550 ASMJIT_FAVOR_SIZE Error BaseBuilder::addPass(Pass* pass) noexcept {
551 if (ASMJIT_UNLIKELY(!_code))
552 return DebugUtils::errored(kErrorNotInitialized);
553
554 if (ASMJIT_UNLIKELY(pass == nullptr)) {
555 // Since this is directly called by `addPassT()` we treat `null` argument
556 // as out-of-memory condition. Otherwise it would be API misuse.
557 return DebugUtils::errored(kErrorOutOfMemory);
558 }
559 else if (ASMJIT_UNLIKELY(pass->_cb)) {
560 // Kinda weird, but okay...
561 if (pass->_cb == this)
562 return kErrorOk;
563 return DebugUtils::errored(kErrorInvalidState);
564 }
565
566 ASMJIT_PROPAGATE(_passes.append(&_allocator, pass));
567 pass->_cb = this;
568 return kErrorOk;
569 }
570
deletePass(Pass * pass)571 ASMJIT_FAVOR_SIZE Error BaseBuilder::deletePass(Pass* pass) noexcept {
572 if (ASMJIT_UNLIKELY(!_code))
573 return DebugUtils::errored(kErrorNotInitialized);
574
575 if (ASMJIT_UNLIKELY(pass == nullptr))
576 return DebugUtils::errored(kErrorInvalidArgument);
577
578 if (pass->_cb != nullptr) {
579 if (pass->_cb != this)
580 return DebugUtils::errored(kErrorInvalidState);
581
582 uint32_t index = _passes.indexOf(pass);
583 ASMJIT_ASSERT(index != Globals::kNotFound);
584
585 pass->_cb = nullptr;
586 _passes.removeAt(index);
587 }
588
589 pass->~Pass();
590 return kErrorOk;
591 }
592
runPasses()593 Error BaseBuilder::runPasses() {
594 if (ASMJIT_UNLIKELY(!_code))
595 return DebugUtils::errored(kErrorNotInitialized);
596
597 if (_passes.empty())
598 return kErrorOk;
599
600 Logger* logger = code()->logger();
601 ErrorHandler* prev = errorHandler();
602 PostponedErrorHandler postponed;
603
604 Error err = kErrorOk;
605 setErrorHandler(&postponed);
606
607 for (Pass* pass : _passes) {
608 _passZone.reset();
609 err = pass->run(&_passZone, logger);
610 if (err) break;
611 }
612 _passZone.reset();
613 setErrorHandler(prev);
614
615 if (ASMJIT_UNLIKELY(err))
616 return reportError(err, !postponed._message.empty() ? postponed._message.data() : nullptr);
617
618 return kErrorOk;
619 }
620
621 // ============================================================================
622 // [asmjit::BaseBuilder - Emit]
623 // ============================================================================
624
_emit(uint32_t instId,const Operand_ & o0,const Operand_ & o1,const Operand_ & o2,const Operand_ & o3)625 Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
626 uint32_t opCount = 4;
627
628 if (o3.isNone()) {
629 opCount = 3;
630 if (o2.isNone()) {
631 opCount = 2;
632 if (o1.isNone()) {
633 opCount = 1;
634 if (o0.isNone())
635 opCount = 0;
636 }
637 }
638 }
639
640 uint32_t options = instOptions() | globalInstOptions();
641 if (options & BaseInst::kOptionReserved) {
642 if (ASMJIT_UNLIKELY(!_code))
643 return DebugUtils::errored(kErrorNotInitialized);
644
645 // Strict validation.
646 #ifndef ASMJIT_NO_VALIDATION
647 if (hasEmitterOption(kOptionStrictValidation)) {
648 Operand_ opArray[4];
649 opArray[0].copyFrom(o0);
650 opArray[1].copyFrom(o1);
651 opArray[2].copyFrom(o2);
652 opArray[3].copyFrom(o3);
653
654 Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount);
655 if (ASMJIT_UNLIKELY(err)) {
656 resetInstOptions();
657 resetExtraReg();
658 resetInlineComment();
659 return reportError(err);
660 }
661 }
662 #endif
663
664 // Clear options that should never be part of `InstNode`.
665 options &= ~BaseInst::kOptionReserved;
666 }
667
668 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
669 ASMJIT_ASSERT(opCapacity >= 4);
670
671 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
672 if (ASMJIT_UNLIKELY(!node)) {
673 resetInstOptions();
674 resetExtraReg();
675 resetInlineComment();
676 return reportError(DebugUtils::errored(kErrorOutOfMemory));
677 }
678
679 node = new(node) InstNode(this, instId, options, opCount, opCapacity);
680 node->setExtraReg(extraReg());
681 node->setOp(0, o0);
682 node->setOp(1, o1);
683 node->setOp(2, o2);
684 node->setOp(3, o3);
685
686 for (uint32_t i = 4; i < InstNode::kBaseOpCapacity; i++)
687 node->resetOp(i);
688
689 const char* comment = inlineComment();
690 if (comment)
691 node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true)));
692
693 resetInstOptions();
694 resetExtraReg();
695 resetInlineComment();
696
697 addNode(node);
698 return kErrorOk;
699 }
700
_emit(uint32_t instId,const Operand_ & o0,const Operand_ & o1,const Operand_ & o2,const Operand_ & o3,const Operand_ & o4,const Operand_ & o5)701 Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
702 uint32_t opCount = Globals::kMaxOpCount;
703 if (o5.isNone()) {
704 opCount = 5;
705 if (o4.isNone())
706 return _emit(instId, o0, o1, o2, o3);
707 }
708
709 uint32_t options = instOptions() | globalInstOptions();
710 if (ASMJIT_UNLIKELY(options & BaseInst::kOptionReserved)) {
711 if (ASMJIT_UNLIKELY(!_code))
712 return DebugUtils::errored(kErrorNotInitialized);
713
714 // Strict validation.
715 #ifndef ASMJIT_NO_VALIDATION
716 if (hasEmitterOption(kOptionStrictValidation)) {
717 Operand_ opArray[Globals::kMaxOpCount];
718 opArray[0].copyFrom(o0);
719 opArray[1].copyFrom(o1);
720 opArray[2].copyFrom(o2);
721 opArray[3].copyFrom(o3);
722 opArray[4].copyFrom(o4);
723 opArray[5].copyFrom(o5);
724
725 Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount);
726 if (ASMJIT_UNLIKELY(err)) {
727 resetInstOptions();
728 resetExtraReg();
729 resetInlineComment();
730 return reportError(err);
731 }
732 }
733 #endif
734
735 // Clear options that should never be part of `InstNode`.
736 options &= ~BaseInst::kOptionReserved;
737 }
738
739 uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
740 ASMJIT_ASSERT(opCapacity >= opCount);
741
742 InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
743 if (ASMJIT_UNLIKELY(!node)) {
744 resetInstOptions();
745 resetExtraReg();
746 resetInlineComment();
747 return reportError(DebugUtils::errored(kErrorOutOfMemory));
748 }
749
750 node = new(node) InstNode(this, instId, options, opCount, opCapacity);
751 node->setExtraReg(extraReg());
752 node->setOp(0, o0);
753 node->setOp(1, o1);
754 node->setOp(2, o2);
755 node->setOp(3, o3);
756 node->setOp(4, o4);
757
758 if (opCapacity > 5)
759 node->setOp(5, o5);
760
761 const char* comment = inlineComment();
762 if (comment)
763 node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true)));
764
765 resetInstOptions();
766 resetExtraReg();
767 resetInlineComment();
768
769 addNode(node);
770 return kErrorOk;
771 }
772
773 // ============================================================================
774 // [asmjit::BaseBuilder - Align]
775 // ============================================================================
776
align(uint32_t alignMode,uint32_t alignment)777 Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) {
778 if (ASMJIT_UNLIKELY(!_code))
779 return DebugUtils::errored(kErrorNotInitialized);
780
781 AlignNode* node = newAlignNode(alignMode, alignment);
782 if (ASMJIT_UNLIKELY(!node))
783 return reportError(DebugUtils::errored(kErrorOutOfMemory));
784
785 addNode(node);
786 return kErrorOk;
787 }
788
789 // ============================================================================
790 // [asmjit::BaseBuilder - Embed]
791 // ============================================================================
792
embed(const void * data,uint32_t dataSize)793 Error BaseBuilder::embed(const void* data, uint32_t dataSize) {
794 if (ASMJIT_UNLIKELY(!_code))
795 return DebugUtils::errored(kErrorNotInitialized);
796
797 EmbedDataNode* node = newEmbedDataNode(data, dataSize);
798 if (ASMJIT_UNLIKELY(!node))
799 return reportError(DebugUtils::errored(kErrorOutOfMemory));
800
801 addNode(node);
802 return kErrorOk;
803 }
804
embedLabel(const Label & label)805 Error BaseBuilder::embedLabel(const Label& label) {
806 if (ASMJIT_UNLIKELY(!_code))
807 return DebugUtils::errored(kErrorNotInitialized);
808
809 EmbedLabelNode* node = newNodeT<EmbedLabelNode>(label.id());
810 if (ASMJIT_UNLIKELY(!node))
811 return reportError(DebugUtils::errored(kErrorOutOfMemory));
812
813 addNode(node);
814 return kErrorOk;
815 }
816
embedLabelDelta(const Label & label,const Label & base,uint32_t dataSize)817 Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) {
818 if (ASMJIT_UNLIKELY(!_code))
819 return DebugUtils::errored(kErrorNotInitialized);
820
821 EmbedLabelDeltaNode* node = newNodeT<EmbedLabelDeltaNode>(label.id(), base.id(), dataSize);
822 if (ASMJIT_UNLIKELY(!node))
823 return reportError(DebugUtils::errored(kErrorOutOfMemory));
824
825 addNode(node);
826 return kErrorOk;
827 }
828
embedConstPool(const Label & label,const ConstPool & pool)829 Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
830 if (ASMJIT_UNLIKELY(!_code))
831 return DebugUtils::errored(kErrorNotInitialized);
832
833 if (!isLabelValid(label))
834 return reportError(DebugUtils::errored(kErrorInvalidLabel));
835
836 ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment())));
837 ASMJIT_PROPAGATE(bind(label));
838
839 EmbedDataNode* node = newEmbedDataNode(nullptr, uint32_t(pool.size()));
840 if (ASMJIT_UNLIKELY(!node))
841 return reportError(DebugUtils::errored(kErrorOutOfMemory));
842
843 pool.fill(node->data());
844 addNode(node);
845 return kErrorOk;
846 }
847
848 // ============================================================================
849 // [asmjit::BaseBuilder - Comment]
850 // ============================================================================
851
comment(const char * data,size_t size)852 Error BaseBuilder::comment(const char* data, size_t size) {
853 if (ASMJIT_UNLIKELY(!_code))
854 return DebugUtils::errored(kErrorNotInitialized);
855
856 CommentNode* node = newCommentNode(data, size);
857 if (ASMJIT_UNLIKELY(!node))
858 return reportError(DebugUtils::errored(kErrorOutOfMemory));
859
860 addNode(node);
861 return kErrorOk;
862 }
863
864 // ============================================================================
865 // [asmjit::BaseBuilder - Serialize]
866 // ============================================================================
867
serialize(BaseEmitter * dst)868 Error BaseBuilder::serialize(BaseEmitter* dst) {
869 Error err = kErrorOk;
870 BaseNode* node_ = _firstNode;
871
872 do {
873 dst->setInlineComment(node_->inlineComment());
874
875 if (node_->isInst()) {
876 InstNode* node = node_->as<InstNode>();
877 err = dst->emitInst(node->baseInst(), node->operands(), node->opCount());
878 }
879 else if (node_->isLabel()) {
880 if (node_->isConstPool()) {
881 ConstPoolNode* node = node_->as<ConstPoolNode>();
882 err = dst->embedConstPool(node->label(), node->constPool());
883 }
884 else {
885 LabelNode* node = node_->as<LabelNode>();
886 err = dst->bind(node->label());
887 }
888 }
889 else if (node_->isAlign()) {
890 AlignNode* node = node_->as<AlignNode>();
891 err = dst->align(node->alignMode(), node->alignment());
892 }
893 else if (node_->isEmbedData()) {
894 EmbedDataNode* node = node_->as<EmbedDataNode>();
895 err = dst->embed(node->data(), node->size());
896 }
897 else if (node_->isEmbedLabel()) {
898 EmbedLabelNode* node = node_->as<EmbedLabelNode>();
899 err = dst->embedLabel(node->label());
900 }
901 else if (node_->isEmbedLabelDelta()) {
902 EmbedLabelDeltaNode* node = node_->as<EmbedLabelDeltaNode>();
903 err = dst->embedLabelDelta(node->label(), node->baseLabel(), node->dataSize());
904 }
905 else if (node_->isSection()) {
906 SectionNode* node = node_->as<SectionNode>();
907 err = dst->section(_code->sectionById(node->id()));
908 }
909 else if (node_->isComment()) {
910 CommentNode* node = node_->as<CommentNode>();
911 err = dst->comment(node->inlineComment());
912 }
913
914 if (err) break;
915 node_ = node_->next();
916 } while (node_);
917
918 return err;
919 }
920
921 // ============================================================================
922 // [asmjit::BaseBuilder - Logging]
923 // ============================================================================
924
925 #ifndef ASMJIT_NO_LOGGING
dump(String & sb,uint32_t flags) const926 Error BaseBuilder::dump(String& sb, uint32_t flags) const noexcept {
927 BaseNode* node = _firstNode;
928 while (node) {
929 ASMJIT_PROPAGATE(Logging::formatNode(sb, flags, this, node));
930 sb.appendChar('\n');
931 node = node->next();
932 }
933
934 return kErrorOk;
935 }
936 #endif
937
938 // ============================================================================
939 // [asmjit::BaseBuilder - Events]
940 // ============================================================================
941
onAttach(CodeHolder * code)942 Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
943 ASMJIT_PROPAGATE(Base::onAttach(code));
944
945 SectionNode* initialSection;
946 Error err = sectionNodeOf(&initialSection, 0);
947
948 if (!err)
949 err = _passes.willGrow(&_allocator, 8);
950
951 if (ASMJIT_UNLIKELY(err)) {
952 onDetach(code);
953 return err;
954 }
955
956
957 _cursor = initialSection;
958 _firstNode = initialSection;
959 _lastNode = initialSection;
960 initialSection->setFlags(BaseNode::kFlagIsActive);
961
962 return kErrorOk;
963 }
964
onDetach(CodeHolder * code)965 Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
966 _passes.reset();
967 _sectionNodes.reset();
968 _labelNodes.reset();
969
970 _allocator.reset(&_codeZone);
971 _codeZone.reset();
972 _dataZone.reset();
973 _passZone.reset();
974
975 _nodeFlags = 0;
976
977 _cursor = nullptr;
978 _firstNode = nullptr;
979 _lastNode = nullptr;
980
981 return Base::onDetach(code);
982 }
983
984 // ============================================================================
985 // [asmjit::Pass - Construction / Destruction]
986 // ============================================================================
987
Pass(const char * name)988 Pass::Pass(const char* name) noexcept
989 : _cb(nullptr),
990 _name(name) {}
~Pass()991 Pass::~Pass() noexcept {}
992
993 ASMJIT_END_NAMESPACE
994
995 #endif // !ASMJIT_NO_BUILDER
996