Commit 02100d56 authored by Florian Sattler's avatar Florian Sattler Committed by Commit Bot

Compress memory by reordering members and storing bits in pointers.

Store the bits of a small type into the lower bits
of a pointer type that are free due to alignment.
Furthermore, reordering of members to reduce size of some classes.

Change-Id: I3c619cb74053f64995ea7d0cb395e8edda604f18
Reviewed-on: https://chromium-review.googlesource.com/c/1273019
Commit-Queue: Florian Sattler <sattlerf@google.com>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56726}
parent 6cde186b
......@@ -67,45 +67,43 @@ class PerThreadAssertData final {
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
};
template <PerThreadAssertType kType, bool kAllow>
PerThreadAssertScope<kType, kAllow>::PerThreadAssertScope()
: data_(PerThreadAssertData::GetCurrent()) {
if (data_ == nullptr) {
data_ = new PerThreadAssertData();
PerThreadAssertData::SetCurrent(data_);
PerThreadAssertScope<kType, kAllow>::PerThreadAssertScope() {
PerThreadAssertData* current_data = PerThreadAssertData::GetCurrent();
if (current_data == nullptr) {
current_data = new PerThreadAssertData();
PerThreadAssertData::SetCurrent(current_data);
}
data_->IncrementLevel();
old_state_ = data_->Get(kType);
data_->Set(kType, kAllow);
data_and_old_state_.update(current_data, current_data->Get(kType));
current_data->IncrementLevel();
current_data->Set(kType, kAllow);
}
template <PerThreadAssertType kType, bool kAllow>
PerThreadAssertScope<kType, kAllow>::~PerThreadAssertScope() {
if (data_ == nullptr) return;
if (data() == nullptr) return;
Release();
}
template <PerThreadAssertType kType, bool kAllow>
void PerThreadAssertScope<kType, kAllow>::Release() {
DCHECK_NOT_NULL(data_);
data_->Set(kType, old_state_);
if (data_->DecrementLevel()) {
auto* current_data = data();
DCHECK_NOT_NULL(current_data);
current_data->Set(kType, old_state());
if (current_data->DecrementLevel()) {
PerThreadAssertData::SetCurrent(nullptr);
delete data_;
delete current_data;
}
data_ = nullptr;
set_data(nullptr);
}
// static
template <PerThreadAssertType kType, bool kAllow>
bool PerThreadAssertScope<kType, kAllow>::IsAllowed() {
PerThreadAssertData* data = PerThreadAssertData::GetCurrent();
return data == nullptr || data->Get(kType);
PerThreadAssertData* current_data = PerThreadAssertData::GetCurrent();
return current_data == nullptr || current_data->Get(kType);
}
template <PerIsolateAssertType kType, bool kAllow>
class PerIsolateAssertScope<kType, kAllow>::DataBit
: public BitField<bool, kType, 1> {};
......
......@@ -6,8 +6,10 @@
#define V8_ASSERT_SCOPE_H_
#include <stdint.h>
#include "src/base/macros.h"
#include "src/globals.h"
#include "src/pointer-with-payload.h"
namespace v8 {
namespace internal {
......@@ -16,6 +18,10 @@ namespace internal {
class Isolate;
class PerThreadAssertData;
template <>
struct PointerWithPayloadTraits<PerThreadAssertData> {
static constexpr int value = 1;
};
enum PerThreadAssertType {
HEAP_ALLOCATION_ASSERT,
......@@ -45,8 +51,21 @@ class PerThreadAssertScope {
void Release();
private:
PerThreadAssertData* data_;
bool old_state_;
PointerWithPayload<PerThreadAssertData, bool, 1> data_and_old_state_;
V8_INLINE void set_data(PerThreadAssertData* data) {
data_and_old_state_.SetPointer(data);
}
V8_INLINE PerThreadAssertData* data() const {
return data_and_old_state_.GetPointer();
}
V8_INLINE void set_old_state(bool old_state) {
return data_and_old_state_.SetPayload(old_state);
}
V8_INLINE bool old_state() const { return data_and_old_state_.GetPayload(); }
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
};
......
......@@ -326,7 +326,7 @@ ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
}
bool LiteralProperty::NeedsSetFunctionName() const {
return is_computed_name_ && (value_->IsAnonymousFunctionDefinition() ||
return is_computed_name() && (value_->IsAnonymousFunctionDefinition() ||
value_->IsConciseMethodDefinition() ||
value_->IsAccessorFunctionDefinition());
}
......
......@@ -1261,19 +1261,20 @@ class AggregateLiteral : public MaterializedLiteral {
// Common supertype for ObjectLiteralProperty and ClassLiteralProperty
class LiteralProperty : public ZoneObject {
public:
Expression* key() const { return key_; }
Expression* key() const { return key_and_is_computed_name_.GetPointer(); }
Expression* value() const { return value_; }
bool is_computed_name() const { return is_computed_name_; }
bool is_computed_name() const {
return key_and_is_computed_name_.GetPayload();
}
bool NeedsSetFunctionName() const;
protected:
LiteralProperty(Expression* key, Expression* value, bool is_computed_name)
: key_(key), value_(value), is_computed_name_(is_computed_name) {}
: key_and_is_computed_name_(key, is_computed_name), value_(value) {}
Expression* key_;
PointerWithPayload<Expression, bool, 1> key_and_is_computed_name_;
Expression* value_;
bool is_computed_name_;
};
// Property is used for passing information
......
......@@ -150,20 +150,19 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type)
}
Scope::Snapshot::Snapshot(Scope* scope)
: outer_scope_(scope),
: outer_scope_and_calls_eval_(scope, scope->scope_calls_eval_),
top_inner_scope_(scope->inner_scope_),
top_unresolved_(scope->unresolved_list_.first()),
top_local_(scope->GetClosureScope()->locals_.end()),
top_decl_(scope->GetClosureScope()->decls_.end()),
outer_scope_calls_eval_(scope->scope_calls_eval_) {
top_decl_(scope->GetClosureScope()->decls_.end()) {
// Reset in order to record eval calls during this Snapshot's lifetime.
outer_scope_->scope_calls_eval_ = false;
outer_scope_and_calls_eval_.GetPointer()->scope_calls_eval_ = false;
}
Scope::Snapshot::~Snapshot() {
// Restore previous calls_eval bit if needed.
if (outer_scope_calls_eval_) {
outer_scope_->scope_calls_eval_ = true;
if (outer_scope_and_calls_eval_.GetPayload()) {
outer_scope_and_calls_eval_->scope_calls_eval_ = true;
}
}
......@@ -864,8 +863,8 @@ Variable* Scope::Declare(Zone* zone, const AstRawString* name,
}
void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const {
DCHECK_EQ(new_parent, outer_scope_->inner_scope_);
DCHECK_EQ(new_parent->outer_scope_, outer_scope_);
DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_);
DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer());
DCHECK_EQ(new_parent, new_parent->GetClosureScope());
DCHECK_NULL(new_parent->inner_scope_);
DCHECK(new_parent->unresolved_list_.is_empty());
......@@ -891,6 +890,7 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const {
new_parent->sibling_ = top_inner_scope_;
}
Scope* outer_scope_ = outer_scope_and_calls_eval_.GetPointer();
if (outer_scope_->unresolved_list_.first() != top_unresolved_) {
// If the marked VariableProxy (snapshoted) is not the first, we need to
// find it and move all VariableProxys up to that point into the new_parent,
......
......@@ -10,6 +10,7 @@
#include "src/base/hashmap.h"
#include "src/globals.h"
#include "src/objects.h"
#include "src/pointer-with-payload.h"
#include "src/zone/zone.h"
namespace v8 {
......@@ -77,6 +78,13 @@ class SloppyBlockFunctionMap : public ZoneHashMap {
int count_;
};
class Scope;
template <>
struct PointerWithPayloadTraits<Scope> {
static constexpr int value = 1;
};
// Global invariants after AST construction: Each reference (i.e. identifier)
// to a JavaScript variable (including global properties) is represented by a
// VariableProxy node. Immediately after AST construction and before variable
......@@ -120,12 +128,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
void Reparent(DeclarationScope* new_parent) const;
private:
Scope* outer_scope_;
PointerWithPayload<Scope, bool, 1> outer_scope_and_calls_eval_;
Scope* top_inner_scope_;
VariableProxy* top_unresolved_;
base::ThreadedList<Variable>::Iterator top_local_;
base::ThreadedList<Declaration>::Iterator top_decl_;
const bool outer_scope_calls_eval_;
};
enum class DeserializationMode { kIncludingVariables, kScopesOnly };
......@@ -947,9 +954,6 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
void SetDefaults();
// If the scope is a function scope, this is the function kind.
const FunctionKind function_kind_;
bool has_simple_parameters_ : 1;
// This scope contains an "use asm" annotation.
bool asm_module_ : 1;
......@@ -969,6 +973,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
bool is_skipped_function_ : 1;
bool has_inferred_function_name_ : 1;
// If the scope is a function scope, this is the function kind.
const FunctionKind function_kind_;
// Parameter list in source order.
ZonePtrList<Variable> params_;
// Map of function names to lists of functions defined in sloppy blocks
......
......@@ -502,10 +502,10 @@ class GlobalHandles::NodeIterator {
GlobalHandles::GlobalHandles(Isolate* isolate)
: isolate_(isolate),
number_of_global_handles_(0),
first_block_(nullptr),
first_used_block_(nullptr),
first_free_(nullptr),
number_of_global_handles_(0),
post_gc_processing_count_(0),
number_of_phantom_handle_resets_(0) {}
......
......@@ -208,9 +208,6 @@ class GlobalHandles {
Isolate* isolate_;
// Field always containing the number of handles to global objects.
int number_of_global_handles_;
// List of all allocated node blocks.
NodeBlock* first_block_;
......@@ -224,6 +221,9 @@ class GlobalHandles {
// is accessed, some of the objects may have been promoted already.
std::vector<Node*> new_space_nodes_;
// Field always containing the number of handles to global objects.
int number_of_global_handles_;
int post_gc_processing_count_;
size_t number_of_phantom_handle_resets_;
......
......@@ -45,7 +45,7 @@ void FuncNameInferrer::PushVariableName(const AstRawString* name) {
void FuncNameInferrer::RemoveAsyncKeywordFromEnd() {
if (IsOpen()) {
CHECK_GT(names_stack_.size(), 0);
CHECK(names_stack_.back().name->IsOneByteEqualTo("async"));
CHECK(names_stack_.back().name()->IsOneByteEqualTo("async"));
names_stack_.pop_back();
}
}
......@@ -65,15 +65,15 @@ const AstConsString* FuncNameInferrer::MakeNameFromStack() {
// Advance the iterator to be able to peek the next value.
auto current = it++;
// Skip consecutive variable declarations.
if (it != names_stack_.end() && current->type == kVariableName &&
it->type == kVariableName) {
if (it != names_stack_.end() && current->type() == kVariableName &&
it->type() == kVariableName) {
continue;
}
// Add name. Separate names with ".".
if (!result->IsEmpty()) {
result->AddString(zone(), ast_value_factory_->dot_string());
}
result->AddString(zone(), current->name);
result->AddString(zone(), current->name());
}
return result;
}
......
......@@ -5,6 +5,7 @@
#ifndef V8_PARSING_FUNC_NAME_INFERRER_H_
#define V8_PARSING_FUNC_NAME_INFERRER_H_
#include "src/pointer-with-payload.h"
#include "src/zone/zone-chunk-list.h"
#include "src/zone/zone.h"
......@@ -18,6 +19,11 @@ class FunctionLiteral;
enum class InferName { kYes, kNo };
template <>
struct PointerWithPayloadTraits<AstRawString> {
static constexpr int value = 2;
};
// FuncNameInferrer is a stateful class that is used to perform name
// inference for anonymous functions during static analysis of source code.
// Inference is performed in cases when an anonymous function is assigned
......@@ -80,15 +86,20 @@ class FuncNameInferrer : public ZoneObject {
}
private:
enum NameType {
enum NameType : uint8_t {
kEnclosingConstructorName,
kLiteralName,
kVariableName
};
struct Name {
Name(const AstRawString* name, NameType type) : name(name), type(type) {}
const AstRawString* name;
NameType type;
Name(const AstRawString* name, NameType type)
: name_and_type_(name, type) {}
PointerWithPayload<const AstRawString, NameType, 2> name_and_type_;
inline const AstRawString* name() const {
return name_and_type_.GetPointer();
}
inline NameType type() const { return name_and_type_.GetPayload(); }
};
void Enter() { entries_stack_.push_back(names_stack_.size()); }
......
......@@ -23,6 +23,7 @@
#include "src/parsing/func-name-inferrer.h"
#include "src/parsing/scanner.h"
#include "src/parsing/token.h"
#include "src/pointer-with-payload.h"
#include "src/zone/zone-chunk-list.h"
namespace v8 {
......@@ -421,20 +422,19 @@ class ParserBase {
class FunctionOrEvalRecordingScope {
public:
explicit FunctionOrEvalRecordingScope(FunctionState* state)
: state_(state) {
prev_value_ = state->contains_function_or_eval_;
: state_and_prev_value_(state, state->contains_function_or_eval_) {
state->contains_function_or_eval_ = false;
}
~FunctionOrEvalRecordingScope() {
bool found = state_->contains_function_or_eval_;
bool found = state_and_prev_value_->contains_function_or_eval_;
if (!found) {
state_->contains_function_or_eval_ = prev_value_;
state_and_prev_value_->contains_function_or_eval_ =
state_and_prev_value_.GetPayload();
}
}
private:
FunctionState* state_;
bool prev_value_;
PointerWithPayload<FunctionState, bool, 1> state_and_prev_value_;
};
private:
......
......@@ -840,7 +840,9 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
(info->function_literal_id() - 1) - GetLastFunctionLiteralId());
for (auto p : formals.params) {
if (p->pattern != nullptr) reindexer.Reindex(p->pattern);
if (p->initializer != nullptr) reindexer.Reindex(p->initializer);
if (p->initializer() != nullptr) {
reindexer.Reindex(p->initializer());
}
}
ResetFunctionLiteralId();
SkipFunctionLiterals(info->function_literal_id() - 1);
......@@ -2897,19 +2899,20 @@ Block* Parser::BuildParameterInitializationBlock(
descriptor.initialization_pos = parameter->pattern->position();
Expression* initial_value =
factory()->NewVariableProxy(parameters.scope->parameter(index));
if (parameter->initializer != nullptr) {
if (parameter->initializer() != nullptr) {
// IS_UNDEFINED($param) ? initializer : $param
// Ensure initializer is rewritten
RewriteParameterInitializer(parameter->initializer);
RewriteParameterInitializer(parameter->initializer());
auto condition = factory()->NewCompareOperation(
Token::EQ_STRICT,
factory()->NewVariableProxy(parameters.scope->parameter(index)),
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
initial_value = factory()->NewConditional(
condition, parameter->initializer, initial_value, kNoSourcePosition);
descriptor.initialization_pos = parameter->initializer->position();
initial_value =
factory()->NewConditional(condition, parameter->initializer(),
initial_value, kNoSourcePosition);
descriptor.initialization_pos = parameter->initializer()->position();
}
Scope* param_scope = scope();
......
......@@ -16,6 +16,7 @@
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
#include "src/pointer-with-payload.h"
#include "src/zone/zone-chunk-list.h"
namespace v8 {
......@@ -87,20 +88,25 @@ struct ParserFormalParameters : FormalParametersBase {
Expression* initializer, int position,
int initializer_end_position, bool is_rest)
: name(name),
name_and_is_rest(initializer, is_rest),
pattern(pattern),
initializer(initializer),
position(position),
initializer_end_position(initializer_end_position),
is_rest(is_rest) {}
initializer_end_position(initializer_end_position) {}
const AstRawString* name;
PointerWithPayload<Expression, bool, 1> name_and_is_rest;
Expression* pattern;
Expression* initializer;
Expression* initializer() const { return name_and_is_rest.GetPointer(); }
int position;
int initializer_end_position;
bool is_rest;
inline bool is_rest() const { return name_and_is_rest.GetPayload(); }
Parameter* next_parameter = nullptr;
bool is_simple() const {
return pattern->IsVariableProxy() && initializer == nullptr && !is_rest;
return pattern->IsVariableProxy() && initializer() == nullptr &&
!is_rest();
}
Parameter** next() { return &next_parameter; }
......@@ -924,7 +930,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
DeclarationScope* scope = parameters->scope;
if (!is_simple) scope->SetHasNonSimpleParameters();
for (auto parameter : parameters->params) {
bool is_optional = parameter->initializer != nullptr;
bool is_optional = parameter->initializer() != nullptr;
// If the parameter list is simple, declare the parameters normally with
// their names. If the parameter list is not simple, declare a temporary
// for each parameter - the corresponding named variable is declared by
......@@ -937,7 +943,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
scope->DeclareParameter(
is_simple ? parameter->name : ast_value_factory()->empty_string(),
is_simple ? VariableMode::kVar : VariableMode::kTemporary,
is_optional, parameter->is_rest, ast_value_factory(),
is_optional, parameter->is_rest(), ast_value_factory(),
parameter->position);
}
}
......
......@@ -38,8 +38,7 @@ class PreParsedScopeDataBuilder::ByteData
public PreParsedScopeByteDataConstants {
public:
explicit ByteData(Zone* zone)
: backing_store_(zone), free_quarters_in_last_byte_(0) {}
: free_quarters_in_last_byte_(0), backing_store_(zone) {}
void WriteUint32(uint32_t data);
void WriteUint8(uint8_t data);
void WriteQuarter(uint8_t data);
......@@ -58,8 +57,8 @@ class PreParsedScopeDataBuilder::ByteData
ZoneChunkList<uint8_t>::iterator end() { return backing_store_.end(); }
private:
ZoneChunkList<uint8_t> backing_store_;
uint8_t free_quarters_in_last_byte_;
ZoneChunkList<uint8_t> backing_store_;
};
template <class Data>
......
......@@ -18,13 +18,13 @@ class Processor final : public AstVisitor<Processor> {
Processor(uintptr_t stack_limit, DeclarationScope* closure_scope,
Variable* result, AstValueFactory* ast_value_factory)
: result_(result),
result_assigned_(false),
replacement_(nullptr),
is_set_(false),
breakable_(false),
zone_(ast_value_factory->zone()),
closure_scope_(closure_scope),
factory_(ast_value_factory, ast_value_factory->zone()) {
factory_(ast_value_factory, ast_value_factory->zone()),
result_assigned_(false),
is_set_(false),
breakable_(false) {
DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
InitializeAstVisitor(stack_limit);
}
......@@ -32,13 +32,13 @@ class Processor final : public AstVisitor<Processor> {
Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
AstValueFactory* ast_value_factory)
: result_(result),
result_assigned_(false),
replacement_(nullptr),
is_set_(false),
breakable_(false),
zone_(ast_value_factory->zone()),
closure_scope_(closure_scope),
factory_(ast_value_factory, zone_) {
factory_(ast_value_factory, zone_),
result_assigned_(false),
is_set_(false),
breakable_(false) {
DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
InitializeAstVisitor(parser->stack_limit());
}
......@@ -64,24 +64,10 @@ class Processor final : public AstVisitor<Processor> {
private:
Variable* result_;
// We are not tracking result usage via the result_'s use
// counts (we leave the accurate computation to the
// usage analyzer). Instead we simple remember if
// there was ever an assignment to result_.
bool result_assigned_;
// When visiting a node, we "return" a replacement for that node in
// [replacement_]. In many cases this will just be the original node.
Statement* replacement_;
// To avoid storing to .result all the time, we eliminate some of
// the stores by keeping track of whether or not we're sure .result
// will be overwritten anyway. This is a bit more tricky than what I
// was hoping for.
bool is_set_;
bool breakable_;
class BreakableScope final {
public:
explicit BreakableScope(Processor* processor, bool breakable = true)
......@@ -108,6 +94,20 @@ class Processor final : public AstVisitor<Processor> {
void VisitIterationStatement(IterationStatement* stmt);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
// We are not tracking result usage via the result_'s use
// counts (we leave the accurate computation to the
// usage analyzer). Instead we simple remember if
// there was ever an assignment to result_.
bool result_assigned_;
// To avoid storing to .result all the time, we eliminate some of
// the stores by keeping track of whether or not we're sure .result
// will be overwritten anyway. This is a bit more tricky than what I
// was hoping for.
bool is_set_;
bool breakable_;
};
......
......@@ -15,6 +15,7 @@
#include "src/globals.h"
#include "src/message-template.h"
#include "src/parsing/token.h"
#include "src/pointer-with-payload.h"
#include "src/unicode-decoder.h"
#include "src/unicode.h"
......@@ -507,8 +508,8 @@ class Scanner {
Vector<byte> backing_store_;
int position_;
bool is_one_byte_;
bool is_used_;
bool is_one_byte_ : 1;
bool is_used_ : 1;
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
......@@ -518,17 +519,18 @@ class Scanner {
class LiteralScope {
public:
explicit LiteralScope(Scanner* scanner)
: buffer_(&scanner->next().literal_chars), complete_(false) {
buffer_->Start();
: buffer_and_complete_(&scanner->next().literal_chars, false) {
buffer()->Start();
}
~LiteralScope() {
if (!complete_) buffer_->Drop();
if (!buffer_and_complete_.GetPayload()) buffer()->Drop();
}
void Complete() { complete_ = true; }
void Complete() { buffer_and_complete_.SetPayload(true); }
private:
LiteralBuffer* buffer_;
bool complete_;
LiteralBuffer* buffer() const { return buffer_and_complete_.GetPointer(); }
PointerWithPayload<LiteralBuffer, bool, 1> buffer_and_complete_;
};
// The current and look-ahead token.
......@@ -537,9 +539,9 @@ class Scanner {
LiteralBuffer literal_chars;
LiteralBuffer raw_literal_chars;
Token::Value token = Token::UNINITIALIZED;
Token::Value contextual_token = Token::UNINITIALIZED;
MessageTemplate invalid_template_escape_message = MessageTemplate::kNone;
Location invalid_template_escape_location;
Token::Value contextual_token = Token::UNINITIALIZED;
uint32_t smi_value_ = 0;
bool after_line_terminator = false;
};
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_POINTER_WITH_PAYLOAD_H_
#define V8_POINTER_WITH_PAYLOAD_H_
#include <cstdint>
#include <type_traits>
#include "include/v8config.h"
#include "src/base/logging.h"
namespace v8 {
namespace internal {
template <typename PointerType>
struct PointerWithPayloadTraits {
static constexpr int value =
alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1;
};
// PointerWithPayload combines a PointerType* an a small PayloadType into
// one. The bits of the storage type get packed into the lower bits of the
// pointer that are free due to alignment. The user needs to specify how many
// bits are needed to store the PayloadType, allowing Types that by default are
// larger to be stored.
//
// Example:
// PointerWithPayload<int *, bool, 1> data_and_flag;
//
// Here we store a bool that needs 1 bit of storage state into the lower bits
// of int *, which points to some int data;
template <typename PointerType, typename PayloadType, int NumPayloadBits>
class PointerWithPayload {
// We have log2(ptr alignment) kAvailBits free to use
static constexpr int kAvailBits = PointerWithPayloadTraits<
typename std::remove_const<PointerType>::type>::value;
static_assert(
kAvailBits >= NumPayloadBits,
"Ptr does not have sufficient alignment for the selected amount of "
"storage bits.");
static constexpr uintptr_t kPayloadMask = (uintptr_t{1} << kAvailBits) - 1;
static constexpr uintptr_t kPointerMask = ~kPayloadMask;
public:
PointerWithPayload() {}
explicit PointerWithPayload(PointerType* pointer)
: pointer_(reinterpret_cast<uintptr_t>(pointer)) {
DCHECK_EQ(GetPointer(), pointer);
DCHECK_EQ(GetPayload(), static_cast<PayloadType>(0));
}
explicit PointerWithPayload(PayloadType payload)
: pointer_(static_cast<uintptr_t>(payload)) {
DCHECK_EQ(GetPointer(), nullptr);
DCHECK_EQ(GetPayload(), payload);
}
PointerWithPayload(PointerType* pointer, PayloadType payload) {
update(pointer, payload);
}
V8_INLINE PointerType* GetPointer() const {
return reinterpret_cast<PointerType*>(pointer_ & kPointerMask);
}
V8_INLINE PointerType* operator->() const { return GetPointer(); }
V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) {
pointer_ = reinterpret_cast<uintptr_t>(new_pointer) |
static_cast<uintptr_t>(new_payload);
DCHECK_EQ(GetPayload(), new_payload);
DCHECK_EQ(GetPointer(), new_pointer);
}
V8_INLINE void SetPointer(PointerType* newptr) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(newptr) & kPayloadMask, 0);
pointer_ = reinterpret_cast<uintptr_t>(newptr) | (pointer_ & kPayloadMask);
DCHECK_EQ(GetPointer(), newptr);
}
V8_INLINE PayloadType GetPayload() const {
return static_cast<PayloadType>(pointer_ & kPayloadMask);
}
V8_INLINE void SetPayload(PayloadType new_payload) {
DCHECK_EQ(new_payload & kPayloadMask, new_payload);
pointer_ = (pointer_ & kPointerMask) | static_cast<uintptr_t>(new_payload);
DCHECK_EQ(GetPayload(), new_payload);
}
private:
uintptr_t pointer_ = 0;
};
} // namespace internal
} // namespace v8
#endif // V8_POINTER_WITH_PAYLOAD_H_
......@@ -159,10 +159,10 @@ class ValueSerializer {
Isolate* const isolate_;
v8::ValueSerializer::Delegate* const delegate_;
bool treat_array_buffer_views_as_host_objects_ = false;
uint8_t* buffer_ = nullptr;
size_t buffer_size_ = 0;
size_t buffer_capacity_ = 0;
bool treat_array_buffer_views_as_host_objects_ = false;
bool out_of_memory_ = false;
Zone zone_;
......
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