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) {
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(
Isolate* isolate) {
return ExternalReference(
......
......@@ -1046,6 +1046,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference stress_deopt_count(Isolate* isolate);
static ExternalReference force_slow_path(Isolate* isolate);
static ExternalReference fixed_typed_array_base_data_offset();
private:
......
......@@ -366,6 +366,8 @@ Node* PromiseBuiltinsAssembler::InternalPromiseThen(Node* context,
VARIABLE(var_deferred_on_resolve, MachineRepresentation::kTagged);
VARIABLE(var_deferred_on_reject, MachineRepresentation::kTagged);
GotoIfForceSlowPath(&promise_capability);
Branch(WordEqual(promise_fun, constructor), &fast_promise_capability,
&promise_capability);
......@@ -615,6 +617,8 @@ void PromiseBuiltinsAssembler::BranchIfFastPath(Node* native_context,
LoadContextElement(native_context,
Context::PROMISE_FUNCTION_INDEX)));
GotoIfForceSlowPath(if_ismodified);
Node* const map = LoadMap(promise);
Node* const initial_map =
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
......@@ -1463,6 +1467,9 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
Node* const native_context = LoadNativeContext(context);
GotoIfForceSlowPath(&if_custompromise);
Node* const promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
......
......@@ -834,6 +834,11 @@ Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context,
Label out(this);
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 regexp_fun =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
......@@ -871,6 +876,8 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
Label* const if_ismodified) {
CSA_ASSERT(this, WordEqual(LoadMap(object), map));
GotoIfForceSlowPath(if_ismodified);
// TODO(ishell): Update this check once map changes for constant field
// tracking are landing.
......
......@@ -872,6 +872,8 @@ TNode<BoolT> CodeStubAssembler::IsFastJSArray(SloppyTNode<Object> object,
void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context,
Label* if_true, Label* if_false) {
GotoIfForceSlowPath(if_false);
// Bailout if receiver is a Smi.
GotoIf(TaggedIsSmi(object), if_false);
......@@ -895,6 +897,16 @@ void CodeStubAssembler::BranchIfFastJSArrayForCopy(Node* object, Node* context,
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* top_address, Node* limit_address) {
Node* top = Load(MachineType::Pointer(), top_address);
......
......@@ -413,6 +413,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void BranchIfFastJSArrayForCopy(Node* object, Node* context, Label* if_true,
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.
Node* LoadFromFrame(int offset, MachineType rep = MachineType::AnyTagged());
// Load value from current parent frame by given offset in bytes.
......
......@@ -3274,6 +3274,10 @@ class TypedElementsAccessor
DisallowHeapAllocation no_gc;
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();
// Null prototypes are OK - we don't need to do prototype chain lookups on
......
......@@ -282,6 +282,8 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"double_constants.minus_one_half");
Add(ExternalReference::stress_deopt_count(isolate).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(),
"Runtime::runtime_function_table_address()");
Add(ExternalReference::address_of_float_abs_constant().address(),
......
......@@ -757,6 +757,7 @@ DEFINE_BOOL(enable_experimental_builtins, true,
// builtins.cc
DEFINE_BOOL(allow_unsafe_function_constructor, false,
"allow invoking the function constructor without security checks")
DEFINE_BOOL(force_slow_path, false, "always take the slow path for builtins")
// builtins-ia32.cc
DEFINE_BOOL(inline_new, true, "use fast inline allocation")
......
......@@ -2408,6 +2408,7 @@ Isolate::Isolate(bool enable_serializer)
deferred_handles_head_(nullptr),
optimizing_compile_dispatcher_(nullptr),
stress_deopt_count_(0),
force_slow_path_(false),
next_optimization_id_(0),
#if V8_SFI_HAS_UNIQUE_ID
next_unique_sfi_id_(0),
......@@ -2746,6 +2747,7 @@ bool Isolate::Init(StartupDeserializer* des) {
TRACE_ISOLATE(init);
stress_deopt_count_ = FLAG_deopt_every_n_times;
force_slow_path_ = FLAG_force_slow_path;
has_fatal_error_ = false;
......
......@@ -1163,6 +1163,10 @@ class Isolate {
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* fuzzer_rng();
......@@ -1599,6 +1603,8 @@ class Isolate {
// Counts deopt points if deopt_every_n_times is enabled.
unsigned int stress_deopt_count_;
bool force_slow_path_;
int next_optimization_id_;
#if V8_SFI_HAS_UNIQUE_ID
......
......@@ -2613,6 +2613,10 @@ bool Object::IterationHasObservableEffects() {
JSArray* array = JSArray::cast(this);
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.
if (!array->map()->prototype()->IsJSObject()) return true;
JSObject* array_proto = JSObject::cast(array->map()->prototype());
......
......@@ -134,6 +134,10 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
// TODO(ishell): Update this check once map changes for constant field
// tracking are landing.
#if defined(DEBUG) || defined(ENABLE_SLOWFAST_SWITCH)
if (isolate->force_slow_path()) return false;
#endif
if (!obj->IsJSReceiver()) return false;
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