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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13836 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 61a2c53d
......@@ -555,34 +555,62 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
// ----------- 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(&not_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(&not_zero_case);
__ Branch(&not_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(&not_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 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// 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 {
......
......@@ -74,6 +74,44 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor(
}
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)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
......@@ -5618,12 +5656,13 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
}
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()),
......@@ -5660,6 +5699,78 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
}
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(&not_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(&not_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) {
// a1 : the function to call
// a2 : cache cell for call target
......@@ -5692,7 +5803,11 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ 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 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ 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
......
......@@ -3965,12 +3965,32 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
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) {
CallRuntime(instr->function(), instr->arity(), instr);
}
......
......@@ -355,6 +355,17 @@ void LCallNew::PrintDataTo(StringStream* stream) {
}
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) {
arguments()->PrintTo(stream);
stream->Add(" length ");
......@@ -1141,6 +1152,14 @@ LInstruction* LChunkBuilder::DoCallNew(HCallNew* 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) {
LOperand* function = UseFixed(instr->function(), a1);
argument_count_ -= instr->argument_count();
......
......@@ -68,6 +68,7 @@ class LCodeGen;
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
......@@ -1762,6 +1763,23 @@ class LCallNew: public LTemplateInstruction<1, 1, 0> {
};
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")
......
......@@ -4557,6 +4557,19 @@ void MacroAssembler::LoadGlobalFunction(int index, Register function) {
}
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,
Register map,
Register scratch) {
......
......@@ -835,6 +835,7 @@ class MacroAssembler: public Assembler {
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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment