[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: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Michael Achenbach <machenbach@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#49642}
This commit is contained in:
parent
b0a87c8532
commit
f2150dbd76
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user