Revision: 13836
Author: [email protected]
Date: Wed Mar 6 04:23:09 2013
Log: MIPS: Allocation Info Tracking, continued.
Port r13790 (0a70a3af)
Original commit message:
Addresses missing cases for array literals.
Adds support for "new Array()" call sites. This isn't complete yet, I have
to run with --noinline_new.
BUG=
Review URL: https://codereview.chromium.org/12507006
http://code.google.com/p/v8/source/detail?r=13836
Modified:
/branches/bleeding_edge/src/mips/builtins-mips.cc
/branches/bleeding_edge/src/mips/code-stubs-mips.cc
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.h
/branches/bleeding_edge/src/mips/macro-assembler-mips.cc
/branches/bleeding_edge/src/mips/macro-assembler-mips.h
=======================================
--- /branches/bleeding_edge/src/mips/builtins-mips.cc Mon Mar 4 06:45:39
2013
+++ /branches/bleeding_edge/src/mips/builtins-mips.cc Wed Mar 6 04:23:09
2013
@@ -555,34 +555,62 @@
// ----------- S t a t e -------------
// -- a0 : number of arguments
// -- a1 : constructor function
+ // -- a2 : type info cell
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
- Label generic_constructor;
if (FLAG_debug_code) {
// The array construct code is only set for the builtin and internal
// Array functions which always have a map.
// Initial map for the builtin Array function should be a map.
- __ lw(a2, FieldMemOperand(a1,
JSFunction::kPrototypeOrInitialMapOffset));
- __ And(t0, a2, Operand(kSmiTagMask));
+ __ lw(a3, FieldMemOperand(a1,
JSFunction::kPrototypeOrInitialMapOffset));
+ __ And(t0, a3, Operand(kSmiTagMask));
__ Assert(ne, "Unexpected initial map for Array function (3)",
t0, Operand(zero_reg));
- __ GetObjectType(a2, a3, t0);
+ __ GetObjectType(a1, a3, t0);
__ Assert(eq, "Unexpected initial map for Array function (4)",
t0, Operand(MAP_TYPE));
+
+ // We should either have undefined in a2 or a valid
jsglobalpropertycell
+ Label okay_here;
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->heap()->undefined_value(), masm->isolate());
+ Handle<Map> global_property_cell_map(
+ masm->isolate()->heap()->global_property_cell_map());
+ __ Branch(&okay_here, eq, a2, Operand(undefined_sentinel));
+ __ lw(a3, FieldMemOperand(a2, 0));
+ __ Assert(eq, "Expected property cell in register a3",
+ a3, Operand(global_property_cell_map));
+ __ bind(&okay_here);
}
- // Run the native code for the Array function called as a constructor.
- ArrayNativeCode(masm, &generic_constructor);
+ if (FLAG_optimize_constructed_arrays) {
+ Label not_zero_case, not_one_case;
+ __ Branch(¬_zero_case, ne, a0, Operand(zero_reg));
+ ArrayNoArgumentConstructorStub no_argument_stub;
+ __ TailCallStub(&no_argument_stub);
- // Jump to the generic construct code in case the specialized code cannot
- // handle the construction.
- __ bind(&generic_constructor);
+ __ bind(¬_zero_case);
+ __ Branch(¬_one_case, gt, a0, Operand(1));
+ ArraySingleArgumentConstructorStub single_argument_stub;
+ __ TailCallStub(&single_argument_stub);
- Handle<Code> generic_construct_stub =
- masm->isolate()->builtins()->JSConstructStubGeneric();
- __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ __ bind(¬_one_case);
+ ArrayNArgumentsConstructorStub n_argument_stub;
+ __ TailCallStub(&n_argument_stub);
+ } else {
+ Label generic_constructor;
+ // Run the native code for the Array function called as a constructor.
+ ArrayNativeCode(masm, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code
cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
+ __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ }
}
@@ -1171,6 +1199,10 @@
// Invoke the code and pass argc as a0.
__ mov(a0, a3);
if (is_construct) {
+ // No type feedback cell is available
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->heap()->undefined_value(), masm->isolate());
+ __ li(a2, Operand(undefined_sentinel));
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ CallStub(&stub);
} else {
=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Tue Mar 5 02:48:16
2013
+++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Wed Mar 6 04:23:09
2013
@@ -72,6 +72,44 @@
Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry;
descriptor->deoptimization_handler_ = FUNCTION_ADDR(entry);
}
+
+
+static void InitializeArrayConstructorDescriptor(Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ // register state
+ // a1 -- constructor function
+ // a2 -- type info cell with elements kind
+ // a0 -- number of arguments to the constructor function
+ static Register registers[] = { a1, a2 };
+ descriptor->register_param_count_ = 2;
+ // stack param count needs (constructor pointer, and single argument)
+ descriptor->stack_parameter_count_ = &a0;
+ descriptor->register_params_ = registers;
+ descriptor->extra_expression_stack_count_ = 1;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ArrayConstructor_StubFailure);
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
#define __ ACCESS_MASM(masm)
@@ -5618,12 +5656,13 @@
}
-static void GenerateRecordCallTarget(MacroAssembler* masm) {
+static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// a1 : the function to call
// a2 : cache cell for call target
+ ASSERT(!FLAG_optimize_constructed_arrays);
Label done;
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
@@ -5658,6 +5697,78 @@
__ bind(&done);
}
+
+
+static void GenerateRecordCallTarget(MacroAssembler* masm) {
+ // Cache the called function in a global property cell. Cache states
+ // are uninitialized, monomorphic (indicated by a JSFunction), and
+ // megamorphic.
+ // a1 : the function to call
+ // a2 : cache cell for call target
+ ASSERT(FLAG_optimize_constructed_arrays);
+ Label initialize, done, miss, megamorphic, not_array_function;
+
+ ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
+ masm->isolate()->heap()->undefined_value());
+ ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
+ masm->isolate()->heap()->the_hole_value());
+
+ // Load the cache state into a3.
+ __ lw(a3, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+
+ // A monomorphic cache hit or an already megamorphic state: invoke the
+ // function without changing the state.
+ __ Branch(&done, eq, a3, Operand(a1));
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ __ Branch(&done, eq, a3, Operand(at));
+
+ // Special handling of the Array() function, which caches not only the
+ // monomorphic Array function but the initial ElementsKind with special
+ // sentinels
+ Handle<Object> terminal_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
+ LAST_FAST_ELEMENTS_KIND);
+ __ Branch(&miss, ne, a3, Operand(terminal_kind_sentinel));
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(a3);
+ __ Branch(&megamorphic, ne, a1, Operand(a3));
+ __ jmp(&done);
+
+ __ bind(&miss);
+
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+ // megamorphic.
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ Branch(&initialize, eq, a3, Operand(at));
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no
+ // write-barrier is needed.
+ __ bind(&megamorphic);
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ __ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+
+ // An uninitialized cache is patched with the function or sentinel to
+ // indicate the ElementsKind if function is the Array constructor.
+ __ bind(&initialize);
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(a3);
+ __ Branch(¬_array_function, ne, a1, Operand(a3));
+
+ // The target function is the Array constructor, install a sentinel
value in
+ // the constructor's type info cell that will track the initial
ElementsKind
+ // that should be used for the array when its constructed.
+ Handle<Object> initial_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
+ GetInitialFastElementsKind());
+ __ li(a3, Operand(initial_kind_sentinel));
+ __ sw(a3, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+ __ Branch(&done);
+
+ __ bind(¬_array_function);
+ __ sw(a1, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+ // No need for a write barrier here - cells are rescanned.
+
+ __ bind(&done);
+}
void CallFunctionStub::Generate(MacroAssembler* masm) {
@@ -5692,7 +5803,11 @@
__ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Fast-case: Invoke the function now.
@@ -5766,13 +5881,19 @@
__ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Jump to the function-specific construct stub.
- __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
- __ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kConstructStubOffset));
- __ Addu(at, a2, Operand(Code::kHeaderSize - kHeapObjectTag));
+ Register jmp_reg = FLAG_optimize_constructed_arrays ? a3 : a2;
+ __ lw(jmp_reg, FieldMemOperand(a1,
JSFunction::kSharedFunctionInfoOffset));
+ __ lw(jmp_reg, FieldMemOperand(jmp_reg,
+
SharedFunctionInfo::kConstructStubOffset));
+ __ Addu(at, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
// a0: number of arguments
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Tue Mar 5
02:48:16 2013
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Mar 6
04:23:09 2013
@@ -3965,10 +3965,30 @@
ASSERT(ToRegister(instr->constructor()).is(a1));
ASSERT(ToRegister(instr->result()).is(v0));
- CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ li(a0, Operand(instr->arity()));
+ if (FLAG_optimize_constructed_arrays) {
+ // No cell in a2 for construct type feedback in optimized code
+ Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
+ isolate());
+ __ li(a2, Operand(undefined_value));
+ }
+ CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
+
+
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+ ASSERT(ToRegister(instr->constructor()).is(a1));
+ ASSERT(ToRegister(instr->result()).is(v0));
+ ASSERT(FLAG_optimize_constructed_arrays);
+
+ __ li(a0, Operand(instr->arity()));
+ __ li(a2, Operand(instr->hydrogen()->property_cell()));
+ Handle<Code> array_construct_code =
+ isolate()->builtins()->ArrayConstructCode();
+
+ CallCode(array_construct_code, RelocInfo::CONSTRUCT_CALL, instr);
+}
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Mon Mar 4 06:23:30
2013
+++ /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Mar 6 04:23:09
2013
@@ -353,6 +353,17 @@
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
+
+
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+ stream->Add("= ");
+ constructor()->PrintTo(stream);
+ stream->Add(" #%d / ", arity());
+ ASSERT(hydrogen()->property_cell()->value()->IsSmi());
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(hydrogen()->property_cell()->value())->value());
+ stream->Add(" (%s) ", ElementsKindToString(kind));
+}
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
@@ -1139,6 +1150,14 @@
LCallNew* result = new(zone()) LCallNew(constructor);
return MarkAsCall(DefineFixed(result, v0), instr);
}
+
+
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+ LOperand* constructor = UseFixed(instr->constructor(), a1);
+ argument_count_ -= instr->argument_count();
+ LCallNewArray* result = new(zone()) LCallNewArray(constructor);
+ return MarkAsCall(DefineFixed(result, v0), instr);
+}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.h Mon Mar 4 06:23:30 2013
+++ /branches/bleeding_edge/src/mips/lithium-mips.h Wed Mar 6 04:23:09 2013
@@ -68,6 +68,7 @@
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
@@ -1762,6 +1763,23 @@
};
+class LCallNewArray: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCallNewArray(LOperand* constructor) {
+ inputs_[0] = constructor;
+ }
+
+ LOperand* constructor() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+ DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Tue Mar 5
02:48:16 2013
+++ /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Wed Mar 6
04:23:09 2013
@@ -4555,6 +4555,19 @@
// Load the function from the native context.
lw(function, MemOperand(function, Context::SlotOffset(index)));
}
+
+
+void MacroAssembler::LoadArrayFunction(Register function) {
+ // Load the global or builtins object from the current context.
+ lw(function,
+ MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+ // Load the global context from the global or builtins object.
+ lw(function,
+ FieldMemOperand(function, GlobalObject::kGlobalContextOffset));
+ // Load the array function from the native context.
+ lw(function,
+ MemOperand(function,
Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.h Mon Feb 25
06:46:09 2013
+++ /branches/bleeding_edge/src/mips/macro-assembler-mips.h Wed Mar 6
04:23:09 2013
@@ -835,6 +835,7 @@
bool can_have_holes);
void LoadGlobalFunction(int index, Register function);
+ void LoadArrayFunction(Register function);
// Load the initial map from the global function. The registers
// function and map can be the same, function is then overwritten.
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.