1 // Copyright 2012 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/ast.h"
6 
7 #include <cmath>  // For isfinite.
8 #include "src/builtins.h"
9 #include "src/code-stubs.h"
10 #include "src/contexts.h"
11 #include "src/conversions.h"
12 #include "src/hashmap.h"
13 #include "src/parser.h"
14 #include "src/property.h"
15 #include "src/property-details.h"
16 #include "src/scopes.h"
17 #include "src/string-stream.h"
18 #include "src/type-info.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 // ----------------------------------------------------------------------------
24 // All the Accept member functions for each syntax tree node type.
25 
26 #define DECL_ACCEPT(type)                                       \
27   void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT)28 AST_NODE_LIST(DECL_ACCEPT)
29 #undef DECL_ACCEPT
30 
31 
32 // ----------------------------------------------------------------------------
33 // Implementation of other node functionality.
34 
35 
36 bool Expression::IsSmiLiteral() const {
37   return IsLiteral() && AsLiteral()->value()->IsSmi();
38 }
39 
40 
IsStringLiteral() const41 bool Expression::IsStringLiteral() const {
42   return IsLiteral() && AsLiteral()->value()->IsString();
43 }
44 
45 
IsNullLiteral() const46 bool Expression::IsNullLiteral() const {
47   return IsLiteral() && AsLiteral()->value()->IsNull();
48 }
49 
50 
IsUndefinedLiteral(Isolate * isolate) const51 bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
52   const VariableProxy* var_proxy = AsVariableProxy();
53   if (var_proxy == NULL) return false;
54   Variable* var = var_proxy->var();
55   // The global identifier "undefined" is immutable. Everything
56   // else could be reassigned.
57   return var != NULL && var->location() == Variable::UNALLOCATED &&
58          var_proxy->raw_name()->IsOneByteEqualTo("undefined");
59 }
60 
61 
VariableProxy(Zone * zone,Variable * var,int position,IdGen * id_gen)62 VariableProxy::VariableProxy(Zone* zone, Variable* var, int position,
63                              IdGen* id_gen)
64     : Expression(zone, position, id_gen),
65       name_(var->raw_name()),
66       var_(NULL),  // Will be set by the call to BindTo.
67       is_this_(var->is_this()),
68       is_assigned_(false),
69       interface_(var->interface()),
70       variable_feedback_slot_(kInvalidFeedbackSlot) {
71   BindTo(var);
72 }
73 
74 
VariableProxy(Zone * zone,const AstRawString * name,bool is_this,Interface * interface,int position,IdGen * id_gen)75 VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
76                              Interface* interface, int position, IdGen* id_gen)
77     : Expression(zone, position, id_gen),
78       name_(name),
79       var_(NULL),
80       is_this_(is_this),
81       is_assigned_(false),
82       interface_(interface),
83       variable_feedback_slot_(kInvalidFeedbackSlot) {}
84 
85 
BindTo(Variable * var)86 void VariableProxy::BindTo(Variable* var) {
87   DCHECK(var_ == NULL);  // must be bound only once
88   DCHECK(var != NULL);  // must bind
89   DCHECK(!FLAG_harmony_modules || interface_->IsUnified(var->interface()));
90   DCHECK((is_this() && var->is_this()) || name_ == var->raw_name());
91   // Ideally CONST-ness should match. However, this is very hard to achieve
92   // because we don't know the exact semantics of conflicting (const and
93   // non-const) multiple variable declarations, const vars introduced via
94   // eval() etc.  Const-ness and variable declarations are a complete mess
95   // in JS. Sigh...
96   var_ = var;
97   var->set_is_used();
98 }
99 
100 
Assignment(Zone * zone,Token::Value op,Expression * target,Expression * value,int pos,IdGen * id_gen)101 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
102                        Expression* value, int pos, IdGen* id_gen)
103     : Expression(zone, pos, id_gen),
104       op_(op),
105       target_(target),
106       value_(value),
107       binary_operation_(NULL),
108       assignment_id_(id_gen->GetNextId()),
109       is_uninitialized_(false),
110       store_mode_(STANDARD_STORE) {}
111 
112 
binary_op() const113 Token::Value Assignment::binary_op() const {
114   switch (op_) {
115     case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
116     case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
117     case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
118     case Token::ASSIGN_SHL: return Token::SHL;
119     case Token::ASSIGN_SAR: return Token::SAR;
120     case Token::ASSIGN_SHR: return Token::SHR;
121     case Token::ASSIGN_ADD: return Token::ADD;
122     case Token::ASSIGN_SUB: return Token::SUB;
123     case Token::ASSIGN_MUL: return Token::MUL;
124     case Token::ASSIGN_DIV: return Token::DIV;
125     case Token::ASSIGN_MOD: return Token::MOD;
126     default: UNREACHABLE();
127   }
128   return Token::ILLEGAL;
129 }
130 
131 
AllowsLazyCompilation()132 bool FunctionLiteral::AllowsLazyCompilation() {
133   return scope()->AllowsLazyCompilation();
134 }
135 
136 
AllowsLazyCompilationWithoutContext()137 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
138   return scope()->AllowsLazyCompilationWithoutContext();
139 }
140 
141 
start_position() const142 int FunctionLiteral::start_position() const {
143   return scope()->start_position();
144 }
145 
146 
end_position() const147 int FunctionLiteral::end_position() const {
148   return scope()->end_position();
149 }
150 
151 
strict_mode() const152 StrictMode FunctionLiteral::strict_mode() const {
153   return scope()->strict_mode();
154 }
155 
156 
InitializeSharedInfo(Handle<Code> unoptimized_code)157 void FunctionLiteral::InitializeSharedInfo(
158     Handle<Code> unoptimized_code) {
159   for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) {
160     RelocInfo* rinfo = it.rinfo();
161     if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
162     Object* obj = rinfo->target_object();
163     if (obj->IsSharedFunctionInfo()) {
164       SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
165       if (shared->start_position() == start_position()) {
166         shared_info_ = Handle<SharedFunctionInfo>(shared);
167         break;
168       }
169     }
170   }
171 }
172 
173 
ObjectLiteralProperty(Zone * zone,AstValueFactory * ast_value_factory,Literal * key,Expression * value,bool is_static)174 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
175                                              AstValueFactory* ast_value_factory,
176                                              Literal* key, Expression* value,
177                                              bool is_static) {
178   emit_store_ = true;
179   key_ = key;
180   value_ = value;
181   is_static_ = is_static;
182   if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
183     kind_ = PROTOTYPE;
184   } else if (value_->AsMaterializedLiteral() != NULL) {
185     kind_ = MATERIALIZED_LITERAL;
186   } else if (value_->IsLiteral()) {
187     kind_ = CONSTANT;
188   } else {
189     kind_ = COMPUTED;
190   }
191 }
192 
193 
ObjectLiteralProperty(Zone * zone,bool is_getter,FunctionLiteral * value,bool is_static)194 ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
195                                              FunctionLiteral* value,
196                                              bool is_static) {
197   emit_store_ = true;
198   value_ = value;
199   kind_ = is_getter ? GETTER : SETTER;
200   is_static_ = is_static;
201 }
202 
203 
IsCompileTimeValue()204 bool ObjectLiteral::Property::IsCompileTimeValue() {
205   return kind_ == CONSTANT ||
206       (kind_ == MATERIALIZED_LITERAL &&
207        CompileTimeValue::IsCompileTimeValue(value_));
208 }
209 
210 
set_emit_store(bool emit_store)211 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
212   emit_store_ = emit_store;
213 }
214 
215 
emit_store()216 bool ObjectLiteral::Property::emit_store() {
217   return emit_store_;
218 }
219 
220 
CalculateEmitStore(Zone * zone)221 void ObjectLiteral::CalculateEmitStore(Zone* zone) {
222   ZoneAllocationPolicy allocator(zone);
223 
224   ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
225                     allocator);
226   for (int i = properties()->length() - 1; i >= 0; i--) {
227     ObjectLiteral::Property* property = properties()->at(i);
228     Literal* literal = property->key();
229     if (literal->value()->IsNull()) continue;
230     uint32_t hash = literal->Hash();
231     // If the key of a computed property is in the table, do not emit
232     // a store for the property later.
233     if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
234          property->kind() == ObjectLiteral::Property::COMPUTED) &&
235         table.Lookup(literal, hash, false, allocator) != NULL) {
236       property->set_emit_store(false);
237     } else {
238       // Add key to the table.
239       table.Lookup(literal, hash, true, allocator);
240     }
241   }
242 }
243 
244 
IsBoilerplateProperty(ObjectLiteral::Property * property)245 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
246   return property != NULL &&
247          property->kind() != ObjectLiteral::Property::PROTOTYPE;
248 }
249 
250 
BuildConstantProperties(Isolate * isolate)251 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
252   if (!constant_properties_.is_null()) return;
253 
254   // Allocate a fixed array to hold all the constant properties.
255   Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
256       boilerplate_properties_ * 2, TENURED);
257 
258   int position = 0;
259   // Accumulate the value in local variables and store it at the end.
260   bool is_simple = true;
261   int depth_acc = 1;
262   uint32_t max_element_index = 0;
263   uint32_t elements = 0;
264   for (int i = 0; i < properties()->length(); i++) {
265     ObjectLiteral::Property* property = properties()->at(i);
266     if (!IsBoilerplateProperty(property)) {
267       is_simple = false;
268       continue;
269     }
270     MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
271     if (m_literal != NULL) {
272       m_literal->BuildConstants(isolate);
273       if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
274     }
275 
276     // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
277     // value for COMPUTED properties, the real value is filled in at
278     // runtime. The enumeration order is maintained.
279     Handle<Object> key = property->key()->value();
280     Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
281 
282     // Ensure objects that may, at any point in time, contain fields with double
283     // representation are always treated as nested objects. This is true for
284     // computed fields (value is undefined), and smi and double literals
285     // (value->IsNumber()).
286     // TODO(verwaest): Remove once we can store them inline.
287     if (FLAG_track_double_fields &&
288         (value->IsNumber() || value->IsUninitialized())) {
289       may_store_doubles_ = true;
290     }
291 
292     is_simple = is_simple && !value->IsUninitialized();
293 
294     // Keep track of the number of elements in the object literal and
295     // the largest element index.  If the largest element index is
296     // much larger than the number of elements, creating an object
297     // literal with fast elements will be a waste of space.
298     uint32_t element_index = 0;
299     if (key->IsString()
300         && Handle<String>::cast(key)->AsArrayIndex(&element_index)
301         && element_index > max_element_index) {
302       max_element_index = element_index;
303       elements++;
304     } else if (key->IsSmi()) {
305       int key_value = Smi::cast(*key)->value();
306       if (key_value > 0
307           && static_cast<uint32_t>(key_value) > max_element_index) {
308         max_element_index = key_value;
309       }
310       elements++;
311     }
312 
313     // Add name, value pair to the fixed array.
314     constant_properties->set(position++, *key);
315     constant_properties->set(position++, *value);
316   }
317 
318   constant_properties_ = constant_properties;
319   fast_elements_ =
320       (max_element_index <= 32) || ((2 * elements) >= max_element_index);
321   set_is_simple(is_simple);
322   set_depth(depth_acc);
323 }
324 
325 
BuildConstantElements(Isolate * isolate)326 void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
327   if (!constant_elements_.is_null()) return;
328 
329   // Allocate a fixed array to hold all the object literals.
330   Handle<JSArray> array =
331       isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
332   JSArray::Expand(array, values()->length());
333 
334   // Fill in the literals.
335   bool is_simple = true;
336   int depth_acc = 1;
337   bool is_holey = false;
338   for (int i = 0, n = values()->length(); i < n; i++) {
339     Expression* element = values()->at(i);
340     MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
341     if (m_literal != NULL) {
342       m_literal->BuildConstants(isolate);
343       if (m_literal->depth() + 1 > depth_acc) {
344         depth_acc = m_literal->depth() + 1;
345       }
346     }
347     Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
348     if (boilerplate_value->IsTheHole()) {
349       is_holey = true;
350     } else if (boilerplate_value->IsUninitialized()) {
351       is_simple = false;
352       JSObject::SetOwnElement(
353           array, i, handle(Smi::FromInt(0), isolate), SLOPPY).Assert();
354     } else {
355       JSObject::SetOwnElement(array, i, boilerplate_value, SLOPPY).Assert();
356     }
357   }
358 
359   Handle<FixedArrayBase> element_values(array->elements());
360 
361   // Simple and shallow arrays can be lazily copied, we transform the
362   // elements array to a copy-on-write array.
363   if (is_simple && depth_acc == 1 && values()->length() > 0 &&
364       array->HasFastSmiOrObjectElements()) {
365     element_values->set_map(isolate->heap()->fixed_cow_array_map());
366   }
367 
368   // Remember both the literal's constant values as well as the ElementsKind
369   // in a 2-element FixedArray.
370   Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
371 
372   ElementsKind kind = array->GetElementsKind();
373   kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
374 
375   literals->set(0, Smi::FromInt(kind));
376   literals->set(1, *element_values);
377 
378   constant_elements_ = literals;
379   set_is_simple(is_simple);
380   set_depth(depth_acc);
381 }
382 
383 
GetBoilerplateValue(Expression * expression,Isolate * isolate)384 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
385                                                         Isolate* isolate) {
386   if (expression->IsLiteral()) {
387     return expression->AsLiteral()->value();
388   }
389   if (CompileTimeValue::IsCompileTimeValue(expression)) {
390     return CompileTimeValue::GetValue(isolate, expression);
391   }
392   return isolate->factory()->uninitialized_value();
393 }
394 
395 
BuildConstants(Isolate * isolate)396 void MaterializedLiteral::BuildConstants(Isolate* isolate) {
397   if (IsArrayLiteral()) {
398     return AsArrayLiteral()->BuildConstantElements(isolate);
399   }
400   if (IsObjectLiteral()) {
401     return AsObjectLiteral()->BuildConstantProperties(isolate);
402   }
403   DCHECK(IsRegExpLiteral());
404   DCHECK(depth() >= 1);  // Depth should be initialized.
405 }
406 
407 
AddTarget(Label * target,Zone * zone)408 void TargetCollector::AddTarget(Label* target, Zone* zone) {
409   // Add the label to the collector, but discard duplicates.
410   int length = targets_.length();
411   for (int i = 0; i < length; i++) {
412     if (targets_[i] == target) return;
413   }
414   targets_.Add(target, zone);
415 }
416 
417 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)418 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
419   // TODO(olivf) If this Operation is used in a test context, then the
420   // expression has a ToBoolean stub and we want to collect the type
421   // information. However the GraphBuilder expects it to be on the instruction
422   // corresponding to the TestContext, therefore we have to store it here and
423   // not on the operand.
424   set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
425 }
426 
427 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)428 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
429   // TODO(olivf) If this Operation is used in a test context, then the right
430   // hand side has a ToBoolean stub and we want to collect the type information.
431   // However the GraphBuilder expects it to be on the instruction corresponding
432   // to the TestContext, therefore we have to store it here and not on the
433   // right hand operand.
434   set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
435 }
436 
437 
ResultOverwriteAllowed() const438 bool BinaryOperation::ResultOverwriteAllowed() const {
439   switch (op_) {
440     case Token::COMMA:
441     case Token::OR:
442     case Token::AND:
443       return false;
444     case Token::BIT_OR:
445     case Token::BIT_XOR:
446     case Token::BIT_AND:
447     case Token::SHL:
448     case Token::SAR:
449     case Token::SHR:
450     case Token::ADD:
451     case Token::SUB:
452     case Token::MUL:
453     case Token::DIV:
454     case Token::MOD:
455       return true;
456     default:
457       UNREACHABLE();
458   }
459   return false;
460 }
461 
462 
IsTypeof(Expression * expr)463 static bool IsTypeof(Expression* expr) {
464   UnaryOperation* maybe_unary = expr->AsUnaryOperation();
465   return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
466 }
467 
468 
469 // Check for the pattern: typeof <expression> equals <string literal>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Handle<String> * check)470 static bool MatchLiteralCompareTypeof(Expression* left,
471                                       Token::Value op,
472                                       Expression* right,
473                                       Expression** expr,
474                                       Handle<String>* check) {
475   if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
476     *expr = left->AsUnaryOperation()->expression();
477     *check = Handle<String>::cast(right->AsLiteral()->value());
478     return true;
479   }
480   return false;
481 }
482 
483 
IsLiteralCompareTypeof(Expression ** expr,Handle<String> * check)484 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
485                                               Handle<String>* check) {
486   return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
487       MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
488 }
489 
490 
IsVoidOfLiteral(Expression * expr)491 static bool IsVoidOfLiteral(Expression* expr) {
492   UnaryOperation* maybe_unary = expr->AsUnaryOperation();
493   return maybe_unary != NULL &&
494       maybe_unary->op() == Token::VOID &&
495       maybe_unary->expression()->IsLiteral();
496 }
497 
498 
499 // Check for the pattern: void <literal> equals <expression> or
500 // undefined equals <expression>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr,Isolate * isolate)501 static bool MatchLiteralCompareUndefined(Expression* left,
502                                          Token::Value op,
503                                          Expression* right,
504                                          Expression** expr,
505                                          Isolate* isolate) {
506   if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
507     *expr = right;
508     return true;
509   }
510   if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) {
511     *expr = right;
512     return true;
513   }
514   return false;
515 }
516 
517 
IsLiteralCompareUndefined(Expression ** expr,Isolate * isolate)518 bool CompareOperation::IsLiteralCompareUndefined(
519     Expression** expr, Isolate* isolate) {
520   return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) ||
521       MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate);
522 }
523 
524 
525 // Check for the pattern: null equals <expression>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)526 static bool MatchLiteralCompareNull(Expression* left,
527                                     Token::Value op,
528                                     Expression* right,
529                                     Expression** expr) {
530   if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
531     *expr = right;
532     return true;
533   }
534   return false;
535 }
536 
537 
IsLiteralCompareNull(Expression ** expr)538 bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
539   return MatchLiteralCompareNull(left_, op_, right_, expr) ||
540       MatchLiteralCompareNull(right_, op_, left_, expr);
541 }
542 
543 
544 // ----------------------------------------------------------------------------
545 // Inlining support
546 
IsInlineable() const547 bool Declaration::IsInlineable() const {
548   return proxy()->var()->IsStackAllocated();
549 }
550 
IsInlineable() const551 bool FunctionDeclaration::IsInlineable() const {
552   return false;
553 }
554 
555 
556 // ----------------------------------------------------------------------------
557 // Recording of type feedback
558 
559 // TODO(rossberg): all RecordTypeFeedback functions should disappear
560 // once we use the common type field in the AST consistently.
561 
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)562 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
563   to_boolean_types_ = oracle->ToBooleanTypes(test_id());
564 }
565 
566 
IsUsingCallFeedbackSlot(Isolate * isolate) const567 bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
568   CallType call_type = GetCallType(isolate);
569   return (call_type != POSSIBLY_EVAL_CALL);
570 }
571 
572 
GetCallType(Isolate * isolate) const573 Call::CallType Call::GetCallType(Isolate* isolate) const {
574   VariableProxy* proxy = expression()->AsVariableProxy();
575   if (proxy != NULL) {
576     if (proxy->var()->is_possibly_eval(isolate)) {
577       return POSSIBLY_EVAL_CALL;
578     } else if (proxy->var()->IsUnallocated()) {
579       return GLOBAL_CALL;
580     } else if (proxy->var()->IsLookupSlot()) {
581       return LOOKUP_SLOT_CALL;
582     }
583   }
584 
585   Property* property = expression()->AsProperty();
586   return property != NULL ? PROPERTY_CALL : OTHER_CALL;
587 }
588 
589 
ComputeGlobalTarget(Handle<GlobalObject> global,LookupIterator * it)590 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
591                                LookupIterator* it) {
592   target_ = Handle<JSFunction>::null();
593   cell_ = Handle<Cell>::null();
594   DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global));
595   cell_ = it->GetPropertyCell();
596   if (cell_->value()->IsJSFunction()) {
597     Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
598     // If the function is in new space we assume it's more likely to
599     // change and thus prefer the general IC code.
600     if (!it->isolate()->heap()->InNewSpace(*candidate)) {
601       target_ = candidate;
602       return true;
603     }
604   }
605   return false;
606 }
607 
608 
RecordTypeFeedback(TypeFeedbackOracle * oracle)609 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
610   int allocation_site_feedback_slot = FLAG_pretenuring_call_new
611       ? AllocationSiteFeedbackSlot()
612       : CallNewFeedbackSlot();
613   allocation_site_ =
614       oracle->GetCallNewAllocationSite(allocation_site_feedback_slot);
615   is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot());
616   if (is_monomorphic_) {
617     target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot());
618     if (!allocation_site_.is_null()) {
619       elements_kind_ = allocation_site_->GetElementsKind();
620     }
621   }
622 }
623 
624 
RecordTypeFeedback(TypeFeedbackOracle * oracle)625 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
626   TypeFeedbackId id = key()->LiteralFeedbackId();
627   SmallMapList maps;
628   oracle->CollectReceiverTypes(id, &maps);
629   receiver_type_ = maps.length() == 1 ? maps.at(0)
630                                       : Handle<Map>::null();
631 }
632 
633 
634 // ----------------------------------------------------------------------------
635 // Implementation of AstVisitor
636 
VisitDeclarations(ZoneList<Declaration * > * declarations)637 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
638   for (int i = 0; i < declarations->length(); i++) {
639     Visit(declarations->at(i));
640   }
641 }
642 
643 
VisitStatements(ZoneList<Statement * > * statements)644 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
645   for (int i = 0; i < statements->length(); i++) {
646     Statement* stmt = statements->at(i);
647     Visit(stmt);
648     if (stmt->IsJump()) break;
649   }
650 }
651 
652 
VisitExpressions(ZoneList<Expression * > * expressions)653 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
654   for (int i = 0; i < expressions->length(); i++) {
655     // The variable statement visiting code may pass NULL expressions
656     // to this code. Maybe this should be handled by introducing an
657     // undefined expression or literal?  Revisit this code if this
658     // changes
659     Expression* expression = expressions->at(i);
660     if (expression != NULL) Visit(expression);
661   }
662 }
663 
664 
665 // ----------------------------------------------------------------------------
666 // Regular expressions
667 
668 #define MAKE_ACCEPT(Name)                                            \
669   void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) {   \
670     return visitor->Visit##Name(this, data);                         \
671   }
672 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
673 #undef MAKE_ACCEPT
674 
675 #define MAKE_TYPE_CASE(Name)                                         \
676   RegExp##Name* RegExpTree::As##Name() {                             \
677     return NULL;                                                     \
678   }                                                                  \
679   bool RegExpTree::Is##Name() { return false; }
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)680 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
681 #undef MAKE_TYPE_CASE
682 
683 #define MAKE_TYPE_CASE(Name)                                        \
684   RegExp##Name* RegExp##Name::As##Name() {                          \
685     return this;                                                    \
686   }                                                                 \
687   bool RegExp##Name::Is##Name() { return true; }
688 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
689 #undef MAKE_TYPE_CASE
690 
691 
692 static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) {
693   Interval result = Interval::Empty();
694   for (int i = 0; i < children->length(); i++)
695     result = result.Union(children->at(i)->CaptureRegisters());
696   return result;
697 }
698 
699 
CaptureRegisters()700 Interval RegExpAlternative::CaptureRegisters() {
701   return ListCaptureRegisters(nodes());
702 }
703 
704 
CaptureRegisters()705 Interval RegExpDisjunction::CaptureRegisters() {
706   return ListCaptureRegisters(alternatives());
707 }
708 
709 
CaptureRegisters()710 Interval RegExpLookahead::CaptureRegisters() {
711   return body()->CaptureRegisters();
712 }
713 
714 
CaptureRegisters()715 Interval RegExpCapture::CaptureRegisters() {
716   Interval self(StartRegister(index()), EndRegister(index()));
717   return self.Union(body()->CaptureRegisters());
718 }
719 
720 
CaptureRegisters()721 Interval RegExpQuantifier::CaptureRegisters() {
722   return body()->CaptureRegisters();
723 }
724 
725 
IsAnchoredAtStart()726 bool RegExpAssertion::IsAnchoredAtStart() {
727   return assertion_type() == RegExpAssertion::START_OF_INPUT;
728 }
729 
730 
IsAnchoredAtEnd()731 bool RegExpAssertion::IsAnchoredAtEnd() {
732   return assertion_type() == RegExpAssertion::END_OF_INPUT;
733 }
734 
735 
IsAnchoredAtStart()736 bool RegExpAlternative::IsAnchoredAtStart() {
737   ZoneList<RegExpTree*>* nodes = this->nodes();
738   for (int i = 0; i < nodes->length(); i++) {
739     RegExpTree* node = nodes->at(i);
740     if (node->IsAnchoredAtStart()) { return true; }
741     if (node->max_match() > 0) { return false; }
742   }
743   return false;
744 }
745 
746 
IsAnchoredAtEnd()747 bool RegExpAlternative::IsAnchoredAtEnd() {
748   ZoneList<RegExpTree*>* nodes = this->nodes();
749   for (int i = nodes->length() - 1; i >= 0; i--) {
750     RegExpTree* node = nodes->at(i);
751     if (node->IsAnchoredAtEnd()) { return true; }
752     if (node->max_match() > 0) { return false; }
753   }
754   return false;
755 }
756 
757 
IsAnchoredAtStart()758 bool RegExpDisjunction::IsAnchoredAtStart() {
759   ZoneList<RegExpTree*>* alternatives = this->alternatives();
760   for (int i = 0; i < alternatives->length(); i++) {
761     if (!alternatives->at(i)->IsAnchoredAtStart())
762       return false;
763   }
764   return true;
765 }
766 
767 
IsAnchoredAtEnd()768 bool RegExpDisjunction::IsAnchoredAtEnd() {
769   ZoneList<RegExpTree*>* alternatives = this->alternatives();
770   for (int i = 0; i < alternatives->length(); i++) {
771     if (!alternatives->at(i)->IsAnchoredAtEnd())
772       return false;
773   }
774   return true;
775 }
776 
777 
IsAnchoredAtStart()778 bool RegExpLookahead::IsAnchoredAtStart() {
779   return is_positive() && body()->IsAnchoredAtStart();
780 }
781 
782 
IsAnchoredAtStart()783 bool RegExpCapture::IsAnchoredAtStart() {
784   return body()->IsAnchoredAtStart();
785 }
786 
787 
IsAnchoredAtEnd()788 bool RegExpCapture::IsAnchoredAtEnd() {
789   return body()->IsAnchoredAtEnd();
790 }
791 
792 
793 // Convert regular expression trees to a simple sexp representation.
794 // This representation should be different from the input grammar
795 // in as many cases as possible, to make it more difficult for incorrect
796 // parses to look as correct ones which is likely if the input and
797 // output formats are alike.
798 class RegExpUnparser FINAL : public RegExpVisitor {
799  public:
RegExpUnparser(OStream & os,Zone * zone)800   RegExpUnparser(OStream& os, Zone* zone) : os_(os), zone_(zone) {}
801   void VisitCharacterRange(CharacterRange that);
802 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*,          \
803                                                   void* data) OVERRIDE;
804   FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
805 #undef MAKE_CASE
806  private:
807   OStream& os_;
808   Zone* zone_;
809 };
810 
811 
VisitDisjunction(RegExpDisjunction * that,void * data)812 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
813   os_ << "(|";
814   for (int i = 0; i <  that->alternatives()->length(); i++) {
815     os_ << " ";
816     that->alternatives()->at(i)->Accept(this, data);
817   }
818   os_ << ")";
819   return NULL;
820 }
821 
822 
VisitAlternative(RegExpAlternative * that,void * data)823 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
824   os_ << "(:";
825   for (int i = 0; i <  that->nodes()->length(); i++) {
826     os_ << " ";
827     that->nodes()->at(i)->Accept(this, data);
828   }
829   os_ << ")";
830   return NULL;
831 }
832 
833 
VisitCharacterRange(CharacterRange that)834 void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
835   os_ << AsUC16(that.from());
836   if (!that.IsSingleton()) {
837     os_ << "-" << AsUC16(that.to());
838   }
839 }
840 
841 
842 
VisitCharacterClass(RegExpCharacterClass * that,void * data)843 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
844                                           void* data) {
845   if (that->is_negated()) os_ << "^";
846   os_ << "[";
847   for (int i = 0; i < that->ranges(zone_)->length(); i++) {
848     if (i > 0) os_ << " ";
849     VisitCharacterRange(that->ranges(zone_)->at(i));
850   }
851   os_ << "]";
852   return NULL;
853 }
854 
855 
VisitAssertion(RegExpAssertion * that,void * data)856 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
857   switch (that->assertion_type()) {
858     case RegExpAssertion::START_OF_INPUT:
859       os_ << "@^i";
860       break;
861     case RegExpAssertion::END_OF_INPUT:
862       os_ << "@$i";
863       break;
864     case RegExpAssertion::START_OF_LINE:
865       os_ << "@^l";
866       break;
867     case RegExpAssertion::END_OF_LINE:
868       os_ << "@$l";
869        break;
870     case RegExpAssertion::BOUNDARY:
871       os_ << "@b";
872       break;
873     case RegExpAssertion::NON_BOUNDARY:
874       os_ << "@B";
875       break;
876   }
877   return NULL;
878 }
879 
880 
VisitAtom(RegExpAtom * that,void * data)881 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
882   os_ << "'";
883   Vector<const uc16> chardata = that->data();
884   for (int i = 0; i < chardata.length(); i++) {
885     os_ << AsUC16(chardata[i]);
886   }
887   os_ << "'";
888   return NULL;
889 }
890 
891 
VisitText(RegExpText * that,void * data)892 void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
893   if (that->elements()->length() == 1) {
894     that->elements()->at(0).tree()->Accept(this, data);
895   } else {
896     os_ << "(!";
897     for (int i = 0; i < that->elements()->length(); i++) {
898       os_ << " ";
899       that->elements()->at(i).tree()->Accept(this, data);
900     }
901     os_ << ")";
902   }
903   return NULL;
904 }
905 
906 
VisitQuantifier(RegExpQuantifier * that,void * data)907 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
908   os_ << "(# " << that->min() << " ";
909   if (that->max() == RegExpTree::kInfinity) {
910     os_ << "- ";
911   } else {
912     os_ << that->max() << " ";
913   }
914   os_ << (that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
915   that->body()->Accept(this, data);
916   os_ << ")";
917   return NULL;
918 }
919 
920 
VisitCapture(RegExpCapture * that,void * data)921 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
922   os_ << "(^ ";
923   that->body()->Accept(this, data);
924   os_ << ")";
925   return NULL;
926 }
927 
928 
VisitLookahead(RegExpLookahead * that,void * data)929 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
930   os_ << "(-> " << (that->is_positive() ? "+ " : "- ");
931   that->body()->Accept(this, data);
932   os_ << ")";
933   return NULL;
934 }
935 
936 
VisitBackReference(RegExpBackReference * that,void * data)937 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
938                                          void* data) {
939   os_ << "(<- " << that->index() << ")";
940   return NULL;
941 }
942 
943 
VisitEmpty(RegExpEmpty * that,void * data)944 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
945   os_ << '%';
946   return NULL;
947 }
948 
949 
Print(OStream & os,Zone * zone)950 OStream& RegExpTree::Print(OStream& os, Zone* zone) {  // NOLINT
951   RegExpUnparser unparser(os, zone);
952   Accept(&unparser, NULL);
953   return os;
954 }
955 
956 
RegExpDisjunction(ZoneList<RegExpTree * > * alternatives)957 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
958     : alternatives_(alternatives) {
959   DCHECK(alternatives->length() > 1);
960   RegExpTree* first_alternative = alternatives->at(0);
961   min_match_ = first_alternative->min_match();
962   max_match_ = first_alternative->max_match();
963   for (int i = 1; i < alternatives->length(); i++) {
964     RegExpTree* alternative = alternatives->at(i);
965     min_match_ = Min(min_match_, alternative->min_match());
966     max_match_ = Max(max_match_, alternative->max_match());
967   }
968 }
969 
970 
IncreaseBy(int previous,int increase)971 static int IncreaseBy(int previous, int increase) {
972   if (RegExpTree::kInfinity - previous < increase) {
973     return RegExpTree::kInfinity;
974   } else {
975     return previous + increase;
976   }
977 }
978 
RegExpAlternative(ZoneList<RegExpTree * > * nodes)979 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
980     : nodes_(nodes) {
981   DCHECK(nodes->length() > 1);
982   min_match_ = 0;
983   max_match_ = 0;
984   for (int i = 0; i < nodes->length(); i++) {
985     RegExpTree* node = nodes->at(i);
986     int node_min_match = node->min_match();
987     min_match_ = IncreaseBy(min_match_, node_min_match);
988     int node_max_match = node->max_match();
989     max_match_ = IncreaseBy(max_match_, node_max_match);
990   }
991 }
992 
993 
CaseClause(Zone * zone,Expression * label,ZoneList<Statement * > * statements,int pos,IdGen * id_gen)994 CaseClause::CaseClause(Zone* zone, Expression* label,
995                        ZoneList<Statement*>* statements, int pos, IdGen* id_gen)
996     : Expression(zone, pos, id_gen),
997       label_(label),
998       statements_(statements),
999       compare_type_(Type::None(zone)),
1000       compare_id_(id_gen->GetNextId()),
1001       entry_id_(id_gen->GetNextId()) {}
1002 
1003 
1004 #define REGULAR_NODE(NodeType)                                   \
1005   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1006     increase_node_count();                                       \
1007   }
1008 #define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType)               \
1009   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1010     increase_node_count();                                       \
1011     add_slot_node(node);                                         \
1012   }
1013 #define DONT_OPTIMIZE_NODE(NodeType)                             \
1014   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1015     increase_node_count();                                       \
1016     set_dont_crankshaft_reason(k##NodeType);                     \
1017     add_flag(kDontSelfOptimize);                                 \
1018   }
1019 #define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)         \
1020   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1021     increase_node_count();                                       \
1022     add_slot_node(node);                                         \
1023     set_dont_crankshaft_reason(k##NodeType);                     \
1024     add_flag(kDontSelfOptimize);                                 \
1025   }
1026 #define DONT_TURBOFAN_NODE(NodeType)                             \
1027   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1028     increase_node_count();                                       \
1029     set_dont_crankshaft_reason(k##NodeType);                     \
1030     set_dont_turbofan_reason(k##NodeType);                       \
1031     add_flag(kDontSelfOptimize);                                 \
1032   }
1033 #define DONT_SELFOPTIMIZE_NODE(NodeType)                         \
1034   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1035     increase_node_count();                                       \
1036     add_flag(kDontSelfOptimize);                                 \
1037   }
1038 #define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)     \
1039   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1040     increase_node_count();                                       \
1041     add_slot_node(node);                                         \
1042     add_flag(kDontSelfOptimize);                                 \
1043   }
1044 #define DONT_CACHE_NODE(NodeType)                                \
1045   void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
1046     increase_node_count();                                       \
1047     set_dont_crankshaft_reason(k##NodeType);                     \
1048     add_flag(kDontSelfOptimize);                                 \
1049     add_flag(kDontCache);                                        \
1050   }
1051 
1052 REGULAR_NODE(VariableDeclaration)
REGULAR_NODE(FunctionDeclaration)1053 REGULAR_NODE(FunctionDeclaration)
1054 REGULAR_NODE(Block)
1055 REGULAR_NODE(ExpressionStatement)
1056 REGULAR_NODE(EmptyStatement)
1057 REGULAR_NODE(IfStatement)
1058 REGULAR_NODE(ContinueStatement)
1059 REGULAR_NODE(BreakStatement)
1060 REGULAR_NODE(ReturnStatement)
1061 REGULAR_NODE(SwitchStatement)
1062 REGULAR_NODE(CaseClause)
1063 REGULAR_NODE(Conditional)
1064 REGULAR_NODE(Literal)
1065 REGULAR_NODE(ArrayLiteral)
1066 REGULAR_NODE(ObjectLiteral)
1067 REGULAR_NODE(RegExpLiteral)
1068 REGULAR_NODE(FunctionLiteral)
1069 REGULAR_NODE(Assignment)
1070 REGULAR_NODE(Throw)
1071 REGULAR_NODE(UnaryOperation)
1072 REGULAR_NODE(CountOperation)
1073 REGULAR_NODE(BinaryOperation)
1074 REGULAR_NODE(CompareOperation)
1075 REGULAR_NODE(ThisFunction)
1076 
1077 REGULAR_NODE_WITH_FEEDBACK_SLOTS(Call)
1078 REGULAR_NODE_WITH_FEEDBACK_SLOTS(CallNew)
1079 REGULAR_NODE_WITH_FEEDBACK_SLOTS(Property)
1080 // In theory, for VariableProxy we'd have to add:
1081 // if (node->var()->IsLookupSlot())
1082 //   set_dont_optimize_reason(kReferenceToAVariableWhichRequiresDynamicLookup);
1083 // But node->var() is usually not bound yet at VariableProxy creation time, and
1084 // LOOKUP variables only result from constructs that cannot be inlined anyway.
1085 REGULAR_NODE_WITH_FEEDBACK_SLOTS(VariableProxy)
1086 
1087 // We currently do not optimize any modules.
1088 DONT_OPTIMIZE_NODE(ModuleDeclaration)
1089 DONT_OPTIMIZE_NODE(ImportDeclaration)
1090 DONT_OPTIMIZE_NODE(ExportDeclaration)
1091 DONT_OPTIMIZE_NODE(ModuleVariable)
1092 DONT_OPTIMIZE_NODE(ModulePath)
1093 DONT_OPTIMIZE_NODE(ModuleUrl)
1094 DONT_OPTIMIZE_NODE(ModuleStatement)
1095 DONT_OPTIMIZE_NODE(WithStatement)
1096 DONT_OPTIMIZE_NODE(DebuggerStatement)
1097 DONT_OPTIMIZE_NODE(ClassLiteral)
1098 DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
1099 DONT_OPTIMIZE_NODE(SuperReference)
1100 
1101 DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(Yield)
1102 
1103 // TODO(turbofan): Remove the dont_turbofan_reason once this list is empty.
1104 DONT_TURBOFAN_NODE(ForOfStatement)
1105 DONT_TURBOFAN_NODE(TryCatchStatement)
1106 DONT_TURBOFAN_NODE(TryFinallyStatement)
1107 
1108 DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
1109 DONT_SELFOPTIMIZE_NODE(WhileStatement)
1110 DONT_SELFOPTIMIZE_NODE(ForStatement)
1111 
1112 DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement)
1113 
1114 DONT_CACHE_NODE(ModuleLiteral)
1115 
1116 
1117 void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
1118   increase_node_count();
1119   add_slot_node(node);
1120   if (node->is_jsruntime()) {
1121     // Don't try to optimize JS runtime calls because we bailout on them.
1122     set_dont_crankshaft_reason(kCallToAJavaScriptRuntimeFunction);
1123   }
1124 }
1125 
1126 #undef REGULAR_NODE
1127 #undef DONT_OPTIMIZE_NODE
1128 #undef DONT_SELFOPTIMIZE_NODE
1129 #undef DONT_CACHE_NODE
1130 
1131 
ToString()1132 Handle<String> Literal::ToString() {
1133   if (value_->IsString()) return value_->AsString()->string();
1134   DCHECK(value_->IsNumber());
1135   char arr[100];
1136   Vector<char> buffer(arr, arraysize(arr));
1137   const char* str;
1138   if (value()->IsSmi()) {
1139     // Optimization only, the heap number case would subsume this.
1140     SNPrintF(buffer, "%d", Smi::cast(*value())->value());
1141     str = arr;
1142   } else {
1143     str = DoubleToCString(value()->Number(), buffer);
1144   }
1145   return isolate_->factory()->NewStringFromAsciiChecked(str);
1146 }
1147 
1148 
1149 } }  // namespace v8::internal
1150