Commit ec7249f2 authored by Creddy's avatar Creddy Committed by Commit Bot

[runtime][parser] Make CompileTimeValue a struct for type safety.

This promotes CompileTimeValue as a seperate struct instead of FixedArray.
This reduces the heap object size by one word (size field of FixedArray)

Change-Id: Id09d9e04c4c1a98aa9fa53b1a44ec17e8cd06f34
Bug: v8:7787, chromium:818642
Reviewed-on: https://chromium-review.googlesource.com/1119918
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54135}
parent 4dbbe078
......@@ -1518,8 +1518,6 @@ v8_source_set("v8_base") {
"src/ast/ast-value-factory.h",
"src/ast/ast.cc",
"src/ast/ast.h",
"src/ast/compile-time-value.cc",
"src/ast/compile-time-value.h",
"src/ast/context-slot-cache.cc",
"src/ast/context-slot-cache.h",
"src/ast/modules.cc",
......
......@@ -7,7 +7,6 @@
#include <cmath> // For isfinite.
#include <vector>
#include "src/ast/compile-time-value.h"
#include "src/ast/prettyprinter.h"
#include "src/ast/scopes.h"
#include "src/base/hashmap.h"
......@@ -114,6 +113,13 @@ bool Expression::IsTheHoleLiteral() const {
return IsLiteral() && AsLiteral()->type() == Literal::kTheHole;
}
bool Expression::IsCompileTimeValue() {
if (IsLiteral()) return true;
MaterializedLiteral* literal = AsMaterializedLiteral();
if (literal == nullptr) return false;
return literal->IsSimple();
}
bool Expression::IsUndefinedLiteral() const {
if (IsLiteral() && AsLiteral()->type() == Literal::kUndefined) return true;
......@@ -334,8 +340,7 @@ ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value,
bool ObjectLiteral::Property::IsCompileTimeValue() const {
return kind_ == CONSTANT ||
(kind_ == MATERIALIZED_LITERAL &&
CompileTimeValue::IsCompileTimeValue(value_));
(kind_ == MATERIALIZED_LITERAL && value_->IsCompileTimeValue());
}
......@@ -445,7 +450,7 @@ int ObjectLiteral::InitDepthAndFlags() {
Literal* key = property->key()->AsLiteral();
Expression* value = property->value();
bool is_compile_time_value = CompileTimeValue::IsCompileTimeValue(value);
bool is_compile_time_value = value->IsCompileTimeValue();
is_simple = is_simple && is_compile_time_value;
// Keep track of the number of elements in the object literal and
......@@ -568,7 +573,7 @@ int ArrayLiteral::InitDepthAndFlags() {
if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
}
if (!CompileTimeValue::IsCompileTimeValue(element)) {
if (!element->IsCompileTimeValue()) {
is_simple = false;
}
}
......@@ -662,8 +667,8 @@ Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
if (expression->IsLiteral()) {
return expression->AsLiteral()->BuildValue(isolate);
}
if (CompileTimeValue::IsCompileTimeValue(expression)) {
return CompileTimeValue::GetValue(isolate, expression);
if (expression->IsCompileTimeValue()) {
return isolate->factory()->NewCompileTimeValue(expression);
}
return isolate->factory()->uninitialized_value();
}
......
......@@ -241,6 +241,8 @@ class Expression : public AstNode {
// that this also checks for loads of the global "undefined" variable.
bool IsUndefinedLiteral() const;
bool IsCompileTimeValue();
protected:
Expression(int pos, NodeType type) : AstNode(pos, type) {}
......@@ -1121,7 +1123,7 @@ class MaterializedLiteral : public Expression {
// If the expression is a literal, return the literal value;
// if the expression is a materialized literal and is simple return a
// compile time value as encoded by CompileTimeValue::GetValue().
// compile time value as encoded by CompileTimeValue
// Otherwise, return undefined literal as the placeholder
// in the object literal boilerplate.
Handle<Object> GetBoilerplateValue(Expression* expression, Isolate* isolate);
......
// Copyright 2016 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.
#include "src/ast/compile-time-value.h"
#include "src/ast/ast.h"
#include "src/handles-inl.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
if (expression->IsLiteral()) return true;
MaterializedLiteral* literal = expression->AsMaterializedLiteral();
if (literal == nullptr) return false;
return literal->IsSimple();
}
Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate,
Expression* expression) {
Factory* factory = isolate->factory();
DCHECK(IsCompileTimeValue(expression));
Handle<FixedArray> result = factory->NewFixedArray(2, TENURED);
if (expression->IsObjectLiteral()) {
ObjectLiteral* object_literal = expression->AsObjectLiteral();
DCHECK(object_literal->is_simple());
int literalTypeFlag = object_literal->EncodeLiteralType();
DCHECK_NE(kArrayLiteralFlag, literalTypeFlag);
result->set(kLiteralTypeSlot, Smi::FromInt(literalTypeFlag));
result->set(kElementsSlot, *object_literal->constant_properties());
} else {
ArrayLiteral* array_literal = expression->AsArrayLiteral();
DCHECK(array_literal->is_simple());
result->set(kLiteralTypeSlot, Smi::FromInt(kArrayLiteralFlag));
result->set(kElementsSlot, *array_literal->constant_elements());
}
return result;
}
int CompileTimeValue::GetLiteralTypeFlags(Handle<FixedArray> value) {
return Smi::ToInt(value->get(kLiteralTypeSlot));
}
Handle<HeapObject> CompileTimeValue::GetElements(Handle<FixedArray> value) {
return Handle<HeapObject>(HeapObject::cast(value->get(kElementsSlot)),
value->GetIsolate());
}
} // namespace internal
} // namespace v8
// Copyright 2015 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_AST_COMPILE_TIME_VALUE_H_
#define V8_AST_COMPILE_TIME_VALUE_H_
#include "src/allocation.h"
#include "src/globals.h"
namespace v8 {
namespace internal {
class Expression;
// Support for handling complex values (array and object literals) that
// can be fully handled at compile time.
class CompileTimeValue : public AllStatic {
public:
// This is a special marker used to encode array literals. The value has to be
// different from any value possibly returned by
// ObjectLiteral::EncodeLiteralType.
static const int kArrayLiteralFlag = -1;
static bool IsCompileTimeValue(Expression* expression);
// Get the value as a compile time value.
static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression);
// Get the encoded literal type. This can either be kArrayLiteralFlag or
// encoded properties of an ObjectLiteral returned by
// ObjectLiteral::EncodeLiteralType.
static int GetLiteralTypeFlags(Handle<FixedArray> value);
// Get the elements of a compile time value returned by GetValue().
static Handle<HeapObject> GetElements(Handle<FixedArray> value);
private:
static const int kLiteralTypeSlot = 0;
static const int kElementsSlot = 1;
};
} // namespace internal
} // namespace v8
#endif // V8_AST_COMPILE_TIME_VALUE_H_
......@@ -23,6 +23,7 @@
#include "src/objects/frame-array-inl.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/promise-inl.h"
......@@ -244,6 +245,27 @@ Handle<ConstantElementsPair> Factory::NewConstantElementsPair(
return result;
}
Handle<CompileTimeValue> Factory::NewCompileTimeValue(Expression* expression) {
DCHECK(expression->IsCompileTimeValue());
Handle<CompileTimeValue> result =
Handle<CompileTimeValue>::cast(NewStruct(TUPLE2_TYPE, TENURED));
if (expression->IsObjectLiteral()) {
ObjectLiteral* object_literal = expression->AsObjectLiteral();
DCHECK(object_literal->is_simple());
int literalTypeFlag = object_literal->EncodeLiteralType();
DCHECK_NE(CompileTimeValue::kArrayLiteralFlag, literalTypeFlag);
result->set_literal_type_flag(literalTypeFlag);
result->set_constant_elements(*object_literal->constant_properties());
} else {
ArrayLiteral* array_literal = expression->AsArrayLiteral();
DCHECK(array_literal->is_simple());
result->set_literal_type_flag(CompileTimeValue::kArrayLiteralFlag);
result->set_constant_elements(*array_literal->constant_elements());
}
return result;
}
Handle<TemplateObjectDescription> Factory::NewTemplateObjectDescription(
Handle<FixedArray> raw_strings, Handle<FixedArray> cooked_strings) {
DCHECK_EQ(raw_strings->length(), cooked_strings->length());
......
......@@ -30,6 +30,8 @@ class CallableTask;
class CallbackTask;
class CallHandlerInfo;
class ConstantElementsPair;
class Expression;
class CompileTimeValue;
class CoverageInfo;
class DebugInfo;
class EnumCache;
......@@ -194,6 +196,9 @@ class V8_EXPORT_PRIVATE Factory {
Handle<ConstantElementsPair> NewConstantElementsPair(
ElementsKind elements_kind, Handle<FixedArrayBase> constant_values);
// Create a new CompileTimeValue struct.
Handle<CompileTimeValue> NewCompileTimeValue(Expression* expression);
// Create a new TemplateObjectDescription struct.
Handle<TemplateObjectDescription> NewTemplateObjectDescription(
Handle<FixedArray> raw_strings, Handle<FixedArray> cooked_strings);
......
......@@ -827,7 +827,8 @@ void ObjectStatsCollectorImpl::
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
array, HeapObject::cast(entry), type);
}
} else if (MatchesConstantElementsPair(object)) {
} else if (MatchesConstantElementsPair(object) ||
object->IsCompileTimeValue()) {
Tuple2* tuple = Tuple2::cast(object);
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
tuple, HeapObject::cast(tuple->value2()), type);
......@@ -844,7 +845,8 @@ void ObjectStatsCollectorImpl::RecordVirtualBytecodeArrayDetails(
FixedArray* constant_pool = FixedArray::cast(bytecode->constant_pool());
for (int i = 0; i < constant_pool->length(); i++) {
Object* entry = constant_pool->get(i);
if (entry->IsFixedArrayExact() || MatchesConstantElementsPair(entry)) {
if (entry->IsFixedArrayExact() || MatchesConstantElementsPair(entry) ||
entry->IsCompileTimeValue()) {
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
constant_pool, HeapObject::cast(entry),
ObjectStats::EMBEDDED_OBJECT_TYPE);
......@@ -906,7 +908,8 @@ void ObjectStatsCollectorImpl::RecordVirtualCodeDetails(Code* code) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
Object* target = it.rinfo()->target_object();
if (target->IsFixedArrayExact() || MatchesConstantElementsPair(target)) {
if (target->IsFixedArrayExact() || MatchesConstantElementsPair(target) ||
target->IsCompileTimeValue()) {
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
code, HeapObject::cast(target), ObjectStats::EMBEDDED_OBJECT_TYPE);
}
......
......@@ -6,7 +6,6 @@
#include "src/api.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/compile-time-value.h"
#include "src/ast/scopes.h"
#include "src/builtins/builtins-constructor.h"
#include "src/code-stubs.h"
......@@ -2144,7 +2143,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
case ObjectLiteral::Property::CONSTANT:
UNREACHABLE();
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
DCHECK(!property->value()->IsCompileTimeValue());
V8_FALLTHROUGH;
case ObjectLiteral::Property::COMPUTED: {
// It is safe to use [[Put]] here because the boilerplate already
......@@ -2333,8 +2332,7 @@ void BytecodeGenerator::BuildArrayLiteralElementsInsertion(
for (; iter != first_spread_or_end; ++iter, array_index++) {
Expression* subexpr = *iter;
DCHECK(!subexpr->IsSpread());
if (skip_constants && CompileTimeValue::IsCompileTimeValue(subexpr))
continue;
if (skip_constants && subexpr->IsCompileTimeValue()) continue;
if (keyed_store_slot.IsInvalid()) {
keyed_store_slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
}
......
......@@ -85,6 +85,7 @@ TYPE_CHECKER(Cell, CELL_TYPE)
TYPE_CHECKER(Code, CODE_TYPE)
TYPE_CHECKER(CodeDataContainer, CODE_DATA_CONTAINER_TYPE)
TYPE_CHECKER(ConstantElementsPair, TUPLE2_TYPE)
TYPE_CHECKER(CompileTimeValue, TUPLE2_TYPE)
TYPE_CHECKER(CoverageInfo, FIXED_ARRAY_TYPE)
TYPE_CHECKER(DescriptorArray, DESCRIPTOR_ARRAY_TYPE)
TYPE_CHECKER(EphemeronHashTable, EPHEMERON_HASH_TABLE_TYPE)
......@@ -596,6 +597,7 @@ CAST_ACCESSOR(BigInt)
CAST_ACCESSOR(BoilerplateDescription)
CAST_ACCESSOR(Cell)
CAST_ACCESSOR(ConstantElementsPair)
CAST_ACCESSOR(CompileTimeValue)
CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(EphemeronHashTable)
CAST_ACCESSOR(EnumCache)
......
......@@ -1072,6 +1072,7 @@ template <class C> inline bool Is(Object* obj);
V(CompilationCacheTable) \
V(ConsString) \
V(ConstantElementsPair) \
V(CompileTimeValue) \
V(Constructor) \
V(Context) \
V(CoverageInfo) \
......
......@@ -43,6 +43,10 @@ ACCESSORS(ClassBoilerplate, instance_elements_template, Object,
ACCESSORS(ClassBoilerplate, instance_computed_properties, FixedArray,
FixedArray::OffsetOfElementAt(kPrototypeComputedPropertiesIndex));
SMI_ACCESSORS(CompileTimeValue, literal_type_flag, kLiteralTypeFlagOffset)
ACCESSORS(CompileTimeValue, constant_elements, HeapObject,
kConstantElementsOffset)
} // namespace internal
} // namespace v8
......
......@@ -60,6 +60,31 @@ class ConstantElementsPair : public Tuple2 {
DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantElementsPair);
};
// Support for handling complex values (array and object literals) that
// can be fully handled at compile time.
class CompileTimeValue : public Tuple2 {
public:
// This is a special marker used to encode array literals. The value has to be
// different from any value possibly returned by
// ObjectLiteral::EncodeLiteralType.
static const int kArrayLiteralFlag = -1;
// Get the encoded literal type. This can either be kArrayLiteralFlag or
// encoded properties of an ObjectLiteral returned by
// ObjectLiteral::EncodeLiteralType.
DECL_INT_ACCESSORS(literal_type_flag);
// For objects literals a FixedArray is stored whereas for array literals
// ConstantElementPair is stored.
DECL_ACCESSORS(constant_elements, HeapObject)
DECL_CAST(CompileTimeValue)
static const int kLiteralTypeFlagOffset = kValue1Offset;
static const int kConstantElementsOffset = kValue2Offset;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
};
class ClassBoilerplate : public FixedArray {
public:
enum ValueKind { kData, kGetter, kSetter };
......
......@@ -7,10 +7,10 @@
#include "src/allocation-site-scopes.h"
#include "src/arguments.h"
#include "src/ast/ast.h"
#include "src/ast/compile-time-value.h"
#include "src/isolate-inl.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/runtime/runtime.h"
namespace v8 {
......@@ -31,9 +31,9 @@ void PreInitializeLiteralSite(Handle<FeedbackVector> vector,
vector->Set(slot, Smi::FromInt(1));
}
Handle<Object> InnerCreateBoilerplate(Isolate* isolate,
Handle<FixedArray> compile_time_value,
PretenureFlag pretenure_flag);
Handle<Object> InnerCreateBoilerplate(
Isolate* isolate, Handle<CompileTimeValue> compile_time_value,
PretenureFlag pretenure_flag);
enum DeepCopyHints { kNoHints = 0, kObjectIsShallow = 1 };
......@@ -357,10 +357,11 @@ struct ObjectBoilerplate {
for (int index = 0; index < length; index++) {
Handle<Object> key(boilerplate_description->name(index), isolate);
Handle<Object> value(boilerplate_description->value(index), isolate);
if (value->IsFixedArray()) {
if (value->IsCompileTimeValue()) {
// The value contains the CompileTimeValue with the boilerplate
// properties of a simple object or array literal.
Handle<FixedArray> compile_time_value = Handle<FixedArray>::cast(value);
Handle<CompileTimeValue> compile_time_value =
Handle<CompileTimeValue>::cast(value);
value =
InnerCreateBoilerplate(isolate, compile_time_value, pretenure_flag);
}
......@@ -429,12 +430,12 @@ struct ArrayBoilerplate {
copied_elements_values = fixed_array_values_copy;
FOR_WITH_HANDLE_SCOPE(
isolate, int, i = 0, i, i < fixed_array_values->length(), i++, {
if (fixed_array_values->get(i)->IsFixedArray()) {
if (fixed_array_values->get(i)->IsCompileTimeValue()) {
// The value contains the CompileTimeValue with the
// boilerplate description of a simple object or
// array literal.
Handle<FixedArray> compile_time_value(
FixedArray::cast(fixed_array_values->get(i)),
Handle<CompileTimeValue> compile_time_value(
CompileTimeValue::cast(fixed_array_values->get(i)),
for_with_handle_isolate);
Handle<Object> result = InnerCreateBoilerplate(
isolate, compile_time_value, pretenure_flag);
......@@ -450,12 +451,12 @@ struct ArrayBoilerplate {
}
};
Handle<Object> InnerCreateBoilerplate(Isolate* isolate,
Handle<FixedArray> compile_time_value,
PretenureFlag pretenure_flag) {
Handle<HeapObject> elements =
CompileTimeValue::GetElements(compile_time_value);
int flags = CompileTimeValue::GetLiteralTypeFlags(compile_time_value);
Handle<Object> InnerCreateBoilerplate(
Isolate* isolate, Handle<CompileTimeValue> compile_time_value,
PretenureFlag pretenure_flag) {
int flags = compile_time_value->literal_type_flag();
Handle<HeapObject> elements(
HeapObject::cast(compile_time_value->constant_elements()), isolate);
if (flags == CompileTimeValue::kArrayLiteralFlag) {
return ArrayBoilerplate::Create(isolate, elements, flags, pretenure_flag);
}
......
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