Commit f2150dbd authored by Michal Majewski's avatar Michal Majewski Committed by Commit Bot

[test] Add switch to always use slow path.

Introduce new runtime flag that forces to always use
slow path for regex, promise and array builtins. It
works in DEBUG or with new compile time flag
ENABLE_FASTSLOW_SWITCH.

It will be used in the fast/slow path fuzzer or as a
testing variant to ensure that slow path implementation
behave equivalent to corresponding fast paths (where
applicable).

Bug: v8:7120
Change-Id: Ia2a4ab7aca5051e852723782c529bd2e8e5925ca
Reviewed-on: https://chromium-review.googlesource.com/787291
Commit-Queue: Michał Majewski <majeski@google.com>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49642}
parent b0a87c85
...@@ -869,6 +869,10 @@ ExternalReference ExternalReference::stress_deopt_count(Isolate* isolate) { ...@@ -869,6 +869,10 @@ ExternalReference ExternalReference::stress_deopt_count(Isolate* isolate) {
return ExternalReference(isolate->stress_deopt_count_address()); return ExternalReference(isolate->stress_deopt_count_address());
} }
ExternalReference ExternalReference::force_slow_path(Isolate* isolate) {
return ExternalReference(isolate->force_slow_path_address());
}
ExternalReference ExternalReference::new_deoptimizer_function( ExternalReference ExternalReference::new_deoptimizer_function(
Isolate* isolate) { Isolate* isolate) {
return ExternalReference( return ExternalReference(
......
...@@ -1046,6 +1046,8 @@ class ExternalReference BASE_EMBEDDED { ...@@ -1046,6 +1046,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference stress_deopt_count(Isolate* isolate); static ExternalReference stress_deopt_count(Isolate* isolate);
static ExternalReference force_slow_path(Isolate* isolate);
static ExternalReference fixed_typed_array_base_data_offset(); static ExternalReference fixed_typed_array_base_data_offset();
private: private:
......
...@@ -366,6 +366,8 @@ Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context, ...@@ -366,6 +366,8 @@ Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
VARIABLE(var_deferred_on_resolve, MachineRepresentation::kTagged); VARIABLE(var_deferred_on_resolve, MachineRepresentation::kTagged);
VARIABLE(var_deferred_on_reject, MachineRepresentation::kTagged); VARIABLE(var_deferred_on_reject, MachineRepresentation::kTagged);
GotoIfForceSlowPath(&promise_capability);
Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
&promise_capability); &promise_capability);
...@@ -615,6 +617,8 @@ void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context, ...@@ -615,6 +617,8 @@ void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
LoadContextElement(native_context, LoadContextElement(native_context,
Context::PROMISE_FUNCTION_INDEX))); Context::PROMISE_FUNCTION_INDEX)));
GotoIfForceSlowPath(if_ismodified);
Node* const map = LoadMap(promise); Node* const map = LoadMap(promise);
Node* const initial_map = Node* const initial_map =
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
...@@ -1463,6 +1467,9 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) { ...@@ -1463,6 +1467,9 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
Label if_nativepromise(this), if_custompromise(this, Label::kDeferred); Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
Node* const native_context = LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
GotoIfForceSlowPath(&if_custompromise);
Node* const promise_fun = Node* const promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
Branch(WordEqual(promise_fun, receiver), &if_nativepromise, Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
......
...@@ -834,6 +834,11 @@ Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context, ...@@ -834,6 +834,11 @@ Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context,
Label out(this); Label out(this);
VARIABLE(var_result, MachineRepresentation::kWord32); VARIABLE(var_result, MachineRepresentation::kWord32);
#if defined(DEBUG) || defined(ENABLE_FASTSLOW_SWITCH)
var_result.Bind(Int32Constant(0));
GotoIfForceSlowPath(&out);
#endif
Node* const native_context = LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const regexp_fun = Node* const regexp_fun =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
...@@ -871,6 +876,8 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, ...@@ -871,6 +876,8 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
Label* const if_ismodified) { Label* const if_ismodified) {
CSA_ASSERT(this, WordEqual(LoadMap(object), map)); CSA_ASSERT(this, WordEqual(LoadMap(object), map));
GotoIfForceSlowPath(if_ismodified);
// TODO(ishell): Update this check once map changes for constant field // TODO(ishell): Update this check once map changes for constant field
// tracking are landing. // tracking are landing.
......
...@@ -872,6 +872,8 @@ TNode<BoolT> CodeStubAssembler::IsFastJSArray(SloppyTNode<Object> object, ...@@ -872,6 +872,8 @@ TNode<BoolT> CodeStubAssembler::IsFastJSArray(SloppyTNode<Object> object,
void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context, void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context,
Label* if_true, Label* if_false) { Label* if_true, Label* if_false) {
GotoIfForceSlowPath(if_false);
// Bailout if receiver is a Smi. // Bailout if receiver is a Smi.
GotoIf(TaggedIsSmi(object), if_false); GotoIf(TaggedIsSmi(object), if_false);
...@@ -895,6 +897,16 @@ void CodeStubAssembler::BranchIfFastJSArrayForCopy(Node* object, Node* context, ...@@ -895,6 +897,16 @@ void CodeStubAssembler::BranchIfFastJSArrayForCopy(Node* object, Node* context,
BranchIfFastJSArray(object, context, if_true, if_false); BranchIfFastJSArray(object, context, if_true, if_false);
} }
void CodeStubAssembler::GotoIfForceSlowPath(Label* if_true) {
#if defined(DEBUG) || defined(ENABLE_FASTSLOW_SWITCH)
Node* const force_slow_path_addr =
ExternalConstant(ExternalReference::force_slow_path(isolate()));
Node* const force_slow = Load(MachineType::Uint8(), force_slow_path_addr);
GotoIf(force_slow, if_true);
#endif
}
Node* CodeStubAssembler::AllocateRaw(Node* size_in_bytes, AllocationFlags flags, Node* CodeStubAssembler::AllocateRaw(Node* size_in_bytes, AllocationFlags flags,
Node* top_address, Node* limit_address) { Node* top_address, Node* limit_address) {
Node* top = Load(MachineType::Pointer(), top_address); Node* top = Load(MachineType::Pointer(), top_address);
......
...@@ -413,6 +413,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -413,6 +413,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void BranchIfFastJSArrayForCopy(Node* object, Node* context, Label* if_true, void BranchIfFastJSArrayForCopy(Node* object, Node* context, Label* if_true,
Label* if_false); Label* if_false);
// Branches to {if_true} when --force-slow-path flag has been passed.
// It's used for testing to ensure that slow path implementation behave
// equivalent to corresponding fast paths (where applicable).
//
// Works only in DEBUG mode or with ENABLE_FASTSLOW_SWITCH compile time flag.
// Nop otherwise.
void GotoIfForceSlowPath(Label* if_true);
// Load value from current frame by given offset in bytes. // Load value from current frame by given offset in bytes.
Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged()); Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged());
// Load value from current parent frame by given offset in bytes. // Load value from current parent frame by given offset in bytes.
......
...@@ -3274,6 +3274,10 @@ class TypedElementsAccessor ...@@ -3274,6 +3274,10 @@ class TypedElementsAccessor
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
DisallowJavascriptExecution no_js(isolate); DisallowJavascriptExecution no_js(isolate);
#if defined(DEBUG) || defined(ENABLE_SLOWFAST_SWITCH)
if (isolate->force_slow_path()) return true;
#endif
Object* source_proto = source->map()->prototype(); Object* source_proto = source->map()->prototype();
// Null prototypes are OK - we don't need to do prototype chain lookups on // Null prototypes are OK - we don't need to do prototype chain lookups on
......
...@@ -282,6 +282,8 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) { ...@@ -282,6 +282,8 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"double_constants.minus_one_half"); "double_constants.minus_one_half");
Add(ExternalReference::stress_deopt_count(isolate).address(), Add(ExternalReference::stress_deopt_count(isolate).address(),
"Isolate::stress_deopt_count_address()"); "Isolate::stress_deopt_count_address()");
Add(ExternalReference::force_slow_path(isolate).address(),
"Isolate::force_slow_path_address()");
Add(ExternalReference::runtime_function_table_address(isolate).address(), Add(ExternalReference::runtime_function_table_address(isolate).address(),
"Runtime::runtime_function_table_address()"); "Runtime::runtime_function_table_address()");
Add(ExternalReference::address_of_float_abs_constant().address(), Add(ExternalReference::address_of_float_abs_constant().address(),
......
...@@ -757,6 +757,7 @@ DEFINE_BOOL(enable_experimental_builtins, true, ...@@ -757,6 +757,7 @@ DEFINE_BOOL(enable_experimental_builtins, true,
// builtins.cc // builtins.cc
DEFINE_BOOL(allow_unsafe_function_constructor, false, DEFINE_BOOL(allow_unsafe_function_constructor, false,
"allow invoking the function constructor without security checks") "allow invoking the function constructor without security checks")
DEFINE_BOOL(force_slow_path, false, "always take the slow path for builtins")
// builtins-ia32.cc // builtins-ia32.cc
DEFINE_BOOL(inline_new, true, "use fast inline allocation") DEFINE_BOOL(inline_new, true, "use fast inline allocation")
......
...@@ -2408,6 +2408,7 @@ Isolate::Isolate(bool enable_serializer) ...@@ -2408,6 +2408,7 @@ Isolate::Isolate(bool enable_serializer)
deferred_handles_head_(nullptr), deferred_handles_head_(nullptr),
optimizing_compile_dispatcher_(nullptr), optimizing_compile_dispatcher_(nullptr),
stress_deopt_count_(0), stress_deopt_count_(0),
force_slow_path_(false),
next_optimization_id_(0), next_optimization_id_(0),
#if V8_SFI_HAS_UNIQUE_ID #if V8_SFI_HAS_UNIQUE_ID
next_unique_sfi_id_(0), next_unique_sfi_id_(0),
...@@ -2746,6 +2747,7 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -2746,6 +2747,7 @@ bool Isolate::Init(StartupDeserializer* des) {
TRACE_ISOLATE(init); TRACE_ISOLATE(init);
stress_deopt_count_ = FLAG_deopt_every_n_times; stress_deopt_count_ = FLAG_deopt_every_n_times;
force_slow_path_ = FLAG_force_slow_path;
has_fatal_error_ = false; has_fatal_error_ = false;
......
...@@ -1163,6 +1163,10 @@ class Isolate { ...@@ -1163,6 +1163,10 @@ class Isolate {
void* stress_deopt_count_address() { return &stress_deopt_count_; } void* stress_deopt_count_address() { return &stress_deopt_count_; }
bool force_slow_path() { return force_slow_path_; }
bool* force_slow_path_address() { return &force_slow_path_; }
V8_EXPORT_PRIVATE base::RandomNumberGenerator* random_number_generator(); V8_EXPORT_PRIVATE base::RandomNumberGenerator* random_number_generator();
V8_EXPORT_PRIVATE base::RandomNumberGenerator* fuzzer_rng(); V8_EXPORT_PRIVATE base::RandomNumberGenerator* fuzzer_rng();
...@@ -1599,6 +1603,8 @@ class Isolate { ...@@ -1599,6 +1603,8 @@ class Isolate {
// Counts deopt points if deopt_every_n_times is enabled. // Counts deopt points if deopt_every_n_times is enabled.
unsigned int stress_deopt_count_; unsigned int stress_deopt_count_;
bool force_slow_path_;
int next_optimization_id_; int next_optimization_id_;
#if V8_SFI_HAS_UNIQUE_ID #if V8_SFI_HAS_UNIQUE_ID
......
...@@ -2613,6 +2613,10 @@ bool Object::IterationHasObservableEffects() { ...@@ -2613,6 +2613,10 @@ bool Object::IterationHasObservableEffects() {
JSArray* array = JSArray::cast(this); JSArray* array = JSArray::cast(this);
Isolate* isolate = array->GetIsolate(); Isolate* isolate = array->GetIsolate();
#if defined(DEBUG) || defined(ENABLE_SLOWFAST_SWITCH)
if (isolate->force_slow_path()) return true;
#endif
// Check that we have the original ArrayPrototype. // Check that we have the original ArrayPrototype.
if (!array->map()->prototype()->IsJSObject()) return true; if (!array->map()->prototype()->IsJSObject()) return true;
JSObject* array_proto = JSObject::cast(array->map()->prototype()); JSObject* array_proto = JSObject::cast(array->map()->prototype());
......
...@@ -134,6 +134,10 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) { ...@@ -134,6 +134,10 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
// TODO(ishell): Update this check once map changes for constant field // TODO(ishell): Update this check once map changes for constant field
// tracking are landing. // tracking are landing.
#if defined(DEBUG) || defined(ENABLE_SLOWFAST_SWITCH)
if (isolate->force_slow_path()) return false;
#endif
if (!obj->IsJSReceiver()) return false; if (!obj->IsJSReceiver()) return false;
JSReceiver* recv = JSReceiver::cast(*obj); JSReceiver* recv = JSReceiver::cast(*obj);
......
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