blob: 7591b4fe7e06a482c445f618af6eb4a0e2994f68 [file] [log] [blame] [edit]
/*
* Copyright 2026 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.
*/
#ifndef wasm_ir_js_utils_h
#define wasm_ir_js_utils_h
#include "ir/intrinsics.h"
#include "wasm-type.h"
#include "wasm.h"
namespace wasm::JSUtils {
// Whether this is a descriptor struct type whose first field is immutable and a
// subtype of externref.
inline bool hasPossibleJSPrototypeField(HeapType type) {
if (!type.getDescribedType()) {
return false;
}
assert(type.isStruct());
const auto& fields = type.getStruct().fields;
if (fields.empty()) {
return false;
}
if (fields[0].mutable_ == Mutable) {
return false;
}
if (!fields[0].type.isRef()) {
return false;
}
return fields[0].type.getHeapType().isMaybeShared(HeapType::ext);
}
// Calls flowIn and flowOut on all types that may flow in from or out to JS.
template<typename In, typename Out>
void iterJSInterface(Module& wasm, In flowIn, Out flowOut) {
// @binaryen.js.called functions are called from JS. Their parameters flow
// in from JS and their results flow back out.
for (auto f : Intrinsics(wasm).getJSCalledFunctions()) {
auto* func = wasm.getFunction(f);
for (auto type : func->getParams()) {
flowIn(type);
}
for (auto type : func->getResults()) {
flowOut(type);
}
}
for (auto& ex : wasm.exports) {
switch (ex->kind) {
case ExternalKindImpl::Function: {
// Exported functions are also called from JS. Their parameters flow
// in from JS and their result flow back out.
auto* func = wasm.getFunction(*ex->getInternalName());
for (auto type : func->getParams()) {
flowIn(type);
}
for (auto type : func->getResults()) {
flowOut(type);
}
break;
}
case ExternalKindImpl::Table: {
// Exported tables let values flow in and out.
auto* table = wasm.getTable(*ex->getInternalName());
flowOut(table->type);
flowIn(table->type);
break;
}
case ExternalKindImpl::Global: {
// Exported globals let values flow out. Iff they are mutable, they
// also let values flow back in.
auto* global = wasm.getGlobal(*ex->getInternalName());
flowOut(global->type);
if (global->mutable_) {
flowIn(global->type);
}
break;
}
case ExternalKindImpl::Memory:
case ExternalKindImpl::Tag:
case ExternalKindImpl::Invalid:
break;
}
}
for (auto& func : wasm.functions) {
// Imported functions are the opposite of exported functions. Their
// parameters flow out and their results flow in.
if (func->imported()) {
for (auto type : func->getParams()) {
flowOut(type);
}
for (auto type : func->getResults()) {
flowIn(type);
}
}
}
for (auto& table : wasm.tables) {
// Imported tables, like exported tables, let values flow in and out.
if (table->imported()) {
flowOut(table->type);
flowIn(table->type);
}
}
for (auto& global : wasm.globals) {
// Imported mutable globals let values flow in and out. Imported immutable
// globals imply that values will flow in.
if (global->imported()) {
flowIn(global->type);
if (global->mutable_) {
flowOut(global->type);
}
}
}
}
} // namespace wasm::JSUtils
#endif // wasm_ir_js_utils_h