Commit ce409375 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[sfi] Reduce FunctionTokenPosition and ExpectedNofProperties to 16 bits.

Changes SharedFunctionInfo to store a function_token_offset, relative
to the start_position, instead of the full function_token_position.
This enables us to reduce both FunctionTokenPosition and
ExpectedNofProperties to 16 bits each, saving 32 bits per SFI.

BUG=chromium:818642,chromium:783853
TBR=yangguo@chromium.org

Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I45aefcec605c1da502053c23c73564ceaed6c9b5
Reviewed-on: https://chromium-review.googlesource.com/1122982
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54220}
parent 67c10796
......@@ -7353,6 +7353,7 @@ class V8_EXPORT Isolate {
kWebAssemblyInstantiation = 46,
kDeoptimizerDisableSpeculation = 47,
kArrayPrototypeSortJSArrayModifiedPrototype = 48,
kFunctionTokenOffsetTooLongForToString = 49,
// If you add new values here, you'll also need to update Chromium's:
// web_feature.mojom, UseCounterCallback.cpp, and enums.xml. V8 changes to
......
......@@ -974,12 +974,13 @@ void UpdatePositions(Isolate* isolate, Handle<SharedFunctionInfo> sfi,
int new_end_position = LiveEdit::TranslatePosition(diffs, sfi->EndPosition());
int new_function_token_position =
LiveEdit::TranslatePosition(diffs, sfi->function_token_position());
sfi->set_raw_start_position(new_start_position);
sfi->set_raw_end_position(new_end_position);
sfi->set_function_token_position(new_function_token_position);
if (sfi->scope_info()->HasPositionInfo()) {
sfi->scope_info()->SetPositionInfo(new_start_position, new_end_position);
}
sfi->SetFunctionTokenPosition(new_function_token_position);
if (sfi->HasBytecodeArray()) {
TranslateSourcePositionTable(handle(sfi->GetBytecodeArray(), isolate),
diffs);
......
......@@ -3495,7 +3495,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_expected_nof_properties(0);
share->set_raw_start_position_and_type(0);
share->set_raw_end_position(0);
share->set_function_token_position(0);
share->set_raw_function_token_offset(0);
// All flags default to false or 0.
share->set_flags(0);
share->CalculateConstructAsBuiltin();
......
......@@ -13333,6 +13333,14 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
}
if (FLAG_harmony_function_tostring) {
if (shared_info->function_token_position() == kNoSourcePosition) {
// If the function token position isn't valid, return [native code] to
// ensure calling eval on the returned source code throws rather than
// giving inconsistent call behaviour.
isolate->CountUsage(v8::Isolate::UseCounterFeature::
kFunctionTokenOffsetTooLongForToString);
return NativeCodeFunctionSourceString(shared_info);
}
return Handle<String>::cast(
SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
}
......@@ -13836,7 +13844,7 @@ Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
Handle<String> script_source(
String::cast(Script::cast(shared->script())->source()), isolate);
int start_pos = shared->function_token_position();
if (start_pos == kNoSourcePosition) start_pos = shared->StartPosition();
DCHECK_NE(start_pos, kNoSourcePosition);
Handle<String> source = isolate->factory()->NewSubString(
script_source, start_pos, shared->EndPosition());
if (!shared->is_wrapped()) return source;
......@@ -13993,9 +14001,9 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
// When adding fields here, make sure DeclarationScope::AnalyzePartially is
// updated accordingly.
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
shared_info->set_function_token_position(lit->function_token_position());
shared_info->set_raw_start_position(lit->start_position());
shared_info->set_raw_end_position(lit->end_position());
shared_info->SetFunctionTokenPosition(lit->function_token_position());
if (shared_info->scope_info()->HasPositionInfo()) {
shared_info->scope_info()->SetPositionInfo(lit->start_position(),
lit->end_position());
......@@ -14067,9 +14075,28 @@ void SharedFunctionInfo::SetExpectedNofPropertiesFromEstimate(
// so we can afford to adjust the estimate generously.
estimate += 8;
// Limit actual estimate to fit in a 16 bit field, we will never allocate
// more than this in any case.
estimate = std::min(estimate, kMaxUInt16);
set_expected_nof_properties(estimate);
}
void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position) {
DCHECK_NE(StartPosition(), kNoSourcePosition);
int offset;
if (function_token_position == kNoSourcePosition) {
offset = 0;
} else {
offset = StartPosition() - function_token_position;
}
if (offset > kMaximumFunctionTokenOffset) {
offset = kFunctionTokenOutOfRange;
}
set_raw_function_token_offset(offset);
}
void Map::StartInobjectSlackTracking() {
DCHECK(!IsInobjectSlackTrackingInProgress());
if (UnusedPropertyFields() == 0) return;
......
......@@ -50,13 +50,13 @@ INT_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset)
UINT16_ACCESSORS(SharedFunctionInfo, length, kLengthOffset)
UINT16_ACCESSORS(SharedFunctionInfo, internal_formal_parameter_count,
kFormalParameterCountOffset)
INT_ACCESSORS(SharedFunctionInfo, expected_nof_properties,
kExpectedNofPropertiesOffset)
UINT16_ACCESSORS(SharedFunctionInfo, expected_nof_properties,
kExpectedNofPropertiesOffset)
UINT16_ACCESSORS(SharedFunctionInfo, raw_function_token_offset,
kFunctionTokenOffsetOffset)
INT_ACCESSORS(SharedFunctionInfo, raw_end_position, kEndPositionOffset)
INT_ACCESSORS(SharedFunctionInfo, raw_start_position_and_type,
kStartPositionAndTypeOffset)
INT_ACCESSORS(SharedFunctionInfo, function_token_position,
kFunctionTokenPositionOffset)
INT_ACCESSORS(SharedFunctionInfo, flags, kFlagsOffset)
bool SharedFunctionInfo::HasSharedName() const {
......@@ -99,6 +99,15 @@ AbstractCode* SharedFunctionInfo::abstract_code() {
}
}
int SharedFunctionInfo::function_token_position() const {
int offset = raw_function_token_offset();
if (offset == kFunctionTokenOutOfRange) {
return kNoSourcePosition;
} else {
return StartPosition() - offset;
}
}
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_wrapped,
SharedFunctionInfo::IsWrappedBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, allows_lazy_compilation,
......
......@@ -147,7 +147,7 @@ class SharedFunctionInfo : public HeapObject {
// [expected_nof_properties]: Expected number of properties for the
// function. The value is only reliable when the function has been compiled.
DECL_INT_ACCESSORS(expected_nof_properties)
DECL_UINT16_ACCESSORS(expected_nof_properties)
// [function_literal_id] - uniquely identifies the FunctionLiteral this
// SharedFunctionInfo represents within its script, or -1 if this
......@@ -247,8 +247,15 @@ class SharedFunctionInfo : public HeapObject {
// [script]: Script from which the function originates.
DECL_ACCESSORS(script, Object)
// Position of the 'function' token in the script source.
DECL_INT_ACCESSORS(function_token_position)
// The offset of the 'function' token in the script source relative to the
// start position. Can return kFunctionTokenOutOfRange if offset doesn't
// fit in 16 bits.
DECL_UINT16_ACCESSORS(raw_function_token_offset)
// The position of the 'function' token in the script source. Can return
// kNoSourcePosition if raw_function_token_offset() returns
// kFunctionTokenOutOfRange.
inline int function_token_position() const;
// [raw_start_position_and_type]: Field used to store both the source code
// position, whether or not the function is a function expression,
......@@ -392,6 +399,9 @@ class SharedFunctionInfo : public HeapObject {
// Sets the expected number of properties based on estimate from parser.
void SetExpectedNofPropertiesFromEstimate(FunctionLiteral* literal);
// Sets the FunctionTokenOffset field based on the
void SetFunctionTokenPosition(int function_token_position);
inline bool construct_as_builtin() const;
// Determines and sets the ConstructAsBuiltinBit in |flags|, based on the
......@@ -445,6 +455,10 @@ class SharedFunctionInfo : public HeapObject {
// Constants.
static const uint16_t kDontAdaptArgumentsSentinel = static_cast<uint16_t>(-1);
static const int kMaximumFunctionTokenOffset = kMaxUInt16 - 1;
static const uint16_t kFunctionTokenOutOfRange = static_cast<uint16_t>(-1);
STATIC_ASSERT(kMaximumFunctionTokenOffset + 1 == kFunctionTokenOutOfRange);
#if V8_SFI_HAS_UNIQUE_ID
static const int kUniqueIdFieldSize = kInt32Size;
#else
......@@ -467,10 +481,10 @@ class SharedFunctionInfo : public HeapObject {
V(kUniqueIdOffset, kUniqueIdFieldSize) \
V(kLengthOffset, kUInt16Size) \
V(kFormalParameterCountOffset, kUInt16Size) \
V(kExpectedNofPropertiesOffset, kInt32Size) \
V(kExpectedNofPropertiesOffset, kUInt16Size) \
V(kFunctionTokenOffsetOffset, kUInt16Size) \
V(kStartPositionAndTypeOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
V(kFunctionTokenPositionOffset, kInt32Size) \
V(kFlagsOffset, kInt32Size) \
/* Total size. */ \
V(kSize, 0)
......
......@@ -141,6 +141,30 @@ assertEquals("function () { [native code] }",
assertEquals("function () { [native code] }",
new Proxy({ method() { hidden } }.method, {}).toString());
// Assert that we return a NativeFunction for script that has too large an
// offset between function token position and start position for us to return
// an exact representation of the source code.
function testLongFunctionTokenOffset(functionType) {
var expected = "function f() { [native code] }";
// Spec requires that we return something that will cause eval to throws if we
// can't reproduce the function's source code.
assertThrows(() => eval(expected), SyntaxError);
var functionSource = functionType + " ".repeat(65535) + " f(){}";
// Function declaration
eval(functionSource);
assertEquals(expected, f.toString());
// Function expression
var f = eval("(" + functionSource + ")");
assertEquals(expected, f.toString());
}
testLongFunctionTokenOffset("function");
testLongFunctionTokenOffset("function*");
testLongFunctionTokenOffset("async function");
testLongFunctionTokenOffset("async function*");
// Non-callable proxies still throw.
assertThrows(() => Function.prototype.toString.call(new Proxy({}, {})),
TypeError);
......@@ -263,7 +263,7 @@ extras_accessors = [
'ExternalString, resource, Object, kResourceOffset',
'SeqOneByteString, chars, char, kHeaderSize',
'SeqTwoByteString, chars, char, kHeaderSize',
'SharedFunctionInfo, function_token_position, int, kFunctionTokenPositionOffset',
'SharedFunctionInfo, raw_function_token_offset, int, kFunctionTokenOffsetOffset',
'SharedFunctionInfo, start_position_and_type, int, kStartPositionAndTypeOffset',
'SharedFunctionInfo, end_position, int, kEndPositionOffset',
'SharedFunctionInfo, internal_formal_parameter_count, uint16_t, kFormalParameterCountOffset',
......
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