Commit e53f7d73 authored by ishell's avatar ishell Committed by Commit bot

[stubs] GetPropertyStub added.

Currently only property queries are supported.
This CL also factores out prototype chain iteration logic.

GetPropertyStub is not used yet.

BUG=v8:4911
LOG=Y

Review-Url: https://codereview.chromium.org/2087863002
Cr-Commit-Position: refs/heads/master@{#37455}
parent f20d6788
......@@ -1502,6 +1502,10 @@ void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) {
}
}
void CodeStubAssembler::Use(Label* label) {
GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label);
}
void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Variable* var_index, Label* if_keyisunique,
Label* if_bailout) {
......@@ -2175,6 +2179,114 @@ template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>(
template void CodeStubAssembler::NumberDictionaryLookup<
UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*);
void CodeStubAssembler::TryPrototypeChainLookup(
Node* receiver, Node* key, LookupInHolder& lookup_property_in_holder,
LookupInHolder& lookup_element_in_holder, Label* if_end,
Label* if_bailout) {
// Ensure receiver is JSReceiver, otherwise bailout.
Label if_objectisnotsmi(this);
Branch(WordIsSmi(receiver), if_bailout, &if_objectisnotsmi);
Bind(&if_objectisnotsmi);
Node* map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(map);
{
Label if_objectisreceiver(this);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
Branch(Int32GreaterThanOrEqual(instance_type,
Int32Constant(FIRST_JS_RECEIVER_TYPE)),
&if_objectisreceiver, if_bailout);
Bind(&if_objectisreceiver);
}
Variable var_index(this, MachineRepresentation::kWord32);
Label if_keyisindex(this), if_iskeyunique(this);
TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout);
Bind(&if_iskeyunique);
{
Variable var_holder(this, MachineRepresentation::kTagged);
Variable var_holder_map(this, MachineRepresentation::kTagged);
Variable var_holder_instance_type(this, MachineRepresentation::kWord8);
Variable* merged_variables[] = {&var_holder, &var_holder_map,
&var_holder_instance_type};
Label loop(this, arraysize(merged_variables), merged_variables);
var_holder.Bind(receiver);
var_holder_map.Bind(map);
var_holder_instance_type.Bind(instance_type);
Goto(&loop);
Bind(&loop);
{
Node* holder_map = var_holder_map.value();
Node* holder_instance_type = var_holder_instance_type.value();
Label next_proto(this);
lookup_property_in_holder(receiver, var_holder.value(), holder_map,
holder_instance_type, key, &next_proto,
if_bailout);
Bind(&next_proto);
// Bailout if it can be an integer indexed exotic case.
GotoIf(
Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
if_bailout);
Node* proto = LoadMapPrototype(holder_map);
Label if_not_null(this);
Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
Bind(&if_not_null);
Node* map = LoadMap(proto);
Node* instance_type = LoadMapInstanceType(map);
var_holder.Bind(proto);
var_holder_map.Bind(map);
var_holder_instance_type.Bind(instance_type);
Goto(&loop);
}
}
Bind(&if_keyisindex);
{
Variable var_holder(this, MachineRepresentation::kTagged);
Variable var_holder_map(this, MachineRepresentation::kTagged);
Variable var_holder_instance_type(this, MachineRepresentation::kWord8);
Variable* merged_variables[] = {&var_holder, &var_holder_map,
&var_holder_instance_type};
Label loop(this, arraysize(merged_variables), merged_variables);
var_holder.Bind(receiver);
var_holder_map.Bind(map);
var_holder_instance_type.Bind(instance_type);
Goto(&loop);
Bind(&loop);
{
Label next_proto(this);
lookup_element_in_holder(receiver, var_holder.value(),
var_holder_map.value(),
var_holder_instance_type.value(),
var_index.value(), &next_proto, if_bailout);
Bind(&next_proto);
Node* proto = LoadMapPrototype(var_holder_map.value());
Label if_not_null(this);
Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
Bind(&if_not_null);
Node* map = LoadMap(proto);
Node* instance_type = LoadMapInstanceType(map);
var_holder.Bind(proto);
var_holder_map.Bind(map);
var_holder_instance_type.Bind(instance_type);
Goto(&loop);
}
}
}
Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
Node* object) {
Variable var_result(this, MachineRepresentation::kTagged);
......
......@@ -5,6 +5,8 @@
#ifndef V8_CODE_STUB_ASSEMBLER_H_
#define V8_CODE_STUB_ASSEMBLER_H_
#include <functional>
#include "src/compiler/code-assembler.h"
#include "src/objects.h"
......@@ -270,6 +272,11 @@ class CodeStubAssembler : public compiler::CodeAssembler {
void IncrementCounter(StatsCounter* counter, int delta);
void DecrementCounter(StatsCounter* counter, int delta);
// Generates "if (false) goto label" code. Useful for marking a label as
// "live" to avoid assertion failures during graph building. In the resulting
// code this check will be eliminated.
void Use(Label* label);
// Various building blocks for stubs doing property lookups.
void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index,
Label* if_keyisunique, Label* if_bailout);
......@@ -356,6 +363,26 @@ class CodeStubAssembler : public compiler::CodeAssembler {
Label* if_found, Label* if_not_found,
Label* if_bailout);
// This is a type of a lookup in holder generator function. In case of a
// property lookup the {key} is guaranteed to be a unique name and in case of
// element lookup the key is an Int32 index.
typedef std::function<void(compiler::Node* receiver, compiler::Node* holder,
compiler::Node* map, compiler::Node* instance_type,
compiler::Node* key, Label* next_holder,
Label* if_bailout)>
LookupInHolder;
// Generic property prototype chain lookup generator.
// For properties it generates lookup using given {lookup_property_in_holder}
// and for elements it uses {lookup_element_in_holder}.
// Upon reaching the end of prototype chain the control goes to {if_end}.
// If it can't handle the case {receiver}/{key} case then the control goes
// to {if_bailout}.
void TryPrototypeChainLookup(compiler::Node* receiver, compiler::Node* key,
LookupInHolder& lookup_property_in_holder,
LookupInHolder& lookup_element_in_holder,
Label* if_end, Label* if_bailout);
// Instanceof helpers.
// ES6 section 7.3.19 OrdinaryHasInstance (C, O)
compiler::Node* OrdinaryHasInstance(compiler::Node* context,
......
......@@ -4300,102 +4300,27 @@ compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler,
Label call_runtime(assembler, Label::kDeferred), return_true(assembler),
return_false(assembler), end(assembler);
// Ensure object is JSReceiver, otherwise call runtime to throw error.
Label if_objectisnotsmi(assembler);
assembler->Branch(assembler->WordIsSmi(object), &call_runtime,
&if_objectisnotsmi);
assembler->Bind(&if_objectisnotsmi);
Node* map = assembler->LoadMap(object);
Node* instance_type = assembler->LoadMapInstanceType(map);
{
Label if_objectisreceiver(assembler);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
assembler->Branch(
assembler->Int32GreaterThanOrEqual(
instance_type, assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE)),
&if_objectisreceiver, &call_runtime);
assembler->Bind(&if_objectisreceiver);
}
Variable var_index(assembler, MachineRepresentation::kWord32);
Label keyisindex(assembler), if_iskeyunique(assembler);
assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique,
&call_runtime);
assembler->Bind(&if_iskeyunique);
{
Variable var_object(assembler, MachineRepresentation::kTagged);
Variable var_map(assembler, MachineRepresentation::kTagged);
Variable var_instance_type(assembler, MachineRepresentation::kWord8);
Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
Label loop(assembler, arraysize(merged_variables), merged_variables);
var_object.Bind(object);
var_map.Bind(map);
var_instance_type.Bind(instance_type);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
Label next_proto(assembler);
assembler->TryHasOwnProperty(var_object.value(), var_map.value(),
var_instance_type.value(), key, &return_true,
&next_proto, &call_runtime);
assembler->Bind(&next_proto);
Node* proto = assembler->LoadMapPrototype(var_map.value());
Label if_not_null(assembler);
assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
&return_false, &if_not_null);
assembler->Bind(&if_not_null);
Node* map = assembler->LoadMap(proto);
Node* instance_type = assembler->LoadMapInstanceType(map);
var_object.Bind(proto);
var_map.Bind(map);
var_instance_type.Bind(instance_type);
assembler->Goto(&loop);
}
}
assembler->Bind(&keyisindex);
{
Variable var_object(assembler, MachineRepresentation::kTagged);
Variable var_map(assembler, MachineRepresentation::kTagged);
Variable var_instance_type(assembler, MachineRepresentation::kWord8);
Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
Label loop(assembler, arraysize(merged_variables), merged_variables);
var_object.Bind(object);
var_map.Bind(map);
var_instance_type.Bind(instance_type);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
Label next_proto(assembler);
assembler->TryLookupElement(var_object.value(), var_map.value(),
var_instance_type.value(), var_index.value(),
&return_true, &next_proto, &call_runtime);
assembler->Bind(&next_proto);
Node* proto = assembler->LoadMapPrototype(var_map.value());
Label if_not_null(assembler);
assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
&return_false, &if_not_null);
assembler->Bind(&if_not_null);
Node* map = assembler->LoadMap(proto);
Node* instance_type = assembler->LoadMapInstanceType(map);
var_object.Bind(proto);
var_map.Bind(map);
var_instance_type.Bind(instance_type);
assembler->Goto(&loop);
}
}
CodeStubAssembler::LookupInHolder lookup_property_in_holder =
[assembler, &return_true](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* unique_name,
Label* next_holder, Label* if_bailout) {
assembler->TryHasOwnProperty(holder, holder_map, holder_instance_type,
unique_name, &return_true, next_holder,
if_bailout);
};
CodeStubAssembler::LookupInHolder lookup_element_in_holder =
[assembler, &return_true](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* index,
Label* next_holder, Label* if_bailout) {
assembler->TryLookupElement(holder, holder_map, holder_instance_type,
index, &return_true, next_holder,
if_bailout);
};
assembler->TryPrototypeChainLookup(object, key, lookup_property_in_holder,
lookup_element_in_holder, &return_false,
&call_runtime);
Variable result(assembler, MachineRepresentation::kTagged);
assembler->Bind(&return_true);
......@@ -4421,6 +4346,67 @@ compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler,
return result.value();
}
void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
Label call_runtime(assembler, Label::kDeferred), return_undefined(assembler),
end(assembler);
Node* object = assembler->Parameter(0);
Node* key = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Variable var_result(assembler, MachineRepresentation::kTagged);
CodeStubAssembler::LookupInHolder lookup_property_in_holder =
[assembler, context, &var_result, &end](
Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* unique_name, Label* next_holder,
Label* if_bailout) {
Variable var_value(assembler, MachineRepresentation::kTagged);
Label if_found(assembler);
assembler->TryGetOwnProperty(
context, receiver, holder, holder_map, holder_instance_type,
unique_name, &if_found, &var_value, next_holder, if_bailout);
assembler->Bind(&if_found);
{
var_result.Bind(var_value.value());
assembler->Goto(&end);
}
};
CodeStubAssembler::LookupInHolder lookup_element_in_holder =
[assembler, context, &var_result, &end](
Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* index, Label* next_holder,
Label* if_bailout) {
// Not supported yet.
assembler->Use(next_holder);
assembler->Goto(if_bailout);
};
assembler->TryPrototypeChainLookup(object, key, lookup_property_in_holder,
lookup_element_in_holder,
&return_undefined, &call_runtime);
assembler->Bind(&return_undefined);
{
var_result.Bind(assembler->UndefinedConstant());
assembler->Goto(&end);
}
assembler->Bind(&call_runtime);
{
var_result.Bind(
assembler->CallRuntime(Runtime::kGetProperty, context, object, key));
assembler->Goto(&end);
}
assembler->Bind(&end);
assembler->Return(var_result.value());
}
// static
compiler::Node* FastNewClosureStub::Generate(CodeStubAssembler* assembler,
compiler::Node* shared_info,
......
......@@ -137,6 +137,7 @@ namespace internal {
V(ToInteger) \
V(ToLength) \
V(HasProperty) \
V(GetProperty) \
V(LoadICTrampolineTF) \
V(LoadICTF) \
/* IC Handler stubs */ \
......@@ -990,6 +991,15 @@ class HasPropertyStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_BINARY_OP_CODE_STUB(HasProperty, TurboFanCodeStub);
};
// ES6 [[Get]] operation.
class GetPropertyStub : public TurboFanCodeStub {
public:
explicit GetPropertyStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(GetProperty);
DEFINE_TURBOFAN_CODE_STUB(GetProperty, TurboFanCodeStub);
};
enum StringAddFlags {
// Omit both parameter checks.
STRING_ADD_CHECK_NONE = 0,
......
......@@ -78,6 +78,7 @@ class PlatformInterfaceDescriptor;
V(Keyed) \
V(Named) \
V(HasProperty) \
V(GetProperty) \
V(CallHandler) \
V(ArgumentAdaptor) \
V(ApiCallbackWith0Args) \
......@@ -544,6 +545,13 @@ class HasPropertyDescriptor final : public CallInterfaceDescriptor {
DECLARE_DEFAULT_DESCRIPTOR(HasPropertyDescriptor, CallInterfaceDescriptor, 2)
};
class GetPropertyDescriptor final : public CallInterfaceDescriptor {
public:
enum ParameterIndices { kObjectIndex, kKeyIndex };
DECLARE_DEFAULT_DESCRIPTOR(GetPropertyDescriptor, CallInterfaceDescriptor, 2)
};
class TypeofDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(TypeofDescriptor, CallInterfaceDescriptor)
......
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