Support load function prototype in hydrogen/lithium.

Review URL: http://codereview.chromium.org/6009005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2010-12-22 15:43:32 +00:00
parent 37567c42da
commit c5916f552f
10 changed files with 175 additions and 1 deletions

View File

@ -1854,6 +1854,14 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
}
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
HLoadFunctionPrototype* instr) {
return AssignEnvironment(DefineAsRegister(
new LLoadFunctionPrototype(UseRegister(instr->function()),
TempRegister())));
}
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
return DefineSameAsFirst(new LLoadElements(input));

View File

@ -127,6 +127,7 @@ class Translation;
// LIsSmiAndBranch
// LLoadNamedField
// LLoadNamedGeneric
// LLoadFunctionPrototype
// LNumberTagD
// LNumberTagI
// LPushArgument
@ -223,6 +224,7 @@ class Translation;
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -1256,6 +1258,22 @@ class LLoadNamedGeneric: public LUnaryOperation {
};
class LLoadFunctionPrototype: public LUnaryOperation {
public:
LLoadFunctionPrototype(LOperand* function, LOperand* temporary)
: LUnaryOperation(function), temporary_(temporary) { }
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
LOperand* function() const { return input(); }
LOperand* temporary() const { return temporary_; }
private:
LOperand* temporary_;
};
class LLoadElements: public LUnaryOperation {
public:
explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { }

View File

@ -1447,6 +1447,50 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
}
void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
Register function = ToRegister(instr->function());
Register temp = ToRegister(instr->temporary());
Register result = ToRegister(instr->result());
// Check that the function really is a function. Load map into the
// result register.
__ CompareObjectType(function, result, temp, JS_FUNCTION_TYPE);
DeoptimizeIf(ne, instr->environment());
// Make sure that the function has an instance prototype.
Label non_instance;
__ ldrb(temp, FieldMemOperand(result, Map::kBitFieldOffset));
__ tst(temp, Operand(1 << Map::kHasNonInstancePrototype));
__ b(ne, &non_instance);
// Get the prototype or initial map from the function.
__ ldr(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Check that the function has a prototype or an initial map.
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(result, ip);
DeoptimizeIf(eq, instr->environment());
// If the function does not have an initial map, we're done.
Label done;
__ CompareObjectType(result, temp, temp, MAP_TYPE);
__ b(ne, &done);
// Get the prototype from the initial map.
__ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
__ jmp(&done);
// Non-instance prototype: Fetch prototype from constructor field
// in initial map.
__ bind(&non_instance);
__ ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
// All done.
__ bind(&done);
}
void LCodeGen::DoLoadElements(LLoadElements* instr) {
Abort("DoLoadElements unimplemented.");
}

View File

