Object* CallStubCompiler::CompileCallField(Object* object,
JSObject* holder,
int index,
- String* name,
- Code::Flags flags) {
- ASSERT_EQ(FIELD, Code::ExtractTypeFromFlags(flags));
+ String* name) {
// ----------- S t a t e -------------
// -- lr: return address
// -----------------------------------
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCodeWithFlags(flags, name);
+ return GetCode(FIELD, name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
- CheckType check,
- Code::Flags flags) {
- ASSERT_EQ(CONSTANT_FUNCTION, Code::ExtractTypeFromFlags(flags));
+ CheckType check) {
// ----------- S t a t e -------------
// -- lr: return address
// -----------------------------------
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
- return GetCodeWithFlags(flags, function_name);
+ return GetCode(CONSTANT_FUNCTION, function_name);
}
Object* LoadStubCompiler::CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
- String* name) {
+ String* name,
+ bool is_dont_delete) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
- // Check for deleted property.
- __ cmp(r0, Operand(Factory::the_hole_value()));
- __ b(eq, &miss);
+ // Check for deleted property if property can actually be deleted.
+ if (!is_dont_delete) {
+ __ cmp(r0, Operand(Factory::the_hole_value()));
+ __ b(eq, &miss);
+ }
__ Ret();
PropertyType type = code->type();
out.AddFormatted(", %s", Code::PropertyType2String(type));
}
+ if (code->ic_in_loop() == IN_LOOP) {
+ out.AddFormatted(", in_loop");
+ }
if (kind == Code::CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count());
}
Object* CallStubCompiler::CompileCallField(Object* object,
JSObject* holder,
int index,
- String* name,
- Code::Flags flags) {
- ASSERT_EQ(FIELD, Code::ExtractTypeFromFlags(flags));
+ String* name) {
// ----------- S t a t e -------------
// -----------------------------------
Label miss;
__ jmp(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCodeWithFlags(flags, name);
+ return GetCode(FIELD, name);
}
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
- CheckType check,
- Code::Flags flags) {
- ASSERT_EQ(CONSTANT_FUNCTION, Code::ExtractTypeFromFlags(flags));
+ CheckType check) {
// ----------- S t a t e -------------
// -----------------------------------
Label miss;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
- return GetCodeWithFlags(flags, function_name);
+ return GetCode(CONSTANT_FUNCTION, function_name);
}
Object* LoadStubCompiler::CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* cell,
- String* name) {
+ String* name,
+ bool is_dont_delete) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
__ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
- // Check for deleted property.
- __ cmp(eax, Factory::the_hole_value());
- __ j(equal, &miss, not_taken);
+ // Check for deleted property if property can actually be deleted.
+ if (!is_dont_delete) {
+ __ cmp(eax, Factory::the_hole_value());
+ __ j(equal, &miss, not_taken);
+ }
__ ret(0);
if (lookup->holder() != *global) return;
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- code = StubCache::ComputeLoadGlobal(*name, *global, cell);
+ code = StubCache::ComputeLoadGlobal(*name, *global,
+ cell, lookup->IsDontDelete());
} else {
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
Object* StubCache::ComputeLoadGlobal(String* name,
JSGlobalObject* receiver,
- JSGlobalPropertyCell* cell) {
+ JSGlobalPropertyCell* cell,
+ bool is_dont_delete) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
LoadStubCompiler compiler;
- code = compiler.CompileLoadGlobal(receiver, cell, name);
+ code = compiler.CompileLoadGlobal(receiver, cell, name, is_dont_delete);
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
// caches.
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
- CallStubCompiler compiler(argc);
- code = compiler.CompileCallConstant(object, holder, function, check, flags);
+ CallStubCompiler compiler(argc, in_loop);
+ code = compiler.CompileCallConstant(object, holder, function, check);
if (code->IsFailure()) return code;
+ ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = map->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return result;
argc);
Object* code = map->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(argc);
- code = compiler.CompileCallField(object, holder, index, name, flags);
+ CallStubCompiler compiler(argc, in_loop);
+ code = compiler.CompileCallField(object, holder, index, name);
if (code->IsFailure()) return code;
+ ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = map->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return result;
argc);
Object* code = map->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(argc);
+ CallStubCompiler compiler(argc, NOT_IN_LOOP);
code = compiler.CompileCallInterceptor(object, holder, name);
if (code->IsFailure()) return code;
+ ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = map->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return result;
JSGlobalObject* receiver,
JSGlobalPropertyCell* cell,
JSFunction* function) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, NORMAL);
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(Code::CALL_IC, NORMAL, in_loop, argc);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
// If the function hasn't been compiled yet, we cannot do it now
// internal error which will make sure we do not update any
// caches.
if (!function->is_compiled()) return Failure::InternalError();
- CallStubCompiler compiler(argc);
+ CallStubCompiler compiler(argc, in_loop);
code = compiler.CompileCallGlobal(receiver, cell, function, name);
if (code->IsFailure()) return code;
+ ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
type,
- NOT_IN_LOOP,
+ in_loop_,
argc);
return GetCodeWithFlags(flags, name);
}
static Object* ComputeLoadGlobal(String* name,
JSGlobalObject* receiver,
- JSGlobalPropertyCell* cell);
+ JSGlobalPropertyCell* cell,
+ bool is_dont_delete);
// ---
Object* CompileLoadGlobal(JSGlobalObject* object,
JSGlobalPropertyCell* holder,
- String* name);
+ String* name,
+ bool is_dont_delete);
private:
Object* GetCode(PropertyType type, String* name);
class CallStubCompiler: public StubCompiler {
public:
- explicit CallStubCompiler(int argc) : arguments_(argc) { }
+ explicit CallStubCompiler(int argc, InLoopFlag in_loop)
+ : arguments_(argc), in_loop_(in_loop) { }
Object* CompileCallField(Object* object,
JSObject* holder,
int index,
- String* name,
- Code::Flags flags);
+ String* name);
Object* CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
- CheckType check,
- Code::Flags flags);
+ CheckType check);
Object* CompileCallInterceptor(Object* object,
JSObject* holder,
String* name);
private:
const ParameterCount arguments_;
+ const InLoopFlag in_loop_;
const ParameterCount& arguments() { return arguments_; }
// Call f1 one time and f2 a number of times. This will ensure that f1 still
// uses the runtime system to retreive property a whereas f2 uses global load
- // inline cache is used.
- CHECK(!f1->Call(global, 0, NULL)->IsUndefined());
+ // inline cache.
+ CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
for (int i = 0; i < 4; i++) {
- CHECK(!f2->Call(global, 0, NULL)->IsUndefined());
+ CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
}
// Same for g1 and g2.
- CHECK(!g1->Call(global, 0, NULL)->IsUndefined());
+ CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
for (int i = 0; i < 4; i++) {
- CHECK(!g2->Call(global, 0, NULL)->IsUndefined());
+ CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
}
// Detach the global and turn on access check.