| /* |
| * 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.h> |
| #include <pass.h> |
| #include <wasm-builder.h> |
| |
| namespace wasm { |
| |
| // Adding segments adds overhead, this is a rough estimate |
| const Index OVERHEAD = 8; |
| |
| struct MemoryPacking : public Pass { |
| void run(PassRunner* runner, Module* module) override { |
| if (!module->memory.exists) return; |
| std::vector<Memory::Segment> packed; |
| for (auto& segment : module->memory.segments) { |
| // skip final zeros |
| while (segment.data.size() > 0 && segment.data.back() == 0) { |
| segment.data.pop_back(); |
| } |
| // we can only handle a constant offset for splitting |
| if (auto* offset = segment.offset->dynCast<Const>()) { |
| // Find runs of zeros, and split |
| auto& data = segment.data; |
| auto base = offset->value.geti32(); |
| Index start = 0; |
| // create new segments |
| while (start < data.size()) { |
| // skip initial zeros |
| while (start < data.size() && data[start] == 0) { |
| start++; |
| } |
| Index end = start; // end of data-containing part |
| Index next = end; // after zeros we can skip. preserves next >= end |
| while (next < data.size() && (next - end < OVERHEAD)) { |
| if (data[end] != 0) { |
| end++; |
| next = end; // we can try to skip zeros from here |
| } else { |
| // end is on a zero, we are looking to skip |
| if (data[next] != 0) { |
| end = next; // we must extend the segment, including some zeros |
| } else { |
| next++; |
| } |
| } |
| } |
| if (end != start) { |
| packed.emplace_back(Builder(*module).makeConst(Literal(int32_t(base + start))), &data[start], end - start); |
| } |
| start = next; |
| } |
| } else { |
| packed.push_back(segment); |
| } |
| } |
| module->memory.segments.swap(packed); |
| } |
| }; |
| |
| Pass *createMemoryPackingPass() { |
| return new MemoryPacking(); |
| } |
| |
| } // namespace wasm |
| |