OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 #include "src/interpreter/register-translator.h" | |
6 | |
7 #include "src/interpreter/bytecode-array-builder.h" | |
8 | |
9 namespace v8 { | |
10 namespace internal { | |
11 namespace interpreter { | |
12 | |
13 RegisterTranslator::RegisterTranslator(RegisterMover* mover) | |
14 : mover_(mover), window_registers_count_(0), register_operands_count_(0) {} | |
15 | |
16 | |
17 Register RegisterTranslator::Translate(Bytecode bytecode, Register reg) { | |
18 if (register_operands_count_ == 0) { | |
19 bytecode_ = bytecode; | |
20 } | |
21 DCHECK_EQ(bytecode, bytecode_); | |
rmcilroy
2016/01/22 17:50:57
I'm not sure what the point of passing bytecode to
| |
22 DCHECK_LT(register_operands_count_, | |
23 static_cast<int>(arraysize(register_operands_))); | |
24 OperandType operand_type = | |
25 GetRegisterOperandType(bytecode, register_operands_count_); | |
26 Register translated_reg = Translate(reg); | |
27 Register addressable = MakeAddressable(translated_reg, operand_type); | |
28 register_operands_[register_operands_count_] = addressable.ToRawOperand(); | |
rmcilroy
2016/01/22 17:50:57
Do we need to keep the register_operands_ in vecto
| |
29 register_operands_count_ += 1; | |
30 if (addressable != translated_reg) { | |
31 Move(translated_reg, addressable, operand_type); | |
32 } | |
33 return addressable; | |
34 } | |
35 | |
36 | |
37 Register RegisterTranslator::MakeAddressable(Register translated_reg, | |
38 OperandType translated_reg_type) { | |
39 DCHECK(!InTranslationWindow(translated_reg)); | |
40 OperandSize translated_reg_size = | |
41 Bytecodes::SizeOfOperand(translated_reg_type); | |
42 if (translated_reg_size == OperandSize::kByte && | |
43 !FitsInReg8Operand(translated_reg)) { | |
44 // TODO(oth): Moves into and out from translation window could be | |
45 // decoupled if there were metadata to say whether the register was | |
46 // an input, output, or both. | |
47 Register destination(kTranslationWindowStart + window_registers_count_); | |
48 window_registers_[window_registers_count_] = translated_reg; | |
49 window_registers_count_ += 1; | |
50 DCHECK_LE(window_registers_count_, kTranslationWindowLength); | |
51 return destination; | |
52 } else { | |
53 return translated_reg; | |
54 } | |
55 } | |
56 | |
57 | |
58 void RegisterTranslator::Move(Register from, Register to, | |
59 OperandType to_operand_type) { | |
60 bool expect_movable = true; | |
61 if (to_operand_type != OperandType::kReg8) { | |
62 // Only tests should visit this path. | |
rmcilroy
2016/01/22 17:50:57
What test kick this path? It seems non-obvious tha
| |
63 from = to = Register::IllegalRegister(); | |
64 expect_movable = false; | |
65 } | |
66 | |
67 bool movable = mover()->MoveRegisterUntranslated(from, to); | |
68 CHECK_EQ(expect_movable, movable); | |
69 } | |
70 | |
71 | |
72 void RegisterTranslator::CompleteTranslations() { | |
73 while (window_registers_count_ > 0) { | |
74 window_registers_count_ -= 1; | |
75 Register source(kTranslationWindowStart + window_registers_count_); | |
76 Register destination = window_registers_[window_registers_count_]; | |
77 mover()->MoveRegisterUntranslated(source, destination); | |
78 } | |
79 register_operands_count_ = 0; | |
80 bytecode_ = static_cast<Bytecode>(-1); | |
81 } | |
82 | |
83 | |
84 bool RegisterTranslator::RegisterOperandsValid(Bytecode bytecode, | |
85 const uint32_t* const operands, | |
86 int operands_count) const { | |
87 if (bytecode != bytecode_ && bytecode == Bytecode::kMovWide) { | |
88 // Checking move emitted by register translator for bytecode_. | |
89 DCHECK_EQ(operands_count, 2); | |
90 Register from = Register::FromRawOperand(operands[0]); | |
91 Register to = Register::FromRawOperand(operands[1]); | |
92 return MoveIsValid(from, to); | |
93 } else if (register_operands_count_ == 0) { | |
94 DCHECK_EQ(Bytecodes::NumberOfRegisterOperands(bytecode), 0); | |
95 return true; | |
96 } | |
97 | |
98 int reg_count = 0; | |
99 for (int i = 0; i < operands_count; i++) { | |
100 OperandType operand_type = Bytecodes::GetOperandType(bytecode, i); | |
101 bool next_operand_is_reg_count = false; | |
102 if (i != operands_count - 1) { | |
103 OperandType next_operand_type = | |
104 Bytecodes::GetOperandType(bytecode, i + 1); | |
105 next_operand_is_reg_count = | |
106 next_operand_type == OperandType::kRegCount8 || | |
107 next_operand_type == OperandType::kRegCount16; | |
rmcilroy
2016/01/22 17:50:57
You don't seem to use next_operand_is_reg_count ?
| |
108 } | |
109 | |
110 Register reg; | |
111 int length = 0; | |
112 switch (operand_type) { | |
113 case OperandType::kNone: | |
114 UNREACHABLE(); | |
115 return false; | |
116 case OperandType::kIdx8: | |
117 case OperandType::kIdx16: | |
118 case OperandType::kImm8: | |
119 case OperandType::kRegCount8: | |
120 case OperandType::kRegCount16: | |
121 break; | |
122 case OperandType::kMaybeReg8: | |
123 case OperandType::kMaybeReg16: { | |
124 DCHECK(next_operand_is_reg_count); | |
125 reg = Register::FromRawOperand(operands[i]); | |
126 length = static_cast<int>(operands[i + 1]); | |
127 break; | |
128 } | |
129 case OperandType::kRegPair8: | |
130 case OperandType::kRegPair16: { | |
131 reg = Register::FromRawOperand(operands[i]); | |
132 length = 2; | |
133 break; | |
134 } | |
135 case OperandType::kRegTriple8: | |
136 case OperandType::kRegTriple16: { | |
137 reg = Register::FromRawOperand(operands[i]); | |
138 length = 3; | |
139 break; | |
140 } | |
141 case OperandType::kReg8: | |
142 case OperandType::kReg16: { | |
143 reg = Register::FromRawOperand(operands[i]); | |
144 if (next_operand_is_reg_count) { | |
145 length = static_cast<int>(operands[i + 1]); | |
146 } else { | |
147 length = 1; | |
148 } | |
149 break; | |
150 } | |
151 } | |
152 if (reg.is_valid()) { | |
153 if (reg.ToRawOperand() != register_operands_[reg_count]) { | |
154 return false; | |
155 } else if (reg.index() < kTranslationWindowStart && | |
156 reg.index() + length > kTranslationWindowStart) { | |
157 return false; | |
158 } | |
159 reg_count++; | |
160 } | |
161 } | |
162 return reg_count == Bytecodes::NumberOfRegisterOperands(bytecode) && | |
163 reg_count == register_operands_count_; | |
164 } | |
165 | |
166 | |
167 bool RegisterTranslator::MoveIsValid(Register from, Register to) const { | |
168 // Checking a move bytecode ahead of emitting actual bytecode. The move | |
169 // is ensuring all register operands are reachable. | |
170 if (InTranslationWindow(to)) { | |
171 // Moving register into translation window. | |
172 DCHECK(!FitsInReg8Operand(from)); | |
173 DCHECK(from.index() > kTranslationWindowLimit || !from.is_byte_operand()); | |
174 DCHECK_GT(window_registers_count_, 0); | |
175 DCHECK_LE(window_registers_count_, | |
176 static_cast<int>(arraysize(window_registers_))); | |
177 Register last_window_register = | |
178 window_registers_[window_registers_count_ - 1]; | |
179 return from == last_window_register; | |
180 } else if (InTranslationWindow(from)) { | |
181 // Moving register out of translation window. | |
182 DCHECK(!FitsInReg8Operand(to)); | |
183 DCHECK(to.index() > kTranslationWindowLimit || !to.is_byte_operand()); | |
184 DCHECK_GE(window_registers_count_, 0); | |
185 DCHECK_LT(window_registers_count_, | |
186 static_cast<int>(arraysize(window_registers_))); | |
187 Register last_window_register = window_registers_[window_registers_count_]; | |
188 return to == last_window_register; | |
189 } else { | |
190 UNREACHABLE(); | |
191 return false; | |
192 } | |
193 } | |
194 | |
195 | |
196 // static | |
197 Register RegisterTranslator::Translate(Register reg) { | |
198 if (reg.index() >= kTranslationWindowStart) { | |
199 return Register(reg.index() + kTranslationWindowLength); | |
rmcilroy
2016/01/22 17:50:57
I wonder whether we should have a TranslatedRegist
| |
200 } else { | |
201 return reg; | |
202 } | |
203 } | |
204 | |
205 | |
206 // static | |
207 OperandType RegisterTranslator::GetRegisterOperandType(Bytecode bytecode, | |
208 int register_operand) { | |
209 int operand_count = Bytecodes::NumberOfOperands(bytecode); | |
210 for (int operand = 0; operand < operand_count; ++operand) { | |
rmcilroy
2016/01/22 17:50:56
Would it be possible to calculate this statically
| |
211 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand); | |
212 switch (operand_type) { | |
213 #define REGISTER_OPERAND_CASE(op, _) case OperandType::k##op: | |
214 REGISTER_OPERAND_TYPE_LIST(REGISTER_OPERAND_CASE) | |
215 #undef REGISTER_OPERAND_CASE | |
216 if (register_operand-- == 0) { | |
217 return operand_type; | |
218 } | |
219 break; | |
220 default: | |
221 break; | |
222 } | |
223 } | |
224 UNREACHABLE(); | |
225 return OperandType::kNone; | |
226 } | |
227 | |
228 | |
229 // static | |
230 bool RegisterTranslator::InTranslationWindow(Register reg) { | |
231 return (reg.index() >= kTranslationWindowStart && | |
232 reg.index() <= kTranslationWindowLimit); | |
233 } | |
234 | |
235 | |
236 // static | |
237 int RegisterTranslator::DistanceToTranslationWindow(Register reg) { | |
238 return kTranslationWindowStart - reg.index(); | |
239 } | |
240 | |
241 | |
242 // static | |
243 bool RegisterTranslator::FitsInReg8Operand(Register reg) { | |
244 return reg.is_byte_operand() && reg.index() < kTranslationWindowStart; | |
245 } | |
246 | |
247 | |
248 // static | |
249 bool RegisterTranslator::FitsInReg16Operand(Register reg) { | |
250 int max_index = Register::MaxRegisterIndex() - kTranslationWindowLength + 1; | |
251 return reg.is_short_operand() && reg.index() < max_index; | |
252 } | |
253 | |
254 | |
255 // static | |
256 int RegisterTranslator::RegisterCountAdjustment(int register_count, | |
257 int parameter_count) { | |
258 if (register_count > kTranslationWindowStart) { | |
259 return kTranslationWindowLength; | |
260 } else if (parameter_count > 0) { | |
261 Register param0 = Register::FromParameterIndex(0, parameter_count); | |
262 DCHECK_LT(param0.index(), 0); | |
263 if (param0.index() < kMinInt8) { | |
264 // TODO(oth): Translation window does not relocate when number of | |
265 // registers is small, but number of parameters is large enough to | |
266 // require translation. The frame may be 128 registers too large. | |
267 return kTranslationWindowLimit + 1 - register_count; | |
268 } | |
269 } | |
270 return 0; | |
271 } | |
272 | |
273 } // namespace interpreter | |
274 } // namespace internal | |
275 } // namespace v8 | |
OLD | NEW |