• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_S390_CODE_STUBS_S390_H_
6 #define V8_S390_CODE_STUBS_S390_H_
7 
8 #include "src/s390/frames-s390.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
14 
15 class StringHelper : public AllStatic {
16  public:
17   // Generate code for copying a large number of characters. This function
18   // is allowed to spend extra time setting up conditions to make copying
19   // faster. Copying of overlapping regions is not supported.
20   // Dest register ends at the position after the last character written.
21   static void GenerateCopyCharacters(MacroAssembler* masm, Register dest,
22                                      Register src, Register count,
23                                      Register scratch,
24                                      String::Encoding encoding);
25 
26   // Compares two flat one-byte strings and returns result in r0.
27   static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm,
28                                                 Register left, Register right,
29                                                 Register scratch1,
30                                                 Register scratch2,
31                                                 Register scratch3);
32 
33   // Compares two flat one-byte strings for equality and returns result in r0.
34   static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
35                                               Register left, Register right,
36                                               Register scratch1,
37                                               Register scratch2);
38 
39  private:
40   static void GenerateOneByteCharsCompareLoop(MacroAssembler* masm,
41                                               Register left, Register right,
42                                               Register length,
43                                               Register scratch1,
44                                               Label* chars_not_equal);
45 
46   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
47 };
48 
49 class StoreRegistersStateStub : public PlatformCodeStub {
50  public:
StoreRegistersStateStub(Isolate * isolate)51   explicit StoreRegistersStateStub(Isolate* isolate)
52       : PlatformCodeStub(isolate) {}
53 
54   static void GenerateAheadOfTime(Isolate* isolate);
55 
56  private:
57   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
58   DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
59 };
60 
61 class RestoreRegistersStateStub : public PlatformCodeStub {
62  public:
RestoreRegistersStateStub(Isolate * isolate)63   explicit RestoreRegistersStateStub(Isolate* isolate)
64       : PlatformCodeStub(isolate) {}
65 
66   static void GenerateAheadOfTime(Isolate* isolate);
67 
68  private:
69   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
70   DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
71 };
72 
73 class RecordWriteStub : public PlatformCodeStub {
74  public:
RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)75   RecordWriteStub(Isolate* isolate, Register object, Register value,
76                   Register address, RememberedSetAction remembered_set_action,
77                   SaveFPRegsMode fp_mode)
78       : PlatformCodeStub(isolate),
79         regs_(object,   // An input reg.
80               address,  // An input reg.
81               value) {  // One scratch reg.
82     minor_key_ = ObjectBits::encode(object.code()) |
83                  ValueBits::encode(value.code()) |
84                  AddressBits::encode(address.code()) |
85                  RememberedSetActionBits::encode(remembered_set_action) |
86                  SaveFPRegsModeBits::encode(fp_mode);
87   }
88 
RecordWriteStub(uint32_t key,Isolate * isolate)89   RecordWriteStub(uint32_t key, Isolate* isolate)
90       : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
91 
92   enum Mode { STORE_BUFFER_ONLY, INCREMENTAL, INCREMENTAL_COMPACTION };
93 
SometimesSetsUpAFrame()94   bool SometimesSetsUpAFrame() override { return false; }
95 
96   // Patch an always taken branch into a NOP branch
PatchBranchCondMask(MacroAssembler * masm,int pos,Condition c)97   static void PatchBranchCondMask(MacroAssembler* masm, int pos, Condition c) {
98     int32_t instrLen = masm->instr_length_at(pos);
99     DCHECK(instrLen == 4 || instrLen == 6);
100 
101     if (instrLen == 4) {
102       // BRC - Branch Mask @ Bits 23-20
103       FourByteInstr updatedMask = static_cast<FourByteInstr>(c) << 20;
104       masm->instr_at_put<FourByteInstr>(
105           pos, (masm->instr_at(pos) & ~kFourByteBrCondMask) | updatedMask);
106     } else {
107       // BRCL - Branch Mask @ Bits 39-36
108       SixByteInstr updatedMask = static_cast<SixByteInstr>(c) << 36;
109       masm->instr_at_put<SixByteInstr>(
110           pos, (masm->instr_at(pos) & ~kSixByteBrCondMask) | updatedMask);
111     }
112   }
113 
isBranchNop(SixByteInstr instr,int instrLength)114   static bool isBranchNop(SixByteInstr instr, int instrLength) {
115     if ((4 == instrLength && 0 == (instr & kFourByteBrCondMask)) ||
116         // BRC - Check for 0x0 mask condition.
117         (6 == instrLength && 0 == (instr & kSixByteBrCondMask))) {
118       // BRCL - Check for 0x0 mask condition
119       return true;
120     }
121     return false;
122   }
123 
GetMode(Code * stub)124   static Mode GetMode(Code* stub) {
125     int32_t first_instr_length =
126         Instruction::InstructionLength(stub->instruction_start());
127     int32_t second_instr_length = Instruction::InstructionLength(
128         stub->instruction_start() + first_instr_length);
129 
130     uint64_t first_instr = Assembler::instr_at(stub->instruction_start());
131     uint64_t second_instr =
132         Assembler::instr_at(stub->instruction_start() + first_instr_length);
133 
134     DCHECK(first_instr_length == 4 || first_instr_length == 6);
135     DCHECK(second_instr_length == 4 || second_instr_length == 6);
136 
137     bool isFirstInstrNOP = isBranchNop(first_instr, first_instr_length);
138     bool isSecondInstrNOP = isBranchNop(second_instr, second_instr_length);
139 
140     // STORE_BUFFER_ONLY has NOP on both branches
141     if (isSecondInstrNOP && isFirstInstrNOP) return STORE_BUFFER_ONLY;
142     // INCREMENTAL_COMPACTION has NOP on second branch.
143     else if (isFirstInstrNOP && !isSecondInstrNOP)
144       return INCREMENTAL_COMPACTION;
145     // INCREMENTAL has NOP on first branch.
146     else if (!isFirstInstrNOP && isSecondInstrNOP)
147       return INCREMENTAL;
148 
149     DCHECK(false);
150     return STORE_BUFFER_ONLY;
151   }
152 
Patch(Code * stub,Mode mode)153   static void Patch(Code* stub, Mode mode) {
154     MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
155                         stub->instruction_size(), CodeObjectRequired::kNo);
156 
157     // Get instruction lengths of two branches
158     int32_t first_instr_length = masm.instr_length_at(0);
159     int32_t second_instr_length = masm.instr_length_at(first_instr_length);
160 
161     switch (mode) {
162       case STORE_BUFFER_ONLY:
163         DCHECK(GetMode(stub) == INCREMENTAL ||
164                GetMode(stub) == INCREMENTAL_COMPACTION);
165 
166         PatchBranchCondMask(&masm, 0, CC_NOP);
167         PatchBranchCondMask(&masm, first_instr_length, CC_NOP);
168         break;
169       case INCREMENTAL:
170         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
171         PatchBranchCondMask(&masm, 0, CC_ALWAYS);
172         break;
173       case INCREMENTAL_COMPACTION:
174         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
175         PatchBranchCondMask(&masm, first_instr_length, CC_ALWAYS);
176         break;
177     }
178     DCHECK(GetMode(stub) == mode);
179     Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
180                            first_instr_length + second_instr_length);
181   }
182 
183   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
184 
185  private:
186   // This is a helper class for freeing up 3 scratch registers.  The input is
187   // two registers that must be preserved and one scratch register provided by
188   // the caller.
189   class RegisterAllocation {
190    public:
RegisterAllocation(Register object,Register address,Register scratch0)191     RegisterAllocation(Register object, Register address, Register scratch0)
192         : object_(object), address_(address), scratch0_(scratch0) {
193       DCHECK(!AreAliased(scratch0, object, address, no_reg));
194       scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
195     }
196 
Save(MacroAssembler * masm)197     void Save(MacroAssembler* masm) {
198       DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
199       // We don't have to save scratch0_ because it was given to us as
200       // a scratch register.
201       masm->push(scratch1_);
202     }
203 
Restore(MacroAssembler * masm)204     void Restore(MacroAssembler* masm) { masm->pop(scratch1_); }
205 
206     // If we have to call into C then we need to save and restore all caller-
207     // saved registers that were not already preserved.  The scratch registers
208     // will be restored by other means so we don't bother pushing them here.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)209     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
210       masm->push(r14);
211       masm->MultiPush(kJSCallerSaved & ~scratch1_.bit());
212       if (mode == kSaveFPRegs) {
213         // Save all volatile FP registers except d0.
214         masm->MultiPushDoubles(kCallerSavedDoubles & ~d0.bit());
215       }
216     }
217 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)218     inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
219                                            SaveFPRegsMode mode) {
220       if (mode == kSaveFPRegs) {
221         // Restore all volatile FP registers except d0.
222         masm->MultiPopDoubles(kCallerSavedDoubles & ~d0.bit());
223       }
224       masm->MultiPop(kJSCallerSaved & ~scratch1_.bit());
225       masm->pop(r14);
226     }
227 
object()228     inline Register object() { return object_; }
address()229     inline Register address() { return address_; }
scratch0()230     inline Register scratch0() { return scratch0_; }
scratch1()231     inline Register scratch1() { return scratch1_; }
232 
233    private:
234     Register object_;
235     Register address_;
236     Register scratch0_;
237     Register scratch1_;
238 
239     friend class RecordWriteStub;
240   };
241 
242   enum OnNoNeedToInformIncrementalMarker {
243     kReturnOnNoNeedToInformIncrementalMarker,
244     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
245   };
246 
MajorKey()247   inline Major MajorKey() const final { return RecordWrite; }
248 
249   void Generate(MacroAssembler* masm) override;
250   void GenerateIncremental(MacroAssembler* masm, Mode mode);
251   void CheckNeedsToInformIncrementalMarker(
252       MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need,
253       Mode mode);
254   void InformIncrementalMarker(MacroAssembler* masm);
255 
Activate(Code * code)256   void Activate(Code* code) override {
257     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
258   }
259 
object()260   Register object() const {
261     return Register::from_code(ObjectBits::decode(minor_key_));
262   }
263 
value()264   Register value() const {
265     return Register::from_code(ValueBits::decode(minor_key_));
266   }
267 
address()268   Register address() const {
269     return Register::from_code(AddressBits::decode(minor_key_));
270   }
271 
remembered_set_action()272   RememberedSetAction remembered_set_action() const {
273     return RememberedSetActionBits::decode(minor_key_);
274   }
275 
save_fp_regs_mode()276   SaveFPRegsMode save_fp_regs_mode() const {
277     return SaveFPRegsModeBits::decode(minor_key_);
278   }
279 
280   class ObjectBits : public BitField<int, 0, 4> {};
281   class ValueBits : public BitField<int, 4, 4> {};
282   class AddressBits : public BitField<int, 8, 4> {};
283   class RememberedSetActionBits : public BitField<RememberedSetAction, 15, 1> {
284   };
285   class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 16, 1> {};
286 
287   Label slow_;
288   RegisterAllocation regs_;
289 
290   DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
291 };
292 
293 // Trampoline stub to call into native code. To call safely into native code
294 // in the presence of compacting GC (which can move code objects) we need to
295 // keep the code which called into native pinned in the memory. Currently the
296 // simplest approach is to generate such stub early enough so it can never be
297 // moved by GC
298 class DirectCEntryStub : public PlatformCodeStub {
299  public:
DirectCEntryStub(Isolate * isolate)300   explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
301   void GenerateCall(MacroAssembler* masm, Register target);
302 
303  private:
NeedsImmovableCode()304   bool NeedsImmovableCode() override { return true; }
305 
306   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
307   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
308 };
309 
310 class NameDictionaryLookupStub : public PlatformCodeStub {
311  public:
312   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
313 
NameDictionaryLookupStub(Isolate * isolate,LookupMode mode)314   NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
315       : PlatformCodeStub(isolate) {
316     minor_key_ = LookupModeBits::encode(mode);
317   }
318 
319   static void GenerateNegativeLookup(MacroAssembler* masm, Label* miss,
320                                      Label* done, Register receiver,
321                                      Register properties, Handle<Name> name,
322                                      Register scratch0);
323 
324   static void GeneratePositiveLookup(MacroAssembler* masm, Label* miss,
325                                      Label* done, Register elements,
326                                      Register name, Register r0, Register r1);
327 
SometimesSetsUpAFrame()328   bool SometimesSetsUpAFrame() override { return false; }
329 
330  private:
331   static const int kInlinedProbes = 4;
332   static const int kTotalProbes = 20;
333 
334   static const int kCapacityOffset =
335       NameDictionary::kHeaderSize +
336       NameDictionary::kCapacityIndex * kPointerSize;
337 
338   static const int kElementsStartOffset =
339       NameDictionary::kHeaderSize +
340       NameDictionary::kElementsStartIndex * kPointerSize;
341 
mode()342   LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
343 
344   class LookupModeBits : public BitField<LookupMode, 0, 1> {};
345 
346   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
347   DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
348 };
349 
350 class FloatingPointHelper : public AllStatic {
351  public:
352   enum Destination { kFPRegisters, kCoreRegisters };
353 
354   // Loads smis from r0 and r1 (right and left in binary operations) into
355   // floating point registers. Depending on the destination the values ends up
356   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
357   // floating point registers VFP3 must be supported. If core registers are
358   // requested when VFP3 is supported d6 and d7 will be scratched.
359   static void LoadSmis(MacroAssembler* masm, Register scratch1,
360                        Register scratch2);
361 
362   // Loads objects from r0 and r1 (right and left in binary operations) into
363   // floating point registers. Depending on the destination the values ends up
364   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
365   // floating point registers VFP3 must be supported. If core registers are
366   // requested when VFP3 is supported d6 and d7 will still be scratched. If
367   // either r0 or r1 is not a number (not smi and not heap number object) the
368   // not_number label is jumped to with r0 and r1 intact.
369   static void LoadOperands(MacroAssembler* masm, Register heap_number_map,
370                            Register scratch1, Register scratch2,
371                            Label* not_number);
372 
373   // Convert the smi or heap number in object to an int32 using the rules
374   // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
375   // and brought into the range -2^31 .. +2^31 - 1.
376   static void ConvertNumberToInt32(MacroAssembler* masm, Register object,
377                                    Register dst, Register heap_number_map,
378                                    Register scratch1, Register scratch2,
379                                    Register scratch3,
380                                    DoubleRegister double_scratch,
381                                    Label* not_int32);
382 
383   // Converts the integer (untagged smi) in |src| to a double, storing
384   // the result to |double_dst|
385   static void ConvertIntToDouble(MacroAssembler* masm, Register src,
386                                  DoubleRegister double_dst);
387 
388   // Converts the unsigned integer (untagged smi) in |src| to
389   // a double, storing the result to |double_dst|
390   static void ConvertUnsignedIntToDouble(MacroAssembler* masm, Register src,
391                                          DoubleRegister double_dst);
392 
393   // Converts the integer (untagged smi) in |src| to
394   // a float, storing the result in |dst|
395   static void ConvertIntToFloat(MacroAssembler* masm, const DoubleRegister dst,
396                                 const Register src);
397 
398   // Load the number from object into double_dst in the double format.
399   // Control will jump to not_int32 if the value cannot be exactly represented
400   // by a 32-bit integer.
401   // Floating point value in the 32-bit integer range that are not exact integer
402   // won't be loaded.
403   static void LoadNumberAsInt32Double(MacroAssembler* masm, Register object,
404                                       DoubleRegister double_dst,
405                                       DoubleRegister double_scratch,
406                                       Register heap_number_map,
407                                       Register scratch1, Register scratch2,
408                                       Label* not_int32);
409 
410   // Loads the number from object into dst as a 32-bit integer.
411   // Control will jump to not_int32 if the object cannot be exactly represented
412   // by a 32-bit integer.
413   // Floating point value in the 32-bit integer range that are not exact integer
414   // won't be converted.
415   // scratch3 is not used when VFP3 is supported.
416   static void LoadNumberAsInt32(MacroAssembler* masm, Register object,
417                                 Register dst, Register heap_number_map,
418                                 Register scratch1, Register scratch2,
419                                 Register scratch3,
420                                 DoubleRegister double_scratch0,
421                                 DoubleRegister double_scratch1,
422                                 Label* not_int32);
423 
424   // Generate non VFP3 code to check if a double can be exactly represented by a
425   // 32-bit integer. This does not check for 0 or -0, which need
426   // to be checked for separately.
427   // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
428   // through otherwise.
429   // src1 and src2 will be cloberred.
430   //
431   // Expected input:
432   // - src1: higher (exponent) part of the double value.
433   // - src2: lower (mantissa) part of the double value.
434   // Output status:
435   // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
436   // - src2: contains 1.
437   // - other registers are clobbered.
438   static void DoubleIs32BitInteger(MacroAssembler* masm, Register src1,
439                                    Register src2, Register dst,
440                                    Register scratch, Label* not_int32);
441 
442   // Generates code to call a C function to do a double operation using core
443   // registers. (Used when VFP3 is not supported.)
444   // This code never falls through, but returns with a heap number containing
445   // the result in r0.
446   // Register heapnumber_result must be a heap number in which the
447   // result of the operation will be stored.
448   // Requires the following layout on entry:
449   // r0: Left value (least significant part of mantissa).
450   // r1: Left value (sign, exponent, top of mantissa).
451   // r2: Right value (least significant part of mantissa).
452   // r3: Right value (sign, exponent, top of mantissa).
453   static void CallCCodeForDoubleOperation(MacroAssembler* masm, Token::Value op,
454                                           Register heap_number_result,
455                                           Register scratch);
456 
457  private:
458   static void LoadNumber(MacroAssembler* masm, Register object,
459                          DoubleRegister dst, Register heap_number_map,
460                          Register scratch1, Register scratch2,
461                          Label* not_number);
462 };
463 
464 }  // namespace internal
465 }  // namespace v8
466 
467 #endif  // V8_S390_CODE_STUBS_S390_H_
468