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:
parent
37567c42da
commit
c5916f552f
@ -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));
|
||||
|
@ -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) { }
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
|
@ -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) { }
|
||||
|
Loading…
Reference in New Issue
Block a user