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:
mstarzinger 2016-03-16 07:30:15 -07:00 committed by Commit bot
parent 5d62db7430
commit eee34dd50f
13 changed files with 59 additions and 28 deletions

View File

@ -646,7 +646,7 @@ void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
} }
NonLiveFrameStateSlotReplacer replacer( NonLiveFrameStateSlotReplacer replacer(
&state_values_cache_, jsgraph()->UndefinedConstant(), &state_values_cache_, jsgraph()->OptimizedOutConstant(),
liveness_analyzer()->local_count(), local_zone()); liveness_analyzer()->local_count(), local_zone());
Variable* arguments = info()->scope()->arguments(); Variable* arguments = info()->scope()->arguments();
if (arguments != nullptr && arguments->IsStackAllocated()) { if (arguments != nullptr && arguments->IsStackAllocated()) {

View File

@ -29,6 +29,10 @@ Node* JSGraph::EmptyFixedArrayConstant() {
HeapConstant(factory()->empty_fixed_array())); HeapConstant(factory()->empty_fixed_array()));
} }
Node* JSGraph::OptimizedOutConstant() {
return CACHED(kOptimizedOutConstant,
HeapConstant(factory()->optimized_out()));
}
Node* JSGraph::UndefinedConstant() { Node* JSGraph::UndefinedConstant() {
return CACHED(kUndefinedConstant, HeapConstant(factory()->undefined_value())); return CACHED(kUndefinedConstant, HeapConstant(factory()->undefined_value()));

View File

@ -41,6 +41,7 @@ class JSGraph : public ZoneObject {
// Canonicalized global constants. // Canonicalized global constants.
Node* CEntryStubConstant(int result_size); Node* CEntryStubConstant(int result_size);
Node* EmptyFixedArrayConstant(); Node* EmptyFixedArrayConstant();
Node* OptimizedOutConstant();
Node* UndefinedConstant(); Node* UndefinedConstant();
Node* TheHoleConstant(); Node* TheHoleConstant();
Node* TrueConstant(); Node* TrueConstant();
@ -136,6 +137,7 @@ class JSGraph : public ZoneObject {
enum CachedNode { enum CachedNode {
kCEntryStubConstant, kCEntryStubConstant,
kEmptyFixedArrayConstant, kEmptyFixedArrayConstant,
kOptimizedOutConstant,
kUndefinedConstant, kUndefinedConstant,
kTheHoleConstant, kTheHoleConstant,
kTrueConstant, kTrueConstant,

View File

@ -37,9 +37,9 @@ void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlot(
int index, HSimulate* simulate) { int index, HSimulate* simulate) {
int operand_index = simulate->ToOperandIndex(index); int operand_index = simulate->ToOperandIndex(index);
if (operand_index == -1) { if (operand_index == -1) {
simulate->AddAssignedValue(index, graph()->GetConstantUndefined()); simulate->AddAssignedValue(index, graph()->GetConstantOptimizedOut());
} else { } else {
simulate->SetOperandAt(operand_index, graph()->GetConstantUndefined()); simulate->SetOperandAt(operand_index, graph()->GetConstantOptimizedOut());
} }
} }

View File

@ -690,13 +690,12 @@ HConstant* HGraph::GetConstantBool(bool value) {
return value ? GetConstantTrue() : GetConstantFalse(); return value ? GetConstantTrue() : GetConstantFalse();
} }
#define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value, \ #define DEFINE_GET_CONSTANT(Name, name, constant, type, htype, boolean_value, \
undetectable) \ undetectable) \
HConstant* HGraph::GetConstant##Name() { \ HConstant* HGraph::GetConstant##Name() { \
if (!constant_##name##_.is_set()) { \ if (!constant_##name##_.is_set()) { \
HConstant* constant = new (zone()) HConstant( \ HConstant* constant = new (zone()) HConstant( \
Unique<Object>::CreateImmovable( \ Unique<Object>::CreateImmovable(isolate()->factory()->constant()), \
isolate()->factory()->name##_value()), \
Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \ Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
false, Representation::Tagged(), htype, true, boolean_value, \ false, Representation::Tagged(), htype, true, boolean_value, \
undetectable, ODDBALL_TYPE); \ undetectable, ODDBALL_TYPE); \
@ -706,12 +705,17 @@ HConstant* HGraph::GetConstantBool(bool value) {
return ReinsertConstantIfNecessary(constant_##name##_.get()); \ return ReinsertConstantIfNecessary(constant_##name##_.get()); \
} }
DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false, DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined,
true) HType::Undefined(), false, true)
DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true, false) DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true,
DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false, false) false)
DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false, false) DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false,
DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false, true) 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 #undef DEFINE_GET_CONSTANT

