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/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
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->IsUnallocatedOrGlobalSlot() &&
58 var_proxy->raw_name()->IsOneByteEqualTo("undefined");
59 }
60
61
IsValidReferenceExpressionOrThis() const62 bool Expression::IsValidReferenceExpressionOrThis() const {
63 return IsValidReferenceExpression() ||
64 (IsVariableProxy() && AsVariableProxy()->is_this());
65 }
66
67
VariableProxy(Zone * zone,Variable * var,int start_position,int end_position)68 VariableProxy::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
VariableProxy(Zone * zone,const AstRawString * name,Variable::Kind variable_kind,int start_position,int end_position)80 VariableProxy::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
BindTo(Variable * var)91 void 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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)99 void 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
AssignVectorSlots(Expression * expr,FeedbackVectorSpec * spec,FeedbackVectorSlot * out_slot)121 static 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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)137 void 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
Assignment(Zone * zone,Token::Value op,Expression * target,Expression * value,int pos)148 Assignment::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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)159 void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
160 FeedbackVectorSpec* spec,
161 FeedbackVectorSlotCache* cache) {
162 AssignVectorSlots(target(), spec, &slot_);
163 }
164
165
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)166 void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
167 FeedbackVectorSpec* spec,
168 FeedbackVectorSlotCache* cache) {
169 AssignVectorSlots(expression(), spec, &slot_);
170 }
171
172
binary_op() const173 Token::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
AllowsLazyCompilation()192 bool FunctionLiteral::AllowsLazyCompilation() {
193 return scope()->AllowsLazyCompilation();
194 }
195
196
AllowsLazyCompilationWithoutContext()197 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
198 return scope()->AllowsLazyCompilationWithoutContext();
199 }
200
201
start_position() const202 int FunctionLiteral::start_position() const {
203 return scope()->start_position();
204 }
205
206
end_position() const207 int FunctionLiteral::end_position() const {
208 return scope()->end_position();
209 }
210
211
language_mode() const212 LanguageMode FunctionLiteral::language_mode() const {
213 return scope()->language_mode();
214 }
215
216
NeedsHomeObject(Expression * expr)217 bool 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
ObjectLiteralProperty(Expression * key,Expression * value,Kind kind,bool is_static,bool is_computed_name)224 ObjectLiteralProperty::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
ObjectLiteralProperty(AstValueFactory * ast_value_factory,Expression * key,Expression * value,bool is_static,bool is_computed_name)235 ObjectLiteralProperty::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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)258 void 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
IsCompileTimeValue()277 bool ObjectLiteral::Property::IsCompileTimeValue() {
278 return kind_ == CONSTANT ||
279 (kind_ == MATERIALIZED_LITERAL &&
280 CompileTimeValue::IsCompileTimeValue(value_));
281 }
282
283
set_emit_store(bool emit_store)284 void ObjectLiteral::Property::set_emit_store(bool emit_store) {
285 emit_store_ = emit_store;
286 }
287
288
emit_store()289 bool ObjectLiteral::Property::emit_store() {
290 return emit_store_;
291 }
292
293
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)294 void 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
CalculateEmitStore(Zone * zone)356 void 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
IsBoilerplateProperty(ObjectLiteral::Property * property)388 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
389 return property != NULL &&
390 property->kind() != ObjectLiteral::Property::PROTOTYPE;
391 }
392
393
BuildConstantProperties(Isolate * isolate)394 void 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
BuildConstantElements(Isolate * isolate)478 void 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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)548 void 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
GetBoilerplateValue(Expression * expression,Isolate * isolate)567 Handle<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
BuildConstants(Isolate * isolate)579 void 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
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)591 void 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
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)601 void 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
IsTypeof(Expression * expr)611 static 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>.
MatchLiteralCompareTypeof(Expression * left,Token::Value op,Expression * right,Expression ** expr,Handle<String> * check)618 static 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
IsLiteralCompareTypeof(Expression ** expr,Handle<String> * check)632 bool 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
IsVoidOfLiteral(Expression * expr)639 static 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>
MatchLiteralCompareUndefined(Expression * left,Token::Value op,Expression * right,Expression ** expr,Isolate * isolate)649 static 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
IsLiteralCompareUndefined(Expression ** expr,Isolate * isolate)666 bool 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>
MatchLiteralCompareNull(Expression * left,Token::Value op,Expression * right,Expression ** expr)674 static 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
IsLiteralCompareNull(Expression ** expr)686 bool 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
IsInlineable() const695 bool Declaration::IsInlineable() const {
696 return proxy()->var()->IsStackAllocated();
697 }
698
IsInlineable() const699 bool 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
RecordToBooleanTypeFeedback(TypeFeedbackOracle * oracle)710 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
711 set_to_boolean_types(oracle->ToBooleanTypes(test_id()));
712 }
713
714
IsUsingCallFeedbackICSlot(Isolate * isolate) const715 bool 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
IsUsingCallFeedbackSlot(Isolate * isolate) const724 bool 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
AssignFeedbackVectorSlots(Isolate * isolate,FeedbackVectorSpec * spec,FeedbackVectorSlotCache * cache)731 void 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
GetCallType(Isolate * isolate) const742 Call::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
VisitDeclarations(ZoneList<Declaration * > * declarations)773 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
774 for (int i = 0; i < declarations->length(); i++) {
775 Visit(declarations->at(i));
776 }
777 }
778
779
VisitStatements(ZoneList<Statement * > * statements)780 void 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
VisitExpressions(ZoneList<Expression * > * expressions)789 void 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
CaseClause(Zone * zone,Expression * label,ZoneList<Statement * > * statements,int pos)801 CaseClause::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
Hash()809 uint32_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
Match(void * literal1,void * literal2)817 bool 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
827