Revert "[sfi] Remove SFI function literal id field"

This reverts commit 1d4a1172f5.

Reason for revert: https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux%20-%20arm64%20-%20sim%20-%20MSAN/21989

Original change's description:
> [sfi] Remove SFI function literal id field
> 
> SharedFunctionInfos store their original function literal's id. This is
> also their index in the Script's SFI list.
> 
> The function literal id is only needed for lazy compilation and live edit,
> and access only has to be fast in the former. So, we can move the SFI
> function literal id field to UncompiledData, and if patching with live
> edit, or discarding compiled code, we can perform a slower linear search
> through the Script's SFI list.
> 
> This is a reland of
> https://chromium-review.googlesource.com/c/v8/v8/+/1082480
> but caching the literal id on UncompiledData rather than always linearly
> searching the SFI list. Also, removes the unused runtime-liveedit.cc file
> instead of fixing it to support this change.
> 
> Bug: chromium:818642
> Change-Id: I977bcca0dc72903ca476a7079d156cc8bbe88fde
> Reviewed-on: https://chromium-review.googlesource.com/1128854
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#54464}

TBR=ulan@chromium.org,marja@chromium.org,yangguo@chromium.org,kozyatinskiy@chromium.org,cbruni@chromium.org,leszeks@chromium.org,verwaest@chromium.org

Change-Id: Icee5ee3ab7688b93e2963f91debed65a58164534
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:818642
Reviewed-on: https://chromium-review.googlesource.com/1138276
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54466}
This commit is contained in:
Sigurd Schneider 2018-07-16 14:24:17 +00:00 committed by Commit Bot
parent e3b4ffa9ba
commit 58578584d6
12 changed files with 329 additions and 125 deletions

View File

@ -623,9 +623,10 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
Handle<WeakFixedArray> infos = factory()->NewWeakFixedArray(2);
script->set_shared_function_infos(*infos);
empty_function->shared()->set_scope_info(*scope_info);
empty_function->shared()->set_function_literal_id(1);
empty_function->shared()->DontAdaptArguments();
SharedFunctionInfo::SetScript(handle(empty_function->shared(), isolate()),
script, 1);
script);
return empty_function;
}

View File

@ -121,7 +121,7 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
unicode_cache_.reset(new UnicodeCache());
parse_info_->set_unicode_cache(unicode_cache_.get());
parse_info_->set_function_literal_id(shared_->FunctionLiteralId(isolate));
parse_info_->set_function_literal_id(shared_->function_literal_id());
if (V8_UNLIKELY(FLAG_runtime_stats)) {
parse_info_->set_runtime_call_stats(new (parse_info_->zone())
RuntimeCallStats());
@ -196,7 +196,6 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
shared_->EndPosition() - offset));
parse_info_->set_character_stream(std::move(stream));
}
parser_.reset(new Parser(parse_info_.get()));
parser_->DeserializeScopeChain(isolate, parse_info_.get(),
parse_info_->maybe_outer_scope_info());

View File

@ -779,13 +779,12 @@ class FunctionDataMap : public ThreadVisitor {
FunctionData{literal, should_restart});
}
bool Lookup(Isolate* isolate, SharedFunctionInfo* sfi, FunctionData** data) {
int function_literal_id = sfi->FunctionLiteralId(isolate);
if (!sfi->script()->IsScript() || function_literal_id == -1) {
bool Lookup(SharedFunctionInfo* sfi, FunctionData** data) {
if (!sfi->script()->IsScript() || sfi->function_literal_id() == -1) {
return false;
}
Script* script = Script::cast(sfi->script());
return Lookup(script->id(), function_literal_id, data);
return Lookup(script->id(), sfi->function_literal_id(), data);
}
bool Lookup(Handle<Script> script, FunctionLiteral* literal,
@ -800,20 +799,20 @@ class FunctionDataMap : public ThreadVisitor {
if (obj->IsSharedFunctionInfo()) {
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
FunctionData* data = nullptr;
if (!Lookup(isolate, sfi, &data)) continue;
if (!Lookup(sfi, &data)) continue;
data->shared = handle(sfi, isolate);
} else if (obj->IsJSFunction()) {
JSFunction* js_function = JSFunction::cast(obj);
SharedFunctionInfo* sfi = js_function->shared();
FunctionData* data = nullptr;
if (!Lookup(isolate, sfi, &data)) continue;
if (!Lookup(sfi, &data)) continue;
data->js_functions.emplace_back(js_function, isolate);
} else if (obj->IsJSGeneratorObject()) {
JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
if (gen->is_closed()) continue;
SharedFunctionInfo* sfi = gen->function()->shared();
FunctionData* data = nullptr;
if (!Lookup(isolate, sfi, &data)) continue;
if (!Lookup(sfi, &data)) continue;
data->running_generators.emplace_back(gen, isolate);
}
}
@ -843,7 +842,7 @@ class FunctionDataMap : public ThreadVisitor {
stack_position = FunctionData::BELOW_NON_DROPPABLE_FRAME;
}
FunctionData* data = nullptr;
if (!Lookup(isolate, *sfi, &data)) continue;
if (!Lookup(*sfi, &data)) continue;
if (!data->should_restart) continue;
data->stack_position = stack_position;
*restart_frame_fp = frame->fp();
@ -867,7 +866,7 @@ class FunctionDataMap : public ThreadVisitor {
it.frame()->GetFunctions(&sfis);
for (auto& sfi : sfis) {
FunctionData* data = nullptr;
if (!Lookup(isolate, *sfi, &data)) continue;
if (!Lookup(*sfi, &data)) continue;
data->stack_position = FunctionData::ARCHIVED_THREAD;
}
}
@ -932,7 +931,7 @@ bool CanRestartFrame(Isolate* isolate, Address fp,
JavaScriptFrame::cast(restart_frame)->GetFunctions(&sfis);
for (auto& sfi : sfis) {
FunctionData* data = nullptr;
if (!function_data_map.Lookup(isolate, *sfi, &data)) continue;
if (!function_data_map.Lookup(*sfi, &data)) continue;
auto new_literal_it = changed.find(data->literal);
if (new_literal_it == changed.end()) continue;
if (new_literal_it->second->scope()->new_target_var()) {
@ -1061,14 +1060,11 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
new_script->shared_function_infos()->Get(
mapping.second->function_literal_id());
sfi->set_function_literal_id(mapping.second->function_literal_id());
sfi->set_script(*new_script);
if (sfi->HasUncompiledData()) {
sfi->uncompiled_data()->set_function_literal_id(
mapping.second->function_literal_id());
}
new_script->shared_function_infos()->Set(
mapping.second->function_literal_id(), HeapObjectReference::Weak(*sfi));
DCHECK_EQ(sfi->FunctionLiteralId(isolate),
DCHECK_EQ(sfi->function_literal_id(),
mapping.second->function_literal_id());
// Swap the now-redundant, newly compiled SFI into the old script, so that
@ -1080,16 +1076,12 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
SharedFunctionInfo* redundant_new_sfi =
SharedFunctionInfo::cast(redundant_new_sfi_obj);
redundant_new_sfi->set_function_literal_id(
mapping.first->function_literal_id());
redundant_new_sfi->set_script(*script);
if (redundant_new_sfi->HasUncompiledData()) {
redundant_new_sfi->uncompiled_data()->set_function_literal_id(
mapping.first->function_literal_id());
}
script->shared_function_infos()->Set(
mapping.first->function_literal_id(),
HeapObjectReference::Weak(redundant_new_sfi));
DCHECK_EQ(redundant_new_sfi->FunctionLiteralId(isolate),
mapping.first->function_literal_id());
}
if (sfi->HasUncompiledDataWithPreParsedScope()) {
@ -1103,12 +1095,13 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
}
if (!sfi->HasBytecodeArray()) continue;
FixedArray* constants = sfi->GetBytecodeArray()->constant_pool();
Handle<BytecodeArray> bytecode(sfi->GetBytecodeArray(), isolate);
Handle<FixedArray> constants(bytecode->constant_pool(), isolate);
for (int i = 0; i < constants->length(); ++i) {
if (!constants->get(i)->IsSharedFunctionInfo()) continue;
FunctionData* data = nullptr;
if (!function_data_map.Lookup(
isolate, SharedFunctionInfo::cast(constants->get(i)), &data)) {
if (!function_data_map.Lookup(SharedFunctionInfo::cast(constants->get(i)),
&data)) {
continue;
}
auto change_it = changed.find(data->literal);
@ -1160,7 +1153,7 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
// inner_sfi, but the resulting FunctionData will still be referring to
// the old, unchanged SFI.
FunctionData* data = nullptr;
if (!function_data_map.Lookup(isolate, inner_sfi, &data)) continue;
if (!function_data_map.Lookup(inner_sfi, &data)) continue;
Handle<SharedFunctionInfo> old_unchanged_inner_sfi =
data->shared.ToHandleChecked();
// Now some sanity checks. Make sure that this inner_sfi is not the
@ -1171,21 +1164,17 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
DCHECK_EQ(old_unchanged_inner_sfi->script(), *new_script);
// ... and that the id of the unchanged SFI matches the unchanged target
// literal's id.
DCHECK_EQ(old_unchanged_inner_sfi->FunctionLiteralId(isolate),
DCHECK_EQ(old_unchanged_inner_sfi->function_literal_id(),
unchanged[data->literal]->function_literal_id());
constants->set(i, *old_unchanged_inner_sfi);
}
}
#ifdef DEBUG
{
// Check that all the functions in the new script are valid and that their
// function literals match what is expected.
DisallowHeapAllocation no_gc;
// Check that all the functions in the new script are valid.
SharedFunctionInfo::ScriptIterator it(isolate, *new_script);
while (SharedFunctionInfo* sfi = it.Next()) {
DCHECK_EQ(sfi->script(), *new_script);
DCHECK_EQ(sfi->FunctionLiteralId(isolate), it.CurrentIndex());
if (!sfi->HasBytecodeArray()) continue;
// Check that all the functions in this function's constant pool are also
@ -1198,7 +1187,7 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
SharedFunctionInfo::cast(constants->get(i));
DCHECK_EQ(inner_sfi->script(), *new_script);
DCHECK_EQ(inner_sfi, new_script->shared_function_infos()
->Get(inner_sfi->FunctionLiteralId(isolate))
->Get(inner_sfi->function_literal_id())
->GetHeapObject());
}
}

View File

@ -2514,21 +2514,19 @@ Handle<PreParsedScopeData> Factory::NewPreParsedScopeData(int length) {
Handle<UncompiledDataWithoutPreParsedScope>
Factory::NewUncompiledDataWithoutPreParsedScope(int32_t start_position,
int32_t end_position,
int32_t function_literal_id) {
int32_t end_position) {
Handle<UncompiledDataWithoutPreParsedScope> result(
UncompiledDataWithoutPreParsedScope::cast(
New(uncompiled_data_without_pre_parsed_scope_map(), TENURED)),
isolate());
result->set_start_position(start_position);
result->set_end_position(end_position);
result->set_function_literal_id(function_literal_id);
return result;
}
Handle<UncompiledDataWithPreParsedScope>
Factory::NewUncompiledDataWithPreParsedScope(
int32_t start_position, int32_t end_position, int32_t function_literal_id,
int32_t start_position, int32_t end_position,
Handle<PreParsedScopeData> pre_parsed_scope_data) {
Handle<UncompiledDataWithPreParsedScope> result(
UncompiledDataWithPreParsedScope::cast(
@ -2536,7 +2534,6 @@ Factory::NewUncompiledDataWithPreParsedScope(
isolate());
result->set_start_position(start_position);
result->set_end_position(end_position);
result->set_function_literal_id(function_literal_id);
result->set_pre_parsed_scope_data(*pre_parsed_scope_data);
return result;
}
@ -3419,8 +3416,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfoForBuiltin(
literal->name(), Builtins::kCompileLazy, kind);
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel);
SharedFunctionInfo::SetScript(shared, script, literal->function_literal_id(),
false);
SharedFunctionInfo::SetScript(shared, script, false);
return shared;
}
@ -3508,6 +3504,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_function_identifier_or_debug_info(*undefined_value(),
SKIP_WRITE_BARRIER);
share->set_function_literal_id(FunctionLiteral::kIdTypeInvalid);
#if V8_SFI_HAS_UNIQUE_ID
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
#endif

View File

@ -728,12 +728,10 @@ class V8_EXPORT_PRIVATE Factory {
Handle<UncompiledDataWithoutPreParsedScope>
NewUncompiledDataWithoutPreParsedScope(int32_t start_position,
int32_t end_position,
int32_t function_literal_id);
int32_t end_position);
Handle<UncompiledDataWithPreParsedScope> NewUncompiledDataWithPreParsedScope(
int32_t start_position, int32_t end_position, int32_t function_literal_id,
Handle<PreParsedScopeData>);
int32_t start_position, int32_t end_position, Handle<PreParsedScopeData>);
// Create an External object for V8's external API.
Handle<JSObject> NewExternal(void* value);

View File

@ -12895,8 +12895,9 @@ void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
map->set_prototype(*prototype, wb_mode);
}
Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
Handle<Map> initial_map) {
Handle<Object> CacheInitialJSArrayMaps(
Handle<Context> native_context, Handle<Map> initial_map) {
// Replace all of the cached initial array maps in the native context with
// the appropriate transitioned elements kind maps.
Handle<Map> current_map = initial_map;
@ -13017,6 +13018,7 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
SetInstancePrototype(isolate, function, construct_prototype);
}
void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
Handle<Object> prototype) {
if (map->prototype() != *prototype)
@ -13734,8 +13736,8 @@ SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Object> script_object,
int function_literal_id,
bool reset_preparsed_scope_data) {
DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
if (shared->script() == *script_object) return;
Isolate* isolate = shared->GetIsolate();
@ -13753,14 +13755,15 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<WeakFixedArray> list =
handle(script->shared_function_infos(), isolate);
#ifdef DEBUG
DCHECK_LT(function_literal_id, list->length());
MaybeObject* maybe_object = list->Get(function_literal_id);
DCHECK_LT(shared->function_literal_id(), list->length());
MaybeObject* maybe_object = list->Get(shared->function_literal_id());
HeapObject* heap_object;
if (maybe_object->ToWeakHeapObject(&heap_object)) {
DCHECK_EQ(heap_object, *shared);
}
#endif
list->Set(function_literal_id, HeapObjectReference::Weak(*shared));
list->Set(shared->function_literal_id(),
HeapObjectReference::Weak(*shared));
} else {
Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
@ -13786,14 +13789,15 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
// Due to liveedit, it might happen that the old_script doesn't know
// about the SharedFunctionInfo, so we have to guard against that.
Handle<WeakFixedArray> infos(old_script->shared_function_infos(), isolate);
if (function_literal_id < infos->length()) {
MaybeObject* raw =
old_script->shared_function_infos()->Get(function_literal_id);
if (shared->function_literal_id() < infos->length()) {
MaybeObject* raw = old_script->shared_function_infos()->Get(
shared->function_literal_id());
HeapObject* heap_object;
if (raw->ToWeakHeapObject(&heap_object) && heap_object == *shared) {
old_script->shared_function_infos()->Set(
function_literal_id, HeapObjectReference::Strong(
ReadOnlyRoots(isolate).undefined_value()));
shared->function_literal_id(),
HeapObjectReference::Strong(
ReadOnlyRoots(isolate).undefined_value()));
}
}
} else {
@ -13906,27 +13910,6 @@ bool SharedFunctionInfo::IsInlineable() {
int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const {
DisallowHeapAllocation no_gc;
Object* script_obj = script();
if (!script_obj->IsScript()) return FunctionLiteral::kIdTypeInvalid;
WeakFixedArray* shared_info_list =
Script::cast(script_obj)->shared_function_infos();
SharedFunctionInfo::ScriptIterator iterator(
isolate, Handle<WeakFixedArray>(&shared_info_list));
for (SharedFunctionInfo* shared = iterator.Next(); shared != nullptr;
shared = iterator.Next()) {
if (shared == this) {
return iterator.CurrentIndex();
}
}
return FunctionLiteral::kIdTypeInvalid;
}
void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
bool has_prototype_slot,
int requested_embedder_fields,
@ -14069,6 +14052,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
// FunctionKind must have already been set.
DCHECK(lit->kind() == shared_info->kind());
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_function_literal_id(lit->function_literal_id());
DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),
IsClassConstructor(lit->kind()));
shared_info->set_requires_instance_fields_initializer(
@ -14115,7 +14099,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithPreParsedScope(
lit->start_position(), lit->end_position(),
lit->function_literal_id(), pre_parsed_scope_data);
pre_parsed_scope_data);
shared_info->set_uncompiled_data(*data);
needs_position_info = false;
}
@ -14125,8 +14109,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
if (needs_position_info) {
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
lit->start_position(), lit->end_position(),
lit->function_literal_id());
lit->start_position(), lit->end_position());
shared_info->set_uncompiled_data(*data);
}
}

View File

@ -55,7 +55,6 @@ void PreParsedScopeData::clear_padding() {
CAST_ACCESSOR(UncompiledData)
INT32_ACCESSORS(UncompiledData, start_position, kStartPositionOffset)
INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset)
INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset)
CAST_ACCESSOR(UncompiledDataWithoutPreParsedScope)
@ -78,6 +77,7 @@ ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, function_identifier_or_debug_info, Object,
kFunctionIdentifierOrDebugInfoOffset)
INT_ACCESSORS(SharedFunctionInfo, function_literal_id, kFunctionLiteralIdOffset)
#if V8_SFI_HAS_UNIQUE_ID
INT_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset)
#endif
@ -650,21 +650,6 @@ WasmExportedFunctionData* SharedFunctionInfo::wasm_exported_function_data()
return WasmExportedFunctionData::cast(function_data());
}
int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const {
// Fast path for the common case when the SFI is uncompiled and so the
// function literal id is already in the uncompiled data.
if (HasUncompiledData()) {
int id = uncompiled_data()->function_literal_id();
// Make sure the id is what we should have found with the slow path.
DCHECK_EQ(id, FindIndexInScript(isolate));
return id;
}
// Otherwise, search for the function in the SFI's script's function list,
// and return its index in that list.
return FindIndexInScript(isolate);
}
bool SharedFunctionInfo::HasDebugInfo() const {
return function_identifier_or_debug_info()->IsDebugInfo();
}
@ -752,11 +737,8 @@ void SharedFunctionInfo::DiscardCompiled(
int start_position = shared_info->StartPosition();
int end_position = shared_info->EndPosition();
int function_literal_id = shared_info->FunctionLiteralId(isolate);
if (shared_info->is_compiled()) {
DisallowHeapAllocation no_gc;
HeapObject* outer_scope_info;
if (shared_info->scope_info()->HasOuterScopeInfo()) {
outer_scope_info = shared_info->scope_info()->OuterScopeInfo();
@ -782,7 +764,7 @@ void SharedFunctionInfo::DiscardCompiled(
// validity checks, since we're performing the unusual task of decompiling.
Handle<UncompiledData> data =
isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
start_position, end_position, function_literal_id);
start_position, end_position);
shared_info->set_function_data(*data);
}
}

View File

@ -70,15 +70,13 @@ class UncompiledData : public HeapObject {
public:
DECL_INT32_ACCESSORS(start_position)
DECL_INT32_ACCESSORS(end_position)
DECL_INT32_ACCESSORS(function_literal_id)
DECL_CAST(UncompiledData)
#define UNCOMPILED_DATA_FIELDS(V) \
V(kStartPositionOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
V(kFunctionLiteralIdOffset, kInt32Size) \
/* Total size. */ \
#define UNCOMPILED_DATA_FIELDS(V) \
V(kStartPositionOffset, kInt32Size) \
V(kEndPositionOffset, kInt32Size) \
/* Total size. */ \
V(kUnalignedSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, UNCOMPILED_DATA_FIELDS)
@ -187,7 +185,7 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
// function info is added to the list on the script.
V8_EXPORT_PRIVATE static void SetScript(
Handle<SharedFunctionInfo> shared, Handle<Object> script_object,
int function_literal_id, bool reset_preparsed_scope_data = true);
bool reset_preparsed_scope_data = true);
// Layout description of the optimized code map.
static const int kEntriesStart = 0;
@ -257,6 +255,11 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
// function. The value is only reliable when the function has been compiled.
DECL_UINT16_ACCESSORS(expected_nof_properties)
// [function_literal_id] - uniquely identifies the FunctionLiteral this
// SharedFunctionInfo represents within its script, or -1 if this
// SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral.
DECL_INT_ACCESSORS(function_literal_id)
#if V8_SFI_HAS_UNIQUE_ID
// [unique_id] - For --trace-maps purposes, an identifier that's persistent
// even if the GC moves this SharedFunctionInfo.
@ -338,9 +341,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
inline String* inferred_name();
inline void set_inferred_name(String* inferred_name);
// Get the function literal id associated with this function, for parsing.
inline int FunctionLiteralId(Isolate* isolate) const;
// The function is subject to debugging if a debug info is attached.
inline bool HasDebugInfo() const;
inline DebugInfo* GetDebugInfo() const;
@ -530,7 +530,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
ScriptIterator(Isolate* isolate,
Handle<WeakFixedArray> shared_function_infos);
SharedFunctionInfo* Next();
int CurrentIndex() const { return index_ - 1; }
// Reset the iterator to run on |script|.
void Reset(Script* script);
@ -583,6 +582,7 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
V(kFunctionIdentifierOrDebugInfoOffset, kPointerSize) \
V(kEndOfPointerFieldsOffset, 0) \
/* Raw data fields. */ \
V(kFunctionLiteralIdOffset, kInt32Size) \
V(kUniqueIdOffset, kUniqueIdFieldSize) \
V(kLengthOffset, kUInt16Size) \
V(kFormalParameterCountOffset, kUInt16Size) \
@ -662,10 +662,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
inline uint16_t length() const;
// Find the index of this function in the parent script. Slow path of
// FunctionLiteralId.
int FindIndexInScript(Isolate* isolate) const;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};

