Skip to content

Commit

Permalink
src: v12 fixed for JSArrayBuffer & FixedTypedArray
Browse files Browse the repository at this point in the history
PR-URL: #330
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
  • Loading branch information
mmarchini committed Jan 21, 2020
1 parent 2cc07cd commit f8eebcc
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 109 deletions.
2 changes: 0 additions & 2 deletions src/constants.h
Expand Up @@ -48,8 +48,6 @@ class Constant {

inline std::string name() { return name_; }

protected:
friend class Constants;
explicit Constant(T value) : value_(value), status_(kValid), name_("") {}
Constant(T value, std::string name)
: value_(value), status_(kLoaded), name_(name) {}
Expand Down
66 changes: 51 additions & 15 deletions src/llv8-constants.cc
Expand Up @@ -348,12 +348,26 @@ void FixedArray::Load() {


void FixedTypedArrayBase::Load() {
kBasePointerOffset = LoadOptionalConstant(
{"class_FixedTypedArrayBase__base_pointer__Object"}, 0);
kExternalPointerOffset = LoadOptionalConstant(
{"class_FixedTypedArrayBase__external_pointer__Object",
"class_FixedTypedArrayBase__external_pointer__uintptr_t"},
0);
}

void JSTypedArray::Load() {
kBasePointerOffset =
LoadConstant("class_FixedTypedArrayBase__base_pointer__Object");
kExternalPointerOffset =
LoadConstant("class_FixedTypedArrayBase__external_pointer__Object");
LoadOptionalConstant({"class_JSTypedArray__base_pointer__Object"}, 0);
kExternalPointerOffset = LoadOptionalConstant(
{"class_JSTypedArray__external_pointer__uintptr_t"}, 0);
}

// TODO(mmarchini): proper validation so that we log an error if neither classes
// were able to load their constants.
bool JSTypedArray::IsDataPointerInJSTypedArray() {
return kBasePointerOffset.Loaded() && kExternalPointerOffset.Loaded();
}

void Oddball::Load() {
kKindOffset = LoadConstant("class_Oddball__kind_offset__int");
Expand All @@ -370,19 +384,15 @@ void Oddball::Load() {

void JSArrayBuffer::Load() {
kBackingStoreOffset =
LoadConstant("class_JSArrayBuffer__backing_store__Object");
kByteLengthOffset = LoadConstant("class_JSArrayBuffer__byte_length__Object");

// v4 compatibility fix
if (kBackingStoreOffset == -1) {
common_->Load();
LoadConstant({"class_JSArrayBuffer__backing_store__Object",
"class_JSArrayBuffer__backing_store__uintptr_t"});
kByteLengthOffset =
LoadConstant({"class_JSArrayBuffer__byte_length__Object",
"class_JSArrayBuffer__byte_length__size_t"});

kBackingStoreOffset = kByteLengthOffset + common_->kPointerSize;
if (kBackingStoreOffset.Check()) {
}

kBitFieldOffset = kBackingStoreOffset + common_->kPointerSize;
if (common_->kPointerSize == 8) kBitFieldOffset += 4;

kWasNeuteredMask = LoadConstant("jsarray_buffer_was_neutered_mask");
kWasNeuteredShift = LoadConstant("jsarray_buffer_was_neutered_shift");

Expand All @@ -394,14 +404,40 @@ void JSArrayBuffer::Load() {
}


bool JSArrayBuffer::IsByteLengthScalar() {
return kByteLengthOffset.name() ==
"v8dbg_class_JSArrayBuffer__byte_length__size_t";
}

Constant<int64_t> JSArrayBuffer::BitFieldOffset() {
if (!kBackingStoreOffset.Check()) return Constant<int64_t>();

common_->Load();
int64_t kBitFieldOffset = *kBackingStoreOffset + common_->kPointerSize;
if (common_->kPointerSize == 8) kBitFieldOffset += 4;
return Constant<int64_t>(kBitFieldOffset);
}


void JSArrayBufferView::Load() {
kBufferOffset = LoadConstant("class_JSArrayBufferView__buffer__Object");
kByteOffsetOffset =
LoadConstant("class_JSArrayBufferView__raw_byte_offset__Object");
LoadConstant({"class_JSArrayBufferView__raw_byte_offset__Object",
"class_JSArrayBufferView__byte_offset__size_t"});
kByteLengthOffset =
LoadConstant("class_JSArrayBufferView__raw_byte_length__Object");
LoadConstant({"class_JSArrayBufferView__raw_byte_length__Object",
"class_JSArrayBufferView__byte_length__size_t"});
}

bool JSArrayBufferView::IsByteLengthScalar() {
return kByteLengthOffset.name() ==
"v8dbg_class_JSArrayBufferView__byte_length__size_t";
}

bool JSArrayBufferView::IsByteOffsetScalar() {
return kByteOffsetOffset.name() ==
"v8dbg_class_JSArrayBufferView__byte_offset__size_t";
}

void DescriptorArray::Load() {
kDetailsOffset = LoadConstant({"prop_desc_details"});
Expand Down
32 changes: 25 additions & 7 deletions src/llv8-constants.h
Expand Up @@ -348,8 +348,21 @@ class FixedTypedArrayBase : public Module {
public:
CONSTANTS_DEFAULT_METHODS(FixedTypedArrayBase);

int64_t kBasePointerOffset;
int64_t kExternalPointerOffset;
Constant<int64_t> kBasePointerOffset;
Constant<int64_t> kExternalPointerOffset;

protected:
void Load();
};

class JSTypedArray : public Module {
public:
CONSTANTS_DEFAULT_METHODS(JSTypedArray);

Constant<int64_t> kBasePointerOffset;
Constant<int64_t> kExternalPointerOffset;

bool IsDataPointerInJSTypedArray();

protected:
void Load();
Expand Down Expand Up @@ -379,13 +392,15 @@ class JSArrayBuffer : public Module {

int64_t kKindOffset;

int64_t kBackingStoreOffset;
int64_t kByteLengthOffset;
int64_t kBitFieldOffset;
Constant<int64_t> kBackingStoreOffset;
Constant<int64_t> kByteLengthOffset;

int64_t kWasNeuteredMask;
int64_t kWasNeuteredShift;

Constant<int64_t> BitFieldOffset();
bool IsByteLengthScalar();

protected:
void Load();
};
Expand All @@ -395,8 +410,11 @@ class JSArrayBufferView : public Module {
CONSTANTS_DEFAULT_METHODS(JSArrayBufferView);

int64_t kBufferOffset;
int64_t kByteOffsetOffset;
int64_t kByteLengthOffset;
Constant<int64_t> kByteOffsetOffset;
Constant<int64_t> kByteLengthOffset;

bool IsByteLengthScalar();
bool IsByteOffsetScalar();

protected:
void Load();
Expand Down
186 changes: 171 additions & 15 deletions src/llv8-inl.h
Expand Up @@ -7,6 +7,33 @@
namespace llnode {
namespace v8 {

using lldb::addr_t;
using lldb::SBError;

template <typename T>
inline std::string CheckedType<T>::ToString(const char* fmt) {
if (!Check()) return "???";

char buf[20];
snprintf(buf, sizeof(buf), fmt, val_);
return std::string(buf);
}

template <class T>
inline CheckedType<T> LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size) {
SBError sberr;
int64_t value = process_.ReadUnsignedFromMemory(static_cast<addr_t>(addr),
byte_size, sberr);

if (sberr.Fail()) {
PRINT_DEBUG("Failed to load unsigned from v8 memory. Reason: %s",
sberr.GetCString());
return CheckedType<T>();
}

return CheckedType<T>(value);
}

template <>
inline double LLV8::LoadValue<double>(int64_t addr, Error& err) {
return LoadDouble(addr, err);
Expand Down Expand Up @@ -67,6 +94,14 @@ inline int64_t HeapObject::LoadField(int64_t off, Error& err) {
}


template <typename T>
inline CheckedType<T> HeapObject::LoadCheckedField(Constant<int64_t> off) {
RETURN_IF_THIS_INVALID(CheckedType<T>());
RETURN_IF_INVALID(off, CheckedType<T>());
return v8()->LoadUnsigned<T>(LeaField(*off), 8);
}


template <>
inline int32_t HeapObject::LoadFieldValue<int32_t>(int64_t off, Error& err) {
return v8()->LoadValue<int32_t>(LeaField(off), err);
Expand Down Expand Up @@ -499,22 +534,139 @@ inline int64_t Code::Size(Error& err) {

ACCESSOR(Oddball, Kind, oddball()->kKindOffset, Smi)

inline int64_t JSArrayBuffer::BackingStore(Error& err) {
return LoadField(v8()->js_array_buffer()->kBackingStoreOffset, err);
inline CheckedType<uintptr_t> JSArrayBuffer::BackingStore() {
RETURN_IF_THIS_INVALID(CheckedType<size_t>());

return LoadCheckedField<uintptr_t>(
v8()->js_array_buffer()->kBackingStoreOffset);
}

inline CheckedType<size_t> JSArrayBuffer::ByteLength() {
RETURN_IF_THIS_INVALID(CheckedType<size_t>());

if (!v8()->js_array_buffer()->IsByteLengthScalar()) {
Error err;
Smi len = byte_length(err);
RETURN_IF_INVALID(len, CheckedType<size_t>());

return CheckedType<size_t>(len.GetValue());
}

return LoadCheckedField<size_t>(v8()->js_array_buffer()->kByteLengthOffset);
}

inline int64_t JSArrayBuffer::BitField(Error& err) {
return LoadField(v8()->js_array_buffer()->kBitFieldOffset, err) & 0xffffffff;
inline CheckedType<int64_t> JSArrayBuffer::BitField() {
RETURN_IF_THIS_INVALID(CheckedType<int64_t>());
CheckedType<int64_t> bit_fields =
LoadCheckedField<int64_t>(v8()->js_array_buffer()->BitFieldOffset());
RETURN_IF_INVALID(bit_fields, CheckedType<int64_t>());
return CheckedType<int64_t>(*bit_fields & 0xffffffff);
}

ACCESSOR(JSArrayBuffer, ByteLength, js_array_buffer()->kByteLengthOffset, Smi)
SAFE_ACCESSOR(JSArrayBuffer, byte_length, js_array_buffer()->kByteLengthOffset,
Smi)

ACCESSOR(JSArrayBufferView, Buffer, js_array_buffer_view()->kBufferOffset,
JSArrayBuffer)
ACCESSOR(JSArrayBufferView, ByteOffset,
js_array_buffer_view()->kByteOffsetOffset, Smi)
ACCESSOR(JSArrayBufferView, ByteLength,
js_array_buffer_view()->kByteLengthOffset, Smi)

inline CheckedType<size_t> JSArrayBufferView::ByteLength() {
RETURN_IF_THIS_INVALID(CheckedType<size_t>());

if (!v8()->js_array_buffer_view()->IsByteLengthScalar()) {
Error err;
Smi len = byte_length(err);
RETURN_IF_INVALID(len, CheckedType<size_t>());

return CheckedType<size_t>(len.GetValue());
}

return LoadCheckedField<size_t>(
v8()->js_array_buffer_view()->kByteLengthOffset);
}

inline CheckedType<size_t> JSArrayBufferView::ByteOffset() {
RETURN_IF_THIS_INVALID(CheckedType<size_t>());

if (!v8()->js_array_buffer_view()->IsByteOffsetScalar()) {
Error err;
Smi len = byte_offset(err);
RETURN_IF_INVALID(len, CheckedType<size_t>());

return CheckedType<size_t>(len.GetValue());
}

return LoadCheckedField<size_t>(
v8()->js_array_buffer_view()->kByteOffsetOffset);
}

SAFE_ACCESSOR(JSArrayBufferView, byte_offset,
js_array_buffer_view()->kByteOffsetOffset, Smi)
SAFE_ACCESSOR(JSArrayBufferView, byte_length,
js_array_buffer_view()->kByteLengthOffset, Smi)

inline CheckedType<int64_t> JSTypedArray::base() {
return LoadCheckedField<int64_t>(v8()->js_typed_array()->kBasePointerOffset);
}

inline CheckedType<int64_t> JSTypedArray::external() {
return LoadCheckedField<int64_t>(
v8()->js_typed_array()->kExternalPointerOffset);
}

inline CheckedType<int64_t> JSTypedArray::GetExternal() {
if (v8()->js_typed_array()->IsDataPointerInJSTypedArray()) {
PRINT_DEBUG("OHALO");
return external();
} else {
PRINT_DEBUG("NAY");
// TODO(mmarchini): don't rely on Error
Error err;
v8::HeapObject elements_obj = Elements(err);
RETURN_IF_INVALID(elements_obj, CheckedType<int64_t>());
v8::FixedTypedArrayBase elements(elements_obj);
return elements.GetExternal();
}
}

inline CheckedType<int64_t> JSTypedArray::GetBase() {
if (v8()->js_typed_array()->IsDataPointerInJSTypedArray()) {
PRINT_DEBUG("ALOHA");
return base();
} else {
PRINT_DEBUG("NEY");
// TODO(mmarchini): don't rely on Error
Error err;
v8::HeapObject elements_obj = Elements(err);
RETURN_IF_INVALID(elements_obj, CheckedType<int64_t>());
v8::FixedTypedArrayBase elements(elements_obj);
return elements.GetBase();
}
}

inline CheckedType<uintptr_t> JSTypedArray::GetData() {
// TODO(mmarchini): don't rely on Error
Error err;
v8::JSArrayBuffer buf = Buffer(err);
if (err.Fail()) return CheckedType<uintptr_t>();

v8::CheckedType<uintptr_t> data = buf.BackingStore();
// TODO(mmarchini): be more lenient to failed load
RETURN_IF_INVALID(data, CheckedType<uintptr_t>());

if (*data == 0) {
// The backing store has not been materialized yet.

CheckedType<int64_t> base = GetBase();
RETURN_IF_INVALID(base, v8::CheckedType<uintptr_t>());

CheckedType<int64_t> external = GetExternal();
RETURN_IF_INVALID(external, v8::CheckedType<uintptr_t>());

data = v8::CheckedType<uintptr_t>(*base + *external);
}
return data;
}


inline ScopeInfo::PositionInfo ScopeInfo::MaybePositionInfo(Error& err) {
ScopeInfo::PositionInfo position_info = {
Expand Down Expand Up @@ -632,12 +784,14 @@ ACCESSOR(ThinString, Actual, thin_string()->kActualOffset, String);

ACCESSOR(FixedArrayBase, Length, fixed_array_base()->kLengthOffset, Smi);

inline int64_t FixedTypedArrayBase::GetBase(Error& err) {
return LoadField(v8()->fixed_typed_array_base()->kBasePointerOffset, err);
inline CheckedType<int64_t> FixedTypedArrayBase::GetBase() {
return LoadCheckedField<int64_t>(
v8()->fixed_typed_array_base()->kBasePointerOffset);
}

inline int64_t FixedTypedArrayBase::GetExternal(Error& err) {
return LoadField(v8()->fixed_typed_array_base()->kExternalPointerOffset, err);
inline CheckedType<int64_t> FixedTypedArrayBase::GetExternal() {
return LoadCheckedField<int64_t>(
v8()->fixed_typed_array_base()->kExternalPointerOffset);
}

inline std::string OneByteString::ToString(Error& err) {
Expand Down Expand Up @@ -973,10 +1127,12 @@ inline bool Oddball::IsHole(Error& err) {
return kind.GetValue() == v8()->oddball()->kTheHole;
}

// TODO(mmarchini): return CheckedType
inline bool JSArrayBuffer::WasNeutered(Error& err) {
int64_t field = BitField(err);
if (err.Fail()) return false;
CheckedType<int64_t> bit_field = BitField();
RETURN_IF_INVALID(bit_field, false);

int64_t field = *bit_field;
field &= v8()->js_array_buffer()->kWasNeuteredMask;
field >>= v8()->js_array_buffer()->kWasNeuteredShift;
return field != 0;
Expand Down

0 comments on commit f8eebcc

Please sign in to comment.