Revision: 12489
Author: [email protected]
Date: Wed Sep 12 05:28:42 2012
Log: Fix arguments object materialization during deopt.
This fixes materialization of arguments objects for strict mode functions
during
deoptimization. We materialize arguments from the stack area where optimized
code pushes the arguments when entering the inlined environment. For adapted
invocations we use the arguments adaptor frame for materialization.
[email protected]
BUG=v8:2261
TEST=mjsunit/regress/regress-2261,mjsunit/compiler/inline-arguments
Review URL: https://chromiumcodereview.appspot.com/10908194
http://code.google.com/p/v8/source/detail?r=12489
Added:
/branches/bleeding_edge/test/mjsunit/regress/regress-2261.js
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.h
/branches/bleeding_edge/src/deoptimizer.cc
/branches/bleeding_edge/src/deoptimizer.h
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/lithium.h
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/mips/lithium-codegen-mips.h
/branches/bleeding_edge/src/mips/lithium-mips.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.h
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js
/branches/bleeding_edge/test/mjsunit/object-define-property.js
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-2261.js Wed Sep 12
05:28:42 2012
@@ -0,0 +1,113 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Test materialization of the arguments object when deoptimizing a
+// strict mode closure after modifying an argument.
+
+(function () {
+ var forceDeopt = 0;
+ function inner(x) {
+ "use strict";
+ x = 2;
+ // Do not remove this %DebugPrint as it makes sure the deopt happens
+ // after the assignment and is not hoisted above the assignment.
+ %DebugPrint(arguments[0]);
+ forceDeopt + 1;
+ return arguments[0];
+ }
+
+ assertEquals(1, inner(1));
+ assertEquals(1, inner(1));
+ %OptimizeFunctionOnNextCall(inner);
+ assertEquals(1, inner(1));
+ forceDeopt = "not a number";
+ assertEquals(1, inner(1));
+})();
+
+
+// Test materialization of the arguments object when deoptimizing an
+// inlined strict mode closure after modifying an argument.
+
+(function () {
+ var forceDeopt = 0;
+ function inner(x) {
+ "use strict";
+ x = 2;
+ // Do not remove this %DebugPrint as it makes sure the deopt happens
+ // after the assignment and is not hoisted above the assignment.
+ %DebugPrint(arguments[0]);
+ forceDeopt + 1;
+ return arguments[0];
+ }
+
+ function outer(x) {
+ return inner(x);
+ }
+
+ assertEquals(1, outer(1));
+ assertEquals(1, outer(1));
+ %OptimizeFunctionOnNextCall(outer);
+ assertEquals(1, outer(1));
+ forceDeopt = "not a number";
+ assertEquals(1, outer(1));
+})();
+
+
+// Test materialization of the multiple arguments objects when
+// deoptimizing several inlined closure after modifying an argument.
+
+(function () {
+ var forceDeopt = 0;
+ function inner(x,y,z) {
+ "use strict";
+ x = 3;
+ // Do not remove this %DebugPrint as it makes sure the deopt happens
+ // after the assignment and is not hoisted above the assignment.
+ %DebugPrint(arguments[0]);
+ forceDeopt + 1;
+ return arguments[0];
+ }
+
+ function middle(x) {
+ "use strict";
+ x = 2;
+ return inner(10*x, 20*x, 30*x) + arguments[0];
+ }
+
+ function outer(x) {
+ return middle(x);
+ }
+
+ assertEquals(21, outer(1));
+ assertEquals(21, outer(1));
+ %OptimizeFunctionOnNextCall(outer);
+ assertEquals(21, outer(1));
+ forceDeopt = "not a number";
+ assertEquals(21, outer(1));
+})();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Sep 10 01:35:26 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Wed Sep 12 05:28:42 2012
@@ -860,6 +860,7 @@
argument_count_,
value_count,
outer,
+ hydrogen_env->entry(),
zone());
int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
@@ -2253,6 +2254,7 @@
if (instr->arguments_var() != NULL) {
inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
+ inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
return NULL;
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Sep 11
04:36:48 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Sep 12
05:28:42 2012
@@ -464,7 +464,9 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation) {
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
@@ -472,7 +474,17 @@
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- WriteTranslation(environment->outer(), translation);
+ // Function parameters are arguments to the outermost environment. The
+ // arguments index points to the first element of a sequence of tagged
+ // values on the stack that represent the arguments. This needs to be
+ // kept in sync with the LArgumentsElements implementation.
+ *arguments_index = -environment->parameter_count();
+ *arguments_count = environment->parameter_count();
+
+ WriteTranslation(environment->outer(),
+ translation,
+ arguments_index,
+ arguments_count);
int closure_id = *info()->closure() != *environment->closure()
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
@@ -498,6 +510,17 @@
translation->BeginArgumentsAdaptorFrame(closure_id,
translation_size);
break;
}
+
+ // Inlined frames which push their arguments cause the index to be
+ // bumped and a new stack area to be used for materialization.
+ if (environment->entry() != NULL &&
+ environment->entry()->arguments_pushed()) {
+ *arguments_index = *arguments_index < 0
+ ? GetStackSlotCount()
+ : *arguments_index + *arguments_count;
+ *arguments_count = environment->entry()->arguments_count() + 1;
+ }
+
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -509,7 +532,9 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL)
{
@@ -518,14 +543,18 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false);
+ false,
+ *arguments_index,
+ *arguments_count);
}
}
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
}
}
@@ -533,12 +562,14 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32) {
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this
value
// is not present and must be reconstructed from the deoptimizer.
Currently
// this is only used for the arguments object.
- translation->StoreArgumentsObject();
+ translation->StoreArgumentsObject(arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
@@ -644,15 +675,16 @@
int frame_count = 0;
int jsframe_count = 0;
+ int args_index = 0;
+ int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
++jsframe_count;
}
}
- Translation translation(&translations_, frame_count, jsframe_count,
- zone());
- WriteTranslation(environment, &translation);
+ Translation translation(&translations_, frame_count, jsframe_count,
zone());
+ WriteTranslation(environment, &translation, &args_index, &args_count);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Wed Sep 12
05:28:42 2012
@@ -147,7 +147,10 @@
int additional_offset);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment, Translation*
translation);
+ void WriteTranslation(LEnvironment* environment,
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -258,7 +261,9 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32);
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
=======================================
--- /branches/bleeding_edge/src/deoptimizer.cc Fri Sep 7 02:01:54 2012
+++ /branches/bleeding_edge/src/deoptimizer.cc Wed Sep 12 05:28:42 2012
@@ -27,6 +27,7 @@
#include "v8.h"
+#include "accessors.h"
#include "codegen.h"
#include "deoptimizer.h"
#include "disasm.h"
@@ -368,6 +369,8 @@
output_count_(0),
jsframe_count_(0),
output_(NULL),
+ deferred_arguments_objects_values_(0),
+ deferred_arguments_objects_(0),
deferred_heap_numbers_(0) {
if (FLAG_trace_deopt && type != OSR) {
if (type == DEBUGGER) {
@@ -633,8 +636,21 @@
}
-void Deoptimizer::MaterializeHeapNumbers() {
+void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ASSERT_NE(DEBUGGER, bailout_type_);
+
+ // Handlify all argument object values before triggering any allocation.
+ List<Handle<Object> >
values(deferred_arguments_objects_values_.length());
+ for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
+ values.Add(Handle<Object>(deferred_arguments_objects_values_[i]));
+ }
+
+ // Play it safe and clear all unhandlified values before we continue.
+ deferred_arguments_objects_values_.Clear();
+
+ // Materialize all heap numbers before looking at arguments because when
the
+ // output frames are used to materialize arguments objects later on they
need
+ // to already contain valid heap numbers.
for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
Handle<Object> num = isolate_->factory()->NewNumber(d.value());
@@ -644,9 +660,55 @@
d.value(),
d.slot_address());
}
-
Memory::Object_at(d.slot_address()) = *num;
}
+
+ // Materialize arguments objects one frame at a time.
+ for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
+ if (frame_index != 0) it->Advance();
+ JavaScriptFrame* frame = it->frame();
+ Handle<JSFunction> function(JSFunction::cast(frame->function()),
isolate_);
+ Handle<JSObject> arguments;
+ for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
+ if (frame->GetExpression(i) == isolate_->heap()->arguments_marker())
{
+ ArgumentsObjectMaterializationDescriptor descriptor =
+ deferred_arguments_objects_.RemoveLast();
+ const int length = descriptor.arguments_length();
+ if (arguments.is_null()) {
+ if (frame->has_adapted_arguments()) {
+ // Use the arguments adapter frame we just built to
materialize the
+ // arguments object. FunctionGetArguments can't throw an
exception,
+ // so cast away the doubt with an assert.
+ arguments = Handle<JSObject>(JSObject::cast(
+ Accessors::FunctionGetArguments(*function,
+
NULL)->ToObjectUnchecked()));
+ values.RewindBy(length);
+ } else {
+ // Construct an arguments object and copy the parameters to a
newly
+ // allocated arguments object backing store.
+ arguments =
+ isolate_->factory()->NewArgumentsObject(function, length);
+ Handle<FixedArray> array =
+ isolate_->factory()->NewFixedArray(length);
+ ASSERT(array->length() == length);
+ for (int i = length - 1; i >= 0 ; --i) {
+ array->set(i, *values.RemoveLast());
+ }
+ arguments->set_elements(*array);
+ }
+ }
+ frame->SetExpression(i, *arguments);
+ ASSERT_EQ(Memory::Object_at(descriptor.slot_address()),
*arguments);
+ if (FLAG_trace_deopt) {
+ PrintF("Materializing %sarguments object for %p: ",
+ frame->has_adapted_arguments() ? "(adapted) " : "",
+ reinterpret_cast<void*>(descriptor.slot_address()));
+ arguments->ShortPrint();
+ PrintF("\n");
+ }
+ }
+ }
+ }
}
@@ -932,8 +994,8 @@
}
case Translation::ARGUMENTS_OBJECT: {
- // Use the arguments marker value as a sentinel and fill in the
arguments
- // object after the deoptimized frame is built.
+ int args_index = iterator->Next() + 1; // Skip receiver.
+ int args_length = iterator->Next() - 1; // Skip receiver.
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
@@ -941,9 +1003,20 @@
isolate_->heap()->arguments_marker()->ShortPrint();
PrintF(" ; arguments object\n");
}
+ // Use the arguments marker value as a sentinel and fill in the
arguments
+ // object after the deoptimized frame is built.
intptr_t value = reinterpret_cast<intptr_t>(
isolate_->heap()->arguments_marker());
+ AddArgumentsObject(
+ output_[frame_index]->GetTop() + output_offset, args_length);
output_[frame_index]->SetFrameSlot(output_offset, value);
+ // We save the tagged argument values on the side and materialize the
+ // actual arguments object after the deoptimized frame is built.
+ for (int i = 0; i < args_length; i++) {
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index
+ i);
+ intptr_t input_value = input_->GetFrameSlot(input_offset);
+ AddArgumentsObjectValue(input_value);
+ }
return;
}
}
@@ -1285,8 +1358,19 @@
}
-void Deoptimizer::AddDoubleValue(intptr_t slot_address,
- double value) {
+void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
+ ArgumentsObjectMaterializationDescriptor object_desc(
+ reinterpret_cast<Address>(slot_address), argc);
+ deferred_arguments_objects_.Add(object_desc);
+}
+
+
+void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
+ deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
+}
+
+
+void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
HeapNumberMaterializationDescriptor value_desc(
reinterpret_cast<Address>(slot_address), value);
deferred_heap_numbers_.Add(value_desc);
@@ -1570,8 +1654,10 @@
}
-void Translation::StoreArgumentsObject() {
+void Translation::StoreArgumentsObject(int args_index, int args_length) {
buffer_->Add(ARGUMENTS_OBJECT, zone());
+ buffer_->Add(args_index, zone());
+ buffer_->Add(args_length, zone());
}
@@ -1582,7 +1668,6 @@
int Translation::NumberOfOperandsFor(Opcode opcode) {
switch (opcode) {
- case ARGUMENTS_OBJECT:
case DUPLICATE:
return 0;
case GETTER_STUB_FRAME:
@@ -1600,6 +1685,7 @@
case BEGIN:
case ARGUMENTS_ADAPTOR_FRAME:
case CONSTRUCT_STUB_FRAME:
+ case ARGUMENTS_OBJECT:
return 2;
case JS_FRAME:
return 3;
=======================================
--- /branches/bleeding_edge/src/deoptimizer.h Fri Sep 7 02:01:54 2012
+++ /branches/bleeding_edge/src/deoptimizer.h Wed Sep 12 05:28:42 2012
@@ -57,6 +57,20 @@
};
+class ArgumentsObjectMaterializationDescriptor BASE_EMBEDDED {
+ public:
+ ArgumentsObjectMaterializationDescriptor(Address slot_address, int argc)
+ : slot_address_(slot_address), arguments_length_(argc) { }
+
+ Address slot_address() const { return slot_address_; }
+ int arguments_length() const { return arguments_length_; }
+
+ private:
+ Address slot_address_;
+ int arguments_length_;
+};
+
+
class OptimizedFunctionVisitor BASE_EMBEDDED {
public:
virtual ~OptimizedFunctionVisitor() {}
@@ -196,7 +210,7 @@
~Deoptimizer();
- void MaterializeHeapNumbers();
+ void MaterializeHeapObjects(JavaScriptFrameIterator* it);
#ifdef ENABLE_DEBUGGER_SUPPORT
void MaterializeHeapNumbersForDebuggerInspectableFrame(
Address parameters_top,
@@ -305,6 +319,8 @@
Object* ComputeLiteral(int index) const;
+ void AddArgumentsObject(intptr_t slot_address, int argc);
+ void AddArgumentsObjectValue(intptr_t value);
void AddDoubleValue(intptr_t slot_address, double value);
static MemoryChunk* CreateCode(BailoutType type);
@@ -340,6 +356,8 @@
// Array of output frame descriptions.
FrameDescription** output_;
+ List<Object*> deferred_arguments_objects_values_;
+ List<ArgumentsObjectMaterializationDescriptor>
deferred_arguments_objects_;
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
static const int table_entry_size_;
@@ -608,7 +626,7 @@
void StoreUint32StackSlot(int index);
void StoreDoubleStackSlot(int index);
void StoreLiteral(int literal_id);
- void StoreArgumentsObject();
+ void StoreArgumentsObject(int args_index, int args_length);
void MarkDuplicate();
Zone* zone() const { return zone_; }
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Sep 7 02:01:54
2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Sep 12 05:28:42
2012
@@ -1431,6 +1431,7 @@
ZoneList<HValue*>* arguments_values)
: closure_(closure),
arguments_count_(arguments_count),
+ arguments_pushed_(false),
function_(function),
call_kind_(call_kind),
inlining_kind_(inlining_kind),
@@ -1442,6 +1443,8 @@
Handle<JSFunction> closure() const { return closure_; }
int arguments_count() const { return arguments_count_; }
+ bool arguments_pushed() const { return arguments_pushed_; }
+ void set_arguments_pushed() { arguments_pushed_ = true; }
FunctionLiteral* function() const { return function_; }
CallKind call_kind() const { return call_kind_; }
InliningKind inlining_kind() const { return inlining_kind_; }
@@ -1458,6 +1461,7 @@
private:
Handle<JSFunction> closure_;
int arguments_count_;
+ bool arguments_pushed_;
FunctionLiteral* function_;
CallKind call_kind_;
InliningKind inlining_kind_;
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Sep 11 07:14:32 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Wed Sep 12 05:28:42 2012
@@ -6550,6 +6550,7 @@
// Push arguments when entering inlined function.
HEnterInlined* entry = function_state()->entry();
+ entry->set_arguments_pushed();
ZoneList<HValue*>* arguments_values = entry->arguments_values();
@@ -9392,6 +9393,7 @@
specials_count_(1),
local_count_(0),
outer_(outer),
+ entry_(NULL),
pop_count_(0),
push_count_(0),
ast_id_(BailoutId::None()),
@@ -9408,6 +9410,7 @@
specials_count_(1),
local_count_(0),
outer_(NULL),
+ entry_(NULL),
pop_count_(0),
push_count_(0),
ast_id_(other->ast_id()),
@@ -9428,6 +9431,7 @@
parameter_count_(arguments),
local_count_(0),
outer_(outer),
+ entry_(NULL),
pop_count_(0),
push_count_(0),
ast_id_(BailoutId::None()),
@@ -9456,6 +9460,7 @@
parameter_count_ = other->parameter_count_;
local_count_ = other->local_count_;
if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
+ entry_ = other->entry_;
pop_count_ = other->pop_count_;
push_count_ = other->push_count_;
ast_id_ = other->ast_id_;
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Fri Sep 7 02:01:54 2012
+++ /branches/bleeding_edge/src/hydrogen.h Wed Sep 12 05:28:42 2012
@@ -434,13 +434,6 @@
Handle<JSFunction> closure,
Zone* zone);
- HEnvironment* DiscardInlined(bool drop_extra) {
- HEnvironment* outer = outer_;
- while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
- if (drop_extra) outer->Drop(1);
- return outer;
- }
-
HEnvironment* arguments_environment() {
return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
}
@@ -461,6 +454,9 @@
BailoutId ast_id() const { return ast_id_; }
void set_ast_id(BailoutId id) { ast_id_ = id; }
+
+ HEnterInlined* entry() const { return entry_; }
+ void set_entry(HEnterInlined* entry) { entry_ = entry; }
int length() const { return values_.length(); }
bool is_special_index(int i) const {
@@ -540,6 +536,13 @@
CallKind call_kind,
InliningKind inlining_kind) const;
+ HEnvironment* DiscardInlined(bool drop_extra) {
+ HEnvironment* outer = outer_;
+ while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
+ if (drop_extra) outer->Drop(1);
+ return outer;
+ }
+
void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
void ClearHistory() {
@@ -600,6 +603,7 @@
int specials_count_;
int local_count_;
HEnvironment* outer_;
+ HEnterInlined* entry_;
int pop_count_;
int push_count_;
BailoutId ast_id_;
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Sep 12
01:37:47 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Sep 12
05:28:42 2012
@@ -404,7 +404,9 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation) {
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
@@ -412,7 +414,17 @@
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- WriteTranslation(environment->outer(), translation);
+ // Function parameters are arguments to the outermost environment. The
+ // arguments index points to the first element of a sequence of tagged
+ // values on the stack that represent the arguments. This needs to be
+ // kept in sync with the LArgumentsElements implementation.
+ *arguments_index = -environment->parameter_count();
+ *arguments_count = environment->parameter_count();
+
+ WriteTranslation(environment->outer(),
+ translation,
+ arguments_index,
+ arguments_count);
int closure_id = *info()->closure() != *environment->closure()
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
@@ -437,6 +449,17 @@
translation->BeginArgumentsAdaptorFrame(closure_id,
translation_size);
break;
}
+
+ // Inlined frames which push their arguments cause the index to be
+ // bumped and another stack area to be used for materialization.
+ if (environment->entry() != NULL &&
+ environment->entry()->arguments_pushed()) {
+ *arguments_index = *arguments_index < 0
+ ? GetStackSlotCount()
+ : *arguments_index + *arguments_count;
+ *arguments_count = environment->entry()->arguments_count() + 1;
+ }
+
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -448,7 +471,9 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL)
{
@@ -457,14 +482,18 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false);
+ false,
+ *arguments_index,
+ *arguments_count);
}
}
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
}
}
@@ -472,12 +501,14 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32) {
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this
value
// is not present and must be reconstructed from the deoptimizer.
Currently
// this is only used for the arguments object.
- translation->StoreArgumentsObject();
+ translation->StoreArgumentsObject(arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
@@ -596,15 +627,16 @@
int frame_count = 0;
int jsframe_count = 0;
+ int args_index = 0;
+ int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
++jsframe_count;
}
}
- Translation translation(&translations_, frame_count, jsframe_count,
- zone());
- WriteTranslation(environment, &translation);
+ Translation translation(&translations_, frame_count, jsframe_count,
zone());
+ WriteTranslation(environment, &translation, &args_index, &args_count);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Wed Sep 12
05:28:42 2012
@@ -129,7 +129,10 @@
void DoGap(LGap* instr);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment, Translation*
translation);
+ void WriteTranslation(LEnvironment* environment,
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count);
void EnsureRelocSpaceForDeoptimization();
@@ -239,7 +242,9 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32);
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Sep 10 01:35:26
2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Wed Sep 12 05:28:42
2012
@@ -886,6 +886,7 @@
argument_count_,
value_count,
outer,
+ hydrogen_env->entry(),
zone());
int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
@@ -2370,6 +2371,7 @@
if (instr->arguments_var() != NULL) {
inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
+ inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
return NULL;
=======================================
--- /branches/bleeding_edge/src/lithium.h Wed Aug 22 08:44:17 2012
+++ /branches/bleeding_edge/src/lithium.h Wed Sep 12 05:28:42 2012
@@ -460,6 +460,7 @@
int argument_count,
int value_count,
LEnvironment* outer,
+ HEnterInlined* entry,
Zone* zone)
: closure_(closure),
frame_type_(frame_type),
@@ -475,6 +476,7 @@
spilled_registers_(NULL),
spilled_double_registers_(NULL),
outer_(outer),
+ entry_(entry),
zone_(zone) { }
Handle<JSFunction> closure() const { return closure_; }
@@ -491,6 +493,7 @@
}
const ZoneList<LOperand*>* values() const { return &values_; }
LEnvironment* outer() const { return outer_; }
+ HEnterInlined* entry() { return entry_; }
void AddValue(LOperand* operand,
Representation representation,
@@ -556,6 +559,7 @@
LOperand** spilled_double_registers_;
LEnvironment* outer_;
+ HEnterInlined* entry_;
Zone* zone_;
};
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Sep 10
01:35:26 2012
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Sep 12
05:28:42 2012
@@ -432,7 +432,9 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation) {
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
@@ -440,7 +442,14 @@
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- WriteTranslation(environment->outer(), translation);
+ // Function parameters are arguments to the outermost environment. The
+ // arguments index points to the first element of a sequence of tagged
+ // values on the stack that represent the arguments. This needs to be
+ // kept in sync with the LArgumentsElements implementation.
+ *arguments_index = -environment->parameter_count();
+ *arguments_count = environment->parameter_count();
+
+ WriteTranslation(environment->outer(), translation, args_index,
args_count);
int closure_id = *info()->closure() != *environment->closure()
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
@@ -466,6 +475,17 @@
translation->BeginArgumentsAdaptorFrame(closure_id,
translation_size);
break;
}
+
+ // Inlined frames which push their arguments cause the index to be
+ // bumped and a new stack area to be used for materialization.
+ if (environment->entry() != NULL &&
+ environment->entry()->arguments_pushed()) {
+ *arguments_index = *arguments_index < 0
+ ? GetStackSlotCount()
+ : *arguments_index + *arguments_count;
+ *arguments_count = environment->entry()->arguments_count() + 1;
+ }
+
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -477,7 +497,9 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL)
{
@@ -486,14 +508,18 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false);
+ false,
+ *arguments_index,
+ *arguments_count);
}
}
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
}
}
@@ -501,12 +527,14 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32) {
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this
value
// is not present and must be reconstructed from the deoptimizer.
Currently
// this is only used for the arguments object.
- translation->StoreArgumentsObject();
+ translation->StoreArgumentsObject(arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
@@ -602,6 +630,8 @@
int frame_count = 0;
int jsframe_count = 0;
+ int args_index = 0;
+ int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
@@ -609,7 +639,7 @@
}
}
Translation translation(&translations_, frame_count, jsframe_count,
zone());
- WriteTranslation(environment, &translation);
+ WriteTranslation(environment, &translation, &args_index, &args_count);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.h Sun Sep 2
23:36:19 2012
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.h Wed Sep 12
05:28:42 2012
@@ -143,7 +143,10 @@
int additional_offset);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment, Translation*
translation);
+ void WriteTranslation(LEnvironment* environment,
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -258,7 +261,9 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32);
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Mon Sep 10 01:35:26
2012
+++ /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Sep 12 05:28:42
2012
@@ -862,6 +862,7 @@
argument_count_,
value_count,
outer,
+ hydrogen_env->entry(),
zone());
int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
@@ -2195,6 +2196,7 @@
if (instr->arguments_var() != NULL) {
inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
+ inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
return NULL;
=======================================
--- /branches/bleeding_edge/src/runtime.cc Mon Sep 10 04:05:17 2012
+++ /branches/bleeding_edge/src/runtime.cc Wed Sep 12 05:28:42 2012
@@ -7968,35 +7968,6 @@
JSFunction* function_;
bool has_activations_;
};
-
-
-static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
- JavaScriptFrame* frame) {
- Handle<JSFunction> function(JSFunction::cast(frame->function()),
isolate);
- Handle<Object> arguments;
- for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
- if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
- if (arguments.is_null()) {
- // FunctionGetArguments can't throw an exception, so cast away the
- // doubt with an assert.
- arguments = Handle<Object>(
- Accessors::FunctionGetArguments(*function,
- NULL)->ToObjectUnchecked());
- ASSERT(*arguments != isolate->heap()->null_value());
- ASSERT(*arguments != isolate->heap()->undefined_value());
- }
- frame->SetExpression(i, *arguments);
- if (FLAG_trace_deopt) {
- PrintF("Materializing arguments object for frame %p - %p: %p ",
- reinterpret_cast<void*>(frame->sp()),
- reinterpret_cast<void*>(frame->fp()),
- reinterpret_cast<void*>(*arguments));
- arguments->ShortPrint();
- PrintF("\n");
- }
- }
- }
-}
RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
@@ -8007,25 +7978,16 @@
static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
ASSERT(isolate->heap()->IsAllocationAllowed());
- int jsframes = deoptimizer->jsframe_count();
+ JavaScriptFrameIterator it(isolate);
- deoptimizer->MaterializeHeapNumbers();
+ // Make sure to materialize objects before causing any allocation.
+ deoptimizer->MaterializeHeapObjects(&it);
delete deoptimizer;
-
- JavaScriptFrameIterator it(isolate);
- for (int i = 0; i < jsframes - 1; i++) {
- MaterializeArgumentsObjectInFrame(isolate, it.frame());
- it.Advance();
- }
JavaScriptFrame* frame = it.frame();
RUNTIME_ASSERT(frame->function()->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(frame->function()),
isolate);
- MaterializeArgumentsObjectInFrame(isolate, frame);
-
- if (type == Deoptimizer::EAGER) {
- RUNTIME_ASSERT(function->IsOptimized());
- }
+ RUNTIME_ASSERT(type != Deoptimizer::EAGER || function->IsOptimized());
// Avoid doing too much work when running with --always-opt and keep
// the optimized code around.
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Sep 10
01:35:26 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Sep 12
05:28:42 2012
@@ -351,7 +351,9 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
- Translation* translation) {
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
@@ -359,7 +361,17 @@
// The output frame height does not include the parameters.
int height = translation_size - environment->parameter_count();
- WriteTranslation(environment->outer(), translation);
+ // Function parameters are arguments to the outermost environment. The
+ // arguments index points to the first element of a sequence of tagged
+ // values on the stack that represent the arguments. This needs to be
+ // kept in sync with the LArgumentsElements implementation.
+ *arguments_index = -environment->parameter_count();
+ *arguments_count = environment->parameter_count();
+
+ WriteTranslation(environment->outer(),
+ translation,
+ arguments_index,
+ arguments_count);
int closure_id = *info()->closure() != *environment->closure()
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
@@ -385,6 +397,17 @@
translation->BeginArgumentsAdaptorFrame(closure_id,
translation_size);
break;
}
+
+ // Inlined frames which push their arguments cause the index to be
+ // bumped and a new stack area to be used for materialization.
+ if (environment->entry() != NULL &&
+ environment->entry()->arguments_pushed()) {
+ *arguments_index = *arguments_index < 0
+ ? GetStackSlotCount()
+ : *arguments_index + *arguments_count;
+ *arguments_count = environment->entry()->arguments_count() + 1;
+ }
+
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -396,7 +419,9 @@
AddToTranslation(translation,
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL)
{
@@ -405,14 +430,18 @@
translation,
environment->spilled_double_registers()[value->index()],
false,
- false);
+ false,
+ *arguments_index,
+ *arguments_count);
}
}
AddToTranslation(translation,
value,
environment->HasTaggedValueAt(i),
- environment->HasUint32ValueAt(i));
+ environment->HasUint32ValueAt(i),
+ *arguments_index,
+ *arguments_count);
}
}
@@ -420,12 +449,14 @@
void LCodeGen::AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32) {
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this
value
// is not present and must be reconstructed from the deoptimizer.
Currently
// this is only used for the arguments object.
- translation->StoreArgumentsObject();
+ translation->StoreArgumentsObject(arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
@@ -531,15 +562,16 @@
int frame_count = 0;
int jsframe_count = 0;
+ int args_index = 0;
+ int args_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
if (e->frame_type() == JS_FUNCTION) {
++jsframe_count;
}
}
- Translation translation(&translations_, frame_count, jsframe_count,
- environment->zone());
- WriteTranslation(environment, &translation);
+ Translation translation(&translations_, frame_count, jsframe_count,
zone());
+ WriteTranslation(environment, &translation, &args_index, &args_count);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Wed Sep 12
05:28:42 2012
@@ -117,7 +117,10 @@
void DoGap(LGap* instr);
// Emit frame translation commands for an environment.
- void WriteTranslation(LEnvironment* environment, Translation*
translation);
+ void WriteTranslation(LEnvironment* environment,
+ Translation* translation,
+ int* arguments_index,
+ int* arguments_count);
// Declare methods that deal with the individual node types.
#define DECLARE_DO(type) void Do##type(L##type* node);
@@ -225,7 +228,9 @@
void AddToTranslation(Translation* translation,
LOperand* op,
bool is_tagged,
- bool is_uint32);
+ bool is_uint32,
+ int arguments_index,
+ int arguments_count);
void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Sep 10 01:35:26 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Wed Sep 12 05:28:42 2012
@@ -865,6 +865,7 @@
argument_count_,
value_count,
outer,
+ hydrogen_env->entry(),
zone());
int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
@@ -2254,6 +2255,7 @@
if (instr->arguments_var() != NULL) {
inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
+ inner->set_entry(instr);
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
return NULL;
=======================================
--- /branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js Tue
Aug 28 07:17:55 2012
+++ /branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js Wed
Sep 12 05:28:42 2012
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --max-opt-count=100
function A() {
}
@@ -157,9 +157,8 @@
test_toarr(toarr1);
test_toarr(toarr2);
+
// Test that arguments access from inlined function uses correct values.
-// TODO(mstarzinger): Tests disabled, see bug 2261
-/*
(function () {
function inner(x, y) {
"use strict";
@@ -204,4 +203,66 @@
%OptimizeFunctionOnNextCall(outer);
assertEquals(2, outer(1, 2));
})();
-*/
+
+
+// Test inlining and deoptimization of functions accessing and modifying
+// the arguments object in strict mode with mismatched arguments count.
+(function () {
+ "use strict";
+ function test(outerCount, middleCount, innerCount) {
+ var forceDeopt = { deopt:false };
+ function inner(x,y) {
+ x = 0; y = 0;
+ forceDeopt.deopt;
+ assertSame(innerCount, arguments.length);
+ for (var i = 0; i < arguments.length; i++) {
+ assertSame(30 + i, arguments[i]);
+ }
+ }
+
+ function middle(x,y) {
+ x = 0; y = 0;
+ if (innerCount == 1) inner(30);
+ if (innerCount == 2) inner(30, 31);
+ if (innerCount == 3) inner(30, 31, 32);
+ assertSame(middleCount, arguments.length);
+ for (var i = 0; i < arguments.length; i++) {
+ assertSame(20 + i, arguments[i]);
+ }
+ }
+
+ function outer(x,y) {
+ x = 0; y = 0;
+ if (middleCount == 1) middle(20);
+ if (middleCount == 2) middle(20, 21);
+ if (middleCount == 3) middle(20, 21, 22);
+ assertSame(outerCount, arguments.length);
+ for (var i = 0; i < arguments.length; i++) {
+ assertSame(10 + i, arguments[i]);
+ }
+ }
+
+ for (var step = 0; step < 4; step++) {
+ if (outerCount == 1) outer(10);
+ if (outerCount == 2) outer(10, 11);
+ if (outerCount == 3) outer(10, 11, 12);
+ if (step == 1) %OptimizeFunctionOnNextCall(outer);
+ if (step == 2) delete forceDeopt.deopt;
+ }
+
+ %DeoptimizeFunction(outer);
+ %DeoptimizeFunction(middle);
+ %DeoptimizeFunction(inner);
+ %ClearFunctionTypeFeedback(outer);
+ %ClearFunctionTypeFeedback(middle);
+ %ClearFunctionTypeFeedback(inner);
+ }
+
+ for (var a = 1; a <= 3; a++) {
+ for (var b = 1; b <= 3; b++) {
+ for (var c = 1; c <= 3; c++) {
+ test(a,b,c);
+ }
+ }
+ }
+})();
=======================================
--- /branches/bleeding_edge/test/mjsunit/object-define-property.js Fri Aug
31 05:02:02 2012
+++ /branches/bleeding_edge/test/mjsunit/object-define-property.js Wed Sep
12 05:28:42 2012
@@ -1057,7 +1057,7 @@
// Regression test: Bizzare behavior on non-strict arguments object.
-// TODO(mstarzinger): Tests disabled, see bug 2261
+// TODO(yangguo): Tests disabled, needs investigation!
/*
(function test(arg0) {
// Here arguments[0] is a fast alias on arg0.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev