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