v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
typing.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "typing.h"
29 
30 #include "frames.h"
31 #include "frames-inl.h"
32 #include "parser.h" // for CompileTimeValue; TODO(rossberg): should move
33 #include "scopes.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 
39 AstTyper::AstTyper(CompilationInfo* info)
40  : info_(info),
41  oracle_(
42  Handle<Code>(info->closure()->shared()->code()),
43  Handle<Context>(info->closure()->context()->native_context()),
44  info->zone()),
45  store_(info->zone()) {
46  InitializeAstVisitor(info->zone());
47 }
48 
49 
50 #define RECURSE(call) \
51  do { \
52  ASSERT(!visitor->HasStackOverflow()); \
53  call; \
54  if (visitor->HasStackOverflow()) return; \
55  } while (false)
56 
57 void AstTyper::Run(CompilationInfo* info) {
58  AstTyper* visitor = new(info->zone()) AstTyper(info);
59  Scope* scope = info->scope();
60 
61  // Handle implicit declaration of the function name in named function
62  // expressions before other declarations.
63  if (scope->is_function_scope() && scope->function() != NULL) {
64  RECURSE(visitor->VisitVariableDeclaration(scope->function()));
65  }
66  RECURSE(visitor->VisitDeclarations(scope->declarations()));
67  RECURSE(visitor->VisitStatements(info->function()->body()));
68 }
69 
70 #undef RECURSE
71 
72 
73 #ifdef OBJECT_PRINT
74  static void PrintObserved(Variable* var, Object* value, Type* type) {
75  PrintF(" observed %s ", var->IsParameter() ? "param" : "local");
76  var->name()->Print();
77  PrintF(" : ");
78  value->ShortPrint();
79  PrintF(" -> ");
80  type->TypePrint();
81  }
82 #endif // OBJECT_PRINT
83 
84 
85 Effect AstTyper::ObservedOnStack(Object* value) {
86  Type* lower = Type::OfCurrently(handle(value, isolate()), zone());
87  return Effect(Bounds(lower, Type::Any(zone())));
88 }
89 
90 
91 void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) {
92  if (stmt->OsrEntryId() != info_->osr_ast_id()) return;
93 
95  JavaScriptFrameIterator it(isolate());
96  JavaScriptFrame* frame = it.frame();
97  Scope* scope = info_->scope();
98 
99  // Assert that the frame on the stack belongs to the function we want to OSR.
100  ASSERT_EQ(*info_->closure(), frame->function());
101 
102  int params = scope->num_parameters();
103  int locals = scope->StackLocalCount();
104 
105  // Use sequential composition to achieve desired narrowing.
106  // The receiver is a parameter with index -1.
107  store_.Seq(parameter_index(-1), ObservedOnStack(frame->receiver()));
108  for (int i = 0; i < params; i++) {
109  store_.Seq(parameter_index(i), ObservedOnStack(frame->GetParameter(i)));
110  }
111 
112  for (int i = 0; i < locals; i++) {
113  store_.Seq(stack_local_index(i), ObservedOnStack(frame->GetExpression(i)));
114  }
115 
116 #ifdef OBJECT_PRINT
117  if (FLAG_trace_osr && FLAG_print_scopes) {
118  PrintObserved(scope->receiver(),
119  frame->receiver(),
120  store_.LookupBounds(parameter_index(-1)).lower);
121 
122  for (int i = 0; i < params; i++) {
123  PrintObserved(scope->parameter(i),
124  frame->GetParameter(i),
125  store_.LookupBounds(parameter_index(i)).lower);
126  }
127 
128  ZoneList<Variable*> local_vars(locals, zone());
129  ZoneList<Variable*> context_vars(scope->ContextLocalCount(), zone());
130  scope->CollectStackAndContextLocals(&local_vars, &context_vars);
131  for (int i = 0; i < locals; i++) {
132  PrintObserved(local_vars.at(i),
133  frame->GetExpression(i),
134  store_.LookupBounds(stack_local_index(i)).lower);
135  }
136  }
137 #endif // OBJECT_PRINT
138 }
139 
140 
141 #define RECURSE(call) \
142  do { \
143  ASSERT(!HasStackOverflow()); \
144  call; \
145  if (HasStackOverflow()) return; \
146  } while (false)
147 
148 
149 void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
150  for (int i = 0; i < stmts->length(); ++i) {
151  Statement* stmt = stmts->at(i);
152  RECURSE(Visit(stmt));
153  if (stmt->IsJump()) break;
154  }
155 }
156 
157 
158 void AstTyper::VisitBlock(Block* stmt) {
159  RECURSE(VisitStatements(stmt->statements()));
160  if (stmt->labels() != NULL) {
161  store_.Forget(); // Control may transfer here via 'break l'.
162  }
163 }
164 
165 
166 void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
167  RECURSE(Visit(stmt->expression()));
168 }
169 
170 
171 void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
172 }
173 
174 
175 void AstTyper::VisitIfStatement(IfStatement* stmt) {
176  // Collect type feedback.
177  if (!stmt->condition()->ToBooleanIsTrue() &&
178  !stmt->condition()->ToBooleanIsFalse()) {
179  stmt->condition()->RecordToBooleanTypeFeedback(oracle());
180  }
181 
182  RECURSE(Visit(stmt->condition()));
183  Effects then_effects = EnterEffects();
184  RECURSE(Visit(stmt->then_statement()));
185  ExitEffects();
186  Effects else_effects = EnterEffects();
187  RECURSE(Visit(stmt->else_statement()));
188  ExitEffects();
189  then_effects.Alt(else_effects);
190  store_.Seq(then_effects);
191 }
192 
193 
194 void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
195  // TODO(rossberg): is it worth having a non-termination effect?
196 }
197 
198 
199 void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
200  // TODO(rossberg): is it worth having a non-termination effect?
201 }
202 
203 
204 void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
205  // Collect type feedback.
206  // TODO(rossberg): we only need this for inlining into test contexts...
207  stmt->expression()->RecordToBooleanTypeFeedback(oracle());
208 
209  RECURSE(Visit(stmt->expression()));
210  // TODO(rossberg): is it worth having a non-termination effect?
211 }
212 
213 
214 void AstTyper::VisitWithStatement(WithStatement* stmt) {
215  RECURSE(stmt->expression());
216  RECURSE(stmt->statement());
217 }
218 
219 
220 void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
221  RECURSE(Visit(stmt->tag()));
222 
223  ZoneList<CaseClause*>* clauses = stmt->cases();
224  Effects local_effects(zone());
225  bool complex_effects = false; // True for label effects or fall-through.
226 
227  for (int i = 0; i < clauses->length(); ++i) {
228  CaseClause* clause = clauses->at(i);
229 
230  Effects clause_effects = EnterEffects();
231 
232  if (!clause->is_default()) {
233  Expression* label = clause->label();
234  // Collect type feedback.
235  Type* tag_type;
236  Type* label_type;
237  Type* combined_type;
238  oracle()->CompareType(clause->CompareId(),
239  &tag_type, &label_type, &combined_type);
240  NarrowLowerType(stmt->tag(), tag_type);
241  NarrowLowerType(label, label_type);
242  clause->set_compare_type(combined_type);
243 
244  RECURSE(Visit(label));
245  if (!clause_effects.IsEmpty()) complex_effects = true;
246  }
247 
248  ZoneList<Statement*>* stmts = clause->statements();
249  RECURSE(VisitStatements(stmts));
250  ExitEffects();
251  if (stmts->is_empty() || stmts->last()->IsJump()) {
252  local_effects.Alt(clause_effects);
253  } else {
254  complex_effects = true;
255  }
256  }
257 
258  if (complex_effects) {
259  store_.Forget(); // Reached this in unknown state.
260  } else {
261  store_.Seq(local_effects);
262  }
263 }
264 
265 
266 void AstTyper::VisitCaseClause(CaseClause* clause) {
267  UNREACHABLE();
268 }
269 
270 
271 void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
272  // Collect type feedback.
273  if (!stmt->cond()->ToBooleanIsTrue()) {
274  stmt->cond()->RecordToBooleanTypeFeedback(oracle());
275  }
276 
277  // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
278  // computing the set of variables assigned in only some of the origins of the
279  // control transfer (such as the loop body here).
280  store_.Forget(); // Control may transfer here via looping or 'continue'.
281  ObserveTypesAtOsrEntry(stmt);
282  RECURSE(Visit(stmt->body()));
283  RECURSE(Visit(stmt->cond()));
284  store_.Forget(); // Control may transfer here via 'break'.
285 }
286 
287 
288 void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
289  // Collect type feedback.
290  if (!stmt->cond()->ToBooleanIsTrue()) {
291  stmt->cond()->RecordToBooleanTypeFeedback(oracle());
292  }
293 
294  store_.Forget(); // Control may transfer here via looping or 'continue'.
295  RECURSE(Visit(stmt->cond()));
296  ObserveTypesAtOsrEntry(stmt);
297  RECURSE(Visit(stmt->body()));
298  store_.Forget(); // Control may transfer here via termination or 'break'.
299 }
300 
301 
302 void AstTyper::VisitForStatement(ForStatement* stmt) {
303  if (stmt->init() != NULL) {
304  RECURSE(Visit(stmt->init()));
305  }
306  store_.Forget(); // Control may transfer here via looping.
307  if (stmt->cond() != NULL) {
308  // Collect type feedback.
309  stmt->cond()->RecordToBooleanTypeFeedback(oracle());
310 
311  RECURSE(Visit(stmt->cond()));
312  }
313  ObserveTypesAtOsrEntry(stmt);
314  RECURSE(Visit(stmt->body()));
315  if (stmt->next() != NULL) {
316  store_.Forget(); // Control may transfer here via 'continue'.
317  RECURSE(Visit(stmt->next()));
318  }
319  store_.Forget(); // Control may transfer here via termination or 'break'.
320 }
321 
322 
323 void AstTyper::VisitForInStatement(ForInStatement* stmt) {
324  // Collect type feedback.
325  stmt->set_for_in_type(static_cast<ForInStatement::ForInType>(
326  oracle()->ForInType(stmt->ForInFeedbackSlot())));
327 
328  RECURSE(Visit(stmt->enumerable()));
329  store_.Forget(); // Control may transfer here via looping or 'continue'.
330  ObserveTypesAtOsrEntry(stmt);
331  RECURSE(Visit(stmt->body()));
332  store_.Forget(); // Control may transfer here via 'break'.
333 }
334 
335 
336 void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
337  RECURSE(Visit(stmt->iterable()));
338  store_.Forget(); // Control may transfer here via looping or 'continue'.
339  RECURSE(Visit(stmt->body()));
340  store_.Forget(); // Control may transfer here via 'break'.
341 }
342 
343 
344 void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
345  Effects try_effects = EnterEffects();
346  RECURSE(Visit(stmt->try_block()));
347  ExitEffects();
348  Effects catch_effects = EnterEffects();
349  store_.Forget(); // Control may transfer here via 'throw'.
350  RECURSE(Visit(stmt->catch_block()));
351  ExitEffects();
352  try_effects.Alt(catch_effects);
353  store_.Seq(try_effects);
354  // At this point, only variables that were reassigned in the catch block are
355  // still remembered.
356 }
357 
358 
359 void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
360  RECURSE(Visit(stmt->try_block()));
361  store_.Forget(); // Control may transfer here via 'throw'.
362  RECURSE(Visit(stmt->finally_block()));
363 }
364 
365 
366 void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
367  store_.Forget(); // May do whatever.
368 }
369 
370 
371 void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
372  expr->InitializeSharedInfo(Handle<Code>(info_->closure()->shared()->code()));
373 }
374 
375 
376 void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
377 }
378 
379 
380 void AstTyper::VisitConditional(Conditional* expr) {
381  // Collect type feedback.
382  expr->condition()->RecordToBooleanTypeFeedback(oracle());
383 
384  RECURSE(Visit(expr->condition()));
385  Effects then_effects = EnterEffects();
386  RECURSE(Visit(expr->then_expression()));
387  ExitEffects();
388  Effects else_effects = EnterEffects();
389  RECURSE(Visit(expr->else_expression()));
390  ExitEffects();
391  then_effects.Alt(else_effects);
392  store_.Seq(then_effects);
393 
394  NarrowType(expr, Bounds::Either(
395  expr->then_expression()->bounds(),
396  expr->else_expression()->bounds(), zone()));
397 }
398 
399 
400 void AstTyper::VisitVariableProxy(VariableProxy* expr) {
401  Variable* var = expr->var();
402  if (var->IsStackAllocated()) {
403  NarrowType(expr, store_.LookupBounds(variable_index(var)));
404  }
405 }
406 
407 
408 void AstTyper::VisitLiteral(Literal* expr) {
409  Type* type = Type::Constant(expr->value(), zone());
410  NarrowType(expr, Bounds(type));
411 }
412 
413 
414 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
415  NarrowType(expr, Bounds(Type::RegExp(zone())));
416 }
417 
418 
419 void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
420  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
421  for (int i = 0; i < properties->length(); ++i) {
422  ObjectLiteral::Property* prop = properties->at(i);
423 
424  // Collect type feedback.
425  if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
426  !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
427  prop->kind() == ObjectLiteral::Property::COMPUTED) {
428  if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
429  prop->RecordTypeFeedback(oracle());
430  }
431  }
432 
433  RECURSE(Visit(prop->value()));
434  }
435 
436  NarrowType(expr, Bounds(Type::Object(zone())));
437 }
438 
439 
440 void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
441  ZoneList<Expression*>* values = expr->values();
442  for (int i = 0; i < values->length(); ++i) {
443  Expression* value = values->at(i);
444  RECURSE(Visit(value));
445  }
446 
447  NarrowType(expr, Bounds(Type::Array(zone())));
448 }
449 
450 
451 void AstTyper::VisitAssignment(Assignment* expr) {
452  // Collect type feedback.
453  Property* prop = expr->target()->AsProperty();
454  if (prop != NULL) {
455  TypeFeedbackId id = expr->AssignmentFeedbackId();
456  expr->set_is_uninitialized(oracle()->StoreIsUninitialized(id));
457  if (!expr->IsUninitialized()) {
458  if (prop->key()->IsPropertyName()) {
459  Literal* lit_key = prop->key()->AsLiteral();
460  ASSERT(lit_key != NULL && lit_key->value()->IsString());
461  Handle<String> name = Handle<String>::cast(lit_key->value());
462  oracle()->AssignmentReceiverTypes(id, name, expr->GetReceiverTypes());
463  } else {
464  KeyedAccessStoreMode store_mode;
465  oracle()->KeyedAssignmentReceiverTypes(
466  id, expr->GetReceiverTypes(), &store_mode);
467  expr->set_store_mode(store_mode);
468  }
469  }
470  }
471 
472  Expression* rhs =
473  expr->is_compound() ? expr->binary_operation() : expr->value();
474  RECURSE(Visit(expr->target()));
475  RECURSE(Visit(rhs));
476  NarrowType(expr, rhs->bounds());
477 
478  VariableProxy* proxy = expr->target()->AsVariableProxy();
479  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
480  store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
481  }
482 }
483 
484 
485 void AstTyper::VisitYield(Yield* expr) {
486  RECURSE(Visit(expr->generator_object()));
487  RECURSE(Visit(expr->expression()));
488 
489  // We don't know anything about the result type.
490 }
491 
492 
493 void AstTyper::VisitThrow(Throw* expr) {
494  RECURSE(Visit(expr->exception()));
495  // TODO(rossberg): is it worth having a non-termination effect?
496 
497  NarrowType(expr, Bounds(Type::None(zone())));
498 }
499 
500 
501 void AstTyper::VisitProperty(Property* expr) {
502  // Collect type feedback.
503  TypeFeedbackId id = expr->PropertyFeedbackId();
504  expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
505  if (!expr->IsUninitialized()) {
506  if (expr->key()->IsPropertyName()) {
507  Literal* lit_key = expr->key()->AsLiteral();
508  ASSERT(lit_key != NULL && lit_key->value()->IsString());
509  Handle<String> name = Handle<String>::cast(lit_key->value());
510  bool is_prototype;
511  oracle()->PropertyReceiverTypes(
512  id, name, expr->GetReceiverTypes(), &is_prototype);
513  expr->set_is_function_prototype(is_prototype);
514  } else {
515  bool is_string;
516  oracle()->KeyedPropertyReceiverTypes(
517  id, expr->GetReceiverTypes(), &is_string);
518  expr->set_is_string_access(is_string);
519  }
520  }
521 
522  RECURSE(Visit(expr->obj()));
523  RECURSE(Visit(expr->key()));
524 
525  // We don't know anything about the result type.
526 }
527 
528 
529 void AstTyper::VisitCall(Call* expr) {
530  // Collect type feedback.
531  RECURSE(Visit(expr->expression()));
532  if (!expr->expression()->IsProperty() &&
533  expr->HasCallFeedbackSlot() &&
534  oracle()->CallIsMonomorphic(expr->CallFeedbackSlot())) {
535  expr->set_target(oracle()->GetCallTarget(expr->CallFeedbackSlot()));
536  }
537 
538  ZoneList<Expression*>* args = expr->arguments();
539  for (int i = 0; i < args->length(); ++i) {
540  Expression* arg = args->at(i);
541  RECURSE(Visit(arg));
542  }
543 
544  VariableProxy* proxy = expr->expression()->AsVariableProxy();
545  if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
546  store_.Forget(); // Eval could do whatever to local variables.
547  }
548 
549  // We don't know anything about the result type.
550 }
551 
552 
553 void AstTyper::VisitCallNew(CallNew* expr) {
554  // Collect type feedback.
555  expr->RecordTypeFeedback(oracle());
556 
557  RECURSE(Visit(expr->expression()));
558  ZoneList<Expression*>* args = expr->arguments();
559  for (int i = 0; i < args->length(); ++i) {
560  Expression* arg = args->at(i);
561  RECURSE(Visit(arg));
562  }
563 
564  NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone())));
565 }
566 
567 
568 void AstTyper::VisitCallRuntime(CallRuntime* expr) {
569  ZoneList<Expression*>* args = expr->arguments();
570  for (int i = 0; i < args->length(); ++i) {
571  Expression* arg = args->at(i);
572  RECURSE(Visit(arg));
573  }
574 
575  // We don't know anything about the result type.
576 }
577 
578 
579 void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
580  // Collect type feedback.
581  if (expr->op() == Token::NOT) {
582  // TODO(rossberg): only do in test or value context.
583  expr->expression()->RecordToBooleanTypeFeedback(oracle());
584  }
585 
586  RECURSE(Visit(expr->expression()));
587 
588  switch (expr->op()) {
589  case Token::NOT:
590  case Token::DELETE:
591  NarrowType(expr, Bounds(Type::Boolean(zone())));
592  break;
593  case Token::VOID:
594  NarrowType(expr, Bounds(Type::Undefined(zone())));
595  break;
596  case Token::TYPEOF:
597  NarrowType(expr, Bounds(Type::InternalizedString(zone())));
598  break;
599  default:
600  UNREACHABLE();
601  }
602 }
603 
604 
605 void AstTyper::VisitCountOperation(CountOperation* expr) {
606  // Collect type feedback.
607  TypeFeedbackId store_id = expr->CountStoreFeedbackId();
608  expr->set_store_mode(oracle()->GetStoreMode(store_id));
609  oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes());
610  expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
611  // TODO(rossberg): merge the count type with the generic expression type.
612 
613  RECURSE(Visit(expr->expression()));
614 
615  NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
616 
617  VariableProxy* proxy = expr->expression()->AsVariableProxy();
618  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
619  store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
620  }
621 }
622 
623 
624 void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
625  // Collect type feedback.
626  Type* type;
627  Type* left_type;
628  Type* right_type;
629  Maybe<int> fixed_right_arg;
630  Handle<AllocationSite> allocation_site;
631  oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
632  &left_type, &right_type, &type, &fixed_right_arg,
633  &allocation_site, expr->op());
634  NarrowLowerType(expr, type);
635  NarrowLowerType(expr->left(), left_type);
636  NarrowLowerType(expr->right(), right_type);
637  expr->set_allocation_site(allocation_site);
638  expr->set_fixed_right_arg(fixed_right_arg);
639  if (expr->op() == Token::OR || expr->op() == Token::AND) {
640  expr->left()->RecordToBooleanTypeFeedback(oracle());
641  }
642 
643  switch (expr->op()) {
644  case Token::COMMA:
645  RECURSE(Visit(expr->left()));
646  RECURSE(Visit(expr->right()));
647  NarrowType(expr, expr->right()->bounds());
648  break;
649  case Token::OR:
650  case Token::AND: {
651  Effects left_effects = EnterEffects();
652  RECURSE(Visit(expr->left()));
653  ExitEffects();
654  Effects right_effects = EnterEffects();
655  RECURSE(Visit(expr->right()));
656  ExitEffects();
657  left_effects.Alt(right_effects);
658  store_.Seq(left_effects);
659 
660  NarrowType(expr, Bounds::Either(
661  expr->left()->bounds(), expr->right()->bounds(), zone()));
662  break;
663  }
664  case Token::BIT_OR:
665  case Token::BIT_AND: {
666  RECURSE(Visit(expr->left()));
667  RECURSE(Visit(expr->right()));
668  Type* upper = Type::Union(
669  expr->left()->bounds().upper, expr->right()->bounds().upper, zone());
670  if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
671  Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
672  NarrowType(expr, Bounds(lower, upper));
673  break;
674  }
675  case Token::BIT_XOR:
676  case Token::SHL:
677  case Token::SAR:
678  RECURSE(Visit(expr->left()));
679  RECURSE(Visit(expr->right()));
680  NarrowType(expr,
681  Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())));
682  break;
683  case Token::SHR:
684  RECURSE(Visit(expr->left()));
685  RECURSE(Visit(expr->right()));
686  // TODO(rossberg): The upper bound would be Unsigned32, but since there
687  // is no 'positive Smi' type for the lower bound, we use the smallest
688  // union of Smi and Unsigned32 as upper bound instead.
689  NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
690  break;
691  case Token::ADD: {
692  RECURSE(Visit(expr->left()));
693  RECURSE(Visit(expr->right()));
694  Bounds l = expr->left()->bounds();
695  Bounds r = expr->right()->bounds();
696  Type* lower =
697  l.lower->Is(Type::None()) || r.lower->Is(Type::None()) ?
698  Type::None(zone()) :
699  l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ?
700  Type::String(zone()) :
701  l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ?
702  Type::SignedSmall(zone()) : Type::None(zone());
703  Type* upper =
704  l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ?
705  Type::String(zone()) :
706  l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ?
707  Type::Number(zone()) : Type::NumberOrString(zone());
708  NarrowType(expr, Bounds(lower, upper));
709  break;
710  }
711  case Token::SUB:
712  case Token::MUL:
713  case Token::DIV:
714  case Token::MOD:
715  RECURSE(Visit(expr->left()));
716  RECURSE(Visit(expr->right()));
717  NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
718  break;
719  default:
720  UNREACHABLE();
721  }
722 }
723 
724 
725 void AstTyper::VisitCompareOperation(CompareOperation* expr) {
726  // Collect type feedback.
727  Type* left_type;
728  Type* right_type;
729  Type* combined_type;
730  oracle()->CompareType(expr->CompareOperationFeedbackId(),
731  &left_type, &right_type, &combined_type);
732  NarrowLowerType(expr->left(), left_type);
733  NarrowLowerType(expr->right(), right_type);
734  expr->set_combined_type(combined_type);
735 
736  RECURSE(Visit(expr->left()));
737  RECURSE(Visit(expr->right()));
738 
739  NarrowType(expr, Bounds(Type::Boolean(zone())));
740 }
741 
742 
743 void AstTyper::VisitThisFunction(ThisFunction* expr) {
744 }
745 
746 
747 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
748  for (int i = 0; i < decls->length(); ++i) {
749  Declaration* decl = decls->at(i);
750  RECURSE(Visit(decl));
751  }
752 }
753 
754 
755 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
756 }
757 
758 
759 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
760  RECURSE(Visit(declaration->fun()));
761 }
762 
763 
764 void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
765  RECURSE(Visit(declaration->module()));
766 }
767 
768 
769 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
770  RECURSE(Visit(declaration->module()));
771 }
772 
773 
774 void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
775 }
776 
777 
778 void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
779  RECURSE(Visit(module->body()));
780 }
781 
782 
783 void AstTyper::VisitModuleVariable(ModuleVariable* module) {
784 }
785 
786 
787 void AstTyper::VisitModulePath(ModulePath* module) {
788  RECURSE(Visit(module->module()));
789 }
790 
791 
792 void AstTyper::VisitModuleUrl(ModuleUrl* module) {
793 }
794 
795 
796 void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
797  RECURSE(Visit(stmt->body()));
798 }
799 
800 
801 } } // namespace v8::internal
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
VariableDeclaration * function() const
Definition: scopes.h:326
void PrintF(const char *format,...)
Definition: v8utils.cc:40
static Handle< String > cast(Handle< S > that)
Definition: handles.h:75
kSerializedDataOffset Object
Definition: objects-inl.h:5016
BoundsImpl< ZoneTypeConfig > Bounds
Definition: types.h:644
TypeImpl< ZoneTypeConfig > Type
KeyedAccessStoreMode
Definition: objects.h:164
#define ASSERT(condition)
Definition: checks.h:329
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
Handle< String > name() const
Definition: variables.h:96
#define UNREACHABLE()
Definition: checks.h:52
FunctionLiteral * function() const
Definition: compiler.h:77
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
#define COMMA
Definition: flags.h:101
bool Is(Object *obj)
V8_INLINE Handle< Primitive > Undefined(Isolate *isolate)
Definition: v8.h:6541
V8_INLINE bool IsString() const
Definition: v8.h:6265
bool Is(TypeImpl *that)
Definition: types.h:246
Definition: v8.h:2107
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:103
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function info
Definition: flags.cc:317
bool IsParameter() const
Definition: variables.h:116
void ShortPrint(FILE *out=stdout)
Definition: objects.cc:1123
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
PerThreadAssertScopeDebugOnly< HEAP_ALLOCATION_ASSERT, false > DisallowHeapAllocation
Definition: assert-scope.h:214
bool is_function_scope() const
Definition: scopes.h:284
#define VOID
#define RECURSE(call)
Definition: typing.cc:141
ZoneList< Declaration * > * declarations()
Definition: scopes.h:344
Scope * scope() const
Definition: compiler.h:78