OLD | NEW |
(Empty) | |
| 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/builtins/builtins.h" |
| 6 #include "src/builtins/builtins-utils.h" |
| 7 |
| 8 #include "src/accessors.h" |
| 9 #include "src/bootstrapper.h" |
| 10 #include "src/property-descriptor.h" |
| 11 #include "src/string-builder.h" |
| 12 |
| 13 namespace v8 { |
| 14 namespace internal { |
| 15 |
| 16 // ES6 section 19.5.1.1 Error ( message ) |
| 17 BUILTIN(ErrorConstructor) { |
| 18 HandleScope scope(isolate); |
| 19 |
| 20 // 1. If NewTarget is undefined, let newTarget be the active function object, |
| 21 // else let newTarget be NewTarget. |
| 22 |
| 23 Handle<JSFunction> target = args.target<JSFunction>(); |
| 24 Handle<JSReceiver> new_target; |
| 25 if (args.new_target()->IsJSReceiver()) { |
| 26 new_target = Handle<JSReceiver>::cast(args.new_target()); |
| 27 } else { |
| 28 new_target = target; |
| 29 } |
| 30 |
| 31 // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%", |
| 32 // « [[ErrorData]] »). |
| 33 Handle<JSObject> err; |
| 34 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, err, |
| 35 JSObject::New(target, new_target)); |
| 36 |
| 37 // 3. If message is not undefined, then |
| 38 // a. Let msg be ? ToString(message). |
| 39 // b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]: |
| 40 // true, [[Enumerable]]: false, [[Configurable]]: true}. |
| 41 // c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc). |
| 42 // 4. Return O. |
| 43 |
| 44 Handle<Object> msg = args.atOrUndefined(isolate, 1); |
| 45 if (!msg->IsUndefined(isolate)) { |
| 46 Handle<String> msg_string; |
| 47 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, msg_string, |
| 48 Object::ToString(isolate, msg)); |
| 49 RETURN_FAILURE_ON_EXCEPTION( |
| 50 isolate, |
| 51 JSObject::SetOwnPropertyIgnoreAttributes( |
| 52 err, isolate->factory()->message_string(), msg_string, DONT_ENUM)); |
| 53 } |
| 54 |
| 55 // Capture the stack trace unless we're setting up. |
| 56 if (!isolate->bootstrapper()->IsActive()) { |
| 57 // Optionally capture a more detailed stack trace for the message. |
| 58 RETURN_FAILURE_ON_EXCEPTION(isolate, |
| 59 isolate->CaptureAndSetDetailedStackTrace(err)); |
| 60 // Capture a simple stack trace for the stack property. |
| 61 RETURN_FAILURE_ON_EXCEPTION(isolate, |
| 62 isolate->CaptureAndSetSimpleStackTrace(err)); |
| 63 } |
| 64 |
| 65 return *err; |
| 66 } |
| 67 |
| 68 // static |
| 69 BUILTIN(ErrorCaptureStackTrace) { |
| 70 HandleScope scope(isolate); |
| 71 Handle<Object> object_obj = args.atOrUndefined(isolate, 1); |
| 72 if (!object_obj->IsJSObject()) { |
| 73 THROW_NEW_ERROR_RETURN_FAILURE( |
| 74 isolate, NewTypeError(MessageTemplate::kInvalidArgument, object_obj)); |
| 75 } |
| 76 Handle<JSObject> object = Handle<JSObject>::cast(object_obj); |
| 77 Handle<Object> caller = args.atOrUndefined(isolate, 2); |
| 78 |
| 79 // TODO(jgruber): Eagerly format the stack trace and remove accessors.h |
| 80 // include. |
| 81 |
| 82 // Handle writes to the global object. |
| 83 |
| 84 if (object->IsJSGlobalProxy()) { |
| 85 Map* map = object->map(); |
| 86 if (map->has_hidden_prototype()) { |
| 87 object = handle(JSGlobalObject::cast(map->prototype()), isolate); |
| 88 } |
| 89 } |
| 90 |
| 91 // Check if the stack property is read-only. |
| 92 |
| 93 bool is_extensible = true; |
| 94 if (!JSObject::IsExtensible(object)) { |
| 95 is_extensible = false; |
| 96 } |
| 97 |
| 98 PropertyDescriptor desc; |
| 99 Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor( |
| 100 isolate, object, isolate->factory()->stack_string(), &desc); |
| 101 if (owned.FromMaybe(false)) { |
| 102 if (!desc.configurable() || !desc.writable()) { |
| 103 is_extensible = false; |
| 104 } |
| 105 } |
| 106 |
| 107 if (!is_extensible) { |
| 108 THROW_NEW_ERROR_RETURN_FAILURE( |
| 109 isolate, NewTypeError(MessageTemplate::kDefineDisallowed, |
| 110 isolate->factory()->stack_string(), object)); |
| 111 } |
| 112 |
| 113 // Add stack accessors to the given object |
| 114 |
| 115 Handle<Map> map(object->map()); |
| 116 PropertyAttributes attribs = DONT_ENUM; |
| 117 Handle<AccessorInfo> error_stack = |
| 118 Accessors::ErrorStackInfo(isolate, attribs); |
| 119 { |
| 120 AccessorConstantDescriptor d(Handle<Name>(Name::cast(error_stack->name())), |
| 121 error_stack, attribs); |
| 122 Handle<DescriptorArray> old_descriptors(map->instance_descriptors()); |
| 123 int index = old_descriptors->SearchWithCache(isolate, *d.GetKey(), *map); |
| 124 if (index == DescriptorArray::kNotFound) { |
| 125 // TODO(jgruber): This ensures we do not crash when CaptureStackTrace is |
| 126 // called on an object with an existing "stack" property. This will be |
| 127 // removed as soon as we move to eager trace formatting. |
| 128 Handle<Map> new_map = |
| 129 Map::CopyInsertDescriptor(map, &d, INSERT_TRANSITION); |
| 130 JSObject::MigrateToMap(object, new_map, 1); |
| 131 } |
| 132 } |
| 133 |
| 134 // Collect the stack trace. |
| 135 |
| 136 RETURN_FAILURE_ON_EXCEPTION(isolate, |
| 137 isolate->CaptureAndSetDetailedStackTrace(object)); |
| 138 RETURN_FAILURE_ON_EXCEPTION( |
| 139 isolate, isolate->CaptureAndSetSimpleStackTrace(object, caller)); |
| 140 |
| 141 return *isolate->factory()->undefined_value(); |
| 142 } |
| 143 |
| 144 namespace { |
| 145 |
| 146 MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate, |
| 147 Handle<JSReceiver> recv, |
| 148 Handle<String> key, |
| 149 Handle<String> default_str) { |
| 150 Handle<Object> obj; |
| 151 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, JSObject::GetProperty(recv, key), |
| 152 String); |
| 153 |
| 154 Handle<String> str; |
| 155 if (obj->IsUndefined(isolate)) { |
| 156 str = default_str; |
| 157 } else { |
| 158 ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj), |
| 159 String); |
| 160 } |
| 161 |
| 162 return str; |
| 163 } |
| 164 |
| 165 } // namespace |
| 166 |
| 167 // ES6 section 19.5.3.4 Error.prototype.toString ( ) |
| 168 BUILTIN(ErrorPrototypeToString) { |
| 169 HandleScope scope(isolate); |
| 170 |
| 171 // 1. Let O be the this value. |
| 172 // 2. If Type(O) is not Object, throw a TypeError exception. |
| 173 CHECK_RECEIVER(JSReceiver, receiver, "Error.prototype.toString"); |
| 174 |
| 175 // 3. Let name be ? Get(O, "name"). |
| 176 // 4. If name is undefined, let name be "Error"; otherwise let name be |
| 177 // ? ToString(name). |
| 178 Handle<String> name_key = isolate->factory()->name_string(); |
| 179 Handle<String> name_default = isolate->factory()->Error_string(); |
| 180 Handle<String> name; |
| 181 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 182 isolate, name, |
| 183 GetStringPropertyOrDefault(isolate, receiver, name_key, name_default)); |
| 184 |
| 185 // 5. Let msg be ? Get(O, "message"). |
| 186 // 6. If msg is undefined, let msg be the empty String; otherwise let msg be |
| 187 // ? ToString(msg). |
| 188 Handle<String> msg_key = isolate->factory()->message_string(); |
| 189 Handle<String> msg_default = isolate->factory()->empty_string(); |
| 190 Handle<String> msg; |
| 191 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 192 isolate, msg, |
| 193 GetStringPropertyOrDefault(isolate, receiver, msg_key, msg_default)); |
| 194 |
| 195 // 7. If name is the empty String, return msg. |
| 196 // 8. If msg is the empty String, return name. |
| 197 if (name->length() == 0) return *msg; |
| 198 if (msg->length() == 0) return *name; |
| 199 |
| 200 // 9. Return the result of concatenating name, the code unit 0x003A (COLON), |
| 201 // the code unit 0x0020 (SPACE), and msg. |
| 202 IncrementalStringBuilder builder(isolate); |
| 203 builder.AppendString(name); |
| 204 builder.AppendCString(": "); |
| 205 builder.AppendString(msg); |
| 206 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); |
| 207 } |
| 208 |
| 209 } // namespace internal |
| 210 } // namespace v8 |
OLD | NEW |