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