View File

@ -68,7 +68,7 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
set_function_flags(shared->flags());
set_start_position(shared->StartPosition());
set_end_position(shared->EndPosition());
function_literal_id_ = shared->FunctionLiteralId(isolate);
function_literal_id_ = shared->function_literal_id();
set_language_mode(shared->language_mode());
set_asm_wasm_broken(shared->is_asm_wasm_broken());

View File

@ -114,17 +114,16 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
bool was_native = target_shared->native();
target_shared->set_flags(source_shared->flags());
target_shared->set_native(was_native);
target_shared->set_function_literal_id(source_shared->function_literal_id());
target_shared->set_scope_info(source_shared->scope_info());
Handle<Object> source_script(source_shared->script(), isolate);
int function_literal_id = source_shared->FunctionLiteralId(isolate);
if (source_script->IsScript()) {
SharedFunctionInfo::SetScript(source_shared,
isolate->factory()->undefined_value(),
function_literal_id);
isolate->factory()->undefined_value());
}
SharedFunctionInfo::SetScript(target_shared, source_script,
function_literal_id);
SharedFunctionInfo::SetScript(target_shared, source_script);
// Set the code of the target function.
target->set_code(source_shared->GetCode());

View File

@ -0,0 +1,260 @@
// Copyright 2014 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/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/debug/debug.h"
#include "src/debug/debug-frames.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate-inl.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
// For a script finds all SharedFunctionInfo's in the heap that points
// to this script. Returns JSArray of SharedFunctionInfo wrapped
// in OpaqueReferences.
RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSValue, script_value, 0);
CHECK(script_value->value()->IsScript());
Handle<Script> script(Script::cast(script_value->value()), isolate);
std::vector<Handle<SharedFunctionInfo>> found;
Heap* heap = isolate->heap();
{
HeapIterator iterator(heap);
HeapObject* heap_obj;
while ((heap_obj = iterator.next()) != nullptr) {
if (!heap_obj->IsSharedFunctionInfo()) continue;
SharedFunctionInfo* shared = SharedFunctionInfo::cast(heap_obj);
if (shared->script() != *script) continue;
found.push_back(Handle<SharedFunctionInfo>(shared, isolate));
}
}
int found_size = static_cast<int>(found.size());
Handle<FixedArray> result = isolate->factory()->NewFixedArray(found_size);
for (int i = 0; i < found_size; ++i) {
Handle<SharedFunctionInfo> shared = found[i];
SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create(isolate);
Handle<String> name(shared->Name(), isolate);
info_wrapper.SetProperties(name, shared->StartPosition(),
shared->EndPosition(), shared);
result->set(i, *info_wrapper.GetJSArray());
}
return *isolate->factory()->NewJSArrayWithElements(result);
}
// For a script calculates compilation information about all its functions.
// The script source is explicitly specified by the second argument.
// The source of the actual script is not used, however it is important that
// all generated code keeps references to this particular instance of script.
// Returns a JSArray of compilation infos. The array is ordered so that
// each function with all its descendant is always stored in a continues range
// with the function itself going first. The root function is a script function.
RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(JSValue, script, 0);
CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
CHECK(script->value()->IsScript());
Handle<Script> script_handle(Script::cast(script->value()), isolate);
RETURN_RESULT_OR_FAILURE(
isolate, LiveEdit::GatherCompileInfo(isolate, script_handle, source));
}
// Changes the source of the script to a new_source.
// If old_script_name is provided (i.e. is a String), also creates a copy of
// the script with its original source and sends notification to debugger.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
CHECK(original_script_value->value()->IsScript());
Handle<Script> original_script(Script::cast(original_script_value->value()),
isolate);
Handle<Object> old_script = LiveEdit::ChangeScriptSource(
isolate, original_script, new_source, old_script_name);
if (old_script->IsScript()) {
Handle<Script> script_handle = Handle<Script>::cast(old_script);
return *Script::GetWrapper(script_handle);
} else {
return ReadOnlyRoots(isolate).null_value();
}
}
// Recreate the shared function infos array after changing the IDs of all
// SharedFunctionInfos.
RUNTIME_FUNCTION(Runtime_LiveEditFixupScript) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 2);
CONVERT_ARG_CHECKED(JSValue, script_value, 0);
CONVERT_INT32_ARG_CHECKED(max_function_literal_id, 1);
CHECK(script_value->value()->IsScript());
Handle<Script> script(Script::cast(script_value->value()), isolate);
LiveEdit::FixupScript(isolate, script, max_function_literal_id);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 2);
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
CONVERT_INT32_ARG_CHECKED(new_function_literal_id, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_info));
LiveEdit::FunctionSourceUpdated(shared_info, new_function_literal_id);
return ReadOnlyRoots(isolate).undefined_value();
}
// Replaces code of SharedFunctionInfo with a new one.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_info));
LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
return ReadOnlyRoots(isolate).undefined_value();
}
// Connects SharedFunctionInfo to another script.
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
if (function_object->IsJSValue()) {
Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
if (script_object->IsJSValue()) {
CHECK(JSValue::cast(*script_object)->value()->IsScript());
Script* script = Script::cast(JSValue::cast(*script_object)->value());
script_object = Handle<Object>(script, isolate);
}
CHECK(function_wrapper->value()->IsSharedFunctionInfo());
LiveEdit::SetFunctionScript(function_wrapper, script_object);
} else {
// Just ignore this. We may not have a SharedFunctionInfo for some functions
// and we check it in this function.
}
return ReadOnlyRoots(isolate).undefined_value();
}
// In a code of a parent function replaces original function as embedded object
// with a substitution one.
RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
CHECK(parent_wrapper->value()->IsSharedFunctionInfo());
CHECK(orig_wrapper->value()->IsSharedFunctionInfo());
CHECK(subst_wrapper->value()->IsSharedFunctionInfo());
LiveEdit::ReplaceRefToNestedFunction(isolate->heap(), parent_wrapper,
orig_wrapper, subst_wrapper);
return ReadOnlyRoots(isolate).undefined_value();
}
// Updates positions of a shared function info (first parameter) according
// to script source change. Text change is described in second parameter as
// array of groups of 3 numbers:
// (change_begin, change_end, change_end_new_position).
// Each group describes a change in text; groups are sorted by change_begin.
RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
CHECK(SharedInfoWrapper::IsInstance(shared_array));
LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
return ReadOnlyRoots(isolate).undefined_value();
}
// For array of SharedFunctionInfo's (each wrapped in JSValue)
// checks that none of them have activations on stacks (of any thread).
// Returns array of the same length with corresponding results of
// LiveEdit::FunctionPatchabilityStatus type.
RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, old_shared_array, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, new_shared_array, 1);
CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 2);
USE(new_shared_array);
CHECK(old_shared_array->length()->IsSmi());
CHECK(new_shared_array->length() == old_shared_array->length());
CHECK(old_shared_array->HasFastElements());
CHECK(new_shared_array->HasFastElements());
int array_length = Smi::ToInt(old_shared_array->length());
for (int i = 0; i < array_length; i++) {
Handle<Object> old_element;
Handle<Object> new_element;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, old_element,
JSReceiver::GetElement(isolate, old_shared_array, i));
CHECK(old_element->IsJSValue() &&
Handle<JSValue>::cast(old_element)->value()->IsSharedFunctionInfo());
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, new_element,
JSReceiver::GetElement(isolate, new_shared_array, i));
CHECK(
new_element->IsUndefined(isolate) ||
(new_element->IsJSValue() &&
Handle<JSValue>::cast(new_element)->value()->IsSharedFunctionInfo()));
}
return *LiveEdit::CheckAndDropActivations(old_shared_array, new_shared_array,
do_drop);
}
// Compares 2 strings line-by-line, then token-wise and returns diff in form
// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
// of diff chunks.
RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
Handle<JSArray> result = LiveEdit::CompareStrings(isolate, s1, s2);
uint32_t array_length = 0;
CHECK(result->length()->ToArrayLength(&array_length));
if (array_length > 0) {
isolate->debug()->feature_tracker()->Track(DebugFeatureTracker::kLiveEdit);
}
return *result;
}
} // namespace internal
} // namespace v8

View File

@ -38,15 +38,15 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->NewStringFromAsciiChecked("f"),
Builtins::kCompileLazy);
int function_literal_id = 1;
// Ensure that the function can be compiled lazily.
shared->set_uncompiled_data(
*isolate->factory()->NewUncompiledDataWithoutPreParsedScope(
0, source->length(), function_literal_id));
0, source->length()));
// Make sure we have an outer scope info, even though it's empty
shared->set_raw_outer_scope_info_or_feedback_metadata(
ScopeInfo::Empty(isolate));
SharedFunctionInfo::SetScript(shared, script, function_literal_id);
shared->set_function_literal_id(1);
SharedFunctionInfo::SetScript(shared, script);
return scope.CloseAndEscape(shared);
}