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