Commit 3de87fd9 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[CSA][cleanup] TNodify builtin-functions-gen and OrdinaryHasInstance.

 - HasInPrototypeChain
 - OrdinaryHasInstance
 - ObjectPrototypeIsPrototype
 - ObjectHasInstance

BUG=v8:6949, v8:9396

Change-Id: I85b21f1e74aa869f212dc788a1dbe76c50a0d96e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1803342
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Auto-Submit: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63761}
parent 4d97099c
......@@ -17,8 +17,8 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
TNode<Int32T> argc =
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
Node* context = Parameter(Descriptor::kContext);
Node* new_target = Parameter(Descriptor::kJSNewTarget);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
CodeStubArguments args(this, argc);
......@@ -83,7 +83,7 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// Choose the right bound function map based on whether the target is
// constructable.
Comment("Choose the right bound function map");
VARIABLE(bound_function_map, MachineRepresentation::kTagged);
TVARIABLE(Map, bound_function_map);
{
Label with_constructor(this);
VariableList vars({&bound_function_map}, zone());
......@@ -92,12 +92,12 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
Label map_done(this, vars);
GotoIf(IsConstructorMap(receiver_map), &with_constructor);
bound_function_map.Bind(LoadContextElement(
bound_function_map = CAST(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
BIND(&with_constructor);
bound_function_map.Bind(LoadContextElement(
bound_function_map = CAST(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
......@@ -113,29 +113,28 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// Allocate the arguments array.
Comment("Allocate the arguments array");
VARIABLE(argument_array, MachineRepresentation::kTagged);
TVARIABLE(FixedArray, argument_array);
{
Label empty_arguments(this);
Label arguments_done(this, &argument_array);
GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
TNode<IntPtrT> elements_length =
Signed(ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1)))));
TNode<FixedArray> elements = CAST(AllocateFixedArray(
PACKED_ELEMENTS, elements_length, kAllowLargeObjectAllocation));
argument_array = CAST(AllocateFixedArray(PACKED_ELEMENTS, elements_length,
kAllowLargeObjectAllocation));
TVARIABLE(IntPtrT, index, IntPtrConstant(0));
VariableList foreach_vars({&index}, zone());
args.ForEach(
foreach_vars,
[&](TNode<Object> arg) {
StoreFixedArrayElement(elements, index.value(), arg);
StoreFixedArrayElement(argument_array.value(), index.value(), arg);
Increment(&index);
},
IntPtrConstant(1));
argument_array.Bind(elements);
Goto(&arguments_done);
BIND(&empty_arguments);
argument_array.Bind(EmptyFixedArrayConstant());
argument_array = EmptyFixedArrayConstant();
Goto(&arguments_done);
BIND(&arguments_done);
......@@ -143,16 +142,16 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// Determine bound receiver.
Comment("Determine bound receiver");
VARIABLE(bound_receiver, MachineRepresentation::kTagged);
TVARIABLE(Object, bound_receiver);
{
Label has_receiver(this);
Label receiver_done(this, &bound_receiver);
GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
bound_receiver.Bind(UndefinedConstant());
bound_receiver = UndefinedConstant();
Goto(&receiver_done);
BIND(&has_receiver);
bound_receiver.Bind(args.AtIndex(0));
bound_receiver = args.AtIndex(0);
Goto(&receiver_done);
BIND(&receiver_done);
......@@ -193,10 +192,10 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// ES6 #sec-function.prototype-@@hasinstance
TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* f = Parameter(Descriptor::kReceiver);
Node* v = Parameter(Descriptor::kV);
Node* result = OrdinaryHasInstance(context, f, v);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> f = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> v = CAST(Parameter(Descriptor::kV));
TNode<Oddball> result = OrdinaryHasInstance(context, f, v);
Return(result);
}
......
......@@ -669,9 +669,9 @@ TF_BUILTIN(ObjectEntries, ObjectEntriesValuesBuiltinsAssembler) {
// ES #sec-object.prototype.isprototypeof
TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Label if_receiverisnullorundefined(this, Label::kDeferred),
if_valueisnotreceiver(this, Label::kDeferred);
......@@ -682,31 +682,35 @@ TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
// immediately aborts and returns false anyways.
GotoIf(TaggedIsSmi(value), &if_valueisnotreceiver);
// Check if {receiver} is either null or undefined and in that case,
// invoke the ToObject builtin, which raises the appropriate error.
// Otherwise we don't need to invoke ToObject, since {receiver} is
// either already a JSReceiver, in which case ToObject is a no-op,
// or it's a Primitive and ToObject would allocate a fresh JSPrimitiveWrapper
// wrapper, which wouldn't be identical to any existing JSReceiver
// found in the prototype chain of {value}, hence it will return
// false no matter if we search for the Primitive {receiver} or
// a newly allocated JSPrimitiveWrapper wrapper for {receiver}.
GotoIf(IsNull(receiver), &if_receiverisnullorundefined);
GotoIf(IsUndefined(receiver), &if_receiverisnullorundefined);
// Loop through the prototype chain looking for the {receiver}.
Return(HasInPrototypeChain(context, value, receiver));
BIND(&if_receiverisnullorundefined);
{
// If {value} is a primitive HeapObject, we need to return
// false instead of throwing an exception per order of the
// steps in the specification, so check that first here.
GotoIfNot(IsJSReceiver(value), &if_valueisnotreceiver);
// Simulate the ToObject invocation on {receiver}.
ToObject(context, receiver);
Unreachable();
TNode<HeapObject> value_heap_object = CAST(value);
// Check if {receiver} is either null or undefined and in that case,
// invoke the ToObject builtin, which raises the appropriate error.
// Otherwise we don't need to invoke ToObject, since {receiver} is
// either already a JSReceiver, in which case ToObject is a no-op,
// or it's a Primitive and ToObject would allocate a fresh
// JSPrimitiveWrapper wrapper, which wouldn't be identical to any existing
// JSReceiver found in the prototype chain of {value}, hence it will return
// false no matter if we search for the Primitive {receiver} or
// a newly allocated JSPrimitiveWrapper wrapper for {receiver}.
GotoIf(IsNull(receiver), &if_receiverisnullorundefined);
GotoIf(IsUndefined(receiver), &if_receiverisnullorundefined);
// Loop through the prototype chain looking for the {receiver}.
Return(HasInPrototypeChain(context, value_heap_object, receiver));
BIND(&if_receiverisnullorundefined);
{
// If {value} is a primitive HeapObject, we need to return
// false instead of throwing an exception per order of the
// steps in the specification, so check that first here.
GotoIfNot(IsJSReceiver(value_heap_object), &if_valueisnotreceiver);
// Simulate the ToObject invocation on {receiver}.
ToObject(context, receiver);
Unreachable();
}
}
BIND(&if_valueisnotreceiver);
......@@ -1252,9 +1256,9 @@ TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
// ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
Node* constructor = Parameter(Descriptor::kLeft);
Node* object = Parameter(Descriptor::kRight);
Node* context = Parameter(Descriptor::kContext);
TNode<Object> constructor = CAST(Parameter(Descriptor::kLeft));
TNode<Object> object = CAST(Parameter(Descriptor::kRight));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Return(OrdinaryHasInstance(context, constructor, object));
}
......
......@@ -10082,22 +10082,22 @@ void CodeStubAssembler::TryPrototypeChainLookup(
}
}
Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
SloppyTNode<Object> prototype) {
CSA_ASSERT(this, TaggedIsNotSmi(object));
VARIABLE(var_result, MachineRepresentation::kTagged);
TNode<Oddball> CodeStubAssembler::HasInPrototypeChain(TNode<Context> context,
TNode<HeapObject> object,
TNode<Object> prototype) {
TVARIABLE(Oddball, var_result);
Label return_false(this), return_true(this),
return_runtime(this, Label::kDeferred), return_result(this);
// Loop through the prototype chain looking for the {prototype}.
VARIABLE(var_object_map, MachineRepresentation::kTagged, LoadMap(object));
TVARIABLE(Map, var_object_map, LoadMap(object));
Label loop(this, &var_object_map);
Goto(&loop);
BIND(&loop);
{
// Check if we can determine the prototype directly from the {object_map}.
Label if_objectisdirect(this), if_objectisspecial(this, Label::kDeferred);
Node* object_map = var_object_map.value();
TNode<Map> object_map = var_object_map.value();
TNode<Uint16T> object_instance_type = LoadMapInstanceType(object_map);
Branch(IsSpecialReceiverInstanceType(object_instance_type),
&if_objectisspecial, &if_objectisdirect);
......@@ -10122,22 +10122,22 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
// Continue with the prototype.
CSA_ASSERT(this, TaggedIsNotSmi(object_prototype));
var_object_map.Bind(LoadMap(object_prototype));
var_object_map = LoadMap(object_prototype);
Goto(&loop);
}
BIND(&return_true);
var_result.Bind(TrueConstant());
var_result = TrueConstant();
Goto(&return_result);
BIND(&return_false);
var_result.Bind(FalseConstant());
var_result = FalseConstant();
Goto(&return_result);
BIND(&return_runtime);
{
// Fallback to the runtime implementation.
var_result.Bind(
var_result = CAST(
CallRuntime(Runtime::kHasInPrototypeChain, context, object, prototype));
}
Goto(&return_result);
......@@ -10146,63 +10146,67 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
return var_result.value();
}
Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
Node* object) {
VARIABLE(var_result, MachineRepresentation::kTagged);
TNode<Oddball> CodeStubAssembler::OrdinaryHasInstance(
TNode<Context> context, TNode<Object> callable_maybe_smi,
TNode<Object> object_maybe_smi) {
TVARIABLE(Oddball, var_result);
Label return_runtime(this, Label::kDeferred), return_result(this);
GotoIfForceSlowPath(&return_runtime);
// Goto runtime if {object} is a Smi.
GotoIf(TaggedIsSmi(object), &return_runtime);
GotoIf(TaggedIsSmi(object_maybe_smi), &return_runtime);
// Goto runtime if {callable} is a Smi.
GotoIf(TaggedIsSmi(callable), &return_runtime);
// Load map of {callable}.
TNode<Map> callable_map = LoadMap(callable);
// Goto runtime if {callable} is not a JSFunction.
TNode<Uint16T> callable_instance_type = LoadMapInstanceType(callable_map);
GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE),
&return_runtime);
GotoIf(TaggedIsSmi(callable_maybe_smi), &return_runtime);
GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), callable_map,
&return_runtime);
// Get the "prototype" (or initial map) of the {callable}.
TNode<HeapObject> callable_prototype = LoadObjectField<HeapObject>(
CAST(callable), JSFunction::kPrototypeOrInitialMapOffset);
{
Label no_initial_map(this), walk_prototype_chain(this);
TVARIABLE(HeapObject, var_callable_prototype, callable_prototype);
// Load map of {callable}.
TNode<HeapObject> object = CAST(object_maybe_smi);
TNode<HeapObject> callable = CAST(callable_maybe_smi);
TNode<Map> callable_map = LoadMap(callable);
// Resolve the "prototype" if the {callable} has an initial map.
GotoIfNot(IsMap(callable_prototype), &no_initial_map);
var_callable_prototype =
LoadObjectField<HeapObject>(callable_prototype, Map::kPrototypeOffset);
Goto(&walk_prototype_chain);
// Goto runtime if {callable} is not a JSFunction.
TNode<Uint16T> callable_instance_type = LoadMapInstanceType(callable_map);
GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE),
&return_runtime);
BIND(&no_initial_map);
// {callable_prototype} is the hole if the "prototype" property hasn't been
// requested so far.
Branch(TaggedEqual(callable_prototype, TheHoleConstant()), &return_runtime,
&walk_prototype_chain);
GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), callable_map,
&return_runtime);
BIND(&walk_prototype_chain);
callable_prototype = var_callable_prototype.value();
}
// Get the "prototype" (or initial map) of the {callable}.
TNode<HeapObject> callable_prototype = LoadObjectField<HeapObject>(
callable, JSFunction::kPrototypeOrInitialMapOffset);
{
Label no_initial_map(this), walk_prototype_chain(this);
TVARIABLE(HeapObject, var_callable_prototype, callable_prototype);
// Resolve the "prototype" if the {callable} has an initial map.
GotoIfNot(IsMap(callable_prototype), &no_initial_map);
var_callable_prototype = LoadObjectField<HeapObject>(
callable_prototype, Map::kPrototypeOffset);
Goto(&walk_prototype_chain);
BIND(&no_initial_map);
// {callable_prototype} is the hole if the "prototype" property hasn't
// been requested so far.
Branch(TaggedEqual(callable_prototype, TheHoleConstant()),
&return_runtime, &walk_prototype_chain);
BIND(&walk_prototype_chain);
callable_prototype = var_callable_prototype.value();
}
// Loop through the prototype chain looking for the {callable} prototype.
CSA_ASSERT(this, IsJSReceiver(callable_prototype));
var_result.Bind(HasInPrototypeChain(context, object, callable_prototype));
Goto(&return_result);
// Loop through the prototype chain looking for the {callable} prototype.
var_result = HasInPrototypeChain(context, object, callable_prototype);
Goto(&return_result);
}
BIND(&return_runtime);
{
// Fallback to the runtime implementation.
var_result.Bind(
CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object));
var_result = CAST(CallRuntime(Runtime::kOrdinaryHasInstance, context,
callable_maybe_smi, object_maybe_smi));
}
Goto(&return_result);
......
......@@ -3196,10 +3196,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Returns true if {object} has {prototype} somewhere in it's prototype
// chain, otherwise false is returned. Might cause arbitrary side effects
// due to [[GetPrototypeOf]] invocations.
Node* HasInPrototypeChain(Node* context, Node* object,
SloppyTNode<Object> prototype);
TNode<Oddball> HasInPrototypeChain(TNode<Context> context,
TNode<HeapObject> object,
TNode<Object> prototype);
// ES6 section 7.3.19 OrdinaryHasInstance (C, O)
Node* OrdinaryHasInstance(Node* context, Node* callable, Node* object);
TNode<Oddball> OrdinaryHasInstance(TNode<Context> context,
TNode<Object> callable,
TNode<Object> object);
// Load type feedback vector from the stub caller's frame.
TNode<FeedbackVector> LoadFeedbackVectorForStub();
......
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