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