|
Lines 1039-1123
void B3IRGenerator::dump(const Vector<Co
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp_sec1
|
| 1039 |
|
1039 |
|
| 1040 |
static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const ModuleInformation& info) |
1040 |
static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const ModuleInformation& info) |
| 1041 |
{ |
1041 |
{ |
| 1042 |
Procedure proc; |
1042 |
CCallHelpers& jit = *compilationContext.jsEntrypointJIT; |
| 1043 |
BasicBlock* block = proc.addBlock(); |
|
|
| 1044 |
|
1043 |
|
| 1045 |
Origin origin; |
1044 |
jit.emitFunctionPrologue(); |
| 1046 |
|
1045 |
|
| 1047 |
jscCallingConvention().setupFrameInPrologue(&function.jsToWasmCalleeMoveLocation, proc, origin, block); |
1046 |
// FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321 |
|
|
1047 |
jit.store64(CCallHelpers::TrustedImm64(0), CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register)))); |
| 1048 |
MacroAssembler::DataLabelPtr calleeMoveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), GPRInfo::nonPreservedNonReturnGPR); |
| 1049 |
jit.storePtr(GPRInfo::nonPreservedNonReturnGPR, CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)))); |
| 1050 |
CodeLocationDataLabelPtr* linkedCalleeMove = &function.jsToWasmCalleeMoveLocation; |
| 1051 |
jit.addLinkTask([=] (LinkBuffer& linkBuffer) { |
| 1052 |
*linkedCalleeMove = linkBuffer.locationOf(calleeMoveLocation); |
| 1053 |
}); |
| 1054 |
|
| 1055 |
RegisterSet toSave; |
| 1056 |
const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get(); |
| 1057 |
toSave.set(pinnedRegs.baseMemoryPointer); |
| 1058 |
for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters) |
| 1059 |
toSave.set(regInfo.sizeRegister); |
| 1060 |
|
| 1061 |
#if !ASSERT_DISABLED |
| 1062 |
unsigned toSaveSize = toSave.numberOfSetGPRs(); |
| 1063 |
// They should all be callee saves. |
| 1064 |
toSave.filter(RegisterSet::calleeSaveRegisters()); |
| 1065 |
ASSERT(toSave.numberOfSetGPRs() == toSaveSize); |
| 1066 |
#endif |
| 1048 |
|
1067 |
|
| 1049 |
if (!ASSERT_DISABLED) { |
1068 |
RegisterAtOffsetList registersToSpill(toSave, RegisterAtOffsetList::OffsetBaseType::FramePointerBased); |
| 1050 |
// This should be guaranteed by our JS wrapper that handles calls to us. |
1069 |
function.jsToWasmEntrypoint.calleeSaveRegisters = registersToSpill; |
| 1051 |
// Just prevent against crazy when ASSERT is enabled. |
|
|
| 1052 |
Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin); |
| 1053 |
Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, origin, CallFrameSlot::argumentCount * sizeof(Register)); |
| 1054 |
Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, origin, |
| 1055 |
block->appendNew<Value>(proc, Add, origin, framePointer, offSetOfArgumentCount)); |
| 1056 |
|
1070 |
|
| 1057 |
Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->argumentCount()); |
1071 |
unsigned totalFrameSize = registersToSpill.size() * sizeof(void*); |
|
|
1072 |
totalFrameSize += WasmCallingConvention::headerSizeInBytes(); |
| 1073 |
totalFrameSize -= sizeof(CallerFrameAndPC); |
| 1074 |
unsigned numGPRs = 0; |
| 1075 |
unsigned numFPRs = 0; |
| 1076 |
for (unsigned i = 0; i < signature->argumentCount(); i++) { |
| 1077 |
switch (signature->argument(i)) { |
| 1078 |
case Wasm::I64: |
| 1079 |
case Wasm::I32: |
| 1080 |
if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) |
| 1081 |
totalFrameSize += sizeof(void*); |
| 1082 |
++numGPRs; |
| 1083 |
break; |
| 1084 |
case Wasm::F32: |
| 1085 |
case Wasm::F64: |
| 1086 |
if (numFPRs >= wasmCallingConvention().m_fprArgs.size()) |
| 1087 |
totalFrameSize += sizeof(void*); |
| 1088 |
++numFPRs; |
| 1089 |
break; |
| 1090 |
default: |
| 1091 |
RELEASE_ASSERT_NOT_REACHED(); |
| 1092 |
} |
| 1093 |
} |
| 1058 |
|
1094 |
|
| 1059 |
CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, origin, |
1095 |
totalFrameSize = WTF::roundUpToMultipleOf(stackAlignmentBytes(), totalFrameSize); |
| 1060 |
block->appendNew<Value>(proc, Above, origin, expectedArgumentCount, argumentCount)); |
1096 |
jit.subPtr(MacroAssembler::TrustedImm32(totalFrameSize), MacroAssembler::stackPointerRegister); |
| 1061 |
|
1097 |
|
| 1062 |
argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) { |
1098 |
// We save all these registers regardless of having a memory or not. |
| 1063 |
jit.breakpoint(); |
1099 |
// The reason is that we use one of these as a scratch. That said, |
| 1064 |
}); |
1100 |
// almost all real wasm programs use memory, so it's not really |
|
|
1101 |
// worth optimizing for the case that they don't. |
| 1102 |
for (const RegisterAtOffset& regAtOffset : registersToSpill) { |
| 1103 |
GPRReg reg = regAtOffset.reg().gpr(); |
| 1104 |
ptrdiff_t offset = regAtOffset.offset(); |
| 1105 |
jit.storePtr(reg, CCallHelpers::Address(GPRInfo::callFrameRegister, offset)); |
| 1065 |
} |
1106 |
} |
| 1066 |
|
1107 |
|
| 1067 |
// FIXME The instance is currently set by the C++ code in WebAssemblyFunction::call. We shouldn't go through the extra C++ hoop. https://bugs.webkit.org/show_bug.cgi?id=166486 |
1108 |
{ |
| 1068 |
Value* instance = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), |
1109 |
CCallHelpers::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))); |
| 1069 |
block->appendNew<ConstPtrValue>(proc, Origin(), &vm.topJSWebAssemblyInstance)); |
1110 |
numGPRs = 0; |
| 1070 |
restoreWebAssemblyGlobalState(vm, info.memory, instance, proc, block); |
1111 |
numFPRs = 0; |
| 1071 |
|
1112 |
// We're going to set the pinned registers after this. So |
| 1072 |
// Get our arguments. |
1113 |
// we can use this as a scratch for now since we saved it above. |
| 1073 |
Vector<Value*> arguments; |
1114 |
GPRReg scratchReg = pinnedRegs.baseMemoryPointer; |
| 1074 |
jscCallingConvention().loadArguments(signature, proc, block, origin, [&] (Value* argument, unsigned) { |
1115 |
|
| 1075 |
arguments.append(argument); |
1116 |
ptrdiff_t jsOffset = CallFrameSlot::thisArgument * sizeof(void*); |
| 1076 |
}); |
1117 |
ptrdiff_t wasmOffset = CallFrame::headerSizeInRegisters * sizeof(void*); |
| 1077 |
|
1118 |
for (unsigned i = 0; i < signature->argumentCount(); i++) { |
| 1078 |
// Move the arguments into place. |
1119 |
switch (signature->argument(i)) { |
| 1079 |
Value* result = wasmCallingConvention().setupCall(proc, block, origin, arguments, toB3Type(signature->returnType()), [&] (PatchpointValue* patchpoint) { |
1120 |
case Wasm::I32: |
| 1080 |
CompilationContext* context = &compilationContext; |
1121 |
case Wasm::I64: |
| 1081 |
|
1122 |
if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) { |
| 1082 |
// wasm -> wasm calls clobber pinned registers unconditionally. This JS -> wasm transition must therefore restore these pinned registers (which are usually callee-saved) to account for this. |
1123 |
if (signature->argument(i) == Wasm::I32) { |
| 1083 |
const PinnedRegisterInfo* pinnedRegs = &PinnedRegisterInfo::get(); |
1124 |
jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg); |
| 1084 |
RegisterSet clobbers; |
1125 |
jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset)); |
| 1085 |
clobbers.set(pinnedRegs->baseMemoryPointer); |
1126 |
} else { |
| 1086 |
for (auto info : pinnedRegs->sizeRegisters) |
1127 |
jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg); |
| 1087 |
clobbers.set(info.sizeRegister); |
1128 |
jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset)); |
| 1088 |
patchpoint->effects.writesPinned = true; |
1129 |
} |
| 1089 |
patchpoint->clobber(clobbers); |
1130 |
wasmOffset += sizeof(void*); |
|
|
1131 |
} else { |
| 1132 |
if (signature->argument(i) == Wasm::I32) |
| 1133 |
jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr()); |
| 1134 |
else |
| 1135 |
jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr()); |
| 1136 |
} |
| 1137 |
++numGPRs; |
| 1138 |
break; |
| 1139 |
case Wasm::F32: |
| 1140 |
case Wasm::F64: |
| 1141 |
if (numFPRs >= wasmCallingConvention().m_fprArgs.size()) { |
| 1142 |
if (signature->argument(i) == Wasm::F32) { |
| 1143 |
jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg); |
| 1144 |
jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset)); |
| 1145 |
} else { |
| 1146 |
jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg); |
| 1147 |
jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset)); |
| 1148 |
} |
| 1149 |
wasmOffset += sizeof(void*); |
| 1150 |
} else { |
| 1151 |
if (signature->argument(i) == Wasm::F32) |
| 1152 |
jit.loadFloat(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr()); |
| 1153 |
else |
| 1154 |
jit.loadDouble(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr()); |
| 1155 |
} |
| 1156 |
++numFPRs; |
| 1157 |
break; |
| 1158 |
default: |
| 1159 |
RELEASE_ASSERT_NOT_REACHED(); |
| 1160 |
} |
| 1090 |
|
1161 |
|
| 1091 |
patchpoint->setGenerator([context] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { |
1162 |
jsOffset += sizeof(void*); |
| 1092 |
AllowMacroScratchRegisterUsage allowScratch(jit); |
1163 |
} |
|
|
1164 |
} |
| 1093 |
|
1165 |
|
| 1094 |
CCallHelpers::Call call = jit.call(); |
1166 |
if (!!info.memory) { |
| 1095 |
context->jsEntrypointToWasmEntrypointCall = call; |
1167 |
GPRReg baseMemory = pinnedRegs.baseMemoryPointer; |
| 1096 |
}); |
1168 |
jit.loadPtr(&vm.topJSWebAssemblyInstance, baseMemory); |
| 1097 |
}); |
1169 |
jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory); |
|
|
1170 |
const auto& sizeRegs = pinnedRegs.sizeRegisters; |
| 1171 |
ASSERT(sizeRegs.size() >= 1); |
| 1172 |
ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0. |
| 1173 |
jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); |
| 1174 |
jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); |
| 1175 |
for (unsigned i = 1; i < sizeRegs.size(); ++i) |
| 1176 |
jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister); |
| 1177 |
} |
| 1178 |
|
| 1179 |
compilationContext.jsEntrypointToWasmEntrypointCall = jit.call(); |
| 1180 |
|
| 1181 |
for (const RegisterAtOffset& regAtOffset : registersToSpill) { |
| 1182 |
GPRReg reg = regAtOffset.reg().gpr(); |
| 1183 |
ASSERT(reg != GPRInfo::returnValueGPR); |
| 1184 |
ptrdiff_t offset = regAtOffset.offset(); |
| 1185 |
jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, offset), reg); |
| 1186 |
} |
| 1098 |
|
1187 |
|
| 1099 |
// Return the result, if needed. |
|
|
| 1100 |
switch (signature->returnType()) { |
1188 |
switch (signature->returnType()) { |
| 1101 |
case Wasm::Void: |
|
|
| 1102 |
block->appendNewControlValue(proc, B3::Return, origin); |
| 1103 |
break; |
| 1104 |
case Wasm::F32: |
1189 |
case Wasm::F32: |
|
|
1190 |
jit.moveFloatTo32(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR); |
| 1191 |
break; |
| 1105 |
case Wasm::F64: |
1192 |
case Wasm::F64: |
| 1106 |
result = block->appendNew<Value>(proc, BitwiseCast, origin, result); |
1193 |
jit.moveDoubleTo64(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR); |
| 1107 |
FALLTHROUGH; |
1194 |
break; |
| 1108 |
case Wasm::I32: |
1195 |
default: |
| 1109 |
case Wasm::I64: |
|
|
| 1110 |
block->appendNewControlValue(proc, B3::Return, origin, result); |
| 1111 |
break; |
1196 |
break; |
| 1112 |
case Wasm::Func: |
|
|
| 1113 |
case Wasm::Anyfunc: |
| 1114 |
RELEASE_ASSERT_NOT_REACHED(); |
| 1115 |
} |
1197 |
} |
| 1116 |
|
1198 |
|
| 1117 |
B3::prepareForGeneration(proc); |
1199 |
jit.emitFunctionEpilogue(); |
| 1118 |
B3::generate(proc, *compilationContext.jsEntrypointJIT); |
1200 |
jit.ret(); |
| 1119 |
compilationContext.jsEntrypointByproducts = proc.releaseByproducts(); |
|
|
| 1120 |
function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters(); |
| 1121 |
} |
1201 |
} |
| 1122 |
|
1202 |
|
| 1123 |
Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, const Vector<SignatureIndex>& moduleSignatureIndicesToUniquedSignatureIndices, unsigned optLevel) |
1203 |
Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, const Vector<SignatureIndex>& moduleSignatureIndicesToUniquedSignatureIndices, unsigned optLevel) |