[es6] Correctify and unify ArrayBuffer and SharedArrayBuffer constructors.

The ArrayBuffer and SharedArrayBuffer constructors should raise an
exception when called with no arguments or undefined length.  Also
unified the ArrayBuffer and SharedArrayBuffer implementations as C++
builtins, and removed some (now) obsolete runtime entries.

R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/1500543002

Cr-Commit-Position: refs/heads/master@{#32590}
This commit is contained in:
bmeurer 2015-12-03 13:15:41 -08:00 committed by Commit bot
parent 9290dd825e
commit 3235ccbb78
14 changed files with 163 additions and 170 deletions

View File

@ -204,6 +204,8 @@ class Genesis BASE_EMBEDDED {
HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
#undef DECLARE_FEATURE_INITIALIZATION
Handle<JSFunction> InstallArrayBuffer(Handle<JSObject> target,
const char* name);
Handle<JSFunction> InstallInternalArray(Handle<JSObject> target,
const char* name,
ElementsKind elements_kind);
@ -1248,11 +1250,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
{ // -- A r r a y B u f f e r
Handle<JSFunction> array_buffer_fun =
InstallFunction(
global, "ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
JSArrayBuffer::kSizeWithInternalFields,
isolate->initial_object_prototype(),
Builtins::kIllegal);
InstallArrayBuffer(global, "ArrayBuffer");
native_context()->set_array_buffer_fun(*array_buffer_fun);
}
@ -2067,13 +2065,9 @@ void Genesis::InitializeGlobal_harmony_reflect() {
void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
if (!FLAG_harmony_sharedarraybuffer) return;
Handle<JSGlobalObject> global(
JSGlobalObject::cast(native_context()->global_object()));
Handle<JSFunction> shared_array_buffer_fun = InstallFunction(
global, "SharedArrayBuffer", JS_ARRAY_BUFFER_TYPE,
JSArrayBuffer::kSizeWithInternalFields,
isolate()->initial_object_prototype(), Builtins::kIllegal);
Handle<JSGlobalObject> global(native_context()->global_object());
Handle<JSFunction> shared_array_buffer_fun =
InstallArrayBuffer(global, "SharedArrayBuffer");
native_context()->set_shared_array_buffer_fun(*shared_array_buffer_fun);
}
@ -2127,6 +2121,39 @@ void Genesis::InitializeGlobal_harmony_proxies() {
}
Handle<JSFunction> Genesis::InstallArrayBuffer(Handle<JSObject> target,
const char* name) {
// Setup the {prototype} with the given {name} for @@toStringTag.
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
JSObject::AddProperty(prototype, factory()->to_string_tag_symbol(),
factory()->NewStringFromAsciiChecked(name),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
// Allocate the constructor with the given {prototype}.
Handle<JSFunction> array_buffer_fun =
InstallFunction(target, name, JS_ARRAY_BUFFER_TYPE,
JSArrayBuffer::kSizeWithInternalFields, prototype,
Builtins::kArrayBufferConstructor);
array_buffer_fun->shared()->set_construct_stub(
*isolate()->builtins()->ArrayBufferConstructor_ConstructStub());
array_buffer_fun->shared()->set_internal_formal_parameter_count(1);
array_buffer_fun->shared()->set_length(1);
// Install the "constructor" property on the {prototype}.
JSObject::AddProperty(prototype, factory()->constructor_string(),
array_buffer_fun, DONT_ENUM);
Handle<JSFunction> array_buffer_is_view_fun = InstallFunction(
array_buffer_fun, "isView", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kArrayBufferIsView);
array_buffer_is_view_fun->shared()->set_internal_formal_parameter_count(1);
array_buffer_is_view_fun->shared()->set_length(1);
return array_buffer_fun;
}
Handle<JSFunction> Genesis::InstallInternalArray(Handle<JSObject> target,
const char* name,
ElementsKind elements_kind) {

View File

@ -1755,6 +1755,66 @@ BUILTIN(SymbolConstructor_ConstructStub) {
}
// ES6 section 24.1.2.1 ArrayBuffer( length ) for the [[Call]] case.
BUILTIN(ArrayBufferConstructor) {
HandleScope scope(isolate);
Handle<JSFunction> target = args.target();
DCHECK(*target == target->native_context()->array_buffer_fun() ||
*target == target->native_context()->shared_array_buffer_fun());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
handle(target->shared()->name(), isolate)));
}
// ES6 section 24.1.2.1 ArrayBuffer( length ) for the [[Construct]] case.
BUILTIN(ArrayBufferConstructor_ConstructStub) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<Object> length = args.at<Object>(1);
DCHECK(*target == target->native_context()->array_buffer_fun() ||
*target == target->native_context()->shared_array_buffer_fun());
// The ConstructStub is executed in the context of the caller, so we need
// to enter the callee context first before raising an exception.
isolate->set_context(args.target()->context());
Handle<Object> number_length;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
Object::ToNumber(length));
size_t byte_length;
if (!TryNumberToSize(isolate, *number_length, &byte_length)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
}
Handle<Map> initial_map;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, initial_map,
JSFunction::GetDerivedMap(isolate, target, new_target));
Handle<JSArrayBuffer> result = Handle<JSArrayBuffer>::cast(
isolate->factory()->NewJSObjectFromMap(initial_map));
SharedFlag shared_flag =
(*target == target->native_context()->array_buffer_fun())
? SharedFlag::kNotShared
: SharedFlag::kShared;
if (!JSArrayBuffer::SetupAllocatingData(result, isolate, byte_length, true,
shared_flag)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
}
return *result;
}
// ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
BUILTIN(ArrayBufferIsView) {
SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length());
Object* arg = args[1];
return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
}
namespace {
// ES6 section 9.5.15 ProxyCreate (target, handler)

View File

@ -51,46 +51,50 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
// Define list of builtins implemented in C++.
#define BUILTIN_LIST_C(V) \
V(Illegal, kNone) \
\
V(EmptyFunction, kNone) \
\
V(ArrayConcat, kNone) \
V(ArrayIsArray, kNone) \
V(ArrayPop, kNone) \
V(ArrayPush, kNone) \
V(ArrayShift, kNone) \
V(ArraySlice, kNone) \
V(ArraySplice, kNone) \
V(ArrayUnshift, kNone) \
\
V(DateToPrimitive, kNone) \
\
V(ProxyConstructor, kNone) \
V(ProxyConstructor_ConstructStub, kTarget) \
\
V(ReflectDefineProperty, kNone) \
V(ReflectDeleteProperty, kNone) \
V(ReflectGet, kNone) \
V(ReflectGetOwnPropertyDescriptor, kNone) \
V(ReflectGetPrototypeOf, kNone) \
V(ReflectHas, kNone) \
V(ReflectIsExtensible, kNone) \
V(ReflectOwnKeys, kNone) \
V(ReflectPreventExtensions, kNone) \
V(ReflectSet, kNone) \
V(ReflectSetPrototypeOf, kNone) \
\
V(SymbolConstructor, kNone) \
V(SymbolConstructor_ConstructStub, kTarget) \
\
V(HandleApiCall, kTarget) \
V(HandleApiCallConstruct, kTarget) \
V(HandleApiCallAsFunction, kNone) \
V(HandleApiCallAsConstructor, kNone) \
\
V(RestrictedFunctionPropertiesThrower, kNone) \
#define BUILTIN_LIST_C(V) \
V(Illegal, kNone) \
\
V(EmptyFunction, kNone) \
\
V(ArrayConcat, kNone) \
V(ArrayIsArray, kNone) \
V(ArrayPop, kNone) \
V(ArrayPush, kNone) \
V(ArrayShift, kNone) \
V(ArraySlice, kNone) \
V(ArraySplice, kNone) \
V(ArrayUnshift, kNone) \
\
V(ArrayBufferConstructor, kTarget) \
V(ArrayBufferConstructor_ConstructStub, kTargetAndNewTarget) \
V(ArrayBufferIsView, kNone) \
\
V(DateToPrimitive, kNone) \
\
V(ProxyConstructor, kNone) \
V(ProxyConstructor_ConstructStub, kTarget) \
\
V(ReflectDefineProperty, kNone) \
V(ReflectDeleteProperty, kNone) \
V(ReflectGet, kNone) \
V(ReflectGetOwnPropertyDescriptor, kNone) \
V(ReflectGetPrototypeOf, kNone) \
V(ReflectHas, kNone) \
V(ReflectIsExtensible, kNone) \
V(ReflectOwnKeys, kNone) \
V(ReflectPreventExtensions, kNone) \
V(ReflectSet, kNone) \
V(ReflectSetPrototypeOf, kNone) \
\
V(SymbolConstructor, kNone) \
V(SymbolConstructor_ConstructStub, kTarget) \
\
V(HandleApiCall, kTarget) \
V(HandleApiCallConstruct, kTarget) \
V(HandleApiCallAsFunction, kNone) \
V(HandleApiCallAsConstructor, kNone) \
\
V(RestrictedFunctionPropertiesThrower, kNone) \
V(RestrictedStrictArgumentsPropertiesThrower, kNone)
// Define list of builtins implemented in assembly.

View File

@ -12,31 +12,18 @@
// Imports
var GlobalArrayBuffer = global.ArrayBuffer;
var GlobalObject = global.Object;
var MakeTypeError;
var MaxSimple;
var MinSimple;
var ToPositiveInteger;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
MakeTypeError = from.MakeTypeError;
MaxSimple = from.MaxSimple;
MinSimple = from.MinSimple;
ToPositiveInteger = from.ToPositiveInteger;
});
// -------------------------------------------------------------------
function ArrayBufferConstructor(length) { // length = 1
if (!IS_UNDEFINED(new.target)) {
var byteLength = ToPositiveInteger(length, kInvalidArrayBufferLength);
%ArrayBufferInitialize(this, byteLength, kNotShared);
} else {
throw MakeTypeError(kConstructorNotFunction, "ArrayBuffer");
}
}
function ArrayBufferGetByteLen() {
if (!IS_ARRAYBUFFER(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
@ -82,29 +69,9 @@ function ArrayBufferSlice(start, end) {
return result;
}
function ArrayBufferIsViewJS(obj) {
return %ArrayBufferIsView(obj);
}
// Set up the ArrayBuffer constructor function.
%SetCode(GlobalArrayBuffer, ArrayBufferConstructor);
%FunctionSetPrototype(GlobalArrayBuffer, new GlobalObject());
// Set up the constructor property on the ArrayBuffer prototype object.
%AddNamedProperty(
GlobalArrayBuffer.prototype, "constructor", GlobalArrayBuffer, DONT_ENUM);
%AddNamedProperty(GlobalArrayBuffer.prototype,
toStringTagSymbol, "ArrayBuffer", DONT_ENUM | READ_ONLY);
utils.InstallGetter(GlobalArrayBuffer.prototype, "byteLength",
ArrayBufferGetByteLen);
utils.InstallFunctions(GlobalArrayBuffer, DONT_ENUM, [
"isView", ArrayBufferIsViewJS
]);
utils.InstallFunctions(GlobalArrayBuffer.prototype, DONT_ENUM, [
"slice", ArrayBufferSlice
]);

View File

@ -9,27 +9,14 @@
%CheckIsBootstrapping();
var GlobalSharedArrayBuffer = global.SharedArrayBuffer;
var GlobalObject = global.Object;
var MakeTypeError;
var ToPositiveInteger;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
MakeTypeError = from.MakeTypeError;
ToPositiveInteger = from.ToPositiveInteger;
})
// -------------------------------------------------------------------
function SharedArrayBufferConstructor(length) { // length = 1
if (!IS_UNDEFINED(new.target)) {
var byteLength = ToPositiveInteger(length, kInvalidArrayBufferLength);
%ArrayBufferInitialize(this, byteLength, kShared);
} else {
throw MakeTypeError(kConstructorNotFunction, "SharedArrayBuffer");
}
}
function SharedArrayBufferGetByteLen() {
if (!IS_SHAREDARRAYBUFFER(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
@ -38,27 +25,7 @@ function SharedArrayBufferGetByteLen() {
return %_ArrayBufferGetByteLength(this);
}
function SharedArrayBufferIsViewJS(obj) {
return %ArrayBufferIsView(obj);
}
// Set up the SharedArrayBuffer constructor function.
%SetCode(GlobalSharedArrayBuffer, SharedArrayBufferConstructor);
%FunctionSetPrototype(GlobalSharedArrayBuffer, new GlobalObject());
// Set up the constructor property on the SharedArrayBuffer prototype object.
%AddNamedProperty(GlobalSharedArrayBuffer.prototype, "constructor",
GlobalSharedArrayBuffer, DONT_ENUM);
%AddNamedProperty(GlobalSharedArrayBuffer.prototype,
toStringTagSymbol, "SharedArrayBuffer", DONT_ENUM | READ_ONLY);
utils.InstallGetter(GlobalSharedArrayBuffer.prototype, "byteLength",
SharedArrayBufferGetByteLen);
utils.InstallFunctions(GlobalSharedArrayBuffer, DONT_ENUM, [
"isView", SharedArrayBufferIsViewJS
]);
})

View File

@ -13,32 +13,6 @@
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
CONVERT_BOOLEAN_ARG_CHECKED(is_shared, 2);
if (!holder->byte_length()->IsUndefined()) {
// ArrayBuffer is already initialized; probably a fuzz test.
return *holder;
}
size_t allocated_length = 0;
if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
}
if (!JSArrayBuffer::SetupAllocatingData(
holder, isolate, allocated_length, true,
is_shared ? SharedFlag::kShared : SharedFlag::kNotShared)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
}
return *holder;
}
RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
@ -70,14 +44,6 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
}
RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, object, 0);
return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
}
RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);

View File

@ -988,10 +988,8 @@ namespace internal {
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
F(ArrayBufferInitialize, 3, 1) \
F(ArrayBufferGetByteLength, 1, 1) \
F(ArrayBufferSliceImpl, 3, 1) \
F(ArrayBufferIsView, 1, 1) \
F(ArrayBufferNeuter, 1, 1) \
F(TypedArrayInitialize, 6, 1) \
F(TypedArrayInitializeFromArrayLike, 4, 1) \

View File

@ -8,4 +8,4 @@
var MEM = new Uint8ClampedArray(heap);
function foo( ) { MEM[0] ^= 1; }
return {foo: foo};
})(this, {}, new ArrayBuffer( ) ).foo();
})(this, {}, new ArrayBuffer(0) ).foo();

View File

@ -436,7 +436,7 @@ function TestMapSetSubclassing(container, is_map) {
assertEquals(4.2, o.d);
assertEquals(153, o.o.foo);
var o1 = new A("bar");
var o1 = new A(8);
assertTrue(%HaveSameMap(o, o1));

View File

@ -39,7 +39,7 @@ function TestArrayBufferCreation() {
TestByteLength(256, 256);
TestByteLength(2.567, 2);
TestByteLength("abc", 0);
TestByteLength("0", 0);
TestByteLength(0, 0);
@ -52,7 +52,7 @@ function TestArrayBufferCreation() {
}, RangeError);
*/
var ab = new ArrayBuffer();
var ab = new ArrayBuffer(0);
assertSame(0, ab.byteLength);
assertEquals("[object ArrayBuffer]",
Object.prototype.toString.call(ab));
@ -729,11 +729,11 @@ function TestEnumerable(func, obj) {
if (obj)
assertArrayEquals([], props(obj));
}
TestEnumerable(ArrayBuffer, new ArrayBuffer());
TestEnumerable(ArrayBuffer, new ArrayBuffer(0));
for(i = 0; i < typedArrayConstructors.length; i++) {
TestEnumerable(typedArrayConstructors[i]);
}
TestEnumerable(DataView, new DataView(new ArrayBuffer()));
TestEnumerable(DataView, new DataView(new ArrayBuffer(0)));
// Test arbitrary properties on ArrayBuffer
function TestArbitrary(m) {
@ -754,8 +754,8 @@ TestArbitrary(new DataView(new ArrayBuffer(256)));
// Test direct constructor call
assertThrows(function() { ArrayBuffer(); }, TypeError);
assertThrows(function() { DataView(new ArrayBuffer()); }, TypeError);
assertThrows(function() { ArrayBuffer(0); }, TypeError);
assertThrows(function() { DataView(new ArrayBuffer(0)); }, TypeError);
function TestNonConfigurableProperties(constructor) {
var arr = new constructor([100])

View File

@ -77,7 +77,6 @@ for (var f of errorFunctions) {
// Builtin constructors.
var functions = [
Array,
ArrayBuffer,
Boolean,
// DataView,
Date,
@ -112,5 +111,8 @@ for (var f of functions) {
var p = new Promise(function() {});
assertPrototypeOf(p, Promise.prototype);
var dv = new DataView(new ArrayBuffer());
var ab = new ArrayBuffer(0);
assertPrototypeOf(ab, ArrayBuffer.prototype);
var dv = new DataView(ab);
assertPrototypeOf(dv, DataView.prototype);

View File

@ -100,7 +100,6 @@ for (var f of errorFunctions) {
// Builtin constructors.
var functions = [
Array,
ArrayBuffer,
Boolean,
// DataView,
Date,
@ -135,5 +134,8 @@ for (var f of functions) {
var p = new Promise(function() {});
assertPrototypeOf(p, Promise.prototype);
var dv = new DataView(new ArrayBuffer());
var ab = new ArrayBuffer(0);
assertPrototypeOf(ab, ArrayBuffer.prototype);
var dv = new DataView(ab);
assertPrototypeOf(dv, DataView.prototype);

View File

@ -40,7 +40,7 @@ function TestArrayBufferCreation() {
TestByteLength(256, 256);
TestByteLength(2.567, 2);
TestByteLength("abc", 0);
TestByteLength("0", 0);
TestByteLength(0, 0);
@ -53,7 +53,7 @@ function TestArrayBufferCreation() {
}, RangeError);
*/
var sab = new SharedArrayBuffer();
var sab = new SharedArrayBuffer(0);
assertSame(0, sab.byteLength);
assertEquals("[object SharedArrayBuffer]",
Object.prototype.toString.call(sab));
@ -548,7 +548,7 @@ function TestEnumerable(func, obj) {
if (obj)
assertArrayEquals([], props(obj));
}
TestEnumerable(ArrayBuffer, new SharedArrayBuffer());
TestEnumerable(ArrayBuffer, new SharedArrayBuffer(0));
for(i = 0; i < typedArrayConstructors.length; i++) {
TestEnumerable(typedArrayConstructors[i]);
}

View File

@ -4,6 +4,6 @@
if (this.Worker) {
var worker = new Worker("onmessage = function(){}");
var buf = new ArrayBuffer();
var buf = new ArrayBuffer(0);
worker.postMessage(buf, [buf]);
}