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