Commit 87199f52 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[es2015] Handle proxies in GetProperty builtin.

Teach the GetProperty builtin how to perform [[Get]] on JSProxy
instances by calling into the dedicated ProxyGetProperty builtin
that we already use for the LOAD_IC / KEYED_LOAD_IC. This is
important when proxies are used in places were GetProperty builtin
is used like for example as iterables in for..of loops or in spreads.

On a simple micro-benchmark like the following

```js
const proxy = new Proxy([1, 2, 3], {
  get(target, property) { return target[property]; }
});
const TESTS = [
    function testForOfProxy() { for (const x of proxy) {} },
    function testSpreadProxy() { return [...proxy]; }
];

function test(fn) {
  var result;
  for (var i = 0; i < 1e6; ++i) result = fn();
  return result;
}
test(x => x);

for (var j = 0; j < TESTS.length; ++j) test(TESTS[j]);
for (var j = 0; j < TESTS.length; ++j) {
  var startTime = Date.now();
  test(TESTS[j]);
  print(TESTS[j].name + ':', (Date.now() - startTime), 'ms.');
}
```

improves from around

  testForOfProxy: 1672.6 ms.
  testSpreadProxy: 1956.6 ms.

to

  testForOfProxy: 408.4 ms.
  testSpreadProxy: 530.8 ms.

on average, which corresponds to a 4-5x performance improvement, even
for small arrays. On the ARES-6 Air benchmark this completely eliminates
all calls to the %GetProperty runtime function, and thereby improves the
steady state mean by 2-3%.

Bug: v8:6344, v8:6557, v8:6559
Change-Id: Ifebdaff8f3ae5899a33ce408ecd54655247f3a02
Reviewed-on: https://chromium-review.googlesource.com/1199023Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55539}
parent 0b0f0623
......@@ -1207,27 +1207,23 @@ void Builtins::Generate_CallApiCallback_Argc1(MacroAssembler* masm) {
// ES6 [[Get]] operation.
TF_BUILTIN(GetProperty, CodeStubAssembler) {
Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_notfound(this), if_proxy(this, Label::kDeferred),
if_slow(this, Label::kDeferred);
CodeStubAssembler::LookupInHolder lookup_property_in_holder =
[=, &var_result, &end](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* unique_name,
Label* next_holder, Label* if_bailout) {
[=](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* unique_name, Label* next_holder,
Label* if_bailout) {
VARIABLE(var_value, MachineRepresentation::kTagged);
Label if_found(this);
TryGetOwnProperty(context, receiver, holder, holder_map,
holder_instance_type, unique_name, &if_found,
&var_value, next_holder, if_bailout);
BIND(&if_found);
{
var_result.Bind(var_value.value());
Goto(&end);
}
Return(var_value.value());
};
CodeStubAssembler::LookupInHolder lookup_element_in_holder =
......@@ -1240,23 +1236,26 @@ TF_BUILTIN(GetProperty, CodeStubAssembler) {
};
TryPrototypeChainLookup(object, key, lookup_property_in_holder,
lookup_element_in_holder, &return_undefined,
&call_runtime);
lookup_element_in_holder, &if_notfound, &if_slow,
&if_proxy);
BIND(&return_undefined);
{
var_result.Bind(UndefinedConstant());
Goto(&end);
}
BIND(&if_notfound);
Return(UndefinedConstant());
BIND(&call_runtime);
BIND(&if_slow);
TailCallRuntime(Runtime::kGetProperty, context, object, key);
BIND(&if_proxy);
{
var_result.Bind(CallRuntime(Runtime::kGetProperty, context, object, key));
Goto(&end);
// Convert the {key} to a Name first.
Node* name = CallBuiltin(Builtins::kToName, context, key);
// The {object} is a JSProxy instance, look up the {name} on it, passing
// {object} both as receiver and holder. If {name} is absent we can safely
// return undefined from here.
TailCallBuiltin(Builtins::kProxyGetProperty, context, object, name, object,
SmiConstant(OnNonExistent::kReturnUndefined));
}
BIND(&end);
Return(var_result.value());
}
// ES6 [[Set]] operation.
......
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