Commit cb6e7056 authored by oth's avatar oth Committed by Commit bot

[Interpreter] Add BytecodeArray class and add to SharedFunctionInfo.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#29843}
parent cc8fa95f
......@@ -6946,7 +6946,7 @@ class Internals {
static const int kNodeIsIndependentShift = 3;
static const int kNodeIsPartiallyDependentShift = 4;
static const int kJSObjectType = 0xbe;
static const int kJSObjectType = 0xbf;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x87;
......
......@@ -873,6 +873,15 @@ Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
}
Handle<BytecodeArray> Factory::NewBytecodeArray(int length,
const byte* raw_bytecodes) {
DCHECK(0 <= length);
CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateBytecodeArray(
length, raw_bytecodes),
BytecodeArray);
}
Handle<ExternalArray> Factory::NewExternalArray(int length,
ExternalArrayType array_type,
void* external_pointer,
......
......@@ -283,6 +283,8 @@ class Factory final {
Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED);
Handle<BytecodeArray> NewBytecodeArray(int length, const byte* raw_bytecodes);
Handle<ExternalArray> NewExternalArray(
int length,
ExternalArrayType array_type,
......
......@@ -1894,18 +1894,17 @@ bool V8HeapExplorer::IterateAndExtractSinglePass() {
bool V8HeapExplorer::IsEssentialObject(Object* object) {
return object->IsHeapObject()
&& !object->IsOddball()
&& object != heap_->empty_byte_array()
&& object != heap_->empty_fixed_array()
&& object != heap_->empty_descriptor_array()
&& object != heap_->fixed_array_map()
&& object != heap_->cell_map()
&& object != heap_->global_property_cell_map()
&& object != heap_->shared_function_info_map()
&& object != heap_->free_space_map()
&& object != heap_->one_pointer_filler_map()
&& object != heap_->two_pointer_filler_map();
return object->IsHeapObject() && !object->IsOddball() &&
object != heap_->empty_byte_array() &&
object != heap_->empty_bytecode_array() &&
object != heap_->empty_fixed_array() &&
object != heap_->empty_descriptor_array() &&
object != heap_->fixed_array_map() && object != heap_->cell_map() &&
object != heap_->global_property_cell_map() &&
object != heap_->shared_function_info_map() &&
object != heap_->free_space_map() &&
object != heap_->one_pointer_filler_map() &&
object != heap_->two_pointer_filler_map();
}
......
......@@ -3001,6 +3001,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array)
ALLOCATE_VARSIZE_MAP(BYTE_ARRAY_TYPE, byte_array)
ALLOCATE_VARSIZE_MAP(BYTECODE_ARRAY_TYPE, bytecode_array)
ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space)
#define ALLOCATE_EXTERNAL_ARRAY_MAP(Type, type, TYPE, ctype, size) \
......@@ -3065,6 +3066,12 @@ bool Heap::CreateInitialMaps() {
ByteArray* byte_array;
if (!AllocateByteArray(0, TENURED).To(&byte_array)) return false;
set_empty_byte_array(byte_array);
BytecodeArray* bytecode_array;
if (!AllocateBytecodeArray(0, nullptr).To(&bytecode_array)) {
return false;
}
set_empty_bytecode_array(bytecode_array);
}
#define ALLOCATE_EMPTY_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size) \
......@@ -3813,6 +3820,28 @@ AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
}
AllocationResult Heap::AllocateBytecodeArray(int length,
const byte* const raw_bytecodes) {
if (length < 0 || length > BytecodeArray::kMaxLength) {
v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true);
}
int size = BytecodeArray::SizeFor(length);
HeapObject* result;
{
AllocationResult allocation = AllocateRaw(size, OLD_SPACE, OLD_SPACE);
if (!allocation.To(&result)) return allocation;
}
result->set_map_no_write_barrier(bytecode_array_map());
BytecodeArray* instance = BytecodeArray::cast(result);
instance->set_length(length);
CopyBytes(instance->GetFirstBytecodeAddress(), raw_bytecodes, length);
return result;
}
void Heap::CreateFillerObjectAt(Address addr, int size) {
if (size == 0) return;
HeapObject* filler = HeapObject::FromAddress(addr);
......
......@@ -198,7 +198,10 @@ namespace internal {
V(Object, weak_stack_trace_list, WeakStackTraceList) \
V(Object, code_stub_context, CodeStubContext) \
V(JSObject, code_stub_exports_object, CodeStubExportsObject) \
V(FixedArray, interpreter_table, InterpreterTable)
V(FixedArray, interpreter_table, InterpreterTable) \
V(Map, bytecode_array_map, BytecodeArrayMap) \
V(BytecodeArray, empty_bytecode_array, EmptyBytecodeArray)
// Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \
......@@ -338,6 +341,7 @@ namespace internal {
// skip write barriers. This list is not complete and has omissions.
#define IMMORTAL_IMMOVABLE_ROOT_LIST(V) \
V(ByteArrayMap) \
V(BytecodeArrayMap) \
V(FreeSpaceMap) \
V(OnePointerFillerMap) \
V(TwoPointerFillerMap) \
......@@ -366,6 +370,7 @@ namespace internal {
V(OrderedHashTableMap) \
V(EmptyFixedArray) \
V(EmptyByteArray) \
V(EmptyBytecodeArray) \
V(EmptyDescriptorArray) \
V(ArgumentsMarker) \
V(SymbolMap) \
......@@ -1675,6 +1680,10 @@ class Heap {
MUST_USE_RESULT AllocationResult
AllocateByteArray(int length, PretenureFlag pretenure = NOT_TENURED);
// Allocates a bytecode array with given contents.
MUST_USE_RESULT AllocationResult
AllocateBytecodeArray(int length, const byte* raw_bytecodes);
// Copy the code and scope info part of the code object, but insert
// the provided data as the relocation information.
MUST_USE_RESULT AllocationResult
......
......@@ -42,6 +42,7 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
int>::Visit);
table_.Register(kVisitByteArray, &VisitByteArray);
table_.Register(kVisitBytecodeArray, &VisitBytecodeArray);
table_.Register(
kVisitSharedFunctionInfo,
......@@ -147,6 +148,8 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
table_.Register(kVisitBytecodeArray, &DataObjectVisitor::Visit);
table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
table_.Register(kVisitSeqOneByteString, &DataObjectVisitor::Visit);
......
......@@ -42,6 +42,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case BYTE_ARRAY_TYPE:
return kVisitByteArray;
case BYTECODE_ARRAY_TYPE:
return kVisitBytecodeArray;
case FREE_SPACE_TYPE:
return kVisitFreeSpace;
......
......@@ -29,6 +29,7 @@ class StaticVisitorBase : public AllStatic {
V(SeqTwoByteString) \
V(ShortcutCandidate) \
V(ByteArray) \
V(BytecodeArray) \
V(FreeSpace) \
V(FixedArray) \
V(FixedDoubleArray) \
......@@ -320,6 +321,10 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
}
INLINE(static int VisitBytecodeArray(Map* map, HeapObject* object)) {
return reinterpret_cast<BytecodeArray*>(object)->BytecodeArraySize();
}
INLINE(static int VisitFixedDoubleArray(Map* map, HeapObject* object)) {
int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
return FixedDoubleArray::SizeFor(length);
......
......@@ -42,6 +42,12 @@ const int Bytecodes::Size(Bytecode bytecode) {
}
#define CHECK_SIZE(Name, arg_count) \
STATIC_ASSERT(arg_count <= Bytecodes::kMaximumNumberOfArguments);
BYTECODE_LIST(CHECK_SIZE)
#undef CHECK_SIZE
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
return os << Bytecodes::ToString(bytecode);
}
......
......@@ -42,11 +42,16 @@ class Bytecodes {
// Returns the size of the bytecode including its arguments.
static const int Size(Bytecode bytecode);
// The maximum number of arguments across all bytecodes.
static const int kMaximumNumberOfArguments = 1;
// Maximum size of a bytecode and its arguments.
static const int kMaximumSize = 1 + kMaximumNumberOfArguments;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Bytecodes);
};
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode);
} // namespace interpreter
......
......@@ -30,6 +30,8 @@ class Interpreter {
void Initialize(bool create_heap_objects);
static bool MakeBytecode(CompilationInfo* info);
private:
// Bytecode handler generator functions.
#define DECLARE_BYTECODE_HANDLER_GENERATOR(Name, _) \
......
......@@ -70,6 +70,9 @@ void HeapObject::HeapObjectVerify() {
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify();
break;
case BYTECODE_ARRAY_TYPE:
BytecodeArray::cast(this)->BytecodeArrayVerify();
break;
case FREE_SPACE_TYPE:
FreeSpace::cast(this)->FreeSpaceVerify();
break;
......@@ -222,6 +225,12 @@ void ByteArray::ByteArrayVerify() {
}
void BytecodeArray::BytecodeArrayVerify() {
// TODO(oth): Walk bytecodes and immediate values to validate sanity.
CHECK(IsBytecodeArray());
}
void FreeSpace::FreeSpaceVerify() {
CHECK(IsFreeSpace());
}
......@@ -540,6 +549,8 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() {
VerifyObjectField(kFeedbackVectorOffset);
VerifyObjectField(kScopeInfoOffset);
VerifyObjectField(kInstanceClassNameOffset);
CHECK(function_data()->IsUndefined() || IsApiFunction() ||
HasBuiltinFunctionId() || HasBytecodeArray());
VerifyObjectField(kFunctionDataOffset);
VerifyObjectField(kScriptOffset);
VerifyObjectField(kDebugInfoOffset);
......
......@@ -648,6 +648,7 @@ bool Object::IsNumber() const {
TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
TYPE_CHECKER(BytecodeArray, BYTECODE_ARRAY_TYPE)
TYPE_CHECKER(FreeSpace, FREE_SPACE_TYPE)
......@@ -2924,6 +2925,7 @@ void SeededNumberDictionary::set_requires_slow_elements() {
CAST_ACCESSOR(AccessorInfo)
CAST_ACCESSOR(ArrayList)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(BytecodeArray)
CAST_ACCESSOR(Cell)
CAST_ACCESSOR(Code)
CAST_ACCESSOR(CodeCacheHashTable)
......@@ -3625,6 +3627,27 @@ Address ByteArray::GetDataStartAddress() {
}
byte BytecodeArray::get(int index) {
DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
}
void BytecodeArray::set(int index, byte value) {
DCHECK(index >= 0 && index < this->length());
WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
}
INT_ACCESSORS(BytecodeArray, frame_size, kFrameSizeOffset)
INT_ACCESSORS(BytecodeArray, number_of_locals, kNumberOfLocalsOffset)
Address BytecodeArray::GetFirstBytecodeAddress() {
return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
}
uint8_t* ExternalUint8ClampedArray::external_uint8_clamped_pointer() {
return reinterpret_cast<uint8_t*>(external_pointer());
}
......@@ -4113,6 +4136,9 @@ int HeapObject::SizeFromMap(Map* map) {
if (instance_type == BYTE_ARRAY_TYPE) {
return reinterpret_cast<ByteArray*>(this)->ByteArraySize();
}
if (instance_type == BYTECODE_ARRAY_TYPE) {
return reinterpret_cast<BytecodeArray*>(this)->BytecodeArraySize();
}
if (instance_type == FREE_SPACE_TYPE) {
return reinterpret_cast<FreeSpace*>(this)->nobarrier_size();
}
......@@ -5515,6 +5541,17 @@ BuiltinFunctionId SharedFunctionInfo::builtin_function_id() {
}
bool SharedFunctionInfo::HasBytecodeArray() {
return function_data()->IsBytecodeArray();
}
BytecodeArray* SharedFunctionInfo::bytecode_array() {
DCHECK(HasBytecodeArray());
return BytecodeArray::cast(function_data());
}
int SharedFunctionInfo::ic_age() {
return ICAgeBits::decode(counters());
}
......
......@@ -7,6 +7,7 @@
#include "src/disasm.h"
#include "src/disassembler.h"
#include "src/heap/objects-visiting.h"
#include "src/interpreter/bytecodes.h"
#include "src/jsregexp.h"
#include "src/ostreams.h"
......@@ -72,6 +73,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayPrint(os);
break;
case BYTECODE_ARRAY_TYPE:
BytecodeArray::cast(this)->BytecodeArrayPrint(os);
break;
case FREE_SPACE_TYPE:
FreeSpace::cast(this)->FreeSpacePrint(os);
break;
......@@ -201,6 +205,11 @@ void ByteArray::ByteArrayPrint(std::ostream& os) { // NOLINT
}
void BytecodeArray::BytecodeArrayPrint(std::ostream& os) { // NOLINT
Disassemble(os);
}
void FreeSpace::FreeSpacePrint(std::ostream& os) { // NOLINT
os << "free space, size " << Size();
}
......@@ -817,6 +826,9 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
os << "\n - optimized_code_map = " << Brief(optimized_code_map());
os << "\n - feedback_vector = ";
feedback_vector()->TypeFeedbackVectorPrint(os);
if (HasBytecodeArray()) {
os << "\n - bytecode_array = " << bytecode_array();
}
os << "\n";
}
......
......@@ -31,6 +31,7 @@
#include "src/heap/objects-visiting-inl.h"
#include "src/hydrogen.h"
#include "src/ic/ic.h"
#include "src/interpreter/bytecodes.h"
#include "src/log.h"
#include "src/lookup.h"
#include "src/macro-assembler.h"
......@@ -1273,6 +1274,9 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case BYTE_ARRAY_TYPE:
os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
break;
case BYTECODE_ARRAY_TYPE:
os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
break;
case FREE_SPACE_TYPE:
os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
break;
......@@ -1499,6 +1503,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case FLOAT32X4_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
case BYTECODE_ARRAY_TYPE:
case FREE_SPACE_TYPE:
break;
......@@ -11612,6 +11617,29 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
#endif // ENABLE_DISASSEMBLER
void BytecodeArray::Disassemble(std::ostream& os) {
os << "Frame size " << frame_size()
<< ", number of locals = " << number_of_locals() << "\n";
Vector<char> buf = Vector<char>::New(50);
int bytecode_size = 0;
for (int i = 0; i < this->length(); i += bytecode_size) {
interpreter::Bytecode bytecode = static_cast<interpreter::Bytecode>(get(i));
bytecode_size = interpreter::Bytecodes::Size(bytecode);
SNPrintF(buf, "%p : ", GetFirstBytecodeAddress() + i);
os << buf.start();
for (int j = 0; j < bytecode_size; j++) {
SNPrintF(buf, "%02x ", get(i + j));
os << buf.start();
}
for (int j = bytecode_size; j < interpreter::Bytecodes::kMaximumSize; j++) {
os << " ";
}
os << bytecode;
}
}
// static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
DCHECK(capacity >= 0);
......
......@@ -73,6 +73,7 @@
// - JSFunctionProxy
// - FixedArrayBase
// - ByteArray
// - BytecodeArray
// - FixedArray
// - DescriptorArray
// - HashTable
......@@ -389,6 +390,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(MUTABLE_HEAP_NUMBER_TYPE) \
V(FOREIGN_TYPE) \
V(BYTE_ARRAY_TYPE) \
V(BYTECODE_ARRAY_TYPE) \
V(FREE_SPACE_TYPE) \
/* Note: the order of these external array */ \
/* types is relied upon in */ \
......@@ -685,6 +687,7 @@ enum InstanceType {
FLOAT32X4_TYPE, // FIRST_SIMD_TYPE, LAST_SIMD_TYPE
FOREIGN_TYPE,
BYTE_ARRAY_TYPE,
BYTECODE_ARRAY_TYPE,
FREE_SPACE_TYPE,
EXTERNAL_INT8_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
EXTERNAL_UINT8_ARRAY_TYPE,
......@@ -951,6 +954,7 @@ template <class C> inline bool Is(Object* obj);
V(FixedFloat64Array) \
V(FixedUint8ClampedArray) \
V(ByteArray) \
V(BytecodeArray) \
V(FreeSpace) \
V(JSReceiver) \
V(JSObject) \
......@@ -4233,6 +4237,53 @@ class ByteArray: public FixedArrayBase {
};
// BytecodeArray represents a sequence of interpreter bytecodes.
class BytecodeArray : public FixedArrayBase {
public:
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length);
}
// Setter and getter
inline byte get(int index);
inline void set(int index, byte value);
// Returns data start address.
inline Address GetFirstBytecodeAddress();
// Accessors for frame size and the number of locals
inline int frame_size() const;
inline void set_frame_size(int value);
inline int number_of_locals() const;
inline void set_number_of_locals(int value);
DECLARE_CAST(BytecodeArray)
// Dispatched behavior.
inline int BytecodeArraySize() { return SizeFor(this->length()); }
DECLARE_PRINTER(BytecodeArray)
DECLARE_VERIFIER(BytecodeArray)
void Disassemble(std::ostream& os);
// Layout description.
static const int kFrameSizeOffset = FixedArrayBase::kHeaderSize;
static const int kNumberOfLocalsOffset = kFrameSizeOffset + kIntSize;
static const int kHeaderSize = kNumberOfLocalsOffset + kIntSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
// Maximal memory consumption for a single BytecodeArray.
static const int kMaxSize = 512 * MB;
// Maximal length of a single BytecodeArray.
static const int kMaxLength = kMaxSize - kHeaderSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArray);
};
// FreeSpace are fixed-size free memory blocks used by the heap and GC.
// They look like heap objects (are heap object tagged and have a map) so that
// the heap remains iterable. They have a size and a next pointer.
......@@ -6646,8 +6697,10 @@ class SharedFunctionInfo: public HeapObject {
DECL_ACCESSORS(instance_class_name, Object)
// [function data]: This field holds some additional data for function.
// Currently it either has FunctionTemplateInfo to make benefit the API
// or Smi identifying a builtin function.
// Currently it has one of:
// - a FunctionTemplateInfo to make benefit the API [IsApiFunction()].
// - a Smi identifying a builtin function [HasBuiltinFunctionId()].
// - a BytecodeArray for the interpreter [HasBytecodeArray()].
// In the long run we don't want all functions to have this field but
// we can fix that when we have a better model for storing hidden data
// on objects.
......@@ -6657,6 +6710,8 @@ class SharedFunctionInfo: public HeapObject {
inline FunctionTemplateInfo* get_api_func_data();
inline bool HasBuiltinFunctionId();
inline BuiltinFunctionId builtin_function_id();
inline bool HasBytecodeArray();
inline BytecodeArray* bytecode_array();
// [script info]: Script from which the function originates.
DECL_ACCESSORS(script, Object)
......
......@@ -276,6 +276,7 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
case ACCESSOR_PAIR_TYPE:
case FIXED_ARRAY_TYPE:
case BYTE_ARRAY_TYPE:
case BYTECODE_ARRAY_TYPE:
case FOREIGN_TYPE:
case SCRIPT_TYPE:
case CODE_TYPE:
......
......@@ -567,6 +567,50 @@ TEST(DeleteWeakGlobalHandle) {
}
TEST(BytecodeArray) {
static const uint8_t kRawBytes[] = {0xc3, 0x7e, 0xa5, 0x5a};
static const int kRawBytesSize = sizeof(kRawBytes);
static const int kFrameSize = 32;
static const int kNumberOfLocals = 20;
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
// Allocate and initialize BytecodeArray
Handle<BytecodeArray> array =
factory->NewBytecodeArray(kRawBytesSize, kRawBytes);
array->set_frame_size(kFrameSize);
array->set_number_of_locals(kNumberOfLocals);
CHECK(array->IsBytecodeArray());
CHECK_EQ(array->length(), (int)sizeof(kRawBytes));
CHECK_LE(array->address(), array->GetFirstBytecodeAddress());
CHECK_GE(array->address() + array->BytecodeArraySize(),
array->GetFirstBytecodeAddress() + array->length());
for (int i = 0; i < kRawBytesSize; i++) {
CHECK_EQ(array->GetFirstBytecodeAddress()[i], kRawBytes[i]);
CHECK_EQ(array->get(i), kRawBytes[i]);
}
// Full garbage collection
heap->CollectAllGarbage();
// BytecodeArray should survive
CHECK_EQ(array->length(), kRawBytesSize);
CHECK_EQ(array->number_of_locals(), kNumberOfLocals);
CHECK_EQ(array->frame_size(), kFrameSize);
for (int i = 0; i < kRawBytesSize; i++) {
CHECK_EQ(array->get(i), kRawBytes[i]);
CHECK_EQ(array->GetFirstBytecodeAddress()[i], kRawBytes[i]);
}
}
static const char* not_so_random_string_table[] = {
"abstract",
"boolean",
......
This diff is collapsed.
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