View File

@ -334,6 +334,7 @@ class HGraph final : public ZoneObject {
HConstant* GetConstantBool(bool value); HConstant* GetConstantBool(bool value);
HConstant* GetConstantHole(); HConstant* GetConstantHole();
HConstant* GetConstantNull(); HConstant* GetConstantNull();
HConstant* GetConstantOptimizedOut();
HConstant* GetInvalidContext(); HConstant* GetInvalidContext();
bool IsConstantUndefined(HConstant* constant); bool IsConstantUndefined(HConstant* constant);
@ -472,6 +473,7 @@ class HGraph final : public ZoneObject {
SetOncePointer<HConstant> constant_false_; SetOncePointer<HConstant> constant_false_;
SetOncePointer<HConstant> constant_the_hole_; SetOncePointer<HConstant> constant_the_hole_;
SetOncePointer<HConstant> constant_null_; SetOncePointer<HConstant> constant_null_;
SetOncePointer<HConstant> constant_optimized_out_;
SetOncePointer<HConstant> constant_invalid_context_; SetOncePointer<HConstant> constant_invalid_context_;
HOsrBuilder* osr_; HOsrBuilder* osr_;

View File

@ -133,8 +133,10 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
if (scope_info->LocalIsSynthetic(i)) continue; if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->StackLocalName(i)); Handle<String> name(scope_info->StackLocalName(i));
Handle<Object> value = GetExpression(scope_info->StackLocalIndex(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->IsTheHole()) value = isolate_->factory()->undefined_value();
if (value->IsOptimizedOut()) value = isolate_->factory()->undefined_value();
JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
} }
} }

View File

