1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/api-arguments-inl.h" 6 #include "src/api-natives.h" 7 #include "src/builtins/builtins-utils-inl.h" 8 #include "src/builtins/builtins.h" 9 #include "src/counters.h" 10 #include "src/log.h" 11 #include "src/objects-inl.h" 12 #include "src/objects/templates.h" 13 #include "src/prototype.h" 14 #include "src/visitors.h" 15 16 namespace v8 { 17 namespace internal { 18 19 namespace { 20 21 // Returns the holder JSObject if the function can legally be called with this 22 // receiver. Returns nullptr if the call is illegal. 23 // TODO(dcarney): CallOptimization duplicates this logic, merge. 24 JSReceiver* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, 25 JSReceiver* receiver) { 26 Object* recv_type = info->signature(); 27 // No signature, return holder. 28 if (!recv_type->IsFunctionTemplateInfo()) return receiver; 29 // A Proxy cannot have been created from the signature template. 30 if (!receiver->IsJSObject()) return nullptr; 31 32 JSObject* js_obj_receiver = JSObject::cast(receiver); 33 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); 34 35 // Check the receiver. Fast path for receivers with no hidden prototypes. 36 if (signature->IsTemplateFor(js_obj_receiver)) return receiver; 37 if (!js_obj_receiver->map()->has_hidden_prototype()) return nullptr; 38 for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype, 39 PrototypeIterator::END_AT_NON_HIDDEN); 40 !iter.IsAtEnd(); iter.Advance()) { 41 JSObject* current = iter.GetCurrent<JSObject>(); 42 if (signature->IsTemplateFor(current)) return current; 43 } 44 return nullptr; 45 } 46 47 template <bool is_construct> 48 V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper( 49 Isolate* isolate, Handle<HeapObject> function, 50 Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data, 51 Handle<Object> receiver, BuiltinArguments args) { 52 Handle<JSReceiver> js_receiver; 53 JSReceiver* raw_holder; 54 if (is_construct) { 55 DCHECK(args.receiver()->IsTheHole(isolate)); 56 if (fun_data->instance_template()->IsUndefined(isolate)) { 57 v8::Local<ObjectTemplate> templ = 58 ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate), 59 ToApiHandle<v8::FunctionTemplate>(fun_data)); 60 fun_data->set_instance_template(*Utils::OpenHandle(*templ)); 61 } 62 Handle<ObjectTemplateInfo> instance_template( 63 ObjectTemplateInfo::cast(fun_data->instance_template()), isolate); 64 ASSIGN_RETURN_ON_EXCEPTION( 65 isolate, js_receiver, 66 ApiNatives::InstantiateObject(isolate, instance_template, 67 Handle<JSReceiver>::cast(new_target)), 68 Object); 69 args[0] = *js_receiver; 70 DCHECK_EQ(*js_receiver, *args.receiver()); 71 72 raw_holder = *js_receiver; 73 } else { 74 DCHECK(receiver->IsJSReceiver()); 75 js_receiver = Handle<JSReceiver>::cast(receiver); 76 77 if (!fun_data->accept_any_receiver() && 78 js_receiver->IsAccessCheckNeeded()) { 79 // Proxies never need access checks. 80 DCHECK(js_receiver->IsJSObject()); 81 Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver); 82 if (!isolate->MayAccess(handle(isolate->context(), isolate), 83 js_obj_receiver)) { 84 isolate->ReportFailedAccessCheck(js_obj_receiver); 85 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 86 return isolate->factory()->undefined_value(); 87 } 88 } 89 90 raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver); 91 92 if (raw_holder == nullptr) { 93 // This function cannot be called with the given receiver. Abort! 94 THROW_NEW_ERROR( 95 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); 96 } 97 } 98 99 Object* raw_call_data = fun_data->call_code(); 100 if (!raw_call_data->IsUndefined(isolate)) { 101 DCHECK(raw_call_data->IsCallHandlerInfo()); 102 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); 103 Object* data_obj = call_data->data(); 104 105 106 FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder, 107 *new_target, &args[0] - 1, 108 args.length() - 1); 109 Handle<Object> result = custom.Call(call_data); 110 111 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 112 if (result.is_null()) { 113 if (is_construct) return js_receiver; 114 return isolate->factory()->undefined_value(); 115 } 116 // Rebox the result. 117 result->VerifyApiCallResultType(); 118 if (!is_construct || result->IsJSReceiver()) 119 return handle(*result, isolate); 120 } 121 122 return js_receiver; 123 } 124 125 } // anonymous namespace 126 127 BUILTIN(HandleApiCall) { 128 HandleScope scope(isolate); 129 Handle<JSFunction> function = args.target(); 130 Handle<Object> receiver = args.receiver(); 131 Handle<HeapObject> new_target = args.new_target(); 132 Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(), 133 isolate); 134 if (new_target->IsJSReceiver()) { 135 RETURN_RESULT_OR_FAILURE( 136 isolate, HandleApiCallHelper<true>(isolate, function, new_target, 137 fun_data, receiver, args)); 138 } else { 139 RETURN_RESULT_OR_FAILURE( 140 isolate, HandleApiCallHelper<false>(isolate, function, new_target, 141 fun_data, receiver, args)); 142 } 143 } 144 145 namespace { 146 147 class RelocatableArguments : public BuiltinArguments, public Relocatable { 148 public: 149 RelocatableArguments(Isolate* isolate, int length, Object** arguments) 150 : BuiltinArguments(length, arguments), Relocatable(isolate) {} 151 152 virtual inline void IterateInstance(RootVisitor* v) { 153 if (length() == 0) return; 154 v->VisitRootPointers(Root::kRelocatable, nullptr, lowest_address(), 155 highest_address() + 1); 156 } 157 158 private: 159 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments); 160 }; 161 162 } // namespace 163 164 MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate, 165 bool is_construct, 166 Handle<HeapObject> function, 167 Handle<Object> receiver, 168 int argc, Handle<Object> args[], 169 Handle<HeapObject> new_target) { 170 DCHECK(function->IsFunctionTemplateInfo() || 171 (function->IsJSFunction() && 172 JSFunction::cast(*function)->shared()->IsApiFunction())); 173 174 // Do proper receiver conversion for non-strict mode api functions. 175 if (!is_construct && !receiver->IsJSReceiver()) { 176 if (function->IsFunctionTemplateInfo() || 177 is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) { 178 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 179 Object::ConvertReceiver(isolate, receiver), 180 Object); 181 } 182 } 183 184 if (function->IsFunctionTemplateInfo()) { 185 Handle<FunctionTemplateInfo> info = 186 Handle<FunctionTemplateInfo>::cast(function); 187 // If we need to break at function entry, go the long way. Instantiate the 188 // function, use the DebugBreakTrampoline, and call it through JS. 189 if (info->BreakAtEntry()) { 190 DCHECK(!is_construct); 191 DCHECK(new_target->IsUndefined(isolate)); 192 Handle<JSFunction> function; 193 ASSIGN_RETURN_ON_EXCEPTION(isolate, function, 194 ApiNatives::InstantiateFunction( 195 info, MaybeHandle<v8::internal::Name>()), 196 Object); 197 Handle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline); 198 function->set_code(*trampoline); 199 return Execution::Call(isolate, function, receiver, argc, args); 200 } 201 } 202 203 Handle<FunctionTemplateInfo> fun_data = 204 function->IsFunctionTemplateInfo() 205 ? Handle<FunctionTemplateInfo>::cast(function) 206 : handle(JSFunction::cast(*function)->shared()->get_api_func_data(), 207 isolate); 208 // Construct BuiltinArguments object: 209 // new target, function, arguments reversed, receiver. 210 const int kBufferSize = 32; 211 Object* small_argv[kBufferSize]; 212 Object** argv; 213 const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver; 214 if (frame_argc <= kBufferSize) { 215 argv = small_argv; 216 } else { 217 argv = new Object*[frame_argc]; 218 } 219 int cursor = frame_argc - 1; 220 argv[cursor--] = *receiver; 221 for (int i = 0; i < argc; ++i) { 222 argv[cursor--] = *args[i]; 223 } 224 DCHECK_EQ(cursor, BuiltinArguments::kPaddingOffset); 225 argv[BuiltinArguments::kPaddingOffset] = 226 ReadOnlyRoots(isolate).the_hole_value(); 227 argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc); 228 argv[BuiltinArguments::kTargetOffset] = *function; 229 argv[BuiltinArguments::kNewTargetOffset] = *new_target; 230 MaybeHandle<Object> result; 231 { 232 RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]); 233 if (is_construct) { 234 result = HandleApiCallHelper<true>(isolate, function, new_target, 235 fun_data, receiver, arguments); 236 } else { 237 result = HandleApiCallHelper<false>(isolate, function, new_target, 238 fun_data, receiver, arguments); 239 } 240 } 241 if (argv != small_argv) delete[] argv; 242 return result; 243 } 244 245 // Helper function to handle calls to non-function objects created through the 246 // API. The object can be called as either a constructor (using new) or just as 247 // a function (without new). 248 V8_WARN_UNUSED_RESULT static Object* HandleApiCallAsFunctionOrConstructor( 249 Isolate* isolate, bool is_construct_call, BuiltinArguments args) { 250 Handle<Object> receiver = args.receiver(); 251 252 // Get the object called. 253 JSObject* obj = JSObject::cast(*receiver); 254 255 // Set the new target. 256 HeapObject* new_target; 257 if (is_construct_call) { 258 // TODO(adamk): This should be passed through in args instead of 259 // being patched in here. We need to set a non-undefined value 260 // for v8::FunctionCallbackInfo::IsConstructCall() to get the 261 // right answer. 262 new_target = obj; 263 } else { 264 new_target = ReadOnlyRoots(isolate).undefined_value(); 265 } 266 267 // Get the invocation callback from the function descriptor that was 268 // used to create the called object. 269 DCHECK(obj->map()->is_callable()); 270 JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor()); 271 // TODO(ishell): turn this back to a DCHECK. 272 CHECK(constructor->shared()->IsApiFunction()); 273 Object* handler = 274 constructor->shared()->get_api_func_data()->instance_call_handler(); 275 DCHECK(!handler->IsUndefined(isolate)); 276 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler); 277 278 // Get the data for the call and perform the callback. 279 Object* result; 280 { 281 HandleScope scope(isolate); 282 LOG(isolate, ApiObjectAccess("call non-function", obj)); 283 FunctionCallbackArguments custom(isolate, call_data->data(), constructor, 284 obj, new_target, &args[0] - 1, 285 args.length() - 1); 286 Handle<Object> result_handle = custom.Call(call_data); 287 if (result_handle.is_null()) { 288 result = ReadOnlyRoots(isolate).undefined_value(); 289 } else { 290 result = *result_handle; 291 } 292 } 293 // Check for exceptions and return result. 294 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 295 return result; 296 } 297 298 // Handle calls to non-function objects created through the API. This delegate 299 // function is used when the call is a normal function call. 300 BUILTIN(HandleApiCallAsFunction) { 301 return HandleApiCallAsFunctionOrConstructor(isolate, false, args); 302 } 303 304 // Handle calls to non-function objects created through the API. This delegate 305 // function is used when the call is a construct call. 306 BUILTIN(HandleApiCallAsConstructor) { 307 return HandleApiCallAsFunctionOrConstructor(isolate, true, args); 308 } 309 310 } // namespace internal 311 } // namespace v8 312