[ic] Fallback to runtime from builtins to check if we throw on error

When an error occurs when storing the properties we either need to
throw or ignore the error depending on the language mode. We used
to infer the language mode from the type feedback vector. This cl
instead falls back to runtime to check and throw an error when
needed.

Bug: v8:8580
Change-Id: Iebeb3ca86d753157329dc1b5cfd1c07af2ff3dcd
Reviewed-on: https://chromium-review.googlesource.com/c/1458220
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59563}
This commit is contained in:
Mythri 2019-02-07 14:35:24 +00:00 committed by Commit Bot
parent 421cf6136c
commit 503fb21987
9 changed files with 32 additions and 161 deletions

View File

@ -918,7 +918,7 @@ namespace internal {
TFJ(ProxyRevoke, 0, kReceiver) \
TFS(ProxyGetProperty, kProxy, kName, kReceiverValue, kOnNonExistent) \
TFS(ProxyHasProperty, kProxy, kName) \
TFS(ProxySetProperty, kProxy, kName, kValue, kReceiverValue, kLanguageMode) \
TFS(ProxySetProperty, kProxy, kName, kValue, kReceiverValue) \
\
/* Reflect */ \
ASM(ReflectApply, Dummy) \

View File

@ -545,7 +545,6 @@ TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
Node* name = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue);
Node* receiver = Parameter(Descriptor::kReceiverValue);
TNode<Smi> language_mode = CAST(Parameter(Descriptor::kLanguageMode));
CSA_ASSERT(this, IsJSProxy(proxy));
@ -596,13 +595,10 @@ TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
BIND(&failure);
{
Label if_throw(this, Label::kDeferred);
Branch(SmiEqual(language_mode, SmiConstant(LanguageMode::kStrict)),
&if_throw, &success);
BIND(&if_throw);
ThrowTypeError(context, MessageTemplate::kProxyTrapReturnedFalsishFor,
HeapConstant(set_string), name);
CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor),
HeapConstant(set_string), name);
Goto(&success);
}
// 12. Return true.
@ -611,16 +607,11 @@ TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
BIND(&private_symbol);
{
Label failure(this), throw_error(this, Label::kDeferred);
Label failure(this);
Branch(SmiEqual(language_mode, SmiConstant(LanguageMode::kStrict)),
&throw_error, &failure);
BIND(&failure);
CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
SmiConstant(MessageTemplate::kProxyPrivate));
Return(UndefinedConstant());
BIND(&throw_error);
ThrowTypeError(context, MessageTemplate::kProxyPrivate);
}
BIND(&trap_undefined);

View File

