DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
/* -*- 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/. */

#ifndef jit_CodeGenerator_h
#define jit_CodeGenerator_h

#include "jit/CacheIR.h"
#if defined(JS_ION_PERF)
#  include "jit/PerfSpewer.h"
#endif

#if defined(JS_CODEGEN_X86)
#  include "jit/x86/CodeGenerator-x86.h"
#elif defined(JS_CODEGEN_X64)
#  include "jit/x64/CodeGenerator-x64.h"
#elif defined(JS_CODEGEN_ARM)
#  include "jit/arm/CodeGenerator-arm.h"
#elif defined(JS_CODEGEN_ARM64)
#  include "jit/arm64/CodeGenerator-arm64.h"
#elif defined(JS_CODEGEN_MIPS32)
#  include "jit/mips32/CodeGenerator-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)
#  include "jit/mips64/CodeGenerator-mips64.h"
#elif defined(JS_CODEGEN_NONE)
#  include "jit/none/CodeGenerator-none.h"
#else
#  error "Unknown architecture!"
#endif

#include "wasm/WasmGC.h"

namespace js {
namespace jit {

template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
class OutOfLineCallVM;

enum class SwitchTableType { Inline, OutOfLine };

template <SwitchTableType tableType>
class OutOfLineSwitch;
class OutOfLineTestObject;
class OutOfLineNewArray;
class OutOfLineNewObject;
class CheckOverRecursedFailure;
class OutOfLineUnboxFloatingPoint;
class OutOfLineStoreElementHole;
class OutOfLineTypeOfV;
class OutOfLineUpdateCache;
class OutOfLineICFallback;
class OutOfLineCallPostWriteBarrier;
class OutOfLineCallPostWriteElementBarrier;
class OutOfLineIsCallable;
class OutOfLineIsConstructor;
class OutOfLineRegExpMatcher;
class OutOfLineRegExpSearcher;
class OutOfLineRegExpTester;
class OutOfLineRegExpPrototypeOptimizable;
class OutOfLineRegExpInstanceOptimizable;
class OutOfLineLambdaArrow;
class OutOfLineNaNToZero;

class CodeGenerator final : public CodeGeneratorSpecific {
  void generateArgumentsChecks(bool assert = false);
  MOZ_MUST_USE bool generateBody();

  ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n,
                                          MIRType type);

#ifdef CHECK_OSIPOINT_REGISTERS
  void resetOsiPointRegs(LSafepoint* safepoint);
  bool shouldVerifyOsiPointRegs(LSafepoint* safepoint);
  void verifyOsiPointRegs(LSafepoint* safepoint);
#endif

  void callVMInternal(VMFunctionId id, LInstruction* ins,
                      const Register* dynStack);

  template <typename Fn, Fn fn>
  void callVM(LInstruction* ins, const Register* dynStack = nullptr);

  template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
  inline OutOfLineCode* oolCallVM(LInstruction* ins, const ArgSeq& args,
                                  const StoreOutputTo& out);

 public:
  CodeGenerator(MIRGenerator* gen, LIRGraph* graph,
                MacroAssembler* masm = nullptr);
  ~CodeGenerator();

  MOZ_MUST_USE bool generate();
  MOZ_MUST_USE bool generateWasm(wasm::FuncTypeIdDesc funcTypeId,
                                 wasm::BytecodeOffset trapOffset,
                                 const wasm::ValTypeVector& argTys,
                                 const MachineState& trapExitLayout,
                                 size_t trapExitLayoutNumWords,
                                 wasm::FuncOffsets* offsets,
                                 wasm::StackMaps* stackMaps);

  MOZ_MUST_USE bool link(JSContext* cx, CompilerConstraintList* constraints);

  void emitOOLTestObject(Register objreg, Label* ifTruthy, Label* ifFalsy,
                         Register scratch);
  void emitIntToString(Register input, Register output, Label* ool);

  template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
  void visitOutOfLineCallVM(
      OutOfLineCallVM<Fn, fn, ArgSeq, StoreOutputTo>* ool);

  void visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool);
  void visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool);
  void visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool);
  void visitOutOfLineRegExpPrototypeOptimizable(
      OutOfLineRegExpPrototypeOptimizable* ool);
  void visitOutOfLineRegExpInstanceOptimizable(
      OutOfLineRegExpInstanceOptimizable* ool);

  void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);

  void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);

  template <SwitchTableType tableType>
  void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);

  void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
  void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);

  void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);

  void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);

  void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool);
  void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool);

  void visitOutOfLineICFallback(OutOfLineICFallback* ool);

  void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
  void visitOutOfLineCallPostWriteElementBarrier(
      OutOfLineCallPostWriteElementBarrier* ool);

  void visitOutOfLineNewArray(OutOfLineNewArray* ool);
  void visitOutOfLineNewObject(OutOfLineNewObject* ool);

 private:
  void emitPostWriteBarrier(const LAllocation* obj);
  void emitPostWriteBarrier(Register objreg);
  void emitPostWriteBarrierS(Address address, Register prev, Register next);

  template <class LPostBarrierType, MIRType nurseryType>
  void visitPostWriteBarrierCommon(LPostBarrierType* lir, OutOfLineCode* ool);
  template <class LPostBarrierType>
  void visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool);

  void emitCallInvokeFunction(LInstruction* call, Register callereg,
                              bool isConstructing, bool ignoresReturnValue,
                              uint32_t argc, uint32_t unusedStack);
  void emitCallInvokeFunctionShuffleNewTarget(LCallKnown* call,
                                              Register calleeReg,
                                              uint32_t numFormals,
                                              uint32_t unusedStack);
  template <typename T>
  void emitApplyGeneric(T* apply);
  template <typename T>
  void emitCallInvokeFunction(T* apply, Register extraStackSize);
  void emitAllocateSpaceForApply(Register argcreg, Register extraStackSpace,
                                 Label* end);
  void emitCopyValuesForApply(Register argvSrcBase, Register argvIndex,
                              Register copyreg, size_t argvSrcOffset,
                              size_t argvDstOffset);
  void emitPopArguments(Register extraStackSize);
  void emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace);
  void emitPushArguments(LApplyArrayGeneric* apply, Register extraStackSpace);

  void visitNewArrayCallVM(LNewArray* lir);
  void visitNewObjectVMCall(LNewObject* lir);

  void emitGetPropertyPolymorphic(LInstruction* lir, Register obj,
                                  Register scratch,
                                  const TypedOrValueRegister& output);
  void emitSetPropertyPolymorphic(LInstruction* lir, Register obj,
                                  Register scratch,
                                  const ConstantOrRegister& value);
  void emitCompareS(LInstruction* lir, JSOp op, Register left, Register right,
                    Register output);
  void emitSameValue(FloatRegister left, FloatRegister right,
                     FloatRegister temp, Register output);

  void emitConcat(LInstruction* lir, Register lhs, Register rhs,
                  Register output);
  template <typename T>
  void emitLoadElementT(LLoadElementT* lir, const T& source);

  template <typename T>
  void emitStoreElementHoleT(T* lir);
  template <typename T>
  void emitStoreElementHoleV(T* lir);

  void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir,
                         Register obj, Register elementsTemp,
                         Register lengthTemp, TypedOrValueRegister out);
  void emitArrayPush(LInstruction* lir, Register obj,
                     const ConstantOrRegister& value, Register elementsTemp,
                     Register length, Register spectreTemp);

  void emitRest(LInstruction* lir, Register array, Register numActuals,
                Register temp0, Register temp1, unsigned numFormals,
                JSObject* templateObject, bool saveAndRestore,
                Register resultreg);
  void emitInstanceOf(LInstruction* ins, JSObject* prototypeObject);

  enum CallableOrConstructor { Callable, Constructor };
  template <CallableOrConstructor mode>
  void emitIsCallableOrConstructor(Register object, Register output,
                                   Label* failure);

  void loadJSScriptForBlock(MBasicBlock* block, Register reg);
  void loadOutermostJSScript(Register reg);

#ifdef DEBUG
  void emitAssertResultV(const ValueOperand output,
                         const TemporaryTypeSet* typeset);
  void emitAssertGCThingResult(Register input, MIRType type,
                               const TemporaryTypeSet* typeset);
#endif

#ifdef DEBUG
  void emitDebugForceBailing(LInstruction* lir);
#endif

  IonScriptCounts* extractScriptCounts() {
    IonScriptCounts* counts = scriptCounts_;
    scriptCounts_ = nullptr;  // prevent delete in dtor
    return counts;
  }

  void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                           TypedOrValueRegister value,
                           const ConstantOrRegister& id,
                           TypedOrValueRegister output, Register maybeTemp,
                           GetPropertyResultFlags flags);
  void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                           Register objReg, Register temp,
                           FloatRegister tempDouble, FloatRegister tempF32,
                           const ConstantOrRegister& id,
                           const ConstantOrRegister& value, bool strict,
                           bool needsPostBarrier, bool needsTypeBarrier,
                           bool guardHoles);

  MOZ_MUST_USE bool generateBranchV(const ValueOperand& value, Label* ifTrue,
                                    Label* ifFalse, FloatRegister fr);

  void emitLambdaInit(Register resultReg, Register envChainReg,
                      const LambdaFunctionInfo& info);

  void emitFilterArgumentsOrEval(LInstruction* lir, Register string,
                                 Register temp1, Register temp2);

  template <class IteratorObject, class OrderedHashTable>
  void emitGetNextEntryForIterator(LGetNextEntryForIterator* lir);

  template <class OrderedHashTable>
  void emitLoadIteratorValues(Register result, Register temp, Register front);

  template <size_t Defs>
  void emitWasmCallBase(LWasmCallBase<Defs>* lir);

  template <size_t NumDefs>
  void emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir);

  IonScriptCounts* maybeCreateScriptCounts();

  // This function behaves like testValueTruthy with the exception that it can
  // choose to let control flow fall through when the object is truthy, as
  // an optimization. Use testValueTruthy when it's required to branch to one
  // of the two labels.
  void testValueTruthyKernel(const ValueOperand& value,
                             const LDefinition* scratch1,
                             const LDefinition* scratch2, FloatRegister fr,
                             Label* ifTruthy, Label* ifFalsy,
                             OutOfLineTestObject* ool, MDefinition* valueMIR);

  // Test whether value is truthy or not and jump to the corresponding label.
  // If the value can be an object that emulates |undefined|, |ool| must be
  // non-null; otherwise it may be null (and the scratch definitions should
  // be bogus), in which case an object encountered here will always be
  // truthy.
  void testValueTruthy(const ValueOperand& value, const LDefinition* scratch1,
                       const LDefinition* scratch2, FloatRegister fr,
                       Label* ifTruthy, Label* ifFalsy,
                       OutOfLineTestObject* ool, MDefinition* valueMIR);

  // This function behaves like testObjectEmulatesUndefined with the exception
  // that it can choose to let control flow fall through when the object
  // doesn't emulate undefined, as an optimization. Use the regular
  // testObjectEmulatesUndefined when it's required to branch to one of the
  // two labels.
  void testObjectEmulatesUndefinedKernel(Register objreg,
                                         Label* ifEmulatesUndefined,
                                         Label* ifDoesntEmulateUndefined,
                                         Register scratch,
                                         OutOfLineTestObject* ool);

  // Test whether an object emulates |undefined|.  If it does, jump to
  // |ifEmulatesUndefined|; the caller is responsible for binding this label.
  // If it doesn't, fall through; the label |ifDoesntEmulateUndefined| (which
  // must be initially unbound) will be bound at this point.
  void branchTestObjectEmulatesUndefined(Register objreg,
                                         Label* ifEmulatesUndefined,
                                         Label* ifDoesntEmulateUndefined,
                                         Register scratch,
                                         OutOfLineTestObject* ool);

  // Test whether an object emulates |undefined|, and jump to the
  // corresponding label.
  //
  // This method should be used when subsequent code can't be laid out in a
  // straight line; if it can, branchTest* should be used instead.
  void testObjectEmulatesUndefined(Register objreg, Label* ifEmulatesUndefined,
                                   Label* ifDoesntEmulateUndefined,
                                   Register scratch, OutOfLineTestObject* ool);

  void emitStoreElementTyped(const LAllocation* value, MIRType valueType,
                             MIRType elementType, Register elements,
                             const LAllocation* index,
                             int32_t offsetAdjustment);

  // Bailout if an element about to be written to is a hole.
  void emitStoreHoleCheck(Register elements, const LAllocation* index,
                          int32_t offsetAdjustment, LSnapshot* snapshot);

  void emitAssertRangeI(const Range* r, Register input);
  void emitAssertRangeD(const Range* r, FloatRegister input,
                        FloatRegister temp);

  void maybeEmitGlobalBarrierCheck(const LAllocation* maybeGlobal,
                                   OutOfLineCode* ool);

  Vector<CodeOffset, 0, JitAllocPolicy> ionScriptLabels_;

  void branchIfInvalidated(Register temp, Label* invalidated);

#ifdef DEBUG
  void emitDebugResultChecks(LInstruction* ins);
  void emitGCThingResultChecks(LInstruction* lir, MDefinition* mir);
  void emitValueResultChecks(LInstruction* lir, MDefinition* mir);
#endif

  // Script counts created during code generation.
  IonScriptCounts* scriptCounts_;

#if defined(JS_ION_PERF)
  PerfSpewer perfSpewer_;
#endif

  // Bit mask of JitRealm stubs that are to be read-barriered.
  uint32_t realmStubsToReadBarrier_;

#define LIR_OP(op) void visit##op(L##op* ins);
  LIR_OPCODE_LIST(LIR_OP)
#undef LIR_OP
};

}  // namespace jit
}  // namespace js

#endif /* jit_CodeGenerator_h */