From 87eef73234e7e801b41e5a52a8ebc66f2c3bc602 Mon Sep 17 00:00:00 2001 From: verwaest Date: Mon, 30 Mar 2015 04:50:04 -0700 Subject: [PATCH] Fix speedup of typedarray-length loading in the ICs as well as Crankshaft BUG= Review URL: https://codereview.chromium.org/1034393002 Cr-Commit-Position: refs/heads/master@{#27519} --- src/accessors.cc | 8 ++ src/ic/ic.cc | 17 ++-- src/typedarray.js | 9 +- src/v8natives.js | 7 +- test/mjsunit/regress/regress-typedarray-length.js | 112 ++++++++++++++++++++++ 5 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 test/mjsunit/regress/regress-typedarray-length.js diff --git a/src/accessors.cc b/src/accessors.cc index f774c6d..fd770ea 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -79,6 +79,14 @@ bool Accessors::IsJSObjectFieldAccessor(Handle map, Handle name, CheckForName(name, isolate->factory()->length_string(), JSArray::kLengthOffset, object_offset); case JS_TYPED_ARRAY_TYPE: + // %TypedArray%.prototype is non-configurable, and so are the following + // named properties on %TypedArray%.prototype, so we can directly inline + // the field-load for typed array maps that still use their + // %TypedArray%.prototype. + if (JSFunction::cast(map->GetConstructor())->prototype() != + map->prototype()) { + return false; + } return CheckForName(name, isolate->factory()->length_string(), JSTypedArray::kLengthOffset, object_offset) || diff --git a/src/ic/ic.cc b/src/ic/ic.cc index 0ba80d3..e250a7f 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1219,16 +1219,13 @@ Handle LoadIC::CompileHandler(LookupIterator* lookup, case LookupIterator::ACCESSOR: { // Use simple field loads for some well-known callback properties. - if (receiver_is_holder) { - DCHECK(receiver->IsJSObject()); - Handle js_receiver = Handle::cast(receiver); - int object_offset; - if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), - &object_offset)) { - FieldIndex index = - FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); - return SimpleFieldLoad(index); - } + // The method will only return true for absolute truths based on the + // receiver maps. + int object_offset; + if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), + &object_offset)) { + FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); + return SimpleFieldLoad(index); } Handle accessors = lookup->GetAccessors(); diff --git a/src/typedarray.js b/src/typedarray.js index caa428c..ac7e6c8 100644 --- a/src/typedarray.js +++ b/src/typedarray.js @@ -314,9 +314,12 @@ macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE) "BYTES_PER_ELEMENT", ELEMENT_SIZE, READ_ONLY | DONT_ENUM | DONT_DELETE); InstallGetter(global.NAME.prototype, "buffer", NAME_GetBuffer); - InstallGetter(global.NAME.prototype, "byteOffset", NAME_GetByteOffset); - InstallGetter(global.NAME.prototype, "byteLength", NAME_GetByteLength); - InstallGetter(global.NAME.prototype, "length", NAME_GetLength); + InstallGetter(global.NAME.prototype, "byteOffset", NAME_GetByteOffset, + DONT_ENUM | DONT_DELETE); + InstallGetter(global.NAME.prototype, "byteLength", NAME_GetByteLength, + DONT_ENUM | DONT_DELETE); + InstallGetter(global.NAME.prototype, "length", NAME_GetLength, + DONT_ENUM | DONT_DELETE); InstallGetter(global.NAME.prototype, symbolToStringTag, TypedArrayGetToStringTag); InstallFunctions(global.NAME.prototype, DONT_ENUM, $Array( diff --git a/src/v8natives.js b/src/v8natives.js index 1ea3f41..cbd8e14 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -44,10 +44,13 @@ function OverrideFunction(object, name, f) { // Helper function to install a getter-only accessor property. -function InstallGetter(object, name, getter) { +function InstallGetter(object, name, getter, attributes) { + if (typeof attributes == "undefined") { + attributes = DONT_ENUM; + } %FunctionSetName(getter, name); %FunctionRemovePrototype(getter); - %DefineAccessorPropertyUnchecked(object, name, getter, null, DONT_ENUM); + %DefineAccessorPropertyUnchecked(object, name, getter, null, attributes); %SetNativeFlag(getter); } diff --git a/test/mjsunit/regress/regress-typedarray-length.js b/test/mjsunit/regress/regress-typedarray-length.js new file mode 100644 index 0000000..cae5573 --- /dev/null +++ b/test/mjsunit/regress/regress-typedarray-length.js @@ -0,0 +1,112 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var a = new Int32Array(100); +a.__proto__ = null; + +function get(a) { + return a.length; +} + +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(undefined, get(a)); + +get = function(a) { + return a.byteLength; +} + +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(undefined, get(a)); + +get = function(a) { + return a.byteOffset; +} + +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +assertEquals(undefined, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(undefined, get(a)); + +(function() { + "use strict"; + + class MyTypedArray extends Int32Array { + get length() { + return "length"; + } + } + + a = new MyTypedArray(); + + get = function(a) { + return a.length; + } + + assertEquals("length", get(a)); + assertEquals("length", get(a)); + assertEquals("length", get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals("length", get(a)); + + a.__proto__ = null; + + get = function(a) { + return a.length; + } + + assertEquals(undefined, get(a)); + assertEquals(undefined, get(a)); + assertEquals(undefined, get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals(undefined, get(a)); +})(); + +// Ensure we cannot delete length, byteOffset, byteLength. +assertTrue(Int32Array.prototype.hasOwnProperty("length")); +assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset")); +assertTrue(Int32Array.prototype.hasOwnProperty("byteLength")); +assertFalse(delete Int32Array.prototype.length); +assertFalse(delete Int32Array.prototype.byteOffset); +assertFalse(delete Int32Array.prototype.byteLength); + +a = new Int32Array(100); + +get = function(a) { + return a.length; +} + +assertEquals(100, get(a)); +assertEquals(100, get(a)); +assertEquals(100, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(100, get(a)); + +get = function(a) { + return a.byteLength; +} + +assertEquals(400, get(a)); +assertEquals(400, get(a)); +assertEquals(400, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(400, get(a)); + +get = function(a) { + return a.byteOffset; +} + +assertEquals(0, get(a)); +assertEquals(0, get(a)); +assertEquals(0, get(a)); +%OptimizeFunctionOnNextCall(get); +assertEquals(0, get(a)); -- 2.7.4