Commit 73529a7d authored by verwaest@chromium.org's avatar verwaest@chromium.org

Support loads from primitive values.

This also changes load computation to use HeapTypes rather than Maps.
TODO: move conversion between maps and heaptypes earlier in the process, already in the oracle.

BUG=
R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/147763006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18938 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0c2c9ece
...@@ -91,10 +91,19 @@ static V8_INLINE bool CheckForName(Handle<String> name, ...@@ -91,10 +91,19 @@ static V8_INLINE bool CheckForName(Handle<String> name,
} }
bool Accessors::IsJSObjectFieldAccessor( bool Accessors::IsJSObjectFieldAccessor(Handle<HeapType> type,
Handle<Map> map, Handle<String> name, Handle<String> name,
int* object_offset) { int* object_offset) {
Isolate* isolate = map->GetIsolate(); Isolate* isolate = name->GetIsolate();
if (type->Is(HeapType::String())) {
return CheckForName(name, isolate->heap()->length_string(),
String::kLengthOffset, object_offset);
}
if (!type->IsClass()) return false;
Handle<Map> map = type->AsClass();
switch (map->instance_type()) { switch (map->instance_type()) {
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
return return
...@@ -122,14 +131,8 @@ bool Accessors::IsJSObjectFieldAccessor( ...@@ -122,14 +131,8 @@ bool Accessors::IsJSObjectFieldAccessor(
JSDataView::kByteOffsetOffset, object_offset) || JSDataView::kByteOffsetOffset, object_offset) ||
CheckForName(name, isolate->heap()->buffer_string(), CheckForName(name, isolate->heap()->buffer_string(),
JSDataView::kBufferOffset, object_offset); JSDataView::kBufferOffset, object_offset);
default: { default:
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
return
CheckForName(name, isolate->heap()->length_string(),
String::kLengthOffset, object_offset);
}
return false; return false;
}
} }
} }
......
...@@ -89,8 +89,7 @@ class Accessors : public AllStatic { ...@@ -89,8 +89,7 @@ class Accessors : public AllStatic {
// Returns true for properties that are accessors to object fields. // Returns true for properties that are accessors to object fields.
// If true, *object_offset contains offset of object field. // If true, *object_offset contains offset of object field.
static bool IsJSObjectFieldAccessor( static bool IsJSObjectFieldAccessor(
Handle<Map> map, Handle<String> name, Handle<HeapType> map, Handle<String> name, int* object_offset);
int* object_offset);
private: private:
......
...@@ -4269,6 +4269,9 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction { ...@@ -4269,6 +4269,9 @@ class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
protected:
virtual int RedefinedOperandIndex() { return 0; }
private: private:
HIsStringAndBranch(HValue* value, HIsStringAndBranch(HValue* value,
HBasicBlock* true_target = NULL, HBasicBlock* true_target = NULL,
...@@ -4291,6 +4294,7 @@ class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction { ...@@ -4291,6 +4294,7 @@ class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction {
protected: protected:
virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
virtual int RedefinedOperandIndex() { return 0; }
private: private:
HIsSmiAndBranch(HValue* value, HIsSmiAndBranch(HValue* value,
......
...@@ -4924,10 +4924,13 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -4924,10 +4924,13 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
} }
static bool CanInlinePropertyAccess(Map* type) { static bool CanInlinePropertyAccess(Handle<HeapType> type) {
return type->IsJSObjectMap() && if (type->Is(HeapType::NumberOrString())) return true;
!type->is_dictionary_map() && if (!type->IsClass()) return false;
!type->has_named_interceptor(); Handle<Map> map = type->AsClass();
return map->IsJSObjectMap() &&
!map->is_dictionary_map() &&
!map->has_named_interceptor();
} }
...@@ -4936,8 +4939,8 @@ static void LookupInPrototypes(Handle<Map> map, ...@@ -4936,8 +4939,8 @@ static void LookupInPrototypes(Handle<Map> map,
LookupResult* lookup) { LookupResult* lookup) {
while (map->prototype()->IsJSObject()) { while (map->prototype()->IsJSObject()) {
Handle<JSObject> holder(JSObject::cast(map->prototype())); Handle<JSObject> holder(JSObject::cast(map->prototype()));
map = Handle<Map>(holder->map()); map = handle(holder->map());
if (!CanInlinePropertyAccess(*map)) break; if (!CanInlinePropertyAccess(IC::MapToType(map))) break;
map->LookupDescriptor(*holder, *name, lookup); map->LookupDescriptor(*holder, *name, lookup);
if (lookup->IsFound()) return; if (lookup->IsFound()) return;
} }
...@@ -5438,7 +5441,7 @@ static bool ComputeStoreField(Handle<Map> type, ...@@ -5438,7 +5441,7 @@ static bool ComputeStoreField(Handle<Map> type,
LookupResult* lookup, LookupResult* lookup,
bool lookup_transition = true) { bool lookup_transition = true) {
ASSERT(!type->is_observed()); ASSERT(!type->is_observed());
if (!CanInlinePropertyAccess(*type)) { if (!CanInlinePropertyAccess(IC::MapToType(type))) {
lookup->NotFound(); lookup->NotFound();
return false; return false;
} }
...@@ -5473,13 +5476,26 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( ...@@ -5473,13 +5476,26 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
PropertyAccessInfo* info) { PropertyAccessInfo* info) {
if (!CanInlinePropertyAccess(*map_)) return false; if (!CanInlinePropertyAccess(type_)) return false;
// Currently only handle HeapType::Number as a polymorphic case.
// TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
// instruction.
if (type_->Is(HeapType::Number())) return false;
// Values are only compatible for monomorphic load if they all behave the same
// regarding value wrappers.
if (type_->Is(HeapType::NumberOrString())) {
if (!info->type_->Is(HeapType::NumberOrString())) return false;
} else {
if (info->type_->Is(HeapType::NumberOrString())) return false;
}
if (!LookupDescriptor()) return false; if (!LookupDescriptor()) return false;
if (!lookup_.IsFound()) { if (!lookup_.IsFound()) {
return (!info->lookup_.IsFound() || info->has_holder()) && return (!info->lookup_.IsFound() || info->has_holder()) &&
map_->prototype() == info->map_->prototype(); map()->prototype() == info->map()->prototype();
} }
// Mismatch if the other access info found the property in the prototype // Mismatch if the other access info found the property in the prototype
...@@ -5507,8 +5523,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( ...@@ -5507,8 +5523,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
map_->LookupDescriptor(NULL, *name_, &lookup_); if (!type_->IsClass()) return true;
return LoadResult(map_); map()->LookupDescriptor(NULL, *name_, &lookup_);
return LoadResult(map());
} }
...@@ -5534,14 +5551,15 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { ...@@ -5534,14 +5551,15 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
Handle<Map> map = map_; Handle<Map> map = this->map();
while (map->prototype()->IsJSObject()) { while (map->prototype()->IsJSObject()) {
holder_ = handle(JSObject::cast(map->prototype())); holder_ = handle(JSObject::cast(map->prototype()));
if (holder_->map()->is_deprecated()) { if (holder_->map()->is_deprecated()) {
JSObject::TryMigrateInstance(holder_); JSObject::TryMigrateInstance(holder_);
} }
map = Handle<Map>(holder_->map()); map = Handle<Map>(holder_->map());
if (!CanInlinePropertyAccess(*map)) { if (!CanInlinePropertyAccess(IC::MapToType(map))) {
lookup_.NotFound(); lookup_.NotFound();
return false; return false;
} }
...@@ -5554,7 +5572,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { ...@@ -5554,7 +5572,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); if (!CanInlinePropertyAccess(type_)) return false;
if (IsJSObjectFieldAccessor()) return true; if (IsJSObjectFieldAccessor()) return true;
if (!LookupDescriptor()) return false; if (!LookupDescriptor()) return false;
if (lookup_.IsFound()) return true; if (lookup_.IsFound()) return true;
...@@ -5564,19 +5582,12 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { ...@@ -5564,19 +5582,12 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
SmallMapList* types) { SmallMapList* types) {
ASSERT(map_.is_identical_to(types->first())); ASSERT(type_->Is(IC::MapToType(types->first())));
if (!CanLoadMonomorphic()) return false; if (!CanLoadMonomorphic()) return false;
if (types->length() > kMaxLoadPolymorphism) return false; if (types->length() > kMaxLoadPolymorphism) return false;
if (IsStringLength()) {
for (int i = 1; i < types->length(); ++i) {
if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
}
return true;
}
if (IsArrayLength()) { if (IsArrayLength()) {
bool is_fast = IsFastElementsKind(map_->elements_kind()); bool is_fast = IsFastElementsKind(map()->elements_kind());
for (int i = 1; i < types->length(); ++i) { for (int i = 1; i < types->length(); ++i) {
Handle<Map> test_map = types->at(i); Handle<Map> test_map = types->at(i);
if (test_map->instance_type() != JS_ARRAY_TYPE) return false; if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
...@@ -5587,16 +5598,25 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( ...@@ -5587,16 +5598,25 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
return true; return true;
} }
if (IsJSObjectFieldAccessor()) { HObjectAccess access = HObjectAccess::ForMap(); // bogus default
InstanceType instance_type = map_->instance_type(); if (GetJSObjectFieldAccess(&access)) {
for (int i = 1; i < types->length(); ++i) { for (int i = 1; i < types->length(); ++i) {
if (types->at(i)->instance_type() != instance_type) return false; PropertyAccessInfo test_info(
builder_, IC::MapToType(types->at(i)), name_);
HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
if (!access.Equals(test_access)) return false;
} }
return true; return true;
} }
// Currently only handle HeapType::Number as a polymorphic case.
// TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
// instruction.
if (type_->Is(HeapType::Number())) return false;
for (int i = 1; i < types->length(); ++i) { for (int i = 1; i < types->length(); ++i) {
PropertyAccessInfo test_info(isolate(), types->at(i), name_); PropertyAccessInfo test_info(builder_, IC::MapToType(types->at(i)), name_);
if (!test_info.IsCompatibleForLoad(this)) return false; if (!test_info.IsCompatibleForLoad(this)) return false;
} }
...@@ -5604,10 +5624,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( ...@@ -5604,10 +5624,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
} }
static bool NeedsWrappingFor(Handle<HeapType> type, Handle<JSFunction> target) {
return type->Is(HeapType::NumberOrString()) &&
target->shared()->is_classic_mode() &&
!target->shared()->native();
}
HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
PropertyAccessInfo* info, PropertyAccessInfo* info,
HValue* object, HValue* object,
HInstruction* checked_object, HValue* checked_object,
BailoutId ast_id, BailoutId ast_id,
BailoutId return_id, BailoutId return_id,
bool can_inline_accessor) { bool can_inline_accessor) {
...@@ -5631,14 +5658,21 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( ...@@ -5631,14 +5658,21 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
} }
if (info->lookup()->IsPropertyCallbacks()) { if (info->lookup()->IsPropertyCallbacks()) {
Push(checked_object); if (NeedsWrappingFor(info->type(), info->accessor())) {
if (FLAG_inline_accessors && return New<HLoadNamedGeneric>(checked_object, info->name());
can_inline_accessor && // HValue* function = Add<HConstant>(info->accessor());
TryInlineGetter(info->accessor(), ast_id, return_id)) { // Add<HPushArgument>(checked_object);
return NULL; // return New<HCallFunction>(function, 1, WRAP_AND_CALL);
} else {
Push(checked_object);
if (FLAG_inline_accessors &&
can_inline_accessor &&
TryInlineGetter(info->accessor(), ast_id, return_id)) {
return NULL;
}
Add<HPushArgument>(Pop());
return BuildCallConstantFunction(info->accessor(), 1);
} }
Add<HPushArgument>(Pop());
return BuildCallConstantFunction(info->accessor(), 1);
} }
ASSERT(info->lookup()->IsConstant()); ASSERT(info->lookup()->IsConstant());
...@@ -5655,36 +5689,88 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( ...@@ -5655,36 +5689,88 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
// Something did not match; must use a polymorphic load. // Something did not match; must use a polymorphic load.
int count = 0; int count = 0;
HBasicBlock* join = NULL; HBasicBlock* join = NULL;
HBasicBlock* number_block = NULL;
bool handle_smi = false;
for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
PropertyAccessInfo info(isolate(), types->at(i), name); PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
if (info.CanLoadMonomorphic()) { if (info.CanLoadMonomorphic()) {
if (count == 0) { count++;
BuildCheckHeapObject(object); if (info.type()->Is(HeapType::Number())) {
join = graph()->CreateBasicBlock(); handle_smi = true;
break;
} }
++count; }
HBasicBlock* if_true = graph()->CreateBasicBlock(); }
HBasicBlock* if_false = graph()->CreateBasicBlock();
HCompareMap* compare = New<HCompareMap>(
object, info.map(), if_true, if_false);
FinishCurrentBlock(compare);
set_current_block(if_true); count = 0;
bool handled_string = false;
HControlInstruction* smi_check = NULL;
for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
if (info.type()->Is(HeapType::String())) {
if (handled_string) continue;
handled_string = true;
}
if (!info.CanLoadMonomorphic()) continue;
HInstruction* load = BuildLoadMonomorphic( if (count == 0) {
&info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); join = graph()->CreateBasicBlock();
if (load == NULL) { if (handle_smi) {
if (HasStackOverflow()) return; HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
number_block = graph()->CreateBasicBlock();
smi_check = New<HIsSmiAndBranch>(
object, empty_smi_block, not_smi_block);
FinishCurrentBlock(smi_check);
Goto(empty_smi_block, number_block);
set_current_block(not_smi_block);
} else { } else {
if (!load->IsLinked()) { BuildCheckHeapObject(object);
AddInstruction(load);
}
if (!ast_context()->IsEffect()) Push(load);
} }
}
++count;
HBasicBlock* if_true = graph()->CreateBasicBlock();
HBasicBlock* if_false = graph()->CreateBasicBlock();
HUnaryControlInstruction* compare;
if (current_block() != NULL) Goto(join); HValue* dependency;
set_current_block(if_false); if (info.type()->Is(HeapType::Number())) {
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
dependency = smi_check;
} else if (info.type()->Is(HeapType::String())) {
compare = New<HIsStringAndBranch>(object, if_true, if_false);
dependency = compare;
} else {
compare = New<HCompareMap>(object, info.map(), if_true, if_false);
dependency = compare;
} }
FinishCurrentBlock(compare);
if (info.type()->Is(HeapType::Number())) {
Goto(if_true, number_block);
if_true = number_block;
number_block->SetJoinId(ast_id);
}
set_current_block(if_true);
HInstruction* load = BuildLoadMonomorphic(
&info, object, dependency, ast_id,
return_id, FLAG_polymorphic_inlining);
if (load == NULL) {
if (HasStackOverflow()) return;
} else {
if (!load->IsLinked()) {
AddInstruction(load);
}
if (!ast_context()->IsEffect()) Push(load);
}
if (current_block() != NULL) Goto(join);
set_current_block(if_false);
} }
// Finish up. Unconditionally deoptimize if we've handled all the maps we // Finish up. Unconditionally deoptimize if we've handled all the maps we
...@@ -5868,7 +5954,7 @@ static bool ComputeReceiverTypes(Expression* expr, ...@@ -5868,7 +5954,7 @@ static bool ComputeReceiverTypes(Expression* expr,
types->FilterForPossibleTransitions(root_map); types->FilterForPossibleTransitions(root_map);
monomorphic = types->length() == 1; monomorphic = types->length() == 1;
} }
return monomorphic && CanInlinePropertyAccess(*types->first()); return monomorphic && CanInlinePropertyAccess(IC::MapToType(types->first()));
} }
...@@ -5915,15 +6001,21 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr, ...@@ -5915,15 +6001,21 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
Handle<JSFunction> setter; Handle<JSFunction> setter;
Handle<JSObject> holder; Handle<JSObject> holder;
if (LookupSetter(map, name, &setter, &holder)) { if (LookupSetter(map, name, &setter, &holder)) {
AddCheckConstantFunction(holder, object, map); AddCheckMap(object, map);
if (FLAG_inline_accessors && AddCheckPrototypeMaps(holder, map);
TryInlineSetter(setter, ast_id, return_id, value)) { bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter);
bool try_inline = FLAG_inline_accessors && !needs_wrapping;
if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) {
return; return;
} }
Drop(2); Drop(2);
Add<HPushArgument>(object); if (needs_wrapping) {
Add<HPushArgument>(value); instr = BuildStoreNamedGeneric(object, name, value);
instr = BuildCallConstantFunction(setter, 2); } else {
Add<HPushArgument>(object);
Add<HPushArgument>(value);
instr = BuildCallConstantFunction(setter, 2);
}
} else { } else {
Drop(2); Drop(2);
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
...@@ -6776,14 +6868,16 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, ...@@ -6776,14 +6868,16 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
ASSERT(types != NULL); ASSERT(types != NULL);
if (types->length() > 0) { if (types->length() > 0) {
PropertyAccessInfo info(isolate(), types->first(), name); PropertyAccessInfo info(this, IC::MapToType(types->first()), name);
if (!info.CanLoadAsMonomorphic(types)) { if (!info.CanLoadAsMonomorphic(types)) {
return HandlePolymorphicLoadNamedField( return HandlePolymorphicLoadNamedField(
ast_id, expr->LoadId(), object, types, name); ast_id, expr->LoadId(), object, types, name);
} }
HValue* checked_object;
// HeapType::Number() is only supported by polymorphic load/call handling.
ASSERT(!info.type()->Is(HeapType::Number()));
BuildCheckHeapObject(object); BuildCheckHeapObject(object);
HInstruction* checked_object;
if (AreStringTypes(types)) { if (AreStringTypes(types)) {
checked_object = checked_object =
Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
...@@ -7010,7 +7104,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( ...@@ -7010,7 +7104,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
Handle<String> name) { Handle<String> name) {
if (types->length() > kMaxCallPolymorphism) return false; if (types->length() > kMaxCallPolymorphism) return false;
PropertyAccessInfo info(isolate(), types->at(0), name); PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name);
if (!info.CanLoadAsMonomorphic(types)) return false; if (!info.CanLoadAsMonomorphic(types)) return false;
if (!expr->ComputeTarget(info.map(), name)) return false; if (!expr->ComputeTarget(info.map(), name)) return false;
......
...@@ -2256,9 +2256,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2256,9 +2256,12 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
class PropertyAccessInfo { class PropertyAccessInfo {
public: public:
PropertyAccessInfo(Isolate* isolate, Handle<Map> map, Handle<String> name) PropertyAccessInfo(HOptimizedGraphBuilder* builder,
: lookup_(isolate), Handle<HeapType> type,
map_(map), Handle<String> name)
: lookup_(builder->isolate()),
builder_(builder),
type_(type),
name_(name), name_(name),
access_(HObjectAccess::ForMap()) { } access_(HObjectAccess::ForMap()) { }
...@@ -2275,32 +2278,48 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2275,32 +2278,48 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
// PropertyAccessInfo is built for types->first(). // PropertyAccessInfo is built for types->first().
bool CanLoadAsMonomorphic(SmallMapList* types); bool CanLoadAsMonomorphic(SmallMapList* types);
Handle<Map> map() {
if (type_->Is(HeapType::Number())) {
Context* context = current_info()->closure()->context();
context = context->native_context();
return handle(context->number_function()->initial_map());
} else if (type_->Is(HeapType::String())) {
Context* context = current_info()->closure()->context();
context = context->native_context();
return handle(context->string_function()->initial_map());
} else {
return type_->AsClass();
}
}
Handle<HeapType> type() const { return type_; }
Handle<String> name() const { return name_; }
bool IsJSObjectFieldAccessor() { bool IsJSObjectFieldAccessor() {
int offset; // unused int offset; // unused
return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset); return Accessors::IsJSObjectFieldAccessor(type_, name_, &offset);
} }
bool GetJSObjectFieldAccess(HObjectAccess* access) { bool GetJSObjectFieldAccess(HObjectAccess* access) {
if (IsStringLength()) { if (IsArrayLength()) {
*access = HObjectAccess::ForStringLength(); *access = HObjectAccess::ForArrayLength(map()->elements_kind());
return true;
} else if (IsArrayLength()) {
*access = HObjectAccess::ForArrayLength(map_->elements_kind());
return true; return true;
} else { }
int offset; int offset;
if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) { if (Accessors::IsJSObjectFieldAccessor(type_, name_, &offset)) {
if (type_->Is(HeapType::String())) {
ASSERT(name_->Equals(isolate()->heap()->length_string()));
*access = HObjectAccess::ForStringLength();
} else {
*access = HObjectAccess::ForJSObjectOffset(offset); *access = HObjectAccess::ForJSObjectOffset(offset);
return true;
} }
return false; return true;
} }
return false;
} }
bool has_holder() { return !holder_.is_null(); } bool has_holder() { return !holder_.is_null(); }
LookupResult* lookup() { return &lookup_; } LookupResult* lookup() { return &lookup_; }
Handle<Map> map() { return map_; }
Handle<JSObject> holder() { return holder_; } Handle<JSObject> holder() { return holder_; }
Handle<JSFunction> accessor() { return accessor_; } Handle<JSFunction> accessor() { return accessor_; }
Handle<Object> constant() { return constant_; } Handle<Object> constant() { return constant_; }
...@@ -2308,14 +2327,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2308,14 +2327,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
private: private:
Isolate* isolate() { return lookup_.isolate(); } Isolate* isolate() { return lookup_.isolate(); }
CompilationInfo* current_info() { return builder_->current_info(); }
bool IsStringLength() {
return map_->instance_type() < FIRST_NONSTRING_TYPE &&
name_->Equals(isolate()->heap()->length_string());
}
bool IsArrayLength() { bool IsArrayLength() {
return map_->instance_type() == JS_ARRAY_TYPE && return map()->instance_type() == JS_ARRAY_TYPE &&
name_->Equals(isolate()->heap()->length_string()); name_->Equals(isolate()->heap()->length_string());
} }
...@@ -2330,7 +2345,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2330,7 +2345,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
} }
LookupResult lookup_; LookupResult lookup_;
Handle<Map> map_; HOptimizedGraphBuilder* builder_;
Handle<HeapType> type_;
Handle<String> name_; Handle<String> name_;
Handle<JSObject> holder_; Handle<JSObject> holder_;
Handle<JSFunction> accessor_; Handle<JSFunction> accessor_;
...@@ -2340,7 +2356,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { ...@@ -2340,7 +2356,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
HInstruction* BuildLoadMonomorphic(PropertyAccessInfo* info, HInstruction* BuildLoadMonomorphic(PropertyAccessInfo* info,
HValue* object, HValue* object,
HInstruction* checked_object, HValue* checked_object,
BailoutId ast_id, BailoutId ast_id,
BailoutId return_id, BailoutId return_id,
bool can_inline_accessor = true); bool can_inline_accessor = true);
......
...@@ -1208,9 +1208,9 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, ...@@ -1208,9 +1208,9 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
// Use simple field loads for some well-known callback properties. // Use simple field loads for some well-known callback properties.
if (object->IsJSObject()) { if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object); Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<Map> map(receiver->map()); Handle<HeapType> type = IC::MapToType(handle(receiver->map()));
int object_offset; int object_offset;
if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { if (Accessors::IsJSObjectFieldAccessor(type, name, &object_offset)) {
return SimpleFieldLoad(object_offset / kPointerSize); return SimpleFieldLoad(object_offset / kPointerSize);
} }
} }
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// When calling user-defined accessors on strings, booleans or
// numbers, we should create a wrapper object in classic-mode.
// Flags: --allow-natives-syntax
function test(object, prototype) {
var result;
Object.defineProperty(prototype, "nonstrict", {
get: function() { result = this; },
set: function(v) { result = this; }
});
Object.defineProperty(prototype, "strict", {
get: function() { "use strict"; result = this; },
set: function(v) { "use strict"; result = this; }
});
(function() {
function nonstrict(s) {
return s.nonstrict;
}
function strict(s) {
return s.strict;
}
nonstrict(object);
nonstrict(object);
%OptimizeFunctionOnNextCall(nonstrict);
result = undefined;
nonstrict(object);
assertEquals("object", typeof result);
strict(object);
strict(object);
%OptimizeFunctionOnNextCall(strict);
result = undefined;
strict(object);
assertEquals(typeof object, typeof result);
})();
(function() {
function nonstrict(s) {
return s.nonstrict = 10;
}
function strict(s) {
return s.strict = 10;
}
nonstrict(object);
nonstrict(object);
%OptimizeFunctionOnNextCall(nonstrict);
result = undefined;
nonstrict(object);
// TODO(1475): Support storing to primitive values.
// This should return "object" once storing to primitive values is
// supported.
assertEquals("undefined", typeof result);
strict(object);
strict(object);
%OptimizeFunctionOnNextCall(strict);
result = undefined;
strict(object);
// TODO(1475): Support storing to primitive values.
// This should return "object" once storing to primitive values is
// supported.
assertEquals("undefined", typeof result);
})();
}
test(1, Number.prototype);
test("string", String.prototype);
test(true, Boolean.prototype);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment