/ bytecode / ValueRecovery.h
ValueRecovery.h
  1  /*
  2   * Copyright (C) 2011-2019 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  #pragma once
 27  
 28  #include "DFGMinifiedID.h"
 29  #include "DataFormat.h"
 30  #if ENABLE(JIT)
 31  #include "GPRInfo.h"
 32  #include "FPRInfo.h"
 33  #include "Reg.h"
 34  #endif
 35  #include "JSCJSValue.h"
 36  #include "MacroAssembler.h"
 37  #include "VirtualRegister.h"
 38  
 39  namespace JSC {
 40  
 41  struct DumpContext;
 42  struct InlineCallFrame;
 43  
 44  // Describes how to recover a given bytecode virtual register at a given
 45  // code point.
 46  enum ValueRecoveryTechnique : uint8_t {
 47      // It's in a register.
 48      InGPR,
 49      UnboxedInt32InGPR,
 50      UnboxedInt52InGPR,
 51      UnboxedStrictInt52InGPR,
 52      UnboxedBooleanInGPR,
 53      UnboxedCellInGPR,
 54  #if USE(JSVALUE32_64)
 55      InPair,
 56  #endif
 57      InFPR,
 58      UnboxedDoubleInFPR,
 59      // It's in the stack, but at a different location.
 60      DisplacedInJSStack,
 61      // It's in the stack, at a different location, and it's unboxed.
 62      Int32DisplacedInJSStack,
 63      Int52DisplacedInJSStack,
 64      StrictInt52DisplacedInJSStack,
 65      DoubleDisplacedInJSStack,
 66      CellDisplacedInJSStack,
 67      BooleanDisplacedInJSStack,
 68      // It's an Arguments object. This arises because of the simplified arguments simplification done by the DFG.
 69      DirectArgumentsThatWereNotCreated,
 70      ClonedArgumentsThatWereNotCreated,
 71      // It's a constant.
 72      Constant,
 73      // Don't know how to recover it.
 74      DontKnow
 75  };
 76  
 77  class ValueRecovery {
 78  public:
 79      ValueRecovery()
 80          : m_technique(DontKnow)
 81      {
 82      }
 83      
 84      bool isSet() const { return m_technique != DontKnow; }
 85      bool operator!() const { return !isSet(); }
 86  
 87  #if ENABLE(JIT)
 88      static ValueRecovery inRegister(Reg reg, DataFormat dataFormat)
 89      {
 90          if (reg.isGPR())
 91              return inGPR(reg.gpr(), dataFormat);
 92  
 93          ASSERT(reg.isFPR());
 94          return inFPR(reg.fpr(), dataFormat);
 95      }
 96  #endif
 97  
 98      explicit operator bool() const { return isSet(); }
 99      
100      static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
101      {
102          ASSERT(dataFormat != DataFormatNone);
103  #if USE(JSVALUE32_64)
104          ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
105  #endif
106          ValueRecovery result;
107          if (dataFormat == DataFormatInt32)
108              result.m_technique = UnboxedInt32InGPR;
109          else if (dataFormat == DataFormatInt52)
110              result.m_technique = UnboxedInt52InGPR;
111          else if (dataFormat == DataFormatStrictInt52)
112              result.m_technique = UnboxedStrictInt52InGPR;
113          else if (dataFormat == DataFormatBoolean)
114              result.m_technique = UnboxedBooleanInGPR;
115          else if (dataFormat == DataFormatCell)
116              result.m_technique = UnboxedCellInGPR;
117          else
118              result.m_technique = InGPR;
119          UnionType u;
120          u.gpr = gpr;
121          result.m_source = WTFMove(u);
122          return result;
123      }
124      
125  #if USE(JSVALUE32_64)
126      static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
127      {
128          ValueRecovery result;
129          result.m_technique = InPair;
130          UnionType u;
131          u.pair.tagGPR = tagGPR;
132          u.pair.payloadGPR = payloadGPR;
133          result.m_source = WTFMove(u);
134          return result;
135      }
136  #endif
137  
138      static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat)
139      {
140          ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS);
141          ValueRecovery result;
142          if (dataFormat == DataFormatDouble)
143              result.m_technique = UnboxedDoubleInFPR;
144          else
145              result.m_technique = InFPR;
146          UnionType u;
147          u.fpr = fpr;
148          result.m_source = WTFMove(u);
149          return result;
150      }
151      
152      static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
153      {
154          ValueRecovery result;
155          switch (dataFormat) {
156          case DataFormatInt32:
157              result.m_technique = Int32DisplacedInJSStack;
158              break;
159              
160          case DataFormatInt52:
161              result.m_technique = Int52DisplacedInJSStack;
162              break;
163              
164          case DataFormatStrictInt52:
165              result.m_technique = StrictInt52DisplacedInJSStack;
166              break;
167              
168          case DataFormatDouble:
169              result.m_technique = DoubleDisplacedInJSStack;
170              break;
171  
172          case DataFormatCell:
173              result.m_technique = CellDisplacedInJSStack;
174              break;
175              
176          case DataFormatBoolean:
177              result.m_technique = BooleanDisplacedInJSStack;
178              break;
179              
180          default:
181              ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
182              result.m_technique = DisplacedInJSStack;
183              break;
184          }
185          UnionType u;
186          u.virtualReg = virtualReg.offset();
187          result.m_source = WTFMove(u);
188          return result;
189      }
190      
191      static ValueRecovery constant(JSValue value)
192      {
193          ValueRecovery result;
194          result.m_technique = Constant;
195          UnionType u;
196          u.constant = JSValue::encode(value);
197          result.m_source = WTFMove(u);
198          return result;
199      }
200      
201      static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id)
202      {
203          ValueRecovery result;
204          result.m_technique = DirectArgumentsThatWereNotCreated;
205          UnionType u;
206          u.nodeID = id.bits();
207          result.m_source = WTFMove(u);
208          return result;
209      }
210      
211      static ValueRecovery clonedArgumentsThatWereNotCreated(DFG::MinifiedID id)
212      {
213          ValueRecovery result;
214          result.m_technique = ClonedArgumentsThatWereNotCreated;
215          UnionType u;
216          u.nodeID = id.bits();
217          result.m_source = WTFMove(u);
218          return result;
219      }
220  
221      ValueRecoveryTechnique technique() const { return m_technique; }
222      
223      bool isConstant() const { return m_technique == Constant; }
224  
225      bool isInGPR() const
226      {
227          switch (m_technique) {
228          case InGPR:
229          case UnboxedInt32InGPR:
230          case UnboxedBooleanInGPR:
231          case UnboxedCellInGPR:
232          case UnboxedInt52InGPR:
233          case UnboxedStrictInt52InGPR:
234              return true;
235          default:
236              return false;
237          }
238      }
239  
240      bool isInFPR() const
241      {
242          switch (m_technique) {
243          case InFPR:
244          case UnboxedDoubleInFPR:
245              return true;
246          default:
247              return false;
248          }
249      }
250  
251      bool isInRegisters() const
252      {
253          return isInJSValueRegs() || isInGPR() || isInFPR();
254      }
255  
256      bool isInJSStack() const
257      {
258          switch (m_technique) {
259          case DisplacedInJSStack:
260          case Int32DisplacedInJSStack:
261          case Int52DisplacedInJSStack:
262          case StrictInt52DisplacedInJSStack:
263          case DoubleDisplacedInJSStack:
264          case CellDisplacedInJSStack:
265          case BooleanDisplacedInJSStack:
266              return true;
267          default:
268              return false;
269          }
270      }
271  
272      DataFormat dataFormat() const
273      {
274          switch (m_technique) {
275          case InGPR:
276          case InFPR:
277          case DisplacedInJSStack:
278          case Constant:
279  #if USE(JSVALUE32_64)
280          case InPair:
281  #endif
282              return DataFormatJS;
283          case UnboxedInt32InGPR:
284          case Int32DisplacedInJSStack:
285              return DataFormatInt32;
286          case UnboxedInt52InGPR:
287          case Int52DisplacedInJSStack:
288              return DataFormatInt52;
289          case UnboxedStrictInt52InGPR:
290          case StrictInt52DisplacedInJSStack:
291              return DataFormatStrictInt52;
292          case UnboxedBooleanInGPR:
293          case BooleanDisplacedInJSStack:
294              return DataFormatBoolean;
295          case UnboxedCellInGPR:
296          case CellDisplacedInJSStack:
297              return DataFormatCell;
298          case UnboxedDoubleInFPR:
299          case DoubleDisplacedInJSStack:
300              return DataFormatDouble;
301          default:
302              return DataFormatNone;
303          }
304      }
305      
306      MacroAssembler::RegisterID gpr() const
307      {
308          ASSERT(isInGPR());
309          return m_source.get().gpr;
310      }
311      
312  #if USE(JSVALUE32_64)
313      MacroAssembler::RegisterID tagGPR() const
314      {
315          ASSERT(m_technique == InPair);
316          return m_source.get().pair.tagGPR;
317      }
318      
319      MacroAssembler::RegisterID payloadGPR() const
320      {
321          ASSERT(m_technique == InPair);
322          return m_source.get().pair.payloadGPR;
323      }
324  
325      bool isInJSValueRegs() const
326      {
327          return m_technique == InPair;
328      }
329  
330  #if ENABLE(JIT)
331      JSValueRegs jsValueRegs() const
332      {
333          ASSERT(isInJSValueRegs());
334          return JSValueRegs(tagGPR(), payloadGPR());
335      }
336  #endif // ENABLE(JIT)
337  #else
338      bool isInJSValueRegs() const
339      {
340          return isInGPR();
341      }
342  #endif // USE(JSVALUE32_64)
343      
344      MacroAssembler::FPRegisterID fpr() const
345      {
346          ASSERT(isInFPR());
347          return m_source.get().fpr;
348      }
349      
350      VirtualRegister virtualRegister() const
351      {
352          ASSERT(isInJSStack());
353          return VirtualRegister(m_source.get().virtualReg);
354      }
355      
356      ValueRecovery withLocalsOffset(int offset) const
357      {
358          switch (m_technique) {
359          case DisplacedInJSStack:
360          case Int32DisplacedInJSStack:
361          case DoubleDisplacedInJSStack:
362          case CellDisplacedInJSStack:
363          case BooleanDisplacedInJSStack:
364          case Int52DisplacedInJSStack:
365          case StrictInt52DisplacedInJSStack: {
366              ValueRecovery result;
367              result.m_technique = m_technique;
368              UnionType u;
369              u.virtualReg = m_source.get().virtualReg + offset;
370              result.m_source = WTFMove(u);
371              return result;
372          }
373              
374          default:
375              return *this;
376          }
377      }
378      
379      JSValue constant() const
380      {
381          ASSERT(isConstant());
382          return JSValue::decode(m_source.get().constant);
383      }
384      
385      DFG::MinifiedID nodeID() const
386      {
387          ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated);
388          return DFG::MinifiedID::fromBits(m_source.get().nodeID);
389      }
390      
391      JSValue recover(CallFrame*) const;
392      
393  #if ENABLE(JIT)
394      template<typename Func>
395      void forEachReg(const Func& func)
396      {
397          switch (m_technique) {
398          case InGPR:
399          case UnboxedInt32InGPR:
400          case UnboxedBooleanInGPR:
401          case UnboxedCellInGPR:
402          case UnboxedInt52InGPR:
403          case UnboxedStrictInt52InGPR:
404              func(gpr());
405              return;
406          case InFPR:
407          case UnboxedDoubleInFPR:
408              func(fpr());
409              return;
410  #if USE(JSVALUE32_64)
411          case InPair:
412              func(jsValueRegs().payloadGPR());
413              func(jsValueRegs().tagGPR());
414              return;
415  #endif
416          default:
417              return;
418          }
419      }
420      
421      void dumpInContext(PrintStream& out, DumpContext* context) const;
422      void dump(PrintStream& out) const;
423  #endif
424  
425  private:
426      ValueRecoveryTechnique m_technique;
427      union UnionType {
428          MacroAssembler::RegisterID gpr;
429          MacroAssembler::FPRegisterID fpr;
430  #if USE(JSVALUE32_64)
431          struct {
432              MacroAssembler::RegisterID tagGPR;
433              MacroAssembler::RegisterID payloadGPR;
434          } pair;
435  #endif
436          int virtualReg;
437          EncodedJSValue constant;
438          unsigned nodeID;
439      };
440      Packed<UnionType> m_source;
441  };
442  static_assert(alignof(ValueRecovery) == 1);
443  
444  } // namespace JSC