File: stub-cache-s390.cc

package info (click to toggle)
nodejs 4.8.2~dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 62,476 kB
  • ctags: 111,183
  • sloc: cpp: 661,544; ansic: 31,406; python: 23,073; makefile: 1,418; sh: 1,384; perl: 255; lisp: 222; ruby: 76; xml: 50
file content (189 lines) | stat: -rw-r--r-- 6,772 bytes parent folder | download | duplicates (3)
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
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#if V8_TARGET_ARCH_S390

#include "src/codegen.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
#include "src/interface-descriptors.h"

namespace v8 {
namespace internal {

#define __ ACCESS_MASM(masm)


static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                       StubCache::Table table, Register receiver, Register name,
                       // Number of the cache entry, not scaled.
                       Register offset, Register scratch, Register scratch2,
                       Register offset_scratch) {
  ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
  ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
  ExternalReference map_offset(isolate->stub_cache()->map_reference(table));

  uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
  uintptr_t value_off_addr =
      reinterpret_cast<uintptr_t>(value_offset.address());
  uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address());

  // Check the relative positions of the address fields.
  DCHECK(value_off_addr > key_off_addr);
  DCHECK((value_off_addr - key_off_addr) % 4 == 0);
  DCHECK((value_off_addr - key_off_addr) < (256 * 4));
  DCHECK(map_off_addr > key_off_addr);
  DCHECK((map_off_addr - key_off_addr) % 4 == 0);
  DCHECK((map_off_addr - key_off_addr) < (256 * 4));

  Label miss;
  Register base_addr = scratch;
  scratch = no_reg;

  // Multiply by 3 because there are 3 fields per entry (name, code, map).
  __ ShiftLeftP(offset_scratch, offset, Operand(1));
  __ AddP(offset_scratch, offset, offset_scratch);

  // Calculate the base address of the entry.
  __ mov(base_addr, Operand(key_offset));
#if V8_TARGET_ARCH_S390X
  DCHECK(kPointerSizeLog2 > StubCache::kCacheIndexShift);
  __ ShiftLeftP(offset_scratch, offset_scratch,
                  Operand(kPointerSizeLog2 - StubCache::kCacheIndexShift));
#else
  DCHECK(kPointerSizeLog2 == StubCache::kCacheIndexShift);
#endif
  __ AddP(base_addr, base_addr, offset_scratch);

  // Check that the key in the entry matches the name.
  __ CmpP(name, MemOperand(base_addr, 0));
  __ bne(&miss, Label::kNear);

  // Check the map matches.
  __ LoadP(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
  __ CmpP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
  __ bne(&miss, Label::kNear);

  // Get the code entry from the cache.
  Register code = scratch2;
  scratch2 = no_reg;
  __ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));

  // Check that the flags match what we're looking for.
  Register flags_reg = base_addr;
  base_addr = no_reg;
  __ LoadlW(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));

  DCHECK(!r0.is(flags_reg));
  __ AndP(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
  __ CmpLogicalP(flags_reg, Operand(flags));
  __ bne(&miss, Label::kNear);

#ifdef DEBUG
  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
    __ b(&miss, Label::kNear);
  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
    __ b(&miss, Label::kNear);
  }
#endif

  if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);

  // Jump to the first instruction in the code stub.
  // TODO(joransiu): Combine into indirect branch
  __ la(code, MemOperand(code, Code::kHeaderSize - kHeapObjectTag));
  __ b(code);

  // Miss: fall through.
  __ bind(&miss);
}


void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
                              Code::Flags flags, bool leave_frame,
                              Register receiver, Register name,
                              Register scratch, Register extra, Register extra2,
                              Register extra3) {
  Isolate* isolate = masm->isolate();
  Label miss;

#if V8_TARGET_ARCH_S390X
  // Make sure that code is valid. The multiplying code relies on the
  // entry size being 24.
  DCHECK(sizeof(Entry) == 24);
#else
  // Make sure that code is valid. The multiplying code relies on the
  // entry size being 12.
  DCHECK(sizeof(Entry) == 12);
#endif

  // Make sure the flags does not name a specific type.
  DCHECK(Code::ExtractTypeFromFlags(flags) == 0);

  // Make sure that there are no register conflicts.
  DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));

  // Check scratch, extra and extra2 registers are valid.
  DCHECK(!scratch.is(no_reg));
  DCHECK(!extra.is(no_reg));
  DCHECK(!extra2.is(no_reg));
  DCHECK(!extra3.is(no_reg));

#ifdef DEBUG
  // If vector-based ics are in use, ensure that scratch, extra, extra2 and
  // extra3 don't conflict with the vector and slot registers, which need
  // to be preserved for a handler call or miss.
  if (IC::ICUseVector(ic_kind)) {
    Register vector = LoadWithVectorDescriptor::VectorRegister();
    Register slot = LoadWithVectorDescriptor::SlotRegister();
    DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
  }
#endif

  Counters* counters = masm->isolate()->counters();
  __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
                      extra3);

  // Check that the receiver isn't a smi.
  __ JumpIfSmi(receiver, &miss);

  // Get the map of the receiver and compute the hash.
  __ LoadlW(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
  __ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
  __ AddP(scratch, scratch, ip);
  __ XorP(scratch, scratch, Operand(flags));
  // The mask omits the last two bits because they are not part of the hash.
  __ AndP(scratch, scratch,
          Operand((kPrimaryTableSize - 1) << kCacheIndexShift));

  // Probe the primary table.
  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
             name, scratch, extra, extra2, extra3);

  // Primary miss: Compute hash for secondary probe.
  __ SubP(scratch, scratch, name);
  __ AddP(scratch, scratch, Operand(flags));
  __ AndP(scratch, scratch,
          Operand((kSecondaryTableSize - 1) << kCacheIndexShift));

  // Probe the secondary table.
  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
             name, scratch, extra, extra2, extra3);

  // Cache miss: Fall-through and let caller handle the miss by
  // entering the runtime system.
  __ bind(&miss);
  __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
                      extra3);
}


#undef __
}  // namespace internal
}  // namespace v8

#endif  // V8_TARGET_ARCH_S390