Commit 8954ea1b authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add support for loading missing properties.

Return undefined for missing properties (or throw an exception in strong
mode). Also do a bit of code cleanup.

R=jarin@chromium.org
BUG=v8:4470
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31700}
parent c4243fcc
......@@ -303,7 +303,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandleList const& receiver_maps,
Handle<Name> name, PropertyAccessMode access_mode) {
Handle<Name> name, PropertyAccessMode access_mode,
LanguageMode language_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed);
Node* receiver = NodeProperties::GetValueInput(node, 0);
......@@ -399,7 +400,17 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
}
// Generate the actual property access.
if (access_info.IsDataConstant()) {
if (access_info.IsNotFound()) {
DCHECK_EQ(PropertyAccessMode::kLoad, access_mode);
if (is_strong(language_mode)) {
// TODO(bmeurer/mstarzinger): Add support for lowering inside try
// blocks rewiring the IfException edge to a runtime call/throw.
exit_controls.push_back(this_control);
continue;
} else {
this_value = jsgraph()->UndefinedConstant();
}
} else if (access_info.IsDataConstant()) {
this_value = jsgraph()->Constant(access_info.constant());
if (access_mode == PropertyAccessMode::kStore) {
Node* check = graph()->NewNode(
......@@ -586,7 +597,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the final merge point for all (polymorphic) branches.
int const control_count = static_cast<int>(controls.size());
if (control_count == 1) {
if (control_count == 0) {
value = effect = control = jsgraph()->Dead();
} else if (control_count == 1) {
value = values.front();
effect = effects.front();
control = controls.front();
......@@ -618,7 +631,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccess(node, value, receiver_maps, p.name(),
PropertyAccessMode::kLoad);
PropertyAccessMode::kLoad, p.language_mode());
}
......@@ -636,7 +649,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccess(node, value, receiver_maps, p.name(),
PropertyAccessMode::kStore);
PropertyAccessMode::kStore, p.language_mode());
}
......
......@@ -64,8 +64,8 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Reduction ReduceNamedAccess(Node* node, Node* value,
MapHandleList const& receiver_maps,
Handle<Name> name,
PropertyAccessMode access_mode);
Handle<Name> name, PropertyAccessMode access_mode,
LanguageMode language_mode);
struct ScriptContextTableLookupResult;
bool LookupInScriptContextTable(Handle<Name> name,
......
......@@ -28,10 +28,42 @@ std::ostream& operator<<(std::ostream& os, PropertyAccessMode access_mode) {
}
// static
PropertyAccessInfo PropertyAccessInfo::NotFound(Type* receiver_type,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(holder, receiver_type);
}
// static
PropertyAccessInfo PropertyAccessInfo::DataConstant(
Type* receiver_type, Handle<Object> constant,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(holder, constant, receiver_type);
}
// static
PropertyAccessInfo PropertyAccessInfo::DataField(
Type* receiver_type, FieldIndex field_index, Type* field_type,
MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) {
return PropertyAccessInfo(holder, transition_map, field_index, field_type,
receiver_type);
}
PropertyAccessInfo::PropertyAccessInfo()
: kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {}
PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
Type* receiver_type)
: kind_(kNotFound),
receiver_type_(receiver_type),
holder_(holder),
field_type_(Type::Any()) {}
PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
Handle<Object> constant,
Type* receiver_type)
......@@ -95,7 +127,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
}
MaybeHandle<JSObject> holder;
while (true) {
do {
// Lookup the named property on the {map}.
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
int const number = descriptors->SearchWithCache(*name, *map);
......@@ -187,8 +219,12 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
if (access_mode == PropertyAccessMode::kStore) {
return LookupTransition(receiver_map, name, holder, access_info);
}
// TODO(bmeurer): Handle the not found case if the prototype is null.
return false;
// The property was not found, return undefined or throw depending
// on the language mode of the load operation.
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
*access_info = PropertyAccessInfo::NotFound(
Type::Class(receiver_map, zone()), holder);
return true;
} else {
return false;
}
......@@ -201,11 +237,25 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
}
map = handle(map_prototype->map(), isolate());
holder = map_prototype;
} while (CanInlinePropertyAccess(map));
return false;
}
// Check if it is safe to inline property access for the {map}.
if (!CanInlinePropertyAccess(map)) return false;
bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name,
PropertyAccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) {
for (Handle<Map> map : maps) {
if (Map::TryUpdate(map).ToHandle(&map)) {
PropertyAccessInfo access_info;
if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
return false;
}
access_infos->push_back(access_info);
}
}
return false;
return true;
}
......@@ -299,23 +349,6 @@ bool PropertyAccessInfoFactory::LookupTransition(
}
bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name,
PropertyAccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) {
for (Handle<Map> map : maps) {
if (Map::TryUpdate(map).ToHandle(&map)) {
PropertyAccessInfo access_info;
if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
return false;
}
access_infos->push_back(access_info);
}
}
return true;
}
Factory* PropertyAccessInfoFactory::factory() const {
return isolate()->factory();
}
......
......@@ -32,26 +32,26 @@ std::ostream& operator<<(std::ostream&, PropertyAccessMode);
// object property, either on the object itself or on the prototype chain.
class PropertyAccessInfo final {
public:
enum Kind { kInvalid, kDataConstant, kDataField };
enum Kind { kInvalid, kNotFound, kDataConstant, kDataField };
static PropertyAccessInfo NotFound(Type* receiver_type,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo DataConstant(Type* receiver_type,
Handle<Object> constant,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(holder, constant, receiver_type);
}
MaybeHandle<JSObject> holder);
static PropertyAccessInfo DataField(
Type* receiver_type, FieldIndex field_index, Type* field_type,
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
MaybeHandle<Map> transition_map = MaybeHandle<Map>()) {
return PropertyAccessInfo(holder, transition_map, field_index, field_type,
receiver_type);
}
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
PropertyAccessInfo();
bool IsNotFound() const { return kind() == kNotFound; }
bool IsDataConstant() const { return kind() == kDataConstant; }
bool IsDataField() const { return kind() == kDataField; }
bool HasTransitionMap() const { return !transition_map().is_null(); }
Kind kind() const { return kind_; }
MaybeHandle<JSObject> holder() const { return holder_; }
MaybeHandle<Map> transition_map() const { return transition_map_; }
......@@ -60,9 +60,8 @@ class PropertyAccessInfo final {
Type* field_type() const { return field_type_; }
Type* receiver_type() const { return receiver_type_; }
bool HasTransitionMap() const { return !transition_map().is_null(); }
private:
PropertyAccessInfo(MaybeHandle<JSObject> holder, Type* receiver_type);
PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
Type* receiver_type);
PropertyAccessInfo(MaybeHandle<JSObject> holder,
......
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