// 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);
}
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());
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);
data,
self,
callee,
- false,
+ is_construct_call,
reinterpret_cast<void**>(__argv__ - 1),
__argc__ - 1);
v8::Handle<v8::Value> value;
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
V(ArrayPop) \
\
V(HandleApiCall) \
- V(HandleApiCallAsFunction)
+ V(HandleApiCallAsFunction) \
+ V(HandleApiCallAsConstructor)
// Define list of builtins implemented in assembly.
#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)
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) \
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,
}
+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_;
// 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);
};
// 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);
}
}
+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);
/* Utilities */ \
F(GetCalledFunction, 0) \
F(GetFunctionDelegate, 1) \
+ F(GetConstructorDelegate, 1) \
F(NewArguments, 1) \
F(NewArgumentsFast, 3) \
F(LazyCompile, 1) \
}
+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
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];
}
// 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());
}