/* * Copyright 2016 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 "wasm-emscripten.h" #include #include "asm_v_wasm.h" #include "asmjs/shared-constants.h" #include "ir/import-utils.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" #include "shared-constants.h" #include "support/debug.h" #include "wasm-builder.h" #include "wasm-traversal.h" #include "wasm.h" #define DEBUG_TYPE "emscripten" namespace wasm { void addExportedFunction(Module& wasm, Function* function) { wasm.addFunction(function); auto export_ = new Export; export_->name = export_->value = function->name; export_->kind = ExternalKind::Function; wasm.addExport(export_); } // TODO(sbc): There should probably be a better way to do this. bool isExported(Module& wasm, Name name) { for (auto& ex : wasm.exports) { if (ex->value == name) { return true; } } return false; } Global* getStackPointerGlobal(Module& wasm) { // Assumption: The stack pointer is either imported as __stack_pointer or // we just assume it's the first non-imported global. // TODO(sbc): Find a better way to discover the stack pointer. Perhaps the // linker could export it by name? for (auto& g : wasm.globals) { if (g->imported() && g->base == STACK_POINTER) { return g.get(); } } for (auto& g : wasm.globals) { if (!g->imported()) { return g.get(); } } return nullptr; } const Address UNKNOWN_OFFSET(uint32_t(-1)); std::string escape(std::string code) { // replace newlines quotes with escaped newlines size_t curr = 0; while ((curr = code.find("\\n", curr)) != std::string::npos) { code = code.replace(curr, 2, "\\\\n"); curr += 3; // skip this one } curr = 0; while ((curr = code.find("\\t", curr)) != std::string::npos) { code = code.replace(curr, 2, "\\\\t"); curr += 3; // skip this one } // replace double quotes with escaped single quotes curr = 0; while ((curr = code.find('"', curr)) != std::string::npos) { if (curr == 0 || code[curr - 1] != '\\') { code = code.replace(curr, 1, "\\" "\""); curr += 2; // skip this one } else { // already escaped, escape the slash as well code = code.replace(curr, 1, "\\" "\\" "\""); curr += 3; // skip this one } } return code; } class StringConstantTracker { public: StringConstantTracker(Module& wasm) : wasm(wasm) { calcSegmentOffsets(); } const char* stringAtAddr(Address address) { for (unsigned i = 0; i < wasm.dataSegments.size(); ++i) { auto& segment = wasm.dataSegments[i]; Address offset = segmentOffsets[i]; if (offset != UNKNOWN_OFFSET && address >= offset && address < offset + segment->data.size()) { return &segment->data[address - offset]; } } Fatal() << "unable to find data for ASM/EM_JS const at: " << address; return nullptr; } std::vector
segmentOffsets; // segment index => address offset private: void calcSegmentOffsets() { std::unordered_map passiveOffsets; if (wasm.features.hasBulkMemory()) { // Fetch passive segment offsets out of memory.init instructions struct OffsetSearcher : PostWalker { std::unordered_map& offsets; OffsetSearcher(std::unordered_map& offsets) : offsets(offsets) {} void visitMemoryInit(MemoryInit* curr) { // The desitination of the memory.init is either a constant // or the result of an addition with __memory_base in the // case of PIC code. auto* dest = curr->dest->dynCast(); if (!dest) { auto* add = curr->dest->dynCast(); if (!add) { return; } dest = add->left->dynCast(); if (!dest) { return; } } auto it = offsets.find(curr->segment); if (it != offsets.end()) { Fatal() << "Cannot get offset of passive segment initialized " "multiple times"; } offsets[curr->segment] = dest->value.getInteger(); } } searcher(passiveOffsets); searcher.walkModule(&wasm); } for (unsigned i = 0; i < wasm.dataSegments.size(); ++i) { auto& segment = wasm.dataSegments[i]; if (segment->isPassive) { auto it = passiveOffsets.find(segment->name); if (it != passiveOffsets.end()) { segmentOffsets.push_back(it->second); } else { // This was a non-constant offset (perhaps TLS) segmentOffsets.push_back(UNKNOWN_OFFSET); } } else if (auto* addrConst = segment->offset->dynCast()) { auto address = addrConst->value.getUnsigned(); segmentOffsets.push_back(address); } else { // TODO(sbc): Wasm shared libraries have data segments with non-const // offset. segmentOffsets.push_back(0); } } } Module& wasm; }; struct AsmConst { Address id; std::string code; }; } // namespace wasm