Inline internal getters for typed arrays & friends.
R=hpayer@chromium.org, yangguo@chromium.org Review URL: https://codereview.chromium.org/212603014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20330 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a72e3525fc
commit
6d91c1e77f
@ -45,7 +45,7 @@ function ArrayBufferGetByteLength() {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
['ArrayBuffer.prototype.byteLength', this]);
|
||||
}
|
||||
return %ArrayBufferGetByteLength(this);
|
||||
return %_ArrayBufferGetByteLength(this);
|
||||
}
|
||||
|
||||
// ES6 Draft 15.13.5.5.3
|
||||
@ -60,7 +60,7 @@ function ArrayBufferSlice(start, end) {
|
||||
end = TO_INTEGER(end);
|
||||
}
|
||||
var first;
|
||||
var byte_length = %ArrayBufferGetByteLength(this);
|
||||
var byte_length = %_ArrayBufferGetByteLength(this);
|
||||
if (relativeStart < 0) {
|
||||
first = MathMax(byte_length + relativeStart, 0);
|
||||
} else {
|
||||
|
@ -6025,6 +6025,11 @@ class HObjectAccess V8_FINAL {
|
||||
JSArrayBuffer::kBackingStoreOffset, Representation::External());
|
||||
}
|
||||
|
||||
static HObjectAccess ForJSArrayBufferByteLength() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
|
||||
}
|
||||
|
||||
static HObjectAccess ForExternalArrayExternalPointer() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
ExternalArray::kExternalPointerOffset, Representation::External());
|
||||
|
@ -8730,6 +8730,58 @@ void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
|
||||
CallRuntime* expr) {
|
||||
ASSERT(expr->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
|
||||
HValue* buffer = Pop();
|
||||
HInstruction* result = New<HLoadNamedField>(
|
||||
buffer,
|
||||
static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSArrayBufferByteLength());
|
||||
return ast_context()->ReturnInstruction(result, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
|
||||
CallRuntime* expr) {
|
||||
ASSERT(expr->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
|
||||
HValue* buffer = Pop();
|
||||
HInstruction* result = New<HLoadNamedField>(
|
||||
buffer,
|
||||
static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSArrayBufferViewByteLength());
|
||||
return ast_context()->ReturnInstruction(result, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
|
||||
CallRuntime* expr) {
|
||||
ASSERT(expr->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
|
||||
HValue* buffer = Pop();
|
||||
HInstruction* result = New<HLoadNamedField>(
|
||||
buffer,
|
||||
static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSArrayBufferViewByteOffset());
|
||||
return ast_context()->ReturnInstruction(result, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
|
||||
CallRuntime* expr) {
|
||||
ASSERT(expr->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
|
||||
HValue* buffer = Pop();
|
||||
HInstruction* result = New<HLoadNamedField>(
|
||||
buffer,
|
||||
static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForJSTypedArrayLength());
|
||||
return ast_context()->ReturnInstruction(result, expr->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
|
@ -1132,33 +1132,26 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
}
|
||||
|
||||
|
||||
#define TYPED_ARRAY_GETTER(getter, accessor) \
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
|
||||
#define BUFFER_VIEW_GETTER(Type, getter, accessor) \
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_##Type##Get##getter) { \
|
||||
HandleScope scope(isolate); \
|
||||
ASSERT(args.length() == 1); \
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
|
||||
if (!holder->IsJSTypedArray()) \
|
||||
return isolate->Throw(*isolate->factory()->NewTypeError( \
|
||||
"not_typed_array", HandleVector<Object>(NULL, 0))); \
|
||||
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
|
||||
return typed_array->accessor(); \
|
||||
CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
|
||||
return holder->accessor(); \
|
||||
}
|
||||
|
||||
TYPED_ARRAY_GETTER(ByteLength, byte_length)
|
||||
TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
|
||||
TYPED_ARRAY_GETTER(Length, length)
|
||||
BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
|
||||
BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
|
||||
BUFFER_VIEW_GETTER(TypedArray, Length, length)
|
||||
BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
|
||||
|
||||
#undef TYPED_ARRAY_GETTER
|
||||
#undef BUFFER_VIEW_GETTER
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGetBuffer) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0);
|
||||
if (!holder->IsJSTypedArray())
|
||||
return isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
"not_typed_array", HandleVector<Object>(NULL, 0)));
|
||||
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder));
|
||||
return *typed_array->GetBuffer();
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
|
||||
return *holder->GetBuffer();
|
||||
}
|
||||
|
||||
|
||||
@ -1273,30 +1266,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
|
||||
return data_view->buffer();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
|
||||
return data_view->byte_offset();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
|
||||
return data_view->byte_length();
|
||||
}
|
||||
|
||||
|
||||
inline static bool NeedToFlipBytes(bool is_little_endian) {
|
||||
#ifdef V8_TARGET_LITTLE_ENDIAN
|
||||
return !is_little_endian;
|
||||
|
@ -328,21 +328,15 @@ namespace internal {
|
||||
\
|
||||
/* Harmony typed arrays */ \
|
||||
F(ArrayBufferInitialize, 2, 1)\
|
||||
F(ArrayBufferGetByteLength, 1, 1)\
|
||||
F(ArrayBufferSliceImpl, 3, 1) \
|
||||
F(ArrayBufferIsView, 1, 1) \
|
||||
F(ArrayBufferNeuter, 1, 1) \
|
||||
\
|
||||
F(TypedArrayInitializeFromArrayLike, 4, 1) \
|
||||
F(TypedArrayGetBuffer, 1, 1) \
|
||||
F(TypedArrayGetByteLength, 1, 1) \
|
||||
F(TypedArrayGetByteOffset, 1, 1) \
|
||||
F(TypedArrayGetLength, 1, 1) \
|
||||
F(TypedArraySetFastCases, 3, 1) \
|
||||
\
|
||||
F(DataViewGetBuffer, 1, 1) \
|
||||
F(DataViewGetByteLength, 1, 1) \
|
||||
F(DataViewGetByteOffset, 1, 1) \
|
||||
F(DataViewGetInt8, 3, 1) \
|
||||
F(DataViewGetUint8, 3, 1) \
|
||||
F(DataViewGetInt16, 3, 1) \
|
||||
@ -690,13 +684,17 @@ namespace internal {
|
||||
// Entries have the form F(name, number of arguments, number of return values).
|
||||
#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \
|
||||
/* Typed Arrays */ \
|
||||
F(ConstructDouble, 2, 1) \
|
||||
F(TypedArrayInitialize, 5, 1) \
|
||||
F(DataViewInitialize, 4, 1) \
|
||||
F(MaxSmi, 0, 1) \
|
||||
F(TypedArrayMaxSizeInHeap, 0, 1) \
|
||||
\
|
||||
F(ArrayBufferViewGetByteLength, 1, 1) \
|
||||
F(ArrayBufferViewGetByteOffset, 1, 1) \
|
||||
F(TypedArrayGetLength, 1, 1) \
|
||||
/* ArrayBuffer */ \
|
||||
F(ArrayBufferGetByteLength, 1, 1) \
|
||||
/* Maths */ \
|
||||
F(ConstructDouble, 2, 1) \
|
||||
F(DoubleHi, 1, 1) \
|
||||
F(DoubleLo, 1, 1) \
|
||||
F(MathSqrt, 1, 1) \
|
||||
|
@ -1051,7 +1051,7 @@ intptr_t PagedSpace::SizeOfFirstPage() {
|
||||
int size = 0;
|
||||
switch (identity()) {
|
||||
case OLD_POINTER_SPACE:
|
||||
size = 72 * kPointerSize * KB;
|
||||
size = 96 * kPointerSize * KB;
|
||||
break;
|
||||
case OLD_DATA_SPACE:
|
||||
size = 192 * KB;
|
||||
|
@ -57,7 +57,7 @@ macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
length = ToPositiveInteger(length, "invalid_typed_array_length");
|
||||
}
|
||||
|
||||
var bufferByteLength = %ArrayBufferGetByteLength(buffer);
|
||||
var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
|
||||
var offset;
|
||||
if (IS_UNDEFINED(byteOffset)) {
|
||||
offset = 0;
|
||||
@ -125,7 +125,6 @@ macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
}
|
||||
|
||||
function NAMEConstructor(arg1, arg2, arg3) {
|
||||
|
||||
if (%_IsConstructCall()) {
|
||||
if (IS_ARRAYBUFFER(arg1)) {
|
||||
NAMEConstructByArrayBuffer(this, arg1, arg2, arg3);
|
||||
@ -139,34 +138,52 @@ macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
throw MakeTypeError("constructor_not_function", ["NAME"])
|
||||
}
|
||||
}
|
||||
endmacro
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
|
||||
|
||||
function TypedArrayGetBuffer() {
|
||||
function NAME_GetBuffer() {
|
||||
if (!(%_ClassOf(this) === 'NAME')) {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
["NAME.buffer", this]);
|
||||
}
|
||||
return %TypedArrayGetBuffer(this);
|
||||
}
|
||||
}
|
||||
|
||||
function TypedArrayGetByteLength() {
|
||||
return %TypedArrayGetByteLength(this);
|
||||
}
|
||||
function NAME_GetByteLength() {
|
||||
if (!(%_ClassOf(this) === 'NAME')) {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
["NAME.byteLength", this]);
|
||||
}
|
||||
return %_ArrayBufferViewGetByteLength(this);
|
||||
}
|
||||
|
||||
function TypedArrayGetByteOffset() {
|
||||
return %TypedArrayGetByteOffset(this);
|
||||
}
|
||||
function NAME_GetByteOffset() {
|
||||
if (!(%_ClassOf(this) === 'NAME')) {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
["NAME.byteOffset", this]);
|
||||
}
|
||||
return %_ArrayBufferViewGetByteOffset(this);
|
||||
}
|
||||
|
||||
function TypedArrayGetLength() {
|
||||
return %TypedArrayGetLength(this);
|
||||
}
|
||||
function NAME_GetLength() {
|
||||
if (!(%_ClassOf(this) === 'NAME')) {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
["NAME.length", this]);
|
||||
}
|
||||
return %_TypedArrayGetLength(this);
|
||||
}
|
||||
|
||||
function CreateSubArray(elementSize, constructor) {
|
||||
return function(begin, end) {
|
||||
var $NAME = global.NAME;
|
||||
|
||||
function NAMESubArray(begin, end) {
|
||||
if (!(%_ClassOf(this) === 'NAME')) {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
["NAME.subarray", this]);
|
||||
}
|
||||
var beginInt = TO_INTEGER(begin);
|
||||
if (!IS_UNDEFINED(end)) {
|
||||
end = TO_INTEGER(end);
|
||||
}
|
||||
|
||||
var srcLength = %TypedArrayGetLength(this);
|
||||
var srcLength = %_TypedArrayGetLength(this);
|
||||
if (beginInt < 0) {
|
||||
beginInt = MathMax(0, srcLength + beginInt);
|
||||
} else {
|
||||
@ -184,11 +201,14 @@ function CreateSubArray(elementSize, constructor) {
|
||||
}
|
||||
var newLength = endInt - beginInt;
|
||||
var beginByteOffset =
|
||||
%TypedArrayGetByteOffset(this) + beginInt * elementSize;
|
||||
return new constructor(%TypedArrayGetBuffer(this),
|
||||
%_ArrayBufferViewGetByteOffset(this) + beginInt * ELEMENT_SIZE;
|
||||
return new $NAME(%TypedArrayGetBuffer(this),
|
||||
beginByteOffset, newLength);
|
||||
}
|
||||
}
|
||||
endmacro
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
|
||||
|
||||
|
||||
function TypedArraySetFromArrayLike(target, source, sourceLength, offset) {
|
||||
if (offset > 0) {
|
||||
@ -296,34 +316,34 @@ function TypedArraySet(obj, offset) {
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
function SetupTypedArray(constructor, fun, elementSize) {
|
||||
function SetupTypedArrays() {
|
||||
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
%CheckIsBootstrapping();
|
||||
%SetCode(constructor, fun);
|
||||
%FunctionSetPrototype(constructor, new $Object());
|
||||
%SetCode(global.NAME, NAMEConstructor);
|
||||
%FunctionSetPrototype(global.NAME, new $Object());
|
||||
|
||||
%SetProperty(constructor, "BYTES_PER_ELEMENT", elementSize,
|
||||
%SetProperty(global.NAME, "BYTES_PER_ELEMENT", ELEMENT_SIZE,
|
||||
READ_ONLY | DONT_ENUM | DONT_DELETE);
|
||||
%SetProperty(constructor.prototype,
|
||||
"constructor", constructor, DONT_ENUM);
|
||||
%SetProperty(constructor.prototype,
|
||||
"BYTES_PER_ELEMENT", elementSize,
|
||||
%SetProperty(global.NAME.prototype,
|
||||
"constructor", global.NAME, DONT_ENUM);
|
||||
%SetProperty(global.NAME.prototype,
|
||||
"BYTES_PER_ELEMENT", ELEMENT_SIZE,
|
||||
READ_ONLY | DONT_ENUM | DONT_DELETE);
|
||||
InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
|
||||
InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
|
||||
InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
|
||||
InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
|
||||
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);
|
||||
|
||||
InstallFunctions(constructor.prototype, DONT_ENUM, $Array(
|
||||
"subarray", CreateSubArray(elementSize, constructor),
|
||||
InstallFunctions(global.NAME.prototype, DONT_ENUM, $Array(
|
||||
"subarray", NAMESubArray,
|
||||
"set", TypedArraySet
|
||||
));
|
||||
}
|
||||
|
||||
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
SetupTypedArray (global.NAME, NAMEConstructor, ELEMENT_SIZE);
|
||||
endmacro
|
||||
|
||||
TYPED_ARRAYS(SETUP_TYPED_ARRAY)
|
||||
}
|
||||
|
||||
SetupTypedArrays();
|
||||
|
||||
// --------------------------- DataView -----------------------------
|
||||
|
||||
@ -341,7 +361,7 @@ function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
|
||||
byteLength = TO_INTEGER(byteLength);
|
||||
}
|
||||
|
||||
var bufferByteLength = %ArrayBufferGetByteLength(buffer);
|
||||
var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
|
||||
|
||||
var offset = IS_UNDEFINED(byteOffset) ? 0 : byteOffset;
|
||||
if (offset > bufferByteLength) {
|
||||
@ -373,7 +393,7 @@ function DataViewGetByteOffset() {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
['DataView.byteOffset', this]);
|
||||
}
|
||||
return %DataViewGetByteOffset(this);
|
||||
return %_ArrayBufferViewGetByteOffset(this);
|
||||
}
|
||||
|
||||
function DataViewGetByteLength() {
|
||||
@ -381,7 +401,7 @@ function DataViewGetByteLength() {
|
||||
throw MakeTypeError('incompatible_method_receiver',
|
||||
['DataView.byteLength', this]);
|
||||
}
|
||||
return %DataViewGetByteLength(this);
|
||||
return %_ArrayBufferViewGetByteLength(this);
|
||||
}
|
||||
|
||||
macro DATA_VIEW_TYPES(FUNCTION)
|
||||
|
@ -310,6 +310,11 @@ function TestSubArray(constructor, item) {
|
||||
|
||||
SubarrayTestCase(constructor, item, 10,90, 100, 90);
|
||||
SubarrayTestCase(constructor, item, 10,90, 100, -10);
|
||||
|
||||
var method = constructor.prototype.subarray;
|
||||
method.call(new constructor(100), 0, 100);
|
||||
var o = {};
|
||||
assertThrows(function() { method.call(o, 0, 100); }, TypeError);
|
||||
}
|
||||
|
||||
TestSubArray(Uint8Array, 0xFF);
|
||||
|
Loading…
Reference in New Issue
Block a user