X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fv8%2Fsrc%2Fast.cc;h=1a9919b5aa52c0343d60cac4cffd4dcf2ee4d24e;hb=ff3e2503a20db9193d323c1d19c38c68004dec4a;hp=843f8c89600d66d5e201064d75643fa6802a04c8;hpb=172ee7c03df346ff158858709f7f6494e695e0e4;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/v8/src/ast.cc b/src/v8/src/ast.cc index 843f8c8..1a9919b 100644 --- a/src/v8/src/ast.cc +++ b/src/v8/src/ast.cc @@ -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 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 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(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 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 key = property->key()->value(); + Handle 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::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(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 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 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 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 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 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(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 name = Handle::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 name = Handle::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 type, Handle 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::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 constant(lookup.GetConstantFromMap(*type), - type->GetIsolate()); - if (constant->IsJSFunction()) { - target_ = Handle::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::cast(type->prototype())); - type = Handle(holder()->map()); - } + Property* property = expression()->AsProperty(); + return property != NULL ? PROPERTY_CALL : OTHER_CALL; } @@ -580,89 +631,25 @@ bool Call::ComputeGlobalTarget(Handle global, } -Handle 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::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 name = Handle::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 = receiver_types_.at(i); - ASSERT(!map.is_null() && *map != NULL); - } - } -#endif - if (is_monomorphic_) { - Handle 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::null(); + TypeFeedbackId id = key()->LiteralFeedbackId(); + SmallMapList maps; + oracle->CollectReceiverTypes(id, &maps); + receiver_type_ = maps.length() == 1 ? maps.at(0) + : Handle::null(); } @@ -1035,16 +1022,16 @@ RegExpAlternative::RegExpAlternative(ZoneList* nodes) } -CaseClause::CaseClause(Isolate* isolate, +CaseClause::CaseClause(Zone* zone, Expression* label, ZoneList* 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)) { }