blob: 69e7351a7d3d9cb1e7626058bd8f97e91ad5c193 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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/ast.h"
6
7#include <cmath> // For isfinite.
8#include "src/ast/scopes.h"
9#include "src/builtins.h"
10#include "src/code-stubs.h"
11#include "src/contexts.h"
12#include "src/conversions.h"
13#include "src/hashmap.h"
14#include "src/parsing/parser.h"
15#include "src/property.h"
16#include "src/property-details.h"
17#include "src/string-stream.h"
18#include "src/type-info.h"
19
20namespace v8 {
21namespace 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); }
28AST_NODE_LIST(DECL_ACCEPT)
29#undef DECL_ACCEPT
30
31
32// ----------------------------------------------------------------------------
33// Implementation of other node functionality.
34
35
36bool Expression::IsSmiLiteral() const {
37 return IsLiteral() && AsLiteral()->value()->IsSmi();
38}
39
40
41bool Expression::IsStringLiteral() const {
42 return IsLiteral() && AsLiteral()->value()->IsString();
43}
44
45
46bool Expression::IsNullLiteral() const {
47 return IsLiteral() && AsLiteral()->value()->IsNull();
48}
49
50
51bool 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->IsUnallocatedOrGlobalSlot() &&
58 var_proxy->raw_name()->IsOneByteEqualTo("undefined");
59}
60
61
62bool Expression::IsValidReferenceExpressionOrThis() const {
63 return IsValidReferenceExpression() ||
64 (IsVariableProxy() && AsVariableProxy()->is_this());
65}
66
67
68VariableProxy::VariableProxy(Zone* zone, Variable* var, int start_position,
69 int end_position)
70 : Expression(zone, start_position),
71 bit_field_(IsThisField::encode(var->is_this()) |
72 IsAssignedField::encode(false) |
73 IsResolvedField::encode(false)),
74 raw_name_(var->raw_name()),
75 end_position_(end_position) {
76 BindTo(var);
77}
78
79
80VariableProxy::VariableProxy(Zone* zone, const AstRawString* name,
81 Variable::Kind variable_kind, int start_position,
82 int end_position)
83 : Expression(zone, start_position),
84 bit_field_(IsThisField::encode(variable_kind == Variable::THIS) |
85 IsAssignedField::encode(false) |
86 IsResolvedField::encode(false)),
87 raw_name_(name),
88 end_position_(end_position) {}
89
90
91void VariableProxy::BindTo(Variable* var) {
92 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
93 set_var(var);
94 set_is_resolved();
95 var->set_is_used();
96}
97
98
99void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate,
100 FeedbackVectorSpec* spec,
101 FeedbackVectorSlotCache* cache) {
102 if (UsesVariableFeedbackSlot()) {
103 // VariableProxies that point to the same Variable within a function can
104 // make their loads from the same IC slot.
105 if (var()->IsUnallocated()) {
106 ZoneHashMap::Entry* entry = cache->Get(var());
107 if (entry != NULL) {
108 variable_feedback_slot_ = FeedbackVectorSlot(
109 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)));
110 return;
111 }
112 }
113 variable_feedback_slot_ = spec->AddLoadICSlot();
114 if (var()->IsUnallocated()) {
115 cache->Put(var(), variable_feedback_slot_);
116 }
117 }
118}
119
120
121static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
122 FeedbackVectorSlot* out_slot) {
123 Property* property = expr->AsProperty();
124 LhsKind assign_type = Property::GetAssignType(property);
125 if ((assign_type == VARIABLE &&
126 expr->AsVariableProxy()->var()->IsUnallocated()) ||
127 assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
128 // TODO(ishell): consider using ICSlotCache for variables here.
129 FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY
130 ? FeedbackVectorSlotKind::KEYED_STORE_IC
131 : FeedbackVectorSlotKind::STORE_IC;
132 *out_slot = spec->AddSlot(kind);
133 }
134}
135
136
137void ForEachStatement::AssignFeedbackVectorSlots(
138 Isolate* isolate, FeedbackVectorSpec* spec,
139 FeedbackVectorSlotCache* cache) {
140 // TODO(adamk): for-of statements do not make use of this feedback slot.
141 // The each_slot_ should be specific to ForInStatement, and this work moved
142 // there.
143 if (IsForOfStatement()) return;
144 AssignVectorSlots(each(), spec, &each_slot_);
145}
146
147
148Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
149 Expression* value, int pos)
150 : Expression(zone, pos),
151 bit_field_(
152 IsUninitializedField::encode(false) | KeyTypeField::encode(ELEMENT) |
153 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)),
154 target_(target),
155 value_(value),
156 binary_operation_(NULL) {}
157
158
159void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
160 FeedbackVectorSpec* spec,
161 FeedbackVectorSlotCache* cache) {
162 AssignVectorSlots(target(), spec, &slot_);
163}
164
165
166void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
167 FeedbackVectorSpec* spec,
168 FeedbackVectorSlotCache* cache) {
169 AssignVectorSlots(expression(), spec, &slot_);
170}
171
172
173Token::Value Assignment::binary_op() const {
174 switch (op()) {
175 case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
176 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
177 case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
178 case Token::ASSIGN_SHL: return Token::SHL;
179 case Token::ASSIGN_SAR: return Token::SAR;
180 case Token::ASSIGN_SHR: return Token::SHR;
181 case Token::ASSIGN_ADD: return Token::ADD;
182 case Token::ASSIGN_SUB: return Token::SUB;
183 case Token::ASSIGN_MUL: return Token::MUL;
184 case Token::ASSIGN_DIV: return Token::DIV;
185 case Token::ASSIGN_MOD: return Token::MOD;
186 default: UNREACHABLE();
187 }
188 return Token::ILLEGAL;
189}
190
191
192bool FunctionLiteral::AllowsLazyCompilation() {
193 return scope()->AllowsLazyCompilation();
194}
195
196
197bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
198 return scope()->AllowsLazyCompilationWithoutContext();
199}
200
201
202int FunctionLiteral::start_position() const {
203 return scope()->start_position();
204}
205
206
207int FunctionLiteral::end_position() const {
208 return scope()->end_position();
209}
210
211
212LanguageMode FunctionLiteral::language_mode() const {
213 return scope()->language_mode();
214}
215
216
217bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
218 if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
219 DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
220 return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
221}
222
223
224ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
225 Kind kind, bool is_static,
226 bool is_computed_name)
227 : key_(key),
228 value_(value),
229 kind_(kind),
230 emit_store_(true),
231 is_static_(is_static),
232 is_computed_name_(is_computed_name) {}
233
234
235ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
236 Expression* key, Expression* value,
237 bool is_static,
238 bool is_computed_name)
239 : key_(key),
240 value_(value),
241 emit_store_(true),
242 is_static_(is_static),
243 is_computed_name_(is_computed_name) {
244 if (!is_computed_name &&
245 key->AsLiteral()->raw_value()->EqualsString(
246 ast_value_factory->proto_string())) {
247 kind_ = PROTOTYPE;
248 } else if (value_->AsMaterializedLiteral() != NULL) {
249 kind_ = MATERIALIZED_LITERAL;
250 } else if (value_->IsLiteral()) {
251 kind_ = CONSTANT;
252 } else {
253 kind_ = COMPUTED;
254 }
255}
256
257
258void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
259 FeedbackVectorSpec* spec,
260 FeedbackVectorSlotCache* cache) {
261 // This logic that computes the number of slots needed for vector store
262 // ICs must mirror FullCodeGenerator::VisitClassLiteral.
263 if (NeedsProxySlot()) {
264 slot_ = spec->AddStoreICSlot();
265 }
266
267 for (int i = 0; i < properties()->length(); i++) {
268 ObjectLiteral::Property* property = properties()->at(i);
269 Expression* value = property->value();
270 if (FunctionLiteral::NeedsHomeObject(value)) {
271 property->SetSlot(spec->AddStoreICSlot());
272 }
273 }
274}
275
276
277bool ObjectLiteral::Property::IsCompileTimeValue() {
278 return kind_ == CONSTANT ||
279 (kind_ == MATERIALIZED_LITERAL &&
280 CompileTimeValue::IsCompileTimeValue(value_));
281}
282
283
284void ObjectLiteral::Property::set_emit_store(bool emit_store) {
285 emit_store_ = emit_store;
286}
287
288
289bool ObjectLiteral::Property::emit_store() {
290 return emit_store_;
291}
292
293
294void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
295 FeedbackVectorSpec* spec,
296 FeedbackVectorSlotCache* cache) {
297 // This logic that computes the number of slots needed for vector store
298 // ics must mirror FullCodeGenerator::VisitObjectLiteral.
299 int property_index = 0;
300 for (; property_index < properties()->length(); property_index++) {
301 ObjectLiteral::Property* property = properties()->at(property_index);
302 if (property->is_computed_name()) break;
303 if (property->IsCompileTimeValue()) continue;
304
305 Literal* key = property->key()->AsLiteral();
306 Expression* value = property->value();
307 switch (property->kind()) {
308 case ObjectLiteral::Property::CONSTANT:
309 UNREACHABLE();
310 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
311 // Fall through.
312 case ObjectLiteral::Property::COMPUTED:
313 // It is safe to use [[Put]] here because the boilerplate already
314 // contains computed properties with an uninitialized value.
315 if (key->value()->IsInternalizedString()) {
316 if (property->emit_store()) {
317 property->SetSlot(spec->AddStoreICSlot());
318 if (FunctionLiteral::NeedsHomeObject(value)) {
319 property->SetSlot(spec->AddStoreICSlot(), 1);
320 }
321 }
322 break;
323 }
324 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
325 property->SetSlot(spec->AddStoreICSlot());
326 }
327 break;
328 case ObjectLiteral::Property::PROTOTYPE:
329 break;
330 case ObjectLiteral::Property::GETTER:
331 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
332 property->SetSlot(spec->AddStoreICSlot());
333 }
334 break;
335 case ObjectLiteral::Property::SETTER:
336 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
337 property->SetSlot(spec->AddStoreICSlot());
338 }
339 break;
340 }
341 }
342
343 for (; property_index < properties()->length(); property_index++) {
344 ObjectLiteral::Property* property = properties()->at(property_index);
345
346 Expression* value = property->value();
347 if (property->kind() != ObjectLiteral::Property::PROTOTYPE) {
348 if (FunctionLiteral::NeedsHomeObject(value)) {
349 property->SetSlot(spec->AddStoreICSlot());
350 }
351 }
352 }
353}
354
355
356void ObjectLiteral::CalculateEmitStore(Zone* zone) {
357 const auto GETTER = ObjectLiteral::Property::GETTER;
358 const auto SETTER = ObjectLiteral::Property::SETTER;
359
360 ZoneAllocationPolicy allocator(zone);
361
362 ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
363 allocator);
364 for (int i = properties()->length() - 1; i >= 0; i--) {
365 ObjectLiteral::Property* property = properties()->at(i);
366 if (property->is_computed_name()) continue;
367 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue;
368 Literal* literal = property->key()->AsLiteral();
369 DCHECK(!literal->value()->IsNull());
370
371 // If there is an existing entry do not emit a store unless the previous
372 // entry was also an accessor.
373 uint32_t hash = literal->Hash();
374 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator);
375 if (entry->value != NULL) {
376 auto previous_kind =
377 static_cast<ObjectLiteral::Property*>(entry->value)->kind();
378 if (!((property->kind() == GETTER && previous_kind == SETTER) ||
379 (property->kind() == SETTER && previous_kind == GETTER))) {
380 property->set_emit_store(false);
381 }
382 }
383 entry->value = property;
384 }
385}
386
387
388bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
389 return property != NULL &&
390 property->kind() != ObjectLiteral::Property::PROTOTYPE;
391}
392
393
394void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
395 if (!constant_properties_.is_null()) return;
396
397 // Allocate a fixed array to hold all the constant properties.
398 Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
399 boilerplate_properties_ * 2, TENURED);
400
401 int position = 0;
402 // Accumulate the value in local variables and store it at the end.
403 bool is_simple = true;
404 int depth_acc = 1;
405 uint32_t max_element_index = 0;
406 uint32_t elements = 0;
407 for (int i = 0; i < properties()->length(); i++) {
408 ObjectLiteral::Property* property = properties()->at(i);
409 if (!IsBoilerplateProperty(property)) {
410 is_simple = false;
411 continue;
412 }
413
414 if (position == boilerplate_properties_ * 2) {
415 DCHECK(property->is_computed_name());
416 is_simple = false;
417 break;
418 }
419 DCHECK(!property->is_computed_name());
420
421 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
422 if (m_literal != NULL) {
423 m_literal->BuildConstants(isolate);
424 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
425 }
426
427 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
428 // value for COMPUTED properties, the real value is filled in at
429 // runtime. The enumeration order is maintained.
430 Handle<Object> key = property->key()->AsLiteral()->value();
431 Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
432
433 // Ensure objects that may, at any point in time, contain fields with double
434 // representation are always treated as nested objects. This is true for
435 // computed fields (value is undefined), and smi and double literals
436 // (value->IsNumber()).
437 // TODO(verwaest): Remove once we can store them inline.
438 if (FLAG_track_double_fields &&
439 (value->IsNumber() || value->IsUninitialized())) {
440 may_store_doubles_ = true;
441 }
442
443 is_simple = is_simple && !value->IsUninitialized();
444
445 // Keep track of the number of elements in the object literal and
446 // the largest element index. If the largest element index is
447 // much larger than the number of elements, creating an object
448 // literal with fast elements will be a waste of space.
449 uint32_t element_index = 0;
450 if (key->IsString()
451 && Handle<String>::cast(key)->AsArrayIndex(&element_index)
452 && element_index > max_element_index) {
453 max_element_index = element_index;
454 elements++;
455 } else if (key->IsSmi()) {
456 int key_value = Smi::cast(*key)->value();
457 if (key_value > 0
458 && static_cast<uint32_t>(key_value) > max_element_index) {
459 max_element_index = key_value;
460 }
461 elements++;
462 }
463
464 // Add name, value pair to the fixed array.
465 constant_properties->set(position++, *key);
466 constant_properties->set(position++, *value);
467 }
468
469 constant_properties_ = constant_properties;
470 fast_elements_ =
471 (max_element_index <= 32) || ((2 * elements) >= max_element_index);
472 has_elements_ = elements > 0;
473 set_is_simple(is_simple);
474 set_depth(depth_acc);
475}
476
477
478void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
479 if (!constant_elements_.is_null()) return;
480
481 int constants_length =
482 first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
483
484 // Allocate a fixed array to hold all the object literals.
485 Handle<JSArray> array = isolate->factory()->NewJSArray(
486 FAST_HOLEY_SMI_ELEMENTS, constants_length, constants_length,
487 Strength::WEAK, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
488
489 // Fill in the literals.
490 bool is_simple = (first_spread_index_ < 0);
491 int depth_acc = 1;
492 bool is_holey = false;
493 int array_index = 0;
494 for (; array_index < constants_length; array_index++) {
495 Expression* element = values()->at(array_index);
496 DCHECK(!element->IsSpread());
497 MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
498 if (m_literal != NULL) {
499 m_literal->BuildConstants(isolate);
500 if (m_literal->depth() + 1 > depth_acc) {
501 depth_acc = m_literal->depth() + 1;
502 }
503 }
504
505 // New handle scope here, needs to be after BuildContants().
506 HandleScope scope(isolate);
507 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
508 if (boilerplate_value->IsTheHole()) {
509 is_holey = true;
510 continue;
511 }
512
513 if (boilerplate_value->IsUninitialized()) {
514 boilerplate_value = handle(Smi::FromInt(0), isolate);
515 is_simple = false;
516 }
517
518 JSObject::AddDataElement(array, array_index, boilerplate_value, NONE)
519 .Assert();
520 }
521
522 JSObject::ValidateElements(array);
523 Handle<FixedArrayBase> element_values(array->elements());
524
525 // Simple and shallow arrays can be lazily copied, we transform the
526 // elements array to a copy-on-write array.
527 if (is_simple && depth_acc == 1 && array_index > 0 &&
528 array->HasFastSmiOrObjectElements()) {
529 element_values->set_map(isolate->heap()->fixed_cow_array_map());
530 }
531
532 // Remember both the literal's constant values as well as the ElementsKind
533 // in a 2-element FixedArray.
534 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
535
536 ElementsKind kind = array->GetElementsKind();
537 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
538
539 literals->set(0, Smi::FromInt(kind));
540 literals->set(1, *element_values);
541
542 constant_elements_ = literals;
543 set_is_simple(is_simple);
544 set_depth(depth_acc);
545}
546
547
548void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
549 FeedbackVectorSpec* spec,
550 FeedbackVectorSlotCache* cache) {
551 // This logic that computes the number of slots needed for vector store
552 // ics must mirror FullCodeGenerator::VisitArrayLiteral.
553 int array_index = 0;
554 for (; array_index < values()->length(); array_index++) {
555 Expression* subexpr = values()->at(array_index);
556 if (subexpr->IsSpread()) break;
557 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
558
559 // We'll reuse the same literal slot for all of the non-constant
560 // subexpressions that use a keyed store IC.
561 literal_slot_ = spec->AddKeyedStoreICSlot();
562 return;
563 }
564}
565
566
567Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
568 Isolate* isolate) {
569 if (expression->IsLiteral()) {
570 return expression->AsLiteral()->value();
571 }
572 if (CompileTimeValue::IsCompileTimeValue(expression)) {
573 return CompileTimeValue::GetValue(isolate, expression);
574 }
575 return isolate->factory()->uninitialized_value();
576}
577
578
579void MaterializedLiteral::BuildConstants(Isolate* isolate) {
580 if (IsArrayLiteral()) {
581 return AsArrayLiteral()->BuildConstantElements(isolate);
582 }
583 if (IsObjectLiteral()) {
584 return AsObjectLiteral()->BuildConstantProperties(isolate);
585 }
586 DCHECK(IsRegExpLiteral());
587 DCHECK(depth() >= 1); // Depth should be initialized.
588}
589
590
591void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
592 // TODO(olivf) If this Operation is used in a test context, then the
593 // expression has a ToBoolean stub and we want to collect the type
594 // information. However the GraphBuilder expects it to be on the instruction
595 // corresponding to the TestContext, therefore we have to store it here and
596 // not on the operand.
597 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
598}
599
600
601void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
602 // TODO(olivf) If this Operation is used in a test context, then the right
603 // hand side has a ToBoolean stub and we want to collect the type information.
604 // However the GraphBuilder expects it to be on the instruction corresponding
605 // to the TestContext, therefore we have to store it here and not on the
606 // right hand operand.
607 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
608}
609
610
611static bool IsTypeof(Expression* expr) {
612 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
613 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
614}
615
616
617// Check for the pattern: typeof <expression> equals <string literal>.
618static bool MatchLiteralCompareTypeof(Expression* left,
619 Token::Value op,
620 Expression* right,
621 Expression** expr,
622 Handle<String>* check) {
623 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
624 *expr = left->AsUnaryOperation()->expression();
625 *check = Handle<String>::cast(right->AsLiteral()->value());
626 return true;
627 }
628 return false;
629}
630
631
632bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
633 Handle<String>* check) {
634 return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
635 MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
636}
637
638
639static bool IsVoidOfLiteral(Expression* expr) {
640 UnaryOperation* maybe_unary = expr->AsUnaryOperation();
641 return maybe_unary != NULL &&
642 maybe_unary->op() == Token::VOID &&
643 maybe_unary->expression()->IsLiteral();
644}
645
646
647// Check for the pattern: void <literal> equals <expression> or
648// undefined equals <expression>
649static bool MatchLiteralCompareUndefined(Expression* left,
650 Token::Value op,
651 Expression* right,
652 Expression** expr,
653 Isolate* isolate) {
654 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
655 *expr = right;
656 return true;
657 }
658 if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) {
659 *expr = right;
660 return true;
661 }
662 return false;
663}
664
665
666bool CompareOperation::IsLiteralCompareUndefined(
667 Expression** expr, Isolate* isolate) {
668 return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) ||
669 MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate);
670}
671
672
673// Check for the pattern: null equals <expression>
674static bool MatchLiteralCompareNull(Expression* left,
675 Token::Value op,
676 Expression* right,
677 Expression** expr) {
678 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
679 *expr = right;
680 return true;
681 }
682 return false;
683}
684
685
686bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
687 return MatchLiteralCompareNull(left_, op_, right_, expr) ||
688 MatchLiteralCompareNull(right_, op_, left_, expr);
689}
690
691
692// ----------------------------------------------------------------------------
693// Inlining support
694
695bool Declaration::IsInlineable() const {
696 return proxy()->var()->IsStackAllocated();
697}
698
699bool FunctionDeclaration::IsInlineable() const {
700 return false;
701}
702
703
704// ----------------------------------------------------------------------------
705// Recording of type feedback
706
707// TODO(rossberg): all RecordTypeFeedback functions should disappear
708// once we use the common type field in the AST consistently.
709
710void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
711 set_to_boolean_types(oracle->ToBooleanTypes(test_id()));
712}
713
714
715bool Call::IsUsingCallFeedbackICSlot(Isolate* isolate) const {
716 CallType call_type = GetCallType(isolate);
717 if (call_type == POSSIBLY_EVAL_CALL) {
718 return false;
719 }
720 return true;
721}
722
723
724bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
725 // SuperConstructorCall uses a CallConstructStub, which wants
726 // a Slot, in addition to any IC slots requested elsewhere.
727 return GetCallType(isolate) == SUPER_CALL;
728}
729
730
731void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
732 FeedbackVectorSlotCache* cache) {
733 if (IsUsingCallFeedbackICSlot(isolate)) {
734 ic_slot_ = spec->AddCallICSlot();
735 }
736 if (IsUsingCallFeedbackSlot(isolate)) {
737 stub_slot_ = spec->AddGeneralSlot();
738 }
739}
740
741
742Call::CallType Call::GetCallType(Isolate* isolate) const {
743 VariableProxy* proxy = expression()->AsVariableProxy();
744 if (proxy != NULL) {
745 if (proxy->var()->is_possibly_eval(isolate)) {
746 return POSSIBLY_EVAL_CALL;
747 } else if (proxy->var()->IsUnallocatedOrGlobalSlot()) {
748 return GLOBAL_CALL;
749 } else if (proxy->var()->IsLookupSlot()) {
750 return LOOKUP_SLOT_CALL;
751 }
752 }
753
754 if (expression()->IsSuperCallReference()) return SUPER_CALL;
755
756 Property* property = expression()->AsProperty();
757 if (property != nullptr) {
758 bool is_super = property->IsSuperAccess();
759 if (property->key()->IsPropertyName()) {
760 return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL;
761 } else {
762 return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL;
763 }
764 }
765
766 return OTHER_CALL;
767}
768
769
770// ----------------------------------------------------------------------------
771// Implementation of AstVisitor
772
773void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
774 for (int i = 0; i < declarations->length(); i++) {
775 Visit(declarations->at(i));
776 }
777}
778
779
780void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
781 for (int i = 0; i < statements->length(); i++) {
782 Statement* stmt = statements->at(i);
783 Visit(stmt);
784 if (stmt->IsJump()) break;
785 }
786}
787
788
789void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
790 for (int i = 0; i < expressions->length(); i++) {
791 // The variable statement visiting code may pass NULL expressions
792 // to this code. Maybe this should be handled by introducing an
793 // undefined expression or literal? Revisit this code if this
794 // changes
795 Expression* expression = expressions->at(i);
796 if (expression != NULL) Visit(expression);
797 }
798}
799
800
801CaseClause::CaseClause(Zone* zone, Expression* label,
802 ZoneList<Statement*>* statements, int pos)
803 : Expression(zone, pos),
804 label_(label),
805 statements_(statements),
806 compare_type_(Type::None(zone)) {}
807
808
809uint32_t Literal::Hash() {
810 return raw_value()->IsString()
811 ? raw_value()->AsString()->hash()
812 : ComputeLongHash(double_to_uint64(raw_value()->AsNumber()));
813}
814
815
816// static
817bool Literal::Match(void* literal1, void* literal2) {
818 const AstValue* x = static_cast<Literal*>(literal1)->raw_value();
819 const AstValue* y = static_cast<Literal*>(literal2)->raw_value();
820 return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) ||
821 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
822}
823
824
825} // namespace internal
826} // namespace v8