Commit a36f2593 authored by Mythri's avatar Mythri Committed by Commit Bot

Don't use feedback vector to infer IC kind and language mode

Currently, the runtime IC functions deduce the IC kind and the language
mode from the feedback slot kind. To support feedback free execution
(for V8 lite mode and lazy allocation of feedback vectors) we need to
infer the IC kind even when feedback vectors are not present.

To be able to infer the language mode without feedback vectors, this cl
forces context allocation in cases where we raise the language mode in
the middle of a function. The language mode is the stricter of the
language mode on the SFI and the language mode of the current context.

This cl updates the bytecode handlers to check for valid feedback vectors
and to call into runtime if the feedback vector is not allocated. It also
adds new runtime functions to be able to infer the IC kind when there is no
feedback vector. Most of the builtins and handlers remain unchanged because
they are only used when feedback vector is present.

Bug: v8:8394
Change-Id: I1f77740c0d68ddaa0de076597f5f6bcb2e966d70
Reviewed-on: https://chromium-review.googlesource.com/c/1358516
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58191}
parent 83544915
......@@ -2311,8 +2311,10 @@ void Scope::AllocateVariablesRecursively() {
// scope and for a function scope that makes an 'eval' call we need a context,
// even if no local variables were statically allocated in the scope.
// Likewise for modules and function scopes representing asm.js modules.
// Also force a context, if the scope is stricter than the outer scope.
bool must_have_context =
is_with_scope() || is_module_scope() || IsAsmModule() ||
ForceContextForLanguageMode() ||
(is_function_scope() && AsDeclarationScope()->calls_sloppy_eval()) ||
(is_block_scope() && is_declaration_scope() &&
AsDeclarationScope()->calls_sloppy_eval());
......
......@@ -422,12 +422,26 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool ContainsAsmModule() const;
// Does this scope have the potential to execute declarations non-linearly?
bool is_nonlinear() const { return scope_nonlinear_; }
// Returns if we need to force a context because the current scope is stricter
// than the outerscope. We need this to properly track the language mode using
// the context. This is required in ICs where we lookup the language mode
// from the context.
bool ForceContextForLanguageMode() const {
// For function scopes we need not force a context since the language mode
// can be obtained from the closure. Script scopes always have a context.
if (scope_type_ == FUNCTION_SCOPE || scope_type_ == SCRIPT_SCOPE) {
return false;
}
DCHECK_NOT_NULL(outer_scope_);
return (language_mode() > outer_scope_->language_mode());
}
// Whether this needs to be represented by a runtime context.
bool NeedsContext() const {
// Catch scopes always have heap slots.
DCHECK_IMPLIES(is_catch_scope(), num_heap_slots() > 0);
DCHECK_IMPLIES(is_with_scope(), num_heap_slots() > 0);
DCHECK_IMPLIES(ForceContextForLanguageMode(), num_heap_slots() > 0);
return num_heap_slots() > 0;
}
......
......@@ -9910,6 +9910,57 @@ void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector,
BIND(&end);
}
Node* CodeStubAssembler::GetLanguageMode(
TNode<SharedFunctionInfo> shared_function_info, Node* context) {
VARIABLE(var_language_mode, MachineRepresentation::kTaggedSigned,
SmiConstant(LanguageMode::kStrict));
Label language_mode_determined(this), language_mode_sloppy(this);
// Get the language mode from SFI
TNode<Uint32T> closure_is_strict =
DecodeWord32<SharedFunctionInfo::IsStrictBit>(LoadObjectField(
shared_function_info, SharedFunctionInfo::kFlagsOffset,
MachineType::Uint32()));
// It is already strict, we need not check context's language mode.
GotoIf(closure_is_strict, &language_mode_determined);
// SFI::LanguageMode is sloppy, check if context has a stricter mode.
TNode<ScopeInfo> scope_info =
CAST(LoadObjectField(context, Context::kScopeInfoOffset));
// If no flags field assume sloppy
GotoIf(SmiLessThanOrEqual(LoadFixedArrayBaseLength(scope_info),
SmiConstant(ScopeInfo::Fields::kFlags)),
&language_mode_sloppy);
TNode<Smi> flags = CAST(LoadFixedArrayElement(
scope_info, SmiConstant(ScopeInfo::Fields::kFlags)));
TNode<Uint32T> context_is_strict =
DecodeWord32<ScopeInfo::LanguageModeField>(SmiToInt32(flags));
GotoIf(context_is_strict, &language_mode_determined);
Goto(&language_mode_sloppy);
// Both Context::ScopeInfo::LanguageMode and SFI::LanguageMode are sloppy.
BIND(&language_mode_sloppy);
var_language_mode.Bind(SmiConstant(LanguageMode::kSloppy));
Goto(&language_mode_determined);
BIND(&language_mode_determined);
return var_language_mode.value();
}
Node* CodeStubAssembler::GetLanguageMode(TNode<JSFunction> closure,
Node* context) {
TNode<SharedFunctionInfo> sfi =
CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
return GetLanguageMode(sfi, context);
}
Node* CodeStubAssembler::GetLanguageMode(TNode<FeedbackVector> vector,
Node* context) {
TNode<SharedFunctionInfo> sfi =
CAST(LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset));
return GetLanguageMode(sfi, context);
}
void CodeStubAssembler::ReportFeedbackUpdate(
SloppyTNode<FeedbackVector> feedback_vector, SloppyTNode<IntPtrT> slot_id,
const char* reason) {
......
......@@ -2700,6 +2700,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Update the type feedback vector.
void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id);
// Returns the stricter of the Context::ScopeInfo::LanguageMode and
// the language mode on the SFI.
Node* GetLanguageMode(TNode<SharedFunctionInfo> sfi, Node* context);
Node* GetLanguageMode(TNode<JSFunction> closure, Node* context);
Node* GetLanguageMode(TNode<FeedbackVector> vector, Node* context);
// Report that there was a feedback update, performing any tasks that should
// be done after a feedback update.
void ReportFeedbackUpdate(SloppyTNode<FeedbackVector> feedback_vector,
......
......@@ -828,6 +828,9 @@ void AccessorAssembler::HandleStoreICNativeDataProperty(
Node* accessor_info = LoadDescriptorValue(LoadMap(holder), descriptor);
CSA_CHECK(this, IsAccessorInfo(accessor_info));
// TODO(8580): Get the language mode lazily when required to avoid the
// computation of GetLanguageMode here. Also make the computation of
// language mode not dependent on vector.
Node* language_mode = GetLanguageMode(p->vector, p->slot);
TailCallRuntime(Runtime::kStoreCallbackProperty, p->context, p->receiver,
......@@ -1448,6 +1451,9 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
Label if_index(this), if_unique_name(this),
to_name_failed(this, Label::kDeferred);
// TODO(8580): Get the language mode lazily when required to avoid the
// computation of GetLanguageMode here. Also make the computation of
// language mode not dependent on vector.
Node* language_mode = GetLanguageMode(p->vector, p->slot);
if (support_elements == kSupportElements) {
......@@ -2383,6 +2389,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
// accident.
Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
GotoIf(IsUndefined(p->vector), &miss);
// Inlined fast path.
{
Comment("LoadIC_BytecodeHandler_fast");
......@@ -2569,7 +2577,8 @@ void AccessorAssembler::LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
TNode<Context> context = lazy_context();
TNode<Name> name = lazy_name();
exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
ParameterToTagged(slot, slot_mode), vector);
ParameterToTagged(slot, slot_mode), vector,
SmiConstant(typeof_mode));
}
}
......@@ -3181,9 +3190,8 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
BIND(&miss);
{
Comment("StoreInArrayLiteralIC_miss");
// TODO(neis): Introduce Runtime::kStoreInArrayLiteralIC_Miss.
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
p->vector, p->receiver, p->name);
TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Miss, p->context, p->value,
p->slot, p->vector, p->receiver, p->name);
}
}
......
......@@ -155,10 +155,11 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
ICStats::instance()->End();
}
IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
FeedbackSlotKind kind)
: isolate_(isolate),
vector_set_(false),
kind_(FeedbackSlotKind::kInvalid),
kind_(kind),
target_maps_set_(false),
slow_stub_reason_(nullptr),
nexus_(vector, slot) {
......@@ -195,7 +196,6 @@ IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
constant_pool_address_ = constant_pool;
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
kind_ = nexus_.kind();
state_ = nexus_.StateFromFeedback();
old_state_ = state_;
}
......@@ -2159,6 +2159,20 @@ void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
// ----------------------------------------------------------------------------
// Static IC stub generators.
//
//
namespace {
// TODO(8580): Compute the language mode lazily to avoid the expensive
// computation of language mode here.
LanguageMode GetLanguageMode(Handle<FeedbackVector> vector, Context context) {
LanguageMode language_mode = vector->shared_function_info()->language_mode();
if (context->scope_info()->language_mode() > language_mode) {
return context->scope_info()->language_mode();
}
return language_mode;
}
} // namespace
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
HandleScope scope(isolate);
......@@ -2167,27 +2181,39 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Handle<Object> receiver = args.at(0);
Handle<Name> key = args.at<Name>(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
if (!maybe_vector->IsUndefined()) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
// A monomorphic or polymorphic KeyedLoadIC with a string key can call the
// LoadIC miss handler if the handler misses. Since the vector Nexus is
// set up outside the IC, handle that here.
FeedbackSlotKind kind = vector->GetKind(vector_slot);
// The only case where we call without a vector is from the LoadNamedProperty
// bytecode handler. Also, when there is no feedback vector, there is no
// difference between LoadProperty or LoadKeyed kind.
FeedbackSlotKind kind = FeedbackSlotKind::kLoadProperty;
if (!vector.is_null()) {
kind = vector->GetKind(vector_slot);
}
if (IsLoadICKind(kind)) {
LoadIC ic(isolate, vector, vector_slot);
LoadIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
} else if (IsLoadGlobalICKind(kind)) {
DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
receiver = isolate->global_object();
LoadGlobalIC ic(isolate, vector, vector_slot);
LoadGlobalIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
} else {
DCHECK(IsKeyedLoadICKind(kind));
KeyedLoadIC ic(isolate, vector, vector_slot);
KeyedLoadIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
......@@ -2195,15 +2221,26 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<JSGlobalObject> global = isolate->global_object();
Handle<String> name = args.at<String>(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
CONVERT_INT32_ARG_CHECKED(typeof_value, 3);
TypeofMode typeof_mode = static_cast<TypeofMode>(typeof_value);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
LoadGlobalIC ic(isolate, vector, vector_slot);
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
if (!maybe_vector->IsUndefined()) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
FeedbackSlotKind kind = (typeof_mode == TypeofMode::INSIDE_TYPEOF)
? FeedbackSlotKind::kLoadGlobalInsideTypeof
: FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
LoadGlobalIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(global, name);
Handle<Object> result;
......@@ -2262,9 +2299,15 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
Handle<Object> receiver = args.at(0);
Handle<Object> key = args.at(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
if (!maybe_vector->IsUndefined()) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
KeyedLoadIC ic(isolate, vector, vector_slot);
KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadKeyed);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
......@@ -2278,26 +2321,51 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> receiver = args.at(3);
Handle<Name> key = args.at<Name>(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind kind = vector->GetKind(vector_slot);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
StoreIC ic(isolate, vector, vector_slot);
StoreIC ic(isolate, vector, vector_slot, kind, language_mode);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else if (IsStoreGlobalICKind(kind)) {
DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
receiver = isolate->global_object();
StoreGlobalIC ic(isolate, vector, vector_slot);
StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
} else {
DCHECK(IsKeyedStoreICKind(kind));
KeyedStoreIC ic(isolate, vector, vector_slot);
KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
}
RUNTIME_FUNCTION(Runtime_StoreICNoFeedback_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
Handle<Object> value = args.at(0);
Handle<Object> receiver = args.at(1);
Handle<Name> key = args.at<Name>(2);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
CONVERT_INT32_ARG_CHECKED(is_own_property_value, 4);
NamedPropertyType property_type =
static_cast<NamedPropertyType>(is_own_property_value);
FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
? FeedbackSlotKind::kStoreNamedStrict
: FeedbackSlotKind::kStoreNamedSloppy;
if (property_type == NamedPropertyType::kOwn) {
language_mode = LanguageMode::kStrict;
kind = FeedbackSlotKind::kStoreOwnNamed;
}
StoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
language_mode);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
......@@ -2306,24 +2374,43 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Name> key = args.at<Name>(3);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
StoreGlobalIC ic(isolate, vector, vector_slot);
FeedbackSlotKind kind = vector->GetKind(vector_slot);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
Handle<JSGlobalObject> global = isolate->global_object();
ic.UpdateState(global, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
}
RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Name> key = args.at<Name>(1);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2);
FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
? FeedbackSlotKind::kStoreGlobalStrict
: FeedbackSlotKind::kStoreGlobalSloppy;
StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
language_mode);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
}
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
#ifdef DEBUG
{
Handle<Smi> slot = args.at<Smi>(1);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
DCHECK(IsStoreGlobalICKind(slot_kind));
......@@ -2359,8 +2446,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
return *value;
}
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, global, name, value, language_mode,
......@@ -2376,13 +2462,15 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind kind = vector->GetKind(vector_slot);
// The elements store stubs miss into this function, but they are shared by
// different ICs.
if (IsKeyedStoreICKind(kind)) {
KeyedStoreIC ic(isolate, vector, vector_slot);
KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
......@@ -2396,19 +2484,54 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
}
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
RUNTIME_FUNCTION(Runtime_KeyedStoreICNoFeedback_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Object> receiver = args.at(1);
Handle<Object> key = args.at(2);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
? FeedbackSlotKind::kStoreKeyedStrict
: FeedbackSlotKind::kStoreKeyedSloppy;
KeyedStoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
language_mode);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
if (!maybe_vector->IsUndefined()) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
DCHECK(receiver->IsJSArray());
DCHECK(key->IsNumber());
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
ic.Store(Handle<JSArray>::cast(receiver), key, value);
return *value;
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
Handle<Object> object = args.at(3);
Handle<Object> key = args.at(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind kind = vector->GetKind(vector_slot);
DCHECK(IsStoreICKind(kind) || IsKeyedStoreICKind(kind));
LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
......@@ -2449,7 +2572,7 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
return *value;
} else {
DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
RETURN_RESULT_OR_FAILURE(
isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
......@@ -2713,7 +2836,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
Handle<JSObject> receiver = args.at<JSObject>(3);
Handle<Name> name = args.at<Name>(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
// TODO(ishell): Cache interceptor_holder in the store handler like we do
// for LoadHandler::kInterceptor case.
......
......@@ -19,6 +19,8 @@
namespace v8 {
namespace internal {
enum class NamedPropertyType : bool { kNotOwn, kOwn };
//
// IC is the base class for LoadIC, StoreIC, KeyedLoadIC, and KeyedStoreIC.
//
......@@ -35,7 +37,8 @@ class IC {
// Construct the IC structure with the given number of extra
// JavaScript frames on the stack.
IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot);
IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
FeedbackSlotKind kind);
virtual ~IC() = default;
State state() const { return state_; }
......@@ -204,8 +207,9 @@ class IC {
class LoadIC : public IC {
public:
LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
: IC(isolate, vector, slot) {
LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
FeedbackSlotKind kind)
: IC(isolate, vector, slot, kind) {
DCHECK(IsAnyLoad());
}
......@@ -239,8 +243,8 @@ class LoadIC : public IC {
class LoadGlobalIC : public LoadIC {
public:
LoadGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: LoadIC(isolate, vector, slot) {}
FeedbackSlot slot, FeedbackSlotKind kind)
: LoadIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
......@@ -253,8 +257,8 @@ class LoadGlobalIC : public LoadIC {
class KeyedLoadIC : public LoadIC {
public:
KeyedLoadIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: LoadIC(isolate, vector, slot) {}
FeedbackSlot slot, FeedbackSlotKind kind)
: LoadIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Object> key);
......@@ -283,12 +287,13 @@ class KeyedLoadIC : public LoadIC {
class StoreIC : public IC {
public:
StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
: IC(isolate, vector, slot) {
StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
FeedbackSlotKind kind, LanguageMode language_mode)
: IC(isolate, vector, slot, kind), language_mode_(language_mode) {
DCHECK(IsAnyStore());
}
LanguageMode language_mode() const { return nexus()->GetLanguageMode(); }
LanguageMode language_mode() const { return language_mode_; }
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
Handle<Object> object, Handle<Name> name, Handle<Object> value,
......@@ -309,6 +314,11 @@ class StoreIC : public IC {
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
StoreOrigin store_origin);
// TODO(v8:8580): Instead of storing the language mode, compute it lazily
// from the closure and context when needed. We only need it when throwing
// exceptions, so it is OK to be slow.
LanguageMode language_mode_;
private:
MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
......@@ -318,8 +328,9 @@ class StoreIC : public IC {
class StoreGlobalIC : public StoreIC {
public:
StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: StoreIC(isolate, vector, slot) {}
FeedbackSlot slot, FeedbackSlotKind kind,
LanguageMode language_mode)
: StoreIC(isolate, vector, slot, kind, language_mode) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
Handle<Object> value);
......@@ -343,8 +354,9 @@ class KeyedStoreIC : public StoreIC {
}
KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: StoreIC(isolate, vector, slot) {}
FeedbackSlot slot, FeedbackSlotKind kind,
LanguageMode language_mode)
: StoreIC(isolate, vector, slot, kind, language_mode) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
Handle<Object> name,
......@@ -377,7 +389,9 @@ class StoreInArrayLiteralIC : public KeyedStoreIC {
public:
StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: KeyedStoreIC(isolate, vector, slot) {
: KeyedStoreIC(isolate, vector, slot,
FeedbackSlotKind::kStoreInArrayLiteral,
LanguageMode::kStrict) {
DCHECK(IsStoreInArrayLiteralICKind(kind()));
}
......
......@@ -15,6 +15,7 @@
#include "src/debug/debug.h"
#include "src/ic/accessor-assembler.h"
#include "src/ic/binary-op-assembler.h"
#include "src/ic/ic.h"
#include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecodes.h"
#include "src/interpreter/interpreter-assembler.h"
......@@ -156,7 +157,7 @@ class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
void LdaGlobal(int slot_operand_index, int name_operand_index,
TypeofMode typeof_mode) {
TNode<FeedbackVector> feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* feedback_slot = BytecodeOperandIdx(slot_operand_index);
AccessorAssembler accessor_asm(state());
......@@ -172,9 +173,20 @@ class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
return CAST(name);
};
accessor_asm.LoadGlobalIC(feedback_vector, feedback_slot, lazy_context,
lazy_name, typeof_mode, &exit_point,
CodeStubAssembler::INTPTR_PARAMETERS);
Label miss(this, Label::kDeferred);
ParameterMode slot_mode = CodeStubAssembler::INTPTR_PARAMETERS;
GotoIf(IsUndefined(maybe_feedback_vector), &miss);
accessor_asm.LoadGlobalIC(CAST(maybe_feedback_vector), feedback_slot,
lazy_context, lazy_name, typeof_mode, &exit_point,
slot_mode);
BIND(&miss);
{
exit_point.ReturnCallRuntime(
Runtime::kLoadGlobalIC_Miss, lazy_context(), lazy_name(),
ParameterToTagged(feedback_slot, slot_mode), maybe_feedback_vector,
SmiConstant(typeof_mode));
}
}
};
......@@ -212,9 +224,23 @@ IGNITION_HANDLER(StaGlobal, InterpreterAssembler) {
Node* value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(1);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_vector = LoadFeedbackVectorUnchecked();
Label no_feedback(this, Label::kDeferred), end(this);
GotoIf(IsUndefined(maybe_vector), &no_feedback);
CallBuiltin(Builtins::kStoreGlobalIC, context, name, value, smi_slot,
feedback_vector);
maybe_vector);
Goto(&end);
Bind(&no_feedback);
TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
Node* language_mode = GetLanguageMode(closure, context);
CallRuntime(Runtime::kStoreGlobalICNoFeedback_Miss, context, value, name,
language_mode);
Goto(&end);
Bind(&end);
Dispatch();
}
......@@ -490,7 +516,7 @@ IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
// constant pool entry <name_index>.
IGNITION_HANDLER(LdaNamedProperty, InterpreterAssembler) {
Node* feedback_vector = LoadFeedbackVector();
Node* feedback_vector = LoadFeedbackVectorUnchecked();
Node* feedback_slot = BytecodeOperandIdx(2);
Node* smi_slot = SmiTag(feedback_slot);
......@@ -539,11 +565,26 @@ IGNITION_HANDLER(LdaKeyedProperty, InterpreterAssembler) {
Node* name = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(1);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
Node* result = CallBuiltin(Builtins::kKeyedLoadIC, context, object, name,
smi_slot, feedback_vector);
SetAccumulator(result);
Label no_feedback(this, Label::kDeferred), end(this);
VARIABLE(var_result, MachineRepresentation::kTagged);
GotoIf(IsUndefined(feedback_vector), &no_feedback);
var_result.Bind(CallBuiltin(Builtins::kKeyedLoadIC, context, object, name,
smi_slot, feedback_vector));
Goto(&end);
BIND(&no_feedback);
{
Comment("KeyedLoadIC_no_feedback");
var_result.Bind(CallRuntime(Runtime::kKeyedLoadIC_Miss, context, object,
name, smi_slot, feedback_vector));
Goto(&end);
}
BIND(&end);
SetAccumulator(var_result.value());
Dispatch();
}
......@@ -554,23 +595,39 @@ class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
OperandScale operand_scale)
: InterpreterAssembler(state, bytecode, operand_scale) {}
void StaNamedProperty(Callable ic) {
void StaNamedProperty(Callable ic, NamedPropertyType property_type) {
Node* code_target = HeapConstant(ic.code());
Node* object = LoadRegisterAtOperandIndex(0);
Node* name = LoadConstantPoolEntryAtOperandIndex(1);
Node* value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
Node* result = CallStub(ic.descriptor(), code_target, context, object, name,
value, smi_slot, feedback_vector);
VARIABLE(var_result, MachineRepresentation::kTagged);
Label no_feedback(this, Label::kDeferred), end(this);
GotoIf(IsUndefined(maybe_vector), &no_feedback);
var_result.Bind(CallStub(ic.descriptor(), code_target, context, object,
name, value, smi_slot, maybe_vector));
Goto(&end);
Bind(&no_feedback);
TNode<JSFunction> closure =
CAST(LoadRegister(Register::function_closure()));
Node* language_mode = GetLanguageMode(closure, context);
var_result.Bind(CallRuntime(Runtime::kStoreICNoFeedback_Miss, context,
value, object, name, language_mode,
SmiConstant(property_type)));
Goto(&end);
Bind(&end);
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
SetAccumulator(var_result.value());
Dispatch();
}
};
......@@ -582,7 +639,7 @@ class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
// accumulator.
IGNITION_HANDLER(StaNamedProperty, InterpreterStoreNamedPropertyAssembler) {
Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreIC);
StaNamedProperty(ic);
StaNamedProperty(ic, NamedPropertyType::kNotOwn);
}
// StaNamedOwnProperty <object> <name_index> <slot>
......@@ -592,7 +649,7 @@ IGNITION_HANDLER(StaNamedProperty, InterpreterStoreNamedPropertyAssembler) {
// accumulator.
IGNITION_HANDLER(StaNamedOwnProperty, InterpreterStoreNamedPropertyAssembler) {
Callable ic = CodeFactory::StoreOwnICInOptimizedCode(isolate());
StaNamedProperty(ic);
StaNamedProperty(ic, NamedPropertyType::kOwn);
}
// StaNamedPropertyNoFeedback <object> <name_index>
......@@ -623,16 +680,31 @@ IGNITION_HANDLER(StaKeyedProperty, InterpreterAssembler) {
Node* value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
Node* result = CallBuiltin(Builtins::kKeyedStoreIC, context, object, name,
value, smi_slot, feedback_vector);
Label no_feedback(this, Label::kDeferred), end(this);
VARIABLE(var_result, MachineRepresentation::kTagged);
GotoIf(IsUndefined(maybe_vector), &no_feedback);
var_result.Bind(CallBuiltin(Builtins::kKeyedStoreIC, context, object, name,
value, smi_slot, maybe_vector));
Goto(&end);
Bind(&no_feedback);
TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
Node* language_mode = GetLanguageMode(closure, context);
var_result.Bind(CallRuntime(Runtime::kKeyedStoreICNoFeedback_Miss, context,
value, object, name, language_mode));
Goto(&end);
Bind(&end);
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
SetAccumulator(var_result.value());
Dispatch();
}
......@@ -646,16 +718,29 @@ IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
Node* value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
Node* smi_slot = SmiTag(raw_slot);
Node* feedback_vector = LoadFeedbackVector();
Node* feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
Node* result = CallBuiltin(Builtins::kStoreInArrayLiteralIC, context, array,
index, value, smi_slot, feedback_vector);
VARIABLE(var_result, MachineRepresentation::kTagged);
Label no_feedback(this, Label::kDeferred), end(this);
GotoIf(IsUndefined(feedback_vector), &no_feedback);
var_result.Bind(CallBuiltin(Builtins::kStoreInArrayLiteralIC, context, array,
index, value, smi_slot, feedback_vector));
Goto(&end);
BIND(&no_feedback);
var_result.Bind(CallRuntime(Runtime::kStoreInArrayLiteralIC_Miss, context,
value, smi_slot, feedback_vector, array, index));
Goto(&end);
BIND(&end);
// To avoid special logic in the deoptimizer to re-materialize the value in
// the accumulator, we overwrite the accumulator after the IC call. It
// doesn't really matter what we write to the accumulator here, since we
// restore to the correct value on the outside. Storing the result means we
// don't need to keep unnecessary state alive across the callstub.
SetAccumulator(result);
SetAccumulator(var_result.value());
Dispatch();
}
......
......@@ -179,7 +179,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
HasSimpleParametersField::encode(has_simple_parameters) |
FunctionKindField::encode(function_kind) |
HasOuterScopeInfoField::encode(has_outer_scope_info) |
IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope());
IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope()) |
ForceContextAllocationField::encode(scope->ForceContextForLanguageMode());
scope_info->SetFlags(flags);
scope_info->SetParameterCount(parameter_count);
......@@ -482,7 +483,9 @@ int ScopeInfo::ContextLength() const {
int context_locals = ContextLocalCount();
bool function_name_context_slot =
FunctionVariableField::decode(Flags()) == CONTEXT;
bool has_context = context_locals > 0 || function_name_context_slot ||
bool force_context = ForceContextAllocationField::decode(Flags());
bool has_context = context_locals > 0 || force_context ||
function_name_context_slot ||
scope_type() == WITH_SCOPE ||
(scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
is_declaration_scope()) ||
......
......@@ -201,13 +201,52 @@ class ScopeInfo : public FixedArray {
FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(FIELD_ACCESSORS)
#undef FIELD_ACCESSORS
enum {
enum Fields {
#define DECL_INDEX(name) k##name,
FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(DECL_INDEX)
#undef DECL_INDEX
kVariablePartIndex
};
// Used for the function name variable for named function expressions, and for
// the receiver.
enum VariableAllocationInfo { NONE, STACK, CONTEXT, UNUSED };
// Properties of scopes.
class ScopeTypeField : public BitField<ScopeType, 0, 4> {};
class CallsSloppyEvalField : public BitField<bool, ScopeTypeField::kNext, 1> {
};
STATIC_ASSERT(LanguageModeSize == 2);
class LanguageModeField
: public BitField<LanguageMode, CallsSloppyEvalField::kNext, 1> {};
class DeclarationScopeField
: public BitField<bool, LanguageModeField::kNext, 1> {};
class ReceiverVariableField
: public BitField<VariableAllocationInfo, DeclarationScopeField::kNext,
2> {};
class HasNewTargetField
: public BitField<bool, ReceiverVariableField::kNext, 1> {};
class FunctionVariableField
: public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
// TODO(cbruni): Combine with function variable field when only storing the
// function name.
class HasInferredFunctionNameField
: public BitField<bool, FunctionVariableField::kNext, 1> {};
class AsmModuleField
: public BitField<bool, HasInferredFunctionNameField::kNext, 1> {};
class HasSimpleParametersField
: public BitField<bool, AsmModuleField::kNext, 1> {};
class FunctionKindField
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 5> {};
class HasOuterScopeInfoField
: public BitField<bool, FunctionKindField::kNext, 1> {};
class IsDebugEvaluateScopeField
: public BitField<bool, HasOuterScopeInfoField::kNext, 1> {};
class ForceContextAllocationField
: public BitField<bool, IsDebugEvaluateScopeField::kNext, 1> {};
STATIC_ASSERT(kLastFunctionKind <= FunctionKindField::kMax);
private:
// The layout of the variable part of a ScopeInfo is as follows:
// 1. ContextLocalNames:
......@@ -267,46 +306,9 @@ class ScopeInfo : public FixedArray {
InitializationFlag* init_flag = nullptr,
MaybeAssignedFlag* maybe_assigned_flag = nullptr);
// Used for the function name variable for named function expressions, and for
// the receiver.
enum VariableAllocationInfo { NONE, STACK, CONTEXT, UNUSED };
static const int kFunctionNameEntries = 2;
static const int kPositionInfoEntries = 2;
// Properties of scopes.
class ScopeTypeField : public BitField<ScopeType, 0, 4> {};
class CallsSloppyEvalField : public BitField<bool, ScopeTypeField::kNext, 1> {
};
STATIC_ASSERT(LanguageModeSize == 2);
class LanguageModeField
: public BitField<LanguageMode, CallsSloppyEvalField::kNext, 1> {};
class DeclarationScopeField
: public BitField<bool, LanguageModeField::kNext, 1> {};
class ReceiverVariableField
: public BitField<VariableAllocationInfo, DeclarationScopeField::kNext,
2> {};
class HasNewTargetField
: public BitField<bool, ReceiverVariableField::kNext, 1> {};
class FunctionVariableField
: public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
// TODO(cbruni): Combine with function variable field when only storing the
// function name.
class HasInferredFunctionNameField
: public BitField<bool, FunctionVariableField::kNext, 1> {};
class AsmModuleField
: public BitField<bool, HasInferredFunctionNameField::kNext, 1> {};
class HasSimpleParametersField
: public BitField<bool, AsmModuleField::kNext, 1> {};
class FunctionKindField
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 5> {};
class HasOuterScopeInfoField
: public BitField<bool, FunctionKindField::kNext, 1> {};
class IsDebugEvaluateScopeField
: public BitField<bool, HasOuterScopeInfoField::kNext, 1> {};
STATIC_ASSERT(kLastFunctionKind <= FunctionKindField::kMax);
// Properties of variables.
class VariableModeField : public BitField<VariableMode, 0, 3> {};
class InitFlagField : public BitField<InitializationFlag, 3, 1> {};
......
......@@ -552,18 +552,22 @@ namespace internal {
F(ElementsTransitionAndStoreIC_Miss, 6, 1) \
F(KeyedLoadIC_Miss, 4, 1) \
F(KeyedStoreIC_Miss, 5, 1) \
F(KeyedStoreICNoFeedback_Miss, 4, 1) \
F(StoreInArrayLiteralIC_Miss, 5, 1) \
F(KeyedStoreIC_Slow, 5, 1) \
F(LoadAccessorProperty, 4, 1) \
F(LoadCallbackProperty, 4, 1) \
F(LoadElementWithInterceptor, 2, 1) \
F(LoadGlobalIC_Miss, 3, 1) \
F(LoadGlobalIC_Miss, 4, 1) \
F(LoadGlobalIC_Slow, 3, 1) \
F(LoadIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \
F(StoreCallbackProperty, 6, 1) \
F(StoreGlobalIC_Miss, 4, 1) \
F(StoreGlobalICNoFeedback_Miss, 3, 1) \
F(StoreGlobalIC_Slow, 5, 1) \
F(StoreIC_Miss, 5, 1) \
F(StoreICNoFeedback_Miss, 5, 1) \
F(StoreInArrayLiteralIC_Slow, 5, 1) \
F(StorePropertyWithInterceptor, 5, 1) \
F(CloneObjectIC_Miss, 4, 1)
......
......@@ -12,28 +12,32 @@ snippet: "
speak() { console.log(this.name + ' is speaking.'); }
}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 38
bytecode array length: 44
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(CreateClosure), U8(2), U8(1), U8(2),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(1),
B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
B(LdaUndefined),
/* 149 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
......@@ -48,28 +52,32 @@ snippet: "
speak() { console.log(this.name + ' is speaking.'); }
}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 38
bytecode array length: 44
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(CreateClosure), U8(2), U8(1), U8(2),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(1),
B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
B(LdaUndefined),
/* 149 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
......@@ -86,9 +94,9 @@ snippet: "
static [n1]() { return n1; }
}
"
frame size: 11
frame size: 12
parameter count: 1
bytecode array length: 77
bytecode array length: 87
bytecodes: [
B(CreateFunctionContext), U8(0), U8(2),
B(PushContext), R(2),
......@@ -97,28 +105,31 @@ bytecodes: [
/* 43 E> */ B(StaCurrentContextSlot), U8(4),
/* 57 S> */ B(LdaConstant), U8(2),
/* 57 E> */ B(StaCurrentContextSlot), U8(5),
B(CreateBlockContext), U8(3),
B(PushContext), R(3),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(4), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(3),
B(Star), R(7),
B(CreateClosure), U8(5), U8(0), U8(2),
B(Star), R(4),
/* 75 S> */ B(LdaImmutableCurrentContextSlot), U8(4),
B(ToName), R(7),
B(CreateClosure), U8(5), U8(1), U8(2),
B(Star), R(8),
/* 106 S> */ B(LdaImmutableCurrentContextSlot), U8(5),
B(ToName), R(9),
B(LdaConstant), U8(6),
B(TestEqualStrict), R(9), U8(2),
B(Mov), R(3), R(5),
B(LdaConstant), U8(4),
B(Star), R(5),
/* 75 S> */ B(LdaImmutableContextSlot), R(3), U8(4), U8(0),
B(ToName), R(8),
B(CreateClosure), U8(6), U8(1), U8(2),
B(Star), R(9),
/* 106 S> */ B(LdaImmutableContextSlot), R(3), U8(5), U8(0),
B(ToName), R(10),
B(LdaConstant), U8(7),
B(TestEqualStrict), R(10), U8(2),
B(Mov), R(4), R(6),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), R(0), U8(0),
B(CreateClosure), U8(7), U8(3), U8(2),
B(Star), R(10),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(7),
B(Star), R(4),
B(Mov), R(3), R(0),
B(CreateClosure), U8(8), U8(3), U8(2),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kDefineClass), R(5), U8(7),
B(Star), R(5),
B(Mov), R(4), R(0),
B(PopContext), R(3),
B(Mov), R(0), R(1),
B(LdaUndefined),
/* 129 S> */ B(Return),
......@@ -127,6 +138,7 @@ constant pool: [
SCOPE_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["a"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["b"],
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
......@@ -142,31 +154,35 @@ snippet: "
class C { constructor() { count++; }}
return new C();
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 46
bytecode array length: 52
bytecodes: [
B(CreateFunctionContext), U8(0), U8(1),
B(PushContext), R(2),
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(LdaZero),
/* 46 E> */ B(StaCurrentContextSlot), U8(4),
B(CreateBlockContext), U8(1),
B(PushContext), R(3),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(7),
B(CreateClosure), U8(3), U8(0), U8(2),
B(Star), R(4),
B(Mov), R(5), R(0),
B(LdaConstant), U8(2),
B(Star), R(5),
B(Mov), R(4), R(6),
B(CallRuntime), U16(Runtime::kDefineClass), R(5), U8(3),
B(Star), R(5),
B(Mov), R(6), R(0),
B(PopContext), R(3),
B(Mov), R(0), R(1),
/* 87 S> */ B(Ldar), R(1),
/* 94 E> */ B(Construct), R(3), R(0), U8(0), U8(1),
/* 94 E> */ B(Construct), R(1), R(0), U8(0), U8(1),
/* 102 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
......@@ -179,39 +195,47 @@ snippet: "
(class {})
class E { static name () {}}
"
frame size: 7
frame size: 8
parameter count: 1
bytecode array length: 61
bytecode array length: 73
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(Star), R(3),
/* 34 S> */ B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(2),
B(LdaConstant), U8(2),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(CreateClosure), U8(4), U8(2), U8(2),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(PopContext), R(2),
B(CreateBlockContext), U8(3),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(CreateClosure), U8(5), U8(1), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(4),
B(Star), R(4),
B(CreateClosure), U8(6), U8(2), U8(2),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
B(LdaUndefined),
/* 74 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
......
......@@ -10,30 +10,34 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(...[1, 2, 3]);
"
frame size: 6
frame size: 7
parameter count: 1
bytecode array length: 45
bytecode array length: 51
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
/* 89 S> */ B(CreateArrayLiteral), U8(3), U8(1), U8(37),
B(Star), R(3),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(1), U8(2),
/* 89 E> */ B(ConstructWithSpread), R(1), R(3), U8(1), U8(2),
B(LdaUndefined),
/* 110 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
......@@ -46,32 +50,36 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(0, ...[1, 2, 3]);
"
frame size: 6
frame size: 7
parameter count: 1
bytecode array length: 48
bytecode array length: 54
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
/* 89 S> */ B(LdaZero),
B(Star), R(3),
B(CreateArrayLiteral), U8(2), U8(1), U8(37),
B(CreateArrayLiteral), U8(3), U8(1), U8(37),
B(Star), R(4),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(2), R(3), U8(2), U8(2),
/* 89 E> */ B(ConstructWithSpread), R(1), R(3), U8(2), U8(2),
B(LdaUndefined),
/* 113 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
......@@ -86,41 +94,45 @@ snippet: "
"
frame size: 10
parameter count: 1
bytecode array length: 124
bytecode array length: 133
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(Mov), R(4), R(0),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(0),
B(PopContext), R(2),
B(Mov), R(0), R(1),
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
/* 89 S> */ B(CreateArrayLiteral), U8(3), U8(1), U8(37),
B(Star), R(4),
B(LdaConstant), U8(3),
B(LdaConstant), U8(4),
B(Star), R(3),
/* 101 S> */ B(CreateArrayLiteral), U8(4), U8(5), U8(37),
/* 101 S> */ B(CreateArrayLiteral), U8(5), U8(5), U8(37),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(5), U8(6),
B(LdaNamedProperty), R(8), U8(6), U8(6),
B(Star), R(9),
B(CallProperty0), R(9), R(8), U8(8),
B(Mov), R(5), R(2),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(6), U8(10),
B(LdaNamedProperty), R(7), U8(7), U8(10),
B(Star), R(6),
B(CallProperty0), R(6), R(7), U8(12),
B(Star), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(5), U8(1),
B(LdaNamedProperty), R(5), U8(7), U8(14),
B(LdaNamedProperty), R(5), U8(8), U8(14),
B(JumpIfToBooleanTrue), U8(21),
B(LdaNamedProperty), R(5), U8(8), U8(16),
B(LdaNamedProperty), R(5), U8(9), U8(16),
B(Star), R(5),
B(StaInArrayLiteral), R(4), R(3), U8(3),
B(Ldar), R(3),
......@@ -135,6 +147,7 @@ bytecodes: [
/* 116 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
......
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