Register function = ToRegister(instr->function());
Register result = ToRegister(instr->result());
- // Check that the function really is a function. Load map into the
- // result register.
- __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
- DeoptimizeIf(ne, instr->environment());
-
- // Make sure that the function has an instance prototype.
- Label non_instance;
- __ ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
- __ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
- __ b(ne, &non_instance);
-
// Get the prototype or initial map from the function.
__ ldr(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// 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);
Register result = ToRegister(instr->result());
Register temp = ToRegister(instr->temp());
- // Check that the function really is a function. Leaves map in 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));
- __ Tbnz(temp, Map::kHasNonInstancePrototype, &non_instance);
-
// Get the prototype or initial map from the function.
__ Ldr(result, FieldMemOperand(function,
JSFunction::kPrototypeOrInitialMapOffset));
// Get the prototype from the initial map.
__ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
- __ B(&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);
BailoutId LoadId() const { return load_id_; }
bool IsStringAccess() const { return is_string_access_; }
- bool IsFunctionPrototype() const { return is_function_prototype_; }
// Type feedback information.
virtual bool IsMonomorphic() V8_OVERRIDE {
}
void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
void set_is_string_access(bool b) { is_string_access_ = b; }
- void set_is_function_prototype(bool b) { is_function_prototype_ = b; }
void mark_for_call() { is_for_call_ = true; }
bool IsForCall() { return is_for_call_; }
int PropertyFeedbackSlot() const { return property_feedback_slot_; }
protected:
- Property(Zone* zone,
- Expression* obj,
- Expression* key,
- int pos)
+ Property(Zone* zone, Expression* obj, Expression* key, int pos)
: Expression(zone, pos),
obj_(obj),
key_(key),
property_feedback_slot_(kInvalidFeedbackSlot),
is_for_call_(false),
is_uninitialized_(false),
- is_string_access_(false),
- is_function_prototype_(false) { }
+ is_string_access_(false) {}
private:
Expression* obj_;
bool is_for_call_ : 1;
bool is_uninitialized_ : 1;
bool is_string_access_ : 1;
- bool is_function_prototype_ : 1;
};
};
-class FunctionPrototypeStub: public ICStub {
+// TODO(verwaest): Translate to hydrogen code stub.
+class FunctionPrototypeStub : public PlatformCodeStub {
public:
FunctionPrototypeStub(Isolate* isolate, Code::Kind kind)
- : ICStub(isolate, kind) { }
+ : PlatformCodeStub(isolate) {
+ bit_field_ = KindBits::encode(kind);
+ }
virtual void Generate(MacroAssembler* masm);
+ virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
+ virtual InlineCacheState GetICState() { return MONOMORPHIC; }
+ virtual ExtraICState GetExtraICState() const { return kind(); }
+
+ protected:
+ class KindBits : public BitField<Code::Kind, 0, 4> {};
+ virtual Code::Kind kind() const { return KindBits::decode(bit_field_); }
private:
virtual CodeStub::Major MajorKey() const { return FunctionPrototype; }
+ virtual int MinorKey() const { return bit_field_; }
+ int bit_field_;
};
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
if (!CanInlinePropertyAccess(type_)) return false;
if (IsJSObjectFieldAccessor()) return IsLoad();
+ if (this->map()->function_with_prototype() &&
+ !this->map()->has_non_instance_prototype() &&
+ name_.is_identical_to(isolate()->factory()->prototype_string())) {
+ return IsLoad();
+ }
if (!LookupDescriptor()) return false;
if (lookup_.IsFound()) {
if (IsLoad()) return true;
return New<HLoadNamedField>(object, checked_object, access);
}
+ if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
+ info->map()->function_with_prototype()) {
+ ASSERT(!info->map()->has_non_instance_prototype());
+ return New<HLoadFunctionPrototype>(checked_object);
+ }
+
HValue* checked_holder = checked_object;
if (info->has_holder()) {
Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
- prop->IsStringAccess()) {
+ if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
}
AddInstruction(char_code);
instr = NewUncasted<HStringCharFromCode>(char_code);
- } else if (expr->IsFunctionPrototype()) {
- HValue* function = Pop();
- BuildCheckHeapObject(function);
- instr = New<HLoadFunctionPrototype>(function);
-
} else if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
HValue* object = Pop();
if (TryArgumentsAccess(expr)) return;
CHECK_ALIVE(VisitForValue(expr->obj()));
- if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
- expr->IsStringAccess()) {
+ if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
}
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
- prop->IsStringAccess()) {
+ if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
}
Register temp = ToRegister(instr->temp());
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.
- Label non_instance;
- __ test_b(FieldOperand(result, Map::kBitFieldOffset),
- 1 << Map::kHasNonInstancePrototype);
- __ j(not_zero, &non_instance, Label::kNear);
-
// Get the prototype or initial map from the function.
__ mov(result,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Get the prototype from the initial map.
__ mov(result, FieldOperand(result, Map::kPrototypeOffset));
- __ jmp(&done, Label::kNear);
-
- // 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);
return TypeError("non_object_property_load", object, name);
}
- if (FLAG_use_ic) {
- // Use specialized code for getting prototype of functions.
- if (object->IsJSFunction() &&
- String::Equals(isolate()->factory()->prototype_string(), name) &&
- Handle<JSFunction>::cast(object)->should_have_prototype()) {
- Handle<Code> stub;
- if (state() == UNINITIALIZED) {
- stub = pre_monomorphic_stub();
- } else if (state() == PREMONOMORPHIC) {
- FunctionPrototypeStub function_prototype_stub(isolate(), kind());
- stub = function_prototype_stub.GetCode();
- } else if (!FLAG_compiled_keyed_generic_loads && state() != MEGAMORPHIC) {
- ASSERT(state() != GENERIC);
- stub = megamorphic_stub();
- } else if (FLAG_compiled_keyed_generic_loads && state() != GENERIC) {
- stub = generic_stub();
- }
- if (!stub.is_null()) {
- set_target(*stub);
- if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
- }
- return Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
- }
- }
-
// Check if the name is trivially convertible to an index and get
// the element or char if so.
uint32_t index;
}
}
+ // Use specialized code for getting prototype of functions.
+ if (object->IsJSFunction() &&
+ String::Equals(isolate()->factory()->prototype_string(), name) &&
+ Handle<JSFunction>::cast(object)->should_have_prototype()) {
+ Handle<Code> stub;
+ FunctionPrototypeStub function_prototype_stub(isolate(), kind());
+ return function_prototype_stub.GetCode();
+ }
+
Handle<HeapType> type = receiver_type();
Handle<JSObject> holder(lookup->holder());
bool receiver_is_holder = object.is_identical_to(holder);
ASSERT(!heap->InNewSpace(name));
ASSERT(name->IsUniqueName());
- // The state bits are not important to the hash function because
- // the stub cache only contains monomorphic stubs. Make sure that
- // the bits are the least significant so they will be the ones
- // masked out.
- ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
+ // The state bits are not important to the hash function because the stub
+ // cache only contains handlers. Make sure that the bits are the least
+ // significant so they will be the ones masked out.
+ ASSERT_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
// Make sure that the code type and cache holder are not included in the hash.
}
-bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) {
- Handle<Object> object = GetInfo(id);
- if (!object->IsCode()) return false;
- Handle<Code> code = Handle<Code>::cast(object);
- if (!code->is_load_stub()) return false;
- if (code->ic_state() != MONOMORPHIC) return false;
- return stub->Describes(*code);
-}
-
-
void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
Type** left_type,
Type** right_type,
}
-void TypeFeedbackOracle::PropertyReceiverTypes(
- TypeFeedbackId id, Handle<String> name,
- SmallMapList* receiver_types, bool* is_prototype) {
+void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id,
+ Handle<String> name,
+ SmallMapList* receiver_types) {
receiver_types->Clear();
- FunctionPrototypeStub proto_stub(isolate(), Code::LOAD_IC);
- *is_prototype = LoadIsStub(id, &proto_stub);
- if (!*is_prototype) {
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
- CollectReceiverTypes(id, name, flags, receiver_types);
- }
+ Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ CollectReceiverTypes(id, name, flags, receiver_types);
}
KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);
- void PropertyReceiverTypes(TypeFeedbackId id,
- Handle<String> name,
- SmallMapList* receiver_types,
- bool* is_prototype);
+ void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
+ SmallMapList* receiver_types);
void KeyedPropertyReceiverTypes(TypeFeedbackId id,
SmallMapList* receiver_types,
bool* is_string);
Handle<AllocationSite> GetCallNewAllocationSite(int slot);
bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
- bool LoadIsStub(TypeFeedbackId id, ICStub* stub);
// TODO(1571) We can't use ToBooleanStub::Types as the return value because
// of various cycles in our headers. Death to tons of implementations in
Literal* lit_key = expr->key()->AsLiteral();
ASSERT(lit_key != NULL && lit_key->value()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->value());
- bool is_prototype;
- oracle()->PropertyReceiverTypes(
- id, name, expr->GetReceiverTypes(), &is_prototype);
- expr->set_is_function_prototype(is_prototype);
+ oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
} else {
bool is_string;
oracle()->KeyedPropertyReceiverTypes(
Register function = ToRegister(instr->function());
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.
- Label non_instance;
- __ testb(FieldOperand(result, Map::kBitFieldOffset),
- Immediate(1 << Map::kHasNonInstancePrototype));
- __ j(not_zero, &non_instance, Label::kNear);
-
// Get the prototype or initial map from the function.
__ movp(result,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
// Get the prototype from the initial map.
__ movp(result, FieldOperand(result, Map::kPrototypeOffset));
- __ jmp(&done, Label::kNear);
-
- // Non-instance prototype: Fetch prototype from constructor field
- // in the function's map.
- __ bind(&non_instance);
- __ movp(result, FieldOperand(result, Map::kConstructorOffset));
// All done.
__ bind(&done);