[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:
parent
421cf6136c
commit
503fb21987
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -912,29 +912,21 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
|
||||
BIND(¬_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user