1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "ast.h" 31 #include "parser.h" 32 #include "scopes.h" 33 #include "string-stream.h" 34 #include "type-info.h" 35 36 namespace v8 { 37 namespace internal { 38 39 AstSentinels::AstSentinels() 40 : this_proxy_(true), 41 identifier_proxy_(false), 42 valid_left_hand_side_sentinel_(), 43 this_property_(&this_proxy_, NULL, 0), 44 call_sentinel_(NULL, NULL, 0) { 45 } 46 47 48 // ---------------------------------------------------------------------------- 49 // All the Accept member functions for each syntax tree node type. 50 51 void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); } 52 53 #define DECL_ACCEPT(type) \ 54 void type::Accept(AstVisitor* v) { v->Visit##type(this); } 55 AST_NODE_LIST(DECL_ACCEPT) 56 #undef DECL_ACCEPT 57 58 59 // ---------------------------------------------------------------------------- 60 // Implementation of other node functionality. 61 62 Assignment* ExpressionStatement::StatementAsSimpleAssignment() { 63 return (expression()->AsAssignment() != NULL && 64 !expression()->AsAssignment()->is_compound()) 65 ? expression()->AsAssignment() 66 : NULL; 67 } 68 69 70 CountOperation* ExpressionStatement::StatementAsCountOperation() { 71 return expression()->AsCountOperation(); 72 } 73 74 75 VariableProxy::VariableProxy(Variable* var) 76 : name_(var->name()), 77 var_(NULL), // Will be set by the call to BindTo. 78 is_this_(var->is_this()), 79 inside_with_(false), 80 is_trivial_(false), 81 position_(RelocInfo::kNoPosition) { 82 BindTo(var); 83 } 84 85 86 VariableProxy::VariableProxy(Handle<String> name, 87 bool is_this, 88 bool inside_with, 89 int position) 90 : name_(name), 91 var_(NULL), 92 is_this_(is_this), 93 inside_with_(inside_with), 94 is_trivial_(false), 95 position_(position) { 96 // Names must be canonicalized for fast equality checks. 97 ASSERT(name->IsSymbol()); 98 } 99 100 101 VariableProxy::VariableProxy(bool is_this) 102 : var_(NULL), 103 is_this_(is_this), 104 inside_with_(false), 105 is_trivial_(false) { 106 } 107 108 109 void VariableProxy::BindTo(Variable* var) { 110 ASSERT(var_ == NULL); // must be bound only once 111 ASSERT(var != NULL); // must bind 112 ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name())); 113 // Ideally CONST-ness should match. However, this is very hard to achieve 114 // because we don't know the exact semantics of conflicting (const and 115 // non-const) multiple variable declarations, const vars introduced via 116 // eval() etc. Const-ness and variable declarations are a complete mess 117 // in JS. Sigh... 118 var_ = var; 119 var->set_is_used(true); 120 } 121 122 123 Assignment::Assignment(Token::Value op, 124 Expression* target, 125 Expression* value, 126 int pos) 127 : op_(op), 128 target_(target), 129 value_(value), 130 pos_(pos), 131 binary_operation_(NULL), 132 compound_load_id_(kNoNumber), 133 assignment_id_(GetNextId()), 134 block_start_(false), 135 block_end_(false), 136 is_monomorphic_(false), 137 receiver_types_(NULL) { 138 ASSERT(Token::IsAssignmentOp(op)); 139 if (is_compound()) { 140 binary_operation_ = 141 new BinaryOperation(binary_op(), target, value, pos + 1); 142 compound_load_id_ = GetNextId(); 143 } 144 } 145 146 147 Token::Value Assignment::binary_op() const { 148 switch (op_) { 149 case Token::ASSIGN_BIT_OR: return Token::BIT_OR; 150 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR; 151 case Token::ASSIGN_BIT_AND: return Token::BIT_AND; 152 case Token::ASSIGN_SHL: return Token::SHL; 153 case Token::ASSIGN_SAR: return Token::SAR; 154 case Token::ASSIGN_SHR: return Token::SHR; 155 case Token::ASSIGN_ADD: return Token::ADD; 156 case Token::ASSIGN_SUB: return Token::SUB; 157 case Token::ASSIGN_MUL: return Token::MUL; 158 case Token::ASSIGN_DIV: return Token::DIV; 159 case Token::ASSIGN_MOD: return Token::MOD; 160 default: UNREACHABLE(); 161 } 162 return Token::ILLEGAL; 163 } 164 165 166 bool FunctionLiteral::AllowsLazyCompilation() { 167 return scope()->AllowsLazyCompilation(); 168 } 169 170 171 ObjectLiteral::Property::Property(Literal* key, Expression* value) { 172 emit_store_ = true; 173 key_ = key; 174 value_ = value; 175 Object* k = *key->handle(); 176 if (k->IsSymbol() && HEAP->Proto_symbol()->Equals(String::cast(k))) { 177 kind_ = PROTOTYPE; 178 } else if (value_->AsMaterializedLiteral() != NULL) { 179 kind_ = MATERIALIZED_LITERAL; 180 } else if (value_->AsLiteral() != NULL) { 181 kind_ = CONSTANT; 182 } else { 183 kind_ = COMPUTED; 184 } 185 } 186 187 188 ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { 189 emit_store_ = true; 190 key_ = new Literal(value->name()); 191 value_ = value; 192 kind_ = is_getter ? GETTER : SETTER; 193 } 194 195 196 bool ObjectLiteral::Property::IsCompileTimeValue() { 197 return kind_ == CONSTANT || 198 (kind_ == MATERIALIZED_LITERAL && 199 CompileTimeValue::IsCompileTimeValue(value_)); 200 } 201 202 203 void ObjectLiteral::Property::set_emit_store(bool emit_store) { 204 emit_store_ = emit_store; 205 } 206 207 208 bool ObjectLiteral::Property::emit_store() { 209 return emit_store_; 210 } 211 212 213 bool IsEqualString(void* first, void* second) { 214 ASSERT((*reinterpret_cast<String**>(first))->IsString()); 215 ASSERT((*reinterpret_cast<String**>(second))->IsString()); 216 Handle<String> h1(reinterpret_cast<String**>(first)); 217 Handle<String> h2(reinterpret_cast<String**>(second)); 218 return (*h1)->Equals(*h2); 219 } 220 221 222 bool IsEqualNumber(void* first, void* second) { 223 ASSERT((*reinterpret_cast<Object**>(first))->IsNumber()); 224 ASSERT((*reinterpret_cast<Object**>(second))->IsNumber()); 225 226 Handle<Object> h1(reinterpret_cast<Object**>(first)); 227 Handle<Object> h2(reinterpret_cast<Object**>(second)); 228 if (h1->IsSmi()) { 229 return h2->IsSmi() && *h1 == *h2; 230 } 231 if (h2->IsSmi()) return false; 232 Handle<HeapNumber> n1 = Handle<HeapNumber>::cast(h1); 233 Handle<HeapNumber> n2 = Handle<HeapNumber>::cast(h2); 234 ASSERT(isfinite(n1->value())); 235 ASSERT(isfinite(n2->value())); 236 return n1->value() == n2->value(); 237 } 238 239 240 void ObjectLiteral::CalculateEmitStore() { 241 HashMap properties(&IsEqualString); 242 HashMap elements(&IsEqualNumber); 243 for (int i = this->properties()->length() - 1; i >= 0; i--) { 244 ObjectLiteral::Property* property = this->properties()->at(i); 245 Literal* literal = property->key(); 246 Handle<Object> handle = literal->handle(); 247 248 if (handle->IsNull()) { 249 continue; 250 } 251 252 uint32_t hash; 253 HashMap* table; 254 void* key; 255 Factory* factory = Isolate::Current()->factory(); 256 if (handle->IsSymbol()) { 257 Handle<String> name(String::cast(*handle)); 258 if (name->AsArrayIndex(&hash)) { 259 Handle<Object> key_handle = factory->NewNumberFromUint(hash); 260 key = key_handle.location(); 261 table = &elements; 262 } else { 263 key = name.location(); 264 hash = name->Hash(); 265 table = &properties; 266 } 267 } else if (handle->ToArrayIndex(&hash)) { 268 key = handle.location(); 269 table = &elements; 270 } else { 271 ASSERT(handle->IsNumber()); 272 double num = handle->Number(); 273 char arr[100]; 274 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 275 const char* str = DoubleToCString(num, buffer); 276 Handle<String> name = factory->NewStringFromAscii(CStrVector(str)); 277 key = name.location(); 278 hash = name->Hash(); 279 table = &properties; 280 } 281 // If the key of a computed property is in the table, do not emit 282 // a store for the property later. 283 if (property->kind() == ObjectLiteral::Property::COMPUTED) { 284 if (table->Lookup(key, hash, false) != NULL) { 285 property->set_emit_store(false); 286 } 287 } 288 // Add key to the table. 289 table->Lookup(key, hash, true); 290 } 291 } 292 293 294 void TargetCollector::AddTarget(Label* target) { 295 // Add the label to the collector, but discard duplicates. 296 int length = targets_->length(); 297 for (int i = 0; i < length; i++) { 298 if (targets_->at(i) == target) return; 299 } 300 targets_->Add(target); 301 } 302 303 304 bool UnaryOperation::ResultOverwriteAllowed() { 305 switch (op_) { 306 case Token::BIT_NOT: 307 case Token::SUB: 308 return true; 309 default: 310 return false; 311 } 312 } 313 314 315 bool BinaryOperation::ResultOverwriteAllowed() { 316 switch (op_) { 317 case Token::COMMA: 318 case Token::OR: 319 case Token::AND: 320 return false; 321 case Token::BIT_OR: 322 case Token::BIT_XOR: 323 case Token::BIT_AND: 324 case Token::SHL: 325 case Token::SAR: 326 case Token::SHR: 327 case Token::ADD: 328 case Token::SUB: 329 case Token::MUL: 330 case Token::DIV: 331 case Token::MOD: 332 return true; 333 default: 334 UNREACHABLE(); 335 } 336 return false; 337 } 338 339 340 BinaryOperation::BinaryOperation(Assignment* assignment) { 341 ASSERT(assignment->is_compound()); 342 op_ = assignment->binary_op(); 343 left_ = assignment->target(); 344 right_ = assignment->value(); 345 pos_ = assignment->position(); 346 } 347 348 349 // ---------------------------------------------------------------------------- 350 // Inlining support 351 352 bool Declaration::IsInlineable() const { 353 UNREACHABLE(); 354 return false; 355 } 356 357 358 bool TargetCollector::IsInlineable() const { 359 UNREACHABLE(); 360 return false; 361 } 362 363 364 bool Slot::IsInlineable() const { 365 UNREACHABLE(); 366 return false; 367 } 368 369 370 bool ForInStatement::IsInlineable() const { 371 return false; 372 } 373 374 375 bool WithEnterStatement::IsInlineable() const { 376 return false; 377 } 378 379 380 bool WithExitStatement::IsInlineable() const { 381 return false; 382 } 383 384 385 bool SwitchStatement::IsInlineable() const { 386 return false; 387 } 388 389 390 bool TryStatement::IsInlineable() const { 391 return false; 392 } 393 394 395 bool TryCatchStatement::IsInlineable() const { 396 return false; 397 } 398 399 400 bool TryFinallyStatement::IsInlineable() const { 401 return false; 402 } 403 404 405 bool CatchExtensionObject::IsInlineable() const { 406 return false; 407 } 408 409 410 bool DebuggerStatement::IsInlineable() const { 411 return false; 412 } 413 414 415 bool Throw::IsInlineable() const { 416 // TODO(1143): Make functions containing throw inlineable. 417 return false; 418 } 419 420 421 bool MaterializedLiteral::IsInlineable() const { 422 // TODO(1322): Allow materialized literals. 423 return false; 424 } 425 426 427 bool FunctionLiteral::IsInlineable() const { 428 // TODO(1322): Allow materialized literals. 429 return false; 430 } 431 432 433 bool ThisFunction::IsInlineable() const { 434 return false; 435 } 436 437 438 bool SharedFunctionInfoLiteral::IsInlineable() const { 439 return false; 440 } 441 442 443 bool ValidLeftHandSideSentinel::IsInlineable() const { 444 UNREACHABLE(); 445 return false; 446 } 447 448 449 bool ForStatement::IsInlineable() const { 450 return (init() == NULL || init()->IsInlineable()) 451 && (cond() == NULL || cond()->IsInlineable()) 452 && (next() == NULL || next()->IsInlineable()) 453 && body()->IsInlineable(); 454 } 455 456 457 bool WhileStatement::IsInlineable() const { 458 return cond()->IsInlineable() 459 && body()->IsInlineable(); 460 } 461 462 463 bool DoWhileStatement::IsInlineable() const { 464 return cond()->IsInlineable() 465 && body()->IsInlineable(); 466 } 467 468 469 bool ContinueStatement::IsInlineable() const { 470 return true; 471 } 472 473 474 bool BreakStatement::IsInlineable() const { 475 return true; 476 } 477 478 479 bool EmptyStatement::IsInlineable() const { 480 return true; 481 } 482 483 484 bool Literal::IsInlineable() const { 485 return true; 486 } 487 488 489 bool Block::IsInlineable() const { 490 const int count = statements_.length(); 491 for (int i = 0; i < count; ++i) { 492 if (!statements_[i]->IsInlineable()) return false; 493 } 494 return true; 495 } 496 497 498 bool ExpressionStatement::IsInlineable() const { 499 return expression()->IsInlineable(); 500 } 501 502 503 bool IfStatement::IsInlineable() const { 504 return condition()->IsInlineable() 505 && then_statement()->IsInlineable() 506 && else_statement()->IsInlineable(); 507 } 508 509 510 bool ReturnStatement::IsInlineable() const { 511 return expression()->IsInlineable(); 512 } 513 514 515 bool Conditional::IsInlineable() const { 516 return condition()->IsInlineable() && then_expression()->IsInlineable() && 517 else_expression()->IsInlineable(); 518 } 519 520 521 bool VariableProxy::IsInlineable() const { 522 return var()->is_global() || var()->IsStackAllocated(); 523 } 524 525 526 bool Assignment::IsInlineable() const { 527 return target()->IsInlineable() && value()->IsInlineable(); 528 } 529 530 531 bool Property::IsInlineable() const { 532 return obj()->IsInlineable() && key()->IsInlineable(); 533 } 534 535 536 bool Call::IsInlineable() const { 537 if (!expression()->IsInlineable()) return false; 538 const int count = arguments()->length(); 539 for (int i = 0; i < count; ++i) { 540 if (!arguments()->at(i)->IsInlineable()) return false; 541 } 542 return true; 543 } 544 545 546 bool CallNew::IsInlineable() const { 547 if (!expression()->IsInlineable()) return false; 548 const int count = arguments()->length(); 549 for (int i = 0; i < count; ++i) { 550 if (!arguments()->at(i)->IsInlineable()) return false; 551 } 552 return true; 553 } 554 555 556 bool CallRuntime::IsInlineable() const { 557 // Don't try to inline JS runtime calls because we don't (currently) even 558 // optimize them. 559 if (is_jsruntime()) return false; 560 // Don't inline the %_ArgumentsLength or %_Arguments because their 561 // implementation will not work. There is no stack frame to get them 562 // from. 563 if (function()->intrinsic_type == Runtime::INLINE && 564 (name()->IsEqualTo(CStrVector("_ArgumentsLength")) || 565 name()->IsEqualTo(CStrVector("_Arguments")))) { 566 return false; 567 } 568 const int count = arguments()->length(); 569 for (int i = 0; i < count; ++i) { 570 if (!arguments()->at(i)->IsInlineable()) return false; 571 } 572 return true; 573 } 574 575 576 bool UnaryOperation::IsInlineable() const { 577 return expression()->IsInlineable(); 578 } 579 580 581 bool BinaryOperation::IsInlineable() const { 582 return left()->IsInlineable() && right()->IsInlineable(); 583 } 584 585 586 bool CompareOperation::IsInlineable() const { 587 return left()->IsInlineable() && right()->IsInlineable(); 588 } 589 590 591 bool CompareToNull::IsInlineable() const { 592 return expression()->IsInlineable(); 593 } 594 595 596 bool CountOperation::IsInlineable() const { 597 return expression()->IsInlineable(); 598 } 599 600 601 // ---------------------------------------------------------------------------- 602 // Recording of type feedback 603 604 void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 605 // Record type feedback from the oracle in the AST. 606 is_monomorphic_ = oracle->LoadIsMonomorphic(this); 607 if (key()->IsPropertyName()) { 608 if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_ArrayLength)) { 609 is_array_length_ = true; 610 } else if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_StringLength)) { 611 is_string_length_ = true; 612 } else if (oracle->LoadIsBuiltin(this, 613 Builtins::kLoadIC_FunctionPrototype)) { 614 is_function_prototype_ = true; 615 } else { 616 Literal* lit_key = key()->AsLiteral(); 617 ASSERT(lit_key != NULL && lit_key->handle()->IsString()); 618 Handle<String> name = Handle<String>::cast(lit_key->handle()); 619 ZoneMapList* types = oracle->LoadReceiverTypes(this, name); 620 receiver_types_ = types; 621 } 622 } else if (oracle->LoadIsBuiltin(this, Builtins::kKeyedLoadIC_String)) { 623 is_string_access_ = true; 624 } else if (is_monomorphic_) { 625 monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this); 626 if (monomorphic_receiver_type_->has_external_array_elements()) { 627 set_external_array_type(oracle->GetKeyedLoadExternalArrayType(this)); 628 } 629 } 630 } 631 632 633 void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 634 Property* prop = target()->AsProperty(); 635 ASSERT(prop != NULL); 636 is_monomorphic_ = oracle->StoreIsMonomorphic(this); 637 if (prop->key()->IsPropertyName()) { 638 Literal* lit_key = prop->key()->AsLiteral(); 639 ASSERT(lit_key != NULL && lit_key->handle()->IsString()); 640 Handle<String> name = Handle<String>::cast(lit_key->handle()); 641 ZoneMapList* types = oracle->StoreReceiverTypes(this, name); 642 receiver_types_ = types; 643 } else if (is_monomorphic_) { 644 // Record receiver type for monomorphic keyed loads. 645 monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this); 646 if (monomorphic_receiver_type_->has_external_array_elements()) { 647 set_external_array_type(oracle->GetKeyedStoreExternalArrayType(this)); 648 } 649 } 650 } 651 652 653 void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 654 is_monomorphic_ = oracle->StoreIsMonomorphic(this); 655 if (is_monomorphic_) { 656 // Record receiver type for monomorphic keyed loads. 657 monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this); 658 if (monomorphic_receiver_type_->has_external_array_elements()) { 659 set_external_array_type(oracle->GetKeyedStoreExternalArrayType(this)); 660 } 661 } 662 } 663 664 665 void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 666 TypeInfo info = oracle->SwitchType(this); 667 if (info.IsSmi()) { 668 compare_type_ = SMI_ONLY; 669 } else if (info.IsNonPrimitive()) { 670 compare_type_ = OBJECT_ONLY; 671 } else { 672 ASSERT(compare_type_ == NONE); 673 } 674 } 675 676 677 static bool CanCallWithoutIC(Handle<JSFunction> target, int arity) { 678 SharedFunctionInfo* info = target->shared(); 679 // If the number of formal parameters of the target function does 680 // not match the number of arguments we're passing, we don't want to 681 // deal with it. Otherwise, we can call it directly. 682 return !target->NeedsArgumentsAdaption() || 683 info->formal_parameter_count() == arity; 684 } 685 686 687 bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) { 688 if (check_type_ == RECEIVER_MAP_CHECK) { 689 // For primitive checks the holder is set up to point to the 690 // corresponding prototype object, i.e. one step of the algorithm 691 // below has been already performed. 692 // For non-primitive checks we clear it to allow computing targets 693 // for polymorphic calls. 694 holder_ = Handle<JSObject>::null(); 695 } 696 while (true) { 697 LookupResult lookup; 698 type->LookupInDescriptors(NULL, *name, &lookup); 699 // If the function wasn't found directly in the map, we start 700 // looking upwards through the prototype chain. 701 if (!lookup.IsFound() && type->prototype()->IsJSObject()) { 702 holder_ = Handle<JSObject>(JSObject::cast(type->prototype())); 703 type = Handle<Map>(holder()->map()); 704 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { 705 target_ = Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type)); 706 return CanCallWithoutIC(target_, arguments()->length()); 707 } else { 708 return false; 709 } 710 } 711 } 712 713 714 bool Call::ComputeGlobalTarget(Handle<GlobalObject> global, 715 LookupResult* lookup) { 716 target_ = Handle<JSFunction>::null(); 717 cell_ = Handle<JSGlobalPropertyCell>::null(); 718 ASSERT(lookup->IsProperty() && 719 lookup->type() == NORMAL && 720 lookup->holder() == *global); 721 cell_ = Handle<JSGlobalPropertyCell>(global->GetPropertyCell(lookup)); 722 if (cell_->value()->IsJSFunction()) { 723 Handle<JSFunction> candidate(JSFunction::cast(cell_->value())); 724 // If the function is in new space we assume it's more likely to 725 // change and thus prefer the general IC code. 726 if (!HEAP->InNewSpace(*candidate) && 727 CanCallWithoutIC(candidate, arguments()->length())) { 728 target_ = candidate; 729 return true; 730 } 731 } 732 return false; 733 } 734 735 736 void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 737 Property* property = expression()->AsProperty(); 738 ASSERT(property != NULL); 739 // Specialize for the receiver types seen at runtime. 740 Literal* key = property->key()->AsLiteral(); 741 ASSERT(key != NULL && key->handle()->IsString()); 742 Handle<String> name = Handle<String>::cast(key->handle()); 743 receiver_types_ = oracle->CallReceiverTypes(this, name); 744 #ifdef DEBUG 745 if (FLAG_enable_slow_asserts) { 746 if (receiver_types_ != NULL) { 747 int length = receiver_types_->length(); 748 for (int i = 0; i < length; i++) { 749 Handle<Map> map = receiver_types_->at(i); 750 ASSERT(!map.is_null() && *map != NULL); 751 } 752 } 753 } 754 #endif 755 is_monomorphic_ = oracle->CallIsMonomorphic(this); 756 check_type_ = oracle->GetCallCheckType(this); 757 if (is_monomorphic_) { 758 Handle<Map> map; 759 if (receiver_types_ != NULL && receiver_types_->length() > 0) { 760 ASSERT(check_type_ == RECEIVER_MAP_CHECK); 761 map = receiver_types_->at(0); 762 } else { 763 ASSERT(check_type_ != RECEIVER_MAP_CHECK); 764 holder_ = Handle<JSObject>( 765 oracle->GetPrototypeForPrimitiveCheck(check_type_)); 766 map = Handle<Map>(holder_->map()); 767 } 768 is_monomorphic_ = ComputeTarget(map, name); 769 } 770 } 771 772 773 void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { 774 TypeInfo info = oracle->CompareType(this); 775 if (info.IsSmi()) { 776 compare_type_ = SMI_ONLY; 777 } else if (info.IsNonPrimitive()) { 778 compare_type_ = OBJECT_ONLY; 779 } else { 780 ASSERT(compare_type_ == NONE); 781 } 782 } 783 784 785 // ---------------------------------------------------------------------------- 786 // Implementation of AstVisitor 787 788 bool AstVisitor::CheckStackOverflow() { 789 if (stack_overflow_) return true; 790 StackLimitCheck check(isolate_); 791 if (!check.HasOverflowed()) return false; 792 return (stack_overflow_ = true); 793 } 794 795 796 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) { 797 for (int i = 0; i < declarations->length(); i++) { 798 Visit(declarations->at(i)); 799 } 800 } 801 802 803 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) { 804 for (int i = 0; i < statements->length(); i++) { 805 Visit(statements->at(i)); 806 } 807 } 808 809 810 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) { 811 for (int i = 0; i < expressions->length(); i++) { 812 // The variable statement visiting code may pass NULL expressions 813 // to this code. Maybe this should be handled by introducing an 814 // undefined expression or literal? Revisit this code if this 815 // changes 816 Expression* expression = expressions->at(i); 817 if (expression != NULL) Visit(expression); 818 } 819 } 820 821 822 // ---------------------------------------------------------------------------- 823 // Regular expressions 824 825 #define MAKE_ACCEPT(Name) \ 826 void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \ 827 return visitor->Visit##Name(this, data); \ 828 } 829 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT) 830 #undef MAKE_ACCEPT 831 832 #define MAKE_TYPE_CASE(Name) \ 833 RegExp##Name* RegExpTree::As##Name() { \ 834 return NULL; \ 835 } \ 836 bool RegExpTree::Is##Name() { return false; } 837 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) 838 #undef MAKE_TYPE_CASE 839 840 #define MAKE_TYPE_CASE(Name) \ 841 RegExp##Name* RegExp##Name::As##Name() { \ 842 return this; \ 843 } \ 844 bool RegExp##Name::Is##Name() { return true; } 845 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) 846 #undef MAKE_TYPE_CASE 847 848 RegExpEmpty RegExpEmpty::kInstance; 849 850 851 static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) { 852 Interval result = Interval::Empty(); 853 for (int i = 0; i < children->length(); i++) 854 result = result.Union(children->at(i)->CaptureRegisters()); 855 return result; 856 } 857 858 859 Interval RegExpAlternative::CaptureRegisters() { 860 return ListCaptureRegisters(nodes()); 861 } 862 863 864 Interval RegExpDisjunction::CaptureRegisters() { 865 return ListCaptureRegisters(alternatives()); 866 } 867 868 869 Interval RegExpLookahead::CaptureRegisters() { 870 return body()->CaptureRegisters(); 871 } 872 873 874 Interval RegExpCapture::CaptureRegisters() { 875 Interval self(StartRegister(index()), EndRegister(index())); 876 return self.Union(body()->CaptureRegisters()); 877 } 878 879 880 Interval RegExpQuantifier::CaptureRegisters() { 881 return body()->CaptureRegisters(); 882 } 883 884 885 bool RegExpAssertion::IsAnchoredAtStart() { 886 return type() == RegExpAssertion::START_OF_INPUT; 887 } 888 889 890 bool RegExpAssertion::IsAnchoredAtEnd() { 891 return type() == RegExpAssertion::END_OF_INPUT; 892 } 893 894 895 bool RegExpAlternative::IsAnchoredAtStart() { 896 ZoneList<RegExpTree*>* nodes = this->nodes(); 897 for (int i = 0; i < nodes->length(); i++) { 898 RegExpTree* node = nodes->at(i); 899 if (node->IsAnchoredAtStart()) { return true; } 900 if (node->max_match() > 0) { return false; } 901 } 902 return false; 903 } 904 905 906 bool RegExpAlternative::IsAnchoredAtEnd() { 907 ZoneList<RegExpTree*>* nodes = this->nodes(); 908 for (int i = nodes->length() - 1; i >= 0; i--) { 909 RegExpTree* node = nodes->at(i); 910 if (node->IsAnchoredAtEnd()) { return true; } 911 if (node->max_match() > 0) { return false; } 912 } 913 return false; 914 } 915 916 917 bool RegExpDisjunction::IsAnchoredAtStart() { 918 ZoneList<RegExpTree*>* alternatives = this->alternatives(); 919 for (int i = 0; i < alternatives->length(); i++) { 920 if (!alternatives->at(i)->IsAnchoredAtStart()) 921 return false; 922 } 923 return true; 924 } 925 926 927 bool RegExpDisjunction::IsAnchoredAtEnd() { 928 ZoneList<RegExpTree*>* alternatives = this->alternatives(); 929 for (int i = 0; i < alternatives->length(); i++) { 930 if (!alternatives->at(i)->IsAnchoredAtEnd()) 931 return false; 932 } 933 return true; 934 } 935 936 937 bool RegExpLookahead::IsAnchoredAtStart() { 938 return is_positive() && body()->IsAnchoredAtStart(); 939 } 940 941 942 bool RegExpCapture::IsAnchoredAtStart() { 943 return body()->IsAnchoredAtStart(); 944 } 945 946 947 bool RegExpCapture::IsAnchoredAtEnd() { 948 return body()->IsAnchoredAtEnd(); 949 } 950 951 952 // Convert regular expression trees to a simple sexp representation. 953 // This representation should be different from the input grammar 954 // in as many cases as possible, to make it more difficult for incorrect 955 // parses to look as correct ones which is likely if the input and 956 // output formats are alike. 957 class RegExpUnparser: public RegExpVisitor { 958 public: 959 RegExpUnparser(); 960 void VisitCharacterRange(CharacterRange that); 961 SmartPointer<const char> ToString() { return stream_.ToCString(); } 962 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data); 963 FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE) 964 #undef MAKE_CASE 965 private: 966 StringStream* stream() { return &stream_; } 967 HeapStringAllocator alloc_; 968 StringStream stream_; 969 }; 970 971 972 RegExpUnparser::RegExpUnparser() : stream_(&alloc_) { 973 } 974 975 976 void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) { 977 stream()->Add("(|"); 978 for (int i = 0; i < that->alternatives()->length(); i++) { 979 stream()->Add(" "); 980 that->alternatives()->at(i)->Accept(this, data); 981 } 982 stream()->Add(")"); 983 return NULL; 984 } 985 986 987 void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) { 988 stream()->Add("(:"); 989 for (int i = 0; i < that->nodes()->length(); i++) { 990 stream()->Add(" "); 991 that->nodes()->at(i)->Accept(this, data); 992 } 993 stream()->Add(")"); 994 return NULL; 995 } 996 997 998 void RegExpUnparser::VisitCharacterRange(CharacterRange that) { 999 stream()->Add("%k", that.from()); 1000 if (!that.IsSingleton()) { 1001 stream()->Add("-%k", that.to()); 1002 } 1003 } 1004 1005 1006 1007 void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that, 1008 void* data) { 1009 if (that->is_negated()) 1010 stream()->Add("^"); 1011 stream()->Add("["); 1012 for (int i = 0; i < that->ranges()->length(); i++) { 1013 if (i > 0) stream()->Add(" "); 1014 VisitCharacterRange(that->ranges()->at(i)); 1015 } 1016 stream()->Add("]"); 1017 return NULL; 1018 } 1019 1020 1021 void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) { 1022 switch (that->type()) { 1023 case RegExpAssertion::START_OF_INPUT: 1024 stream()->Add("@^i"); 1025 break; 1026 case RegExpAssertion::END_OF_INPUT: 1027 stream()->Add("@$i"); 1028 break; 1029 case RegExpAssertion::START_OF_LINE: 1030 stream()->Add("@^l"); 1031 break; 1032 case RegExpAssertion::END_OF_LINE: 1033 stream()->Add("@$l"); 1034 break; 1035 case RegExpAssertion::BOUNDARY: 1036 stream()->Add("@b"); 1037 break; 1038 case RegExpAssertion::NON_BOUNDARY: 1039 stream()->Add("@B"); 1040 break; 1041 } 1042 return NULL; 1043 } 1044 1045 1046 void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) { 1047 stream()->Add("'"); 1048 Vector<const uc16> chardata = that->data(); 1049 for (int i = 0; i < chardata.length(); i++) { 1050 stream()->Add("%k", chardata[i]); 1051 } 1052 stream()->Add("'"); 1053 return NULL; 1054 } 1055 1056 1057 void* RegExpUnparser::VisitText(RegExpText* that, void* data) { 1058 if (that->elements()->length() == 1) { 1059 that->elements()->at(0).data.u_atom->Accept(this, data); 1060 } else { 1061 stream()->Add("(!"); 1062 for (int i = 0; i < that->elements()->length(); i++) { 1063 stream()->Add(" "); 1064 that->elements()->at(i).data.u_atom->Accept(this, data); 1065 } 1066 stream()->Add(")"); 1067 } 1068 return NULL; 1069 } 1070 1071 1072 void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) { 1073 stream()->Add("(# %i ", that->min()); 1074 if (that->max() == RegExpTree::kInfinity) { 1075 stream()->Add("- "); 1076 } else { 1077 stream()->Add("%i ", that->max()); 1078 } 1079 stream()->Add(that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n "); 1080 that->body()->Accept(this, data); 1081 stream()->Add(")"); 1082 return NULL; 1083 } 1084 1085 1086 void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) { 1087 stream()->Add("(^ "); 1088 that->body()->Accept(this, data); 1089 stream()->Add(")"); 1090 return NULL; 1091 } 1092 1093 1094 void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) { 1095 stream()->Add("(-> "); 1096 stream()->Add(that->is_positive() ? "+ " : "- "); 1097 that->body()->Accept(this, data); 1098 stream()->Add(")"); 1099 return NULL; 1100 } 1101 1102 1103 void* RegExpUnparser::VisitBackReference(RegExpBackReference* that, 1104 void* data) { 1105 stream()->Add("(<- %i)", that->index()); 1106 return NULL; 1107 } 1108 1109 1110 void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) { 1111 stream()->Put('%'); 1112 return NULL; 1113 } 1114 1115 1116 SmartPointer<const char> RegExpTree::ToString() { 1117 RegExpUnparser unparser; 1118 Accept(&unparser, NULL); 1119 return unparser.ToString(); 1120 } 1121 1122 1123 RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives) 1124 : alternatives_(alternatives) { 1125 ASSERT(alternatives->length() > 1); 1126 RegExpTree* first_alternative = alternatives->at(0); 1127 min_match_ = first_alternative->min_match(); 1128 max_match_ = first_alternative->max_match(); 1129 for (int i = 1; i < alternatives->length(); i++) { 1130 RegExpTree* alternative = alternatives->at(i); 1131 min_match_ = Min(min_match_, alternative->min_match()); 1132 max_match_ = Max(max_match_, alternative->max_match()); 1133 } 1134 } 1135 1136 1137 RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes) 1138 : nodes_(nodes) { 1139 ASSERT(nodes->length() > 1); 1140 min_match_ = 0; 1141 max_match_ = 0; 1142 for (int i = 0; i < nodes->length(); i++) { 1143 RegExpTree* node = nodes->at(i); 1144 min_match_ += node->min_match(); 1145 int node_max_match = node->max_match(); 1146 if (kInfinity - max_match_ < node_max_match) { 1147 max_match_ = kInfinity; 1148 } else { 1149 max_match_ += node->max_match(); 1150 } 1151 } 1152 } 1153 1154 1155 CaseClause::CaseClause(Expression* label, 1156 ZoneList<Statement*>* statements, 1157 int pos) 1158 : label_(label), 1159 statements_(statements), 1160 position_(pos), 1161 compare_type_(NONE), 1162 entry_id_(AstNode::GetNextId()) { 1163 } 1164 1165 } } // namespace v8::internal 1166