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(
&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()) {

View File

@ -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()));

View File

@ -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,

View File

@ -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());
}
}

View File

@ -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

View File

@ -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_;

View File

@ -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();
}
}

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, 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);

View File

@ -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) \

View File

@ -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();
}

View File

@ -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;

View File

@ -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) {

View File

@ -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: