Revision: 16543
Author: dcar...@chromium.org
Date: Thu Sep 5 08:34:17 2013 UTC
Log: load ics for js api accessors
R=mstarzin...@chromium.org
BUG=
Review URL: https://codereview.chromium.org/23699002
http://code.google.com/p/v8/source/detail?r=16543
Modified:
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/test/cctest/test-accessors.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Aug 27 13:41:44
2013 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Sep 5 08:34:17
2013 UTC
@@ -1292,7 +1292,7 @@
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
- Handle<ExecutableAccessorInfo> callback) {
+ Handle<Object> callback) {
Label miss;
Register reg = HandlerFrontendHeader(object, object_reg, holder, name,
&miss);
@@ -1377,6 +1377,24 @@
__ LoadObject(r0, value);
__ Ret();
}
+
+
+void BaseLoadStubCompiler::GenerateLoadCallback(
+ const CallOptimization& call_optimization) {
+ ASSERT(call_optimization.is_simple_api_call());
+
+ // Assign stack space for the call arguments.
+ __ sub(sp, sp, Operand((kFastApiCallArguments + 1) * kPointerSize));
+
+ int argc = 0;
+ int api_call_argc = argc + kFastApiCallArguments;
+ // Write holder to stack frame.
+ __ str(receiver(), MemOperand(sp, 0));
+ // Write receiver to stack frame.
+ __ str(receiver(), MemOperand(sp, api_call_argc * kPointerSize));
+
+ GenerateFastApiDirectCall(masm(), call_optimization, argc);
+}
void BaseLoadStubCompiler::GenerateLoadCallback(
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Aug 27 13:41:44
2013 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Sep 5 08:34:17
2013 UTC
@@ -1261,7 +1261,7 @@
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
- Handle<ExecutableAccessorInfo> callback) {
+ Handle<Object> callback) {
Label miss;
Register reg = HandlerFrontendHeader(object, object_reg, holder, name,
&miss);
@@ -1352,6 +1352,28 @@
GenerateTailCall(masm(), stub.GetCode(isolate()));
}
}
+
+
+void BaseLoadStubCompiler::GenerateLoadCallback(
+ const CallOptimization& call_optimization) {
+ ASSERT(call_optimization.is_simple_api_call());
+
+ // Copy return value.
+ __ mov(scratch3(), Operand(esp, 0));
+ // Assign stack space for the call arguments.
+ __ sub(esp, Immediate((kFastApiCallArguments + 1) * kPointerSize));
+ // Move the return address on top of the stack.
+ __ mov(Operand(esp, 0), scratch3());
+
+ int argc = 0;
+ int api_call_argc = argc + kFastApiCallArguments;
+ // Write holder to stack frame.
+ __ mov(Operand(esp, 1 * kPointerSize), receiver());
+ // Write receiver to stack frame.
+ __ mov(Operand(esp, (api_call_argc + 1) * kPointerSize), receiver());
+
+ GenerateFastApiCall(masm(), call_optimization, argc);
+}
void BaseLoadStubCompiler::GenerateLoadCallback(
=======================================
--- /branches/bleeding_edge/src/ic.cc Wed Sep 4 07:05:11 2013 UTC
+++ /branches/bleeding_edge/src/ic.cc Thu Sep 5 08:34:17 2013 UTC
@@ -1357,8 +1357,15 @@
if (!getter->IsJSFunction()) break;
if (holder->IsGlobalObject()) break;
if (!holder->HasFastProperties()) break;
+ Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+ CallOptimization call_optimization(function);
+ if (call_optimization.is_simple_api_call() &&
+ call_optimization.IsCompatibleReceiver(*receiver)) {
+ return isolate()->stub_cache()->ComputeLoadCallback(
+ name, receiver, holder, call_optimization);
+ }
return isolate()->stub_cache()->ComputeLoadViaGetter(
- name, receiver, holder, Handle<JSFunction>::cast(getter));
+ name, receiver, holder, function);
} else if (receiver->IsJSArray() &&
name->Equals(isolate()->heap()->length_string())) {
PropertyIndex lengthIndex =
@@ -1544,13 +1551,29 @@
case CALLBACKS: {
Handle<Object> callback_object(lookup->GetCallbackObject(),
isolate());
// TODO(dcarney): Handle DeclaredAccessorInfo correctly.
- if (!callback_object->IsExecutableAccessorInfo()) break;
- Handle<ExecutableAccessorInfo> callback =
- Handle<ExecutableAccessorInfo>::cast(callback_object);
- if (v8::ToCData<Address>(callback->getter()) == 0) break;
- if (!callback->IsCompatibleReceiver(*receiver)) break;
- return isolate()->stub_cache()->ComputeKeyedLoadCallback(
- name, receiver, holder, callback);
+ if (callback_object->IsExecutableAccessorInfo()) {
+ Handle<ExecutableAccessorInfo> callback =
+ Handle<ExecutableAccessorInfo>::cast(callback_object);
+ if (v8::ToCData<Address>(callback->getter()) == 0) break;
+ if (!callback->IsCompatibleReceiver(*receiver)) break;
+ return isolate()->stub_cache()->ComputeKeyedLoadCallback(
+ name, receiver, holder, callback);
+ } else if (callback_object->IsAccessorPair()) {
+ Handle<Object> getter(
+ Handle<AccessorPair>::cast(callback_object)->getter(),
+ isolate());
+ if (!getter->IsJSFunction()) break;
+ if (holder->IsGlobalObject()) break;
+ if (!holder->HasFastProperties()) break;
+ Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+ CallOptimization call_optimization(function);
+ if (call_optimization.is_simple_api_call() &&
+ call_optimization.IsCompatibleReceiver(*receiver)) {
+ return isolate()->stub_cache()->ComputeKeyedLoadCallback(
+ name, receiver, holder, call_optimization);
+ }
+ }
+ break;
}
case INTERCEPTOR:
ASSERT(HasInterceptorGetter(lookup->holder()));
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Tue Aug 27 11:47:52 2013 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc Thu Sep 5 08:34:17 2013 UTC
@@ -313,6 +313,24 @@
JSObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
+
+
+Handle<Code> StubCache::ComputeLoadCallback(
+ Handle<Name> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ const CallOptimization& call_optimization) {
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindLoadHandler(
+ name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
+
+ LoadStubCompiler compiler(isolate_);
+ Handle<Code> handler =
+ compiler.CompileLoadCallback(receiver, holder, name,
call_optimization);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
+}
Handle<Code> StubCache::ComputeLoadViaGetter(Handle<Name> name,
@@ -464,6 +482,24 @@
return handler;
}
+
+Handle<Code> StubCache::ComputeKeyedLoadCallback(
+ Handle<Name> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ const CallOptimization& call_optimization) {
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindLoadHandler(
+ name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> handler =
+ compiler.CompileLoadCallback(receiver, holder, name,
call_optimization);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
+}
+
Handle<Code> StubCache::ComputeStoreField(Handle<Name> name,
Handle<JSObject> receiver,
@@ -1646,6 +1682,25 @@
// Return the generated code.
return GetCode(kind(), Code::CALLBACKS, name);
}
+
+
+Handle<Code> BaseLoadStubCompiler::CompileLoadCallback(
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization& call_optimization) {
+ ASSERT(call_optimization.is_simple_api_call());
+ Label success;
+
+ Handle<JSFunction> callback = call_optimization.constant_function();
+ CallbackHandlerFrontend(
+ object, receiver(), holder, name, &success, callback);
+ __ bind(&success);
+ GenerateLoadCallback(call_optimization);
+
+ // Return the generated code.
+ return GetCode(kind(), Code::CALLBACKS, name);
+}
Handle<Code> BaseLoadStubCompiler::CompileLoadInterceptor(
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Mon Aug 19 22:12:46 2013 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Thu Sep 5 08:34:17 2013 UTC
@@ -48,6 +48,8 @@
// invalidate the cache whenever a prototype map is changed. The stub
// validates the map chain as in the mono-morphic case.
+
+class CallOptimization;
class SmallMapList;
class StubCache;
@@ -136,6 +138,11 @@
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo>
callback);
+ Handle<Code> ComputeLoadCallback(Handle<Name> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ const CallOptimization&
call_optimization);
+
Handle<Code> ComputeLoadViaGetter(Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
@@ -173,6 +180,12 @@
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback);
+ Handle<Code> ComputeKeyedLoadCallback(
+ Handle<Name> name,
+ Handle<JSObject> object,
+ Handle<JSObject> holder,
+ const CallOptimization& call_optimization);
+
Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
@@ -705,6 +718,11 @@
Handle<Name> name,
Handle<ExecutableAccessorInfo>
callback);
+ Handle<Code> CompileLoadCallback(Handle<JSObject> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ const CallOptimization&
call_optimization);
+
Handle<Code> CompileLoadConstant(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
@@ -730,7 +748,7 @@
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
- Handle<ExecutableAccessorInfo>
callback);
+ Handle<Object> callback);
void NonexistentHandlerFrontend(Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
@@ -744,6 +762,7 @@
void GenerateLoadConstant(Handle<Object> value);
void GenerateLoadCallback(Register reg,
Handle<ExecutableAccessorInfo> callback);
+ void GenerateLoadCallback(const CallOptimization& call_optimization);
void GenerateLoadInterceptor(Register holder_reg,
Handle<JSObject> object,
Handle<JSObject> holder,
@@ -1028,8 +1047,6 @@
V(ArrayCode)
-class CallOptimization;
-
class CallStubCompiler: public StubCompiler {
public:
CallStubCompiler(Isolate* isolate,
@@ -1161,6 +1178,12 @@
int GetPrototypeDepthOfExpectedType(Handle<JSObject> object,
Handle<JSObject> holder) const;
+ bool IsCompatibleReceiver(Object* receiver) {
+ ASSERT(is_simple_api_call());
+ if (expected_receiver_type_.is_null()) return true;
+ return receiver->IsInstanceOf(*expected_receiver_type_);
+ }
+
private:
void Initialize(Handle<JSFunction> function);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Aug 27 13:41:44
2013 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Sep 5 08:34:17
2013 UTC
@@ -1191,7 +1191,7 @@
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
- Handle<ExecutableAccessorInfo> callback) {
+ Handle<Object> callback) {
Label miss;
Register reg = HandlerFrontendHeader(object, object_reg, holder, name,
&miss);
@@ -1273,6 +1273,29 @@
GenerateTailCall(masm(), stub.GetCode(isolate()));
}
}
+
+
+void BaseLoadStubCompiler::GenerateLoadCallback(
+ const CallOptimization& call_optimization) {
+ ASSERT(call_optimization.is_simple_api_call());
+
+ // Copy return value.
+ __ movq(scratch3(), StackSpaceOperand(0));
+ // Assign stack space for the call arguments.
+ __ subq(rsp, Immediate((kFastApiCallArguments + 1) * kPointerSize));
+ // Move the return address on top of the stack.
+ __ movq(StackOperandForReturnAddress(0), scratch3());
+
+ int argc = 0;
+ int api_call_argc = argc + kFastApiCallArguments;
+ StackArgumentsAccessor args(rsp, api_call_argc);
+ // Write holder to stack frame.
+ __ movq(args.GetArgumentOperand(api_call_argc), receiver());
+ // Write receiver to stack frame.
+ __ movq(args.GetArgumentOperand(api_call_argc - (argc + 6)), receiver());
+
+ GenerateFastApiCall(masm(), call_optimization, argc);
+}
void BaseLoadStubCompiler::GenerateLoadCallback(
=======================================
--- /branches/bleeding_edge/test/cctest/test-accessors.cc Wed Sep 4
07:45:36 2013 UTC
+++ /branches/bleeding_edge/test/cctest/test-accessors.cc Thu Sep 5
08:34:17 2013 UTC
@@ -163,6 +163,7 @@
static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ CHECK_EQ(x_receiver, info.Holder());
XGetter(info, 1);
}
@@ -172,6 +173,7 @@
v8::Isolate* isolate = v8::Isolate::GetCurrent();
CHECK_EQ(isolate, info.GetIsolate());
CHECK_EQ(x_holder, info.This());
+ CHECK_EQ(x_holder, info.Holder());
x_register[offset] = value->Int32Value();
}
@@ -179,7 +181,6 @@
static void XSetter(Local<String> name,
Local<Value> value,
const v8::PropertyCallbackInfo<void>& info) {
- CHECK_EQ(x_holder, info.Holder());
XSetter(value, info, 0);
}
@@ -205,17 +206,23 @@
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
"obj.__proto__ = holder;"
"var result = [];"
+ "var key_0 = 'x0';"
+ "var key_1 = 'x1';"
"for (var i = 0; i < 10; i++) {"
" holder.x0 = i;"
+ " result.push(obj.x0);"
" holder.x1 = i;"
- " result.push(obj.x0);"
" result.push(obj.x1);"
+ " holder[key_0] = i;"
+ " result.push(obj[key_0]);"
+ " holder[key_1] = i;"
+ " result.push(obj[key_1]);"
"}"
"result"));
- CHECK_EQ(20, array->Length());
- for (int i = 0; i < 20; i++) {
+ CHECK_EQ(40, array->Length());
+ for (int i = 0; i < 40; i++) {
v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
- CHECK_EQ(v8::Integer::New(i/2), entry);
+ CHECK_EQ(v8::Integer::New(i/4), entry);
}
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed Sep 4 07:05:11
2013 UTC
+++ /branches/bleeding_edge/test/cctest/test-api.cc Thu Sep 5 08:34:17
2013 UTC
@@ -141,10 +141,13 @@
static int signature_callback_count;
+static Local<Value> signature_expected_receiver;
static void IncrementingSignatureCallback(
const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
signature_callback_count++;
+ CHECK_EQ(signature_expected_receiver, args.Holder());
+ CHECK_EQ(signature_expected_receiver, args.This());
v8::Handle<v8::Array> result = v8::Array::New(args.Length());
for (int i = 0; i < args.Length(); i++)
result->Set(v8::Integer::New(i), args[i]);
@@ -213,26 +216,50 @@
v8::FunctionTemplate::New(IncrementingSignatureCallback,
v8::Handle<Value>(),
sig));
+ fun->PrototypeTemplate()->SetAccessorProperty(
+ v8_str("n"),
+ v8::FunctionTemplate::New(IncrementingSignatureCallback,
+ v8::Handle<Value>(),
+ sig));
env->Global()->Set(v8_str("Fun"), fun->GetFunction());
+ Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
+ env->Global()->Set(v8_str("fun_instance"), fun_instance);
signature_callback_count = 0;
+ int expected_count = 0;
+ signature_expected_receiver = fun_instance;
CompileRun(
- "var o = new Fun();"
- "o.m();");
- CHECK_EQ(1, signature_callback_count);
+ "var o = fun_instance;"
+ "var key_n = 'n';"
+ "for (var i = 0; i < 10; i++) o.m();"
+ "for (var i = 0; i < 10; i++) o.n;"
+ "for (var i = 0; i < 10; i++) o[key_n];");
+ expected_count += 30;
+ CHECK_EQ(expected_count, signature_callback_count);
v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
sub_fun->Inherit(fun);
- env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
+ fun_instance = sub_fun->InstanceTemplate()->NewInstance();
+ env->Global()->Set(v8_str("fun_instance"), fun_instance);
+ signature_expected_receiver = fun_instance;
CompileRun(
- "var o = new SubFun();"
- "o.m();");
- CHECK_EQ(2, signature_callback_count);
-
+ "var o = fun_instance;"
+ "var key_n = 'n';"
+ "for (var i = 0; i < 10; i++) o.m();"
+ "for (var i = 0; i < 10; i++) o.n;"
+ "for (var i = 0; i < 10; i++) o[key_n];");
+ expected_count += 30;
+ CHECK_EQ(expected_count, signature_callback_count);
v8::TryCatch try_catch;
CompileRun(
"var o = { };"
"o.m = Fun.prototype.m;"
"o.m();");
- CHECK_EQ(2, signature_callback_count);
+ CHECK_EQ(expected_count, signature_callback_count);
+ CHECK(try_catch.HasCaught());
+ CompileRun(
+ "var o = { };"
+ "o.n = Fun.prototype.n;"
+ "o.n;");
+ CHECK_EQ(expected_count, signature_callback_count);
CHECK(try_catch.HasCaught());
try_catch.Reset();
v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
@@ -242,7 +269,14 @@
"var o = new UnrelFun();"
"o.m = Fun.prototype.m;"
"o.m();");
- CHECK_EQ(2, signature_callback_count);
+ CHECK_EQ(expected_count, signature_callback_count);
+ CHECK(try_catch.HasCaught());
+ try_catch.Reset();
+ CompileRun(
+ "var o = new UnrelFun();"
+ "o.n = Fun.prototype.n;"
+ "o.n;");
+ CHECK_EQ(expected_count, signature_callback_count);
CHECK(try_catch.HasCaught());
}
--
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.