Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / src / ast.cc
index 843f8c8..1a9919b 100644 (file)
@@ -82,8 +82,8 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) {
 }
 
 
-VariableProxy::VariableProxy(Isolate* isolate, Variable* var, int position)
-    : Expression(isolate, position),
+VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
+    : Expression(zone, position),
       name_(var->name()),
       var_(NULL),  // Will be set by the call to BindTo.
       is_this_(var->is_this()),
@@ -94,12 +94,12 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var, int position)
 }
 
 
-VariableProxy::VariableProxy(Isolate* isolate,
+VariableProxy::VariableProxy(Zone* zone,
                              Handle<String> name,
                              bool is_this,
                              Interface* interface,
                              int position)
-    : Expression(isolate, position),
+    : Expression(zone, position),
       name_(name),
       var_(NULL),
       is_this_(is_this),
@@ -126,20 +126,18 @@ void VariableProxy::BindTo(Variable* var) {
 }
 
 
-Assignment::Assignment(Isolate* isolate,
+Assignment::Assignment(Zone* zone,
                        Token::Value op,
                        Expression* target,
                        Expression* value,
                        int pos)
-    : Expression(isolate, pos),
+    : Expression(zone, pos),
       op_(op),
       target_(target),
       value_(value),
       binary_operation_(NULL),
-      assignment_id_(GetNextId(isolate)),
-      is_monomorphic_(false),
+      assignment_id_(GetNextId(zone)),
       is_uninitialized_(false),
-      is_pre_monomorphic_(false),
       store_mode_(STANDARD_STORE) { }
 
 
@@ -187,15 +185,31 @@ LanguageMode FunctionLiteral::language_mode() const {
 }
 
 
-ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
-                                             Expression* value,
-                                             Isolate* isolate) {
+void FunctionLiteral::InitializeSharedInfo(
+    Handle<Code> unoptimized_code) {
+  for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) {
+    RelocInfo* rinfo = it.rinfo();
+    if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
+    Object* obj = rinfo->target_object();
+    if (obj->IsSharedFunctionInfo()) {
+      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+      if (shared->start_position() == start_position()) {
+        shared_info_ = Handle<SharedFunctionInfo>(shared);
+        break;
+      }
+    }
+  }
+}
+
+
+ObjectLiteralProperty::ObjectLiteralProperty(
+    Zone* zone, Literal* key, Expression* value) {
   emit_store_ = true;
   key_ = key;
   value_ = value;
   Object* k = *key->value();
   if (k->IsInternalizedString() &&
-      isolate->heap()->proto_string()->Equals(String::cast(k))) {
+      zone->isolate()->heap()->proto_string()->Equals(String::cast(k))) {
     kind_ = PROTOTYPE;
   } else if (value_->AsMaterializedLiteral() != NULL) {
     kind_ = MATERIALIZED_LITERAL;
@@ -207,8 +221,8 @@ ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
 }
 
 
-ObjectLiteralProperty::ObjectLiteralProperty(bool is_getter,
-                                             FunctionLiteral* value) {
+ObjectLiteralProperty::ObjectLiteralProperty(
+    Zone* zone, bool is_getter, FunctionLiteral* value) {
   emit_store_ = true;
   value_ = value;
   kind_ = is_getter ? GETTER : SETTER;
@@ -256,6 +270,170 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
 }
 
 
+bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
+  return property != NULL &&
+         property->kind() != ObjectLiteral::Property::PROTOTYPE;
+}
+
+
+void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
+  if (!constant_properties_.is_null()) return;
+
+  // Allocate a fixed array to hold all the constant properties.
+  Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
+      boilerplate_properties_ * 2, TENURED);
+
+  int position = 0;
+  // Accumulate the value in local variables and store it at the end.
+  bool is_simple = true;
+  int depth_acc = 1;
+  uint32_t max_element_index = 0;
+  uint32_t elements = 0;
+  for (int i = 0; i < properties()->length(); i++) {
+    ObjectLiteral::Property* property = properties()->at(i);
+    if (!IsBoilerplateProperty(property)) {
+      is_simple = false;
+      continue;
+    }
+    MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
+    if (m_literal != NULL) {
+      m_literal->BuildConstants(isolate);
+      if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
+    }
+
+    // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
+    // value for COMPUTED properties, the real value is filled in at
+    // runtime. The enumeration order is maintained.
+    Handle<Object> key = property->key()->value();
+    Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
+
+    // Ensure objects that may, at any point in time, contain fields with double
+    // representation are always treated as nested objects. This is true for
+    // computed fields (value is undefined), and smi and double literals
+    // (value->IsNumber()).
+    // TODO(verwaest): Remove once we can store them inline.
+    if (FLAG_track_double_fields &&
+        (value->IsNumber() || value->IsUninitialized())) {
+      may_store_doubles_ = true;
+    }
+
+    is_simple = is_simple && !value->IsUninitialized();
+
+    // Keep track of the number of elements in the object literal and
+    // the largest element index.  If the largest element index is
+    // much larger than the number of elements, creating an object
+    // literal with fast elements will be a waste of space.
+    uint32_t element_index = 0;
+    if (key->IsString()
+        && Handle<String>::cast(key)->AsArrayIndex(&element_index)
+        && element_index > max_element_index) {
+      max_element_index = element_index;
+      elements++;
+    } else if (key->IsSmi()) {
+      int key_value = Smi::cast(*key)->value();
+      if (key_value > 0
+          && static_cast<uint32_t>(key_value) > max_element_index) {
+        max_element_index = key_value;
+      }
+      elements++;
+    }
+
+    // Add name, value pair to the fixed array.
+    constant_properties->set(position++, *key);
+    constant_properties->set(position++, *value);
+  }
+
+  constant_properties_ = constant_properties;
+  fast_elements_ =
+      (max_element_index <= 32) || ((2 * elements) >= max_element_index);
+  set_is_simple(is_simple);
+  set_depth(depth_acc);
+}
+
+
+void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
+  if (!constant_elements_.is_null()) return;
+
+  // Allocate a fixed array to hold all the object literals.
+  Handle<JSArray> array =
+      isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
+  isolate->factory()->SetElementsCapacityAndLength(
+      array, values()->length(), values()->length());
+
+  // Fill in the literals.
+  bool is_simple = true;
+  int depth_acc = 1;
+  bool is_holey = false;
+  for (int i = 0, n = values()->length(); i < n; i++) {
+    Expression* element = values()->at(i);
+    MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
+    if (m_literal != NULL) {
+      m_literal->BuildConstants(isolate);
+      if (m_literal->depth() + 1 > depth_acc) {
+        depth_acc = m_literal->depth() + 1;
+      }
+    }
+    Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
+    if (boilerplate_value->IsTheHole()) {
+      is_holey = true;
+    } else if (boilerplate_value->IsUninitialized()) {
+      is_simple = false;
+      JSObject::SetOwnElement(
+          array, i, handle(Smi::FromInt(0), isolate), kNonStrictMode);
+    } else {
+      JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
+    }
+  }
+
+  Handle<FixedArrayBase> element_values(array->elements());
+
+  // Simple and shallow arrays can be lazily copied, we transform the
+  // elements array to a copy-on-write array.
+  if (is_simple && depth_acc == 1 && values()->length() > 0 &&
+      array->HasFastSmiOrObjectElements()) {
+    element_values->set_map(isolate->heap()->fixed_cow_array_map());
+  }
+
+  // Remember both the literal's constant values as well as the ElementsKind
+  // in a 2-element FixedArray.
+  Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
+
+  ElementsKind kind = array->GetElementsKind();
+  kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
+
+  literals->set(0, Smi::FromInt(kind));
+  literals->set(1, *element_values);
+
+  constant_elements_ = literals;
+  set_is_simple(is_simple);
+  set_depth(depth_acc);
+}
+
+
+Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
+                                                        Isolate* isolate) {
+  if (expression->AsLiteral() != NULL) {
+    return expression->AsLiteral()->value();
+  }
+  if (CompileTimeValue::IsCompileTimeValue(expression)) {
+    return CompileTimeValue::GetValue(isolate, expression);
+  }
+  return isolate->factory()->uninitialized_value();
+}
+
+
+void MaterializedLiteral::BuildConstants(Isolate* isolate) {
+  if (IsArrayLiteral()) {
+    return AsArrayLiteral()->BuildConstantElements(isolate);
+  }
+  if (IsObjectLiteral()) {
+    return AsObjectLiteral()->BuildConstantProperties(isolate);
+  }
+  ASSERT(IsRegExpLiteral());
+  ASSERT(depth() >= 1);  // Depth should be initialized.
+}
+
+
 void TargetCollector::AddTarget(Label* target, Zone* zone) {
   // Add the label to the collector, but discard duplicates.
   int length = targets_.length();
@@ -410,152 +588,25 @@ bool FunctionDeclaration::IsInlineable() const {
 // TODO(rossberg): all RecordTypeFeedback functions should disappear
 // once we use the common type field in the AST consistently.
 
-
-void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
-}
-
-
 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
   to_boolean_types_ = oracle->ToBooleanTypes(test_id());
 }
 
 
