1 // Copyright 2014 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/runtime/runtime-utils.h"
6 
7 #include "src/arguments.h"
8 #include "src/deoptimizer.h"
9 #include "src/frames-inl.h"
10 #include "src/full-codegen/full-codegen.h"
11 #include "src/snapshot/natives.h"
12 
13 namespace v8 {
14 namespace internal {
15 
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction)16 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
17   HandleScope scope(isolate);
18   DCHECK(args.length() == 1);
19   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
20   if (!function->IsOptimized()) return isolate->heap()->undefined_value();
21 
22   // TODO(turbofan): Deoptimization is not supported yet.
23   if (function->code()->is_turbofanned() &&
24       function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
25     return isolate->heap()->undefined_value();
26   }
27 
28   Deoptimizer::DeoptimizeFunction(*function);
29 
30   return isolate->heap()->undefined_value();
31 }
32 
33 
RUNTIME_FUNCTION(Runtime_DeoptimizeNow)34 RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
35   HandleScope scope(isolate);
36   DCHECK(args.length() == 0);
37 
38   Handle<JSFunction> function;
39 
40   // If the argument is 'undefined', deoptimize the topmost
41   // function.
42   JavaScriptFrameIterator it(isolate);
43   while (!it.done()) {
44     if (it.frame()->is_java_script()) {
45       function = Handle<JSFunction>(it.frame()->function());
46       break;
47     }
48   }
49   if (function.is_null()) return isolate->heap()->undefined_value();
50 
51   if (!function->IsOptimized()) return isolate->heap()->undefined_value();
52 
53   // TODO(turbofan): Deoptimization is not supported yet.
54   if (function->code()->is_turbofanned() &&
55       function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
56     return isolate->heap()->undefined_value();
57   }
58 
59   Deoptimizer::DeoptimizeFunction(*function);
60 
61   return isolate->heap()->undefined_value();
62 }
63 
64 
RUNTIME_FUNCTION(Runtime_RunningInSimulator)65 RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
66   SealHandleScope shs(isolate);
67   DCHECK(args.length() == 0);
68 #if defined(USE_SIMULATOR)
69   return isolate->heap()->true_value();
70 #else
71   return isolate->heap()->false_value();
72 #endif
73 }
74 
75 
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported)76 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
77   SealHandleScope shs(isolate);
78   DCHECK(args.length() == 0);
79   return isolate->heap()->ToBoolean(
80       isolate->concurrent_recompilation_enabled());
81 }
82 
83 
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall)84 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
85   HandleScope scope(isolate);
86   RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
87   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
88   // The following assertion was lifted from the DCHECK inside
89   // JSFunction::MarkForOptimization().
90   RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
91                  (function->code()->kind() == Code::FUNCTION &&
92                   !function->shared()->optimization_disabled()));
93 
94   // If the function is already optimized, just return.
95   if (function->IsOptimized()) return isolate->heap()->undefined_value();
96 
97   function->MarkForOptimization();
98 
99   Code* unoptimized = function->shared()->code();
100   if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) {
101     CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
102     if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
103         isolate->concurrent_recompilation_enabled()) {
104       function->AttemptConcurrentOptimization();
105     }
106   }
107 
108   return isolate->heap()->undefined_value();
109 }
110 
111 
RUNTIME_FUNCTION(Runtime_OptimizeOsr)112 RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
113   HandleScope scope(isolate);
114   RUNTIME_ASSERT(args.length() == 0 || args.length() == 1);
115   Handle<JSFunction> function = Handle<JSFunction>::null();
116 
117   if (args.length() == 0) {
118     // Find the JavaScript function on the top of the stack.
119     JavaScriptFrameIterator it(isolate);
120     while (!it.done()) {
121       if (it.frame()->is_java_script()) {
122         function = Handle<JSFunction>(it.frame()->function());
123         break;
124       }
125     }
126     if (function.is_null()) return isolate->heap()->undefined_value();
127   } else {
128     // Function was passed as an argument.
129     CONVERT_ARG_HANDLE_CHECKED(JSFunction, arg, 0);
130     function = arg;
131   }
132 
133   // The following assertion was lifted from the DCHECK inside
134   // JSFunction::MarkForOptimization().
135   RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
136                  !function->shared()->optimization_disabled());
137 
138   // If the function is already optimized, just return.
139   if (function->IsOptimized()) return isolate->heap()->undefined_value();
140 
141   Code* unoptimized = function->shared()->code();
142   if (unoptimized->kind() == Code::FUNCTION) {
143     DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
144     isolate->runtime_profiler()->AttemptOnStackReplacement(
145         *function, Code::kMaxLoopNestingMarker);
146   }
147 
148   return isolate->heap()->undefined_value();
149 }
150 
151 
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction)152 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
153   HandleScope scope(isolate);
154   DCHECK(args.length() == 1);
155   CONVERT_ARG_CHECKED(JSFunction, function, 0);
156   function->shared()->set_disable_optimization_reason(kOptimizationDisabled);
157   function->shared()->set_optimization_disabled(true);
158   return isolate->heap()->undefined_value();
159 }
160 
161 
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus)162 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
163   HandleScope scope(isolate);
164   RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
165   if (!isolate->use_crankshaft()) {
166     return Smi::FromInt(4);  // 4 == "never".
167   }
168   bool sync_with_compiler_thread = true;
169   if (args.length() == 2) {
170     CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
171     if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
172       sync_with_compiler_thread = false;
173     }
174   }
175   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
176   if (isolate->concurrent_recompilation_enabled() &&
177       sync_with_compiler_thread) {
178     while (function->IsInOptimizationQueue()) {
179       isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
180       base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
181     }
182   }
183   if (FLAG_always_opt || FLAG_prepare_always_opt) {
184     // With --always-opt, optimization status expectations might not
185     // match up, so just return a sentinel.
186     return Smi::FromInt(3);  // 3 == "always".
187   }
188   if (FLAG_deopt_every_n_times) {
189     return Smi::FromInt(6);  // 6 == "maybe deopted".
190   }
191   if (function->IsOptimized() && function->code()->is_turbofanned()) {
192     return Smi::FromInt(7);  // 7 == "TurboFan compiler".
193   }
194   return function->IsOptimized() ? Smi::FromInt(1)   // 1 == "yes".
195                                  : Smi::FromInt(2);  // 2 == "no".
196 }
197 
198 
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation)199 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
200   DCHECK(args.length() == 0);
201   RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
202   RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
203   isolate->optimizing_compile_dispatcher()->Unblock();
204   return isolate->heap()->undefined_value();
205 }
206 
207 
RUNTIME_FUNCTION(Runtime_GetOptimizationCount)208 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
209   HandleScope scope(isolate);
210   DCHECK(args.length() == 1);
211   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
212   return Smi::FromInt(function->shared()->opt_count());
213 }
214 
215 
RUNTIME_FUNCTION(Runtime_GetUndetectable)216 RUNTIME_FUNCTION(Runtime_GetUndetectable) {
217   HandleScope scope(isolate);
218   DCHECK(args.length() == 0);
219   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
220 
221   Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
222   desc->MarkAsUndetectable();
223   Local<v8::Object> obj;
224   if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) {
225     return nullptr;
226   }
227   return *Utils::OpenHandle(*obj);
228 }
229 
230 
RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback)231 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
232   HandleScope scope(isolate);
233   DCHECK(args.length() == 1);
234   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
235   function->shared()->ClearTypeFeedbackInfo();
236   Code* unoptimized = function->shared()->code();
237   if (unoptimized->kind() == Code::FUNCTION) {
238     unoptimized->ClearInlineCaches();
239   }
240   return isolate->heap()->undefined_value();
241 }
242 
243 
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed)244 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
245   HandleScope scope(isolate);
246   DCHECK(args.length() == 0);
247   isolate->heap()->NotifyContextDisposed(true);
248   return isolate->heap()->undefined_value();
249 }
250 
251 
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout)252 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
253   SealHandleScope shs(isolate);
254   DCHECK(args.length() == 2 || args.length() == 3);
255 #ifdef DEBUG
256   CONVERT_SMI_ARG_CHECKED(interval, 0);
257   CONVERT_SMI_ARG_CHECKED(timeout, 1);
258   isolate->heap()->set_allocation_timeout(timeout);
259   FLAG_gc_interval = interval;
260   if (args.length() == 3) {
261     // Enable/disable inline allocation if requested.
262     CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
263     if (inline_allocation) {
264       isolate->heap()->EnableInlineAllocation();
265     } else {
266       isolate->heap()->DisableInlineAllocation();
267     }
268   }
269 #endif
270   return isolate->heap()->undefined_value();
271 }
272 
273 
RUNTIME_FUNCTION(Runtime_DebugPrint)274 RUNTIME_FUNCTION(Runtime_DebugPrint) {
275   SealHandleScope shs(isolate);
276   DCHECK(args.length() == 1);
277 
278   OFStream os(stdout);
279 #ifdef DEBUG
280   if (args[0]->IsString()) {
281     // If we have a string, assume it's a code "marker"
282     // and print some interesting cpu debugging info.
283     JavaScriptFrameIterator it(isolate);
284     JavaScriptFrame* frame = it.frame();
285     os << "fp = " << static_cast<void*>(frame->fp())
286        << ", sp = " << static_cast<void*>(frame->sp())
287        << ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": ";
288   } else {
289     os << "DebugPrint: ";
290   }
291   args[0]->Print(os);
292   if (args[0]->IsHeapObject()) {
293     os << "\n";
294     HeapObject::cast(args[0])->map()->Print(os);
295   }
296 #else
297   // ShortPrint is available in release mode. Print is not.
298   os << Brief(args[0]);
299 #endif
300   os << std::endl;
301 
302   return args[0];  // return TOS
303 }
304 
305 
RUNTIME_FUNCTION(Runtime_DebugTrace)306 RUNTIME_FUNCTION(Runtime_DebugTrace) {
307   SealHandleScope shs(isolate);
308   DCHECK(args.length() == 0);
309   isolate->PrintStack(stdout);
310   return isolate->heap()->undefined_value();
311 }
312 
313 
314 // This will not allocate (flatten the string), but it may run
315 // very slowly for very deeply nested ConsStrings.  For debugging use only.
RUNTIME_FUNCTION(Runtime_GlobalPrint)316 RUNTIME_FUNCTION(Runtime_GlobalPrint) {
317   SealHandleScope shs(isolate);
318   DCHECK(args.length() == 1);
319 
320   CONVERT_ARG_CHECKED(String, string, 0);
321   StringCharacterStream stream(string);
322   while (stream.HasMore()) {
323     uint16_t character = stream.GetNext();
324     PrintF("%c", character);
325   }
326   return string;
327 }
328 
329 
RUNTIME_FUNCTION(Runtime_SystemBreak)330 RUNTIME_FUNCTION(Runtime_SystemBreak) {
331   // The code below doesn't create handles, but when breaking here in GDB
332   // having a handle scope might be useful.
333   HandleScope scope(isolate);
334   DCHECK(args.length() == 0);
335   base::OS::DebugBreak();
336   return isolate->heap()->undefined_value();
337 }
338 
339 
340 // Sets a v8 flag.
RUNTIME_FUNCTION(Runtime_SetFlags)341 RUNTIME_FUNCTION(Runtime_SetFlags) {
342   SealHandleScope shs(isolate);
343   DCHECK(args.length() == 1);
344   CONVERT_ARG_CHECKED(String, arg, 0);
345   base::SmartArrayPointer<char> flags =
346       arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
347   FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
348   return isolate->heap()->undefined_value();
349 }
350 
351 
RUNTIME_FUNCTION(Runtime_Abort)352 RUNTIME_FUNCTION(Runtime_Abort) {
353   SealHandleScope shs(isolate);
354   DCHECK(args.length() == 1);
355   CONVERT_SMI_ARG_CHECKED(message_id, 0);
356   const char* message =
357       GetBailoutReason(static_cast<BailoutReason>(message_id));
358   base::OS::PrintError("abort: %s\n", message);
359   isolate->PrintStack(stderr);
360   base::OS::Abort();
361   UNREACHABLE();
362   return NULL;
363 }
364 
365 
RUNTIME_FUNCTION(Runtime_AbortJS)366 RUNTIME_FUNCTION(Runtime_AbortJS) {
367   HandleScope scope(isolate);
368   DCHECK(args.length() == 1);
369   CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
370   base::OS::PrintError("abort: %s\n", message->ToCString().get());
371   isolate->PrintStack(stderr);
372   base::OS::Abort();
373   UNREACHABLE();
374   return NULL;
375 }
376 
377 
RUNTIME_FUNCTION(Runtime_NativeScriptsCount)378 RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
379   DCHECK(args.length() == 0);
380   return Smi::FromInt(Natives::GetBuiltinsCount() +
381                       ExtraNatives::GetBuiltinsCount());
382 }
383 
384 
385 // Returns V8 version as a string.
RUNTIME_FUNCTION(Runtime_GetV8Version)386 RUNTIME_FUNCTION(Runtime_GetV8Version) {
387   HandleScope scope(isolate);
388   DCHECK(args.length() == 0);
389 
390   const char* version_string = v8::V8::GetVersion();
391 
392   return *isolate->factory()->NewStringFromAsciiChecked(version_string);
393 }
394 
395 
RUNTIME_FUNCTION(Runtime_DisassembleFunction)396 RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
397   HandleScope scope(isolate);
398 #ifdef DEBUG
399   DCHECK(args.length() == 1);
400   // Get the function and make sure it is compiled.
401   CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
402   if (!Compiler::Compile(func, KEEP_EXCEPTION)) {
403     return isolate->heap()->exception();
404   }
405   OFStream os(stdout);
406   func->code()->Print(os);
407   os << std::endl;
408 #endif  // DEBUG
409   return isolate->heap()->undefined_value();
410 }
411 
412 
StackSize(Isolate * isolate)413 static int StackSize(Isolate* isolate) {
414   int n = 0;
415   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
416   return n;
417 }
418 
419 
PrintTransition(Isolate * isolate,Object * result)420 static void PrintTransition(Isolate* isolate, Object* result) {
421   // indentation
422   {
423     const int nmax = 80;
424     int n = StackSize(isolate);
425     if (n <= nmax)
426       PrintF("%4d:%*s", n, n, "");
427     else
428       PrintF("%4d:%*s", n, nmax, "...");
429   }
430 
431   if (result == NULL) {
432     JavaScriptFrame::PrintTop(isolate, stdout, true, false);
433     PrintF(" {\n");
434   } else {
435     // function result
436     PrintF("} -> ");
437     result->ShortPrint();
438     PrintF("\n");
439   }
440 }
441 
442 
RUNTIME_FUNCTION(Runtime_TraceEnter)443 RUNTIME_FUNCTION(Runtime_TraceEnter) {
444   SealHandleScope shs(isolate);
445   DCHECK(args.length() == 0);
446   PrintTransition(isolate, NULL);
447   return isolate->heap()->undefined_value();
448 }
449 
450 
RUNTIME_FUNCTION(Runtime_TraceExit)451 RUNTIME_FUNCTION(Runtime_TraceExit) {
452   SealHandleScope shs(isolate);
453   DCHECK(args.length() == 1);
454   CONVERT_ARG_CHECKED(Object, obj, 0);
455   PrintTransition(isolate, obj);
456   return obj;  // return TOS
457 }
458 
459 
RUNTIME_FUNCTION(Runtime_HaveSameMap)460 RUNTIME_FUNCTION(Runtime_HaveSameMap) {
461   SealHandleScope shs(isolate);
462   DCHECK(args.length() == 2);
463   CONVERT_ARG_CHECKED(JSObject, obj1, 0);
464   CONVERT_ARG_CHECKED(JSObject, obj2, 1);
465   return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
466 }
467 
468 
RUNTIME_FUNCTION(Runtime_InNewSpace)469 RUNTIME_FUNCTION(Runtime_InNewSpace) {
470   SealHandleScope shs(isolate);
471   DCHECK(args.length() == 1);
472   CONVERT_ARG_CHECKED(Object, obj, 0);
473   return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj));
474 }
475 
476 
477 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name)       \
478   RUNTIME_FUNCTION(Runtime_Has##Name) {                  \
479     CONVERT_ARG_CHECKED(JSObject, obj, 0);               \
480     return isolate->heap()->ToBoolean(obj->Has##Name()); \
481   }
482 
483 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
484 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
485 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
486 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
487 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
488 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
489 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
490 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements)
491 // Properties test sitting with elements tests - not fooling anyone.
492 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
493 
494 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
495 
496 
497 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
498   RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) {                        \
499     CONVERT_ARG_CHECKED(JSObject, obj, 0);                                    \
500     return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements());       \
501   }
502 
503 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
504 
505 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
506 }  // namespace internal
507 }  // namespace v8
508