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