-void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle,
-                                  Zone* zone) {
-  // Record type feedback from the oracle in the AST.
-  is_uninitialized_ = oracle->LoadIsUninitialized(this);
-  if (is_uninitialized_) return;
-
-  is_pre_monomorphic_ = oracle->LoadIsPreMonomorphic(this);
-  is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this);
-  ASSERT(!is_pre_monomorphic_ || !is_monomorphic_);
-  receiver_types_.Clear();
-  if (key()->IsPropertyName()) {
-    FunctionPrototypeStub proto_stub(Code::LOAD_IC);
-    if (oracle->LoadIsStub(this, &proto_stub)) {
-      is_function_prototype_ = true;
-    } else {
-      Literal* lit_key = key()->AsLiteral();
-      ASSERT(lit_key != NULL && lit_key->value()->IsString());
-      Handle<String> name = Handle<String>::cast(lit_key->value());
-      oracle->LoadReceiverTypes(this, name, &receiver_types_);
+Call::CallType Call::GetCallType(Isolate* isolate) const {
+  VariableProxy* proxy = expression()->AsVariableProxy();
+  if (proxy != NULL) {
+    if (proxy->var()->is_possibly_eval(isolate)) {
+      return POSSIBLY_EVAL_CALL;
+    } else if (proxy->var()->IsUnallocated()) {
+      return GLOBAL_CALL;
+    } else if (proxy->var()->IsLookupSlot()) {
+      return LOOKUP_SLOT_CALL;
     }
-  } else if (oracle->LoadIsBuiltin(this, Builtins::kKeyedLoadIC_String)) {
-    is_string_access_ = true;
-  } else if (is_monomorphic_) {
-    receiver_types_.Add(oracle->LoadMonomorphicReceiverType(this), zone);
-  } else if (oracle->LoadIsPolymorphic(this)) {
-    receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
-    oracle->CollectKeyedReceiverTypes(PropertyFeedbackId(), &receiver_types_);
-  }
-}
-
-
-void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle,
-                                    Zone* zone) {
-  Property* prop = target()->AsProperty();
-  ASSERT(prop != NULL);
-  TypeFeedbackId id = AssignmentFeedbackId();
-  is_uninitialized_ = oracle->StoreIsUninitialized(id);
-  if (is_uninitialized_) return;
-
-  is_pre_monomorphic_ = oracle->StoreIsPreMonomorphic(id);
-  is_monomorphic_ = oracle->StoreIsMonomorphicNormal(id);
-  ASSERT(!is_pre_monomorphic_ || !is_monomorphic_);
-  receiver_types_.Clear();
-  if (prop->key()->IsPropertyName()) {
-    Literal* lit_key = prop->key()->AsLiteral();
-    ASSERT(lit_key != NULL && lit_key->value()->IsString());
-    Handle<String> name = Handle<String>::cast(lit_key->value());
-    oracle->StoreReceiverTypes(this, name, &receiver_types_);
-  } else if (is_monomorphic_) {
-    // Record receiver type for monomorphic keyed stores.
-    receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone);
-    store_mode_ = oracle->GetStoreMode(id);
-  } else if (oracle->StoreIsKeyedPolymorphic(id)) {
-    receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
-    oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
-    store_mode_ = oracle->GetStoreMode(id);
-  }
-}
-
-
-void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle,
-                                        Zone* zone) {
-  TypeFeedbackId id = CountStoreFeedbackId();
-  is_monomorphic_ = oracle->StoreIsMonomorphicNormal(id);
-  receiver_types_.Clear();
-  if (is_monomorphic_) {
-    // Record receiver type for monomorphic keyed stores.
-    receiver_types_.Add(
-        oracle->StoreMonomorphicReceiverType(id), zone);
-  } else if (oracle->StoreIsKeyedPolymorphic(id)) {
-    receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
-    oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
-  } else {
-    oracle->CollectPolymorphicStoreReceiverTypes(id, &receiver_types_);
   }
-  store_mode_ = oracle->GetStoreMode(id);
-  type_ = oracle->IncrementType(this);
-}
-
-
-void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  compare_type_ = oracle->ClauseType(CompareId());
-}
-
-
-bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
-  // If there is an interceptor, we can't compute the target for a direct call.
-  if (type->has_named_interceptor()) return false;
 
-  if (check_type_ == RECEIVER_MAP_CHECK) {
-    // For primitive checks the holder is set up to point to the corresponding
-    // prototype object, i.e. one step of the algorithm below has been already
-    // performed. For non-primitive checks we clear it to allow computing
-    // targets for polymorphic calls.
-    holder_ = Handle<JSObject>::null();
-  }
-  LookupResult lookup(type->GetIsolate());
-  while (true) {
-    // If a dictionary map is found in the prototype chain before the actual
-    // target, a new target can always appear. In that case, bail out.
-    // TODO(verwaest): Alternatively a runtime negative lookup on the normal
-    // receiver or prototype could be added.
-    if (type->is_dictionary_map()) return false;
-    type->LookupDescriptor(NULL, *name, &lookup);
-    if (lookup.IsFound()) {
-      switch (lookup.type()) {
-        case CONSTANT: {
-          // We surely know the target for a constant function.
-          Handle<Object> constant(lookup.GetConstantFromMap(*type),
-                                  type->GetIsolate());
-          if (constant->IsJSFunction()) {
-            target_ = Handle<JSFunction>::cast(constant);
-            return true;
-          }
-          // Fall through.
-        }
-        case NORMAL:
-        case FIELD:
-        case CALLBACKS:
-        case HANDLER:
-        case INTERCEPTOR:
-          // We don't know the target.
-          return false;
-        case TRANSITION:
-        case NONEXISTENT:
-          UNREACHABLE();
-          break;
-      }
-    }
-    // If we reach the end of the prototype chain, we don't know the target.
-    if (!type->prototype()->IsJSObject()) return false;
-    // Go up the prototype chain, recording where we are currently.
-    holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
-    type = Handle<Map>(holder()->map());
-  }
+  Property* property = expression()->AsProperty();
+  return property != NULL ? PROPERTY_CALL : OTHER_CALL;
 }
 
 
