diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/wasm/WasmCallingConvention.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/wasm/WasmCallingConvention.h')
-rw-r--r-- | Source/JavaScriptCore/wasm/WasmCallingConvention.h | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wasm/WasmCallingConvention.h b/Source/JavaScriptCore/wasm/WasmCallingConvention.h new file mode 100644 index 000000000..d79014f27 --- /dev/null +++ b/Source/JavaScriptCore/wasm/WasmCallingConvention.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2016 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 "AllowMacroScratchRegisterUsage.h" +#include "B3ArgumentRegValue.h" +#include "B3BasicBlock.h" +#include "B3Const64Value.h" +#include "B3ConstrainedValue.h" +#include "B3MemoryValue.h" +#include "B3PatchpointValue.h" +#include "B3Procedure.h" +#include "B3StackmapGenerationParams.h" +#include "CallFrame.h" +#include "LinkBuffer.h" +#include "RegisterSet.h" +#include "WasmFormat.h" + +namespace JSC { namespace Wasm { + +typedef unsigned (*NextOffset)(unsigned currentOffset, B3::Type type); + +template<unsigned headerSize, NextOffset updateOffset> +class CallingConvention { +public: + CallingConvention(Vector<Reg>&& gprArgs, Vector<Reg>&& fprArgs, RegisterSet&& calleeSaveRegisters) + : m_gprArgs(gprArgs) + , m_fprArgs(fprArgs) + , m_calleeSaveRegisters(calleeSaveRegisters) + { + } + +private: + B3::ValueRep marshallArgumentImpl(Vector<Reg> regArgs, B3::Type type, size_t& count, size_t& stackOffset) const + { + if (count < regArgs.size()) + return B3::ValueRep::reg(regArgs[count++]); + + count++; + B3::ValueRep result = B3::ValueRep::stackArgument(stackOffset); + stackOffset = updateOffset(stackOffset, type); + return result; + } + + B3::ValueRep marshallArgument(B3::Type type, size_t& gpArgumentCount, size_t& fpArgumentCount, size_t& stackOffset) const + { + switch (type) { + case B3::Int32: + case B3::Int64: + return marshallArgumentImpl(m_gprArgs, type, gpArgumentCount, stackOffset); + case B3::Float: + case B3::Double: + return marshallArgumentImpl(m_fprArgs, type, fpArgumentCount, stackOffset); + case B3::Void: + break; + } + RELEASE_ASSERT_NOT_REACHED(); + } + +public: + void setupFrameInPrologue(CodeLocationDataLabelPtr* calleeMoveLocation, B3::Procedure& proc, B3::Origin origin, B3::BasicBlock* block) const + { + static_assert(CallFrameSlot::callee * sizeof(Register) < headerSize, "We rely on this here for now."); + static_assert(CallFrameSlot::codeBlock * sizeof(Register) < headerSize, "We rely on this here for now."); + + B3::PatchpointValue* getCalleePatchpoint = block->appendNew<B3::PatchpointValue>(proc, B3::Int64, origin); + getCalleePatchpoint->resultConstraint = B3::ValueRep::SomeRegister; + getCalleePatchpoint->effects = B3::Effects::none(); + getCalleePatchpoint->setGenerator( + [=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { + GPRReg result = params[0].gpr(); + MacroAssembler::DataLabelPtr moveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), result); + jit.addLinkTask([calleeMoveLocation, moveLocation] (LinkBuffer& linkBuffer) { + *calleeMoveLocation = linkBuffer.locationOf(moveLocation); + }); + }); + + B3::Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin); + B3::Value* offsetOfCallee = block->appendNew<B3::Const64Value>(proc, origin, CallFrameSlot::callee * sizeof(Register)); + block->appendNew<B3::MemoryValue>(proc, B3::Store, origin, + getCalleePatchpoint, + block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer, offsetOfCallee)); + + // FIXME: We shouldn't have to store zero into the CodeBlock* spot in the call frame, + // but there are places that interpret non-null CodeBlock slot to mean a valid CodeBlock. + // When doing unwinding, we'll need to verify that the entire runtime is OK with a non-null + // CodeBlock not implying that the CodeBlock is valid. + // https://bugs.webkit.org/show_bug.cgi?id=165321 + B3::Value* offsetOfCodeBlock = block->appendNew<B3::Const64Value>(proc, origin, CallFrameSlot::codeBlock * sizeof(Register)); + block->appendNew<B3::MemoryValue>(proc, B3::Store, origin, + block->appendNew<B3::Const64Value>(proc, origin, 0), + block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer, offsetOfCodeBlock)); + } + + template<typename Functor> + void loadArguments(const Signature* signature, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const + { + B3::Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin); + + size_t gpArgumentCount = 0; + size_t fpArgumentCount = 0; + size_t stackOffset = headerSize; + + for (size_t i = 0; i < signature->argumentCount(); ++i) { + B3::Type type = toB3Type(signature->argument(i)); + B3::Value* argument; + B3::ValueRep rep = marshallArgument(type, gpArgumentCount, fpArgumentCount, stackOffset); + if (rep.isReg()) { + argument = block->appendNew<B3::ArgumentRegValue>(proc, origin, rep.reg()); + if (type == B3::Int32 || type == B3::Float) + argument = block->appendNew<B3::Value>(proc, B3::Trunc, origin, argument); + } else { + ASSERT(rep.isStackArgument()); + B3::Value* address = block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer, + block->appendNew<B3::Const64Value>(proc, origin, rep.offsetFromSP())); + argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, type, origin, address); + } + functor(argument, i); + } + } + + // It's expected that the pachpointFunctor sets the generator for the call operation. + template<typename Functor> + B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const + { + size_t gpArgumentCount = 0; + size_t fpArgumentCount = 0; + size_t stackOffset = headerSize - sizeof(CallerFrameAndPC); + + Vector<B3::ConstrainedValue> constrainedArguments; + for (B3::Value* argument : arguments) { + B3::ValueRep rep = marshallArgument(argument->type(), gpArgumentCount, fpArgumentCount, stackOffset); + constrainedArguments.append(B3::ConstrainedValue(argument, rep)); + } + + proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), stackOffset)); + + B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin); + patchpoint->clobberEarly(RegisterSet::macroScratchRegisters()); + patchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall()); + patchpointFunctor(patchpoint); + patchpoint->appendVector(constrainedArguments); + + switch (returnType) { + case B3::Void: + return nullptr; + case B3::Float: + case B3::Double: + patchpoint->resultConstraint = B3::ValueRep::reg(FPRInfo::returnValueFPR); + break; + case B3::Int32: + case B3::Int64: + patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR); + break; + } + return patchpoint; + } + + const Vector<Reg> m_gprArgs; + const Vector<Reg> m_fprArgs; + const RegisterSet m_calleeSaveRegisters; + const RegisterSet m_callerSaveRegisters; +}; + +inline unsigned nextJSCOffset(unsigned currentOffset, B3::Type) +{ + return currentOffset + sizeof(Register); +} + +constexpr unsigned jscHeaderSize = ExecState::headerSizeInRegisters * sizeof(Register); +typedef CallingConvention<jscHeaderSize, nextJSCOffset> JSCCallingConvention; + +typedef JSCCallingConvention WasmCallingConvention; + +const JSCCallingConvention& jscCallingConvention(); +const WasmCallingConvention& wasmCallingConvention(); + +} } // namespace JSC::Wasm + +#endif // ENABLE(WEBASSEMBLY) |