From 57ac971a78eddce1acfdcc9d77082f8f7d601b15 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Wed, 28 Aug 2013 14:16:57 +0000 Subject: [PATCH] Implement proper map checks of captured objects. R=verwaest@chromium.org TEST=mjsunit/compiler/escape-analysis Review URL: https://codereview.chromium.org/23697002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16403 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-arm.cc | 4 +-- src/arm/lithium-arm.h | 10 ++++---- src/arm/lithium-codegen-arm.cc | 10 ++++---- src/hydrogen-escape-analysis.cc | 34 +++++++++++++++++------- src/hydrogen-escape-analysis.h | 2 ++ src/hydrogen-instructions.cc | 11 ++++---- src/hydrogen-instructions.h | 44 +++++++++++++++++++++----------- src/hydrogen.cc | 10 ++++---- src/ia32/lithium-codegen-ia32.cc | 10 ++++---- src/ia32/lithium-ia32.cc | 10 ++++---- src/ia32/lithium-ia32.h | 10 ++++---- src/mips/lithium-codegen-mips.cc | 10 ++++---- src/mips/lithium-mips.cc | 4 +-- src/mips/lithium-mips.h | 10 ++++---- src/x64/lithium-codegen-x64.cc | 6 ++--- src/x64/lithium-x64.cc | 4 +-- src/x64/lithium-x64.h | 10 ++++---- test/mjsunit/compiler/escape-analysis.js | 27 ++++++++++++++++++++ 18 files changed, 143 insertions(+), 83 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 5978fad..d0d7f5c 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2027,9 +2027,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } -LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { +LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - return AssignEnvironment(new(zone()) LCheckFunction(value)); + return AssignEnvironment(new(zone()) LCheckValue(value)); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 90fb117..781dcf4 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -62,12 +62,12 @@ class LCodeGen; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CheckFunction) \ V(CheckInstanceType) \ V(CheckNonSmi) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ @@ -2338,16 +2338,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> { +class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckFunction(LOperand* value) { + explicit LCheckValue(LOperand* value) { inputs_[0] = value; } LOperand* value() { return inputs_[0]; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") - DECLARE_HYDROGEN_ACCESSOR(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value") + DECLARE_HYDROGEN_ACCESSOR(CheckValue) }; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index e34e15b..9cb92e8 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5131,18 +5131,18 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { } -void LCodeGen::DoCheckFunction(LCheckFunction* instr) { +void LCodeGen::DoCheckValue(LCheckValue* instr) { Register reg = ToRegister(instr->value()); - Handle target = instr->hydrogen()->target(); + Handle object = instr->hydrogen()->object(); AllowDeferredHandleDereference smi_check; - if (isolate()->heap()->InNewSpace(*target)) { + if (isolate()->heap()->InNewSpace(*object)) { Register reg = ToRegister(instr->value()); - Handle cell = isolate()->factory()->NewCell(target); + Handle cell = isolate()->factory()->NewCell(object); __ mov(ip, Operand(Handle(cell))); __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset)); __ cmp(reg, ip); } else { - __ cmp(reg, Operand(target)); + __ cmp(reg, Operand(object)); } DeoptimizeIf(ne, instr->environment()); } diff --git a/src/hydrogen-escape-analysis.cc b/src/hydrogen-escape-analysis.cc index b508644..145a779 100644 --- a/src/hydrogen-escape-analysis.cc +++ b/src/hydrogen-escape-analysis.cc @@ -86,7 +86,8 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation( // Create a new state full of phis for loop header entries. HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader( - HInstruction* previous, HCapturedObject* old_state) { + HInstruction* previous, + HCapturedObject* old_state) { HBasicBlock* block = previous->block(); HCapturedObject* state = NewState(previous); for (int index = 0; index < number_of_values_; index++) { @@ -100,7 +101,8 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader( // Create a new state by copying an existing one. HCapturedObject* HEscapeAnalysisPhase::NewStateCopy( - HInstruction* previous, HCapturedObject* old_state) { + HInstruction* previous, + HCapturedObject* old_state) { HCapturedObject* state = NewState(previous); for (int index = 0; index < number_of_values_; index++) { HValue* operand = old_state->OperandAt(index); @@ -112,8 +114,9 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateCopy( // Insert a newly created phi into the given block and fill all incoming // edges with the given value. -HPhi* HEscapeAnalysisPhase::NewPhiAndInsert( - HBasicBlock* block, HValue* incoming_value, int index) { +HPhi* HEscapeAnalysisPhase::NewPhiAndInsert(HBasicBlock* block, + HValue* incoming_value, + int index) { Zone* zone = graph()->zone(); HPhi* phi = new(zone) HPhi(HPhi::kInvalidMergedIndex, zone); for (int i = 0; i < block->predecessors()->length(); i++) { @@ -124,6 +127,21 @@ HPhi* HEscapeAnalysisPhase::NewPhiAndInsert( } +// Insert a newly created value check as a replacement for map checks. +HValue* HEscapeAnalysisPhase::NewMapCheckAndInsert(HCapturedObject* state, + HCheckMaps* mapcheck) { + Zone* zone = graph()->zone(); + HValue* value = state->map_value(); + // TODO(mstarzinger): This will narrow a map check against a set of maps + // down to the first element in the set. Revisit and fix this. + Handle map_object = mapcheck->map_set()->first(); + UniqueValueId map_id = mapcheck->map_unique_ids()->first(); + HCheckValue* check = HCheckValue::New(zone, NULL, value, map_object, map_id); + check->InsertBefore(mapcheck); + return check; +} + + // Performs a forward data-flow analysis of all loads and stores on the // given captured allocation. This uses a reverse post-order iteration // over affected basic blocks. All non-escaping instructions are handled @@ -180,7 +198,7 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) { if (store->HasObservableSideEffects()) { state->ReuseSideEffectsFromStore(store); } - store->DeleteAndReplaceWith(NULL); + store->DeleteAndReplaceWith(store->ActualValue()); if (FLAG_trace_escape_analysis) { PrintF("Replacing store #%d%s\n", instr->id(), store->has_transition() ? " (with transition)" : ""); @@ -199,15 +217,13 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) { case HValue::kCheckHeapObject: { HCheckHeapObject* check = HCheckHeapObject::cast(instr); if (check->value() != allocate) continue; - check->DeleteAndReplaceWith(NULL); + check->DeleteAndReplaceWith(check->ActualValue()); break; } case HValue::kCheckMaps: { HCheckMaps* mapcheck = HCheckMaps::cast(instr); if (mapcheck->value() != allocate) continue; - // TODO(mstarzinger): This approach breaks if the tracked map value - // is not a HConstant. Find a repro test case and fix this. - ASSERT(mapcheck->ActualValue() == allocate); + NewMapCheckAndInsert(state, mapcheck); mapcheck->DeleteAndReplaceWith(mapcheck->ActualValue()); break; } diff --git a/src/hydrogen-escape-analysis.h b/src/hydrogen-escape-analysis.h index 2d425e2..9db46cb 100644 --- a/src/hydrogen-escape-analysis.h +++ b/src/hydrogen-escape-analysis.h @@ -63,6 +63,8 @@ class HEscapeAnalysisPhase : public HPhase { HPhi* NewPhiAndInsert(HBasicBlock* block, HValue* incoming_value, int index); + HValue* NewMapCheckAndInsert(HCapturedObject* state, HCheckMaps* mapcheck); + HCapturedObject* StateAt(HBasicBlock* block) { return block_states_.at(block->block_id()); } diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index a9adfc1..f6ee8dc 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1451,15 +1451,16 @@ void HCheckMaps::PrintDataTo(StringStream* stream) { } -void HCheckFunction::PrintDataTo(StringStream* stream) { +void HCheckValue::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); - stream->Add(" %p", *target()); + stream->Add(" "); + object()->ShortPrint(stream); } -HValue* HCheckFunction::Canonicalize() { +HValue* HCheckValue::Canonicalize() { return (value()->IsConstant() && - HConstant::cast(value())->UniqueValueIdsMatch(target_unique_id_)) + HConstant::cast(value())->UniqueValueIdsMatch(object_unique_id_)) ? NULL : this; } @@ -4052,7 +4053,7 @@ void HCheckHeapObject::Verify() { } -void HCheckFunction::Verify() { +void HCheckValue::Verify() { HInstruction::Verify(); ASSERT(HasNoUses()); } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 773ba3b..2e9aa00 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -88,12 +88,12 @@ class LChunkBuilder; V(CallStub) \ V(CapturedObject) \ V(Change) \ - V(CheckFunction) \ V(CheckHeapObject) \ V(CheckInstanceType) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampToUint8) \ V(ClassOfTestAndBranch) \ V(CompareNumericAndBranch) \ @@ -2562,6 +2562,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { HValue* value() { return OperandAt(0); } SmallMapList* map_set() { return &map_set_; } + ZoneList* map_unique_ids() { return &map_unique_ids_; } bool has_migration_target() { return has_migration_target_; @@ -2630,9 +2631,20 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { }; -class HCheckFunction V8_FINAL : public HUnaryOperation { +class HCheckValue V8_FINAL : public HUnaryOperation { public: - DECLARE_INSTRUCTION_FACTORY_P2(HCheckFunction, HValue*, Handle); + static HCheckValue* New(Zone* zone, HValue* context, + HValue* value, Handle target) { + bool in_new_space = Isolate::Current()->heap()->InNewSpace(*target); + HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); + return check; + } + static HCheckValue* New(Zone* zone, HValue* context, + HValue* value, Handle map, UniqueValueId id) { + HCheckValue* check = new(zone) HCheckValue(value, map, false); + check->object_unique_id_ = id; + return check; + } virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { return Representation::Tagged(); @@ -2646,32 +2658,31 @@ class HCheckFunction V8_FINAL : public HUnaryOperation { #endif virtual void FinalizeUniqueValueId() V8_OVERRIDE { - target_unique_id_ = UniqueValueId(target_); + object_unique_id_ = UniqueValueId(object_); } - Handle target() const { return target_; } - bool target_in_new_space() const { return target_in_new_space_; } + Handle object() const { return object_; } + bool object_in_new_space() const { return object_in_new_space_; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue) protected: virtual bool DataEquals(HValue* other) V8_OVERRIDE { - HCheckFunction* b = HCheckFunction::cast(other); - return target_unique_id_ == b->target_unique_id_; + HCheckValue* b = HCheckValue::cast(other); + return object_unique_id_ == b->object_unique_id_; } private: - HCheckFunction(HValue* value, Handle function) + HCheckValue(HValue* value, Handle object, bool in_new_space) : HUnaryOperation(value, value->type()), - target_(function), target_unique_id_() { + object_(object), object_in_new_space_(in_new_space) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); - target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function); } - Handle target_; - UniqueValueId target_unique_id_; - bool target_in_new_space_; + Handle object_; + UniqueValueId object_unique_id_; + bool object_in_new_space_; }; @@ -3230,6 +3241,9 @@ class HCapturedObject V8_FINAL : public HDematerializedObject { int length() const { return values_.length(); } int capture_id() const { return capture_id_; } + // Shortcut for the map value of this captured object. + HValue* map_value() const { return values()->first(); } + void ReuseSideEffectsFromStore(HInstruction* store) { ASSERT(store->HasObservableSideEffects()); ASSERT(store->IsStoreNamedField()); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index bffbcce..445a0a0 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -7110,7 +7110,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { CHECK_ALIVE(VisitForValue(expr->expression())); HValue* function = Pop(); - Add(function, expr->target()); + Add(function, expr->target()); // Replace the global object with the global receiver. HGlobalReceiver* global_receiver = Add(global_object); @@ -7162,7 +7162,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { HGlobalReceiver* receiver = New(global); PushAndAdd(receiver); CHECK_ALIVE(VisitExpressions(expr->arguments())); - Add(function, expr->target()); + Add(function, expr->target()); if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. if (FLAG_trace_inlining) { @@ -7225,7 +7225,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { HValue* function = Top(); CHECK_ALIVE(VisitExpressions(expr->arguments())); Handle constructor = expr->target(); - HValue* check = Add(function, constructor); + HValue* check = Add(function, constructor); // Force completion of inobject slack tracking before generating // allocation code to finalize instance size. @@ -7317,7 +7317,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { HBinaryCall* call; if (expr->target().is_identical_to(array_function)) { Handle cell = expr->allocation_info_cell(); - Add(constructor, array_function); + Add(constructor, array_function); call = new(zone()) HCallNewArray(context, constructor, argument_count, cell, expr->elements_kind()); } else { @@ -8149,7 +8149,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); } else { - Add(right, target); + Add(right, target); HInstanceOfKnownGlobal* result = new(zone()) HInstanceOfKnownGlobal(context, left, target); result->set_position(expr->position()); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index ccd623c..e7e0327 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5800,15 +5800,15 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { } -void LCodeGen::DoCheckFunction(LCheckFunction* instr) { - Handle target = instr->hydrogen()->target(); - if (instr->hydrogen()->target_in_new_space()) { +void LCodeGen::DoCheckValue(LCheckValue* instr) { + Handle object = instr->hydrogen()->object(); + if (instr->hydrogen()->object_in_new_space()) { Register reg = ToRegister(instr->value()); - Handle cell = isolate()->factory()->NewCell(target); + Handle cell = isolate()->factory()->NewCell(object); __ cmp(reg, Operand::ForCell(cell)); } else { Operand operand = ToOperand(instr->value()); - __ cmp(operand, target); + __ cmp(operand, object); } DeoptimizeIf(not_equal, instr->environment()); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 7ec1258..c2ffc50 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2060,14 +2060,14 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } -LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { - // If the target is in new space, we'll emit a global cell compare and so - // want the value in a register. If the target gets promoted before we +LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) { + // If the object is in new space, we'll emit a global cell compare and so + // want the value in a register. If the object gets promoted before we // emit code, we will still get the register but will do an immediate // compare instead of the cell compare. This is safe. - LOperand* value = instr->target_in_new_space() + LOperand* value = instr->object_in_new_space() ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value()); - return AssignEnvironment(new(zone()) LCheckFunction(value)); + return AssignEnvironment(new(zone()) LCheckValue(value)); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index e8a3baf..e795926 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -62,12 +62,12 @@ class LCodeGen; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CheckFunction) \ V(CheckInstanceType) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ @@ -2437,16 +2437,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; -class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> { +class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckFunction(LOperand* value) { + explicit LCheckValue(LOperand* value) { inputs_[0] = value; } LOperand* value() { return inputs_[0]; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") - DECLARE_HYDROGEN_ACCESSOR(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value") + DECLARE_HYDROGEN_ACCESSOR(CheckValue) }; diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 80794c8..d2ab06a 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5116,20 +5116,20 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { } -void LCodeGen::DoCheckFunction(LCheckFunction* instr) { +void LCodeGen::DoCheckValue(LCheckValue* instr) { Register reg = ToRegister(instr->value()); - Handle target = instr->hydrogen()->target(); + Handle object = instr->hydrogen()->object(); AllowDeferredHandleDereference smi_check; - if (isolate()->heap()->InNewSpace(*target)) { + if (isolate()->heap()->InNewSpace(*object)) { Register reg = ToRegister(instr->value()); - Handle cell = isolate()->factory()->NewCell(target); + Handle cell = isolate()->factory()->NewCell(object); __ li(at, Operand(Handle(cell))); __ lw(at, FieldMemOperand(at, Cell::kValueOffset)); DeoptimizeIf(ne, instr->environment(), reg, Operand(at)); } else { DeoptimizeIf(ne, instr->environment(), reg, - Operand(target)); + Operand(object)); } } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index b11c9c2..d71c32b 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1951,9 +1951,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } -LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { +LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - return AssignEnvironment(new(zone()) LCheckFunction(value)); + return AssignEnvironment(new(zone()) LCheckValue(value)); } diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 6498943..dfdf63c 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -62,12 +62,12 @@ class LCodeGen; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CheckFunction) \ V(CheckInstanceType) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ @@ -2321,16 +2321,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> { +class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckFunction(LOperand* value) { + explicit LCheckValue(LOperand* value) { inputs_[0] = value; } LOperand* value() { return inputs_[0]; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") - DECLARE_HYDROGEN_ACCESSOR(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value") + DECLARE_HYDROGEN_ACCESSOR(CheckValue) }; diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 094d239..ce66285 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -4915,10 +4915,10 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { } -void LCodeGen::DoCheckFunction(LCheckFunction* instr) { +void LCodeGen::DoCheckValue(LCheckValue* instr) { Register reg = ToRegister(instr->value()); - Handle target = instr->hydrogen()->target(); - __ CmpHeapObject(reg, target); + Handle object = instr->hydrogen()->object(); + __ CmpHeapObject(reg, object); DeoptimizeIf(not_equal, instr->environment()); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 57938b2..85181c0 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1940,9 +1940,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } -LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { +LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - return AssignEnvironment(new(zone()) LCheckFunction(value)); + return AssignEnvironment(new(zone()) LCheckValue(value)); } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 00642ff..e95713d 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -62,12 +62,12 @@ class LCodeGen; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CheckFunction) \ V(CheckInstanceType) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckNonSmi) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ @@ -2260,16 +2260,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> { +class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckFunction(LOperand* value) { + explicit LCheckValue(LOperand* value) { inputs_[0] = value; } LOperand* value() { return inputs_[0]; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") - DECLARE_HYDROGEN_ACCESSOR(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value") + DECLARE_HYDROGEN_ACCESSOR(CheckValue) }; diff --git a/test/mjsunit/compiler/escape-analysis.js b/test/mjsunit/compiler/escape-analysis.js index 9b9341b..f32069c 100644 --- a/test/mjsunit/compiler/escape-analysis.js +++ b/test/mjsunit/compiler/escape-analysis.js @@ -173,3 +173,30 @@ delete deopt.deopt; func(); func(); })(); + + +// Test map checks on captured objects. +(function testMapCheck() { + var sum = 0; + function getter() { return 27; } + function setter(v) { sum += v; } + function constructor() { + this.x = 23; + this.y = 42; + } + function check(x, y) { + var o = new constructor(); + assertEquals(x, o.x); + assertEquals(y, o.y); + } + var monkey = Object.create(null, { + x: { get:getter, set:setter }, + y: { get:getter, set:setter } + }); + check(23, 42); check(23, 42); + %OptimizeFunctionOnNextCall(check); + check(23, 42); check(23, 42); + constructor.prototype = monkey; + check(27, 27); check(27, 27); + assertEquals(130, sum); +})(); -- 2.7.4