Commit 3e76ba9a authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Propagate information on whether a non function was called as constructor or...

Propagate information on whether a non function was called as constructor or not.The Arguments object passed to the callback now has IsConstructCall set accordingly.BUG=http://crbug.com/3285
Review URL: http://codereview.chromium.org/113634

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2020 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f76cb020
......@@ -187,7 +187,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing r0).
__ mov(r2, Operand(0));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
}
......
......@@ -820,14 +820,28 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
global_context()->set_context_extension_function(*context_extension_fun);
}
// Setup the call-as-function delegate.
Handle<Code> code =
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
Handle<JSFunction> delegate =
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
global_context()->set_call_as_function_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
{
// Setup the call-as-function delegate.
Handle<Code> code =
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
Handle<JSFunction> delegate =
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
global_context()->set_call_as_function_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
}
{
// Setup the call-as-constructor delegate.
Handle<Code> code =
Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsConstructor));
Handle<JSFunction> delegate =
Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
global_context()->set_call_as_constructor_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
}
global_context()->set_special_function_table(Heap::empty_fixed_array());
......
......@@ -394,12 +394,18 @@ BUILTIN(HandleApiCall) {
BUILTIN_END
// Handle calls to non-function objects created through the API that
// support calls.
BUILTIN(HandleApiCallAsFunction) {
// Non-functions are never called as constructors.
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
int __argc__,
Object** __argv__) {
// Non-functions are never called as constructors. Even if this is an object
// called as a constructor the delegate call is not a construct call.
ASSERT(!CalledAsConstructor());
Handle<Object> receiver(&__argv__[0]);
// Get the object called.
JSObject* obj = JSObject::cast(*receiver);
......@@ -431,7 +437,7 @@ BUILTIN(HandleApiCallAsFunction) {
data,
self,
callee,
false,
is_construct_call,
reinterpret_cast<void**>(__argv__ - 1),
__argc__ - 1);
v8::Handle<v8::Value> value;
......@@ -450,6 +456,21 @@ BUILTIN(HandleApiCallAsFunction) {
RETURN_IF_SCHEDULED_EXCEPTION();
return result;
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction) {
return HandleApiCallAsFunctionOrConstructor(false, __argc__, __argv__);
}
BUILTIN_END
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor) {
return HandleApiCallAsFunctionOrConstructor(true, __argc__, __argv__);
}
BUILTIN_END
......
......@@ -42,7 +42,8 @@ namespace v8 { namespace internal {
V(ArrayPop) \
\
V(HandleApiCall) \
V(HandleApiCallAsFunction)
V(HandleApiCallAsFunction) \
V(HandleApiCallAsConstructor)
// Define list of builtins implemented in assembly.
......@@ -99,35 +100,36 @@ namespace v8 { namespace internal {
#endif
// Define list of builtins implemented in JavaScript.
#define BUILTINS_LIST_JS(V) \
V(EQUALS, 1) \
V(STRICT_EQUALS, 1) \
V(COMPARE, 2) \
V(ADD, 1) \
V(SUB, 1) \
V(MUL, 1) \
V(DIV, 1) \
V(MOD, 1) \
V(BIT_OR, 1) \
V(BIT_AND, 1) \
V(BIT_XOR, 1) \
V(UNARY_MINUS, 0) \
V(BIT_NOT, 0) \
V(SHL, 1) \
V(SAR, 1) \
V(SHR, 1) \
V(DELETE, 1) \
V(IN, 1) \
V(INSTANCE_OF, 1) \
V(GET_KEYS, 0) \
V(FILTER_KEY, 1) \
V(CALL_NON_FUNCTION, 0) \
V(TO_OBJECT, 0) \
V(TO_NUMBER, 0) \
V(TO_STRING, 0) \
V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \
#define BUILTINS_LIST_JS(V) \
V(EQUALS, 1) \
V(STRICT_EQUALS, 1) \
V(COMPARE, 2) \
V(ADD, 1) \
V(SUB, 1) \
V(MUL, 1) \
V(DIV, 1) \
V(MOD, 1) \
V(BIT_OR, 1) \
V(BIT_AND, 1) \
V(BIT_XOR, 1) \
V(UNARY_MINUS, 0) \
V(BIT_NOT, 0) \
V(SHL, 1) \
V(SAR, 1) \
V(SHR, 1) \
V(DELETE, 1) \
V(IN, 1) \
V(INSTANCE_OF, 1) \
V(GET_KEYS, 0) \
V(FILTER_KEY, 1) \
V(CALL_NON_FUNCTION, 0) \
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
V(TO_OBJECT, 0) \
V(TO_NUMBER, 0) \
V(TO_STRING, 0) \
V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)
......
......@@ -90,6 +90,8 @@ enum ContextLookupFlags {
V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \
V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \
call_as_constructor_delegate) \
V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
......@@ -209,6 +211,7 @@ class Context: public FixedArray {
FUNCTION_CACHE_INDEX,
RUNTIME_CONTEXT_INDEX,
CALL_AS_FUNCTION_DELEGATE_INDEX,
CALL_AS_CONSTRUCTOR_DELEGATE_INDEX,
EMPTY_SCRIPT_INDEX,
SCRIPT_FUNCTION_INDEX,
CONTEXT_EXTENSION_FUNCTION_INDEX,
......
......@@ -188,6 +188,24 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
}
Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
ASSERT(!object->IsJSFunction());
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
if (object->IsHeapObject() &&
HeapObject::cast(*object)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
Top::global_context()->call_as_constructor_delegate());
}
return Factory::undefined_value();
}
// Static state for stack guards.
StackGuard::ThreadLocal StackGuard::thread_local_;
......
......@@ -129,6 +129,10 @@ class Execution : public AllStatic {
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as functions.
static Handle<Object> GetFunctionDelegate(Handle<Object> object);
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as constructors.
static Handle<Object> GetConstructorDelegate(Handle<Object> object);
};
......
......@@ -311,7 +311,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing eax).
__ Set(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
}
......
......@@ -4358,6 +4358,14 @@ static Object* Runtime_GetFunctionDelegate(Arguments args) {
}
static Object* Runtime_GetConstructorDelegate(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 1);
RUNTIME_ASSERT(!args[0]->IsJSFunction());
return *Execution::GetConstructorDelegate(args.at<Object>(0));
}
static Object* Runtime_NewContext(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
......
......@@ -63,6 +63,7 @@ namespace v8 { namespace internal {
/* Utilities */ \
F(GetCalledFunction, 0) \
F(GetFunctionDelegate, 1) \
F(GetConstructorDelegate, 1) \
F(NewArguments, 1) \
F(NewArgumentsFast, 3) \
F(LazyCompile, 1) \
......
......@@ -327,6 +327,18 @@ function CALL_NON_FUNCTION() {
}
function CALL_NON_FUNCTION_AS_CONSTRUCTOR() {
var callee = %GetCalledFunction();
var delegate = %GetConstructorDelegate(callee);
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof callee]);
}
var parameters = %NewArguments(delegate);
return delegate.apply(callee, parameters);
}
function APPLY_PREPARE(args) {
var length;
// First check whether length is a positive Smi and args is an array. This is the
......
......@@ -4644,6 +4644,12 @@ THREADED_TEST(CrossLazyLoad) {
static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
if (args.IsConstructCall()) {
if (args[0]->IsInt32()) {
return v8_num(-args[0]->Int32Value());
}
}
return args[0];
}
......@@ -4697,9 +4703,9 @@ THREADED_TEST(CallAsFunction) {
// Check that the call-as-function handler can be called through
// new. Currently, there is no way to check in the call-as-function
// handler if it has been called through new or not.
value = CompileRun("new obj(42)");
value = CompileRun("new obj(43)");
CHECK(!try_catch.HasCaught());
CHECK_EQ(42, value->Int32Value());
CHECK_EQ(-43, value->Int32Value());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment