| /* | |
| * Copyright 2017 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "ir/load-utils.h" | |
| #include "ir/utils.h" | |
| namespace wasm::ExpressionManipulator { | |
| Expression* | |
| flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) { | |
| // Perform the copy using a stack of tasks (avoiding recursion). | |
| struct CopyTask { | |
| // The thing to copy. | |
| Expression* original; | |
| // The location of the pointer to write the copy to. | |
| Expression** destPointer; | |
| }; | |
| std::vector<CopyTask> tasks; | |
| Expression* ret; | |
| tasks.push_back({original, &ret}); | |
| while (!tasks.empty()) { | |
| auto task = tasks.back(); | |
| tasks.pop_back(); | |
| // If the custom copier handled this one, we have nothing to do. | |
| auto* copy = custom(task.original); | |
| if (copy) { | |
| *task.destPointer = copy; | |
| continue; | |
| } | |
| // If the original is a null, just copy that. (This can happen for an | |
| // optional child.) | |
| auto* original = task.original; | |
| if (original == nullptr) { | |
| *task.destPointer = nullptr; | |
| continue; | |
| } | |
| // Allocate a new copy, and copy the fields. | |
| #define DELEGATE_ID original->_id | |
| // Allocate a new expression of the right type, and create cast versions of it | |
| // for later operations. | |
| #define DELEGATE_START(id) \ | |
| copy = wasm.allocator.alloc<id>(); \ | |
| [[maybe_unused]] auto* castOriginal = original->cast<id>(); \ | |
| [[maybe_unused]] auto* castCopy = copy->cast<id>(); | |
| // Handle each type of field, copying it appropriately. | |
| #define DELEGATE_FIELD_CHILD(id, field) \ | |
| tasks.push_back({castOriginal->field, &castCopy->field}); | |
| // Iterate in reverse order here so we visit children in normal order. | |
| #define DELEGATE_FIELD_CHILD_VECTOR(id, field) \ | |
| castCopy->field.resize(castOriginal->field.size()); \ | |
| for (auto i = int64_t(castOriginal->field.size()) - 1; i >= 0; i--) { \ | |
| tasks.push_back({castOriginal->field[i], &castCopy->field[i]}); \ | |
| } | |
| #define COPY_FIELD(field) castCopy->field = castOriginal->field; | |
| #define DELEGATE_FIELD_INT(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_LITERAL(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_NAME(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_SCOPE_NAME_DEF(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_SCOPE_NAME_USE(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_TYPE(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_HEAPTYPE(id, field) COPY_FIELD(field) | |
| #define DELEGATE_FIELD_ADDRESS(id, field) COPY_FIELD(field) | |
| #define COPY_FIELD_LIST(field) \ | |
| for (Index i = 0; i < castOriginal->field.size(); i++) { \ | |
| castCopy->field[i] = castOriginal->field[i]; \ | |
| } | |
| #define COPY_VECTOR(field) \ | |
| castCopy->field.resize(castOriginal->field.size()); \ | |
| COPY_FIELD_LIST(field) | |
| #define COPY_ARRAY(field) \ | |
| assert(castCopy->field.size() == castOriginal->field.size()); \ | |
| COPY_FIELD_LIST(field) | |
| #define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, field) COPY_VECTOR(field) | |
| #define DELEGATE_FIELD_NAME_VECTOR(id, field) COPY_VECTOR(field) | |
| #define DELEGATE_FIELD_TYPE_VECTOR(id, field) COPY_VECTOR(field) | |
| #define DELEGATE_FIELD_INT_ARRAY(id, field) COPY_ARRAY(field) | |
| #define DELEGATE_FIELD_INT_VECTOR(id, field) COPY_VECTOR(field) | |
| #include "wasm-delegations-fields.def" | |
| // The type can be simply copied. | |
| copy->type = original->type; | |
| // Write the copy to where it should be referred to. | |
| *task.destPointer = copy; | |
| } | |
| return ret; | |
| } | |
| // Splice an item into the middle of a block's list | |
| void spliceIntoBlock(Block* block, Index index, Expression* add) { | |
| block->list.insertAt(index, add); | |
| block->finalize(block->type); | |
| } | |
| } // namespace wasm::ExpressionManipulator |