Introduce "optimized_out" oddball marker for compilers.
This introduces {optimized_out} as another Oddball kind to be used by optimizing compilers when values are being optimized away. The aim is providing visibility when this value leaks into the application domain. Currently this will lead to {undefined} values appearing which then silently propagate through the application. The special oddball can be identified easily as a bug and also the debugger can treat it specially when needed. R=jarin@chromium.org Review URL: https://codereview.chromium.org/1810483002 Cr-Commit-Position: refs/heads/master@{#34817}
This commit is contained in:
parent
5d62db7430
commit
eee34dd50f
@ -646,7 +646,7 @@ void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
|
||||
}
|
||||
|
||||
NonLiveFrameStateSlotReplacer replacer(
|
||||
&state_values_cache_, jsgraph()->UndefinedConstant(),
|
||||
&state_values_cache_, jsgraph()->OptimizedOutConstant(),
|
||||
liveness_analyzer()->local_count(), local_zone());
|
||||
Variable* arguments = info()->scope()->arguments();
|
||||
if (arguments != nullptr && arguments->IsStackAllocated()) {
|
||||
|
@ -29,6 +29,10 @@ Node* JSGraph::EmptyFixedArrayConstant() {
|
||||
HeapConstant(factory()->empty_fixed_array()));
|
||||
}
|
||||
|
||||
Node* JSGraph::OptimizedOutConstant() {
|
||||
return CACHED(kOptimizedOutConstant,
|
||||
HeapConstant(factory()->optimized_out()));
|
||||
}
|
||||
|
||||
Node* JSGraph::UndefinedConstant() {
|
||||
return CACHED(kUndefinedConstant, HeapConstant(factory()->undefined_value()));
|
||||
|
@ -41,6 +41,7 @@ class JSGraph : public ZoneObject {
|
||||
// Canonicalized global constants.
|
||||
Node* CEntryStubConstant(int result_size);
|
||||
Node* EmptyFixedArrayConstant();
|
||||
Node* OptimizedOutConstant();
|
||||
Node* UndefinedConstant();
|
||||
Node* TheHoleConstant();
|
||||
Node* TrueConstant();
|
||||
@ -136,6 +137,7 @@ class JSGraph : public ZoneObject {
|
||||
enum CachedNode {
|
||||
kCEntryStubConstant,
|
||||
kEmptyFixedArrayConstant,
|
||||
kOptimizedOutConstant,
|
||||
kUndefinedConstant,
|
||||
kTheHoleConstant,
|
||||
kTrueConstant,
|
||||
|
@ -37,9 +37,9 @@ void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlot(
|
||||
int index, HSimulate* simulate) {
|
||||
int operand_index = simulate->ToOperandIndex(index);
|
||||
if (operand_index == -1) {
|
||||
simulate->AddAssignedValue(index, graph()->GetConstantUndefined());
|
||||
simulate->AddAssignedValue(index, graph()->GetConstantOptimizedOut());
|
||||
} else {
|
||||
simulate->SetOperandAt(operand_index, graph()->GetConstantUndefined());
|
||||
simulate->SetOperandAt(operand_index, graph()->GetConstantOptimizedOut());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,28 +690,32 @@ HConstant* HGraph::GetConstantBool(bool value) {
|
||||
return value ? GetConstantTrue() : GetConstantFalse();
|
||||
}
|
||||
|
||||
#define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value, \
|
||||
undetectable) \
|
||||
HConstant* HGraph::GetConstant##Name() { \
|
||||
if (!constant_##name##_.is_set()) { \
|
||||
HConstant* constant = new (zone()) HConstant( \
|
||||
Unique<Object>::CreateImmovable( \
|
||||
isolate()->factory()->name##_value()), \
|
||||
Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
|
||||
false, Representation::Tagged(), htype, true, boolean_value, \
|
||||
undetectable, ODDBALL_TYPE); \
|
||||
constant->InsertAfter(entry_block()->first()); \
|
||||
constant_##name##_.set(constant); \
|
||||
} \
|
||||
return ReinsertConstantIfNecessary(constant_##name##_.get()); \
|
||||
#define DEFINE_GET_CONSTANT(Name, name, constant, type, htype, boolean_value, \
|
||||
undetectable) \
|
||||
HConstant* HGraph::GetConstant##Name() { \
|
||||
if (!constant_##name##_.is_set()) { \
|
||||
HConstant* constant = new (zone()) HConstant( \
|
||||
Unique<Object>::CreateImmovable(isolate()->factory()->constant()), \
|
||||
Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
|
||||
false, Representation::Tagged(), htype, true, boolean_value, \
|
||||
undetectable, ODDBALL_TYPE); \
|
||||
constant->InsertAfter(entry_block()->first()); \
|
||||
constant_##name##_.set(constant); \
|
||||
} \
|
||||
return ReinsertConstantIfNecessary(constant_##name##_.get()); \
|
||||
}
|
||||
|
||||
DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false,
|
||||
true)
|
||||
DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true, false)
|
||||
DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false, false)
|
||||
DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false, false)
|
||||
DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false, true)
|
||||
DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined,
|
||||
HType::Undefined(), false, true)
|
||||
DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true,
|
||||
false)
|
||||
DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false,
|
||||
false)
|
||||
DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(),
|
||||
false, false)
|
||||
DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true)
|
||||
DEFINE_GET_CONSTANT(OptimizedOut, optimized_out, optimized_out, optimized_out,
|
||||
HType::None(), false, false)
|
||||
|
||||
#undef DEFINE_GET_CONSTANT
|
||||
|
||||
|
@ -334,6 +334,7 @@ class HGraph final : public ZoneObject {
|
||||
HConstant* GetConstantBool(bool value);
|
||||
HConstant* GetConstantHole();
|
||||
HConstant* GetConstantNull();
|
||||
HConstant* GetConstantOptimizedOut();
|
||||
HConstant* GetInvalidContext();
|
||||
|
||||
bool IsConstantUndefined(HConstant* constant);
|
||||
@ -472,6 +473,7 @@ class HGraph final : public ZoneObject {
|
||||
SetOncePointer<HConstant> constant_false_;
|
||||
SetOncePointer<HConstant> constant_the_hole_;
|
||||
SetOncePointer<HConstant> constant_null_;
|
||||
SetOncePointer<HConstant> constant_optimized_out_;
|
||||
SetOncePointer<HConstant> constant_invalid_context_;
|
||||
|
||||
HOsrBuilder* osr_;
|
||||
|
@ -133,8 +133,10 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
|
||||
if (scope_info->LocalIsSynthetic(i)) continue;
|
||||
Handle<String> name(scope_info->StackLocalName(i));
|
||||
Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
|
||||
// TODO(yangguo): We convert optimized out values to {undefined} when they
|
||||
// are passed to the debugger. Eventually we should handle them somehow.
|
||||
if (value->IsTheHole()) value = isolate_->factory()->undefined_value();
|
||||
|
||||
if (value->IsOptimizedOut()) value = isolate_->factory()->undefined_value();
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
|
||||
}
|
||||
}
|
||||
|
@ -2329,6 +2329,7 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out);
|
||||
|
||||
for (unsigned i = 0; i < arraysize(string_type_table); i++) {
|
||||
const StringTypeTable& entry = string_type_table[i];
|
||||
@ -2700,6 +2701,11 @@ void Heap::CreateInitialObjects() {
|
||||
handle(Smi::FromInt(-5), isolate()), false,
|
||||
"undefined", Oddball::kException));
|
||||
|
||||
set_optimized_out(
|
||||
*factory->NewOddball(factory->optimized_out_map(), "optimized_out",
|
||||
handle(Smi::FromInt(-6), isolate()), false,
|
||||
"undefined", Oddball::kOptimizedOut));
|
||||
|
||||
for (unsigned i = 0; i < arraysize(constant_string_table); i++) {
|
||||
Handle<String> str =
|
||||
factory->InternalizeUtf8String(constant_string_table[i].contents);
|
||||
|
@ -75,6 +75,7 @@ namespace internal {
|
||||
V(Oddball, arguments_marker, ArgumentsMarker) \
|
||||
V(Oddball, exception, Exception) \
|
||||
V(Oddball, termination_exception, TerminationException) \
|
||||
V(Oddball, optimized_out, OptimizedOut) \
|
||||
V(FixedArray, number_string_cache, NumberStringCache) \
|
||||
V(Object, instanceof_cache_function, InstanceofCacheFunction) \
|
||||
V(Object, instanceof_cache_map, InstanceofCacheMap) \
|
||||
@ -147,6 +148,7 @@ namespace internal {
|
||||
V(Map, no_interceptor_result_sentinel_map, NoInterceptorResultSentinelMap) \
|
||||
V(Map, exception_map, ExceptionMap) \
|
||||
V(Map, termination_exception_map, TerminationExceptionMap) \
|
||||
V(Map, optimized_out_map, OptimizedOutMap) \
|
||||
V(Map, message_object_map, JSMessageObjectMap) \
|
||||
V(Map, foreign_map, ForeignMap) \
|
||||
V(Map, neander_map, NeanderMap) \
|
||||
|
@ -619,7 +619,7 @@ void Oddball::OddballVerify() {
|
||||
CHECK(number->IsSmi());
|
||||
int value = Smi::cast(number)->value();
|
||||
// Hidden oddballs have negative smis.
|
||||
const int kLeastHiddenOddballNumber = -5;
|
||||
const int kLeastHiddenOddballNumber = -6;
|
||||
CHECK_LE(value, 1);
|
||||
CHECK(value >= kLeastHiddenOddballNumber);
|
||||
}
|
||||
@ -642,6 +642,8 @@ void Oddball::OddballVerify() {
|
||||
CHECK(this == heap->termination_exception());
|
||||
} else if (map() == heap->exception_map()) {
|
||||
CHECK(this == heap->exception());
|
||||
} else if (map() == heap->optimized_out_map()) {
|
||||
CHECK(this == heap->optimized_out());
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -1004,7 +1004,8 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(Uninitialized) \
|
||||
V(True) \
|
||||
V(False) \
|
||||
V(ArgumentsMarker)
|
||||
V(ArgumentsMarker) \
|
||||
V(OptimizedOut)
|
||||
|
||||
// The element types selection for CreateListFromArrayLike.
|
||||
enum class ElementTypes { kAll, kStringAndSymbol };
|
||||
@ -9595,6 +9596,7 @@ class Oddball: public HeapObject {
|
||||
static const byte kUninitialized = 6;
|
||||
static const byte kOther = 7;
|
||||
static const byte kException = 8;
|
||||
static const byte kOptimizedOut = 9;
|
||||
|
||||
typedef FixedBodyDescriptor<kToStringOffset, kTypeOfOffset + kPointerSize,
|
||||
kSize> BodyDescriptor;
|
||||
|
@ -554,7 +554,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
|
||||
// Use the value from the stack.
|
||||
if (scope_info->LocalIsSynthetic(i)) continue;
|
||||
locals->set(local * 2, scope_info->LocalName(i));
|
||||
locals->set(local * 2 + 1, *(frame_inspector.GetExpression(i)));
|
||||
Handle<Object> value = frame_inspector.GetExpression(i);
|
||||
// TODO(yangguo): We convert optimized out values to {undefined} when they
|
||||
// are passed to the debugger. Eventually we should handle them somehow.
|
||||
if (value->IsOptimizedOut()) value = isolate->factory()->undefined_value();
|
||||
locals->set(local * 2 + 1, *value);
|
||||
local++;
|
||||
}
|
||||
if (local < local_count) {
|
||||
|
@ -191,7 +191,8 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
||||
map == heap->uninitialized_map() ||
|
||||
map == heap->no_interceptor_result_sentinel_map() ||
|
||||
map == heap->termination_exception_map() ||
|
||||
map == heap->arguments_marker_map());
|
||||
map == heap->arguments_marker_map() ||
|
||||
map == heap->optimized_out_map());
|
||||
return kInternal & kTaggedPointer;
|
||||
}
|
||||
case HEAP_NUMBER_TYPE:
|
||||
|
Loading…
Reference in New Issue
Block a user