Commit be234381 authored by bmeurer's avatar bmeurer Committed by Commit bot

[builtins] Migrate the DataView constructor to C++.

The DataView constructor calls into C++ anyway, and is easier to deal
with this way, especially since we don't have the half initialized
object floating through JavaScript.

R=yangguo@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#34145}
parent e22f046f
......@@ -1579,16 +1579,16 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
TYPED_ARRAYS(INSTALL_TYPED_ARRAY)
#undef INSTALL_TYPED_ARRAY
Handle<JSFunction> data_view_fun =
InstallFunction(
global, "DataView", JS_DATA_VIEW_TYPE,
JSDataView::kSizeWithInternalFields,
isolate->initial_object_prototype(),
Builtins::kIllegal);
Handle<JSFunction> data_view_fun = InstallFunction(
global, "DataView", JS_DATA_VIEW_TYPE,
JSDataView::kSizeWithInternalFields,
isolate->initial_object_prototype(), Builtins::kDataViewConstructor);
InstallWithIntrinsicDefaultProto(isolate, data_view_fun,
Context::DATA_VIEW_FUN_INDEX);
data_view_fun->shared()->set_construct_stub(
*isolate->builtins()->JSBuiltinsConstructStub());
*isolate->builtins()->DataViewConstructor_ConstructStub());
data_view_fun->shared()->set_length(3);
data_view_fun->shared()->DontAdaptArguments();
}
{ // -- M a p
......
......@@ -2387,6 +2387,118 @@ BUILTIN(BooleanPrototypeValueOf) {
}
// -----------------------------------------------------------------------------
// ES6 section 24.2 DataView Objects
// ES6 section 24.2.2 The DataView Constructor for the [[Call]] case.
BUILTIN(DataViewConstructor) {
HandleScope scope(isolate);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromAsciiChecked("DataView")));
}
// ES6 section 24.2.2 The DataView Constructor for the [[Construct]] case.
BUILTIN(DataViewConstructor_ConstructStub) {
HandleScope scope(isolate);
Handle<JSFunction> target = args.target<JSFunction>();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<Object> buffer = args.atOrUndefined(isolate, 1);
Handle<Object> byte_offset = args.atOrUndefined(isolate, 2);
Handle<Object> byte_length = args.atOrUndefined(isolate, 3);
// 2. If Type(buffer) is not Object, throw a TypeError exception.
// 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a
// TypeError exception.
if (!buffer->IsJSArrayBuffer()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kDataViewNotArrayBuffer));
}
Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(buffer);
// 4. Let numberOffset be ? ToNumber(byteOffset).
Handle<Object> number_offset;
if (byte_offset->IsUndefined()) {
// We intentionally violate the specification at this point to allow
// for new DataView(buffer) invocations to be equivalent to the full
// new DataView(buffer, 0) invocation.
number_offset = handle(Smi::FromInt(0), isolate);
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_offset,
Object::ToNumber(byte_offset));
}
// 5. Let offset be ToInteger(numberOffset).
Handle<Object> offset;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset,
Object::ToInteger(isolate, number_offset));
// 6. If numberOffset ≠ offset or offset < 0, throw a RangeError exception.
if (number_offset->Number() != offset->Number() || offset->Number() < 0.0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset));
}
// 7. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
// We currently violate the specification at this point.
// 8. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]]
// internal slot.
double const buffer_byte_length = array_buffer->byte_length()->Number();
// 9. If offset > bufferByteLength, throw a RangeError exception
if (offset->Number() > buffer_byte_length) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset));
}
Handle<Object> view_byte_length;
if (byte_length->IsUndefined()) {
// 10. If byteLength is undefined, then
// a. Let viewByteLength be bufferByteLength - offset.
view_byte_length =
isolate->factory()->NewNumber(buffer_byte_length - offset->Number());
} else {
// 11. Else,
// a. Let viewByteLength be ? ToLength(byteLength).
// b. If offset+viewByteLength > bufferByteLength, throw a RangeError
// exception
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, view_byte_length, Object::ToLength(isolate, byte_length));
if (offset->Number() + view_byte_length->Number() > buffer_byte_length) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength));
}
}
// 12. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
// "%DataViewPrototype%", «[[DataView]], [[ViewedArrayBuffer]],
// [[ByteLength]], [[ByteOffset]]»).
// 13. Set O's [[DataView]] internal slot to true.
Handle<JSObject> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
JSObject::New(target, new_target));
for (int i = 0; i < ArrayBufferView::kInternalFieldCount; ++i) {
Handle<JSDataView>::cast(result)->SetInternalField(i, Smi::FromInt(0));
}
// 14. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
Handle<JSDataView>::cast(result)->set_buffer(*array_buffer);
// 15. Set O's [[ByteLength]] internal slot to viewByteLength.
Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length);
// 16. Set O's [[ByteOffset]] internal slot to offset.
Handle<JSDataView>::cast(result)->set_byte_offset(*offset);
// 17. Return O.
return *result;
}
// -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects
......
......@@ -74,6 +74,9 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(BooleanPrototypeToString, kNone) \
V(BooleanPrototypeValueOf, kNone) \
\
V(DataViewConstructor, kNone) \
V(DataViewConstructor_ConstructStub, kTargetAndNewTarget) \
\
V(DateConstructor, kNone) \
V(DateConstructor_ConstructStub, kTargetAndNewTarget) \
V(DateNow, kNone) \
......
......@@ -10200,31 +10200,6 @@ void HGraphBuilder::BuildArrayBufferViewInitialization(
}
void HOptimizedGraphBuilder::GenerateDataViewInitialize(
CallRuntime* expr) {
ZoneList<Expression*>* arguments = expr->arguments();
DCHECK(arguments->length()== 4);
CHECK_ALIVE(VisitForValue(arguments->at(0)));
HValue* obj = Pop();
CHECK_ALIVE(VisitForValue(arguments->at(1)));
HValue* buffer = Pop();
CHECK_ALIVE(VisitForValue(arguments->at(2)));
HValue* byte_offset = Pop();
CHECK_ALIVE(VisitForValue(arguments->at(3)));
HValue* byte_length = Pop();
{
NoObservableSideEffectsScope scope(this);
BuildArrayBufferViewInitialization<JSDataView>(
obj, buffer, byte_offset, byte_length);
}
}
HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
ExternalArrayType array_type,
bool is_zero_byte_offset,
......
......@@ -2225,7 +2225,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
F(DebugIsActive) \
/* Typed Arrays */ \
F(TypedArrayInitialize) \
F(DataViewInitialize) \
F(MaxSmi) \
F(TypedArrayMaxSizeInHeap) \
F(ArrayBufferViewGetByteLength) \
......
......@@ -847,36 +847,6 @@ TYPED_ARRAYS(SETUP_TYPED_ARRAY)
// --------------------------- DataView -----------------------------
function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
if (IS_UNDEFINED(new.target)) {
throw MakeTypeError(kConstructorNotFunction, "DataView");
}
// TODO(binji): support SharedArrayBuffers?
if (!IS_ARRAYBUFFER(buffer)) throw MakeTypeError(kDataViewNotArrayBuffer);
if (!IS_UNDEFINED(byteOffset)) {
byteOffset = ToPositiveInteger(byteOffset, kInvalidDataViewOffset);
}
if (!IS_UNDEFINED(byteLength)) {
byteLength = TO_INTEGER(byteLength);
}
var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
var offset = IS_UNDEFINED(byteOffset) ? 0 : byteOffset;
if (offset > bufferByteLength) throw MakeRangeError(kInvalidDataViewOffset);
var length = IS_UNDEFINED(byteLength)
? bufferByteLength - offset
: byteLength;
if (length < 0 || offset + length > bufferByteLength) {
throw new MakeRangeError(kInvalidDataViewLength);
}
var result = %NewObject(GlobalDataView, new.target);
%_DataViewInitialize(result, buffer, offset, length);
return result;
}
function DataViewGetBufferJS() {
if (!IS_DATAVIEW(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, 'DataView.buffer', this);
......@@ -939,7 +909,6 @@ endmacro
DATA_VIEW_TYPES(DATA_VIEW_GETTER_SETTER)
// Setup the DataView constructor.
%SetCode(GlobalDataView, DataViewConstructor);
%FunctionSetPrototype(GlobalDataView, new GlobalObject);
// Set up constructor property on the DataView prototype.
......
......@@ -414,42 +414,6 @@ RUNTIME_FUNCTION(Runtime_IsSharedInteger32TypedArray) {
}
RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
DCHECK_EQ(v8::ArrayBufferView::kInternalFieldCount,
holder->GetInternalFieldCount());
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
holder->SetInternalField(i, Smi::FromInt(0));
}
size_t buffer_length = 0;
size_t offset = 0;
size_t length = 0;
RUNTIME_ASSERT(
TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
// TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
// Entire range [offset, offset + length] must be in bounds.
RUNTIME_ASSERT(offset <= buffer_length);
RUNTIME_ASSERT(offset + length <= buffer_length);
// No overflow.
RUNTIME_ASSERT(offset + length >= offset);
holder->set_buffer(*buffer);
holder->set_byte_offset(*byte_offset);
holder->set_byte_length(*byte_length);
return isolate->heap()->undefined_value();
}
inline static bool NeedToFlipBytes(bool is_little_endian) {
#ifdef V8_TARGET_LITTLE_ENDIAN
return !is_little_endian;
......
......@@ -964,7 +964,6 @@ namespace internal {
F(IsSharedTypedArray, 1, 1) \
F(IsSharedIntegerTypedArray, 1, 1) \
F(IsSharedInteger32TypedArray, 1, 1) \
F(DataViewInitialize, 4, 1) \
F(DataViewGetUint8, 3, 1) \
F(DataViewGetInt8, 3, 1) \
F(DataViewGetUint16, 3, 1) \
......
......@@ -674,7 +674,6 @@ function TestDataViewConstructor() {
// error cases
assertThrows(function() { new DataView(ab, -1); }, RangeError);
assertThrows(function() { new DataView(ab, 1, -1); }, RangeError);
assertThrows(function() { new DataView(); }, TypeError);
assertThrows(function() { new DataView([]); }, TypeError);
assertThrows(function() { new DataView(ab, 257); }, RangeError);
......
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