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/bytecode/GetterSetterAccessCase.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp')
-rw-r--r-- | Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp b/Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp new file mode 100644 index 000000000..9b6bccc29 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "config.h" +#include "GetterSetterAccessCase.h" + +#if ENABLE(JIT) + +#include "DOMJITAccessCasePatchpointParams.h" +#include "DOMJITCallDOMGetterPatchpoint.h" +#include "DOMJITGetterSetter.h" +#include "HeapInlines.h" +#include "JSCJSValueInlines.h" +#include "PolymorphicAccess.h" +#include "StructureStubInfo.h" + +namespace JSC { + +static const bool verbose = false; + +GetterSetterAccessCase::GetterSetterAccessCase(VM& vm, JSCell* owner, AccessType accessType, PropertyOffset offset, Structure* structure, const ObjectPropertyConditionSet& conditionSet, bool viaProxy, WatchpointSet* additionalSet, JSObject* customSlotBase) + : Base(vm, owner, accessType, offset, structure, conditionSet, viaProxy, additionalSet) +{ + m_customSlotBase.setMayBeNull(vm, owner, customSlotBase); +} + + +std::unique_ptr<AccessCase> GetterSetterAccessCase::create( + VM& vm, JSCell* owner, AccessType type, PropertyOffset offset, Structure* structure, + const ObjectPropertyConditionSet& conditionSet, bool viaProxy, WatchpointSet* additionalSet, + PropertySlot::GetValueFunc customGetter, JSObject* customSlotBase, DOMJIT::GetterSetter* domJIT) +{ + switch (type) { + case Getter: + case CustomAccessorGetter: + case CustomValueGetter: + break; + default: + ASSERT_NOT_REACHED(); + }; + + std::unique_ptr<GetterSetterAccessCase> result(new GetterSetterAccessCase(vm, owner, type, offset, structure, conditionSet, viaProxy, additionalSet, customSlotBase)); + result->m_domJIT = domJIT; + result->m_customAccessor.getter = customGetter; + return WTFMove(result); +} + +std::unique_ptr<AccessCase> GetterSetterAccessCase::create(VM& vm, JSCell* owner, AccessType type, Structure* structure, PropertyOffset offset, + const ObjectPropertyConditionSet& conditionSet, PutPropertySlot::PutValueFunc customSetter, + JSObject* customSlotBase) +{ + ASSERT(type == Setter || type == CustomValueSetter || type == CustomAccessorSetter); + std::unique_ptr<GetterSetterAccessCase> result(new GetterSetterAccessCase(vm, owner, type, offset, structure, conditionSet, false, nullptr, customSlotBase)); + result->m_customAccessor.setter = customSetter; + return WTFMove(result); +} + + +GetterSetterAccessCase::~GetterSetterAccessCase() +{ +} + + +GetterSetterAccessCase::GetterSetterAccessCase(const GetterSetterAccessCase& other) + : Base(other) + , m_customSlotBase(other.m_customSlotBase) +{ + m_customAccessor.opaque = other.m_customAccessor.opaque; + m_domJIT = other.m_domJIT; +} + +std::unique_ptr<AccessCase> GetterSetterAccessCase::clone() const +{ + std::unique_ptr<GetterSetterAccessCase> result(new GetterSetterAccessCase(*this)); + result->resetState(); + return WTFMove(result); +} + +JSObject* GetterSetterAccessCase::alternateBase() const +{ + if (customSlotBase()) + return customSlotBase(); + return conditionSet().slotBaseCondition().object(); +} + +void GetterSetterAccessCase::dumpImpl(PrintStream& out, CommaPrinter& comma) const +{ + Base::dumpImpl(out, comma); + out.print(comma, "customSlotBase = ", RawPointer(customSlotBase())); + if (callLinkInfo()) + out.print(comma, "callLinkInfo = ", RawPointer(callLinkInfo())); + out.print(comma, "customAccessor = ", RawPointer(m_customAccessor.opaque)); +} + +void GetterSetterAccessCase::emitDOMJITGetter(AccessGenerationState& state, GPRReg baseForGetGPR) +{ + CCallHelpers& jit = *state.jit; + StructureStubInfo& stubInfo = *state.stubInfo; + JSValueRegs valueRegs = state.valueRegs; + GPRReg baseGPR = state.baseGPR; + GPRReg scratchGPR = state.scratchGPR; + + // We construct the environment that can execute the DOMJIT::Patchpoint here. + Ref<DOMJIT::CallDOMGetterPatchpoint> patchpoint = domJIT()->callDOMGetter(); + + Vector<GPRReg> gpScratch; + Vector<FPRReg> fpScratch; + Vector<DOMJIT::Value> regs; + + ScratchRegisterAllocator allocator(stubInfo.patch.usedRegisters); + allocator.lock(baseGPR); +#if USE(JSVALUE32_64) + allocator.lock(static_cast<GPRReg>(stubInfo.patch.baseTagGPR)); +#endif + allocator.lock(valueRegs); + allocator.lock(scratchGPR); + + GPRReg paramBaseGPR = InvalidGPRReg; + GPRReg paramGlobalObjectGPR = InvalidGPRReg; + JSValueRegs paramValueRegs = valueRegs; + GPRReg remainingScratchGPR = InvalidGPRReg; + + // valueRegs and baseForGetGPR may be the same. For example, in Baseline JIT, we pass the same regT0 for baseGPR and valueRegs. + // In FTL, there is no constraint that the baseForGetGPR interferes with the result. To make implementation simple in + // DOMJIT::Patchpoint, DOMJIT::Patchpoint assumes that result registers always early interfere with input registers, in this case, + // baseForGetGPR. So we move baseForGetGPR to the other register if baseForGetGPR == valueRegs. + if (baseForGetGPR != valueRegs.payloadGPR()) { + paramBaseGPR = baseForGetGPR; + if (!patchpoint->requireGlobalObject) + remainingScratchGPR = scratchGPR; + else + paramGlobalObjectGPR = scratchGPR; + } else { + jit.move(valueRegs.payloadGPR(), scratchGPR); + paramBaseGPR = scratchGPR; + if (patchpoint->requireGlobalObject) + paramGlobalObjectGPR = allocator.allocateScratchGPR(); + } + + JSGlobalObject* globalObjectForDOMJIT = structure()->globalObject(); + + regs.append(paramValueRegs); + regs.append(paramBaseGPR); + if (patchpoint->requireGlobalObject) { + ASSERT(paramGlobalObjectGPR != InvalidGPRReg); + regs.append(DOMJIT::Value(paramGlobalObjectGPR, globalObjectForDOMJIT)); + } + + if (patchpoint->numGPScratchRegisters) { + unsigned i = 0; + if (remainingScratchGPR != InvalidGPRReg) { + gpScratch.append(remainingScratchGPR); + ++i; + } + for (; i < patchpoint->numGPScratchRegisters; ++i) + gpScratch.append(allocator.allocateScratchGPR()); + } + + for (unsigned i = 0; i < patchpoint->numFPScratchRegisters; ++i) + fpScratch.append(allocator.allocateScratchFPR()); + + // Let's store the reused registers to the stack. After that, we can use allocated scratch registers. + ScratchRegisterAllocator::PreservedState preservedState = + allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall); + + if (verbose) { + dataLog("baseGPR = ", baseGPR, "\n"); + dataLog("valueRegs = ", valueRegs, "\n"); + dataLog("scratchGPR = ", scratchGPR, "\n"); + dataLog("paramBaseGPR = ", paramBaseGPR, "\n"); + if (paramGlobalObjectGPR != InvalidGPRReg) + dataLog("paramGlobalObjectGPR = ", paramGlobalObjectGPR, "\n"); + dataLog("paramValueRegs = ", paramValueRegs, "\n"); + for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i) + dataLog("gpScratch[", i, "] = ", gpScratch[i], "\n"); + } + + if (patchpoint->requireGlobalObject) + jit.move(CCallHelpers::TrustedImmPtr(globalObjectForDOMJIT), paramGlobalObjectGPR); + + // We just spill the registers used in DOMJIT::Patchpoint here. For not spilled registers here explicitly, + // they must be in the used register set passed by the callers (Baseline, DFG, and FTL) if they need to be kept. + // Some registers can be locked, but not in the used register set. For example, the caller could make baseGPR + // same to valueRegs, and not include it in the used registers since it will be changed. + RegisterSet registersToSpillForCCall; + for (auto& value : regs) { + DOMJIT::Reg reg = value.reg(); + if (reg.isJSValueRegs()) + registersToSpillForCCall.set(reg.jsValueRegs()); + else if (reg.isGPR()) + registersToSpillForCCall.set(reg.gpr()); + else + registersToSpillForCCall.set(reg.fpr()); + } + for (GPRReg reg : gpScratch) + registersToSpillForCCall.set(reg); + for (FPRReg reg : fpScratch) + registersToSpillForCCall.set(reg); + registersToSpillForCCall.exclude(RegisterSet::registersToNotSaveForCCall()); + + DOMJITAccessCasePatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch)); + patchpoint->generator()->run(jit, params); + allocator.restoreReusedRegistersByPopping(jit, preservedState); + state.succeed(); + + CCallHelpers::JumpList exceptions = params.emitSlowPathCalls(state, registersToSpillForCCall, jit); + if (!exceptions.empty()) { + exceptions.link(&jit); + allocator.restoreReusedRegistersByPopping(jit, preservedState); + state.emitExplicitExceptionHandler(); + } +} + +} // namespace JSC + +#endif // ENABLE(JIT) |