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