OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/compiler.h" | 8 #include "src/compiler.h" |
9 #include "src/interpreter/control-flow-builders.h" | 9 #include "src/interpreter/control-flow-builders.h" |
10 #include "src/objects.h" | 10 #include "src/objects.h" |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
207 | 207 |
208 Register NewRegister() { | 208 Register NewRegister() { |
209 ExpressionResultScope* current_scope = generator()->execution_result(); | 209 ExpressionResultScope* current_scope = generator()->execution_result(); |
210 if ((current_scope == this) || | 210 if ((current_scope == this) || |
211 (current_scope->outer() == this && | 211 (current_scope->outer() == this && |
212 !current_scope->allocator_.hasConsecutiveAllocations())) { | 212 !current_scope->allocator_.hasConsecutiveAllocations())) { |
213 // Regular case - Allocating registers in current or outer context. | 213 // Regular case - Allocating registers in current or outer context. |
214 // VisitForRegisterValue allocates register in outer context. | 214 // VisitForRegisterValue allocates register in outer context. |
215 return allocator_.NewRegister(); | 215 return allocator_.NewRegister(); |
216 } else { | 216 } else { |
217 // We need this when allocating registers due to an Assignment hazard. | 217 // Allocating a register other than the current or outer scope: |
218 // It might be expensive to walk the full context chain and compute the | 218 // It might be expensive to walk the full context chain and compute the |
219 // list of consecutive reservations in the innerscopes. So allocates a | 219 // list of consecutive reservations in the innerscopes. So allocates a |
220 // new unallocated temporary register. | 220 // new unallocated temporary register. We needed this in an implementation |
221 // of Assignment hazard. | |
222 // TODO(mythria): Reevaluate this after we have the new assignment hazard | |
223 // implementation. Remove this if not required. | |
rmcilroy
2016/01/12 14:43:17
I'd rather just remove this now if it is no longer
mythria
2016/01/12 16:53:21
Done.
| |
221 return allocator_.AllocateNewRegister(); | 224 return allocator_.AllocateNewRegister(); |
222 } | 225 } |
223 } | 226 } |
224 | 227 |
225 void PrepareForConsecutiveAllocations(size_t count) { | 228 void PrepareForConsecutiveAllocations(size_t count) { |
226 allocator_.PrepareForConsecutiveAllocations(count); | 229 allocator_.PrepareForConsecutiveAllocations(count); |
227 } | 230 } |
228 | 231 |
229 Register NextConsecutiveRegister() { | 232 Register NextConsecutiveRegister() { |
230 return allocator_.NextConsecutiveRegister(); | 233 return allocator_.NextConsecutiveRegister(); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 set_result_identified(); | 308 set_result_identified(); |
306 } | 309 } |
307 | 310 |
308 Register ResultRegister() const { return result_register_; } | 311 Register ResultRegister() const { return result_register_; } |
309 | 312 |
310 private: | 313 private: |
311 Register result_register_; | 314 Register result_register_; |
312 }; | 315 }; |
313 | 316 |
314 | 317 |
315 BytecodeGenerator::AssignmentHazardHelper::AssignmentHazardHelper( | |
316 BytecodeGenerator* generator) | |
317 : generator_(generator), | |
318 alias_mappings_(generator->zone()), | |
319 aliased_locals_and_parameters_(generator->zone()), | |
320 execution_result_(nullptr), | |
321 scope_depth_(0) {} | |
322 | |
323 | |
324 void BytecodeGenerator::AssignmentHazardHelper::EnterScope() { | |
325 DCHECK_GE(scope_depth_, 0); | |
326 if (scope_depth_++ == 0) { | |
327 execution_result_ = generator_->execution_result(); | |
328 } | |
329 } | |
330 | |
331 | |
332 void BytecodeGenerator::AssignmentHazardHelper::LeaveScope() { | |
333 DCHECK_GT(scope_depth_, 0); | |
334 if (--scope_depth_ == 0) { | |
335 DCHECK_EQ(execution_result_, generator_->execution_result()); | |
336 RestoreAliasedLocalsAndParameters(); | |
337 } | |
338 } | |
339 | |
340 | |
341 // Returns a register that a load instruction should use when | |
342 // loading from |reg|. This allows an alias for a modified version | |
343 // of |reg| to be used within a hazard regions. | |
344 MUST_USE_RESULT Register | |
345 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForLoad(Register reg) { | |
346 if (scope_depth_ == 0) { | |
347 return reg; | |
348 } else { | |
349 // A load from |reg| is to be issued. The register is placed in | |
350 // the mappings table initially mapping to itself. Future stores | |
351 // will update the mapping with temporaries thus preserving the | |
352 // original register's value. | |
353 // | |
354 // NB This insert only updates the table if no mapping exists | |
355 // already (std::map::insert semantics). | |
356 auto insert_result = | |
357 alias_mappings_.insert(std::make_pair(reg.index(), reg.index())); | |
358 auto mapping = insert_result.first; | |
359 // Return the current alias for reg. | |
360 return Register(mapping->second); | |
361 } | |
362 } | |
363 | |
364 | |
365 // Returns a register that a store instruction should use when | |
366 // loading from |reg|. This allows an alias for a modified version | |
367 // of |reg| to be used within hazard regions. | |
368 MUST_USE_RESULT Register | |
369 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForStore(Register reg) { | |
370 if (scope_depth_ == 0 || | |
371 alias_mappings_.find(reg.index()) == alias_mappings_.end()) { | |
372 // If not in a hazard region or a load for this register has not | |
373 // occurred no mapping is necessary. | |
374 return reg; | |
375 } else { | |
376 // Storing to a register with 1 or more loads issued. The | |
377 // register is mapped to a temporary alias so we don't overwrite | |
378 // the lhs value, e.g. y = x + (x = 1); has a register for x on | |
379 // the lhs and needs a new register x' for the upcoming store on | |
380 // the rhs as the original x is an input to the add operation. | |
381 Register alias = execution_result_->NewRegister(); | |
382 alias_mappings_[reg.index()] = alias.index(); | |
383 if (generator_->builder()->RegisterIsParameterOrLocal(reg)) { | |
384 // Keep track of registers that need to be restored on exit | |
385 // from the assignment hazard region. | |
386 aliased_locals_and_parameters_.insert(reg.index()); | |
387 } | |
388 return alias; | |
389 } | |
390 } | |
391 | |
392 | |
393 void BytecodeGenerator::AssignmentHazardHelper:: | |
394 RestoreAliasedLocalsAndParameters() { | |
395 DCHECK(scope_depth_ == 0); | |
396 // Move temporary registers holding values for locals and | |
397 // parameters back into their local and parameter registers. | |
398 for (auto reg = aliased_locals_and_parameters_.begin(); | |
399 reg != aliased_locals_and_parameters_.end(); reg++) { | |
400 auto mapping = alias_mappings_.find(*reg); | |
401 if (mapping != alias_mappings_.end()) { | |
402 generator_->builder()->MoveRegister(Register(mapping->second), | |
403 Register(*reg)); | |
404 } | |
405 } | |
406 alias_mappings_.clear(); | |
407 aliased_locals_and_parameters_.clear(); | |
408 } | |
409 | |
410 | |
411 class BytecodeGenerator::AssignmentHazardScope final { | |
412 public: | |
413 explicit AssignmentHazardScope(BytecodeGenerator* generator) | |
414 : generator_(generator) { | |
415 generator_->assignment_hazard_helper()->EnterScope(); | |
416 } | |
417 | |
418 ~AssignmentHazardScope() { | |
419 generator_->assignment_hazard_helper()->LeaveScope(); | |
420 } | |
421 | |
422 private: | |
423 BytecodeGenerator* generator_; | |
424 | |
425 DISALLOW_COPY_AND_ASSIGN(AssignmentHazardScope); | |
426 }; | |
427 | |
428 | |
429 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 318 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
430 : isolate_(isolate), | 319 : isolate_(isolate), |
431 zone_(zone), | 320 zone_(zone), |
432 builder_(isolate, zone), | 321 builder_(isolate, zone), |
433 info_(nullptr), | 322 info_(nullptr), |
434 scope_(nullptr), | 323 scope_(nullptr), |
435 globals_(0, zone), | 324 globals_(0, zone), |
436 execution_control_(nullptr), | 325 execution_control_(nullptr), |
437 execution_context_(nullptr), | 326 execution_context_(nullptr), |
438 execution_result_(nullptr), | 327 execution_result_(nullptr) { |
439 assignment_hazard_helper_(this) { | |
440 InitializeAstVisitor(isolate); | 328 InitializeAstVisitor(isolate); |
441 } | 329 } |
442 | 330 |
443 | 331 |
444 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 332 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
445 set_info(info); | 333 set_info(info); |
446 set_scope(info->scope()); | 334 set_scope(info->scope()); |
447 | 335 |
448 // Initialize the incoming context. | 336 // Initialize the incoming context. |
449 ContextScope incoming_context(this, scope(), false); | 337 ContextScope incoming_context(this, scope(), false); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 builder()->Return(); | 589 builder()->Return(); |
702 } | 590 } |
703 | 591 |
704 | 592 |
705 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 593 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
706 UNIMPLEMENTED(); | 594 UNIMPLEMENTED(); |
707 } | 595 } |
708 | 596 |
709 | 597 |
710 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 598 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
599 // We need this scope because we visit for register values. We have to | |
600 // maintain a execution result scope where registers can be allocated. | |
601 EffectResultScope switch_result_scope(this); | |
rmcilroy
2016/01/12 14:43:17
nit - effect_results_scope
mythria
2016/01/12 16:53:21
Done.
| |
711 ZoneList<CaseClause*>* clauses = stmt->cases(); | 602 ZoneList<CaseClause*>* clauses = stmt->cases(); |
712 SwitchBuilder switch_builder(builder(), clauses->length()); | 603 SwitchBuilder switch_builder(builder(), clauses->length()); |
713 ControlScopeForBreakable scope(this, stmt, &switch_builder); | 604 ControlScopeForBreakable scope(this, stmt, &switch_builder); |
714 int default_index = -1; | 605 int default_index = -1; |
715 | 606 |
716 // Keep the switch value in a register until a case matches. | 607 // Keep the switch value in a register until a case matches. |
717 Register tag = VisitForRegisterValue(stmt->tag()); | 608 Register tag = VisitForRegisterValue(stmt->tag()); |
718 | 609 |
719 // Iterate over all cases and create nodes for label comparison. | 610 // Iterate over all cases and create nodes for label comparison. |
720 BytecodeLabel done_label; | 611 BytecodeLabel done_label; |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1274 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 1165 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
1275 } | 1166 } |
1276 | 1167 |
1277 | 1168 |
1278 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1169 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
1279 FeedbackVectorSlot slot, | 1170 FeedbackVectorSlot slot, |
1280 TypeofMode typeof_mode) { | 1171 TypeofMode typeof_mode) { |
1281 switch (variable->location()) { | 1172 switch (variable->location()) { |
1282 case VariableLocation::LOCAL: { | 1173 case VariableLocation::LOCAL: { |
1283 Register source(Register(variable->index())); | 1174 Register source(Register(variable->index())); |
1284 source = assignment_hazard_helper()->GetRegisterForLoad(source); | 1175 builder()->LoadAccumulatorWithRegister(source); |
1285 execution_result()->SetResultInRegister(source); | 1176 execution_result()->SetResultInAccumulator(); |
1286 break; | 1177 break; |
1287 } | 1178 } |
1288 case VariableLocation::PARAMETER: { | 1179 case VariableLocation::PARAMETER: { |
1289 // The parameter indices are shifted by 1 (receiver is variable | 1180 // The parameter indices are shifted by 1 (receiver is variable |
1290 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1181 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
1291 Register source = builder()->Parameter(variable->index() + 1); | 1182 Register source = builder()->Parameter(variable->index() + 1); |
1292 source = assignment_hazard_helper()->GetRegisterForLoad(source); | 1183 builder()->LoadAccumulatorWithRegister(source); |
1293 execution_result()->SetResultInRegister(source); | 1184 execution_result()->SetResultInAccumulator(); |
1294 break; | 1185 break; |
1295 } | 1186 } |
1296 case VariableLocation::GLOBAL: | 1187 case VariableLocation::GLOBAL: |
1297 case VariableLocation::UNALLOCATED: { | 1188 case VariableLocation::UNALLOCATED: { |
1298 builder()->LoadGlobal(variable->name(), feedback_index(slot), | 1189 builder()->LoadGlobal(variable->name(), feedback_index(slot), |
1299 language_mode(), typeof_mode); | 1190 language_mode(), typeof_mode); |
1300 execution_result()->SetResultInAccumulator(); | 1191 execution_result()->SetResultInAccumulator(); |
1301 break; | 1192 break; |
1302 } | 1193 } |
1303 case VariableLocation::CONTEXT: { | 1194 case VariableLocation::CONTEXT: { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 return register_scope.ResultRegister(); | 1242 return register_scope.ResultRegister(); |
1352 } | 1243 } |
1353 | 1244 |
1354 | 1245 |
1355 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 1246 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
1356 FeedbackVectorSlot slot) { | 1247 FeedbackVectorSlot slot) { |
1357 switch (variable->location()) { | 1248 switch (variable->location()) { |
1358 case VariableLocation::LOCAL: { | 1249 case VariableLocation::LOCAL: { |
1359 // TODO(rmcilroy): support const mode initialization. | 1250 // TODO(rmcilroy): support const mode initialization. |
1360 Register destination(variable->index()); | 1251 Register destination(variable->index()); |
1361 destination = | |
1362 assignment_hazard_helper()->GetRegisterForStore(destination); | |
1363 builder()->StoreAccumulatorInRegister(destination); | 1252 builder()->StoreAccumulatorInRegister(destination); |
1364 break; | 1253 break; |
1365 } | 1254 } |
1366 case VariableLocation::PARAMETER: { | 1255 case VariableLocation::PARAMETER: { |
1367 // The parameter indices are shifted by 1 (receiver is variable | 1256 // The parameter indices are shifted by 1 (receiver is variable |
1368 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1257 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
1369 Register destination(builder()->Parameter(variable->index() + 1)); | 1258 Register destination(builder()->Parameter(variable->index() + 1)); |
1370 destination = | |
1371 assignment_hazard_helper()->GetRegisterForStore(destination); | |
1372 | |
1373 builder()->StoreAccumulatorInRegister(destination); | 1259 builder()->StoreAccumulatorInRegister(destination); |
1374 break; | 1260 break; |
1375 } | 1261 } |
1376 case VariableLocation::GLOBAL: | 1262 case VariableLocation::GLOBAL: |
1377 case VariableLocation::UNALLOCATED: { | 1263 case VariableLocation::UNALLOCATED: { |
1378 builder()->StoreGlobal(variable->name(), feedback_index(slot), | 1264 builder()->StoreGlobal(variable->name(), feedback_index(slot), |
1379 language_mode()); | 1265 language_mode()); |
1380 break; | 1266 break; |
1381 } | 1267 } |
1382 case VariableLocation::CONTEXT: { | 1268 case VariableLocation::CONTEXT: { |
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1963 VisitLogicalAndExpression(binop); | 1849 VisitLogicalAndExpression(binop); |
1964 break; | 1850 break; |
1965 default: | 1851 default: |
1966 VisitArithmeticExpression(binop); | 1852 VisitArithmeticExpression(binop); |
1967 break; | 1853 break; |
1968 } | 1854 } |
1969 } | 1855 } |
1970 | 1856 |
1971 | 1857 |
1972 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1858 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
1973 // The evaluation of binary comparison expressions has an assignment | |
1974 // hazard because the lhs may be a variable that evaluates to a | |
1975 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) | |
1976 // To get a correct result the generator treats the inner assigment | |
1977 // as being made to a temporary x' that is spilled on exit of the | |
1978 // assignment hazard. | |
1979 AssignmentHazardScope assignment_hazard_scope(this); | |
1980 | |
1981 Register lhs = VisitForRegisterValue(expr->left()); | 1859 Register lhs = VisitForRegisterValue(expr->left()); |
1982 VisitForAccumulatorValue(expr->right()); | 1860 VisitForAccumulatorValue(expr->right()); |
1983 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); | 1861 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); |
1984 execution_result()->SetResultInAccumulator(); | 1862 execution_result()->SetResultInAccumulator(); |
1985 } | 1863 } |
1986 | 1864 |
1987 | 1865 |
1988 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { | 1866 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
1989 // The evaluation of binary arithmetic expressions has an assignment | |
1990 // hazard because the lhs may be a variable that evaluates to a | |
1991 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) | |
1992 // To get a correct result the generator treats the inner assigment | |
1993 // as being made to a temporary x' that is spilled on exit of the | |
1994 // assignment hazard. | |
1995 AssignmentHazardScope assignment_hazard_scope(this); | |
1996 | |
1997 Register lhs = VisitForRegisterValue(expr->left()); | 1867 Register lhs = VisitForRegisterValue(expr->left()); |
1998 VisitForAccumulatorValue(expr->right()); | 1868 VisitForAccumulatorValue(expr->right()); |
1999 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); | 1869 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); |
2000 execution_result()->SetResultInAccumulator(); | 1870 execution_result()->SetResultInAccumulator(); |
2001 } | 1871 } |
2002 | 1872 |
2003 | 1873 |
2004 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } | 1874 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } |
2005 | 1875 |
2006 | 1876 |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2281 } | 2151 } |
2282 | 2152 |
2283 | 2153 |
2284 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2154 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
2285 return info()->feedback_vector()->GetIndex(slot); | 2155 return info()->feedback_vector()->GetIndex(slot); |
2286 } | 2156 } |
2287 | 2157 |
2288 } // namespace interpreter | 2158 } // namespace interpreter |
2289 } // namespace internal | 2159 } // namespace internal |
2290 } // namespace v8 | 2160 } // namespace v8 |
OLD | NEW |