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/b3/air/AirCustom.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/b3/air/AirCustom.h')
-rw-r--r-- | Source/JavaScriptCore/b3/air/AirCustom.h | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/b3/air/AirCustom.h b/Source/JavaScriptCore/b3/air/AirCustom.h new file mode 100644 index 000000000..cddc03857 --- /dev/null +++ b/Source/JavaScriptCore/b3/air/AirCustom.h @@ -0,0 +1,328 @@ +/* + * 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(B3_JIT) + +#include "AirCode.h" +#include "AirGenerationContext.h" +#include "AirInst.h" +#include "AirSpecial.h" +#include "B3ValueInlines.h" +#include "B3WasmBoundsCheckValue.h" + +namespace JSC { namespace B3 { namespace Air { + +// This defines the behavior of custom instructions - i.e. those whose behavior cannot be +// described using AirOpcode.opcodes. If you define an opcode as "custom Foo" in that file, then +// you will need to create a "struct FooCustom" here that implements the custom behavior +// methods. +// +// The customizability granted by the custom instruction mechanism is strictly less than what +// you get using the Patch instruction and implementing a Special. However, that path requires +// allocating a Special object and ensuring that it's the first operand. For many instructions, +// that is not as convenient as using Custom, which makes the instruction look like any other +// instruction. Note that both of those extra powers of the Patch instruction happen because we +// special-case that instruction in many phases and analyses. Non-special-cased behaviors of +// Patch are implemented using the custom instruction mechanism. +// +// Specials are still more flexible if you need to list extra clobbered registers and you'd like +// that to be expressed as a bitvector rather than an arglist. They are also more flexible if +// you need to carry extra state around with the instruction. Also, Specials mean that you +// always have access to Code& even in methods that don't take a GenerationContext. + +// Definition of Patch instruction. Patch is used to delegate the behavior of the instruction to the +// Special object, which will be the first argument to the instruction. +struct PatchCustom { + template<typename Functor> + static void forEachArg(Inst& inst, const Functor& functor) + { + // This is basically bogus, but it works for analyses that model Special as an + // immediate. + functor(inst.args[0], Arg::Use, Arg::GP, Arg::pointerWidth()); + + inst.args[0].special()->forEachArg(inst, scopedLambda<Inst::EachArgCallback>(functor)); + } + + template<typename... Arguments> + static bool isValidFormStatic(Arguments...) + { + return false; + } + + static bool isValidForm(Inst& inst); + + static bool admitsStack(Inst& inst, unsigned argIndex) + { + if (!argIndex) + return false; + return inst.args[0].special()->admitsStack(inst, argIndex); + } + + static std::optional<unsigned> shouldTryAliasingDef(Inst& inst) + { + return inst.args[0].special()->shouldTryAliasingDef(inst); + } + + static bool isTerminal(Inst& inst) + { + return inst.args[0].special()->isTerminal(inst); + } + + static bool hasNonArgEffects(Inst& inst) + { + return inst.args[0].special()->hasNonArgEffects(inst); + } + + static bool hasNonArgNonControlEffects(Inst& inst) + { + return inst.args[0].special()->hasNonArgNonControlEffects(inst); + } + + static CCallHelpers::Jump generate( + Inst& inst, CCallHelpers& jit, GenerationContext& context) + { + return inst.args[0].special()->generate(inst, jit, context); + } +}; + +template<typename Subtype> +struct CommonCustomBase { + static bool hasNonArgEffects(Inst& inst) + { + return Subtype::isTerminal(inst) || Subtype::hasNonArgNonControlEffects(inst); + } +}; + +// Definition of CCall instruction. CCall is used for hot path C function calls. It's lowered to a +// Patch with an Air CCallSpecial along with code to marshal instructions. The lowering happens +// before register allocation, so that the register allocator sees the clobbers. +struct CCallCustom : public CommonCustomBase<CCallCustom> { + template<typename Functor> + static void forEachArg(Inst& inst, const Functor& functor) + { + Value* value = inst.origin; + + unsigned index = 0; + + functor(inst.args[index++], Arg::Use, Arg::GP, Arg::pointerWidth()); // callee + + if (value->type() != Void) { + functor( + inst.args[index++], Arg::Def, + Arg::typeForB3Type(value->type()), + Arg::widthForB3Type(value->type())); + } + + for (unsigned i = 1; i < value->numChildren(); ++i) { + Value* child = value->child(i); + functor( + inst.args[index++], Arg::Use, + Arg::typeForB3Type(child->type()), + Arg::widthForB3Type(child->type())); + } + } + + template<typename... Arguments> + static bool isValidFormStatic(Arguments...) + { + return false; + } + + static bool isValidForm(Inst&); + + static bool admitsStack(Inst&, unsigned) + { + return true; + } + + static bool isTerminal(Inst&) + { + return false; + } + + static bool hasNonArgNonControlEffects(Inst&) + { + return true; + } + + // This just crashes, since we expect C calls to be lowered before generation. + static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&); +}; + +struct ColdCCallCustom : CCallCustom { + template<typename Functor> + static void forEachArg(Inst& inst, const Functor& functor) + { + // This is just like a call, but uses become cold. + CCallCustom::forEachArg( + inst, + [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) { + functor(arg, Arg::cooled(role), type, width); + }); + } +}; + +struct ShuffleCustom : public CommonCustomBase<ShuffleCustom> { + template<typename Functor> + static void forEachArg(Inst& inst, const Functor& functor) + { + unsigned limit = inst.args.size() / 3 * 3; + for (unsigned i = 0; i < limit; i += 3) { + Arg& src = inst.args[i + 0]; + Arg& dst = inst.args[i + 1]; + Arg& widthArg = inst.args[i + 2]; + Arg::Width width = widthArg.width(); + Arg::Type type = src.isGP() && dst.isGP() ? Arg::GP : Arg::FP; + functor(src, Arg::Use, type, width); + functor(dst, Arg::Def, type, width); + functor(widthArg, Arg::Use, Arg::GP, Arg::Width8); + } + } + + template<typename... Arguments> + static bool isValidFormStatic(Arguments...) + { + return false; + } + + static bool isValidForm(Inst&); + + static bool admitsStack(Inst&, unsigned index) + { + switch (index % 3) { + case 0: + case 1: + return true; + default: + return false; + } + } + + static bool isTerminal(Inst&) + { + return false; + } + + static bool hasNonArgNonControlEffects(Inst&) + { + return false; + } + + static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&); +}; + +struct EntrySwitchCustom : public CommonCustomBase<EntrySwitchCustom> { + template<typename Func> + static void forEachArg(Inst&, const Func&) + { + } + + template<typename... Arguments> + static bool isValidFormStatic(Arguments...) + { + return !sizeof...(Arguments); + } + + static bool isValidForm(Inst& inst) + { + return inst.args.isEmpty(); + } + + static bool admitsStack(Inst&, unsigned) + { + return false; + } + + static bool isTerminal(Inst&) + { + return true; + } + + static bool hasNonArgNonControlEffects(Inst&) + { + return false; + } + + static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&) + { + // This should never be reached because we should have lowered EntrySwitch before + // generation. + UNREACHABLE_FOR_PLATFORM(); + return CCallHelpers::Jump(); + } +}; + +struct WasmBoundsCheckCustom : public CommonCustomBase<WasmBoundsCheckCustom> { + template<typename Func> + static void forEachArg(Inst& inst, const Func& functor) + { + functor(inst.args[0], Arg::Use, Arg::GP, Arg::Width64); + functor(inst.args[1], Arg::Use, Arg::GP, Arg::Width64); + } + + template<typename... Arguments> + static bool isValidFormStatic(Arguments...) + { + return false; + } + + static bool isValidForm(Inst&); + + static bool admitsStack(Inst&, unsigned) + { + return false; + } + + static bool isTerminal(Inst&) + { + return false; + } + + static bool hasNonArgNonControlEffects(Inst&) + { + return true; + } + + static CCallHelpers::Jump generate(Inst& inst, CCallHelpers& jit, GenerationContext& context) + { + WasmBoundsCheckValue* value = inst.origin->as<WasmBoundsCheckValue>(); + CCallHelpers::Jump outOfBounds = Inst(Air::Branch64, value, Arg::relCond(CCallHelpers::AboveOrEqual), inst.args[0], inst.args[1]).generate(jit, context); + + context.latePaths.append(createSharedTask<GenerationContext::LatePathFunction>( + [outOfBounds, value] (CCallHelpers& jit, Air::GenerationContext& context) { + outOfBounds.link(&jit); + context.code->wasmBoundsCheckGenerator()->run(jit, value->pinnedGPR(), value->offset()); + })); + + // We said we were not a terminal. + return CCallHelpers::Jump(); + } +}; + +} } } // namespace JSC::B3::Air + +#endif // ENABLE(B3_JIT) |