Index: src/builtins/builtins-object-gen.cc |
diff --git a/src/builtins/builtins-object-gen.cc b/src/builtins/builtins-object-gen.cc |
index 09930c21b804fff1c204d37441e72433018f1623..f9ba906f2ea1b00bd84bf2af2705d3314a5af501 100644 |
--- a/src/builtins/builtins-object-gen.cc |
+++ b/src/builtins/builtins-object-gen.cc |
@@ -192,6 +192,52 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) { |
} |
} |
+// ES #sec-object.prototype.isprototypeof |
+TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) { |
+ Node* receiver = Parameter(Descriptor::kReceiver); |
+ Node* value = Parameter(Descriptor::kValue); |
+ Node* context = Parameter(Descriptor::kContext); |
+ Label if_receiverisnullorundefined(this, Label::kDeferred), |
+ if_valueisnotreceiver(this, Label::kDeferred); |
+ |
+ // We only check whether {value} is a Smi here, so that the |
+ // prototype chain walk below can safely access the {value}s |
+ // map. We don't rule out Primitive {value}s, since all of |
+ // them have null as their prototype, so the chain walk below |
+ // 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 JSValue |
+ // 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 JSValue 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}. |
+ CallBuiltin(Builtins::kToObject, context, receiver); |
+ Unreachable(); |
+ } |
+ |
+ BIND(&if_valueisnotreceiver); |
+ Return(FalseConstant()); |
+} |
+ |
// ES6 #sec-object.prototype.tostring |
TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) { |
Label return_undefined(this, Label::kDeferred), |