@@ -580,89 +631,25 @@ bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
 }
 
 
-Handle<JSObject> Call::GetPrototypeForPrimitiveCheck(
-    CheckType check, Isolate* isolate) {
-  v8::internal::Context* native_context = isolate->context()->native_context();
-  JSFunction* function = NULL;
-  switch (check) {
-    case RECEIVER_MAP_CHECK:
-      UNREACHABLE();
-      break;
-    case STRING_CHECK:
-      function = native_context->string_function();
-      break;
-    case SYMBOL_CHECK:
-      function = native_context->symbol_function();
-      break;
-    case NUMBER_CHECK:
-      function = native_context->number_function();
-      break;
-    case BOOLEAN_CHECK:
-      function = native_context->boolean_function();
-      break;
-  }
-  ASSERT(function != NULL);
-  return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
-}
-
-
-void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
-                              CallKind call_kind) {
-  is_monomorphic_ = oracle->CallIsMonomorphic(this);
-  Property* property = expression()->AsProperty();
-  if (property == NULL) {
-    // Function call.  Specialize for monomorphic calls.
-    if (is_monomorphic_) target_ = oracle->GetCallTarget(this);
-  } else {
-    // Method call.  Specialize for the receiver types seen at runtime.
-    Literal* key = property->key()->AsLiteral();
-    ASSERT(key != NULL && key->value()->IsString());
-    Handle<String> name = Handle<String>::cast(key->value());
-    check_type_ = oracle->GetCallCheckType(this);
-    receiver_types_.Clear();
-    if (check_type_ == RECEIVER_MAP_CHECK) {
-      oracle->CallReceiverTypes(this, name, call_kind, &receiver_types_);
-      is_monomorphic_ = is_monomorphic_ && receiver_types_.length() > 0;
-    } else {
-      holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
-      receiver_types_.Add(handle(holder_->map()), oracle->zone());
-    }
-#ifdef ENABLE_SLOW_ASSERTS
-    if (FLAG_enable_slow_asserts) {
-      int length = receiver_types_.length();
-      for (int i = 0; i < length; i++) {
-        Handle<Map> map = receiver_types_.at(i);
-        ASSERT(!map.is_null() && *map != NULL);
-      }
-    }
-#endif
-    if (is_monomorphic_) {
-      Handle<Map> map = receiver_types_.first();
-      is_monomorphic_ = ComputeTarget(map, name);
-    }
-  }
-}
-
-
 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  allocation_info_cell_ = oracle->GetCallNewAllocationInfoCell(this);
-  is_monomorphic_ = oracle->CallNewIsMonomorphic(this);
+  allocation_site_ =
+      oracle->GetCallNewAllocationSite(CallNewFeedbackId());
+  is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackId());
   if (is_monomorphic_) {
-    target_ = oracle->GetCallNewTarget(this);
-    Object* value = allocation_info_cell_->value();
-    ASSERT(!value->IsTheHole());
-    if (value->IsAllocationSite()) {
-      AllocationSite* site = AllocationSite::cast(value);
-      elements_kind_ = site->GetElementsKind();
+    target_ = oracle->GetCallNewTarget(CallNewFeedbackId());
+    if (!allocation_site_.is_null()) {
+      elements_kind_ = allocation_site_->GetElementsKind();
     }
   }
 }
 
 
 void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this)
-      ? oracle->GetObjectLiteralStoreMap(this)
-      : Handle<Map>::null();
+  TypeFeedbackId id = key()->LiteralFeedbackId();
+  SmallMapList maps;
+  oracle->CollectReceiverTypes(id, &maps);
+  receiver_type_ = maps.length() == 1 ? maps.at(0)
+                                      : Handle<Map>::null();
 }
 
 
@@ -1035,16 +1022,16 @@ RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
 }
 
 
-CaseClause::CaseClause(Isolate* isolate,
+CaseClause::CaseClause(Zone* zone,
                        Expression* label,
                        ZoneList<Statement*>* statements,
                        int pos)
-    : AstNode(pos),
+    : Expression(zone, pos),
       label_(label),
       statements_(statements),
-      compare_type_(Type::None(), isolate),
-      compare_id_(AstNode::GetNextId(isolate)),
-      entry_id_(AstNode::GetNextId(isolate)) {
+      compare_type_(Type::None(zone)),
+      compare_id_(AstNode::GetNextId(zone)),
+      entry_id_(AstNode::GetNextId(zone)) {
 }