@ -517,6 +517,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
if (key()->IsPropertyName()) {
if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) {
is_array_length_ = true;
} else if (oracle->LoadIsBuiltin(this,
Builtins::LoadIC_FunctionPrototype)) {
is_function_prototype_ = true;
} else {
Literal* lit_key = key()->AsLiteral();
ASSERT(lit_key != NULL && lit_key->handle()->IsString());

View File

@ -1208,6 +1208,7 @@ class Property: public Expression {
is_monomorphic_(false),
receiver_types_(NULL),
is_array_length_(false),
is_function_prototype_(false),
is_arguments_access_(false) { }
DECLARE_NODE_TYPE(Property)
@ -1220,6 +1221,8 @@ class Property: public Expression {
int position() const { return pos_; }
bool is_synthetic() const { return type_ == SYNTHETIC; }
bool IsFunctionPrototype() const { return is_function_prototype_; }
// Marks that this is actually an argument rewritten to a keyed property
// accessing the argument through the arguments shadow object.
void set_is_arguments_access(bool is_arguments_access) {
@ -1249,6 +1252,7 @@ class Property: public Expression {
bool is_monomorphic_;
ZoneMapList* receiver_types_;
bool is_array_length_;
bool is_function_prototype_;
bool is_arguments_access_;
Handle<Map> monomorphic_receiver_type_;

View File

@ -76,7 +76,6 @@ class LChunkBuilder;
// HLoadKeyed
// HLoadKeyedFastElement
// HLoadKeyedGeneric
// HLoadNamedGeneric
// HPower
// HStoreNamed
// HStoreNamedField
@ -132,6 +131,8 @@ class LChunkBuilder;
// HLoadElements
// HTypeofIs
// HLoadNamedField
// HLoadNamedGeneric
// HLoadFunctionPrototype
// HPushArgument
// HTypeof
// HUnaryMathOperation
@ -221,6 +222,7 @@ class LChunkBuilder;
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(Mod) \
V(Mul) \
V(ObjectLiteral) \
@ -256,6 +258,7 @@ class LChunkBuilder;
V(GlobalVars) \
V(Maps) \
V(ArrayLengths) \
V(FunctionPrototypes) \
V(OsrEntries)
#define DECLARE_INSTRUCTION(type) \
@ -2617,6 +2620,27 @@ class HLoadNamedGeneric: public HUnaryOperation {
};
class HLoadFunctionPrototype: public HUnaryOperation {
public:
explicit HLoadFunctionPrototype(HValue* function)
: HUnaryOperation(function) {
set_representation(Representation::Tagged());
SetFlagMask(kDependsOnFunctionPrototypes);
}
HValue* function() const { return OperandAt(0); }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype")
protected:
virtual bool DataEquals(HValue* other) const { return true; }
};
class HLoadKeyed: public HBinaryOperation {
public:
HLoadKeyed(HValue* obj, HValue* key) : HBinaryOperation(obj, key) {

View File

@ -3722,6 +3722,11 @@ void HGraphBuilder::VisitProperty(Property* expr) {
AddInstruction(new HCheckNonSmi(array));
instr = new HArrayLength(array);
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
AddInstruction(new HCheckNonSmi(function));
instr = new HLoadFunctionPrototype(function);
} else if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
ZoneMapList* types = expr->GetReceiverTypes();

View File

@ -1837,6 +1837,48 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
}
void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
Register function = ToRegister(instr->function());
Register temp = ToRegister(instr->temporary());
Register result = ToRegister(instr->result());
// Check that the function really is a function.
__ CmpObjectType(function, JS_FUNCTION_TYPE, result);
DeoptimizeIf(not_equal, instr->environment());
// Check whether the function has an instance prototype.
NearLabel non_instance;
__ test_b(FieldOperand(result, Map::kBitFieldOffset),
1 << Map::kHasNonInstancePrototype);
__ j(not_zero, &non_instance);
// Get the prototype or initial map from the function.
__ mov(result,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Check that the function has a prototype or an initial map.
__ cmp(Operand(result), Immediate(Factory::the_hole_value()));
DeoptimizeIf(equal, instr->environment());
// If the function does not have an initial map, we're done.
NearLabel done;
__ CmpObjectType(result, MAP_TYPE, temp);
__ j(not_equal, &done);
// Get the prototype from the initial map.
__ mov(result, FieldOperand(result, Map::kPrototypeOffset));
__ jmp(&done);
// Non-instance prototype: Fetch prototype from constructor field
// in the function's map.
__ bind(&non_instance);
__ mov(result, FieldOperand(result, Map::kConstructorOffset));
// All done.
__ bind(&done);
}
void LCodeGen::DoLoadElements(LLoadElements* instr) {
ASSERT(instr->result()->Equals(instr->input()));
Register reg = ToRegister(instr->input());

View File

@ -1860,6 +1860,14 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
}
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
HLoadFunctionPrototype* instr) {
return AssignEnvironment(DefineAsRegister(
new LLoadFunctionPrototype(UseRegister(instr->function()),
TempRegister())));
}
LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
return DefineSameAsFirst(new LLoadElements(input));

View File

@ -130,6 +130,7 @@ class LGapNode;
// LIsSmiAndBranch
// LLoadNamedField
// LLoadNamedGeneric
// LLoadFunctionPrototype
// LNumberTagD
// LNumberTagI
// LPushArgument
@ -226,6 +227,7 @@ class LGapNode;
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@ -1271,6 +1273,22 @@ class LLoadNamedGeneric: public LUnaryOperation {
};
class LLoadFunctionPrototype: public LUnaryOperation {
public:
LLoadFunctionPrototype(LOperand* function, LOperand* temporary)
: LUnaryOperation(function), temporary_(temporary) { }
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
LOperand* function() const { return input(); }
LOperand* temporary() const { return temporary_; }
private:
LOperand* temporary_;
};
class LLoadElements: public LUnaryOperation {
public:
explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { }