summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/DataViewObject.h
blob: a17b3e117491a71438796ce38351da73a71728a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef vm_DataViewObject_h
#define vm_DataViewObject_h

#include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"

#include "js/Class.h"
#include "vm/ArrayBufferViewObject.h"
#include "vm/JSObject.h"

namespace js {

class ArrayBufferObjectMaybeShared;

// In the DataViewObject, the private slot contains a raw pointer into
// the buffer.  The buffer may be shared memory and the raw pointer
// should not be exposed without sharedness information accompanying
// it.
//
// DataViewObject is an abstract base class and has exactly two concrete
// subclasses, FixedLengthDataViewObject and ResizableDataViewObject.

class DataViewObject : public ArrayBufferViewObject {
 protected:
  static const ClassSpec classSpec_;

 private:
  template <typename NativeType>
  SharedMem<uint8_t*> getDataPointer(uint64_t offset, size_t length,
                                     bool* isSharedMemory);

  static bool bufferGetterImpl(JSContext* cx, const CallArgs& args);
  static bool bufferGetter(JSContext* cx, unsigned argc, Value* vp);

  static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
  static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);

  static bool byteOffsetGetterImpl(JSContext* cx, const CallArgs& args);
  static bool byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp);

  static bool getAndCheckConstructorArgs(JSContext* cx, HandleObject bufobj,
                                         const CallArgs& args,
                                         size_t* byteOffsetPtr,
                                         size_t* byteLengthPtr,
                                         bool* autoLengthPtr);
  static bool constructSameCompartment(JSContext* cx, HandleObject bufobj,
                                       const CallArgs& args);
  static bool constructWrapped(JSContext* cx, HandleObject bufobj,
                               const CallArgs& args);

  static DataViewObject* create(
      JSContext* cx, size_t byteOffset, size_t byteLength,
      Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto);

 protected:
  size_t rawByteLength() const {
    return size_t(getFixedSlot(LENGTH_SLOT).toPrivate());
  }

 public:
  static const JSClass protoClass_;

  mozilla::Maybe<size_t> byteLength();
  mozilla::Maybe<size_t> byteOffset();

  template <typename NativeType>
  static bool offsetIsInBounds(uint64_t offset, size_t byteLength) {
    return offsetIsInBounds(sizeof(NativeType), offset, byteLength);
  }
  static bool offsetIsInBounds(uint32_t byteSize, uint64_t offset,
                               size_t byteLength) {
    MOZ_ASSERT(byteSize <= 8);
    mozilla::CheckedInt<uint64_t> endOffset(offset);
    endOffset += byteSize;
    return endOffset.isValid() && endOffset.value() <= byteLength;
  }

  static bool isOriginalByteOffsetGetter(Native native) {
    return native == byteOffsetGetter;
  }

  static bool isOriginalByteLengthGetter(Native native) {
    return native == byteLengthGetter;
  }

  static bool construct(JSContext* cx, unsigned argc, Value* vp);

  static bool getInt8Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);

  static bool getUint8Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getUint8(JSContext* cx, unsigned argc, Value* vp);

  static bool getInt16Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getInt16(JSContext* cx, unsigned argc, Value* vp);

  static bool getUint16Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getUint16(JSContext* cx, unsigned argc, Value* vp);

  static bool getInt32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getInt32(JSContext* cx, unsigned argc, Value* vp);

  static bool getUint32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getUint32(JSContext* cx, unsigned argc, Value* vp);

  static bool getBigInt64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getBigInt64(JSContext* cx, unsigned argc, Value* vp);

  static bool getBigUint64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp);

  static bool getFloat32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getFloat32(JSContext* cx, unsigned argc, Value* vp);

  static bool getFloat64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_getFloat64(JSContext* cx, unsigned argc, Value* vp);

  static bool setInt8Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setInt8(JSContext* cx, unsigned argc, Value* vp);

  static bool setUint8Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setUint8(JSContext* cx, unsigned argc, Value* vp);

  static bool setInt16Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setInt16(JSContext* cx, unsigned argc, Value* vp);

  static bool setUint16Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setUint16(JSContext* cx, unsigned argc, Value* vp);

  static bool setInt32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setInt32(JSContext* cx, unsigned argc, Value* vp);

  static bool setUint32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setUint32(JSContext* cx, unsigned argc, Value* vp);

  static bool setBigInt64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setBigInt64(JSContext* cx, unsigned argc, Value* vp);

  static bool setBigUint64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp);

  static bool setFloat32Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setFloat32(JSContext* cx, unsigned argc, Value* vp);

  static bool setFloat64Impl(JSContext* cx, const CallArgs& args);
  static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);

  template <typename NativeType>
  NativeType read(uint64_t offset, size_t length, bool isLittleEndian);

  template <typename NativeType>
  static bool read(JSContext* cx, Handle<DataViewObject*> obj,
                   const CallArgs& args, NativeType* val);
  template <typename NativeType>
  static bool write(JSContext* cx, Handle<DataViewObject*> obj,
                    const CallArgs& args);

 private:
  static const JSFunctionSpec methods[];
  static const JSPropertySpec properties[];
};

/**
 * DataView whose buffer is a fixed-length (Shared)ArrayBuffer object.
 */
class FixedLengthDataViewObject : public DataViewObject {
 public:
  static const JSClass class_;

  size_t byteOffset() const { return ArrayBufferViewObject::byteOffset(); }

  size_t byteLength() const { return rawByteLength(); }

  bool offsetIsInBounds(uint32_t byteSize, uint64_t offset) const {
    return DataViewObject::offsetIsInBounds(byteSize, offset, byteLength());
  }

  template <typename NativeType>
  NativeType read(uint64_t offset, bool isLittleEndian) {
    return DataViewObject::read<NativeType>(offset, byteLength(),
                                            isLittleEndian);
  }
};

/**
 * DataView whose buffer is a resizable (Shared)ArrayBuffer object.
 */
class ResizableDataViewObject : public DataViewObject {
  friend class DataViewObject;

  static ResizableDataViewObject* create(
      JSContext* cx, size_t byteOffset, size_t byteLength, bool autoLength,
      Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto);

 public:
  static const uint8_t AUTO_LENGTH_SLOT = DataViewObject::RESERVED_SLOTS;

  static const uint8_t RESERVED_SLOTS = DataViewObject::RESERVED_SLOTS + 1;

  static const JSClass class_;

  bool isAutoLength() const {
    return getFixedSlot(AUTO_LENGTH_SLOT).toBoolean();
  }
};

// For structured cloning.
JSObject* NewDataView(JSContext* cx, HandleObject buffer, size_t byteOffset);

}  // namespace js

template <>
inline bool JSObject::is<js::DataViewObject>() const {
  return is<js::FixedLengthDataViewObject>() ||
         is<js::ResizableDataViewObject>();
}

#endif /* vm_DataViewObject_h */