Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  InterpreterEntryTrampoline.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "jit/InterpreterEntryTrampoline.h"
#include "jit/JitRuntime.h"
#include "jit/Linker.h"
#include "vm/Interpreter.h"

#include "gc/Marking-inl.h"
#include "jit/MacroAssembler-inl.h"

using namespace js;
using namespace js::jit;

void js::ClearInterpreterEntryMap(JSRuntime* runtime) {
  if (runtime->hasJitRuntime() &&
      runtime->jitRuntime()->hasInterpreterEntryMap()) {
    runtime->jitRuntime()->getInterpreterEntryMap()->clear();
  }
}

void EntryTrampolineMap::traceTrampolineCode(JSTracer* trc) {
  for (jit::EntryTrampolineMap::Enum e(*this); !e.empty(); e.popFront()) {
    EntryTrampoline& trampoline = e.front().value();
    trampoline.trace(trc);
  }
}

void EntryTrampolineMap::updateScriptsAfterMovingGC(void) {
  for (jit::EntryTrampolineMap::Enum e(*this); !e.empty(); e.popFront()) {
    BaseScript* script = e.front().key();
    if (IsForwarded(script)) {
      script = Forwarded(script);
      e.rekeyFront(script);
    }
  }
}

#ifdef JSGC_HASH_TABLE_CHECKS
void EntryTrampoline::checkTrampolineAfterMovingGC() const {
  JitCode* trampoline = entryTrampoline_;
  CheckGCThingAfterMovingGC(trampoline);
}

void EntryTrampolineMap::checkScriptsAfterMovingGC() {
  gc::CheckTableAfterMovingGC(*this, [](const auto& entry) {
    BaseScript* script = entry.key();
    CheckGCThingAfterMovingGC(script);
    entry.value().checkTrampolineAfterMovingGC();
    return script;
  });
}
#endif

void JitRuntime::generateBaselineInterpreterEntryTrampoline(
    MacroAssembler& masm) {
  AutoCreatedBy acb(masm,
                    "JitRuntime::generateBaselineInterpreterEntryTrampoline");

#ifdef JS_USE_LINK_REGISTER
  masm.pushReturnAddress();
#endif
  masm.push(FramePointer);
  masm.moveStackPtrTo(FramePointer);

  AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
  Register nargs = regs.takeAny();
  Register callee = regs.takeAny();
  Register scratch = regs.takeAny();

  // Load callee token and keep it in a register as it will be used often
  Address calleeTokenAddr(
      FramePointer, BaselineInterpreterEntryFrameLayout::offsetOfCalleeToken());
  masm.loadPtr(calleeTokenAddr, callee);

  // Load argc into nargs.
  masm.loadNumActualArgs(FramePointer, nargs);

  Label notFunction;
  {
    // Check if calleetoken is script or function
    masm.branchTestPtr(Assembler::NonZero, callee, Imm32(CalleeTokenScriptBit),
                       ¬Function);

    // CalleeToken is a function, load |nformals| into scratch
    masm.movePtr(callee, scratch);
    masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), scratch);
    masm.loadFunctionArgCount(scratch, scratch);

    // Take max(nformals, argc).
    Label noUnderflow;
    masm.branch32(Assembler::AboveOrEqual, nargs, scratch, &noUnderflow);
    { masm.movePtr(scratch, nargs); }
    masm.bind(&noUnderflow);

    // Add 1 to nargs if constructing.
    static_assert(
        CalleeToken_FunctionConstructing == 1,
        "Ensure that we can use the constructing bit to count the value");
    masm.movePtr(callee, scratch);
    masm.and32(Imm32(uint32_t(CalleeToken_FunctionConstructing)), scratch);
    masm.addPtr(scratch, nargs);
  }
  masm.bind(¬Function);

  // Align stack
  masm.alignJitStackBasedOnNArgs(nargs, /*countIncludesThis = */ false);

  // Point argPtr to the topmost argument.
  static_assert(sizeof(Value) == 8,
                "Using TimesEight for scale of sizeof(Value).");
  BaseIndex topPtrAddr(FramePointer, nargs, TimesEight,
                       sizeof(BaselineInterpreterEntryFrameLayout));
  Register argPtr = nargs;
  masm.computeEffectiveAddress(topPtrAddr, argPtr);

  // Load the end address into scratch, which is the callee token.
  masm.computeEffectiveAddress(calleeTokenAddr, scratch);

  // Copy |this|+arguments
  Label loop;
  masm.bind(&loop);
  {
    masm.pushValue(Address(argPtr, 0));
    masm.subPtr(Imm32(sizeof(Value)), argPtr);
    masm.branchPtr(Assembler::Above, argPtr, scratch, &loop);
  }

  // Copy callee token
  masm.push(callee);

  // Save a new descriptor using BaselineInterpreterEntry frame type.
  masm.loadNumActualArgs(FramePointer, scratch);
  masm.pushFrameDescriptorForJitCall(FrameType::BaselineInterpreterEntry,
                                     scratch, scratch);

  // Call into baseline interpreter
  uint8_t* blinterpAddr = baselineInterpreter().codeRaw();
  masm.assertStackAlignment(JitStackAlignment, 2 * sizeof(uintptr_t));
  masm.call(ImmPtr(blinterpAddr));

  masm.moveToStackPtr(FramePointer);
  masm.pop(FramePointer);
  masm.ret();
}

void JitRuntime::generateInterpreterEntryTrampoline(MacroAssembler& masm) {
  AutoCreatedBy acb(masm, "JitRuntime::generateInterpreterEntryTrampoline");

  // If BLI is disabled, we don't need an offset.
  if (IsBaselineInterpreterEnabled()) {
    uint32_t offset = startTrampolineCode(masm);
    if (!vmInterpreterEntryOffset_) {
      vmInterpreterEntryOffset_ = offset;
    }
  }

#ifdef JS_CODEGEN_ARM64
  // Use the normal stack pointer for the initial pushes.
  masm.SetStackPointer64(sp);

  // Push lr and fp together to maintain 16-byte alignment.
  masm.push(lr, FramePointer);
  masm.moveStackPtrTo(FramePointer);

  // Save the PSP register (r28), and a scratch (r19).
  masm.push(r19, r28);

  // Setup the PSP so we can use callWithABI below.
  masm.SetStackPointer64(PseudoStackPointer64);
  masm.initPseudoStackPtr();

  Register arg0 = IntArgReg0;
  Register arg1 = IntArgReg1;
  Register scratch = r19;
#elif defined(JS_CODEGEN_X86)
  masm.push(FramePointer);
  masm.moveStackPtrTo(FramePointer);

  AllocatableRegisterSet regs(RegisterSet::Volatile());
  Register arg0 = regs.takeAnyGeneral();
  Register arg1 = regs.takeAnyGeneral();
  Register scratch = regs.takeAnyGeneral();

  // First two arguments are passed on the stack in 32-bit.
  Address cxAddr(FramePointer, 2 * sizeof(void*));
  Address stateAddr(FramePointer, 3 * sizeof(void*));
  masm.loadPtr(cxAddr, arg0);
  masm.loadPtr(stateAddr, arg1);
#else
  masm.push(FramePointer);
  masm.moveStackPtrTo(FramePointer);

  AllocatableRegisterSet regs(RegisterSet::Volatile());
  regs.take(IntArgReg0);
  regs.take(IntArgReg1);
  Register arg0 = IntArgReg0;
  Register arg1 = IntArgReg1;
  Register scratch = regs.takeAnyGeneral();
#endif

  using Fn = bool (*)(JSContext* cx, js::RunState& state);
  masm.setupUnalignedABICall(scratch);
  masm.passABIArg(arg0);  // cx
  masm.passABIArg(arg1);  // state
  masm.callWithABI<Fn, Interpret>(
      ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame);

#ifdef JS_CODEGEN_ARM64
  masm.syncStackPtr();
  masm.SetStackPointer64(sp);

  // Restore r28 and r19.
  masm.pop(r28, r19);

  // Restore old fp and pop lr for return.
  masm.pop(FramePointer, lr);
  masm.abiret();

  // Reset stack pointer.
  masm.SetStackPointer64(PseudoStackPointer64);
#else
  masm.moveToStackPtr(FramePointer);
  masm.pop(FramePointer);
  masm.ret();
#endif
}

JitCode* JitRuntime::generateEntryTrampolineForScript(JSContext* cx,
                                                      JSScript* script) {
  if (JitSpewEnabled(JitSpew_Codegen)) {
    UniqueChars funName;
    if (script->function() && script->function()->fullDisplayAtom()) {
      funName =
          AtomToPrintableString(cx, script->function()->fullDisplayAtom());
    }

    JitSpew(JitSpew_Codegen,
            "# Emitting Interpreter Entry Trampoline for %s (%s:%u:%u)",
            funName ? funName.get() : "*", script->filename(), script->lineno(),
            script->column().oneOriginValue());
  }

  TempAllocator temp(&cx->tempLifoAlloc());
  JitContext jctx(cx);
  StackMacroAssembler masm(cx, temp);
  AutoCreatedBy acb(masm, "JitRuntime::generateEntryTrampolineForScript");
  PerfSpewerRangeRecorder rangeRecorder(masm);

  if (IsBaselineInterpreterEnabled()) {
    generateBaselineInterpreterEntryTrampoline(masm);
    rangeRecorder.recordOffset("BaselineInterpreter", cx, script);
  }

  generateInterpreterEntryTrampoline(masm);
  rangeRecorder.recordOffset("Interpreter", cx, script);

  Linker linker(masm);
  JitCode* code = linker.newCode(cx, CodeKind::Other);
  if (!code) {
    return nullptr;
  }
  rangeRecorder.collectRangesForJitCode(code);
  JitSpew(JitSpew_Codegen, "# code = %p", code->raw());
  return code;
}

Messung V0.5
C=88 H=97 G=92

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge