1 // Copyright 2017 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/api-inl.h"
6 #include "src/builtins/builtins-utils-inl.h"
7 #include "src/builtins/builtins.h"
8 #include "src/debug/interface-types.h"
9 #include "src/logging/counters.h"
10 #include "src/logging/log.h"
11 #include "src/objects/objects-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 // -----------------------------------------------------------------------------
17 // Console
18 
19 #define CONSOLE_METHOD_LIST(V)      \
20   V(Debug, debug)                   \
21   V(Error, error)                   \
22   V(Info, info)                     \
23   V(Log, log)                       \
24   V(Warn, warn)                     \
25   V(Dir, dir)                       \
26   V(DirXml, dirXml)                 \
27   V(Table, table)                   \
28   V(Trace, trace)                   \
29   V(Group, group)                   \
30   V(GroupCollapsed, groupCollapsed) \
31   V(GroupEnd, groupEnd)             \
32   V(Clear, clear)                   \
33   V(Count, count)                   \
34   V(CountReset, countReset)         \
35   V(Assert, assert)                 \
36   V(Profile, profile)               \
37   V(ProfileEnd, profileEnd)         \
38   V(TimeLog, timeLog)
39 
40 namespace {
ConsoleCall(Isolate * isolate,const internal::BuiltinArguments & args,void (debug::ConsoleDelegate::* func)(const v8::debug::ConsoleCallArguments &,const v8::debug::ConsoleContext &))41 void ConsoleCall(
42     Isolate* isolate, const internal::BuiltinArguments& args,
43     void (debug::ConsoleDelegate::*func)(const v8::debug::ConsoleCallArguments&,
44                                          const v8::debug::ConsoleContext&)) {
45   CHECK(!isolate->has_pending_exception());
46   CHECK(!isolate->has_scheduled_exception());
47   if (!isolate->console_delegate()) return;
48   HandleScope scope(isolate);
49   debug::ConsoleCallArguments wrapper(args);
50   Handle<Object> context_id_obj = JSObject::GetDataProperty(
51       args.target(), isolate->factory()->console_context_id_symbol());
52   int context_id =
53       context_id_obj->IsSmi() ? Handle<Smi>::cast(context_id_obj)->value() : 0;
54   Handle<Object> context_name_obj = JSObject::GetDataProperty(
55       args.target(), isolate->factory()->console_context_name_symbol());
56   Handle<String> context_name = context_name_obj->IsString()
57                                     ? Handle<String>::cast(context_name_obj)
58                                     : isolate->factory()->anonymous_string();
59   (isolate->console_delegate()->*func)(
60       wrapper,
61       v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
62 }
63 
LogTimerEvent(Isolate * isolate,BuiltinArguments args,v8::LogEventStatus se)64 void LogTimerEvent(Isolate* isolate, BuiltinArguments args,
65                    v8::LogEventStatus se) {
66   if (!isolate->logger()->is_logging()) return;
67   HandleScope scope(isolate);
68   std::unique_ptr<char[]> name;
69   const char* raw_name = "default";
70   if (args.length() > 1 && args[1].IsString()) {
71     // Try converting the first argument to a string.
72     name = args.at<String>(1)->ToCString();
73     raw_name = name.get();
74   }
75   LOG(isolate, TimerEvent(se, raw_name));
76 }
77 }  // namespace
78 
79 #define CONSOLE_BUILTIN_IMPLEMENTATION(call, name)             \
80   BUILTIN(Console##call) {                                     \
81     ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \
82     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);            \
83     return ReadOnlyRoots(isolate).undefined_value();           \
84   }
85 CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
86 #undef CONSOLE_BUILTIN_IMPLEMENTATION
87 
BUILTIN(ConsoleTime)88 BUILTIN(ConsoleTime) {
89   LogTimerEvent(isolate, args, v8::LogEventStatus::kStart);
90   ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time);
91   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
92   return ReadOnlyRoots(isolate).undefined_value();
93 }
94 
BUILTIN(ConsoleTimeEnd)95 BUILTIN(ConsoleTimeEnd) {
96   LogTimerEvent(isolate, args, v8::LogEventStatus::kEnd);
97   ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd);
98   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
99   return ReadOnlyRoots(isolate).undefined_value();
100 }
101 
BUILTIN(ConsoleTimeStamp)102 BUILTIN(ConsoleTimeStamp) {
103   LogTimerEvent(isolate, args, v8::LogEventStatus::kStamp);
104   ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp);
105   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
106   return ReadOnlyRoots(isolate).undefined_value();
107 }
108 
109 namespace {
110 
InstallContextFunction(Isolate * isolate,Handle<JSObject> target,const char * name,Builtin builtin,int context_id,Handle<Object> context_name)111 void InstallContextFunction(Isolate* isolate, Handle<JSObject> target,
112                             const char* name, Builtin builtin, int context_id,
113                             Handle<Object> context_name) {
114   Factory* const factory = isolate->factory();
115 
116   Handle<NativeContext> context(isolate->native_context());
117   Handle<Map> map = isolate->sloppy_function_without_prototype_map();
118 
119   Handle<String> name_string =
120       Name::ToFunctionName(isolate, factory->InternalizeUtf8String(name))
121           .ToHandleChecked();
122   Handle<SharedFunctionInfo> info =
123       factory->NewSharedFunctionInfoForBuiltin(name_string, builtin);
124   info->set_language_mode(LanguageMode::kSloppy);
125 
126   Handle<JSFunction> fun =
127       Factory::JSFunctionBuilder{isolate, info, context}.set_map(map).Build();
128 
129   fun->shared().set_native(true);
130   fun->shared().DontAdaptArguments();
131   fun->shared().set_length(1);
132 
133   JSObject::AddProperty(isolate, fun, factory->console_context_id_symbol(),
134                         handle(Smi::FromInt(context_id), isolate), NONE);
135   if (context_name->IsString()) {
136     JSObject::AddProperty(isolate, fun, factory->console_context_name_symbol(),
137                           context_name, NONE);
138   }
139   JSObject::AddProperty(isolate, target, name_string, fun, NONE);
140 }
141 
142 }  // namespace
143 
BUILTIN(ConsoleContext)144 BUILTIN(ConsoleContext) {
145   HandleScope scope(isolate);
146 
147   Factory* const factory = isolate->factory();
148   Handle<String> name = factory->InternalizeUtf8String("Context");
149   Handle<SharedFunctionInfo> info =
150       factory->NewSharedFunctionInfoForBuiltin(name, Builtin::kIllegal);
151   info->set_language_mode(LanguageMode::kSloppy);
152 
153   Handle<JSFunction> cons =
154       Factory::JSFunctionBuilder{isolate, info, isolate->native_context()}
155           .Build();
156 
157   Handle<JSObject> prototype = factory->NewJSObject(isolate->object_function());
158   JSFunction::SetPrototype(cons, prototype);
159 
160   Handle<JSObject> context = factory->NewJSObject(cons, AllocationType::kOld);
161   DCHECK(context->IsJSObject());
162   int id = isolate->last_console_context_id() + 1;
163   isolate->set_last_console_context_id(id);
164 
165 #define CONSOLE_BUILTIN_SETUP(call, name)                                      \
166   InstallContextFunction(isolate, context, #name, Builtin::kConsole##call, id, \
167                          args.at(1));
168   CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP)
169 #undef CONSOLE_BUILTIN_SETUP
170   InstallContextFunction(isolate, context, "time", Builtin::kConsoleTime, id,
171                          args.at(1));
172   InstallContextFunction(isolate, context, "timeEnd", Builtin::kConsoleTimeEnd,
173                          id, args.at(1));
174   InstallContextFunction(isolate, context, "timeStamp",
175                          Builtin::kConsoleTimeStamp, id, args.at(1));
176 
177   return *context;
178 }
179 
180 #undef CONSOLE_METHOD_LIST
181 
182 }  // namespace internal
183 }  // namespace v8
184