@ -10028,57 +10028,6 @@ 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) {

View File

@ -2788,11 +2788,6 @@ 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.

View File

@ -1393,17 +1393,6 @@ void AccessorAssembler::HandleStoreICProtoHandler(
}
}
Node* AccessorAssembler::GetLanguageMode(Node* vector, Node* slot) {
VARIABLE(var_language_mode, MachineRepresentation::kTaggedSigned,
SmiConstant(LanguageMode::kStrict));
Label language_mode_determined(this);
BranchIfStrictMode(vector, slot, &language_mode_determined);
var_language_mode.Bind(SmiConstant(LanguageMode::kSloppy));
Goto(&language_mode_determined);
BIND(&language_mode_determined);
return var_language_mode.value();
}
void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
Node* proxy, Label* miss,
ElementSupport support_elements) {
@ -1413,18 +1402,13 @@ 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) {
TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
&to_name_failed);
BIND(&if_unique_name);
CallBuiltin(Builtins::kProxySetProperty, p->context, proxy,
var_unique.value(), p->value, p->receiver, language_mode);
var_unique.value(), p->value, p->receiver);
Return(p->value);
// The index case is handled earlier by the runtime.
@ -1439,7 +1423,7 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
} else {
Node* name = CallBuiltin(Builtins::kToName, p->context, p->name);
TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name,
p->value, p->receiver, language_mode);
p->value, p->receiver);
}
}
@ -1949,43 +1933,6 @@ void AccessorAssembler::NameDictionaryNegativeLookup(Node* object,
BIND(&done);
}
void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
Label* if_strict) {
Node* sfi =
LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset);
TNode<FeedbackMetadata> metadata = CAST(LoadObjectField(
sfi, SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset));
Node* slot_int = SmiToInt32(slot);
// See VectorICComputer::index().
const int kItemsPerWord = FeedbackMetadata::VectorICComputer::kItemsPerWord;
Node* word_index = Int32Div(slot_int, Int32Constant(kItemsPerWord));
Node* word_offset = Int32Mod(slot_int, Int32Constant(kItemsPerWord));
int32_t first_item = FeedbackMetadata::kHeaderSize - kHeapObjectTag;
Node* offset =
ElementOffsetFromIndex(ChangeInt32ToIntPtr(word_index), UINT32_ELEMENTS,
INTPTR_PARAMETERS, first_item);
Node* data = Load(MachineType::Int32(), metadata, offset);
// See VectorICComputer::decode().
const int kBitsPerItem = FeedbackMetadata::kFeedbackSlotKindBits;
Node* shift = Int32Mul(word_offset, Int32Constant(kBitsPerItem));
const int kMask = FeedbackMetadata::VectorICComputer::kMask;
Node* kind = Word32And(Word32Shr(data, shift), Int32Constant(kMask));
STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
FeedbackSlotKind::kLastSloppyKind);
STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
FeedbackSlotKind::kLastSloppyKind);
STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
FeedbackSlotKind::kLastSloppyKind);
GotoIfNot(Int32LessThanOrEqual(kind, Int32Constant(static_cast<int>(
FeedbackSlotKind::kLastSloppyKind))),
if_strict);
}
void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
Node* bitfield2) {
Label is_prototype(this), cont(this);

View File

@ -123,8 +123,6 @@ class AccessorAssembler : public CodeStubAssembler {
void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
void BranchIfStrictMode(Node* vector, Node* slot, Label* if_strict);
void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
@ -274,8 +272,6 @@ class AccessorAssembler : public CodeStubAssembler {
const OnFoundOnReceiver& on_found_on_receiver,
Label* miss, ICMode ic_mode);
Node* GetLanguageMode(Node* vector, Node* slot);
Node* PrepareValueForStore(Node* handler_word, Node* holder,
Representation representation, Node* value,
Label* bailout);

View File

@ -912,29 +912,21 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&not_callable);
{
bool handle_strict = true;
Label strict(this);
LanguageMode language_mode;
if (maybe_language_mode.To(&language_mode)) {
if (language_mode == LanguageMode::kStrict) {
Goto(&strict);
} else {
handle_strict = false;
exit_point->Return(p->value);
}
} else {
BranchIfStrictMode(p->vector, p->slot, &strict);
exit_point->Return(p->value);
}
if (handle_strict) {
BIND(&strict);
{
exit_point->ReturnCallRuntime(
Runtime::kThrowTypeError, p->context,
SmiConstant(MessageTemplate::kNoSetterInCallback), p->name,
var_accessor_holder.value());
} else {
exit_point->Return(p->value);
}
} else {
CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
SmiConstant(MessageTemplate::kNoSetterInCallback),
p->name, var_accessor_holder.value());
exit_point->Return(p->value);
}
}
}
@ -943,27 +935,20 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (!ShouldReconfigureExisting()) {
BIND(&readonly);
{
bool handle_strict = true;
Label strict(this);
LanguageMode language_mode;
if (maybe_language_mode.To(&language_mode)) {
if (language_mode == LanguageMode::kStrict) {
Goto(&strict);
} else {
handle_strict = false;
exit_point->Return(p->value);
}
} else {
BranchIfStrictMode(p->vector, p->slot, &strict);
exit_point->Return(p->value);
}
if (handle_strict) {
BIND(&strict);
{
Node* type = Typeof(p->receiver);
ThrowTypeError(p->context, MessageTemplate::kStrictReadOnlyProperty,
p->name, type, p->receiver);
} else {
exit_point->Return(p->value);
}
} else {
CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
SmiConstant(MessageTemplate::kStrictReadOnlyProperty),
p->name, Typeof(p->receiver), p->receiver);
exit_point->Return(p->value);
}
}
}

View File

@ -95,6 +95,13 @@ RUNTIME_FUNCTION(Runtime_ThrowTypeError) {
THROW_ERROR(isolate, args, NewTypeError);
}
RUNTIME_FUNCTION(Runtime_ThrowTypeErrorIfStrict) {
if (GetShouldThrow(isolate, Nothing<ShouldThrow>()) ==
ShouldThrow::kDontThrow)
return ReadOnlyRoots(isolate).undefined_value();
THROW_ERROR(isolate, args, NewTypeError);
}
#undef THROW_ERROR
namespace {

View File

@ -248,6 +248,7 @@ namespace internal {
F(ThrowSymbolIteratorInvalid, 0, 1) \
F(ThrowThrowMethodMissing, 0, 1) \
F(ThrowTypeError, -1 /* >= 1 */, 1) \
F(ThrowTypeErrorIfStrict, -1 /* >= 1 */, 1) \
F(Typeof, 1, 1) \
F(UnwindAndFindExceptionHandler, 0, 1) \
F(FinalizationGroupCleanupJob, 1, 1)