#include "bootstrapper.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
}
+void StringLengthStub::Generate(MacroAssembler* masm) {
+ Label miss;
+ Register receiver;
+ if (kind() == Code::KEYED_LOAD_IC) {
+ // ----------- S t a t e -------------
+ // -- lr : return address
+ // -- r0 : key
+ // -- r1 : receiver
+ // -----------------------------------
+ __ cmp(r0, Operand(masm->isolate()->factory()->length_symbol()));
+ __ b(ne, &miss);
+ receiver = r1;
+ } else {
+ ASSERT(kind() == Code::LOAD_IC);
+ // ----------- S t a t e -------------
+ // -- r2 : name
+ // -- lr : return address
+ // -- r0 : receiver
+ // -- sp[0] : receiver
+ // -----------------------------------
+ receiver = r0;
+ }
+
+ StubCompiler::GenerateLoadStringLength(masm, receiver, r3, r4, &miss,
+ support_wrapper_);
+
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, kind());
+}
+
+
Register InstanceofStub::left() { return r0; }
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
- // ----------- S t a t e -------------
- // -- r2 : name
- // -- lr : return address
- // -- r0 : receiver
- // -- sp[0] : receiver
- // -----------------------------------
- Label miss;
-
- StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
- support_wrappers);
- // Cache miss: Jump to runtime.
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
-}
-
-
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : name
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
- Handle<String> name) {
- // ----------- S t a t e -------------
- // -- lr : return address
- // -- r0 : key
- // -- r1 : receiver
- // -----------------------------------
- Label miss;
-
- Counters* counters = masm()->isolate()->counters();
- __ IncrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
-
- // Check the key is the cached one.
- __ cmp(r0, Operand(name));
- __ b(ne, &miss);
-
- GenerateLoadStringLength(masm(), r1, r2, r3, &miss, true);
- __ bind(&miss);
- __ DecrementCounter(counters->keyed_load_string_length(), 1, r2, r3);
-
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- return GetCode(Code::CALLBACKS, name);
-}
-
-
Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
Handle<String> name) {
// ----------- S t a t e -------------
#include <math.h> // For isfinite.
#include "builtins.h"
+#include "code-stubs.h"
#include "conversions.h"
#include "hashmap.h"
#include "parser.h"
is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this);
receiver_types_.Clear();
if (key()->IsPropertyName()) {
+ StringLengthStub string_stub(Code::LOAD_IC, false);
if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_ArrayLength)) {
is_array_length_ = true;
- } else if (oracle->LoadIsBuiltin(this, Builtins::kLoadIC_StringLength)) {
+ } else if (oracle->LoadIsStub(this, &string_stub)) {
is_string_length_ = true;
} else if (oracle->LoadIsBuiltin(this,
Builtins::kLoadIC_FunctionPrototype)) {
}
-static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
- LoadIC::GenerateStringLength(masm, false);
-}
-
-
-static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
- LoadIC::GenerateStringLength(masm, true);
-}
-
-
static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
LoadIC::GenerateFunctionPrototype(masm);
}
Code::kNoExtraICState) \
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
- V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
- V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
V(Compare) \
V(CompareIC) \
V(MathPow) \
+ V(StringLength) \
V(RecordWrite) \
V(StoreBufferOverflow) \
V(RegExpExec) \
};
+class ICStub: public PlatformCodeStub {
+ public:
+ explicit ICStub(Code::Kind kind) : kind_(kind) { }
+ virtual int GetCodeKind() { return kind_; }
+ virtual InlineCacheState GetICState() { return MONOMORPHIC; }
+
+ bool Describes(Code* code) {
+ return GetMajorKey(code) == MajorKey() && code->stub_info() == MinorKey();
+ }
+
+ protected:
+ class KindBits: public BitField<Code::Kind, 0, 4> {};
+ virtual void FinishCode(Handle<Code> code) {
+ code->set_stub_info(MinorKey());
+ }
+ Code::Kind kind() { return kind_; }
+
+ private:
+ Code::Kind kind_;
+};
+
+
+class StringLengthStub: public ICStub {
+ public:
+ StringLengthStub(Code::Kind kind, bool support_wrapper)
+ : ICStub(kind), support_wrapper_(support_wrapper) { }
+ virtual void Generate(MacroAssembler* masm);
+
+ private:
+ class WrapperModeBits: public BitField<bool, 4, 1> {};
+ virtual CodeStub::Major MajorKey() { return StringLength; }
+ virtual int MinorKey() {
+ return KindBits::encode(kind()) | WrapperModeBits::encode(support_wrapper_);
+ }
+
+ bool support_wrapper_;
+};
+
+
class BinaryOpStub: public PlatformCodeStub {
public:
BinaryOpStub(Token::Value op, OverwriteMode mode)
}
+void StringLengthStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- ecx : name
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ if (kind() == Code::KEYED_LOAD_IC) {
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->length_symbol()));
+ __ j(not_equal, &miss);
+ }
+
+ StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
+ support_wrapper_);
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, kind());
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in edx and the parameter count is in eax.
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm,
- bool support_wrappers) {
- // ----------- S t a t e -------------
- // -- ecx : name
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
- support_wrappers);
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
-}
-
-
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
- Handle<String> name) {
- // ----------- S t a t e -------------
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
- Label miss;
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->keyed_load_string_length(), 1);
-
- // Check that the name has not changed.
- __ cmp(ecx, Immediate(name));
- __ j(not_equal, &miss);
-
- GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true);
- __ bind(&miss);
- __ DecrementCounter(counters->keyed_load_string_length(), 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(Code::CALLBACKS, name);
-}
-
-
Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
Handle<String> name) {
// ----------- S t a t e -------------
}
+bool IC::HandleLoad(State state,
+ Handle<Object> object,
+ Handle<String> name,
+ MaybeObject** result) {
+ // Use specialized code for getting the length of strings and
+ // string wrapper objects. The length property of string wrapper
+ // objects is read-only and therefore always returns the length of
+ // the underlying string value. See ECMA-262 15.5.5.1.
+ if ((object->IsString() || object->IsStringWrapper()) &&
+ name->Equals(isolate()->heap()->length_symbol())) {
+ Handle<Code> stub;
+ if (state == UNINITIALIZED) {
+ stub = pre_monomorphic_stub();
+ } else if (state == PREMONOMORPHIC) {
+ StringLengthStub string_length_stub(kind(), !object->IsString());
+ stub = string_length_stub.GetCode();
+ } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
+ StringLengthStub string_length_stub(kind(), true);
+ stub = string_length_stub.GetCode();
+ } else if (state != MEGAMORPHIC) {
+ ASSERT(state != GENERIC);
+ stub = megamorphic_stub();
+ }
+ if (!stub.is_null()) {
+ set_target(*stub);
+#ifdef DEBUG
+ if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
+#endif
+ }
+ // Get the string if we have a string wrapper object.
+ Handle<Object> string = object->IsJSValue()
+ ? Handle<Object>(Handle<JSValue>::cast(object)->value())
+ : object;
+ *result = Smi::FromInt(String::cast(*string)->length());
+ return true;
+ }
+ return false;
+}
+
+
MaybeObject* LoadIC::Load(State state,
Handle<Object> object,
Handle<String> name) {
}
if (FLAG_use_ic) {
- // Use specialized code for getting the length of strings and
- // string wrapper objects. The length property of string wrapper
- // objects is read-only and therefore always returns the length of
- // the underlying string value. See ECMA-262 15.5.5.1.
- if ((object->IsString() || object->IsStringWrapper()) &&
- name->Equals(isolate()->heap()->length_symbol())) {
- Handle<Code> stub;
- if (state == UNINITIALIZED) {
- stub = pre_monomorphic_stub();
- } else if (state == PREMONOMORPHIC) {
- stub = object->IsString()
- ? isolate()->builtins()->LoadIC_StringLength()
- : isolate()->builtins()->LoadIC_StringWrapperLength();
- } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
- stub = isolate()->builtins()->LoadIC_StringWrapperLength();
- } else if (state != MEGAMORPHIC) {
- ASSERT(state != GENERIC);
- stub = megamorphic_stub();
- }
- if (!stub.is_null()) {
- set_target(*stub);
-#ifdef DEBUG
- if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
-#endif
- }
- // Get the string if we have a string wrapper object.
- Handle<Object> string = object->IsJSValue()
- ? Handle<Object>(Handle<JSValue>::cast(object)->value())
- : object;
- return Smi::FromInt(String::cast(*string)->length());
+ MaybeObject* result;
+ if (HandleLoad(state, object, name, &result)) {
+ return result;
}
// Use specialized code for getting the length of arrays.
}
if (FLAG_use_ic) {
- // TODO(1073): don't ignore the current stub state.
-
- // Use specialized code for getting the length of strings.
- if (object->IsString() &&
- name->Equals(isolate()->heap()->length_symbol())) {
- Handle<String> string = Handle<String>::cast(object);
- Handle<Code> code =
- isolate()->stub_cache()->ComputeKeyedLoadStringLength(name, string);
- ASSERT(!code.is_null());
- set_target(*code);
- TRACE_IC("KeyedLoadIC", name, state, target());
- return Smi::FromInt(string->length());
+ MaybeObject* result;
+ if (HandleLoad(state, object, name, &result)) {
+ return result;
}
+ // TODO(1073): don't ignore the current stub state.
// Use specialized code for getting the length of arrays.
if (object->IsJSArray() &&
name->Equals(isolate()->heap()->length_symbol())) {
isolate()->stub_cache()->Set(*name, receiver->map(), *code);
set_target((strict_mode == kStrictMode)
? megamorphic_stub_strict()
- : megamorphic_stub());
+ : *megamorphic_stub());
}
break;
case MEGAMORPHIC:
InlineCacheHolderFlag holder);
protected:
+ virtual Handle<Code> pre_monomorphic_stub() {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
+ virtual Handle<Code> megamorphic_stub() {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
+ virtual Code::Kind kind() const {
+ UNREACHABLE();
+ return Code::STUB;
+ }
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
Isolate* isolate() const { return isolate_; }
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
+ bool HandleLoad(State state,
+ Handle<Object> object,
+ Handle<String> name,
+ MaybeObject** result);
+
private:
// Frame pointer for the frame that uses (calls) the IC.
Address fp_;
// Specialized code generator routines.
static void GenerateArrayLength(MacroAssembler* masm);
- static void GenerateStringLength(MacroAssembler* masm,
- bool support_wrappers);
static void GenerateFunctionPrototype(MacroAssembler* masm);
+ protected:
+ virtual Code::Kind kind() const { return Code::LOAD_IC; }
+
+ virtual Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->LoadIC_Megamorphic();
+ }
+
private:
// Update the inline cache and the global stub cache based on the
// lookup result.
Handle<String> name);
// Stub accessors.
- Handle<Code> megamorphic_stub() {
- return isolate()->builtins()->LoadIC_Megamorphic();
- }
static Code* initialize_stub() {
return Isolate::Current()->builtins()->builtin(
Builtins::kLoadIC_Initialize);
}
- Handle<Code> pre_monomorphic_stub() {
+ virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->LoadIC_PreMonomorphic();
}
return Handle<Code>::null();
}
- virtual Code::Kind kind() const = 0;
-
Handle<Code> ComputeStub(Handle<JSObject> receiver,
StubKind stub_kind,
StrictModeFlag strict_mode,
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
+ virtual Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->KeyedLoadIC_Generic();
+ }
+
virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
StrictModeFlag strict_mode,
KeyedAccessGrowMode grow_mode);
return Isolate::Current()->builtins()->builtin(
Builtins::kKeyedLoadIC_Initialize);
}
- Handle<Code> megamorphic_stub() {
- return isolate()->builtins()->KeyedLoadIC_Generic();
- }
Handle<Code> generic_stub() const {
return isolate()->builtins()->KeyedLoadIC_Generic();
}
- Handle<Code> pre_monomorphic_stub() {
+ virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
}
Handle<Code> indexed_interceptor_stub() {
static void GenerateGlobalProxy(MacroAssembler* masm,
StrictModeFlag strict_mode);
+ protected:
+ virtual Code::Kind kind() const { return Code::STORE_IC; }
+ virtual Handle<Code> megamorphic_stub() {
+ return isolate()->builtins()->StoreIC_Megamorphic();
+ }
+
private:
// Update the inline cache and the global stub cache based on the
// lookup result.
}
// Stub accessors.
- Code* megamorphic_stub() {
- return isolate()->builtins()->builtin(
- Builtins::kStoreIC_Megamorphic);
- }
Code* megamorphic_stub_strict() {
return isolate()->builtins()->builtin(
Builtins::kStoreIC_Megamorphic_Strict);
kind() == UNARY_OP_IC ||
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
+ kind() == LOAD_IC ||
+ kind() == KEYED_LOAD_IC ||
kind() == TO_BOOLEAN_IC);
return StubMajorKeyField::decode(
READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
kind() == UNARY_OP_IC ||
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
+ kind() == LOAD_IC ||
+ kind() == KEYED_LOAD_IC ||
kind() == TO_BOOLEAN_IC);
ASSERT(0 <= major && major < 256);
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
int Code::stub_info() {
- ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC);
+ ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC || kind() == LOAD_IC);
Object* value = READ_FIELD(this, kTypeFeedbackInfoOffset);
return Smi::cast(value)->value();
}
void Code::set_stub_info(int value) {
- ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC);
+ ASSERT(kind() == COMPARE_IC ||
+ kind() == BINARY_OP_IC ||
+ kind() == LOAD_IC ||
+ kind() == KEYED_LOAD_IC);
WRITE_FIELD(this, kTypeFeedbackInfoOffset, Smi::FromInt(value));
}
}
-Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
- Handle<String> receiver) {
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
- Handle<Map> map(receiver->map());
- Handle<Object> probe(map->FindInCodeCache(*name, flags), isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
-
- KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadStringLength(name);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- Map::UpdateCodeCache(map, name, code);
- return code;
-}
-
-
Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
Handle<String> name,
Handle<JSFunction> receiver) {
Handle<Code> ComputeKeyedLoadArrayLength(Handle<String> name,
Handle<JSArray> receiver);
- Handle<Code> ComputeKeyedLoadStringLength(Handle<String> name,
- Handle<String> receiver);
-
Handle<Code> ComputeKeyedLoadFunctionPrototype(Handle<String> name,
Handle<JSFunction> receiver);
Handle<Code> CompileLoadArrayLength(Handle<String> name);
- Handle<Code> CompileLoadStringLength(Handle<String> name);
-
Handle<Code> CompileLoadFunctionPrototype(Handle<String> name);
Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
}
+bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) {
+ Handle<Object> object = GetInfo(expr->PropertyFeedbackId());
+ if (!object->IsCode()) return false;
+ Handle<Code> code = Handle<Code>::cast(object);
+ if (!code->is_load_stub()) return false;
+ return stub->Describes(*code);
+}
+
+
static TypeInfo TypeFromCompareType(CompareIC::State state) {
switch (state) {
case CompareIC::UNINITIALIZED:
class CompilationInfo;
class CountOperation;
class Expression;
+class ForInStatement;
+class ICStub;
class Property;
class SmallMapList;
class UnaryOperation;
-class ForInStatement;
class TypeFeedbackOracle: public ZoneObject {
Handle<Map> GetObjectLiteralStoreMap(ObjectLiteral::Property* prop);
bool LoadIsBuiltin(Property* expr, Builtins::Name id);
+ bool LoadIsStub(Property* expr, ICStub* stub);
// TODO(1571) We can't use ToBooleanStub::Types as the return value because
// of various cylces in our headers. Death to tons of implementations in
#include "bootstrapper.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
+#include "stub-cache.h"
namespace v8 {
namespace internal {
}
+void StringLengthStub::Generate(MacroAssembler* masm) {
+ Label miss;
+ Register receiver;
+ if (kind() == Code::KEYED_LOAD_IC) {
+ // ----------- S t a t e -------------
+ // -- rax : key
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ __ Cmp(rax, masm->isolate()->factory()->length_symbol());
+ receiver = rdx;
+ } else {
+ ASSERT(kind() == Code::LOAD_IC);
+ // ----------- S t a t e -------------
+ // -- rax : receiver
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -----------------------------------
+ receiver = rax;
+ }
+
+ StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss,
+ support_wrapper_);
+ __ bind(&miss);
+ StubCompiler::GenerateLoadMiss(masm, kind());
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in rdx and the parameter count is in rax.
}
-void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss,
- support_wrappers);
- __ bind(&miss);
- StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
-}
-
-
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : receiver
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
- Handle<String> name) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
- Label miss;
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->keyed_load_string_length(), 1);
-
- // Check that the name has not changed.
- __ Cmp(rax, name);
- __ j(not_equal, &miss);
-
- GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
- __ bind(&miss);
- __ DecrementCounter(counters->keyed_load_string_length(), 1);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
-
- // Return the generated code.
- return GetCode(Code::CALLBACKS, name);
-}
-
-
Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
Handle<String> name) {
// ----------- S t a t e -------------