Skip to content

Commit

Permalink
[JSC] Add call_builtin wasm opcode
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=249520
rdar://103471989

Reviewed by Mark Lam.

This patch adds call_builtin Wasm opcode to save Wasm opcode space.
There are many Wasm opcodes which are just calling a function because of opcode's complexity.
We should represent it as a form of "call_builtin" instead and reduce # of opcodes.

In LLIntGenerator, we materialize call_builtin like what we materialize a normal call.
And instead of passing functionIndex, we pass builtinIndex. And then, call_builtin
slowpath offers a way to retrieve arguments from call's format so that we can pass arbitrary
number of values and we can return arbitrary number of values.

The definition of calling convension is following to wasm's call. And we use pre-defined
function signatures to materialize them correctly in LLIntGenerator.

* Source/JavaScriptCore/CMakeLists.txt:
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/llint/WebAssembly.asm:
* Source/JavaScriptCore/wasm/WasmLLIntBuiltin.h: Added.
* Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::addConstantWithoutPush):
(JSC::Wasm::LLIntGenerator::addConstant):
(JSC::Wasm::LLIntGenerator::addElemDrop):
(JSC::Wasm::LLIntGenerator::addTableSize):
(JSC::Wasm::LLIntGenerator::addTableCopy):
(JSC::Wasm::LLIntGenerator::addCallBuiltin):
(JSC::Wasm::LLIntGenerator::addCurrentMemory):
(JSC::Wasm::LLIntGenerator::addMemoryInit):
(JSC::Wasm::LLIntGenerator::addDataDrop):
(JSC::Wasm::LLIntGenerator::addMemoryFill):
(JSC::Wasm::LLIntGenerator::addMemoryCopy):
* Source/JavaScriptCore/wasm/WasmSlowPaths.cpp:
(JSC::LLInt::jsrSize):
(JSC::LLInt::fprSize):
(JSC::LLInt::WASM_SLOW_PATH_DECL):
* Source/JavaScriptCore/wasm/WasmSlowPaths.h:
* Source/JavaScriptCore/wasm/WasmTypeDefinition.cpp:
(JSC::Wasm::TypeInformation::typeDefinitionForLLIntBuiltin):
(JSC::Wasm::TypeInformation::TypeInformation):
* Source/JavaScriptCore/wasm/WasmTypeDefinition.h:

Canonical link: https://commits.webkit.org/258047@main
  • Loading branch information
Constellation committed Dec 17, 2022
1 parent d2163c2 commit 841f77f
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 199 deletions.
1 change: 1 addition & 0 deletions Source/JavaScriptCore/CMakeLists.txt
Expand Up @@ -1281,6 +1281,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
wasm/WasmFunctionCodeBlockGenerator.h
wasm/WasmHandlerInfo.h
wasm/WasmIndexOrName.h
wasm/WasmLLIntBuiltin.h
wasm/WasmLLIntTierUpCounter.h
wasm/WasmMemory.h
wasm/WasmMemoryInformation.h
Expand Down
Expand Up @@ -1868,6 +1868,7 @@
E307178D24C7829A00DF0644 /* IntlLocaleConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */; };
E307178E24C7829D00DF0644 /* IntlLocale.h in Headers */ = {isa = PBXBuildFile; fileRef = A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */; };
E30873E7272559410053B601 /* IntlPluralRules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7D5FB18F20744BF1005DDF64 /* IntlPluralRules.cpp */; };
E308A80E294D39340044A109 /* WasmLLIntBuiltin.h in Headers */ = {isa = PBXBuildFile; fileRef = E308A80D294D39330044A109 /* WasmLLIntBuiltin.h */; settings = {ATTRIBUTES = (Private, ); }; };
E30D903A28B77F28008B2CDC /* ProxyObjectAccessCase.h in Headers */ = {isa = PBXBuildFile; fileRef = E30D903828B77F28008B2CDC /* ProxyObjectAccessCase.h */; };
E30E8A5426DE2E4800DA4915 /* TemporalTimeZonePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E30E8A4E26DE2E4700DA4915 /* TemporalTimeZonePrototype.h */; };
E30E8A5626DE2E4800DA4915 /* TemporalTimeZone.h in Headers */ = {isa = PBXBuildFile; fileRef = E30E8A5026DE2E4800DA4915 /* TemporalTimeZone.h */; };
Expand Down Expand Up @@ -5340,6 +5341,7 @@
E307178024C7824700DF0644 /* IntlSegmenter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntlSegmenter.cpp; sourceTree = "<group>"; };
E307178124C7824700DF0644 /* IntlSegmenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntlSegmenter.h; sourceTree = "<group>"; };
E307178224C7824700DF0644 /* IntlSegmenterConstructor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntlSegmenterConstructor.cpp; sourceTree = "<group>"; };
E308A80D294D39330044A109 /* WasmLLIntBuiltin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmLLIntBuiltin.h; sourceTree = "<group>"; };
E30D903728B77F27008B2CDC /* ProxyObjectAccessCase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyObjectAccessCase.cpp; sourceTree = "<group>"; };
E30D903828B77F28008B2CDC /* ProxyObjectAccessCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyObjectAccessCase.h; sourceTree = "<group>"; };
E30E8A4C26DE2E4700DA4915 /* TemporalTimeZonePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalTimeZonePrototype.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7522,6 +7524,7 @@
AD5C36DF1F699EB6000BCAAF /* WasmInstance.h */,
52FDABC22788076900C15B59 /* WasmIRGeneratorHelpers.h */,
AD00659D1ECAC7FE000CA926 /* WasmLimits.h */,
E308A80D294D39330044A109 /* WasmLLIntBuiltin.h */,
14C5AD6822F33FBF00F1FB83 /* WasmLLIntGenerator.cpp */,
14C5AD6922F33FBF00F1FB83 /* WasmLLIntGenerator.h */,
14C5AD6A22F33FBF00F1FB83 /* WasmLLIntPlan.cpp */,
Expand Down Expand Up @@ -11408,6 +11411,7 @@
AD5C36E21F699EC0000BCAAF /* WasmInstance.h in Headers */,
52FDABC32788076B00C15B59 /* WasmIRGeneratorHelpers.h in Headers */,
AD00659E1ECAC812000CA926 /* WasmLimits.h in Headers */,
E308A80E294D39340044A109 /* WasmLLIntBuiltin.h in Headers */,
1450FA1F2357BEC90093CD4D /* WasmLLIntTierUpCounter.h in Headers */,
53E9E0AC1EAE83DF00FEE251 /* WasmMachineThreads.h in Headers */,
535557141D9D9EA5006D583B /* WasmMemory.h in Headers */,
Expand Down
53 changes: 4 additions & 49 deletions Source/JavaScriptCore/bytecode/BytecodeList.rb
Expand Up @@ -1654,17 +1654,6 @@
tableIndex: unsigned,
}

op :elem_drop,
args: {
elementIndex: unsigned,
}

op :table_size,
args: {
dst: VirtualRegister,
tableIndex: unsigned,
}

op :table_grow,
args: {
dst: VirtualRegister,
Expand All @@ -1681,15 +1670,6 @@
tableIndex: unsigned,
}

op :table_copy,
args: {
dstOffset: VirtualRegister,
srcOffset: VirtualRegister,
length: VirtualRegister,
dstTableIndex: unsigned,
srcTableIndex: unsigned,
}

op :call,
args: {
functionIndex: unsigned,
Expand Down Expand Up @@ -1738,9 +1718,11 @@
numberOfStackArgs: unsigned,
}

op :current_memory,
op :call_builtin,
args: {
dst: VirtualRegister,
builtinIndex: unsigned,
stackOffset: unsigned,
numberOfStackArgs: unsigned,
}

op :grow_memory,
Expand All @@ -1749,33 +1731,6 @@
delta: VirtualRegister
}

op :memory_fill,
args: {
dstAddress: VirtualRegister,
targetValue: VirtualRegister,
count: VirtualRegister,
}

op :memory_copy,
args: {
dstAddress: VirtualRegister,
srcAddress: VirtualRegister,
count: VirtualRegister,
}

op :memory_init,
args: {
dstAddress: VirtualRegister,
srcAddress: VirtualRegister,
length: VirtualRegister,
dataSegmentIndex: unsigned,
}

op :data_drop,
args: {
dataSegmentIndex: unsigned,
}

op :select,
args: {
dst: VirtualRegister,
Expand Down
19 changes: 1 addition & 18 deletions Source/JavaScriptCore/llint/WebAssembly.asm
Expand Up @@ -829,15 +829,8 @@ slowWasmOp(ref_func)
slowWasmOp(table_get)
slowWasmOp(table_set)
slowWasmOp(table_init)
slowWasmOp(elem_drop)
slowWasmOp(table_size)
slowWasmOp(table_fill)
slowWasmOp(table_copy)
slowWasmOp(table_grow)
slowWasmOp(memory_fill)
slowWasmOp(memory_copy)
slowWasmOp(memory_init)
slowWasmOp(data_drop)
slowWasmOp(set_global_ref)
slowWasmOp(set_global_ref_portable_binding)
slowWasmOp(memory_atomic_wait32)
Expand Down Expand Up @@ -1170,17 +1163,7 @@ wasmOp(call_ref_no_tls, WasmCallRefNoTls, macro(ctx)
slowPathForWasmCall(ctx, _slow_path_wasm_call_ref_no_tls, macro(targetInstance) move targetInstance, wasmInstance end)
end)

wasmOp(current_memory, WasmCurrentMemory, macro(ctx)
loadp Wasm::Instance::m_memory[wasmInstance], t0
loadp Wasm::Memory::m_handle[t0], t0
loadp BufferMemoryHandle::m_size[t0], t0
urshiftp 16, t0
if JSVALUE64
returnq(ctx, t0)
else
return2i(ctx, 0, t0)
end
end)
slowWasmOp(call_builtin)

wasmOp(select, WasmSelect, macro(ctx)
mloadi(ctx, m_condition, t0)
Expand Down
49 changes: 49 additions & 0 deletions Source/JavaScriptCore/wasm/WasmLLIntBuiltin.h
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#if ENABLE(WEBASSEMBLY)

#include <cstdint>

namespace JSC {

namespace Wasm {

enum class LLIntBuiltin : uint8_t {
CurrentMemory = 0,
MemoryFill,
MemoryCopy,
MemoryInit,
TableSize,
TableCopy,
DataDrop,
ElemDrop,
};

} } // namespace JSC::Wasm

#endif // ENABLE(WEBASSEMBLY)
87 changes: 53 additions & 34 deletions Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp
Expand Up @@ -261,6 +261,7 @@ class LLIntGenerator : public BytecodeGeneratorBase<GeneratorTraits> {
PartialResult WARN_UNUSED_RETURN addArguments(const TypeDefinition&);
PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
ExpressionType addConstant(Type, int64_t);
ExpressionType addConstantWithoutPush(Type, int64_t);

// References
PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType value, ExpressionType& result);
Expand Down Expand Up @@ -526,6 +527,8 @@ class LLIntGenerator : public BytecodeGeneratorBase<GeneratorTraits> {

void finalizePreviousBlockForCatch(ControlType&, Stack&);

void addCallBuiltin(LLIntBuiltin, const Vector<ExpressionType> args, ResultList& results);

struct SwitchEntry {
WasmInstructionStream::Offset offset;
int* jumpTarget;
Expand Down Expand Up @@ -623,8 +626,8 @@ auto LLIntGenerator::callInformationForCaller(const FunctionSignature& signature
{
// This function sets up the stack layout for calls. The desired stack layout is:

// FPRn
// ...
// FPRn |
// ... v stack-growth towards lower memory
// FPR1
// FPR0
// ---
Expand Down Expand Up @@ -937,27 +940,29 @@ void LLIntGenerator::didFinishParsingLocals()
m_unitializedLocals.clear();
}

auto LLIntGenerator::addConstantWithoutPush(Type type, int64_t value) -> ExpressionType
{
if (!value)
return zeroConstant();

if (value == JSValue::encode(jsNull()))
return jsNullConstant();

VirtualRegister source(FirstConstantRegisterIndex + m_codeBlock->m_constants.size());
auto result = m_constantMap.add(value, source);
if (!result.isNewEntry)
return result.iterator->value;
m_codeBlock->m_constants.append(value);
if (UNLIKELY(Options::dumpGeneratedWasmBytecodes()))
m_codeBlock->m_constantTypes.append(type);
return source;
}

auto LLIntGenerator::addConstant(Type type, int64_t value) -> ExpressionType
{
auto constant = [&] {
if (!value)
return zeroConstant();

if (value == JSValue::encode(jsNull()))
return jsNullConstant();

VirtualRegister source(FirstConstantRegisterIndex + m_codeBlock->m_constants.size());
auto result = m_constantMap.add(value, source);
if (!result.isNewEntry)
return result.iterator->value;
m_codeBlock->m_constants.append(value);
if (UNLIKELY(Options::dumpGeneratedWasmBytecodes()))
m_codeBlock->m_constantTypes.append(type);
return source;
};
// leave a hole if we need to materialize the constant
push();
return constant();
return addConstantWithoutPush(type, value);
}

auto LLIntGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
Expand Down Expand Up @@ -1494,16 +1499,16 @@ auto LLIntGenerator::addTableInit(unsigned elementIndex, unsigned tableIndex, Ex

auto LLIntGenerator::addElemDrop(unsigned elementIndex) -> PartialResult
{
WasmElemDrop::emit(this, elementIndex);

ResultList results;
addCallBuiltin(LLIntBuiltin::ElemDrop, { addConstantWithoutPush(Types::I32, elementIndex) }, results);
return { };
}

auto LLIntGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult
{
result = push();
WasmTableSize::emit(this, result, tableIndex);

ResultList results;
addCallBuiltin(LLIntBuiltin::TableSize, { addConstantWithoutPush(Types::I32, tableIndex) }, results);
result = results.at(0);
return { };
}

Expand All @@ -1524,7 +1529,8 @@ auto LLIntGenerator::addTableFill(unsigned tableIndex, ExpressionType offset, Ex

auto LLIntGenerator::addTableCopy(unsigned dstTableIndex, unsigned srcTableIndex, ExpressionType dstOffset, ExpressionType srcOffset, ExpressionType length) -> PartialResult
{
WasmTableCopy::emit(this, dstOffset, srcOffset, length, dstTableIndex, srcTableIndex);
ResultList results;
addCallBuiltin(LLIntBuiltin::TableCopy, { dstOffset, srcOffset, length, addConstantWithoutPush(Types::I32, dstTableIndex), addConstantWithoutPush(Types::I32, srcTableIndex) }, results);
return { };
}

Expand All @@ -1542,25 +1548,36 @@ auto LLIntGenerator::addCrash() -> PartialResult
return { };
}

auto LLIntGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
void LLIntGenerator::addCallBuiltin(LLIntBuiltin builtin, const Vector<ExpressionType> args, ResultList& results)
{
result = push();
WasmCurrentMemory::emit(this, result);
const TypeDefinition& signature = TypeInformation::signatureForLLIntBuiltin(builtin);
ASSERT(signature.as<FunctionSignature>()->argumentCount() == args.size());
LLIntCallInformation info = callInformationForCaller(*signature.as<FunctionSignature>());
unifyValuesWithBlock(info.arguments, args);
WasmCallBuiltin::emit(this, static_cast<uint32_t>(builtin), info.stackOffset, info.numberOfStackArguments);
info.commitResults(results);
ASSERT(signature.as<FunctionSignature>()->returnCount() == results.size());
}

auto LLIntGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
{
ResultList results;
addCallBuiltin(LLIntBuiltin::CurrentMemory, { }, results);
result = results.at(0);
return { };
}

auto LLIntGenerator::addMemoryInit(unsigned dataSegmentIndex, ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType length) -> PartialResult
{
WasmMemoryInit::emit(this, dstAddress, srcAddress, length, dataSegmentIndex);

ResultList results;
addCallBuiltin(LLIntBuiltin::MemoryInit, { dstAddress, srcAddress, length, addConstantWithoutPush(Types::I32, dataSegmentIndex) }, results);
return { };
}

auto LLIntGenerator::addDataDrop(unsigned dataSegmentIndex) -> PartialResult
{
WasmDataDrop::emit(this, dataSegmentIndex);

ResultList results;
addCallBuiltin(LLIntBuiltin::DataDrop, { addConstantWithoutPush(Types::I32, dataSegmentIndex) }, results);
return { };
}

Expand All @@ -1574,13 +1591,15 @@ auto LLIntGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result)

auto LLIntGenerator::addMemoryFill(ExpressionType dstAddress, ExpressionType targetValue, ExpressionType count) -> PartialResult
{
WasmMemoryFill::emit(this, dstAddress, targetValue, count);
ResultList results;
addCallBuiltin(LLIntBuiltin::MemoryFill, { dstAddress, targetValue, count }, results);
return { };
}

auto LLIntGenerator::addMemoryCopy(ExpressionType dstAddress, ExpressionType srcAddress, ExpressionType count) -> PartialResult
{
WasmMemoryCopy::emit(this, dstAddress, srcAddress, count);
ResultList results;
addCallBuiltin(LLIntBuiltin::MemoryCopy, { dstAddress, srcAddress, count }, results);
return { };
}

Expand Down

0 comments on commit 841f77f

Please sign in to comment.