@ -2329,6 +2329,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_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++) { for (unsigned i = 0; i < arraysize(string_type_table); i++) {
const StringTypeTable& entry = string_type_table[i]; const StringTypeTable& entry = string_type_table[i];
@ -2700,6 +2701,11 @@ void Heap::CreateInitialObjects() {
handle(Smi::FromInt(-5), isolate()), false, handle(Smi::FromInt(-5), isolate()), false,
"undefined", Oddball::kException)); "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++) { for (unsigned i = 0; i < arraysize(constant_string_table); i++) {
Handle<String> str = Handle<String> str =
factory->InternalizeUtf8String(constant_string_table[i].contents); factory->InternalizeUtf8String(constant_string_table[i].contents);

View File

@ -75,6 +75,7 @@ namespace internal {
V(Oddball, arguments_marker, ArgumentsMarker) \ V(Oddball, arguments_marker, ArgumentsMarker) \
V(Oddball, exception, Exception) \ V(Oddball, exception, Exception) \
V(Oddball, termination_exception, TerminationException) \ V(Oddball, termination_exception, TerminationException) \
V(Oddball, optimized_out, OptimizedOut) \
V(FixedArray, number_string_cache, NumberStringCache) \ V(FixedArray, number_string_cache, NumberStringCache) \
V(Object, instanceof_cache_function, InstanceofCacheFunction) \ V(Object, instanceof_cache_function, InstanceofCacheFunction) \
V(Object, instanceof_cache_map, InstanceofCacheMap) \ V(Object, instanceof_cache_map, InstanceofCacheMap) \
@ -147,6 +148,7 @@ namespace internal {
V(Map, no_interceptor_result_sentinel_map, NoInterceptorResultSentinelMap) \ V(Map, no_interceptor_result_sentinel_map, NoInterceptorResultSentinelMap) \
V(Map, exception_map, ExceptionMap) \ V(Map, exception_map, ExceptionMap) \
V(Map, termination_exception_map, TerminationExceptionMap) \ V(Map, termination_exception_map, TerminationExceptionMap) \
V(Map, optimized_out_map, OptimizedOutMap) \
V(Map, message_object_map, JSMessageObjectMap) \ V(Map, message_object_map, JSMessageObjectMap) \
V(Map, foreign_map, ForeignMap) \ V(Map, foreign_map, ForeignMap) \
V(Map, neander_map, NeanderMap) \ V(Map, neander_map, NeanderMap) \

View File

@ -619,7 +619,7 @@ void Oddball::OddballVerify() {
CHECK(number->IsSmi()); CHECK(number->IsSmi());
int value = Smi::cast(number)->value(); int value = Smi::cast(number)->value();
// Hidden oddballs have negative smis. // Hidden oddballs have negative smis.
const int kLeastHiddenOddballNumber = -5; const int kLeastHiddenOddballNumber = -6;
CHECK_LE(value, 1); CHECK_LE(value, 1);
CHECK(value >= kLeastHiddenOddballNumber); CHECK(value >= kLeastHiddenOddballNumber);
} }
@ -642,6 +642,8 @@ void Oddball::OddballVerify() {
CHECK(this == heap->termination_exception()); CHECK(this == heap->termination_exception());
} else if (map() == heap->exception_map()) { } else if (map() == heap->exception_map()) {
CHECK(this == heap->exception()); CHECK(this == heap->exception());
} else if (map() == heap->optimized_out_map()) {
CHECK(this == heap->optimized_out());
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -1004,7 +1004,8 @@ template <class C> inline bool Is(Object* obj);
V(Uninitialized) \ V(Uninitialized) \
V(True) \ V(True) \
V(False) \ V(False) \
V(ArgumentsMarker) V(ArgumentsMarker) \
V(OptimizedOut)
// The element types selection for CreateListFromArrayLike. // The element types selection for CreateListFromArrayLike.
enum class ElementTypes { kAll, kStringAndSymbol }; enum class ElementTypes { kAll, kStringAndSymbol };
@ -9595,6 +9596,7 @@ class Oddball: public HeapObject {
static const byte kUninitialized = 6; static const byte kUninitialized = 6;
static const byte kOther = 7; static const byte kOther = 7;
static const byte kException = 8; static const byte kException = 8;
static const byte kOptimizedOut = 9;
typedef FixedBodyDescriptor<kToStringOffset, kTypeOfOffset + kPointerSize, typedef FixedBodyDescriptor<kToStringOffset, kTypeOfOffset + kPointerSize,
kSize> BodyDescriptor; kSize> BodyDescriptor;

View File

@ -554,7 +554,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// Use the value from the stack. // Use the value from the stack.
if (scope_info->LocalIsSynthetic(i)) continue; if (scope_info->LocalIsSynthetic(i)) continue;
locals->set(local * 2, scope_info->LocalName(i)); 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++; local++;
} }
if (local < local_count) { if (local < local_count) {

View File

@ -191,7 +191,8 @@ Type::bitset BitsetType::Lub(i::Map* map) {
map == heap->uninitialized_map() || map == heap->uninitialized_map() ||
map == heap->no_interceptor_result_sentinel_map() || map == heap->no_interceptor_result_sentinel_map() ||
map == heap->termination_exception_map() || map == heap->termination_exception_map() ||
map == heap->arguments_marker_map()); map == heap->arguments_marker_map() ||
map == heap->optimized_out_map());
return kInternal & kTaggedPointer; return kInternal & kTaggedPointer;
} }
case HEAP_NUMBER_TYPE: case HEAP_NUMBER_TYPE: