/ wasm / WasmThunks.cpp
WasmThunks.cpp
  1  /*
  2   * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #include "config.h"
 27  #include "WasmThunks.h"
 28  
 29  #if ENABLE(WEBASSEMBLY)
 30  
 31  #include "CCallHelpers.h"
 32  #include "LinkBuffer.h"
 33  #include "ScratchRegisterAllocator.h"
 34  #include "WasmExceptionType.h"
 35  #include "WasmInstance.h"
 36  #include "WasmOperations.h"
 37  
 38  namespace JSC { namespace Wasm {
 39  
 40  MacroAssemblerCodeRef<JITThunkPtrTag> throwExceptionFromWasmThunkGenerator(const AbstractLocker&)
 41  {
 42      CCallHelpers jit;
 43  
 44      // The thing that jumps here must move ExceptionType into the argumentGPR1 before jumping here.
 45      // We're allowed to use temp registers here. We are not allowed to use callee saves.
 46      jit.loadWasmContextInstance(GPRInfo::argumentGPR2);
 47      jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
 48      jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
 49      jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
 50      jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
 51  
 52      CCallHelpers::Call call = jit.call(OperationPtrTag);
 53      jit.farJump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
 54      jit.breakpoint(); // We should not reach this.
 55  
 56      LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
 57      linkBuffer.link(call, FunctionPtr<OperationPtrTag>(operationWasmToJSException));
 58      return FINALIZE_WASM_CODE(linkBuffer, JITThunkPtrTag, "Throw exception from Wasm");
 59  }
 60  
 61  MacroAssemblerCodeRef<JITThunkPtrTag> throwStackOverflowFromWasmThunkGenerator(const AbstractLocker& locker)
 62  {
 63      CCallHelpers jit;
 64  
 65      int32_t stackSpace = WTF::roundUpToMultipleOf(stackAlignmentBytes(), RegisterSet::calleeSaveRegisters().numberOfSetRegisters() * sizeof(Register));
 66      ASSERT(static_cast<unsigned>(stackSpace) < Options::softReservedZoneSize());
 67      jit.addPtr(CCallHelpers::TrustedImm32(-stackSpace), GPRInfo::callFrameRegister, MacroAssembler::stackPointerRegister);
 68      jit.move(CCallHelpers::TrustedImm32(static_cast<uint32_t>(ExceptionType::StackOverflow)), GPRInfo::argumentGPR1);
 69      auto jumpToExceptionHandler = jit.jump();
 70      LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
 71      linkBuffer.link(jumpToExceptionHandler, CodeLocationLabel<JITThunkPtrTag>(Thunks::singleton().stub(locker, throwExceptionFromWasmThunkGenerator).code()));
 72      return FINALIZE_WASM_CODE(linkBuffer, JITThunkPtrTag, "Throw stack overflow from Wasm");
 73  }
 74  
 75  MacroAssemblerCodeRef<JITThunkPtrTag> triggerOMGEntryTierUpThunkGenerator(const AbstractLocker&)
 76  {
 77      // We expect that the user has already put the function index into GPRInfo::argumentGPR1
 78      CCallHelpers jit;
 79  
 80      jit.emitFunctionPrologue();
 81  
 82      const unsigned extraPaddingBytes = 0;
 83      RegisterSet registersToSpill = RegisterSet::allRegisters();
 84      registersToSpill.exclude(RegisterSet::registersToNotSaveForCCall());
 85      unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(jit, registersToSpill, extraPaddingBytes);
 86  
 87      jit.loadWasmContextInstance(GPRInfo::argumentGPR0);
 88      jit.move(MacroAssembler::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationWasmTriggerTierUpNow)), GPRInfo::argumentGPR2);
 89      jit.call(GPRInfo::argumentGPR2, OperationPtrTag);
 90  
 91      ScratchRegisterAllocator::restoreRegistersFromStackForCall(jit, registersToSpill, RegisterSet(), numberOfStackBytesUsedForRegisterPreservation, extraPaddingBytes);
 92  
 93      jit.emitFunctionEpilogue();
 94      jit.ret();
 95      LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
 96      return FINALIZE_WASM_CODE(linkBuffer, JITThunkPtrTag, "Trigger OMG entry tier up");
 97  }
 98  
 99  static Thunks* thunks;
100  void Thunks::initialize()
101  {
102      thunks = new Thunks;
103  }
104  
105  Thunks& Thunks::singleton()
106  {
107      ASSERT(thunks);
108      return *thunks;
109  }
110  
111  MacroAssemblerCodeRef<JITThunkPtrTag> Thunks::stub(ThunkGenerator generator)
112  {
113      auto locker = holdLock(m_lock);
114      return stub(locker, generator);
115  }
116  
117  MacroAssemblerCodeRef<JITThunkPtrTag> Thunks::stub(const AbstractLocker& locker, ThunkGenerator generator)
118  {
119      ASSERT(!!generator);
120      {
121          auto addResult = m_stubs.add(generator, MacroAssemblerCodeRef<JITThunkPtrTag>());
122          if (!addResult.isNewEntry)
123              return addResult.iterator->value;
124      }
125  
126      MacroAssemblerCodeRef<JITThunkPtrTag> code = generator(locker);
127      // We specifically don't use the iterator here to allow generator to recursively change m_stubs.
128      m_stubs.set(generator, code);
129      return code;
130  }
131  
132  MacroAssemblerCodeRef<JITThunkPtrTag> Thunks::existingStub(ThunkGenerator generator)
133  {
134      auto locker = holdLock(m_lock);
135  
136      auto iter = m_stubs.find(generator);
137      if (iter != m_stubs.end())
138          return iter->value;
139  
140      return MacroAssemblerCodeRef<JITThunkPtrTag>();
141  }
142  
143  } } // namespace JSC::Wasm
144  
145  #endif // ENABLE(WEBASSEMBLY)