OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/ast/ast.h" | 5 #include "src/ast/ast.h" |
6 | 6 |
7 #include <cmath> // For isfinite. | 7 #include <cmath> // For isfinite. |
8 | 8 |
9 #include "src/ast/compile-time-value.h" | 9 #include "src/ast/compile-time-value.h" |
10 #include "src/ast/prettyprinter.h" | 10 #include "src/ast/prettyprinter.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 return nullptr; | 66 return nullptr; |
67 } | 67 } |
68 } | 68 } |
69 | 69 |
70 #undef RETURN_NODE | 70 #undef RETURN_NODE |
71 | 71 |
72 bool Expression::IsSmiLiteral() const { | 72 bool Expression::IsSmiLiteral() const { |
73 return IsLiteral() && AsLiteral()->raw_value()->IsSmi(); | 73 return IsLiteral() && AsLiteral()->raw_value()->IsSmi(); |
74 } | 74 } |
75 | 75 |
| 76 bool Expression::IsNumberLiteral() const { |
| 77 return IsLiteral() && AsLiteral()->raw_value()->IsNumber(); |
| 78 } |
| 79 |
76 bool Expression::IsStringLiteral() const { | 80 bool Expression::IsStringLiteral() const { |
77 return IsLiteral() && AsLiteral()->raw_value()->IsString(); | 81 return IsLiteral() && AsLiteral()->raw_value()->IsString(); |
78 } | 82 } |
79 | 83 |
80 bool Expression::IsPropertyName() const { | 84 bool Expression::IsPropertyName() const { |
81 return IsLiteral() && AsLiteral()->IsPropertyName(); | 85 return IsLiteral() && AsLiteral()->IsPropertyName(); |
82 } | 86 } |
83 | 87 |
84 bool Expression::IsNullLiteral() const { | 88 bool Expression::IsNullLiteral() const { |
85 if (!IsLiteral()) return false; | 89 if (!IsLiteral()) return false; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 raw_name_ = copy_from->raw_name_; | 197 raw_name_ = copy_from->raw_name_; |
194 } | 198 } |
195 | 199 |
196 void VariableProxy::BindTo(Variable* var) { | 200 void VariableProxy::BindTo(Variable* var) { |
197 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); | 201 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); |
198 set_var(var); | 202 set_var(var); |
199 set_is_resolved(); | 203 set_is_resolved(); |
200 var->set_is_used(); | 204 var->set_is_used(); |
201 } | 205 } |
202 | 206 |
203 | 207 void VariableProxy::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
204 void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate, | |
205 FeedbackVectorSpec* spec, | |
206 FeedbackVectorSlotCache* cache) { | 208 FeedbackVectorSlotCache* cache) { |
207 if (UsesVariableFeedbackSlot()) { | 209 if (UsesVariableFeedbackSlot()) { |
208 // VariableProxies that point to the same Variable within a function can | 210 // VariableProxies that point to the same Variable within a function can |
209 // make their loads from the same IC slot. | 211 // make their loads from the same IC slot. |
210 if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) { | 212 if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) { |
211 ZoneHashMap::Entry* entry = cache->Get(var()); | 213 ZoneHashMap::Entry* entry = cache->Get(var()); |
212 if (entry != NULL) { | 214 if (entry != NULL) { |
213 variable_feedback_slot_ = FeedbackVectorSlot( | 215 variable_feedback_slot_ = FeedbackVectorSlot( |
214 static_cast<int>(reinterpret_cast<intptr_t>(entry->value))); | 216 static_cast<int>(reinterpret_cast<intptr_t>(entry->value))); |
215 return; | 217 return; |
(...skipping 15 matching lines...) Expand all Loading... |
231 expr->AsVariableProxy()->var()->IsUnallocated()) || | 233 expr->AsVariableProxy()->var()->IsUnallocated()) || |
232 assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { | 234 assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { |
233 // TODO(ishell): consider using ICSlotCache for variables here. | 235 // TODO(ishell): consider using ICSlotCache for variables here. |
234 FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY | 236 FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY |
235 ? FeedbackVectorSlotKind::KEYED_STORE_IC | 237 ? FeedbackVectorSlotKind::KEYED_STORE_IC |
236 : FeedbackVectorSlotKind::STORE_IC; | 238 : FeedbackVectorSlotKind::STORE_IC; |
237 *out_slot = spec->AddSlot(kind); | 239 *out_slot = spec->AddSlot(kind); |
238 } | 240 } |
239 } | 241 } |
240 | 242 |
241 void ForInStatement::AssignFeedbackVectorSlots(Isolate* isolate, | 243 void ForInStatement::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
242 FeedbackVectorSpec* spec, | |
243 FeedbackVectorSlotCache* cache) { | 244 FeedbackVectorSlotCache* cache) { |
244 AssignVectorSlots(each(), spec, &each_slot_); | 245 AssignVectorSlots(each(), spec, &each_slot_); |
245 for_in_feedback_slot_ = spec->AddGeneralSlot(); | 246 for_in_feedback_slot_ = spec->AddGeneralSlot(); |
246 } | 247 } |
247 | 248 |
248 Assignment::Assignment(Token::Value op, Expression* target, Expression* value, | 249 Assignment::Assignment(Token::Value op, Expression* target, Expression* value, |
249 int pos) | 250 int pos) |
250 : Expression(pos, kAssignment), | 251 : Expression(pos, kAssignment), |
251 target_(target), | 252 target_(target), |
252 value_(value), | 253 value_(value), |
253 binary_operation_(NULL) { | 254 binary_operation_(NULL) { |
254 bit_field_ |= IsUninitializedField::encode(false) | | 255 bit_field_ |= IsUninitializedField::encode(false) | |
255 KeyTypeField::encode(ELEMENT) | | 256 KeyTypeField::encode(ELEMENT) | |
256 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op); | 257 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op); |
257 } | 258 } |
258 | 259 |
259 void Assignment::AssignFeedbackVectorSlots(Isolate* isolate, | 260 void Assignment::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
260 FeedbackVectorSpec* spec, | |
261 FeedbackVectorSlotCache* cache) { | 261 FeedbackVectorSlotCache* cache) { |
262 AssignVectorSlots(target(), spec, &slot_); | 262 AssignVectorSlots(target(), spec, &slot_); |
263 } | 263 } |
264 | 264 |
265 | 265 void CountOperation::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
266 void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate, | |
267 FeedbackVectorSpec* spec, | |
268 FeedbackVectorSlotCache* cache) { | 266 FeedbackVectorSlotCache* cache) { |
269 AssignVectorSlots(expression(), spec, &slot_); | 267 AssignVectorSlots(expression(), spec, &slot_); |
270 // Assign a slot to collect feedback about binary operations. Used only in | 268 // Assign a slot to collect feedback about binary operations. Used only in |
271 // ignition. Fullcodegen uses AstId to record type feedback. | 269 // ignition. Fullcodegen uses AstId to record type feedback. |
272 binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot(); | 270 binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot(); |
273 } | 271 } |
274 | 272 |
275 | 273 |
276 Token::Value Assignment::binary_op() const { | 274 Token::Value Assignment::binary_op() const { |
277 switch (op()) { | 275 switch (op()) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 IsConciseMethod(value_->AsFunctionLiteral()->kind()))); | 364 IsConciseMethod(value_->AsFunctionLiteral()->kind()))); |
367 } | 365 } |
368 | 366 |
369 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value, | 367 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value, |
370 Kind kind, bool is_static, | 368 Kind kind, bool is_static, |
371 bool is_computed_name) | 369 bool is_computed_name) |
372 : LiteralProperty(key, value, is_computed_name), | 370 : LiteralProperty(key, value, is_computed_name), |
373 kind_(kind), | 371 kind_(kind), |
374 is_static_(is_static) {} | 372 is_static_(is_static) {} |
375 | 373 |
376 void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate, | 374 void ClassLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
377 FeedbackVectorSpec* spec, | |
378 FeedbackVectorSlotCache* cache) { | 375 FeedbackVectorSlotCache* cache) { |
379 // This logic that computes the number of slots needed for vector store | 376 // This logic that computes the number of slots needed for vector store |
380 // ICs must mirror BytecodeGenerator::VisitClassLiteral. | 377 // ICs must mirror BytecodeGenerator::VisitClassLiteral. |
381 if (FunctionLiteral::NeedsHomeObject(constructor())) { | 378 if (FunctionLiteral::NeedsHomeObject(constructor())) { |
382 home_object_slot_ = spec->AddStoreICSlot(); | 379 home_object_slot_ = spec->AddStoreICSlot(); |
383 } | 380 } |
384 | 381 |
385 if (NeedsProxySlot()) { | 382 if (NeedsProxySlot()) { |
386 proxy_slot_ = spec->AddStoreICSlot(); | 383 proxy_slot_ = spec->AddStoreICSlot(); |
387 } | 384 } |
(...skipping 15 matching lines...) Expand all Loading... |
403 CompileTimeValue::IsCompileTimeValue(value_)); | 400 CompileTimeValue::IsCompileTimeValue(value_)); |
404 } | 401 } |
405 | 402 |
406 | 403 |
407 void ObjectLiteral::Property::set_emit_store(bool emit_store) { | 404 void ObjectLiteral::Property::set_emit_store(bool emit_store) { |
408 emit_store_ = emit_store; | 405 emit_store_ = emit_store; |
409 } | 406 } |
410 | 407 |
411 bool ObjectLiteral::Property::emit_store() const { return emit_store_; } | 408 bool ObjectLiteral::Property::emit_store() const { return emit_store_; } |
412 | 409 |
413 void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, | 410 void ObjectLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
414 FeedbackVectorSpec* spec, | |
415 FeedbackVectorSlotCache* cache) { | 411 FeedbackVectorSlotCache* cache) { |
416 // This logic that computes the number of slots needed for vector store | 412 // This logic that computes the number of slots needed for vector store |
417 // ics must mirror FullCodeGenerator::VisitObjectLiteral. | 413 // ics must mirror FullCodeGenerator::VisitObjectLiteral. |
418 int property_index = 0; | 414 int property_index = 0; |
419 for (; property_index < properties()->length(); property_index++) { | 415 for (; property_index < properties()->length(); property_index++) { |
420 ObjectLiteral::Property* property = properties()->at(property_index); | 416 ObjectLiteral::Property* property = properties()->at(property_index); |
421 if (property->is_computed_name()) break; | 417 if (property->is_computed_name()) break; |
422 if (property->IsCompileTimeValue()) continue; | 418 if (property->IsCompileTimeValue()) continue; |
423 | 419 |
424 Literal* key = property->key()->AsLiteral(); | 420 Literal* key = property->key()->AsLiteral(); |
425 Expression* value = property->value(); | 421 Expression* value = property->value(); |
426 switch (property->kind()) { | 422 switch (property->kind()) { |
427 case ObjectLiteral::Property::SPREAD: | 423 case ObjectLiteral::Property::SPREAD: |
428 case ObjectLiteral::Property::CONSTANT: | 424 case ObjectLiteral::Property::CONSTANT: |
429 UNREACHABLE(); | 425 UNREACHABLE(); |
430 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 426 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
431 // Fall through. | 427 // Fall through. |
432 case ObjectLiteral::Property::COMPUTED: | 428 case ObjectLiteral::Property::COMPUTED: |
433 // It is safe to use [[Put]] here because the boilerplate already | 429 // It is safe to use [[Put]] here because the boilerplate already |
434 // contains computed properties with an uninitialized value. | 430 // contains computed properties with an uninitialized value. |
435 if (key->value()->IsInternalizedString()) { | 431 if (key->IsStringLiteral()) { |
436 if (property->emit_store()) { | 432 if (property->emit_store()) { |
437 property->SetSlot(spec->AddStoreICSlot()); | 433 property->SetSlot(spec->AddStoreICSlot()); |
438 if (FunctionLiteral::NeedsHomeObject(value)) { | 434 if (FunctionLiteral::NeedsHomeObject(value)) { |
439 property->SetSlot(spec->AddStoreICSlot(), 1); | 435 property->SetSlot(spec->AddStoreICSlot(), 1); |
440 } | 436 } |
441 } | 437 } |
442 break; | 438 break; |
443 } | 439 } |
444 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { | 440 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { |
445 property->SetSlot(spec->AddStoreICSlot()); | 441 property->SetSlot(spec->AddStoreICSlot()); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 entry->value = property; | 501 entry->value = property; |
506 } | 502 } |
507 } | 503 } |
508 | 504 |
509 | 505 |
510 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { | 506 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { |
511 return property != NULL && | 507 return property != NULL && |
512 property->kind() != ObjectLiteral::Property::PROTOTYPE; | 508 property->kind() != ObjectLiteral::Property::PROTOTYPE; |
513 } | 509 } |
514 | 510 |
515 | 511 void ObjectLiteral::InitDepthAndFlags() { |
516 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { | 512 if (depth_ > 0) return; |
517 if (!constant_properties_.is_null()) return; | |
518 | |
519 // Allocate a fixed array to hold all the constant properties. | |
520 Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray( | |
521 boilerplate_properties_ * 2, TENURED); | |
522 | 513 |
523 int position = 0; | 514 int position = 0; |
524 // Accumulate the value in local variables and store it at the end. | 515 // Accumulate the value in local variables and store it at the end. |
525 bool is_simple = true; | 516 bool is_simple = true; |
526 int depth_acc = 1; | 517 int depth_acc = 1; |
527 uint32_t max_element_index = 0; | 518 uint32_t max_element_index = 0; |
528 uint32_t elements = 0; | 519 uint32_t elements = 0; |
529 for (int i = 0; i < properties()->length(); i++) { | 520 for (int i = 0; i < properties()->length(); i++) { |
530 ObjectLiteral::Property* property = properties()->at(i); | 521 ObjectLiteral::Property* property = properties()->at(i); |
531 if (!IsBoilerplateProperty(property)) { | 522 if (!IsBoilerplateProperty(property)) { |
532 is_simple = false; | 523 is_simple = false; |
533 continue; | 524 continue; |
534 } | 525 } |
535 | 526 |
536 if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { | 527 if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { |
537 DCHECK(property->is_computed_name()); | 528 DCHECK(property->is_computed_name()); |
538 is_simple = false; | 529 is_simple = false; |
539 break; | 530 break; |
540 } | 531 } |
541 DCHECK(!property->is_computed_name()); | 532 DCHECK(!property->is_computed_name()); |
542 | 533 |
543 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); | 534 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); |
544 if (m_literal != NULL) { | 535 if (m_literal != NULL) { |
545 m_literal->BuildConstants(isolate); | 536 m_literal->InitDepthAndFlags(); |
546 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; | 537 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; |
547 } | 538 } |
548 | 539 |
549 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined | 540 const AstValue* key = property->key()->AsLiteral()->raw_value(); |
550 // value for COMPUTED properties, the real value is filled in at | 541 Expression* value = property->value(); |
551 // runtime. The enumeration order is maintained. | 542 |
552 Handle<Object> key = property->key()->AsLiteral()->value(); | 543 bool is_compile_time_value = CompileTimeValue::IsCompileTimeValue(value); |
553 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); | |
554 | 544 |
555 // Ensure objects that may, at any point in time, contain fields with double | 545 // Ensure objects that may, at any point in time, contain fields with double |
556 // representation are always treated as nested objects. This is true for | 546 // representation are always treated as nested objects. This is true for |
557 // computed fields (value is undefined), and smi and double literals | 547 // computed fields, and smi and double literals. |
558 // (value->IsNumber()). | |
559 // TODO(verwaest): Remove once we can store them inline. | 548 // TODO(verwaest): Remove once we can store them inline. |
560 if (FLAG_track_double_fields && | 549 if (FLAG_track_double_fields && |
561 (value->IsNumber() || value->IsUninitialized(isolate))) { | 550 (value->IsNumberLiteral() || !is_compile_time_value)) { |
562 bit_field_ = MayStoreDoublesField::update(bit_field_, true); | 551 bit_field_ = MayStoreDoublesField::update(bit_field_, true); |
563 } | 552 } |
564 | 553 |
565 is_simple = is_simple && !value->IsUninitialized(isolate); | 554 is_simple = is_simple && is_compile_time_value; |
566 | 555 |
567 // Keep track of the number of elements in the object literal and | 556 // Keep track of the number of elements in the object literal and |
568 // the largest element index. If the largest element index is | 557 // the largest element index. If the largest element index is |
569 // much larger than the number of elements, creating an object | 558 // much larger than the number of elements, creating an object |
570 // literal with fast elements will be a waste of space. | 559 // literal with fast elements will be a waste of space. |
571 uint32_t element_index = 0; | 560 uint32_t element_index = 0; |
572 if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) { | 561 if (key->IsString() && key->AsString()->AsArrayIndex(&element_index)) { |
573 max_element_index = Max(element_index, max_element_index); | 562 max_element_index = Max(element_index, max_element_index); |
574 elements++; | 563 elements++; |
575 key = isolate->factory()->NewNumberFromUint(element_index); | 564 } else if (key->ToUint32(&element_index) && element_index != kMaxUInt32) { |
576 } else if (key->ToArrayIndex(&element_index)) { | |
577 max_element_index = Max(element_index, max_element_index); | 565 max_element_index = Max(element_index, max_element_index); |
578 elements++; | 566 elements++; |
579 } else if (key->IsNumber()) { | |
580 key = isolate->factory()->NumberToString(key); | |
581 } | 567 } |
582 | 568 |
583 // Add name, value pair to the fixed array. | 569 // Increment the position for the key and the value. |
584 constant_properties->set(position++, *key); | 570 position += 2; |
585 constant_properties->set(position++, *value); | |
586 } | 571 } |
587 | 572 |
588 constant_properties_ = constant_properties; | |
589 bit_field_ = FastElementsField::update( | 573 bit_field_ = FastElementsField::update( |
590 bit_field_, | 574 bit_field_, |
591 (max_element_index <= 32) || ((2 * elements) >= max_element_index)); | 575 (max_element_index <= 32) || ((2 * elements) >= max_element_index)); |
592 bit_field_ = HasElementsField::update(bit_field_, elements > 0); | 576 bit_field_ = HasElementsField::update(bit_field_, elements > 0); |
593 | 577 |
594 set_is_simple(is_simple); | 578 set_is_simple(is_simple); |
595 set_depth(depth_acc); | 579 set_depth(depth_acc); |
596 } | 580 } |
597 | 581 |
| 582 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { |
| 583 if (!constant_properties_.is_null()) return; |
| 584 |
| 585 // Allocate a fixed array to hold all the constant properties. |
| 586 Handle<FixedArray> constant_properties = |
| 587 isolate->factory()->NewFixedArray(boilerplate_properties_ * 2, TENURED); |
| 588 |
| 589 int position = 0; |
| 590 for (int i = 0; i < properties()->length(); i++) { |
| 591 ObjectLiteral::Property* property = properties()->at(i); |
| 592 if (!IsBoilerplateProperty(property)) { |
| 593 continue; |
| 594 } |
| 595 |
| 596 if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { |
| 597 DCHECK(property->is_computed_name()); |
| 598 break; |
| 599 } |
| 600 DCHECK(!property->is_computed_name()); |
| 601 |
| 602 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); |
| 603 if (m_literal != NULL) { |
| 604 m_literal->BuildConstants(isolate); |
| 605 } |
| 606 |
| 607 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined |
| 608 // value for COMPUTED properties, the real value is filled in at |
| 609 // runtime. The enumeration order is maintained. |
| 610 Handle<Object> key = property->key()->AsLiteral()->value(); |
| 611 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); |
| 612 |
| 613 uint32_t element_index = 0; |
| 614 if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) { |
| 615 key = isolate->factory()->NewNumberFromUint(element_index); |
| 616 } else if (key->IsNumber() && !key->ToArrayIndex(&element_index)) { |
| 617 key = isolate->factory()->NumberToString(key); |
| 618 } |
| 619 |
| 620 // Add name, value pair to the fixed array. |
| 621 constant_properties->set(position++, *key); |
| 622 constant_properties->set(position++, *value); |
| 623 } |
| 624 |
| 625 constant_properties_ = constant_properties; |
| 626 } |
| 627 |
598 bool ObjectLiteral::IsFastCloningSupported() const { | 628 bool ObjectLiteral::IsFastCloningSupported() const { |
599 // The FastCloneShallowObject builtin doesn't copy elements, and object | 629 // The FastCloneShallowObject builtin doesn't copy elements, and object |
600 // literals don't support copy-on-write (COW) elements for now. | 630 // literals don't support copy-on-write (COW) elements for now. |
601 // TODO(mvstanton): make object literals support COW elements. | 631 // TODO(mvstanton): make object literals support COW elements. |
602 return fast_elements() && has_shallow_properties() && | 632 return fast_elements() && has_shallow_properties() && |
603 properties_count() <= ConstructorBuiltinsAssembler:: | 633 properties_count() <= ConstructorBuiltinsAssembler:: |
604 kMaximumClonedShallowObjectProperties; | 634 kMaximumClonedShallowObjectProperties; |
605 } | 635 } |
606 | 636 |
| 637 void ArrayLiteral::InitDepthAndFlags() { |
| 638 DCHECK_LT(first_spread_index_, 0); |
| 639 |
| 640 if (depth_ > 0) return; |
| 641 |
| 642 int constants_length = values()->length(); |
| 643 |
| 644 // Fill in the literals. |
| 645 bool is_simple = true; |
| 646 int depth_acc = 1; |
| 647 int array_index = 0; |
| 648 for (; array_index < constants_length; array_index++) { |
| 649 Expression* element = values()->at(array_index); |
| 650 DCHECK(!element->IsSpread()); |
| 651 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); |
| 652 if (m_literal != NULL) { |
| 653 m_literal->InitDepthAndFlags(); |
| 654 if (m_literal->depth() + 1 > depth_acc) { |
| 655 depth_acc = m_literal->depth() + 1; |
| 656 } |
| 657 } |
| 658 |
| 659 if (!CompileTimeValue::IsCompileTimeValue(element)) { |
| 660 is_simple = false; |
| 661 } |
| 662 } |
| 663 |
| 664 set_is_simple(is_simple); |
| 665 set_depth(depth_acc); |
| 666 } |
| 667 |
607 void ArrayLiteral::BuildConstantElements(Isolate* isolate) { | 668 void ArrayLiteral::BuildConstantElements(Isolate* isolate) { |
608 DCHECK_LT(first_spread_index_, 0); | 669 DCHECK_LT(first_spread_index_, 0); |
609 | 670 |
610 if (!constant_elements_.is_null()) return; | 671 if (!constant_elements_.is_null()) return; |
611 | 672 |
612 int constants_length = values()->length(); | 673 int constants_length = values()->length(); |
613 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND; | 674 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND; |
614 Handle<FixedArray> fixed_array = | 675 Handle<FixedArray> fixed_array = |
615 isolate->factory()->NewFixedArrayWithHoles(constants_length); | 676 isolate->factory()->NewFixedArrayWithHoles(constants_length); |
616 | 677 |
617 // Fill in the literals. | 678 // Fill in the literals. |
618 bool is_simple = true; | |
619 int depth_acc = 1; | |
620 bool is_holey = false; | 679 bool is_holey = false; |
621 int array_index = 0; | 680 int array_index = 0; |
622 for (; array_index < constants_length; array_index++) { | 681 for (; array_index < constants_length; array_index++) { |
623 Expression* element = values()->at(array_index); | 682 Expression* element = values()->at(array_index); |
624 DCHECK(!element->IsSpread()); | 683 DCHECK(!element->IsSpread()); |
625 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); | 684 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); |
626 if (m_literal != NULL) { | 685 if (m_literal != NULL) { |
627 m_literal->BuildConstants(isolate); | 686 m_literal->BuildConstants(isolate); |
628 if (m_literal->depth() + 1 > depth_acc) { | |
629 depth_acc = m_literal->depth() + 1; | |
630 } | |
631 } | 687 } |
632 | 688 |
633 // New handle scope here, needs to be after BuildContants(). | 689 // New handle scope here, needs to be after BuildContants(). |
634 HandleScope scope(isolate); | 690 HandleScope scope(isolate); |
635 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); | 691 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); |
636 if (boilerplate_value->IsTheHole(isolate)) { | 692 if (boilerplate_value->IsTheHole(isolate)) { |
637 is_holey = true; | 693 is_holey = true; |
638 continue; | 694 continue; |
639 } | 695 } |
640 | 696 |
641 if (boilerplate_value->IsUninitialized(isolate)) { | 697 if (boilerplate_value->IsUninitialized(isolate)) { |
642 boilerplate_value = handle(Smi::kZero, isolate); | 698 boilerplate_value = handle(Smi::kZero, isolate); |
643 is_simple = false; | |
644 } | 699 } |
645 | 700 |
646 kind = GetMoreGeneralElementsKind(kind, | 701 kind = GetMoreGeneralElementsKind(kind, |
647 boilerplate_value->OptimalElementsKind()); | 702 boilerplate_value->OptimalElementsKind()); |
648 fixed_array->set(array_index, *boilerplate_value); | 703 fixed_array->set(array_index, *boilerplate_value); |
649 } | 704 } |
650 | 705 |
651 if (is_holey) kind = GetHoleyElementsKind(kind); | 706 if (is_holey) kind = GetHoleyElementsKind(kind); |
652 | 707 |
653 // Simple and shallow arrays can be lazily copied, we transform the | 708 // Simple and shallow arrays can be lazily copied, we transform the |
654 // elements array to a copy-on-write array. | 709 // elements array to a copy-on-write array. |
655 if (is_simple && depth_acc == 1 && array_index > 0 && | 710 if (is_simple() && depth() == 1 && array_index > 0 && |
656 IsFastSmiOrObjectElementsKind(kind)) { | 711 IsFastSmiOrObjectElementsKind(kind)) { |
657 fixed_array->set_map(isolate->heap()->fixed_cow_array_map()); | 712 fixed_array->set_map(isolate->heap()->fixed_cow_array_map()); |
658 } | 713 } |
659 | 714 |
660 Handle<FixedArrayBase> elements = fixed_array; | 715 Handle<FixedArrayBase> elements = fixed_array; |
661 if (IsFastDoubleElementsKind(kind)) { | 716 if (IsFastDoubleElementsKind(kind)) { |
662 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); | 717 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); |
663 elements = isolate->factory()->NewFixedDoubleArray(constants_length); | 718 elements = isolate->factory()->NewFixedDoubleArray(constants_length); |
664 // We are copying from non-fast-double to fast-double. | 719 // We are copying from non-fast-double to fast-double. |
665 ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND; | 720 ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND; |
666 accessor->CopyElements(fixed_array, from_kind, elements, constants_length); | 721 accessor->CopyElements(fixed_array, from_kind, elements, constants_length); |
667 } | 722 } |
668 | 723 |
669 // Remember both the literal's constant values as well as the ElementsKind. | 724 // Remember both the literal's constant values as well as the ElementsKind. |
670 Handle<ConstantElementsPair> literals = | 725 Handle<ConstantElementsPair> literals = |
671 isolate->factory()->NewConstantElementsPair(kind, elements); | 726 isolate->factory()->NewConstantElementsPair(kind, elements); |
672 | 727 |
673 constant_elements_ = literals; | 728 constant_elements_ = literals; |
674 set_is_simple(is_simple); | |
675 set_depth(depth_acc); | |
676 } | 729 } |
677 | 730 |
678 bool ArrayLiteral::IsFastCloningSupported() const { | 731 bool ArrayLiteral::IsFastCloningSupported() const { |
679 return depth() <= 1 && | 732 return depth() <= 1 && |
680 values()->length() <= | 733 values()->length() <= |
681 ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements; | 734 ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements; |
682 } | 735 } |
683 | 736 |
684 void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate, | 737 void ArrayLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
685 FeedbackVectorSpec* spec, | |
686 FeedbackVectorSlotCache* cache) { | 738 FeedbackVectorSlotCache* cache) { |
687 // This logic that computes the number of slots needed for vector store | 739 // This logic that computes the number of slots needed for vector store |
688 // ics must mirror FullCodeGenerator::VisitArrayLiteral. | 740 // ics must mirror FullCodeGenerator::VisitArrayLiteral. |
689 for (int array_index = 0; array_index < values()->length(); array_index++) { | 741 for (int array_index = 0; array_index < values()->length(); array_index++) { |
690 Expression* subexpr = values()->at(array_index); | 742 Expression* subexpr = values()->at(array_index); |
691 DCHECK(!subexpr->IsSpread()); | 743 DCHECK(!subexpr->IsSpread()); |
692 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 744 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
693 | 745 |
694 // We'll reuse the same literal slot for all of the non-constant | 746 // We'll reuse the same literal slot for all of the non-constant |
695 // subexpressions that use a keyed store IC. | 747 // subexpressions that use a keyed store IC. |
696 literal_slot_ = spec->AddKeyedStoreICSlot(); | 748 literal_slot_ = spec->AddKeyedStoreICSlot(); |
697 return; | 749 return; |
698 } | 750 } |
699 } | 751 } |
700 | 752 |
701 | 753 |
702 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, | 754 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, |
703 Isolate* isolate) { | 755 Isolate* isolate) { |
704 if (expression->IsLiteral()) { | 756 if (expression->IsLiteral()) { |
705 return expression->AsLiteral()->value(); | 757 return expression->AsLiteral()->value(); |
706 } | 758 } |
707 if (CompileTimeValue::IsCompileTimeValue(expression)) { | 759 if (CompileTimeValue::IsCompileTimeValue(expression)) { |
708 return CompileTimeValue::GetValue(isolate, expression); | 760 return CompileTimeValue::GetValue(isolate, expression); |
709 } | 761 } |
710 return isolate->factory()->uninitialized_value(); | 762 return isolate->factory()->uninitialized_value(); |
711 } | 763 } |
712 | 764 |
| 765 void MaterializedLiteral::InitDepthAndFlags() { |
| 766 if (IsArrayLiteral()) { |
| 767 return AsArrayLiteral()->InitDepthAndFlags(); |
| 768 } |
| 769 if (IsObjectLiteral()) { |
| 770 return AsObjectLiteral()->InitDepthAndFlags(); |
| 771 } |
| 772 DCHECK(IsRegExpLiteral()); |
| 773 DCHECK_LE(1, depth()); // Depth should be initialized. |
| 774 } |
713 | 775 |
714 void MaterializedLiteral::BuildConstants(Isolate* isolate) { | 776 void MaterializedLiteral::BuildConstants(Isolate* isolate) { |
715 if (IsArrayLiteral()) { | 777 if (IsArrayLiteral()) { |
716 return AsArrayLiteral()->BuildConstantElements(isolate); | 778 return AsArrayLiteral()->BuildConstantElements(isolate); |
717 } | 779 } |
718 if (IsObjectLiteral()) { | 780 if (IsObjectLiteral()) { |
719 return AsObjectLiteral()->BuildConstantProperties(isolate); | 781 return AsObjectLiteral()->BuildConstantProperties(isolate); |
720 } | 782 } |
721 DCHECK(IsRegExpLiteral()); | 783 DCHECK(IsRegExpLiteral()); |
722 DCHECK(depth() >= 1); // Depth should be initialized. | |
723 } | 784 } |
724 | 785 |
725 | 786 |
726 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { | 787 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
727 // TODO(olivf) If this Operation is used in a test context, then the | 788 // TODO(olivf) If this Operation is used in a test context, then the |
728 // expression has a ToBoolean stub and we want to collect the type | 789 // expression has a ToBoolean stub and we want to collect the type |
729 // information. However the GraphBuilder expects it to be on the instruction | 790 // information. However the GraphBuilder expects it to be on the instruction |
730 // corresponding to the TestContext, therefore we have to store it here and | 791 // corresponding to the TestContext, therefore we have to store it here and |
731 // not on the operand. | 792 // not on the operand. |
732 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); | 793 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); |
733 } | 794 } |
734 | 795 |
735 | 796 |
736 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { | 797 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
737 // TODO(olivf) If this Operation is used in a test context, then the right | 798 // TODO(olivf) If this Operation is used in a test context, then the right |
738 // hand side has a ToBoolean stub and we want to collect the type information. | 799 // hand side has a ToBoolean stub and we want to collect the type information. |
739 // However the GraphBuilder expects it to be on the instruction corresponding | 800 // However the GraphBuilder expects it to be on the instruction corresponding |
740 // to the TestContext, therefore we have to store it here and not on the | 801 // to the TestContext, therefore we have to store it here and not on the |
741 // right hand operand. | 802 // right hand operand. |
742 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); | 803 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); |
743 } | 804 } |
744 | 805 |
745 void BinaryOperation::AssignFeedbackVectorSlots( | 806 void BinaryOperation::AssignFeedbackVectorSlots( |
746 Isolate* isolate, FeedbackVectorSpec* spec, | 807 FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { |
747 FeedbackVectorSlotCache* cache) { | |
748 // Feedback vector slot is only used by interpreter for binary operations. | 808 // Feedback vector slot is only used by interpreter for binary operations. |
749 // Full-codegen uses AstId to record type feedback. | 809 // Full-codegen uses AstId to record type feedback. |
750 switch (op()) { | 810 switch (op()) { |
751 // Comma, logical_or and logical_and do not collect type feedback. | 811 // Comma, logical_or and logical_and do not collect type feedback. |
752 case Token::COMMA: | 812 case Token::COMMA: |
753 case Token::AND: | 813 case Token::AND: |
754 case Token::OR: | 814 case Token::OR: |
755 return; | 815 return; |
756 default: | 816 default: |
757 type_feedback_slot_ = spec->AddInterpreterBinaryOpICSlot(); | 817 type_feedback_slot_ = spec->AddInterpreterBinaryOpICSlot(); |
758 return; | 818 return; |
759 } | 819 } |
760 } | 820 } |
761 | 821 |
762 static bool IsTypeof(Expression* expr) { | 822 static bool IsTypeof(Expression* expr) { |
763 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); | 823 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); |
764 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; | 824 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; |
765 } | 825 } |
766 | 826 |
767 void CompareOperation::AssignFeedbackVectorSlots( | 827 void CompareOperation::AssignFeedbackVectorSlots( |
768 Isolate* isolate, FeedbackVectorSpec* spec, | 828 FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache_) { |
769 FeedbackVectorSlotCache* cache_) { | |
770 // Feedback vector slot is only used by interpreter for binary operations. | 829 // Feedback vector slot is only used by interpreter for binary operations. |
771 // Full-codegen uses AstId to record type feedback. | 830 // Full-codegen uses AstId to record type feedback. |
772 switch (op()) { | 831 switch (op()) { |
773 // instanceof and in do not collect type feedback. | 832 // instanceof and in do not collect type feedback. |
774 case Token::INSTANCEOF: | 833 case Token::INSTANCEOF: |
775 case Token::IN: | 834 case Token::IN: |
776 return; | 835 return; |
777 default: | 836 default: |
778 type_feedback_slot_ = spec->AddInterpreterCompareICSlot(); | 837 type_feedback_slot_ = spec->AddInterpreterCompareICSlot(); |
779 } | 838 } |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 return static_cast<const Node*>(this)->IsMonomorphic(); | 976 return static_cast<const Node*>(this)->IsMonomorphic(); |
918 PROPERTY_NODE_LIST(GENERATE_CASE) | 977 PROPERTY_NODE_LIST(GENERATE_CASE) |
919 CALL_NODE_LIST(GENERATE_CASE) | 978 CALL_NODE_LIST(GENERATE_CASE) |
920 #undef GENERATE_CASE | 979 #undef GENERATE_CASE |
921 default: | 980 default: |
922 UNREACHABLE(); | 981 UNREACHABLE(); |
923 return false; | 982 return false; |
924 } | 983 } |
925 } | 984 } |
926 | 985 |
927 void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, | 986 void Call::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
928 FeedbackVectorSlotCache* cache) { | 987 FeedbackVectorSlotCache* cache) { |
929 ic_slot_ = spec->AddCallICSlot(); | 988 ic_slot_ = spec->AddCallICSlot(); |
930 } | 989 } |
931 | 990 |
932 Call::CallType Call::GetCallType() const { | 991 Call::CallType Call::GetCallType() const { |
933 VariableProxy* proxy = expression()->AsVariableProxy(); | 992 VariableProxy* proxy = expression()->AsVariableProxy(); |
934 if (proxy != NULL) { | 993 if (proxy != NULL) { |
935 if (proxy->var()->IsUnallocated()) { | 994 if (proxy->var()->IsUnallocated()) { |
936 return GLOBAL_CALL; | 995 return GLOBAL_CALL; |
937 } else if (proxy->var()->IsLookupSlot()) { | 996 } else if (proxy->var()->IsLookupSlot()) { |
(...skipping 18 matching lines...) Expand all Loading... |
956 return OTHER_CALL; | 1015 return OTHER_CALL; |
957 } | 1016 } |
958 | 1017 |
959 CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements, | 1018 CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements, |
960 int pos) | 1019 int pos) |
961 : Expression(pos, kCaseClause), | 1020 : Expression(pos, kCaseClause), |
962 label_(label), | 1021 label_(label), |
963 statements_(statements), | 1022 statements_(statements), |
964 compare_type_(AstType::None()) {} | 1023 compare_type_(AstType::None()) {} |
965 | 1024 |
966 void CaseClause::AssignFeedbackVectorSlots(Isolate* isolate, | 1025 void CaseClause::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, |
967 FeedbackVectorSpec* spec, | |
968 FeedbackVectorSlotCache* cache) { | 1026 FeedbackVectorSlotCache* cache) { |
969 type_feedback_slot_ = spec->AddInterpreterCompareICSlot(); | 1027 type_feedback_slot_ = spec->AddInterpreterCompareICSlot(); |
970 } | 1028 } |
971 | 1029 |
972 uint32_t Literal::Hash() { | 1030 uint32_t Literal::Hash() { |
973 return raw_value()->IsString() | 1031 return raw_value()->IsString() |
974 ? raw_value()->AsString()->hash() | 1032 ? raw_value()->AsString()->hash() |
975 : ComputeLongHash(double_to_uint64(raw_value()->AsNumber())); | 1033 : ComputeLongHash(double_to_uint64(raw_value()->AsNumber())); |
976 } | 1034 } |
977 | 1035 |
978 | 1036 |
979 // static | 1037 // static |
980 bool Literal::Match(void* literal1, void* literal2) { | 1038 bool Literal::Match(void* literal1, void* literal2) { |
981 const AstValue* x = static_cast<Literal*>(literal1)->raw_value(); | 1039 const AstValue* x = static_cast<Literal*>(literal1)->raw_value(); |
982 const AstValue* y = static_cast<Literal*>(literal2)->raw_value(); | 1040 const AstValue* y = static_cast<Literal*>(literal2)->raw_value(); |
983 return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) || | 1041 return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) || |
984 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); | 1042 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); |
985 } | 1043 } |
986 | 1044 |
987 } // namespace internal | 1045 } // namespace internal |
988 } // namespace v8 | 1046 } // namespace v8 |
OLD | NEW |