diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index e02f7718b..07b5ddd43 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -74,6 +74,7 @@ import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryWriter; import org.teavm.backend.wasm.render.WasmCRenderer; import org.teavm.backend.wasm.render.WasmRenderer; +import org.teavm.backend.wasm.transformation.IndirectCallTraceTransformation; import org.teavm.backend.wasm.transformation.MemoryAccessTraceTransformation; import org.teavm.dependency.ClassDependency; import org.teavm.dependency.DependencyChecker; @@ -374,6 +375,9 @@ public class WasmTarget implements TeaVMTarget { if (Boolean.parseBoolean(System.getProperty("wasm.memoryTrace", "false"))) { new MemoryAccessTraceTransformation(module).apply(); } + if (Boolean.parseBoolean(System.getProperty("wasm.indirectCallTrace", "false"))) { + new IndirectCallTraceTransformation(module).apply(); + } WasmBinaryWriter writer = new WasmBinaryWriter(); WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer, version); diff --git a/core/src/main/java/org/teavm/backend/wasm/transformation/IndirectCallTraceTransformation.java b/core/src/main/java/org/teavm/backend/wasm/transformation/IndirectCallTraceTransformation.java new file mode 100644 index 000000000..cf1d97da9 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/transformation/IndirectCallTraceTransformation.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Alexey Andreev. + * + * 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. + */ +package org.teavm.backend.wasm.transformation; + +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmModule; +import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmIndirectCall; +import org.teavm.backend.wasm.model.expression.WasmInt32Constant; +import org.teavm.backend.wasm.model.expression.WasmReplacingExpressionVisitor; + +public class IndirectCallTraceTransformation { + private WasmModule module; + + public IndirectCallTraceTransformation(WasmModule module) { + this.module = module; + } + + public void apply() { + WasmFunction traceFunction = new WasmFunction("traceIndirectCall"); + traceFunction.setImportModule("debug"); + traceFunction.setImportName("traceIndirectCall"); + traceFunction.getParameters().add(WasmType.INT32); + traceFunction.getParameters().add(WasmType.INT32); + traceFunction.setResult(WasmType.INT32); + module.add(traceFunction); + + int[] positionHolder = { 0 }; + WasmReplacingExpressionVisitor visitor = new WasmReplacingExpressionVisitor(expression -> { + if (expression instanceof WasmIndirectCall) { + WasmIndirectCall indirectCall = (WasmIndirectCall) expression; + WasmCall call = new WasmCall(traceFunction.getName()); + call.setImported(true); + call.getArguments().add(new WasmInt32Constant(positionHolder[0]++)); + call.getArguments().add(indirectCall.getSelector()); + indirectCall.setSelector(call); + } + return expression; + }); + for (WasmFunction function : module.getFunctions().values()) { + visitor.replace(function); + } + } +}