OLD | NEW |
| (Empty) |
1 // Copyright 2012 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 <stdlib.h> | |
6 #include <limits> | |
7 | |
8 #include "src/v8.h" | |
9 | |
10 #include "src/accessors.h" | |
11 #include "src/allocation-site-scopes.h" | |
12 #include "src/api.h" | |
13 #include "src/arguments.h" | |
14 #include "src/bailout-reason.h" | |
15 #include "src/base/cpu.h" | |
16 #include "src/base/platform/platform.h" | |
17 #include "src/bootstrapper.h" | |
18 #include "src/codegen.h" | |
19 #include "src/compilation-cache.h" | |
20 #include "src/compiler.h" | |
21 #include "src/conversions.h" | |
22 #include "src/cpu-profiler.h" | |
23 #include "src/date.h" | |
24 #include "src/dateparser-inl.h" | |
25 #include "src/debug.h" | |
26 #include "src/deoptimizer.h" | |
27 #include "src/execution.h" | |
28 #include "src/full-codegen.h" | |
29 #include "src/global-handles.h" | |
30 #include "src/isolate-inl.h" | |
31 #include "src/json-parser.h" | |
32 #include "src/json-stringifier.h" | |
33 #include "src/jsregexp-inl.h" | |
34 #include "src/jsregexp.h" | |
35 #include "src/liveedit.h" | |
36 #include "src/misc-intrinsics.h" | |
37 #include "src/parser.h" | |
38 #include "src/prototype.h" | |
39 #include "src/runtime.h" | |
40 #include "src/runtime-profiler.h" | |
41 #include "src/scopeinfo.h" | |
42 #include "src/smart-pointers.h" | |
43 #include "src/string-search.h" | |
44 #include "src/uri.h" | |
45 #include "src/utils.h" | |
46 #include "src/v8threads.h" | |
47 #include "src/vm-state-inl.h" | |
48 #include "third_party/fdlibm/fdlibm.h" | |
49 | |
50 #ifdef V8_I18N_SUPPORT | |
51 #include "src/i18n.h" | |
52 #include "unicode/brkiter.h" | |
53 #include "unicode/calendar.h" | |
54 #include "unicode/coll.h" | |
55 #include "unicode/curramt.h" | |
56 #include "unicode/datefmt.h" | |
57 #include "unicode/dcfmtsym.h" | |
58 #include "unicode/decimfmt.h" | |
59 #include "unicode/dtfmtsym.h" | |
60 #include "unicode/dtptngen.h" | |
61 #include "unicode/locid.h" | |
62 #include "unicode/numfmt.h" | |
63 #include "unicode/numsys.h" | |
64 #include "unicode/rbbi.h" | |
65 #include "unicode/smpdtfmt.h" | |
66 #include "unicode/timezone.h" | |
67 #include "unicode/uchar.h" | |
68 #include "unicode/ucol.h" | |
69 #include "unicode/ucurr.h" | |
70 #include "unicode/uloc.h" | |
71 #include "unicode/unum.h" | |
72 #include "unicode/uversion.h" | |
73 #endif | |
74 | |
75 #ifndef _STLP_VENDOR_CSTD | |
76 // STLPort doesn't import fpclassify and isless into the std namespace. | |
77 using std::fpclassify; | |
78 using std::isless; | |
79 #endif | |
80 | |
81 namespace v8 { | |
82 namespace internal { | |
83 | |
84 | |
85 #define RUNTIME_ASSERT(value) \ | |
86 if (!(value)) return isolate->ThrowIllegalOperation(); | |
87 | |
88 #define RUNTIME_ASSERT_HANDLIFIED(value, T) \ | |
89 if (!(value)) { \ | |
90 isolate->ThrowIllegalOperation(); \ | |
91 return MaybeHandle<T>(); \ | |
92 } | |
93 | |
94 // Cast the given object to a value of the specified type and store | |
95 // it in a variable with the given name. If the object is not of the | |
96 // expected type call IllegalOperation and return. | |
97 #define CONVERT_ARG_CHECKED(Type, name, index) \ | |
98 RUNTIME_ASSERT(args[index]->Is##Type()); \ | |
99 Type* name = Type::cast(args[index]); | |
100 | |
101 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ | |
102 RUNTIME_ASSERT(args[index]->Is##Type()); \ | |
103 Handle<Type> name = args.at<Type>(index); | |
104 | |
105 #define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \ | |
106 RUNTIME_ASSERT(args[index]->IsNumber()); \ | |
107 Handle<Object> name = args.at<Object>(index); | |
108 | |
109 // Cast the given object to a boolean and store it in a variable with | |
110 // the given name. If the object is not a boolean call IllegalOperation | |
111 // and return. | |
112 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ | |
113 RUNTIME_ASSERT(args[index]->IsBoolean()); \ | |
114 bool name = args[index]->IsTrue(); | |
115 | |
116 // Cast the given argument to a Smi and store its value in an int variable | |
117 // with the given name. If the argument is not a Smi call IllegalOperation | |
118 // and return. | |
119 #define CONVERT_SMI_ARG_CHECKED(name, index) \ | |
120 RUNTIME_ASSERT(args[index]->IsSmi()); \ | |
121 int name = args.smi_at(index); | |
122 | |
123 // Cast the given argument to a double and store it in a variable with | |
124 // the given name. If the argument is not a number (as opposed to | |
125 // the number not-a-number) call IllegalOperation and return. | |
126 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ | |
127 RUNTIME_ASSERT(args[index]->IsNumber()); \ | |
128 double name = args.number_at(index); | |
129 | |
130 // Call the specified converter on the object *comand store the result in | |
131 // a variable of the specified type with the given name. If the | |
132 // object is not a Number call IllegalOperation and return. | |
133 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ | |
134 RUNTIME_ASSERT(obj->IsNumber()); \ | |
135 type name = NumberTo##Type(obj); | |
136 | |
137 | |
138 // Cast the given argument to PropertyDetails and store its value in a | |
139 // variable with the given name. If the argument is not a Smi call | |
140 // IllegalOperation and return. | |
141 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ | |
142 RUNTIME_ASSERT(args[index]->IsSmi()); \ | |
143 PropertyDetails name = PropertyDetails(Smi::cast(args[index])); | |
144 | |
145 | |
146 // Assert that the given argument has a valid value for a StrictMode | |
147 // and store it in a StrictMode variable with the given name. | |
148 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ | |
149 RUNTIME_ASSERT(args[index]->IsSmi()); \ | |
150 RUNTIME_ASSERT(args.smi_at(index) == STRICT || \ | |
151 args.smi_at(index) == SLOPPY); \ | |
152 StrictMode name = static_cast<StrictMode>(args.smi_at(index)); | |
153 | |
154 | |
155 // Assert that the given argument is a number within the Int32 range | |
156 // and convert it to int32_t. If the argument is not an Int32 call | |
157 // IllegalOperation and return. | |
158 #define CONVERT_INT32_ARG_CHECKED(name, index) \ | |
159 RUNTIME_ASSERT(args[index]->IsNumber()); \ | |
160 int32_t name = 0; \ | |
161 RUNTIME_ASSERT(args[index]->ToInt32(&name)); | |
162 | |
163 | |
164 static Handle<Map> ComputeObjectLiteralMap( | |
165 Handle<Context> context, | |
166 Handle<FixedArray> constant_properties, | |
167 bool* is_result_from_cache) { | |
168 Isolate* isolate = context->GetIsolate(); | |
169 int properties_length = constant_properties->length(); | |
170 int number_of_properties = properties_length / 2; | |
171 // Check that there are only internal strings and array indices among keys. | |
172 int number_of_string_keys = 0; | |
173 for (int p = 0; p != properties_length; p += 2) { | |
174 Object* key = constant_properties->get(p); | |
175 uint32_t element_index = 0; | |
176 if (key->IsInternalizedString()) { | |
177 number_of_string_keys++; | |
178 } else if (key->ToArrayIndex(&element_index)) { | |
179 // An index key does not require space in the property backing store. | |
180 number_of_properties--; | |
181 } else { | |
182 // Bail out as a non-internalized-string non-index key makes caching | |
183 // impossible. | |
184 // DCHECK to make sure that the if condition after the loop is false. | |
185 DCHECK(number_of_string_keys != number_of_properties); | |
186 break; | |
187 } | |
188 } | |
189 // If we only have internalized strings and array indices among keys then we | |
190 // can use the map cache in the native context. | |
191 const int kMaxKeys = 10; | |
192 if ((number_of_string_keys == number_of_properties) && | |
193 (number_of_string_keys < kMaxKeys)) { | |
194 // Create the fixed array with the key. | |
195 Handle<FixedArray> keys = | |
196 isolate->factory()->NewFixedArray(number_of_string_keys); | |
197 if (number_of_string_keys > 0) { | |
198 int index = 0; | |
199 for (int p = 0; p < properties_length; p += 2) { | |
200 Object* key = constant_properties->get(p); | |
201 if (key->IsInternalizedString()) { | |
202 keys->set(index++, key); | |
203 } | |
204 } | |
205 DCHECK(index == number_of_string_keys); | |
206 } | |
207 *is_result_from_cache = true; | |
208 return isolate->factory()->ObjectLiteralMapFromCache(context, keys); | |
209 } | |
210 *is_result_from_cache = false; | |
211 return Map::Create(isolate, number_of_properties); | |
212 } | |
213 | |
214 | |
215 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( | |
216 Isolate* isolate, | |
217 Handle<FixedArray> literals, | |
218 Handle<FixedArray> constant_properties); | |
219 | |
220 | |
221 MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate( | |
222 Isolate* isolate, | |
223 Handle<FixedArray> literals, | |
224 Handle<FixedArray> constant_properties, | |
225 bool should_have_fast_elements, | |
226 bool has_function_literal) { | |
227 // Get the native context from the literals array. This is the | |
228 // context in which the function was created and we use the object | |
229 // function from this context to create the object literal. We do | |
230 // not use the object function from the current native context | |
231 // because this might be the object function from another context | |
232 // which we should not have access to. | |
233 Handle<Context> context = | |
234 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals)); | |
235 | |
236 // In case we have function literals, we want the object to be in | |
237 // slow properties mode for now. We don't go in the map cache because | |
238 // maps with constant functions can't be shared if the functions are | |
239 // not the same (which is the common case). | |
240 bool is_result_from_cache = false; | |
241 Handle<Map> map = has_function_literal | |
242 ? Handle<Map>(context->object_function()->initial_map()) | |
243 : ComputeObjectLiteralMap(context, | |
244 constant_properties, | |
245 &is_result_from_cache); | |
246 | |
247 PretenureFlag pretenure_flag = | |
248 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; | |
249 | |
250 Handle<JSObject> boilerplate = | |
251 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag); | |
252 | |
253 // Normalize the elements of the boilerplate to save space if needed. | |
254 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); | |
255 | |
256 // Add the constant properties to the boilerplate. | |
257 int length = constant_properties->length(); | |
258 bool should_transform = | |
259 !is_result_from_cache && boilerplate->HasFastProperties(); | |
260 bool should_normalize = should_transform || has_function_literal; | |
261 if (should_normalize) { | |
262 // TODO(verwaest): We might not want to ever normalize here. | |
263 JSObject::NormalizeProperties( | |
264 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); | |
265 } | |
266 // TODO(verwaest): Support tracking representations in the boilerplate. | |
267 for (int index = 0; index < length; index +=2) { | |
268 Handle<Object> key(constant_properties->get(index+0), isolate); | |
269 Handle<Object> value(constant_properties->get(index+1), isolate); | |
270 if (value->IsFixedArray()) { | |
271 // The value contains the constant_properties of a | |
272 // simple object or array literal. | |
273 Handle<FixedArray> array = Handle<FixedArray>::cast(value); | |
274 ASSIGN_RETURN_ON_EXCEPTION( | |
275 isolate, value, | |
276 CreateLiteralBoilerplate(isolate, literals, array), | |
277 Object); | |
278 } | |
279 MaybeHandle<Object> maybe_result; | |
280 uint32_t element_index = 0; | |
281 if (key->IsInternalizedString()) { | |
282 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { | |
283 // Array index as string (uint32). | |
284 if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate); | |
285 maybe_result = | |
286 JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY); | |
287 } else { | |
288 Handle<String> name(String::cast(*key)); | |
289 DCHECK(!name->AsArrayIndex(&element_index)); | |
290 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes( | |
291 boilerplate, name, value, NONE); | |
292 } | |
293 } else if (key->ToArrayIndex(&element_index)) { | |
294 // Array index (uint32). | |
295 if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate); | |
296 maybe_result = | |
297 JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY); | |
298 } else { | |
299 // Non-uint32 number. | |
300 DCHECK(key->IsNumber()); | |
301 double num = key->Number(); | |
302 char arr[100]; | |
303 Vector<char> buffer(arr, arraysize(arr)); | |
304 const char* str = DoubleToCString(num, buffer); | |
305 Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str); | |
306 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, | |
307 value, NONE); | |
308 } | |
309 // If setting the property on the boilerplate throws an | |
310 // exception, the exception is converted to an empty handle in | |
311 // the handle based operations. In that case, we need to | |
312 // convert back to an exception. | |
313 RETURN_ON_EXCEPTION(isolate, maybe_result, Object); | |
314 } | |
315 | |
316 // Transform to fast properties if necessary. For object literals with | |
317 // containing function literals we defer this operation until after all | |
318 // computed properties have been assigned so that we can generate | |
319 // constant function properties. | |
320 if (should_transform && !has_function_literal) { | |
321 JSObject::MigrateSlowToFast( | |
322 boilerplate, boilerplate->map()->unused_property_fields()); | |
323 } | |
324 | |
325 return boilerplate; | |
326 } | |
327 | |
328 | |
329 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( | |
330 Handle<Object> object, | |
331 ElementsKind to_kind, | |
332 Isolate* isolate) { | |
333 HandleScope scope(isolate); | |
334 if (!object->IsJSObject()) { | |
335 isolate->ThrowIllegalOperation(); | |
336 return MaybeHandle<Object>(); | |
337 } | |
338 ElementsKind from_kind = | |
339 Handle<JSObject>::cast(object)->map()->elements_kind(); | |
340 if (Map::IsValidElementsTransition(from_kind, to_kind)) { | |
341 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); | |
342 return object; | |
343 } | |
344 isolate->ThrowIllegalOperation(); | |
345 return MaybeHandle<Object>(); | |
346 } | |
347 | |
348 | |
349 MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate( | |
350 Isolate* isolate, | |
351 Handle<FixedArray> literals, | |
352 Handle<FixedArray> elements) { | |
353 // Create the JSArray. | |
354 Handle<JSFunction> constructor( | |
355 JSFunction::NativeContextFromLiterals(*literals)->array_function()); | |
356 | |
357 PretenureFlag pretenure_flag = | |
358 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; | |
359 | |
360 Handle<JSArray> object = Handle<JSArray>::cast( | |
361 isolate->factory()->NewJSObject(constructor, pretenure_flag)); | |
362 | |
363 ElementsKind constant_elements_kind = | |
364 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value()); | |
365 Handle<FixedArrayBase> constant_elements_values( | |
366 FixedArrayBase::cast(elements->get(1))); | |
367 | |
368 { DisallowHeapAllocation no_gc; | |
369 DCHECK(IsFastElementsKind(constant_elements_kind)); | |
370 Context* native_context = isolate->context()->native_context(); | |
371 Object* maps_array = native_context->js_array_maps(); | |
372 DCHECK(!maps_array->IsUndefined()); | |
373 Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind); | |
374 object->set_map(Map::cast(map)); | |
375 } | |
376 | |
377 Handle<FixedArrayBase> copied_elements_values; | |
378 if (IsFastDoubleElementsKind(constant_elements_kind)) { | |
379 copied_elements_values = isolate->factory()->CopyFixedDoubleArray( | |
380 Handle<FixedDoubleArray>::cast(constant_elements_values)); | |
381 } else { | |
382 DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind)); | |
383 const bool is_cow = | |
384 (constant_elements_values->map() == | |
385 isolate->heap()->fixed_cow_array_map()); | |
386 if (is_cow) { | |
387 copied_elements_values = constant_elements_values; | |
388 #if DEBUG | |
389 Handle<FixedArray> fixed_array_values = | |
390 Handle<FixedArray>::cast(copied_elements_values); | |
391 for (int i = 0; i < fixed_array_values->length(); i++) { | |
392 DCHECK(!fixed_array_values->get(i)->IsFixedArray()); | |
393 } | |
394 #endif | |
395 } else { | |
396 Handle<FixedArray> fixed_array_values = | |
397 Handle<FixedArray>::cast(constant_elements_values); | |
398 Handle<FixedArray> fixed_array_values_copy = | |
399 isolate->factory()->CopyFixedArray(fixed_array_values); | |
400 copied_elements_values = fixed_array_values_copy; | |
401 for (int i = 0; i < fixed_array_values->length(); i++) { | |
402 if (fixed_array_values->get(i)->IsFixedArray()) { | |
403 // The value contains the constant_properties of a | |
404 // simple object or array literal. | |
405 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); | |
406 Handle<Object> result; | |
407 ASSIGN_RETURN_ON_EXCEPTION( | |
408 isolate, result, | |
409 CreateLiteralBoilerplate(isolate, literals, fa), | |
410 Object); | |
411 fixed_array_values_copy->set(i, *result); | |
412 } | |
413 } | |
414 } | |
415 } | |
416 object->set_elements(*copied_elements_values); | |
417 object->set_length(Smi::FromInt(copied_elements_values->length())); | |
418 | |
419 JSObject::ValidateElements(object); | |
420 return object; | |
421 } | |
422 | |
423 | |
424 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( | |
425 Isolate* isolate, | |
426 Handle<FixedArray> literals, | |
427 Handle<FixedArray> array) { | |
428 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | |
429 const bool kHasNoFunctionLiteral = false; | |
430 switch (CompileTimeValue::GetLiteralType(array)) { | |
431 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: | |
432 return CreateObjectLiteralBoilerplate(isolate, | |
433 literals, | |
434 elements, | |
435 true, | |
436 kHasNoFunctionLiteral); | |
437 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: | |
438 return CreateObjectLiteralBoilerplate(isolate, | |
439 literals, | |
440 elements, | |
441 false, | |
442 kHasNoFunctionLiteral); | |
443 case CompileTimeValue::ARRAY_LITERAL: | |
444 return Runtime::CreateArrayLiteralBoilerplate( | |
445 isolate, literals, elements); | |
446 default: | |
447 UNREACHABLE(); | |
448 return MaybeHandle<Object>(); | |
449 } | |
450 } | |
451 | |
452 | |
453 RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) { | |
454 HandleScope scope(isolate); | |
455 DCHECK(args.length() == 4); | |
456 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); | |
457 CONVERT_SMI_ARG_CHECKED(literals_index, 1); | |
458 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2); | |
459 CONVERT_SMI_ARG_CHECKED(flags, 3); | |
460 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; | |
461 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; | |
462 | |
463 RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length()); | |
464 | |
465 // Check if boilerplate exists. If not, create it first. | |
466 Handle<Object> literal_site(literals->get(literals_index), isolate); | |
467 Handle<AllocationSite> site; | |
468 Handle<JSObject> boilerplate; | |
469 if (*literal_site == isolate->heap()->undefined_value()) { | |
470 Handle<Object> raw_boilerplate; | |
471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
472 isolate, raw_boilerplate, | |
473 CreateObjectLiteralBoilerplate( | |
474 isolate, | |
475 literals, | |
476 constant_properties, | |
477 should_have_fast_elements, | |
478 has_function_literal)); | |
479 boilerplate = Handle<JSObject>::cast(raw_boilerplate); | |
480 | |
481 AllocationSiteCreationContext creation_context(isolate); | |
482 site = creation_context.EnterNewScope(); | |
483 RETURN_FAILURE_ON_EXCEPTION( | |
484 isolate, | |
485 JSObject::DeepWalk(boilerplate, &creation_context)); | |
486 creation_context.ExitScope(site, boilerplate); | |
487 | |
488 // Update the functions literal and return the boilerplate. | |
489 literals->set(literals_index, *site); | |
490 } else { | |
491 site = Handle<AllocationSite>::cast(literal_site); | |
492 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()), | |
493 isolate); | |
494 } | |
495 | |
496 AllocationSiteUsageContext usage_context(isolate, site, true); | |
497 usage_context.EnterNewScope(); | |
498 MaybeHandle<Object> maybe_copy = JSObject::DeepCopy( | |
499 boilerplate, &usage_context); | |
500 usage_context.ExitScope(site, boilerplate); | |
501 Handle<Object> copy; | |
502 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy); | |
503 return *copy; | |
504 } | |
505 | |
506 | |
507 MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite( | |
508 Isolate* isolate, | |
509 Handle<FixedArray> literals, | |
510 int literals_index, | |
511 Handle<FixedArray> elements) { | |
512 // Check if boilerplate exists. If not, create it first. | |
513 Handle<Object> literal_site(literals->get(literals_index), isolate); | |
514 Handle<AllocationSite> site; | |
515 if (*literal_site == isolate->heap()->undefined_value()) { | |
516 DCHECK(*elements != isolate->heap()->empty_fixed_array()); | |
517 Handle<Object> boilerplate; | |
518 ASSIGN_RETURN_ON_EXCEPTION( | |
519 isolate, boilerplate, | |
520 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements), | |
521 AllocationSite); | |
522 | |
523 AllocationSiteCreationContext creation_context(isolate); | |
524 site = creation_context.EnterNewScope(); | |
525 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), | |
526 &creation_context).is_null()) { | |
527 return Handle<AllocationSite>::null(); | |
528 } | |
529 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate)); | |
530 | |
531 literals->set(literals_index, *site); | |
532 } else { | |
533 site = Handle<AllocationSite>::cast(literal_site); | |
534 } | |
535 | |
536 return site; | |
537 } | |
538 | |
539 | |
540 static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate, | |
541 Handle<FixedArray> literals, | |
542 int literals_index, | |
543 Handle<FixedArray> elements, | |
544 int flags) { | |
545 RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 && | |
546 literals_index < literals->length(), JSObject); | |
547 Handle<AllocationSite> site; | |
548 ASSIGN_RETURN_ON_EXCEPTION( | |
549 isolate, site, | |
550 GetLiteralAllocationSite(isolate, literals, literals_index, elements), | |
551 JSObject); | |
552 | |
553 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0; | |
554 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info())); | |
555 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos); | |
556 usage_context.EnterNewScope(); | |
557 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0 | |
558 ? JSObject::kNoHints | |
559 : JSObject::kObjectIsShallow; | |
560 MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context, | |
561 hints); | |
562 usage_context.ExitScope(site, boilerplate); | |
563 return copy; | |
564 } | |
565 | |
566 | |
567 RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) { | |
568 HandleScope scope(isolate); | |
569 DCHECK(args.length() == 4); | |
570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); | |
571 CONVERT_SMI_ARG_CHECKED(literals_index, 1); | |
572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); | |
573 CONVERT_SMI_ARG_CHECKED(flags, 3); | |
574 | |
575 Handle<JSObject> result; | |
576 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
577 CreateArrayLiteralImpl(isolate, literals, literals_index, elements, | |
578 flags)); | |
579 return *result; | |
580 } | |
581 | |
582 | |
583 RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) { | |
584 HandleScope scope(isolate); | |
585 DCHECK(args.length() == 3); | |
586 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); | |
587 CONVERT_SMI_ARG_CHECKED(literals_index, 1); | |
588 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); | |
589 | |
590 Handle<JSObject> result; | |
591 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
592 CreateArrayLiteralImpl(isolate, literals, literals_index, elements, | |
593 ArrayLiteral::kShallowElements)); | |
594 return *result; | |
595 } | |
596 | |
597 | |
598 RUNTIME_FUNCTION(Runtime_CreateSymbol) { | |
599 HandleScope scope(isolate); | |
600 DCHECK(args.length() == 1); | |
601 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); | |
602 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); | |
603 Handle<Symbol> symbol = isolate->factory()->NewSymbol(); | |
604 if (name->IsString()) symbol->set_name(*name); | |
605 return *symbol; | |
606 } | |
607 | |
608 | |
609 RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) { | |
610 HandleScope scope(isolate); | |
611 DCHECK(args.length() == 1); | |
612 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); | |
613 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); | |
614 Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol(); | |
615 if (name->IsString()) symbol->set_name(*name); | |
616 return *symbol; | |
617 } | |
618 | |
619 | |
620 RUNTIME_FUNCTION(Runtime_CreatePrivateOwnSymbol) { | |
621 HandleScope scope(isolate); | |
622 DCHECK(args.length() == 1); | |
623 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); | |
624 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); | |
625 Handle<Symbol> symbol = isolate->factory()->NewPrivateOwnSymbol(); | |
626 if (name->IsString()) symbol->set_name(*name); | |
627 return *symbol; | |
628 } | |
629 | |
630 | |
631 RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateOwnSymbol) { | |
632 HandleScope scope(isolate); | |
633 DCHECK(args.length() == 1); | |
634 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
635 Handle<JSObject> registry = isolate->GetSymbolRegistry(); | |
636 Handle<String> part = isolate->factory()->private_intern_string(); | |
637 Handle<Object> privates; | |
638 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
639 isolate, privates, Object::GetPropertyOrElement(registry, part)); | |
640 Handle<Object> symbol; | |
641 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
642 isolate, symbol, Object::GetPropertyOrElement(privates, name)); | |
643 if (!symbol->IsSymbol()) { | |
644 DCHECK(symbol->IsUndefined()); | |
645 symbol = isolate->factory()->NewPrivateSymbol(); | |
646 Handle<Symbol>::cast(symbol)->set_name(*name); | |
647 Handle<Symbol>::cast(symbol)->set_is_own(true); | |
648 JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol, | |
649 STRICT).Assert(); | |
650 } | |
651 return *symbol; | |
652 } | |
653 | |
654 | |
655 RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) { | |
656 HandleScope scope(isolate); | |
657 DCHECK(args.length() == 1); | |
658 CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); | |
659 return *Object::ToObject(isolate, symbol).ToHandleChecked(); | |
660 } | |
661 | |
662 | |
663 RUNTIME_FUNCTION(Runtime_SymbolDescription) { | |
664 SealHandleScope shs(isolate); | |
665 DCHECK(args.length() == 1); | |
666 CONVERT_ARG_CHECKED(Symbol, symbol, 0); | |
667 return symbol->name(); | |
668 } | |
669 | |
670 | |
671 RUNTIME_FUNCTION(Runtime_SymbolRegistry) { | |
672 HandleScope scope(isolate); | |
673 DCHECK(args.length() == 0); | |
674 return *isolate->GetSymbolRegistry(); | |
675 } | |
676 | |
677 | |
678 RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) { | |
679 SealHandleScope shs(isolate); | |
680 DCHECK(args.length() == 1); | |
681 CONVERT_ARG_CHECKED(Symbol, symbol, 0); | |
682 return isolate->heap()->ToBoolean(symbol->is_private()); | |
683 } | |
684 | |
685 | |
686 RUNTIME_FUNCTION(Runtime_CreateJSProxy) { | |
687 HandleScope scope(isolate); | |
688 DCHECK(args.length() == 2); | |
689 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); | |
690 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | |
691 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); | |
692 return *isolate->factory()->NewJSProxy(handler, prototype); | |
693 } | |
694 | |
695 | |
696 RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) { | |
697 HandleScope scope(isolate); | |
698 DCHECK(args.length() == 4); | |
699 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); | |
700 CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1); | |
701 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); | |
702 CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2); | |
703 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3); | |
704 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); | |
705 return *isolate->factory()->NewJSFunctionProxy( | |
706 handler, call_trap, construct_trap, prototype); | |
707 } | |
708 | |
709 | |
710 RUNTIME_FUNCTION(Runtime_IsJSProxy) { | |
711 SealHandleScope shs(isolate); | |
712 DCHECK(args.length() == 1); | |
713 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); | |
714 return isolate->heap()->ToBoolean(obj->IsJSProxy()); | |
715 } | |
716 | |
717 | |
718 RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) { | |
719 SealHandleScope shs(isolate); | |
720 DCHECK(args.length() == 1); | |
721 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); | |
722 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); | |
723 } | |
724 | |
725 | |
726 RUNTIME_FUNCTION(Runtime_GetHandler) { | |
727 SealHandleScope shs(isolate); | |
728 DCHECK(args.length() == 1); | |
729 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); | |
730 return proxy->handler(); | |
731 } | |
732 | |
733 | |
734 RUNTIME_FUNCTION(Runtime_GetCallTrap) { | |
735 SealHandleScope shs(isolate); | |
736 DCHECK(args.length() == 1); | |
737 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); | |
738 return proxy->call_trap(); | |
739 } | |
740 | |
741 | |
742 RUNTIME_FUNCTION(Runtime_GetConstructTrap) { | |
743 SealHandleScope shs(isolate); | |
744 DCHECK(args.length() == 1); | |
745 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); | |
746 return proxy->construct_trap(); | |
747 } | |
748 | |
749 | |
750 RUNTIME_FUNCTION(Runtime_Fix) { | |
751 HandleScope scope(isolate); | |
752 DCHECK(args.length() == 1); | |
753 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0); | |
754 JSProxy::Fix(proxy); | |
755 return isolate->heap()->undefined_value(); | |
756 } | |
757 | |
758 | |
759 void Runtime::FreeArrayBuffer(Isolate* isolate, | |
760 JSArrayBuffer* phantom_array_buffer) { | |
761 if (phantom_array_buffer->should_be_freed()) { | |
762 DCHECK(phantom_array_buffer->is_external()); | |
763 free(phantom_array_buffer->backing_store()); | |
764 } | |
765 if (phantom_array_buffer->is_external()) return; | |
766 | |
767 size_t allocated_length = NumberToSize( | |
768 isolate, phantom_array_buffer->byte_length()); | |
769 | |
770 reinterpret_cast<v8::Isolate*>(isolate) | |
771 ->AdjustAmountOfExternalAllocatedMemory( | |
772 -static_cast<int64_t>(allocated_length)); | |
773 CHECK(V8::ArrayBufferAllocator() != NULL); | |
774 V8::ArrayBufferAllocator()->Free( | |
775 phantom_array_buffer->backing_store(), | |
776 allocated_length); | |
777 } | |
778 | |
779 | |
780 void Runtime::SetupArrayBuffer(Isolate* isolate, | |
781 Handle<JSArrayBuffer> array_buffer, | |
782 bool is_external, | |
783 void* data, | |
784 size_t allocated_length) { | |
785 DCHECK(array_buffer->GetInternalFieldCount() == | |
786 v8::ArrayBuffer::kInternalFieldCount); | |
787 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { | |
788 array_buffer->SetInternalField(i, Smi::FromInt(0)); | |
789 } | |
790 array_buffer->set_backing_store(data); | |
791 array_buffer->set_flag(Smi::FromInt(0)); | |
792 array_buffer->set_is_external(is_external); | |
793 | |
794 Handle<Object> byte_length = | |
795 isolate->factory()->NewNumberFromSize(allocated_length); | |
796 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); | |
797 array_buffer->set_byte_length(*byte_length); | |
798 | |
799 array_buffer->set_weak_next(isolate->heap()->array_buffers_list()); | |
800 isolate->heap()->set_array_buffers_list(*array_buffer); | |
801 array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); | |
802 } | |
803 | |
804 | |
805 bool Runtime::SetupArrayBufferAllocatingData( | |
806 Isolate* isolate, | |
807 Handle<JSArrayBuffer> array_buffer, | |
808 size_t allocated_length, | |
809 bool initialize) { | |
810 void* data; | |
811 CHECK(V8::ArrayBufferAllocator() != NULL); | |
812 if (allocated_length != 0) { | |
813 if (initialize) { | |
814 data = V8::ArrayBufferAllocator()->Allocate(allocated_length); | |
815 } else { | |
816 data = | |
817 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); | |
818 } | |
819 if (data == NULL) return false; | |
820 } else { | |
821 data = NULL; | |
822 } | |
823 | |
824 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); | |
825 | |
826 reinterpret_cast<v8::Isolate*>(isolate) | |
827 ->AdjustAmountOfExternalAllocatedMemory(allocated_length); | |
828 | |
829 return true; | |
830 } | |
831 | |
832 | |
833 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) { | |
834 Isolate* isolate = array_buffer->GetIsolate(); | |
835 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate); | |
836 !view_obj->IsUndefined();) { | |
837 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj)); | |
838 if (view->IsJSTypedArray()) { | |
839 JSTypedArray::cast(*view)->Neuter(); | |
840 } else if (view->IsJSDataView()) { | |
841 JSDataView::cast(*view)->Neuter(); | |
842 } else { | |
843 UNREACHABLE(); | |
844 } | |
845 view_obj = handle(view->weak_next(), isolate); | |
846 } | |
847 array_buffer->Neuter(); | |
848 } | |
849 | |
850 | |
851 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) { | |
852 HandleScope scope(isolate); | |
853 DCHECK(args.length() == 2); | |
854 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); | |
855 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1); | |
856 if (!holder->byte_length()->IsUndefined()) { | |
857 // ArrayBuffer is already initialized; probably a fuzz test. | |
858 return *holder; | |
859 } | |
860 size_t allocated_length = 0; | |
861 if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) { | |
862 THROW_NEW_ERROR_RETURN_FAILURE( | |
863 isolate, NewRangeError("invalid_array_buffer_length", | |
864 HandleVector<Object>(NULL, 0))); | |
865 } | |
866 if (!Runtime::SetupArrayBufferAllocatingData(isolate, | |
867 holder, allocated_length)) { | |
868 THROW_NEW_ERROR_RETURN_FAILURE( | |
869 isolate, NewRangeError("invalid_array_buffer_length", | |
870 HandleVector<Object>(NULL, 0))); | |
871 } | |
872 return *holder; | |
873 } | |
874 | |
875 | |
876 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) { | |
877 SealHandleScope shs(isolate); | |
878 DCHECK(args.length() == 1); | |
879 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); | |
880 return holder->byte_length(); | |
881 } | |
882 | |
883 | |
884 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) { | |
885 HandleScope scope(isolate); | |
886 DCHECK(args.length() == 3); | |
887 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); | |
888 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); | |
889 CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2); | |
890 RUNTIME_ASSERT(!source.is_identical_to(target)); | |
891 size_t start = 0; | |
892 RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start)); | |
893 size_t target_length = NumberToSize(isolate, target->byte_length()); | |
894 | |
895 if (target_length == 0) return isolate->heap()->undefined_value(); | |
896 | |
897 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); | |
898 RUNTIME_ASSERT(start <= source_byte_length); | |
899 RUNTIME_ASSERT(source_byte_length - start >= target_length); | |
900 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); | |
901 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); | |
902 CopyBytes(target_data, source_data + start, target_length); | |
903 return isolate->heap()->undefined_value(); | |
904 } | |
905 | |
906 | |
907 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) { | |
908 HandleScope scope(isolate); | |
909 DCHECK(args.length() == 1); | |
910 CONVERT_ARG_CHECKED(Object, object, 0); | |
911 return isolate->heap()->ToBoolean(object->IsJSArrayBufferView()); | |
912 } | |
913 | |
914 | |
915 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { | |
916 HandleScope scope(isolate); | |
917 DCHECK(args.length() == 1); | |
918 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); | |
919 if (array_buffer->backing_store() == NULL) { | |
920 CHECK(Smi::FromInt(0) == array_buffer->byte_length()); | |
921 return isolate->heap()->undefined_value(); | |
922 } | |
923 DCHECK(!array_buffer->is_external()); | |
924 void* backing_store = array_buffer->backing_store(); | |
925 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length()); | |
926 array_buffer->set_is_external(true); | |
927 Runtime::NeuterArrayBuffer(array_buffer); | |
928 V8::ArrayBufferAllocator()->Free(backing_store, byte_length); | |
929 return isolate->heap()->undefined_value(); | |
930 } | |
931 | |
932 | |
933 void Runtime::ArrayIdToTypeAndSize( | |
934 int arrayId, | |
935 ExternalArrayType* array_type, | |
936 ElementsKind* external_elements_kind, | |
937 ElementsKind* fixed_elements_kind, | |
938 size_t* element_size) { | |
939 switch (arrayId) { | |
940 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ | |
941 case ARRAY_ID_##TYPE: \ | |
942 *array_type = kExternal##Type##Array; \ | |
943 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \ | |
944 *fixed_elements_kind = TYPE##_ELEMENTS; \ | |
945 *element_size = size; \ | |
946 break; | |
947 | |
948 TYPED_ARRAYS(ARRAY_ID_CASE) | |
949 #undef ARRAY_ID_CASE | |
950 | |
951 default: | |
952 UNREACHABLE(); | |
953 } | |
954 } | |
955 | |
956 | |
957 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { | |
958 HandleScope scope(isolate); | |
959 DCHECK(args.length() == 5); | |
960 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); | |
961 CONVERT_SMI_ARG_CHECKED(arrayId, 1); | |
962 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2); | |
963 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3); | |
964 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4); | |
965 | |
966 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && | |
967 arrayId <= Runtime::ARRAY_ID_LAST); | |
968 | |
969 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. | |
970 size_t element_size = 1; // Bogus initialization. | |
971 ElementsKind external_elements_kind = | |
972 EXTERNAL_INT8_ELEMENTS; // Bogus initialization. | |
973 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. | |
974 Runtime::ArrayIdToTypeAndSize(arrayId, | |
975 &array_type, | |
976 &external_elements_kind, | |
977 &fixed_elements_kind, | |
978 &element_size); | |
979 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); | |
980 | |
981 size_t byte_offset = 0; | |
982 size_t byte_length = 0; | |
983 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset)); | |
984 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length)); | |
985 | |
986 if (maybe_buffer->IsJSArrayBuffer()) { | |
987 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); | |
988 size_t array_buffer_byte_length = | |
989 NumberToSize(isolate, buffer->byte_length()); | |
990 RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length); | |
991 RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length); | |
992 } else { | |
993 RUNTIME_ASSERT(maybe_buffer->IsNull()); | |
994 } | |
995 | |
996 RUNTIME_ASSERT(byte_length % element_size == 0); | |
997 size_t length = byte_length / element_size; | |
998 | |
999 if (length > static_cast<unsigned>(Smi::kMaxValue)) { | |
1000 THROW_NEW_ERROR_RETURN_FAILURE( | |
1001 isolate, NewRangeError("invalid_typed_array_length", | |
1002 HandleVector<Object>(NULL, 0))); | |
1003 } | |
1004 | |
1005 // All checks are done, now we can modify objects. | |
1006 | |
1007 DCHECK(holder->GetInternalFieldCount() == | |
1008 v8::ArrayBufferView::kInternalFieldCount); | |
1009 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { | |
1010 holder->SetInternalField(i, Smi::FromInt(0)); | |
1011 } | |
1012 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); | |
1013 holder->set_length(*length_obj); | |
1014 holder->set_byte_offset(*byte_offset_object); | |
1015 holder->set_byte_length(*byte_length_object); | |
1016 | |
1017 if (!maybe_buffer->IsNull()) { | |
1018 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); | |
1019 holder->set_buffer(*buffer); | |
1020 holder->set_weak_next(buffer->weak_first_view()); | |
1021 buffer->set_weak_first_view(*holder); | |
1022 | |
1023 Handle<ExternalArray> elements = | |
1024 isolate->factory()->NewExternalArray( | |
1025 static_cast<int>(length), array_type, | |
1026 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); | |
1027 Handle<Map> map = | |
1028 JSObject::GetElementsTransitionMap(holder, external_elements_kind); | |
1029 JSObject::SetMapAndElements(holder, map, elements); | |
1030 DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind())); | |
1031 } else { | |
1032 holder->set_buffer(Smi::FromInt(0)); | |
1033 holder->set_weak_next(isolate->heap()->undefined_value()); | |
1034 Handle<FixedTypedArrayBase> elements = | |
1035 isolate->factory()->NewFixedTypedArray( | |
1036 static_cast<int>(length), array_type); | |
1037 holder->set_elements(*elements); | |
1038 } | |
1039 return isolate->heap()->undefined_value(); | |
1040 } | |
1041 | |
1042 | |
1043 // Initializes a typed array from an array-like object. | |
1044 // If an array-like object happens to be a typed array of the same type, | |
1045 // initializes backing store using memove. | |
1046 // | |
1047 // Returns true if backing store was initialized or false otherwise. | |
1048 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { | |
1049 HandleScope scope(isolate); | |
1050 DCHECK(args.length() == 4); | |
1051 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); | |
1052 CONVERT_SMI_ARG_CHECKED(arrayId, 1); | |
1053 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); | |
1054 CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); | |
1055 | |
1056 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && | |
1057 arrayId <= Runtime::ARRAY_ID_LAST); | |
1058 | |
1059 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. | |
1060 size_t element_size = 1; // Bogus initialization. | |
1061 ElementsKind external_elements_kind = | |
1062 EXTERNAL_INT8_ELEMENTS; // Bogus intialization. | |
1063 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. | |
1064 Runtime::ArrayIdToTypeAndSize(arrayId, | |
1065 &array_type, | |
1066 &external_elements_kind, | |
1067 &fixed_elements_kind, | |
1068 &element_size); | |
1069 | |
1070 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); | |
1071 | |
1072 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); | |
1073 if (source->IsJSTypedArray() && | |
1074 JSTypedArray::cast(*source)->type() == array_type) { | |
1075 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate); | |
1076 } | |
1077 size_t length = 0; | |
1078 RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length)); | |
1079 | |
1080 if ((length > static_cast<unsigned>(Smi::kMaxValue)) || | |
1081 (length > (kMaxInt / element_size))) { | |
1082 THROW_NEW_ERROR_RETURN_FAILURE( | |
1083 isolate, NewRangeError("invalid_typed_array_length", | |
1084 HandleVector<Object>(NULL, 0))); | |
1085 } | |
1086 size_t byte_length = length * element_size; | |
1087 | |
1088 DCHECK(holder->GetInternalFieldCount() == | |
1089 v8::ArrayBufferView::kInternalFieldCount); | |
1090 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { | |
1091 holder->SetInternalField(i, Smi::FromInt(0)); | |
1092 } | |
1093 | |
1094 // NOTE: not initializing backing store. | |
1095 // We assume that the caller of this function will initialize holder | |
1096 // with the loop | |
1097 // for(i = 0; i < length; i++) { holder[i] = source[i]; } | |
1098 // We assume that the caller of this function is always a typed array | |
1099 // constructor. | |
1100 // If source is a typed array, this loop will always run to completion, | |
1101 // so we are sure that the backing store will be initialized. | |
1102 // Otherwise, the indexing operation might throw, so the loop will not | |
1103 // run to completion and the typed array might remain partly initialized. | |
1104 // However we further assume that the caller of this function is a typed array | |
1105 // constructor, and the exception will propagate out of the constructor, | |
1106 // therefore uninitialized memory will not be accessible by a user program. | |
1107 // | |
1108 // TODO(dslomov): revise this once we support subclassing. | |
1109 | |
1110 if (!Runtime::SetupArrayBufferAllocatingData( | |
1111 isolate, buffer, byte_length, false)) { | |
1112 THROW_NEW_ERROR_RETURN_FAILURE( | |
1113 isolate, NewRangeError("invalid_array_buffer_length", | |
1114 HandleVector<Object>(NULL, 0))); | |
1115 } | |
1116 | |
1117 holder->set_buffer(*buffer); | |
1118 holder->set_byte_offset(Smi::FromInt(0)); | |
1119 Handle<Object> byte_length_obj( | |
1120 isolate->factory()->NewNumberFromSize(byte_length)); | |
1121 holder->set_byte_length(*byte_length_obj); | |
1122 holder->set_length(*length_obj); | |
1123 holder->set_weak_next(buffer->weak_first_view()); | |
1124 buffer->set_weak_first_view(*holder); | |
1125 | |
1126 Handle<ExternalArray> elements = | |
1127 isolate->factory()->NewExternalArray( | |
1128 static_cast<int>(length), array_type, | |
1129 static_cast<uint8_t*>(buffer->backing_store())); | |
1130 Handle<Map> map = JSObject::GetElementsTransitionMap( | |
1131 holder, external_elements_kind); | |
1132 JSObject::SetMapAndElements(holder, map, elements); | |
1133 | |
1134 if (source->IsJSTypedArray()) { | |
1135 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); | |
1136 | |
1137 if (typed_array->type() == holder->type()) { | |
1138 uint8_t* backing_store = | |
1139 static_cast<uint8_t*>( | |
1140 typed_array->GetBuffer()->backing_store()); | |
1141 size_t source_byte_offset = | |
1142 NumberToSize(isolate, typed_array->byte_offset()); | |
1143 memcpy( | |
1144 buffer->backing_store(), | |
1145 backing_store + source_byte_offset, | |
1146 byte_length); | |
1147 return isolate->heap()->true_value(); | |
1148 } | |
1149 } | |
1150 | |
1151 return isolate->heap()->false_value(); | |
1152 } | |
1153 | |
1154 | |
1155 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \ | |
1156 RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \ | |
1157 HandleScope scope(isolate); \ | |
1158 DCHECK(args.length() == 1); \ | |
1159 CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \ | |
1160 return holder->accessor(); \ | |
1161 } | |
1162 | |
1163 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length) | |
1164 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset) | |
1165 BUFFER_VIEW_GETTER(TypedArray, Length, length) | |
1166 BUFFER_VIEW_GETTER(DataView, Buffer, buffer) | |
1167 | |
1168 #undef BUFFER_VIEW_GETTER | |
1169 | |
1170 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { | |
1171 HandleScope scope(isolate); | |
1172 DCHECK(args.length() == 1); | |
1173 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); | |
1174 return *holder->GetBuffer(); | |
1175 } | |
1176 | |
1177 | |
1178 // Return codes for Runtime_TypedArraySetFastCases. | |
1179 // Should be synchronized with typedarray.js natives. | |
1180 enum TypedArraySetResultCodes { | |
1181 // Set from typed array of the same type. | |
1182 // This is processed by TypedArraySetFastCases | |
1183 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, | |
1184 // Set from typed array of the different type, overlapping in memory. | |
1185 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, | |
1186 // Set from typed array of the different type, non-overlapping. | |
1187 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, | |
1188 // Set from non-typed array. | |
1189 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 | |
1190 }; | |
1191 | |
1192 | |
1193 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { | |
1194 HandleScope scope(isolate); | |
1195 DCHECK(args.length() == 3); | |
1196 if (!args[0]->IsJSTypedArray()) { | |
1197 THROW_NEW_ERROR_RETURN_FAILURE( | |
1198 isolate, | |
1199 NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0))); | |
1200 } | |
1201 | |
1202 if (!args[1]->IsJSTypedArray()) | |
1203 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); | |
1204 | |
1205 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); | |
1206 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); | |
1207 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2); | |
1208 | |
1209 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); | |
1210 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); | |
1211 size_t offset = 0; | |
1212 RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset)); | |
1213 size_t target_length = NumberToSize(isolate, target->length()); | |
1214 size_t source_length = NumberToSize(isolate, source->length()); | |
1215 size_t target_byte_length = NumberToSize(isolate, target->byte_length()); | |
1216 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); | |
1217 if (offset > target_length || offset + source_length > target_length || | |
1218 offset + source_length < offset) { // overflow | |
1219 THROW_NEW_ERROR_RETURN_FAILURE( | |
1220 isolate, NewRangeError("typed_array_set_source_too_large", | |
1221 HandleVector<Object>(NULL, 0))); | |
1222 } | |
1223 | |
1224 size_t target_offset = NumberToSize(isolate, target->byte_offset()); | |
1225 size_t source_offset = NumberToSize(isolate, source->byte_offset()); | |
1226 uint8_t* target_base = | |
1227 static_cast<uint8_t*>( | |
1228 target->GetBuffer()->backing_store()) + target_offset; | |
1229 uint8_t* source_base = | |
1230 static_cast<uint8_t*>( | |
1231 source->GetBuffer()->backing_store()) + source_offset; | |
1232 | |
1233 // Typed arrays of the same type: use memmove. | |
1234 if (target->type() == source->type()) { | |
1235 memmove(target_base + offset * target->element_size(), | |
1236 source_base, source_byte_length); | |
1237 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); | |
1238 } | |
1239 | |
1240 // Typed arrays of different types over the same backing store | |
1241 if ((source_base <= target_base && | |
1242 source_base + source_byte_length > target_base) || | |
1243 (target_base <= source_base && | |
1244 target_base + target_byte_length > source_base)) { | |
1245 // We do not support overlapping ArrayBuffers | |
1246 DCHECK( | |
1247 target->GetBuffer()->backing_store() == | |
1248 source->GetBuffer()->backing_store()); | |
1249 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); | |
1250 } else { // Non-overlapping typed arrays | |
1251 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); | |
1252 } | |
1253 } | |
1254 | |
1255 | |
1256 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) { | |
1257 DCHECK(args.length() == 0); | |
1258 DCHECK_OBJECT_SIZE( | |
1259 FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset); | |
1260 return Smi::FromInt(FLAG_typed_array_max_size_in_heap); | |
1261 } | |
1262 | |
1263 | |
1264 RUNTIME_FUNCTION(Runtime_DataViewInitialize) { | |
1265 HandleScope scope(isolate); | |
1266 DCHECK(args.length() == 4); | |
1267 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); | |
1268 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); | |
1269 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2); | |
1270 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3); | |
1271 | |
1272 DCHECK(holder->GetInternalFieldCount() == | |
1273 v8::ArrayBufferView::kInternalFieldCount); | |
1274 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { | |
1275 holder->SetInternalField(i, Smi::FromInt(0)); | |
1276 } | |
1277 size_t buffer_length = 0; | |
1278 size_t offset = 0; | |
1279 size_t length = 0; | |
1280 RUNTIME_ASSERT( | |
1281 TryNumberToSize(isolate, buffer->byte_length(), &buffer_length)); | |
1282 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset)); | |
1283 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length)); | |
1284 | |
1285 // TODO(jkummerow): When we have a "safe numerics" helper class, use it here. | |
1286 // Entire range [offset, offset + length] must be in bounds. | |
1287 RUNTIME_ASSERT(offset <= buffer_length); | |
1288 RUNTIME_ASSERT(offset + length <= buffer_length); | |
1289 // No overflow. | |
1290 RUNTIME_ASSERT(offset + length >= offset); | |
1291 | |
1292 holder->set_buffer(*buffer); | |
1293 holder->set_byte_offset(*byte_offset); | |
1294 holder->set_byte_length(*byte_length); | |
1295 | |
1296 holder->set_weak_next(buffer->weak_first_view()); | |
1297 buffer->set_weak_first_view(*holder); | |
1298 | |
1299 return isolate->heap()->undefined_value(); | |
1300 } | |
1301 | |
1302 | |
1303 inline static bool NeedToFlipBytes(bool is_little_endian) { | |
1304 #ifdef V8_TARGET_LITTLE_ENDIAN | |
1305 return !is_little_endian; | |
1306 #else | |
1307 return is_little_endian; | |
1308 #endif | |
1309 } | |
1310 | |
1311 | |
1312 template<int n> | |
1313 inline void CopyBytes(uint8_t* target, uint8_t* source) { | |
1314 for (int i = 0; i < n; i++) { | |
1315 *(target++) = *(source++); | |
1316 } | |
1317 } | |
1318 | |
1319 | |
1320 template<int n> | |
1321 inline void FlipBytes(uint8_t* target, uint8_t* source) { | |
1322 source = source + (n-1); | |
1323 for (int i = 0; i < n; i++) { | |
1324 *(target++) = *(source--); | |
1325 } | |
1326 } | |
1327 | |
1328 | |
1329 template<typename T> | |
1330 inline static bool DataViewGetValue( | |
1331 Isolate* isolate, | |
1332 Handle<JSDataView> data_view, | |
1333 Handle<Object> byte_offset_obj, | |
1334 bool is_little_endian, | |
1335 T* result) { | |
1336 size_t byte_offset = 0; | |
1337 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { | |
1338 return false; | |
1339 } | |
1340 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); | |
1341 | |
1342 size_t data_view_byte_offset = | |
1343 NumberToSize(isolate, data_view->byte_offset()); | |
1344 size_t data_view_byte_length = | |
1345 NumberToSize(isolate, data_view->byte_length()); | |
1346 if (byte_offset + sizeof(T) > data_view_byte_length || | |
1347 byte_offset + sizeof(T) < byte_offset) { // overflow | |
1348 return false; | |
1349 } | |
1350 | |
1351 union Value { | |
1352 T data; | |
1353 uint8_t bytes[sizeof(T)]; | |
1354 }; | |
1355 | |
1356 Value value; | |
1357 size_t buffer_offset = data_view_byte_offset + byte_offset; | |
1358 DCHECK( | |
1359 NumberToSize(isolate, buffer->byte_length()) | |
1360 >= buffer_offset + sizeof(T)); | |
1361 uint8_t* source = | |
1362 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; | |
1363 if (NeedToFlipBytes(is_little_endian)) { | |
1364 FlipBytes<sizeof(T)>(value.bytes, source); | |
1365 } else { | |
1366 CopyBytes<sizeof(T)>(value.bytes, source); | |
1367 } | |
1368 *result = value.data; | |
1369 return true; | |
1370 } | |
1371 | |
1372 | |
1373 template<typename T> | |
1374 static bool DataViewSetValue( | |
1375 Isolate* isolate, | |
1376 Handle<JSDataView> data_view, | |
1377 Handle<Object> byte_offset_obj, | |
1378 bool is_little_endian, | |
1379 T data) { | |
1380 size_t byte_offset = 0; | |
1381 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { | |
1382 return false; | |
1383 } | |
1384 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); | |
1385 | |
1386 size_t data_view_byte_offset = | |
1387 NumberToSize(isolate, data_view->byte_offset()); | |
1388 size_t data_view_byte_length = | |
1389 NumberToSize(isolate, data_view->byte_length()); | |
1390 if (byte_offset + sizeof(T) > data_view_byte_length || | |
1391 byte_offset + sizeof(T) < byte_offset) { // overflow | |
1392 return false; | |
1393 } | |
1394 | |
1395 union Value { | |
1396 T data; | |
1397 uint8_t bytes[sizeof(T)]; | |
1398 }; | |
1399 | |
1400 Value value; | |
1401 value.data = data; | |
1402 size_t buffer_offset = data_view_byte_offset + byte_offset; | |
1403 DCHECK( | |
1404 NumberToSize(isolate, buffer->byte_length()) | |
1405 >= buffer_offset + sizeof(T)); | |
1406 uint8_t* target = | |
1407 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; | |
1408 if (NeedToFlipBytes(is_little_endian)) { | |
1409 FlipBytes<sizeof(T)>(target, value.bytes); | |
1410 } else { | |
1411 CopyBytes<sizeof(T)>(target, value.bytes); | |
1412 } | |
1413 return true; | |
1414 } | |
1415 | |
1416 | |
1417 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ | |
1418 RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \ | |
1419 HandleScope scope(isolate); \ | |
1420 DCHECK(args.length() == 3); \ | |
1421 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ | |
1422 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ | |
1423 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ | |
1424 Type result; \ | |
1425 if (DataViewGetValue(isolate, holder, offset, is_little_endian, \ | |
1426 &result)) { \ | |
1427 return *isolate->factory()->Converter(result); \ | |
1428 } else { \ | |
1429 THROW_NEW_ERROR_RETURN_FAILURE( \ | |
1430 isolate, NewRangeError("invalid_data_view_accessor_offset", \ | |
1431 HandleVector<Object>(NULL, 0))); \ | |
1432 } \ | |
1433 } | |
1434 | |
1435 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint) | |
1436 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt) | |
1437 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint) | |
1438 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt) | |
1439 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint) | |
1440 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt) | |
1441 DATA_VIEW_GETTER(Float32, float, NewNumber) | |
1442 DATA_VIEW_GETTER(Float64, double, NewNumber) | |
1443 | |
1444 #undef DATA_VIEW_GETTER | |
1445 | |
1446 | |
1447 template <typename T> | |
1448 static T DataViewConvertValue(double value); | |
1449 | |
1450 | |
1451 template <> | |
1452 int8_t DataViewConvertValue<int8_t>(double value) { | |
1453 return static_cast<int8_t>(DoubleToInt32(value)); | |
1454 } | |
1455 | |
1456 | |
1457 template <> | |
1458 int16_t DataViewConvertValue<int16_t>(double value) { | |
1459 return static_cast<int16_t>(DoubleToInt32(value)); | |
1460 } | |
1461 | |
1462 | |
1463 template <> | |
1464 int32_t DataViewConvertValue<int32_t>(double value) { | |
1465 return DoubleToInt32(value); | |
1466 } | |
1467 | |
1468 | |
1469 template <> | |
1470 uint8_t DataViewConvertValue<uint8_t>(double value) { | |
1471 return static_cast<uint8_t>(DoubleToUint32(value)); | |
1472 } | |
1473 | |
1474 | |
1475 template <> | |
1476 uint16_t DataViewConvertValue<uint16_t>(double value) { | |
1477 return static_cast<uint16_t>(DoubleToUint32(value)); | |
1478 } | |
1479 | |
1480 | |
1481 template <> | |
1482 uint32_t DataViewConvertValue<uint32_t>(double value) { | |
1483 return DoubleToUint32(value); | |
1484 } | |
1485 | |
1486 | |
1487 template <> | |
1488 float DataViewConvertValue<float>(double value) { | |
1489 return static_cast<float>(value); | |
1490 } | |
1491 | |
1492 | |
1493 template <> | |
1494 double DataViewConvertValue<double>(double value) { | |
1495 return value; | |
1496 } | |
1497 | |
1498 | |
1499 #define DATA_VIEW_SETTER(TypeName, Type) \ | |
1500 RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \ | |
1501 HandleScope scope(isolate); \ | |
1502 DCHECK(args.length() == 4); \ | |
1503 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ | |
1504 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ | |
1505 CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \ | |
1506 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ | |
1507 Type v = DataViewConvertValue<Type>(value->Number()); \ | |
1508 if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \ | |
1509 return isolate->heap()->undefined_value(); \ | |
1510 } else { \ | |
1511 THROW_NEW_ERROR_RETURN_FAILURE( \ | |
1512 isolate, NewRangeError("invalid_data_view_accessor_offset", \ | |
1513 HandleVector<Object>(NULL, 0))); \ | |
1514 } \ | |
1515 } | |
1516 | |
1517 DATA_VIEW_SETTER(Uint8, uint8_t) | |
1518 DATA_VIEW_SETTER(Int8, int8_t) | |
1519 DATA_VIEW_SETTER(Uint16, uint16_t) | |
1520 DATA_VIEW_SETTER(Int16, int16_t) | |
1521 DATA_VIEW_SETTER(Uint32, uint32_t) | |
1522 DATA_VIEW_SETTER(Int32, int32_t) | |
1523 DATA_VIEW_SETTER(Float32, float) | |
1524 DATA_VIEW_SETTER(Float64, double) | |
1525 | |
1526 #undef DATA_VIEW_SETTER | |
1527 | |
1528 | |
1529 RUNTIME_FUNCTION(Runtime_SetInitialize) { | |
1530 HandleScope scope(isolate); | |
1531 DCHECK(args.length() == 1); | |
1532 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1533 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); | |
1534 holder->set_table(*table); | |
1535 return *holder; | |
1536 } | |
1537 | |
1538 | |
1539 RUNTIME_FUNCTION(Runtime_SetAdd) { | |
1540 HandleScope scope(isolate); | |
1541 DCHECK(args.length() == 2); | |
1542 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1543 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1544 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); | |
1545 table = OrderedHashSet::Add(table, key); | |
1546 holder->set_table(*table); | |
1547 return *holder; | |
1548 } | |
1549 | |
1550 | |
1551 RUNTIME_FUNCTION(Runtime_SetHas) { | |
1552 HandleScope scope(isolate); | |
1553 DCHECK(args.length() == 2); | |
1554 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1555 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1556 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); | |
1557 return isolate->heap()->ToBoolean(table->Contains(key)); | |
1558 } | |
1559 | |
1560 | |
1561 RUNTIME_FUNCTION(Runtime_SetDelete) { | |
1562 HandleScope scope(isolate); | |
1563 DCHECK(args.length() == 2); | |
1564 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1565 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1566 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); | |
1567 bool was_present = false; | |
1568 table = OrderedHashSet::Remove(table, key, &was_present); | |
1569 holder->set_table(*table); | |
1570 return isolate->heap()->ToBoolean(was_present); | |
1571 } | |
1572 | |
1573 | |
1574 RUNTIME_FUNCTION(Runtime_SetClear) { | |
1575 HandleScope scope(isolate); | |
1576 DCHECK(args.length() == 1); | |
1577 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1578 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); | |
1579 table = OrderedHashSet::Clear(table); | |
1580 holder->set_table(*table); | |
1581 return isolate->heap()->undefined_value(); | |
1582 } | |
1583 | |
1584 | |
1585 RUNTIME_FUNCTION(Runtime_SetGetSize) { | |
1586 HandleScope scope(isolate); | |
1587 DCHECK(args.length() == 1); | |
1588 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); | |
1589 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); | |
1590 return Smi::FromInt(table->NumberOfElements()); | |
1591 } | |
1592 | |
1593 | |
1594 RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) { | |
1595 HandleScope scope(isolate); | |
1596 DCHECK(args.length() == 3); | |
1597 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); | |
1598 CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1); | |
1599 CONVERT_SMI_ARG_CHECKED(kind, 2) | |
1600 RUNTIME_ASSERT(kind == JSSetIterator::kKindValues || | |
1601 kind == JSSetIterator::kKindEntries); | |
1602 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); | |
1603 holder->set_table(*table); | |
1604 holder->set_index(Smi::FromInt(0)); | |
1605 holder->set_kind(Smi::FromInt(kind)); | |
1606 return isolate->heap()->undefined_value(); | |
1607 } | |
1608 | |
1609 | |
1610 RUNTIME_FUNCTION(Runtime_SetIteratorNext) { | |
1611 SealHandleScope shs(isolate); | |
1612 DCHECK(args.length() == 2); | |
1613 CONVERT_ARG_CHECKED(JSSetIterator, holder, 0); | |
1614 CONVERT_ARG_CHECKED(JSArray, value_array, 1); | |
1615 return holder->Next(value_array); | |
1616 } | |
1617 | |
1618 | |
1619 RUNTIME_FUNCTION(Runtime_MapInitialize) { | |
1620 HandleScope scope(isolate); | |
1621 DCHECK(args.length() == 1); | |
1622 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1623 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); | |
1624 holder->set_table(*table); | |
1625 return *holder; | |
1626 } | |
1627 | |
1628 | |
1629 RUNTIME_FUNCTION(Runtime_MapGet) { | |
1630 HandleScope scope(isolate); | |
1631 DCHECK(args.length() == 2); | |
1632 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1633 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1634 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1635 Handle<Object> lookup(table->Lookup(key), isolate); | |
1636 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; | |
1637 } | |
1638 | |
1639 | |
1640 RUNTIME_FUNCTION(Runtime_MapHas) { | |
1641 HandleScope scope(isolate); | |
1642 DCHECK(args.length() == 2); | |
1643 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1644 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1645 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1646 Handle<Object> lookup(table->Lookup(key), isolate); | |
1647 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); | |
1648 } | |
1649 | |
1650 | |
1651 RUNTIME_FUNCTION(Runtime_MapDelete) { | |
1652 HandleScope scope(isolate); | |
1653 DCHECK(args.length() == 2); | |
1654 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1655 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1656 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1657 bool was_present = false; | |
1658 Handle<OrderedHashMap> new_table = | |
1659 OrderedHashMap::Remove(table, key, &was_present); | |
1660 holder->set_table(*new_table); | |
1661 return isolate->heap()->ToBoolean(was_present); | |
1662 } | |
1663 | |
1664 | |
1665 RUNTIME_FUNCTION(Runtime_MapClear) { | |
1666 HandleScope scope(isolate); | |
1667 DCHECK(args.length() == 1); | |
1668 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1669 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1670 table = OrderedHashMap::Clear(table); | |
1671 holder->set_table(*table); | |
1672 return isolate->heap()->undefined_value(); | |
1673 } | |
1674 | |
1675 | |
1676 RUNTIME_FUNCTION(Runtime_MapSet) { | |
1677 HandleScope scope(isolate); | |
1678 DCHECK(args.length() == 3); | |
1679 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1680 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1681 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
1682 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1683 Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value); | |
1684 holder->set_table(*new_table); | |
1685 return *holder; | |
1686 } | |
1687 | |
1688 | |
1689 RUNTIME_FUNCTION(Runtime_MapGetSize) { | |
1690 HandleScope scope(isolate); | |
1691 DCHECK(args.length() == 1); | |
1692 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); | |
1693 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); | |
1694 return Smi::FromInt(table->NumberOfElements()); | |
1695 } | |
1696 | |
1697 | |
1698 RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) { | |
1699 HandleScope scope(isolate); | |
1700 DCHECK(args.length() == 3); | |
1701 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); | |
1702 CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1); | |
1703 CONVERT_SMI_ARG_CHECKED(kind, 2) | |
1704 RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys | |
1705 || kind == JSMapIterator::kKindValues | |
1706 || kind == JSMapIterator::kKindEntries); | |
1707 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); | |
1708 holder->set_table(*table); | |
1709 holder->set_index(Smi::FromInt(0)); | |
1710 holder->set_kind(Smi::FromInt(kind)); | |
1711 return isolate->heap()->undefined_value(); | |
1712 } | |
1713 | |
1714 | |
1715 RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) { | |
1716 HandleScope scope(isolate); | |
1717 DCHECK(args.length() == 1); | |
1718 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); | |
1719 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); | |
1720 Handle<FixedArray> entries = | |
1721 isolate->factory()->NewFixedArray(table->NumberOfElements() * 2); | |
1722 { | |
1723 DisallowHeapAllocation no_gc; | |
1724 int number_of_non_hole_elements = 0; | |
1725 for (int i = 0; i < table->Capacity(); i++) { | |
1726 Handle<Object> key(table->KeyAt(i), isolate); | |
1727 if (table->IsKey(*key)) { | |
1728 entries->set(number_of_non_hole_elements++, *key); | |
1729 Object* value = table->Lookup(key); | |
1730 entries->set(number_of_non_hole_elements++, value); | |
1731 } | |
1732 } | |
1733 DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements); | |
1734 } | |
1735 return *isolate->factory()->NewJSArrayWithElements(entries); | |
1736 } | |
1737 | |
1738 | |
1739 RUNTIME_FUNCTION(Runtime_MapIteratorNext) { | |
1740 SealHandleScope shs(isolate); | |
1741 DCHECK(args.length() == 2); | |
1742 CONVERT_ARG_CHECKED(JSMapIterator, holder, 0); | |
1743 CONVERT_ARG_CHECKED(JSArray, value_array, 1); | |
1744 return holder->Next(value_array); | |
1745 } | |
1746 | |
1747 | |
1748 static Handle<JSWeakCollection> WeakCollectionInitialize( | |
1749 Isolate* isolate, | |
1750 Handle<JSWeakCollection> weak_collection) { | |
1751 DCHECK(weak_collection->map()->inobject_properties() == 0); | |
1752 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); | |
1753 weak_collection->set_table(*table); | |
1754 return weak_collection; | |
1755 } | |
1756 | |
1757 | |
1758 RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) { | |
1759 HandleScope scope(isolate); | |
1760 DCHECK(args.length() == 1); | |
1761 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); | |
1762 return *WeakCollectionInitialize(isolate, weak_collection); | |
1763 } | |
1764 | |
1765 | |
1766 RUNTIME_FUNCTION(Runtime_WeakCollectionGet) { | |
1767 HandleScope scope(isolate); | |
1768 DCHECK(args.length() == 2); | |
1769 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); | |
1770 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1771 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); | |
1772 Handle<ObjectHashTable> table( | |
1773 ObjectHashTable::cast(weak_collection->table())); | |
1774 RUNTIME_ASSERT(table->IsKey(*key)); | |
1775 Handle<Object> lookup(table->Lookup(key), isolate); | |
1776 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; | |
1777 } | |
1778 | |
1779 | |
1780 RUNTIME_FUNCTION(Runtime_WeakCollectionHas) { | |
1781 HandleScope scope(isolate); | |
1782 DCHECK(args.length() == 2); | |
1783 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); | |
1784 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1785 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); | |
1786 Handle<ObjectHashTable> table( | |
1787 ObjectHashTable::cast(weak_collection->table())); | |
1788 RUNTIME_ASSERT(table->IsKey(*key)); | |
1789 Handle<Object> lookup(table->Lookup(key), isolate); | |
1790 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); | |
1791 } | |
1792 | |
1793 | |
1794 RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) { | |
1795 HandleScope scope(isolate); | |
1796 DCHECK(args.length() == 2); | |
1797 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); | |
1798 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1799 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); | |
1800 Handle<ObjectHashTable> table(ObjectHashTable::cast( | |
1801 weak_collection->table())); | |
1802 RUNTIME_ASSERT(table->IsKey(*key)); | |
1803 bool was_present = false; | |
1804 Handle<ObjectHashTable> new_table = | |
1805 ObjectHashTable::Remove(table, key, &was_present); | |
1806 weak_collection->set_table(*new_table); | |
1807 return isolate->heap()->ToBoolean(was_present); | |
1808 } | |
1809 | |
1810 | |
1811 RUNTIME_FUNCTION(Runtime_WeakCollectionSet) { | |
1812 HandleScope scope(isolate); | |
1813 DCHECK(args.length() == 3); | |
1814 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); | |
1815 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
1816 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); | |
1817 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
1818 Handle<ObjectHashTable> table( | |
1819 ObjectHashTable::cast(weak_collection->table())); | |
1820 RUNTIME_ASSERT(table->IsKey(*key)); | |
1821 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); | |
1822 weak_collection->set_table(*new_table); | |
1823 return *weak_collection; | |
1824 } | |
1825 | |
1826 | |
1827 RUNTIME_FUNCTION(Runtime_GetWeakSetValues) { | |
1828 HandleScope scope(isolate); | |
1829 DCHECK(args.length() == 1); | |
1830 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); | |
1831 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); | |
1832 Handle<FixedArray> values = | |
1833 isolate->factory()->NewFixedArray(table->NumberOfElements()); | |
1834 { | |
1835 DisallowHeapAllocation no_gc; | |
1836 int number_of_non_hole_elements = 0; | |
1837 for (int i = 0; i < table->Capacity(); i++) { | |
1838 Handle<Object> key(table->KeyAt(i), isolate); | |
1839 if (table->IsKey(*key)) { | |
1840 values->set(number_of_non_hole_elements++, *key); | |
1841 } | |
1842 } | |
1843 DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements); | |
1844 } | |
1845 return *isolate->factory()->NewJSArrayWithElements(values); | |
1846 } | |
1847 | |
1848 | |
1849 RUNTIME_FUNCTION(Runtime_GetPrototype) { | |
1850 HandleScope scope(isolate); | |
1851 DCHECK(args.length() == 1); | |
1852 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); | |
1853 // We don't expect access checks to be needed on JSProxy objects. | |
1854 DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); | |
1855 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); | |
1856 do { | |
1857 if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() && | |
1858 !isolate->MayNamedAccess( | |
1859 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), | |
1860 isolate->factory()->proto_string(), v8::ACCESS_GET)) { | |
1861 isolate->ReportFailedAccessCheck( | |
1862 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), | |
1863 v8::ACCESS_GET); | |
1864 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
1865 return isolate->heap()->undefined_value(); | |
1866 } | |
1867 iter.AdvanceIgnoringProxies(); | |
1868 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
1869 return *PrototypeIterator::GetCurrent(iter); | |
1870 } | |
1871 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); | |
1872 return *PrototypeIterator::GetCurrent(iter); | |
1873 } | |
1874 | |
1875 | |
1876 static inline Handle<Object> GetPrototypeSkipHiddenPrototypes( | |
1877 Isolate* isolate, Handle<Object> receiver) { | |
1878 PrototypeIterator iter(isolate, receiver); | |
1879 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | |
1880 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
1881 return PrototypeIterator::GetCurrent(iter); | |
1882 } | |
1883 iter.Advance(); | |
1884 } | |
1885 return PrototypeIterator::GetCurrent(iter); | |
1886 } | |
1887 | |
1888 | |
1889 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { | |
1890 HandleScope scope(isolate); | |
1891 DCHECK(args.length() == 2); | |
1892 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
1893 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | |
1894 DCHECK(!obj->IsAccessCheckNeeded()); | |
1895 DCHECK(!obj->map()->is_observed()); | |
1896 Handle<Object> result; | |
1897 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1898 isolate, result, JSObject::SetPrototype(obj, prototype, false)); | |
1899 return *result; | |
1900 } | |
1901 | |
1902 | |
1903 RUNTIME_FUNCTION(Runtime_SetPrototype) { | |
1904 HandleScope scope(isolate); | |
1905 DCHECK(args.length() == 2); | |
1906 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
1907 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | |
1908 if (obj->IsAccessCheckNeeded() && | |
1909 !isolate->MayNamedAccess( | |
1910 obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) { | |
1911 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); | |
1912 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
1913 return isolate->heap()->undefined_value(); | |
1914 } | |
1915 if (obj->map()->is_observed()) { | |
1916 Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); | |
1917 Handle<Object> result; | |
1918 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1919 isolate, result, | |
1920 JSObject::SetPrototype(obj, prototype, true)); | |
1921 | |
1922 Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); | |
1923 if (!new_value->SameValue(*old_value)) { | |
1924 JSObject::EnqueueChangeRecord(obj, "setPrototype", | |
1925 isolate->factory()->proto_string(), | |
1926 old_value); | |
1927 } | |
1928 return *result; | |
1929 } | |
1930 Handle<Object> result; | |
1931 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1932 isolate, result, | |
1933 JSObject::SetPrototype(obj, prototype, true)); | |
1934 return *result; | |
1935 } | |
1936 | |
1937 | |
1938 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { | |
1939 HandleScope shs(isolate); | |
1940 DCHECK(args.length() == 2); | |
1941 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). | |
1942 CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); | |
1943 CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); | |
1944 PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER); | |
1945 while (true) { | |
1946 iter.AdvanceIgnoringProxies(); | |
1947 if (iter.IsAtEnd()) return isolate->heap()->false_value(); | |
1948 if (iter.IsAtEnd(O)) return isolate->heap()->true_value(); | |
1949 } | |
1950 } | |
1951 | |
1952 | |
1953 // Enumerator used as indices into the array returned from GetOwnProperty | |
1954 enum PropertyDescriptorIndices { | |
1955 IS_ACCESSOR_INDEX, | |
1956 VALUE_INDEX, | |
1957 GETTER_INDEX, | |
1958 SETTER_INDEX, | |
1959 WRITABLE_INDEX, | |
1960 ENUMERABLE_INDEX, | |
1961 CONFIGURABLE_INDEX, | |
1962 DESCRIPTOR_SIZE | |
1963 }; | |
1964 | |
1965 | |
1966 MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, | |
1967 Handle<JSObject> obj, | |
1968 Handle<Name> name) { | |
1969 Heap* heap = isolate->heap(); | |
1970 Factory* factory = isolate->factory(); | |
1971 | |
1972 PropertyAttributes attrs; | |
1973 uint32_t index = 0; | |
1974 Handle<Object> value; | |
1975 MaybeHandle<AccessorPair> maybe_accessors; | |
1976 // TODO(verwaest): Unify once indexed properties can be handled by the | |
1977 // LookupIterator. | |
1978 if (name->AsArrayIndex(&index)) { | |
1979 // Get attributes. | |
1980 Maybe<PropertyAttributes> maybe = | |
1981 JSReceiver::GetOwnElementAttribute(obj, index); | |
1982 if (!maybe.has_value) return MaybeHandle<Object>(); | |
1983 attrs = maybe.value; | |
1984 if (attrs == ABSENT) return factory->undefined_value(); | |
1985 | |
1986 // Get AccessorPair if present. | |
1987 maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index); | |
1988 | |
1989 // Get value if not an AccessorPair. | |
1990 if (maybe_accessors.is_null()) { | |
1991 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, | |
1992 Runtime::GetElementOrCharAt(isolate, obj, index), Object); | |
1993 } | |
1994 } else { | |
1995 // Get attributes. | |
1996 LookupIterator it(obj, name, LookupIterator::HIDDEN); | |
1997 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it); | |
1998 if (!maybe.has_value) return MaybeHandle<Object>(); | |
1999 attrs = maybe.value; | |
2000 if (attrs == ABSENT) return factory->undefined_value(); | |
2001 | |
2002 // Get AccessorPair if present. | |
2003 if (it.state() == LookupIterator::ACCESSOR && | |
2004 it.GetAccessors()->IsAccessorPair()) { | |
2005 maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors()); | |
2006 } | |
2007 | |
2008 // Get value if not an AccessorPair. | |
2009 if (maybe_accessors.is_null()) { | |
2010 ASSIGN_RETURN_ON_EXCEPTION( | |
2011 isolate, value, Object::GetProperty(&it), Object); | |
2012 } | |
2013 } | |
2014 DCHECK(!isolate->has_pending_exception()); | |
2015 Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE); | |
2016 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); | |
2017 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); | |
2018 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null())); | |
2019 | |
2020 Handle<AccessorPair> accessors; | |
2021 if (maybe_accessors.ToHandle(&accessors)) { | |
2022 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); | |
2023 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); | |
2024 elms->set(GETTER_INDEX, *getter); | |
2025 elms->set(SETTER_INDEX, *setter); | |
2026 } else { | |
2027 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); | |
2028 elms->set(VALUE_INDEX, *value); | |
2029 } | |
2030 | |
2031 return factory->NewJSArrayWithElements(elms); | |
2032 } | |
2033 | |
2034 | |
2035 // Returns an array with the property description: | |
2036 // if args[1] is not a property on args[0] | |
2037 // returns undefined | |
2038 // if args[1] is a data property on args[0] | |
2039 // [false, value, Writeable, Enumerable, Configurable] | |
2040 // if args[1] is an accessor on args[0] | |
2041 // [true, GetFunction, SetFunction, Enumerable, Configurable] | |
2042 RUNTIME_FUNCTION(Runtime_GetOwnProperty) { | |
2043 HandleScope scope(isolate); | |
2044 DCHECK(args.length() == 2); | |
2045 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
2046 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
2047 Handle<Object> result; | |
2048 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2049 isolate, result, GetOwnProperty(isolate, obj, name)); | |
2050 return *result; | |
2051 } | |
2052 | |
2053 | |
2054 RUNTIME_FUNCTION(Runtime_PreventExtensions) { | |
2055 HandleScope scope(isolate); | |
2056 DCHECK(args.length() == 1); | |
2057 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
2058 Handle<Object> result; | |
2059 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2060 isolate, result, JSObject::PreventExtensions(obj)); | |
2061 return *result; | |
2062 } | |
2063 | |
2064 | |
2065 RUNTIME_FUNCTION(Runtime_ToMethod) { | |
2066 HandleScope scope(isolate); | |
2067 DCHECK(args.length() == 2); | |
2068 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
2069 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); | |
2070 Handle<JSFunction> clone = JSFunction::CloneClosure(fun); | |
2071 Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol()); | |
2072 JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol, | |
2073 home_object, DONT_ENUM).Assert(); | |
2074 return *clone; | |
2075 } | |
2076 | |
2077 | |
2078 RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) { | |
2079 DCHECK(args.length() == 0); | |
2080 return isolate->heap()->home_object_symbol(); | |
2081 } | |
2082 | |
2083 | |
2084 RUNTIME_FUNCTION(Runtime_LoadFromSuper) { | |
2085 HandleScope scope(isolate); | |
2086 DCHECK(args.length() == 3); | |
2087 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0); | |
2088 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); | |
2089 CONVERT_ARG_HANDLE_CHECKED(Name, name, 2); | |
2090 | |
2091 if (home_object->IsAccessCheckNeeded() && | |
2092 !isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) { | |
2093 isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET); | |
2094 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
2095 } | |
2096 | |
2097 PrototypeIterator iter(isolate, home_object); | |
2098 Handle<Object> proto = PrototypeIterator::GetCurrent(iter); | |
2099 if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); | |
2100 | |
2101 LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto)); | |
2102 Handle<Object> result; | |
2103 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it)); | |
2104 return *result; | |
2105 } | |
2106 | |
2107 | |
2108 RUNTIME_FUNCTION(Runtime_IsExtensible) { | |
2109 SealHandleScope shs(isolate); | |
2110 DCHECK(args.length() == 1); | |
2111 CONVERT_ARG_CHECKED(JSObject, obj, 0); | |
2112 if (obj->IsJSGlobalProxy()) { | |
2113 PrototypeIterator iter(isolate, obj); | |
2114 if (iter.IsAtEnd()) return isolate->heap()->false_value(); | |
2115 DCHECK(iter.GetCurrent()->IsJSGlobalObject()); | |
2116 obj = JSObject::cast(iter.GetCurrent()); | |
2117 } | |
2118 return isolate->heap()->ToBoolean(obj->map()->is_extensible()); | |
2119 } | |
2120 | |
2121 | |
2122 RUNTIME_FUNCTION(Runtime_RegExpCompile) { | |
2123 HandleScope scope(isolate); | |
2124 DCHECK(args.length() == 3); | |
2125 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); | |
2126 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); | |
2127 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); | |
2128 Handle<Object> result; | |
2129 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2130 isolate, result, RegExpImpl::Compile(re, pattern, flags)); | |
2131 return *result; | |
2132 } | |
2133 | |
2134 | |
2135 RUNTIME_FUNCTION(Runtime_CreateApiFunction) { | |
2136 HandleScope scope(isolate); | |
2137 DCHECK(args.length() == 2); | |
2138 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); | |
2139 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | |
2140 return *isolate->factory()->CreateApiFunction(data, prototype); | |
2141 } | |
2142 | |
2143 | |
2144 RUNTIME_FUNCTION(Runtime_IsTemplate) { | |
2145 SealHandleScope shs(isolate); | |
2146 DCHECK(args.length() == 1); | |
2147 CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0); | |
2148 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); | |
2149 return isolate->heap()->ToBoolean(result); | |
2150 } | |
2151 | |
2152 | |
2153 RUNTIME_FUNCTION(Runtime_GetTemplateField) { | |
2154 SealHandleScope shs(isolate); | |
2155 DCHECK(args.length() == 2); | |
2156 CONVERT_ARG_CHECKED(HeapObject, templ, 0); | |
2157 CONVERT_SMI_ARG_CHECKED(index, 1); | |
2158 int offset = index * kPointerSize + HeapObject::kHeaderSize; | |
2159 InstanceType type = templ->map()->instance_type(); | |
2160 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || | |
2161 type == OBJECT_TEMPLATE_INFO_TYPE); | |
2162 RUNTIME_ASSERT(offset > 0); | |
2163 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { | |
2164 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); | |
2165 } else { | |
2166 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); | |
2167 } | |
2168 return *HeapObject::RawField(templ, offset); | |
2169 } | |
2170 | |
2171 | |
2172 RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { | |
2173 HandleScope scope(isolate); | |
2174 DCHECK(args.length() == 1); | |
2175 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); | |
2176 Handle<Map> old_map(object->map()); | |
2177 bool needs_access_checks = old_map->is_access_check_needed(); | |
2178 if (needs_access_checks) { | |
2179 // Copy map so it won't interfere constructor's initial map. | |
2180 Handle<Map> new_map = Map::Copy(old_map); | |
2181 new_map->set_is_access_check_needed(false); | |
2182 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); | |
2183 } | |
2184 return isolate->heap()->ToBoolean(needs_access_checks); | |
2185 } | |
2186 | |
2187 | |
2188 RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { | |
2189 HandleScope scope(isolate); | |
2190 DCHECK(args.length() == 1); | |
2191 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
2192 Handle<Map> old_map(object->map()); | |
2193 RUNTIME_ASSERT(!old_map->is_access_check_needed()); | |
2194 // Copy map so it won't interfere constructor's initial map. | |
2195 Handle<Map> new_map = Map::Copy(old_map); | |
2196 new_map->set_is_access_check_needed(true); | |
2197 JSObject::MigrateToMap(object, new_map); | |
2198 return isolate->heap()->undefined_value(); | |
2199 } | |
2200 | |
2201 | |
2202 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) { | |
2203 HandleScope scope(isolate); | |
2204 Handle<Object> args[1] = { name }; | |
2205 THROW_NEW_ERROR_RETURN_FAILURE( | |
2206 isolate, NewTypeError("var_redeclaration", HandleVector(args, 1))); | |
2207 } | |
2208 | |
2209 | |
2210 // May throw a RedeclarationError. | |
2211 static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global, | |
2212 Handle<String> name, Handle<Object> value, | |
2213 PropertyAttributes attr, bool is_var, | |
2214 bool is_const, bool is_function) { | |
2215 // Do the lookup own properties only, see ES5 erratum. | |
2216 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); | |
2217 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
2218 if (!maybe.has_value) return isolate->heap()->exception(); | |
2219 | |
2220 if (it.IsFound()) { | |
2221 PropertyAttributes old_attributes = maybe.value; | |
2222 // The name was declared before; check for conflicting re-declarations. | |
2223 if (is_const) return ThrowRedeclarationError(isolate, name); | |
2224 | |
2225 // Skip var re-declarations. | |
2226 if (is_var) return isolate->heap()->undefined_value(); | |
2227 | |
2228 DCHECK(is_function); | |
2229 if ((old_attributes & DONT_DELETE) != 0) { | |
2230 // Only allow reconfiguring globals to functions in user code (no | |
2231 // natives, which are marked as read-only). | |
2232 DCHECK((attr & READ_ONLY) == 0); | |
2233 | |
2234 // Check whether we can reconfigure the existing property into a | |
2235 // function. | |
2236 PropertyDetails old_details = it.property_details(); | |
2237 // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo, | |
2238 // which are actually data properties, not accessor properties. | |
2239 if (old_details.IsReadOnly() || old_details.IsDontEnum() || | |
2240 old_details.type() == CALLBACKS) { | |
2241 return ThrowRedeclarationError(isolate, name); | |
2242 } | |
2243 // If the existing property is not configurable, keep its attributes. Do | |
2244 attr = old_attributes; | |
2245 } | |
2246 } | |
2247 | |
2248 // Define or redefine own property. | |
2249 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2250 global, name, value, attr)); | |
2251 | |
2252 return isolate->heap()->undefined_value(); | |
2253 } | |
2254 | |
2255 | |
2256 RUNTIME_FUNCTION(Runtime_DeclareGlobals) { | |
2257 HandleScope scope(isolate); | |
2258 DCHECK(args.length() == 3); | |
2259 Handle<GlobalObject> global(isolate->global_object()); | |
2260 | |
2261 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); | |
2262 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); | |
2263 CONVERT_SMI_ARG_CHECKED(flags, 2); | |
2264 | |
2265 // Traverse the name/value pairs and set the properties. | |
2266 int length = pairs->length(); | |
2267 for (int i = 0; i < length; i += 2) { | |
2268 HandleScope scope(isolate); | |
2269 Handle<String> name(String::cast(pairs->get(i))); | |
2270 Handle<Object> initial_value(pairs->get(i + 1), isolate); | |
2271 | |
2272 // We have to declare a global const property. To capture we only | |
2273 // assign to it when evaluating the assignment for "const x = | |
2274 // <expr>" the initial value is the hole. | |
2275 bool is_var = initial_value->IsUndefined(); | |
2276 bool is_const = initial_value->IsTheHole(); | |
2277 bool is_function = initial_value->IsSharedFunctionInfo(); | |
2278 DCHECK(is_var + is_const + is_function == 1); | |
2279 | |
2280 Handle<Object> value; | |
2281 if (is_function) { | |
2282 // Copy the function and update its context. Use it as value. | |
2283 Handle<SharedFunctionInfo> shared = | |
2284 Handle<SharedFunctionInfo>::cast(initial_value); | |
2285 Handle<JSFunction> function = | |
2286 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context, | |
2287 TENURED); | |
2288 value = function; | |
2289 } else { | |
2290 value = isolate->factory()->undefined_value(); | |
2291 } | |
2292 | |
2293 // Compute the property attributes. According to ECMA-262, | |
2294 // the property must be non-configurable except in eval. | |
2295 bool is_native = DeclareGlobalsNativeFlag::decode(flags); | |
2296 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); | |
2297 int attr = NONE; | |
2298 if (is_const) attr |= READ_ONLY; | |
2299 if (is_function && is_native) attr |= READ_ONLY; | |
2300 if (!is_const && !is_eval) attr |= DONT_DELETE; | |
2301 | |
2302 Object* result = DeclareGlobals(isolate, global, name, value, | |
2303 static_cast<PropertyAttributes>(attr), | |
2304 is_var, is_const, is_function); | |
2305 if (isolate->has_pending_exception()) return result; | |
2306 } | |
2307 | |
2308 return isolate->heap()->undefined_value(); | |
2309 } | |
2310 | |
2311 | |
2312 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) { | |
2313 HandleScope scope(isolate); | |
2314 // args[0] == name | |
2315 // args[1] == language_mode | |
2316 // args[2] == value (optional) | |
2317 | |
2318 // Determine if we need to assign to the variable if it already | |
2319 // exists (based on the number of arguments). | |
2320 RUNTIME_ASSERT(args.length() == 3); | |
2321 | |
2322 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
2323 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1); | |
2324 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
2325 | |
2326 Handle<GlobalObject> global(isolate->context()->global_object()); | |
2327 Handle<Object> result; | |
2328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2329 isolate, result, Object::SetProperty(global, name, value, strict_mode)); | |
2330 return *result; | |
2331 } | |
2332 | |
2333 | |
2334 RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) { | |
2335 HandleScope handle_scope(isolate); | |
2336 // All constants are declared with an initial value. The name | |
2337 // of the constant is the first argument and the initial value | |
2338 // is the second. | |
2339 RUNTIME_ASSERT(args.length() == 2); | |
2340 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
2341 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | |
2342 | |
2343 Handle<GlobalObject> global = isolate->global_object(); | |
2344 | |
2345 // Lookup the property as own on the global object. | |
2346 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); | |
2347 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
2348 DCHECK(maybe.has_value); | |
2349 PropertyAttributes old_attributes = maybe.value; | |
2350 | |
2351 PropertyAttributes attr = | |
2352 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); | |
2353 // Set the value if the property is either missing, or the property attributes | |
2354 // allow setting the value without invoking an accessor. | |
2355 if (it.IsFound()) { | |
2356 // Ignore if we can't reconfigure the value. | |
2357 if ((old_attributes & DONT_DELETE) != 0) { | |
2358 if ((old_attributes & READ_ONLY) != 0 || | |
2359 it.state() == LookupIterator::ACCESSOR) { | |
2360 return *value; | |
2361 } | |
2362 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY); | |
2363 } | |
2364 } | |
2365 | |
2366 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2367 global, name, value, attr)); | |
2368 | |
2369 return *value; | |
2370 } | |
2371 | |
2372 | |
2373 RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) { | |
2374 HandleScope scope(isolate); | |
2375 DCHECK(args.length() == 4); | |
2376 | |
2377 // Declarations are always made in a function, native, or global context. In | |
2378 // the case of eval code, the context passed is the context of the caller, | |
2379 // which may be some nested context and not the declaration context. | |
2380 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0); | |
2381 Handle<Context> context(context_arg->declaration_context()); | |
2382 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); | |
2383 CONVERT_SMI_ARG_CHECKED(attr_arg, 2); | |
2384 PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg); | |
2385 RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE); | |
2386 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3); | |
2387 | |
2388 // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals. | |
2389 bool is_var = *initial_value == NULL; | |
2390 bool is_const = initial_value->IsTheHole(); | |
2391 bool is_function = initial_value->IsJSFunction(); | |
2392 DCHECK(is_var + is_const + is_function == 1); | |
2393 | |
2394 int index; | |
2395 PropertyAttributes attributes; | |
2396 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; | |
2397 BindingFlags binding_flags; | |
2398 Handle<Object> holder = | |
2399 context->Lookup(name, flags, &index, &attributes, &binding_flags); | |
2400 | |
2401 Handle<JSObject> object; | |
2402 Handle<Object> value = | |
2403 is_function ? initial_value | |
2404 : Handle<Object>::cast(isolate->factory()->undefined_value()); | |
2405 | |
2406 // TODO(verwaest): This case should probably not be covered by this function, | |
2407 // but by DeclareGlobals instead. | |
2408 if ((attributes != ABSENT && holder->IsJSGlobalObject()) || | |
2409 (context_arg->has_extension() && | |
2410 context_arg->extension()->IsJSGlobalObject())) { | |
2411 return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name, | |
2412 value, attr, is_var, is_const, is_function); | |
2413 } | |
2414 | |
2415 if (attributes != ABSENT) { | |
2416 // The name was declared before; check for conflicting re-declarations. | |
2417 if (is_const || (attributes & READ_ONLY) != 0) { | |
2418 return ThrowRedeclarationError(isolate, name); | |
2419 } | |
2420 | |
2421 // Skip var re-declarations. | |
2422 if (is_var) return isolate->heap()->undefined_value(); | |
2423 | |
2424 DCHECK(is_function); | |
2425 if (index >= 0) { | |
2426 DCHECK(holder.is_identical_to(context)); | |
2427 context->set(index, *initial_value); | |
2428 return isolate->heap()->undefined_value(); | |
2429 } | |
2430 | |
2431 object = Handle<JSObject>::cast(holder); | |
2432 | |
2433 } else if (context->has_extension()) { | |
2434 object = handle(JSObject::cast(context->extension())); | |
2435 DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject()); | |
2436 } else { | |
2437 DCHECK(context->IsFunctionContext()); | |
2438 object = | |
2439 isolate->factory()->NewJSObject(isolate->context_extension_function()); | |
2440 context->set_extension(*object); | |
2441 } | |
2442 | |
2443 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2444 object, name, value, attr)); | |
2445 | |
2446 return isolate->heap()->undefined_value(); | |
2447 } | |
2448 | |
2449 | |
2450 RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) { | |
2451 HandleScope scope(isolate); | |
2452 DCHECK(args.length() == 3); | |
2453 | |
2454 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); | |
2455 DCHECK(!value->IsTheHole()); | |
2456 // Initializations are always done in a function or native context. | |
2457 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1); | |
2458 Handle<Context> context(context_arg->declaration_context()); | |
2459 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); | |
2460 | |
2461 int index; | |
2462 PropertyAttributes attributes; | |
2463 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; | |
2464 BindingFlags binding_flags; | |
2465 Handle<Object> holder = | |
2466 context->Lookup(name, flags, &index, &attributes, &binding_flags); | |
2467 | |
2468 if (index >= 0) { | |
2469 DCHECK(holder->IsContext()); | |
2470 // Property was found in a context. Perform the assignment if the constant | |
2471 // was uninitialized. | |
2472 Handle<Context> context = Handle<Context>::cast(holder); | |
2473 DCHECK((attributes & READ_ONLY) != 0); | |
2474 if (context->get(index)->IsTheHole()) context->set(index, *value); | |
2475 return *value; | |
2476 } | |
2477 | |
2478 PropertyAttributes attr = | |
2479 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); | |
2480 | |
2481 // Strict mode handling not needed (legacy const is disallowed in strict | |
2482 // mode). | |
2483 | |
2484 // The declared const was configurable, and may have been deleted in the | |
2485 // meanwhile. If so, re-introduce the variable in the context extension. | |
2486 DCHECK(context_arg->has_extension()); | |
2487 if (attributes == ABSENT) { | |
2488 holder = handle(context_arg->extension(), isolate); | |
2489 } else { | |
2490 // For JSContextExtensionObjects, the initializer can be run multiple times | |
2491 // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the | |
2492 // first assignment should go through. For JSGlobalObjects, additionally any | |
2493 // code can run in between that modifies the declared property. | |
2494 DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject()); | |
2495 | |
2496 LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); | |
2497 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
2498 if (!maybe.has_value) return isolate->heap()->exception(); | |
2499 PropertyAttributes old_attributes = maybe.value; | |
2500 | |
2501 // Ignore if we can't reconfigure the value. | |
2502 if ((old_attributes & DONT_DELETE) != 0) { | |
2503 if ((old_attributes & READ_ONLY) != 0 || | |
2504 it.state() == LookupIterator::ACCESSOR) { | |
2505 return *value; | |
2506 } | |
2507 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY); | |
2508 } | |
2509 } | |
2510 | |
2511 RETURN_FAILURE_ON_EXCEPTION( | |
2512 isolate, JSObject::SetOwnPropertyIgnoreAttributes( | |
2513 Handle<JSObject>::cast(holder), name, value, attr)); | |
2514 | |
2515 return *value; | |
2516 } | |
2517 | |
2518 | |
2519 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { | |
2520 HandleScope scope(isolate); | |
2521 DCHECK(args.length() == 2); | |
2522 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
2523 CONVERT_SMI_ARG_CHECKED(properties, 1); | |
2524 // Conservative upper limit to prevent fuzz tests from going OOM. | |
2525 RUNTIME_ASSERT(properties <= 100000); | |
2526 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { | |
2527 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); | |
2528 } | |
2529 return *object; | |
2530 } | |
2531 | |
2532 | |
2533 RUNTIME_FUNCTION(Runtime_RegExpExecRT) { | |
2534 HandleScope scope(isolate); | |
2535 DCHECK(args.length() == 4); | |
2536 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | |
2537 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | |
2538 CONVERT_INT32_ARG_CHECKED(index, 2); | |
2539 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); | |
2540 // Due to the way the JS calls are constructed this must be less than the | |
2541 // length of a string, i.e. it is always a Smi. We check anyway for security. | |
2542 RUNTIME_ASSERT(index >= 0); | |
2543 RUNTIME_ASSERT(index <= subject->length()); | |
2544 isolate->counters()->regexp_entry_runtime()->Increment(); | |
2545 Handle<Object> result; | |
2546 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2547 isolate, result, | |
2548 RegExpImpl::Exec(regexp, subject, index, last_match_info)); | |
2549 return *result; | |
2550 } | |
2551 | |
2552 | |
2553 RUNTIME_FUNCTION(Runtime_RegExpConstructResult) { | |
2554 HandleScope handle_scope(isolate); | |
2555 DCHECK(args.length() == 3); | |
2556 CONVERT_SMI_ARG_CHECKED(size, 0); | |
2557 RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength); | |
2558 CONVERT_ARG_HANDLE_CHECKED(Object, index, 1); | |
2559 CONVERT_ARG_HANDLE_CHECKED(Object, input, 2); | |
2560 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size); | |
2561 Handle<Map> regexp_map(isolate->native_context()->regexp_result_map()); | |
2562 Handle<JSObject> object = | |
2563 isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false); | |
2564 Handle<JSArray> array = Handle<JSArray>::cast(object); | |
2565 array->set_elements(*elements); | |
2566 array->set_length(Smi::FromInt(size)); | |
2567 // Write in-object properties after the length of the array. | |
2568 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); | |
2569 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); | |
2570 return *array; | |
2571 } | |
2572 | |
2573 | |
2574 RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) { | |
2575 HandleScope scope(isolate); | |
2576 DCHECK(args.length() == 6); | |
2577 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | |
2578 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
2579 // If source is the empty string we set it to "(?:)" instead as | |
2580 // suggested by ECMA-262, 5th, section 15.10.4.1. | |
2581 if (source->length() == 0) source = isolate->factory()->query_colon_string(); | |
2582 | |
2583 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2); | |
2584 if (!global->IsTrue()) global = isolate->factory()->false_value(); | |
2585 | |
2586 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3); | |
2587 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value(); | |
2588 | |
2589 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4); | |
2590 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value(); | |
2591 | |
2592 CONVERT_ARG_HANDLE_CHECKED(Object, sticky, 5); | |
2593 if (!sticky->IsTrue()) sticky = isolate->factory()->false_value(); | |
2594 | |
2595 Map* map = regexp->map(); | |
2596 Object* constructor = map->constructor(); | |
2597 if (!FLAG_harmony_regexps && | |
2598 constructor->IsJSFunction() && | |
2599 JSFunction::cast(constructor)->initial_map() == map) { | |
2600 // If we still have the original map, set in-object properties directly. | |
2601 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source); | |
2602 // Both true and false are immovable immortal objects so no need for write | |
2603 // barrier. | |
2604 regexp->InObjectPropertyAtPut( | |
2605 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER); | |
2606 regexp->InObjectPropertyAtPut( | |
2607 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER); | |
2608 regexp->InObjectPropertyAtPut( | |
2609 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER); | |
2610 regexp->InObjectPropertyAtPut( | |
2611 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER); | |
2612 return *regexp; | |
2613 } | |
2614 | |
2615 // Map has changed, so use generic, but slower, method. We also end here if | |
2616 // the --harmony-regexp flag is set, because the initial map does not have | |
2617 // space for the 'sticky' flag, since it is from the snapshot, but must work | |
2618 // both with and without --harmony-regexp. When sticky comes out from under | |
2619 // the flag, we will be able to use the fast initial map. | |
2620 PropertyAttributes final = | |
2621 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); | |
2622 PropertyAttributes writable = | |
2623 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); | |
2624 Handle<Object> zero(Smi::FromInt(0), isolate); | |
2625 Factory* factory = isolate->factory(); | |
2626 JSObject::SetOwnPropertyIgnoreAttributes( | |
2627 regexp, factory->source_string(), source, final).Check(); | |
2628 JSObject::SetOwnPropertyIgnoreAttributes( | |
2629 regexp, factory->global_string(), global, final).Check(); | |
2630 JSObject::SetOwnPropertyIgnoreAttributes( | |
2631 regexp, factory->ignore_case_string(), ignoreCase, final).Check(); | |
2632 JSObject::SetOwnPropertyIgnoreAttributes( | |
2633 regexp, factory->multiline_string(), multiline, final).Check(); | |
2634 if (FLAG_harmony_regexps) { | |
2635 JSObject::SetOwnPropertyIgnoreAttributes( | |
2636 regexp, factory->sticky_string(), sticky, final).Check(); | |
2637 } | |
2638 JSObject::SetOwnPropertyIgnoreAttributes( | |
2639 regexp, factory->last_index_string(), zero, writable).Check(); | |
2640 return *regexp; | |
2641 } | |
2642 | |
2643 | |
2644 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { | |
2645 HandleScope scope(isolate); | |
2646 DCHECK(args.length() == 1); | |
2647 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); | |
2648 Object* length = prototype->length(); | |
2649 RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0); | |
2650 RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements()); | |
2651 // This is necessary to enable fast checks for absence of elements | |
2652 // on Array.prototype and below. | |
2653 prototype->set_elements(isolate->heap()->empty_fixed_array()); | |
2654 return Smi::FromInt(0); | |
2655 } | |
2656 | |
2657 | |
2658 static void InstallBuiltin(Isolate* isolate, | |
2659 Handle<JSObject> holder, | |
2660 const char* name, | |
2661 Builtins::Name builtin_name) { | |
2662 Handle<String> key = isolate->factory()->InternalizeUtf8String(name); | |
2663 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); | |
2664 Handle<JSFunction> optimized = | |
2665 isolate->factory()->NewFunctionWithoutPrototype(key, code); | |
2666 optimized->shared()->DontAdaptArguments(); | |
2667 JSObject::AddProperty(holder, key, optimized, NONE); | |
2668 } | |
2669 | |
2670 | |
2671 RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) { | |
2672 HandleScope scope(isolate); | |
2673 DCHECK(args.length() == 0); | |
2674 Handle<JSObject> holder = | |
2675 isolate->factory()->NewJSObject(isolate->object_function()); | |
2676 | |
2677 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); | |
2678 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); | |
2679 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); | |
2680 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); | |
2681 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); | |
2682 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); | |
2683 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); | |
2684 | |
2685 return *holder; | |
2686 } | |
2687 | |
2688 | |
2689 RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) { | |
2690 SealHandleScope shs(isolate); | |
2691 DCHECK(args.length() == 1); | |
2692 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); | |
2693 if (!callable->IsJSFunction()) { | |
2694 HandleScope scope(isolate); | |
2695 Handle<Object> delegate; | |
2696 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2697 isolate, delegate, | |
2698 Execution::TryGetFunctionDelegate( | |
2699 isolate, Handle<JSReceiver>(callable))); | |
2700 callable = JSFunction::cast(*delegate); | |
2701 } | |
2702 JSFunction* function = JSFunction::cast(callable); | |
2703 SharedFunctionInfo* shared = function->shared(); | |
2704 return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY); | |
2705 } | |
2706 | |
2707 | |
2708 RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) { | |
2709 SealHandleScope shs(isolate); | |
2710 DCHECK(args.length() == 1); | |
2711 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); | |
2712 | |
2713 if (!callable->IsJSFunction()) { | |
2714 HandleScope scope(isolate); | |
2715 Handle<Object> delegate; | |
2716 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2717 isolate, delegate, | |
2718 Execution::TryGetFunctionDelegate( | |
2719 isolate, Handle<JSReceiver>(callable))); | |
2720 callable = JSFunction::cast(*delegate); | |
2721 } | |
2722 JSFunction* function = JSFunction::cast(callable); | |
2723 | |
2724 SharedFunctionInfo* shared = function->shared(); | |
2725 if (shared->native() || shared->strict_mode() == STRICT) { | |
2726 return isolate->heap()->undefined_value(); | |
2727 } | |
2728 // Returns undefined for strict or native functions, or | |
2729 // the associated global receiver for "normal" functions. | |
2730 | |
2731 return function->global_proxy(); | |
2732 } | |
2733 | |
2734 | |
2735 RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) { | |
2736 HandleScope scope(isolate); | |
2737 DCHECK(args.length() == 4); | |
2738 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); | |
2739 CONVERT_SMI_ARG_CHECKED(index, 1); | |
2740 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); | |
2741 CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); | |
2742 | |
2743 // Get the RegExp function from the context in the literals array. | |
2744 // This is the RegExp function from the context in which the | |
2745 // function was created. We do not use the RegExp function from the | |
2746 // current native context because this might be the RegExp function | |
2747 // from another context which we should not have access to. | |
2748 Handle<JSFunction> constructor = | |
2749 Handle<JSFunction>( | |
2750 JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); | |
2751 // Compute the regular expression literal. | |
2752 Handle<Object> regexp; | |
2753 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2754 isolate, regexp, | |
2755 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags)); | |
2756 literals->set(index, *regexp); | |
2757 return *regexp; | |
2758 } | |
2759 | |
2760 | |
2761 RUNTIME_FUNCTION(Runtime_FunctionGetName) { | |
2762 SealHandleScope shs(isolate); | |
2763 DCHECK(args.length() == 1); | |
2764 | |
2765 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2766 return f->shared()->name(); | |
2767 } | |
2768 | |
2769 | |
2770 RUNTIME_FUNCTION(Runtime_FunctionSetName) { | |
2771 SealHandleScope shs(isolate); | |
2772 DCHECK(args.length() == 2); | |
2773 | |
2774 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2775 CONVERT_ARG_CHECKED(String, name, 1); | |
2776 f->shared()->set_name(name); | |
2777 return isolate->heap()->undefined_value(); | |
2778 } | |
2779 | |
2780 | |
2781 RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) { | |
2782 SealHandleScope shs(isolate); | |
2783 DCHECK(args.length() == 1); | |
2784 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2785 return isolate->heap()->ToBoolean( | |
2786 f->shared()->name_should_print_as_anonymous()); | |
2787 } | |
2788 | |
2789 | |
2790 RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) { | |
2791 SealHandleScope shs(isolate); | |
2792 DCHECK(args.length() == 1); | |
2793 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2794 f->shared()->set_name_should_print_as_anonymous(true); | |
2795 return isolate->heap()->undefined_value(); | |
2796 } | |
2797 | |
2798 | |
2799 RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) { | |
2800 SealHandleScope shs(isolate); | |
2801 DCHECK(args.length() == 1); | |
2802 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2803 return isolate->heap()->ToBoolean(f->shared()->is_generator()); | |
2804 } | |
2805 | |
2806 | |
2807 RUNTIME_FUNCTION(Runtime_FunctionIsArrow) { | |
2808 SealHandleScope shs(isolate); | |
2809 DCHECK(args.length() == 1); | |
2810 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2811 return isolate->heap()->ToBoolean(f->shared()->is_arrow()); | |
2812 } | |
2813 | |
2814 | |
2815 RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) { | |
2816 SealHandleScope shs(isolate); | |
2817 DCHECK(args.length() == 1); | |
2818 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2819 return isolate->heap()->ToBoolean(f->shared()->is_concise_method()); | |
2820 } | |
2821 | |
2822 | |
2823 RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) { | |
2824 SealHandleScope shs(isolate); | |
2825 DCHECK(args.length() == 1); | |
2826 | |
2827 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2828 RUNTIME_ASSERT(f->RemovePrototype()); | |
2829 | |
2830 return isolate->heap()->undefined_value(); | |
2831 } | |
2832 | |
2833 | |
2834 RUNTIME_FUNCTION(Runtime_FunctionGetScript) { | |
2835 HandleScope scope(isolate); | |
2836 DCHECK(args.length() == 1); | |
2837 | |
2838 CONVERT_ARG_CHECKED(JSFunction, fun, 0); | |
2839 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); | |
2840 if (!script->IsScript()) return isolate->heap()->undefined_value(); | |
2841 | |
2842 return *Script::GetWrapper(Handle<Script>::cast(script)); | |
2843 } | |
2844 | |
2845 | |
2846 RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) { | |
2847 HandleScope scope(isolate); | |
2848 DCHECK(args.length() == 1); | |
2849 | |
2850 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); | |
2851 Handle<SharedFunctionInfo> shared(f->shared()); | |
2852 return *shared->GetSourceCode(); | |
2853 } | |
2854 | |
2855 | |
2856 RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) { | |
2857 SealHandleScope shs(isolate); | |
2858 DCHECK(args.length() == 1); | |
2859 | |
2860 CONVERT_ARG_CHECKED(JSFunction, fun, 0); | |
2861 int pos = fun->shared()->start_position(); | |
2862 return Smi::FromInt(pos); | |
2863 } | |
2864 | |
2865 | |
2866 RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) { | |
2867 SealHandleScope shs(isolate); | |
2868 DCHECK(args.length() == 2); | |
2869 | |
2870 CONVERT_ARG_CHECKED(Code, code, 0); | |
2871 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); | |
2872 | |
2873 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); | |
2874 | |
2875 Address pc = code->address() + offset; | |
2876 return Smi::FromInt(code->SourcePosition(pc)); | |
2877 } | |
2878 | |
2879 | |
2880 RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) { | |
2881 SealHandleScope shs(isolate); | |
2882 DCHECK(args.length() == 2); | |
2883 | |
2884 CONVERT_ARG_CHECKED(JSFunction, fun, 0); | |
2885 CONVERT_ARG_CHECKED(String, name, 1); | |
2886 fun->SetInstanceClassName(name); | |
2887 return isolate->heap()->undefined_value(); | |
2888 } | |
2889 | |
2890 | |
2891 RUNTIME_FUNCTION(Runtime_FunctionSetLength) { | |
2892 SealHandleScope shs(isolate); | |
2893 DCHECK(args.length() == 2); | |
2894 | |
2895 CONVERT_ARG_CHECKED(JSFunction, fun, 0); | |
2896 CONVERT_SMI_ARG_CHECKED(length, 1); | |
2897 RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 || | |
2898 (length & 0xC0000000) == 0x0); | |
2899 fun->shared()->set_length(length); | |
2900 return isolate->heap()->undefined_value(); | |
2901 } | |
2902 | |
2903 | |
2904 RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { | |
2905 HandleScope scope(isolate); | |
2906 DCHECK(args.length() == 2); | |
2907 | |
2908 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
2909 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | |
2910 RUNTIME_ASSERT(fun->should_have_prototype()); | |
2911 Accessors::FunctionSetPrototype(fun, value); | |
2912 return args[0]; // return TOS | |
2913 } | |
2914 | |
2915 | |
2916 RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) { | |
2917 SealHandleScope shs(isolate); | |
2918 DCHECK(args.length() == 1); | |
2919 | |
2920 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2921 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); | |
2922 } | |
2923 | |
2924 | |
2925 RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) { | |
2926 SealHandleScope shs(isolate); | |
2927 DCHECK(args.length() == 1); | |
2928 | |
2929 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
2930 return isolate->heap()->ToBoolean(f->IsBuiltin()); | |
2931 } | |
2932 | |
2933 | |
2934 RUNTIME_FUNCTION(Runtime_SetCode) { | |
2935 HandleScope scope(isolate); | |
2936 DCHECK(args.length() == 2); | |
2937 | |
2938 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); | |
2939 CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1); | |
2940 | |
2941 Handle<SharedFunctionInfo> target_shared(target->shared()); | |
2942 Handle<SharedFunctionInfo> source_shared(source->shared()); | |
2943 RUNTIME_ASSERT(!source_shared->bound()); | |
2944 | |
2945 if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) { | |
2946 return isolate->heap()->exception(); | |
2947 } | |
2948 | |
2949 // Mark both, the source and the target, as un-flushable because the | |
2950 // shared unoptimized code makes them impossible to enqueue in a list. | |
2951 DCHECK(target_shared->code()->gc_metadata() == NULL); | |
2952 DCHECK(source_shared->code()->gc_metadata() == NULL); | |
2953 target_shared->set_dont_flush(true); | |
2954 source_shared->set_dont_flush(true); | |
2955 | |
2956 // Set the code, scope info, formal parameter count, and the length | |
2957 // of the target shared function info. | |
2958 target_shared->ReplaceCode(source_shared->code()); | |
2959 target_shared->set_scope_info(source_shared->scope_info()); | |
2960 target_shared->set_length(source_shared->length()); | |
2961 target_shared->set_feedback_vector(source_shared->feedback_vector()); | |
2962 target_shared->set_formal_parameter_count( | |
2963 source_shared->formal_parameter_count()); | |
2964 target_shared->set_script(source_shared->script()); | |
2965 target_shared->set_start_position_and_type( | |
2966 source_shared->start_position_and_type()); | |
2967 target_shared->set_end_position(source_shared->end_position()); | |
2968 bool was_native = target_shared->native(); | |
2969 target_shared->set_compiler_hints(source_shared->compiler_hints()); | |
2970 target_shared->set_native(was_native); | |
2971 target_shared->set_profiler_ticks(source_shared->profiler_ticks()); | |
2972 | |
2973 // Set the code of the target function. | |
2974 target->ReplaceCode(source_shared->code()); | |
2975 DCHECK(target->next_function_link()->IsUndefined()); | |
2976 | |
2977 // Make sure we get a fresh copy of the literal vector to avoid cross | |
2978 // context contamination. | |
2979 Handle<Context> context(source->context()); | |
2980 int number_of_literals = source->NumberOfLiterals(); | |
2981 Handle<FixedArray> literals = | |
2982 isolate->factory()->NewFixedArray(number_of_literals, TENURED); | |
2983 if (number_of_literals > 0) { | |
2984 literals->set(JSFunction::kLiteralNativeContextIndex, | |
2985 context->native_context()); | |
2986 } | |
2987 target->set_context(*context); | |
2988 target->set_literals(*literals); | |
2989 | |
2990 if (isolate->logger()->is_logging_code_events() || | |
2991 isolate->cpu_profiler()->is_profiling()) { | |
2992 isolate->logger()->LogExistingFunction( | |
2993 source_shared, Handle<Code>(source_shared->code())); | |
2994 } | |
2995 | |
2996 return *target; | |
2997 } | |
2998 | |
2999 | |
3000 RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) { | |
3001 HandleScope scope(isolate); | |
3002 DCHECK(args.length() == 0); | |
3003 | |
3004 JavaScriptFrameIterator it(isolate); | |
3005 JavaScriptFrame* frame = it.frame(); | |
3006 Handle<JSFunction> function(frame->function()); | |
3007 RUNTIME_ASSERT(function->shared()->is_generator()); | |
3008 | |
3009 Handle<JSGeneratorObject> generator; | |
3010 if (frame->IsConstructor()) { | |
3011 generator = handle(JSGeneratorObject::cast(frame->receiver())); | |
3012 } else { | |
3013 generator = isolate->factory()->NewJSGeneratorObject(function); | |
3014 } | |
3015 generator->set_function(*function); | |
3016 generator->set_context(Context::cast(frame->context())); | |
3017 generator->set_receiver(frame->receiver()); | |
3018 generator->set_continuation(0); | |
3019 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); | |
3020 generator->set_stack_handler_index(-1); | |
3021 | |
3022 return *generator; | |
3023 } | |
3024 | |
3025 | |
3026 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) { | |
3027 HandleScope handle_scope(isolate); | |
3028 DCHECK(args.length() == 1); | |
3029 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); | |
3030 | |
3031 JavaScriptFrameIterator stack_iterator(isolate); | |
3032 JavaScriptFrame* frame = stack_iterator.frame(); | |
3033 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); | |
3034 DCHECK_EQ(frame->function(), generator_object->function()); | |
3035 | |
3036 // The caller should have saved the context and continuation already. | |
3037 DCHECK_EQ(generator_object->context(), Context::cast(frame->context())); | |
3038 DCHECK_LT(0, generator_object->continuation()); | |
3039 | |
3040 // We expect there to be at least two values on the operand stack: the return | |
3041 // value of the yield expression, and the argument to this runtime call. | |
3042 // Neither of those should be saved. | |
3043 int operands_count = frame->ComputeOperandsCount(); | |
3044 DCHECK_GE(operands_count, 2); | |
3045 operands_count -= 2; | |
3046 | |
3047 if (operands_count == 0) { | |
3048 // Although it's semantically harmless to call this function with an | |
3049 // operands_count of zero, it is also unnecessary. | |
3050 DCHECK_EQ(generator_object->operand_stack(), | |
3051 isolate->heap()->empty_fixed_array()); | |
3052 DCHECK_EQ(generator_object->stack_handler_index(), -1); | |
3053 // If there are no operands on the stack, there shouldn't be a handler | |
3054 // active either. | |
3055 DCHECK(!frame->HasHandler()); | |
3056 } else { | |
3057 int stack_handler_index = -1; | |
3058 Handle<FixedArray> operand_stack = | |
3059 isolate->factory()->NewFixedArray(operands_count); | |
3060 frame->SaveOperandStack(*operand_stack, &stack_handler_index); | |
3061 generator_object->set_operand_stack(*operand_stack); | |
3062 generator_object->set_stack_handler_index(stack_handler_index); | |
3063 } | |
3064 | |
3065 return isolate->heap()->undefined_value(); | |
3066 } | |
3067 | |
3068 | |
3069 // Note that this function is the slow path for resuming generators. It is only | |
3070 // called if the suspended activation had operands on the stack, stack handlers | |
3071 // needing rewinding, or if the resume should throw an exception. The fast path | |
3072 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is | |
3073 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is | |
3074 // called in any case, as it needs to reconstruct the stack frame and make space | |
3075 // for arguments and operands. | |
3076 RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) { | |
3077 SealHandleScope shs(isolate); | |
3078 DCHECK(args.length() == 3); | |
3079 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); | |
3080 CONVERT_ARG_CHECKED(Object, value, 1); | |
3081 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); | |
3082 JavaScriptFrameIterator stack_iterator(isolate); | |
3083 JavaScriptFrame* frame = stack_iterator.frame(); | |
3084 | |
3085 DCHECK_EQ(frame->function(), generator_object->function()); | |
3086 DCHECK(frame->function()->is_compiled()); | |
3087 | |
3088 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); | |
3089 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); | |
3090 | |
3091 Address pc = generator_object->function()->code()->instruction_start(); | |
3092 int offset = generator_object->continuation(); | |
3093 DCHECK(offset > 0); | |
3094 frame->set_pc(pc + offset); | |
3095 if (FLAG_enable_ool_constant_pool) { | |
3096 frame->set_constant_pool( | |
3097 generator_object->function()->code()->constant_pool()); | |
3098 } | |
3099 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); | |
3100 | |
3101 FixedArray* operand_stack = generator_object->operand_stack(); | |
3102 int operands_count = operand_stack->length(); | |
3103 if (operands_count != 0) { | |
3104 frame->RestoreOperandStack(operand_stack, | |
3105 generator_object->stack_handler_index()); | |
3106 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); | |
3107 generator_object->set_stack_handler_index(-1); | |
3108 } | |
3109 | |
3110 JSGeneratorObject::ResumeMode resume_mode = | |
3111 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); | |
3112 switch (resume_mode) { | |
3113 case JSGeneratorObject::NEXT: | |
3114 return value; | |
3115 case JSGeneratorObject::THROW: | |
3116 return isolate->Throw(value); | |
3117 } | |
3118 | |
3119 UNREACHABLE(); | |
3120 return isolate->ThrowIllegalOperation(); | |
3121 } | |
3122 | |
3123 | |
3124 RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) { | |
3125 HandleScope scope(isolate); | |
3126 DCHECK(args.length() == 1); | |
3127 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
3128 int continuation = generator->continuation(); | |
3129 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ? | |
3130 "generator_finished" : "generator_running"; | |
3131 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0); | |
3132 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv)); | |
3133 } | |
3134 | |
3135 | |
3136 RUNTIME_FUNCTION(Runtime_ObjectFreeze) { | |
3137 HandleScope scope(isolate); | |
3138 DCHECK(args.length() == 1); | |
3139 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
3140 | |
3141 // %ObjectFreeze is a fast path and these cases are handled elsewhere. | |
3142 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && | |
3143 !object->map()->is_observed() && | |
3144 !object->IsJSProxy()); | |
3145 | |
3146 Handle<Object> result; | |
3147 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); | |
3148 return *result; | |
3149 } | |
3150 | |
3151 | |
3152 RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) { | |
3153 HandleScope handle_scope(isolate); | |
3154 DCHECK(args.length() == 2); | |
3155 | |
3156 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
3157 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); | |
3158 | |
3159 // Flatten the string. If someone wants to get a char at an index | |
3160 // in a cons string, it is likely that more indices will be | |
3161 // accessed. | |
3162 subject = String::Flatten(subject); | |
3163 | |
3164 if (i >= static_cast<uint32_t>(subject->length())) { | |
3165 return isolate->heap()->nan_value(); | |
3166 } | |
3167 | |
3168 return Smi::FromInt(subject->Get(i)); | |
3169 } | |
3170 | |
3171 | |
3172 RUNTIME_FUNCTION(Runtime_CharFromCode) { | |
3173 HandleScope handlescope(isolate); | |
3174 DCHECK(args.length() == 1); | |
3175 if (args[0]->IsNumber()) { | |
3176 CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]); | |
3177 code &= 0xffff; | |
3178 return *isolate->factory()->LookupSingleCharacterStringFromCode(code); | |
3179 } | |
3180 return isolate->heap()->empty_string(); | |
3181 } | |
3182 | |
3183 | |
3184 class FixedArrayBuilder { | |
3185 public: | |
3186 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) | |
3187 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), | |
3188 length_(0), | |
3189 has_non_smi_elements_(false) { | |
3190 // Require a non-zero initial size. Ensures that doubling the size to | |
3191 // extend the array will work. | |
3192 DCHECK(initial_capacity > 0); | |
3193 } | |
3194 | |
3195 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) | |
3196 : array_(backing_store), | |
3197 length_(0), | |
3198 has_non_smi_elements_(false) { | |
3199 // Require a non-zero initial size. Ensures that doubling the size to | |
3200 // extend the array will work. | |
3201 DCHECK(backing_store->length() > 0); | |
3202 } | |
3203 | |
3204 bool HasCapacity(int elements) { | |
3205 int length = array_->length(); | |
3206 int required_length = length_ + elements; | |
3207 return (length >= required_length); | |
3208 } | |
3209 | |
3210 void EnsureCapacity(int elements) { | |
3211 int length = array_->length(); | |
3212 int required_length = length_ + elements; | |
3213 if (length < required_length) { | |
3214 int new_length = length; | |
3215 do { | |
3216 new_length *= 2; | |
3217 } while (new_length < required_length); | |
3218 Handle<FixedArray> extended_array = | |
3219 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); | |
3220 array_->CopyTo(0, *extended_array, 0, length_); | |
3221 array_ = extended_array; | |
3222 } | |
3223 } | |
3224 | |
3225 void Add(Object* value) { | |
3226 DCHECK(!value->IsSmi()); | |
3227 DCHECK(length_ < capacity()); | |
3228 array_->set(length_, value); | |
3229 length_++; | |
3230 has_non_smi_elements_ = true; | |
3231 } | |
3232 | |
3233 void Add(Smi* value) { | |
3234 DCHECK(value->IsSmi()); | |
3235 DCHECK(length_ < capacity()); | |
3236 array_->set(length_, value); | |
3237 length_++; | |
3238 } | |
3239 | |
3240 Handle<FixedArray> array() { | |
3241 return array_; | |
3242 } | |
3243 | |
3244 int length() { | |
3245 return length_; | |
3246 } | |
3247 | |
3248 int capacity() { | |
3249 return array_->length(); | |
3250 } | |
3251 | |
3252 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { | |
3253 JSArray::SetContent(target_array, array_); | |
3254 target_array->set_length(Smi::FromInt(length_)); | |
3255 return target_array; | |
3256 } | |
3257 | |
3258 | |
3259 private: | |
3260 Handle<FixedArray> array_; | |
3261 int length_; | |
3262 bool has_non_smi_elements_; | |
3263 }; | |
3264 | |
3265 | |
3266 // Forward declarations. | |
3267 const int kStringBuilderConcatHelperLengthBits = 11; | |
3268 const int kStringBuilderConcatHelperPositionBits = 19; | |
3269 | |
3270 template <typename schar> | |
3271 static inline void StringBuilderConcatHelper(String*, | |
3272 schar*, | |
3273 FixedArray*, | |
3274 int); | |
3275 | |
3276 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> | |
3277 StringBuilderSubstringLength; | |
3278 typedef BitField<int, | |
3279 kStringBuilderConcatHelperLengthBits, | |
3280 kStringBuilderConcatHelperPositionBits> | |
3281 StringBuilderSubstringPosition; | |
3282 | |
3283 | |
3284 class ReplacementStringBuilder { | |
3285 public: | |
3286 ReplacementStringBuilder(Heap* heap, Handle<String> subject, | |
3287 int estimated_part_count) | |
3288 : heap_(heap), | |
3289 array_builder_(heap->isolate(), estimated_part_count), | |
3290 subject_(subject), | |
3291 character_count_(0), | |
3292 is_one_byte_(subject->IsOneByteRepresentation()) { | |
3293 // Require a non-zero initial size. Ensures that doubling the size to | |
3294 // extend the array will work. | |
3295 DCHECK(estimated_part_count > 0); | |
3296 } | |
3297 | |
3298 static inline void AddSubjectSlice(FixedArrayBuilder* builder, | |
3299 int from, | |
3300 int to) { | |
3301 DCHECK(from >= 0); | |
3302 int length = to - from; | |
3303 DCHECK(length > 0); | |
3304 if (StringBuilderSubstringLength::is_valid(length) && | |
3305 StringBuilderSubstringPosition::is_valid(from)) { | |
3306 int encoded_slice = StringBuilderSubstringLength::encode(length) | | |
3307 StringBuilderSubstringPosition::encode(from); | |
3308 builder->Add(Smi::FromInt(encoded_slice)); | |
3309 } else { | |
3310 // Otherwise encode as two smis. | |
3311 builder->Add(Smi::FromInt(-length)); | |
3312 builder->Add(Smi::FromInt(from)); | |
3313 } | |
3314 } | |
3315 | |
3316 | |
3317 void EnsureCapacity(int elements) { | |
3318 array_builder_.EnsureCapacity(elements); | |
3319 } | |
3320 | |
3321 | |
3322 void AddSubjectSlice(int from, int to) { | |
3323 AddSubjectSlice(&array_builder_, from, to); | |
3324 IncrementCharacterCount(to - from); | |
3325 } | |
3326 | |
3327 | |
3328 void AddString(Handle<String> string) { | |
3329 int length = string->length(); | |
3330 DCHECK(length > 0); | |
3331 AddElement(*string); | |
3332 if (!string->IsOneByteRepresentation()) { | |
3333 is_one_byte_ = false; | |
3334 } | |
3335 IncrementCharacterCount(length); | |
3336 } | |
3337 | |
3338 | |
3339 MaybeHandle<String> ToString() { | |
3340 Isolate* isolate = heap_->isolate(); | |
3341 if (array_builder_.length() == 0) { | |
3342 return isolate->factory()->empty_string(); | |
3343 } | |
3344 | |
3345 Handle<String> joined_string; | |
3346 if (is_one_byte_) { | |
3347 Handle<SeqOneByteString> seq; | |
3348 ASSIGN_RETURN_ON_EXCEPTION( | |
3349 isolate, seq, | |
3350 isolate->factory()->NewRawOneByteString(character_count_), | |
3351 String); | |
3352 | |
3353 DisallowHeapAllocation no_gc; | |
3354 uint8_t* char_buffer = seq->GetChars(); | |
3355 StringBuilderConcatHelper(*subject_, | |
3356 char_buffer, | |
3357 *array_builder_.array(), | |
3358 array_builder_.length()); | |
3359 joined_string = Handle<String>::cast(seq); | |
3360 } else { | |
3361 // Two-byte. | |
3362 Handle<SeqTwoByteString> seq; | |
3363 ASSIGN_RETURN_ON_EXCEPTION( | |
3364 isolate, seq, | |
3365 isolate->factory()->NewRawTwoByteString(character_count_), | |
3366 String); | |
3367 | |
3368 DisallowHeapAllocation no_gc; | |
3369 uc16* char_buffer = seq->GetChars(); | |
3370 StringBuilderConcatHelper(*subject_, | |
3371 char_buffer, | |
3372 *array_builder_.array(), | |
3373 array_builder_.length()); | |
3374 joined_string = Handle<String>::cast(seq); | |
3375 } | |
3376 return joined_string; | |
3377 } | |
3378 | |
3379 | |
3380 void IncrementCharacterCount(int by) { | |
3381 if (character_count_ > String::kMaxLength - by) { | |
3382 STATIC_ASSERT(String::kMaxLength < kMaxInt); | |
3383 character_count_ = kMaxInt; | |
3384 } else { | |
3385 character_count_ += by; | |
3386 } | |
3387 } | |
3388 | |
3389 private: | |
3390 void AddElement(Object* element) { | |
3391 DCHECK(element->IsSmi() || element->IsString()); | |
3392 DCHECK(array_builder_.capacity() > array_builder_.length()); | |
3393 array_builder_.Add(element); | |
3394 } | |
3395 | |
3396 Heap* heap_; | |
3397 FixedArrayBuilder array_builder_; | |
3398 Handle<String> subject_; | |
3399 int character_count_; | |
3400 bool is_one_byte_; | |
3401 }; | |
3402 | |
3403 | |
3404 class CompiledReplacement { | |
3405 public: | |
3406 explicit CompiledReplacement(Zone* zone) | |
3407 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} | |
3408 | |
3409 // Return whether the replacement is simple. | |
3410 bool Compile(Handle<String> replacement, | |
3411 int capture_count, | |
3412 int subject_length); | |
3413 | |
3414 // Use Apply only if Compile returned false. | |
3415 void Apply(ReplacementStringBuilder* builder, | |
3416 int match_from, | |
3417 int match_to, | |
3418 int32_t* match); | |
3419 | |
3420 // Number of distinct parts of the replacement pattern. | |
3421 int parts() { | |
3422 return parts_.length(); | |
3423 } | |
3424 | |
3425 Zone* zone() const { return zone_; } | |
3426 | |
3427 private: | |
3428 enum PartType { | |
3429 SUBJECT_PREFIX = 1, | |
3430 SUBJECT_SUFFIX, | |
3431 SUBJECT_CAPTURE, | |
3432 REPLACEMENT_SUBSTRING, | |
3433 REPLACEMENT_STRING, | |
3434 | |
3435 NUMBER_OF_PART_TYPES | |
3436 }; | |
3437 | |
3438 struct ReplacementPart { | |
3439 static inline ReplacementPart SubjectMatch() { | |
3440 return ReplacementPart(SUBJECT_CAPTURE, 0); | |
3441 } | |
3442 static inline ReplacementPart SubjectCapture(int capture_index) { | |
3443 return ReplacementPart(SUBJECT_CAPTURE, capture_index); | |
3444 } | |
3445 static inline ReplacementPart SubjectPrefix() { | |
3446 return ReplacementPart(SUBJECT_PREFIX, 0); | |
3447 } | |
3448 static inline ReplacementPart SubjectSuffix(int subject_length) { | |
3449 return ReplacementPart(SUBJECT_SUFFIX, subject_length); | |
3450 } | |
3451 static inline ReplacementPart ReplacementString() { | |
3452 return ReplacementPart(REPLACEMENT_STRING, 0); | |
3453 } | |
3454 static inline ReplacementPart ReplacementSubString(int from, int to) { | |
3455 DCHECK(from >= 0); | |
3456 DCHECK(to > from); | |
3457 return ReplacementPart(-from, to); | |
3458 } | |
3459 | |
3460 // If tag <= 0 then it is the negation of a start index of a substring of | |
3461 // the replacement pattern, otherwise it's a value from PartType. | |
3462 ReplacementPart(int tag, int data) | |
3463 : tag(tag), data(data) { | |
3464 // Must be non-positive or a PartType value. | |
3465 DCHECK(tag < NUMBER_OF_PART_TYPES); | |
3466 } | |
3467 // Either a value of PartType or a non-positive number that is | |
3468 // the negation of an index into the replacement string. | |
3469 int tag; | |
3470 // The data value's interpretation depends on the value of tag: | |
3471 // tag == SUBJECT_PREFIX || | |
3472 // tag == SUBJECT_SUFFIX: data is unused. | |
3473 // tag == SUBJECT_CAPTURE: data is the number of the capture. | |
3474 // tag == REPLACEMENT_SUBSTRING || | |
3475 // tag == REPLACEMENT_STRING: data is index into array of substrings | |
3476 // of the replacement string. | |
3477 // tag <= 0: Temporary representation of the substring of the replacement | |
3478 // string ranging over -tag .. data. | |
3479 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the | |
3480 // substring objects. | |
3481 int data; | |
3482 }; | |
3483 | |
3484 template<typename Char> | |
3485 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, | |
3486 Vector<Char> characters, | |
3487 int capture_count, | |
3488 int subject_length, | |
3489 Zone* zone) { | |
3490 int length = characters.length(); | |
3491 int last = 0; | |
3492 for (int i = 0; i < length; i++) { | |
3493 Char c = characters[i]; | |
3494 if (c == '$') { | |
3495 int next_index = i + 1; | |
3496 if (next_index == length) { // No next character! | |
3497 break; | |
3498 } | |
3499 Char c2 = characters[next_index]; | |
3500 switch (c2) { | |
3501 case '$': | |
3502 if (i > last) { | |
3503 // There is a substring before. Include the first "$". | |
3504 parts->Add(ReplacementPart::ReplacementSubString(last, next_index), | |
3505 zone); | |
3506 last = next_index + 1; // Continue after the second "$". | |
3507 } else { | |
3508 // Let the next substring start with the second "$". | |
3509 last = next_index; | |
3510 } | |
3511 i = next_index; | |
3512 break; | |
3513 case '`': | |
3514 if (i > last) { | |
3515 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); | |
3516 } | |
3517 parts->Add(ReplacementPart::SubjectPrefix(), zone); | |
3518 i = next_index; | |
3519 last = i + 1; | |
3520 break; | |
3521 case '\'': | |
3522 if (i > last) { | |
3523 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); | |
3524 } | |
3525 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone); | |
3526 i = next_index; | |
3527 last = i + 1; | |
3528 break; | |
3529 case '&': | |
3530 if (i > last) { | |
3531 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); | |
3532 } | |
3533 parts->Add(ReplacementPart::SubjectMatch(), zone); | |
3534 i = next_index; | |
3535 last = i + 1; | |
3536 break; | |
3537 case '0': | |
3538 case '1': | |
3539 case '2': | |
3540 case '3': | |
3541 case '4': | |
3542 case '5': | |
3543 case '6': | |
3544 case '7': | |
3545 case '8': | |
3546 case '9': { | |
3547 int capture_ref = c2 - '0'; | |
3548 if (capture_ref > capture_count) { | |
3549 i = next_index; | |
3550 continue; | |
3551 } | |
3552 int second_digit_index = next_index + 1; | |
3553 if (second_digit_index < length) { | |
3554 // Peek ahead to see if we have two digits. | |
3555 Char c3 = characters[second_digit_index]; | |
3556 if ('0' <= c3 && c3 <= '9') { // Double digits. | |
3557 int double_digit_ref = capture_ref * 10 + c3 - '0'; | |
3558 if (double_digit_ref <= capture_count) { | |
3559 next_index = second_digit_index; | |
3560 capture_ref = double_digit_ref; | |
3561 } | |
3562 } | |
3563 } | |
3564 if (capture_ref > 0) { | |
3565 if (i > last) { | |
3566 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); | |
3567 } | |
3568 DCHECK(capture_ref <= capture_count); | |
3569 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); | |
3570 last = next_index + 1; | |
3571 } | |
3572 i = next_index; | |
3573 break; | |
3574 } | |
3575 default: | |
3576 i = next_index; | |
3577 break; | |
3578 } | |
3579 } | |
3580 } | |
3581 if (length > last) { | |
3582 if (last == 0) { | |
3583 // Replacement is simple. Do not use Apply to do the replacement. | |
3584 return true; | |
3585 } else { | |
3586 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); | |
3587 } | |
3588 } | |
3589 return false; | |
3590 } | |
3591 | |
3592 ZoneList<ReplacementPart> parts_; | |
3593 ZoneList<Handle<String> > replacement_substrings_; | |
3594 Zone* zone_; | |
3595 }; | |
3596 | |
3597 | |
3598 bool CompiledReplacement::Compile(Handle<String> replacement, | |
3599 int capture_count, | |
3600 int subject_length) { | |
3601 { | |
3602 DisallowHeapAllocation no_gc; | |
3603 String::FlatContent content = replacement->GetFlatContent(); | |
3604 DCHECK(content.IsFlat()); | |
3605 bool simple = false; | |
3606 if (content.IsOneByte()) { | |
3607 simple = ParseReplacementPattern(&parts_, | |
3608 content.ToOneByteVector(), | |
3609 capture_count, | |
3610 subject_length, | |
3611 zone()); | |
3612 } else { | |
3613 DCHECK(content.IsTwoByte()); | |
3614 simple = ParseReplacementPattern(&parts_, | |
3615 content.ToUC16Vector(), | |
3616 capture_count, | |
3617 subject_length, | |
3618 zone()); | |
3619 } | |
3620 if (simple) return true; | |
3621 } | |
3622 | |
3623 Isolate* isolate = replacement->GetIsolate(); | |
3624 // Find substrings of replacement string and create them as String objects. | |
3625 int substring_index = 0; | |
3626 for (int i = 0, n = parts_.length(); i < n; i++) { | |
3627 int tag = parts_[i].tag; | |
3628 if (tag <= 0) { // A replacement string slice. | |
3629 int from = -tag; | |
3630 int to = parts_[i].data; | |
3631 replacement_substrings_.Add( | |
3632 isolate->factory()->NewSubString(replacement, from, to), zone()); | |
3633 parts_[i].tag = REPLACEMENT_SUBSTRING; | |
3634 parts_[i].data = substring_index; | |
3635 substring_index++; | |
3636 } else if (tag == REPLACEMENT_STRING) { | |
3637 replacement_substrings_.Add(replacement, zone()); | |
3638 parts_[i].data = substring_index; | |
3639 substring_index++; | |
3640 } | |
3641 } | |
3642 return false; | |
3643 } | |
3644 | |
3645 | |
3646 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, | |
3647 int match_from, | |
3648 int match_to, | |
3649 int32_t* match) { | |
3650 DCHECK_LT(0, parts_.length()); | |
3651 for (int i = 0, n = parts_.length(); i < n; i++) { | |
3652 ReplacementPart part = parts_[i]; | |
3653 switch (part.tag) { | |
3654 case SUBJECT_PREFIX: | |
3655 if (match_from > 0) builder->AddSubjectSlice(0, match_from); | |
3656 break; | |
3657 case SUBJECT_SUFFIX: { | |
3658 int subject_length = part.data; | |
3659 if (match_to < subject_length) { | |
3660 builder->AddSubjectSlice(match_to, subject_length); | |
3661 } | |
3662 break; | |
3663 } | |
3664 case SUBJECT_CAPTURE: { | |
3665 int capture = part.data; | |
3666 int from = match[capture * 2]; | |
3667 int to = match[capture * 2 + 1]; | |
3668 if (from >= 0 && to > from) { | |
3669 builder->AddSubjectSlice(from, to); | |
3670 } | |
3671 break; | |
3672 } | |
3673 case REPLACEMENT_SUBSTRING: | |
3674 case REPLACEMENT_STRING: | |
3675 builder->AddString(replacement_substrings_[part.data]); | |
3676 break; | |
3677 default: | |
3678 UNREACHABLE(); | |
3679 } | |
3680 } | |
3681 } | |
3682 | |
3683 | |
3684 void FindOneByteStringIndices(Vector<const uint8_t> subject, char pattern, | |
3685 ZoneList<int>* indices, unsigned int limit, | |
3686 Zone* zone) { | |
3687 DCHECK(limit > 0); | |
3688 // Collect indices of pattern in subject using memchr. | |
3689 // Stop after finding at most limit values. | |
3690 const uint8_t* subject_start = subject.start(); | |
3691 const uint8_t* subject_end = subject_start + subject.length(); | |
3692 const uint8_t* pos = subject_start; | |
3693 while (limit > 0) { | |
3694 pos = reinterpret_cast<const uint8_t*>( | |
3695 memchr(pos, pattern, subject_end - pos)); | |
3696 if (pos == NULL) return; | |
3697 indices->Add(static_cast<int>(pos - subject_start), zone); | |
3698 pos++; | |
3699 limit--; | |
3700 } | |
3701 } | |
3702 | |
3703 | |
3704 void FindTwoByteStringIndices(const Vector<const uc16> subject, | |
3705 uc16 pattern, | |
3706 ZoneList<int>* indices, | |
3707 unsigned int limit, | |
3708 Zone* zone) { | |
3709 DCHECK(limit > 0); | |
3710 const uc16* subject_start = subject.start(); | |
3711 const uc16* subject_end = subject_start + subject.length(); | |
3712 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { | |
3713 if (*pos == pattern) { | |
3714 indices->Add(static_cast<int>(pos - subject_start), zone); | |
3715 limit--; | |
3716 } | |
3717 } | |
3718 } | |
3719 | |
3720 | |
3721 template <typename SubjectChar, typename PatternChar> | |
3722 void FindStringIndices(Isolate* isolate, | |
3723 Vector<const SubjectChar> subject, | |
3724 Vector<const PatternChar> pattern, | |
3725 ZoneList<int>* indices, | |
3726 unsigned int limit, | |
3727 Zone* zone) { | |
3728 DCHECK(limit > 0); | |
3729 // Collect indices of pattern in subject. | |
3730 // Stop after finding at most limit values. | |
3731 int pattern_length = pattern.length(); | |
3732 int index = 0; | |
3733 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); | |
3734 while (limit > 0) { | |
3735 index = search.Search(subject, index); | |
3736 if (index < 0) return; | |
3737 indices->Add(index, zone); | |
3738 index += pattern_length; | |
3739 limit--; | |
3740 } | |
3741 } | |
3742 | |
3743 | |
3744 void FindStringIndicesDispatch(Isolate* isolate, | |
3745 String* subject, | |
3746 String* pattern, | |
3747 ZoneList<int>* indices, | |
3748 unsigned int limit, | |
3749 Zone* zone) { | |
3750 { | |
3751 DisallowHeapAllocation no_gc; | |
3752 String::FlatContent subject_content = subject->GetFlatContent(); | |
3753 String::FlatContent pattern_content = pattern->GetFlatContent(); | |
3754 DCHECK(subject_content.IsFlat()); | |
3755 DCHECK(pattern_content.IsFlat()); | |
3756 if (subject_content.IsOneByte()) { | |
3757 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector(); | |
3758 if (pattern_content.IsOneByte()) { | |
3759 Vector<const uint8_t> pattern_vector = | |
3760 pattern_content.ToOneByteVector(); | |
3761 if (pattern_vector.length() == 1) { | |
3762 FindOneByteStringIndices(subject_vector, pattern_vector[0], indices, | |
3763 limit, zone); | |
3764 } else { | |
3765 FindStringIndices(isolate, | |
3766 subject_vector, | |
3767 pattern_vector, | |
3768 indices, | |
3769 limit, | |
3770 zone); | |
3771 } | |
3772 } else { | |
3773 FindStringIndices(isolate, | |
3774 subject_vector, | |
3775 pattern_content.ToUC16Vector(), | |
3776 indices, | |
3777 limit, | |
3778 zone); | |
3779 } | |
3780 } else { | |
3781 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); | |
3782 if (pattern_content.IsOneByte()) { | |
3783 Vector<const uint8_t> pattern_vector = | |
3784 pattern_content.ToOneByteVector(); | |
3785 if (pattern_vector.length() == 1) { | |
3786 FindTwoByteStringIndices(subject_vector, | |
3787 pattern_vector[0], | |
3788 indices, | |
3789 limit, | |
3790 zone); | |
3791 } else { | |
3792 FindStringIndices(isolate, | |
3793 subject_vector, | |
3794 pattern_vector, | |
3795 indices, | |
3796 limit, | |
3797 zone); | |
3798 } | |
3799 } else { | |
3800 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); | |
3801 if (pattern_vector.length() == 1) { | |
3802 FindTwoByteStringIndices(subject_vector, | |
3803 pattern_vector[0], | |
3804 indices, | |
3805 limit, | |
3806 zone); | |
3807 } else { | |
3808 FindStringIndices(isolate, | |
3809 subject_vector, | |
3810 pattern_vector, | |
3811 indices, | |
3812 limit, | |
3813 zone); | |
3814 } | |
3815 } | |
3816 } | |
3817 } | |
3818 } | |
3819 | |
3820 | |
3821 template<typename ResultSeqString> | |
3822 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( | |
3823 Isolate* isolate, | |
3824 Handle<String> subject, | |
3825 Handle<JSRegExp> pattern_regexp, | |
3826 Handle<String> replacement, | |
3827 Handle<JSArray> last_match_info) { | |
3828 DCHECK(subject->IsFlat()); | |
3829 DCHECK(replacement->IsFlat()); | |
3830 | |
3831 ZoneScope zone_scope(isolate->runtime_zone()); | |
3832 ZoneList<int> indices(8, zone_scope.zone()); | |
3833 DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); | |
3834 String* pattern = | |
3835 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); | |
3836 int subject_len = subject->length(); | |
3837 int pattern_len = pattern->length(); | |
3838 int replacement_len = replacement->length(); | |
3839 | |
3840 FindStringIndicesDispatch( | |
3841 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone()); | |
3842 | |
3843 int matches = indices.length(); | |
3844 if (matches == 0) return *subject; | |
3845 | |
3846 // Detect integer overflow. | |
3847 int64_t result_len_64 = | |
3848 (static_cast<int64_t>(replacement_len) - | |
3849 static_cast<int64_t>(pattern_len)) * | |
3850 static_cast<int64_t>(matches) + | |
3851 static_cast<int64_t>(subject_len); | |
3852 int result_len; | |
3853 if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) { | |
3854 STATIC_ASSERT(String::kMaxLength < kMaxInt); | |
3855 result_len = kMaxInt; // Provoke exception. | |
3856 } else { | |
3857 result_len = static_cast<int>(result_len_64); | |
3858 } | |
3859 | |
3860 int subject_pos = 0; | |
3861 int result_pos = 0; | |
3862 | |
3863 MaybeHandle<SeqString> maybe_res; | |
3864 if (ResultSeqString::kHasOneByteEncoding) { | |
3865 maybe_res = isolate->factory()->NewRawOneByteString(result_len); | |
3866 } else { | |
3867 maybe_res = isolate->factory()->NewRawTwoByteString(result_len); | |
3868 } | |
3869 Handle<SeqString> untyped_res; | |
3870 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res); | |
3871 Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res); | |
3872 | |
3873 for (int i = 0; i < matches; i++) { | |
3874 // Copy non-matched subject content. | |
3875 if (subject_pos < indices.at(i)) { | |
3876 String::WriteToFlat(*subject, | |
3877 result->GetChars() + result_pos, | |
3878 subject_pos, | |
3879 indices.at(i)); | |
3880 result_pos += indices.at(i) - subject_pos; | |
3881 } | |
3882 | |
3883 // Replace match. | |
3884 if (replacement_len > 0) { | |
3885 String::WriteToFlat(*replacement, | |
3886 result->GetChars() + result_pos, | |
3887 0, | |
3888 replacement_len); | |
3889 result_pos += replacement_len; | |
3890 } | |
3891 | |
3892 subject_pos = indices.at(i) + pattern_len; | |
3893 } | |
3894 // Add remaining subject content at the end. | |
3895 if (subject_pos < subject_len) { | |
3896 String::WriteToFlat(*subject, | |
3897 result->GetChars() + result_pos, | |
3898 subject_pos, | |
3899 subject_len); | |
3900 } | |
3901 | |
3902 int32_t match_indices[] = { indices.at(matches - 1), | |
3903 indices.at(matches - 1) + pattern_len }; | |
3904 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); | |
3905 | |
3906 return *result; | |
3907 } | |
3908 | |
3909 | |
3910 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( | |
3911 Isolate* isolate, | |
3912 Handle<String> subject, | |
3913 Handle<JSRegExp> regexp, | |
3914 Handle<String> replacement, | |
3915 Handle<JSArray> last_match_info) { | |
3916 DCHECK(subject->IsFlat()); | |
3917 DCHECK(replacement->IsFlat()); | |
3918 | |
3919 int capture_count = regexp->CaptureCount(); | |
3920 int subject_length = subject->length(); | |
3921 | |
3922 // CompiledReplacement uses zone allocation. | |
3923 ZoneScope zone_scope(isolate->runtime_zone()); | |
3924 CompiledReplacement compiled_replacement(zone_scope.zone()); | |
3925 bool simple_replace = compiled_replacement.Compile(replacement, | |
3926 capture_count, | |
3927 subject_length); | |
3928 | |
3929 // Shortcut for simple non-regexp global replacements | |
3930 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { | |
3931 if (subject->HasOnlyOneByteChars() && | |
3932 replacement->HasOnlyOneByteChars()) { | |
3933 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( | |
3934 isolate, subject, regexp, replacement, last_match_info); | |
3935 } else { | |
3936 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( | |
3937 isolate, subject, regexp, replacement, last_match_info); | |
3938 } | |
3939 } | |
3940 | |
3941 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); | |
3942 if (global_cache.HasException()) return isolate->heap()->exception(); | |
3943 | |
3944 int32_t* current_match = global_cache.FetchNext(); | |
3945 if (current_match == NULL) { | |
3946 if (global_cache.HasException()) return isolate->heap()->exception(); | |
3947 return *subject; | |
3948 } | |
3949 | |
3950 // Guessing the number of parts that the final result string is built | |
3951 // from. Global regexps can match any number of times, so we guess | |
3952 // conservatively. | |
3953 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1; | |
3954 ReplacementStringBuilder builder(isolate->heap(), | |
3955 subject, | |
3956 expected_parts); | |
3957 | |
3958 // Number of parts added by compiled replacement plus preceeding | |
3959 // string and possibly suffix after last match. It is possible for | |
3960 // all components to use two elements when encoded as two smis. | |
3961 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); | |
3962 | |
3963 int prev = 0; | |
3964 | |
3965 do { | |
3966 builder.EnsureCapacity(parts_added_per_loop); | |
3967 | |
3968 int start = current_match[0]; | |
3969 int end = current_match[1]; | |
3970 | |
3971 if (prev < start) { | |
3972 builder.AddSubjectSlice(prev, start); | |
3973 } | |
3974 | |
3975 if (simple_replace) { | |
3976 builder.AddString(replacement); | |
3977 } else { | |
3978 compiled_replacement.Apply(&builder, | |
3979 start, | |
3980 end, | |
3981 current_match); | |
3982 } | |
3983 prev = end; | |
3984 | |
3985 current_match = global_cache.FetchNext(); | |
3986 } while (current_match != NULL); | |
3987 | |
3988 if (global_cache.HasException()) return isolate->heap()->exception(); | |
3989 | |
3990 if (prev < subject_length) { | |
3991 builder.EnsureCapacity(2); | |
3992 builder.AddSubjectSlice(prev, subject_length); | |
3993 } | |
3994 | |
3995 RegExpImpl::SetLastMatchInfo(last_match_info, | |
3996 subject, | |
3997 capture_count, | |
3998 global_cache.LastSuccessfulMatch()); | |
3999 | |
4000 Handle<String> result; | |
4001 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString()); | |
4002 return *result; | |
4003 } | |
4004 | |
4005 | |
4006 template <typename ResultSeqString> | |
4007 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( | |
4008 Isolate* isolate, | |
4009 Handle<String> subject, | |
4010 Handle<JSRegExp> regexp, | |
4011 Handle<JSArray> last_match_info) { | |
4012 DCHECK(subject->IsFlat()); | |
4013 | |
4014 // Shortcut for simple non-regexp global replacements | |
4015 if (regexp->TypeTag() == JSRegExp::ATOM) { | |
4016 Handle<String> empty_string = isolate->factory()->empty_string(); | |
4017 if (subject->IsOneByteRepresentation()) { | |
4018 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( | |
4019 isolate, subject, regexp, empty_string, last_match_info); | |
4020 } else { | |
4021 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( | |
4022 isolate, subject, regexp, empty_string, last_match_info); | |
4023 } | |
4024 } | |
4025 | |
4026 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); | |
4027 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4028 | |
4029 int32_t* current_match = global_cache.FetchNext(); | |
4030 if (current_match == NULL) { | |
4031 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4032 return *subject; | |
4033 } | |
4034 | |
4035 int start = current_match[0]; | |
4036 int end = current_match[1]; | |
4037 int capture_count = regexp->CaptureCount(); | |
4038 int subject_length = subject->length(); | |
4039 | |
4040 int new_length = subject_length - (end - start); | |
4041 if (new_length == 0) return isolate->heap()->empty_string(); | |
4042 | |
4043 Handle<ResultSeqString> answer; | |
4044 if (ResultSeqString::kHasOneByteEncoding) { | |
4045 answer = Handle<ResultSeqString>::cast( | |
4046 isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked()); | |
4047 } else { | |
4048 answer = Handle<ResultSeqString>::cast( | |
4049 isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked()); | |
4050 } | |
4051 | |
4052 int prev = 0; | |
4053 int position = 0; | |
4054 | |
4055 do { | |
4056 start = current_match[0]; | |
4057 end = current_match[1]; | |
4058 if (prev < start) { | |
4059 // Add substring subject[prev;start] to answer string. | |
4060 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start); | |
4061 position += start - prev; | |
4062 } | |
4063 prev = end; | |
4064 | |
4065 current_match = global_cache.FetchNext(); | |
4066 } while (current_match != NULL); | |
4067 | |
4068 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4069 | |
4070 RegExpImpl::SetLastMatchInfo(last_match_info, | |
4071 subject, | |
4072 capture_count, | |
4073 global_cache.LastSuccessfulMatch()); | |
4074 | |
4075 if (prev < subject_length) { | |
4076 // Add substring subject[prev;length] to answer string. | |
4077 String::WriteToFlat( | |
4078 *subject, answer->GetChars() + position, prev, subject_length); | |
4079 position += subject_length - prev; | |
4080 } | |
4081 | |
4082 if (position == 0) return isolate->heap()->empty_string(); | |
4083 | |
4084 // Shorten string and fill | |
4085 int string_size = ResultSeqString::SizeFor(position); | |
4086 int allocated_string_size = ResultSeqString::SizeFor(new_length); | |
4087 int delta = allocated_string_size - string_size; | |
4088 | |
4089 answer->set_length(position); | |
4090 if (delta == 0) return *answer; | |
4091 | |
4092 Address end_of_string = answer->address() + string_size; | |
4093 Heap* heap = isolate->heap(); | |
4094 | |
4095 // The trimming is performed on a newly allocated object, which is on a | |
4096 // fresly allocated page or on an already swept page. Hence, the sweeper | |
4097 // thread can not get confused with the filler creation. No synchronization | |
4098 // needed. | |
4099 heap->CreateFillerObjectAt(end_of_string, delta); | |
4100 heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR); | |
4101 return *answer; | |
4102 } | |
4103 | |
4104 | |
4105 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { | |
4106 HandleScope scope(isolate); | |
4107 DCHECK(args.length() == 4); | |
4108 | |
4109 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
4110 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); | |
4111 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | |
4112 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); | |
4113 | |
4114 RUNTIME_ASSERT(regexp->GetFlags().is_global()); | |
4115 RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); | |
4116 | |
4117 subject = String::Flatten(subject); | |
4118 | |
4119 if (replacement->length() == 0) { | |
4120 if (subject->HasOnlyOneByteChars()) { | |
4121 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( | |
4122 isolate, subject, regexp, last_match_info); | |
4123 } else { | |
4124 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( | |
4125 isolate, subject, regexp, last_match_info); | |
4126 } | |
4127 } | |
4128 | |
4129 replacement = String::Flatten(replacement); | |
4130 | |
4131 return StringReplaceGlobalRegExpWithString( | |
4132 isolate, subject, regexp, replacement, last_match_info); | |
4133 } | |
4134 | |
4135 | |
4136 // This may return an empty MaybeHandle if an exception is thrown or | |
4137 // we abort due to reaching the recursion limit. | |
4138 MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate, | |
4139 Handle<String> subject, | |
4140 Handle<String> search, | |
4141 Handle<String> replace, | |
4142 bool* found, | |
4143 int recursion_limit) { | |
4144 StackLimitCheck stackLimitCheck(isolate); | |
4145 if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) { | |
4146 return MaybeHandle<String>(); | |
4147 } | |
4148 recursion_limit--; | |
4149 if (subject->IsConsString()) { | |
4150 ConsString* cons = ConsString::cast(*subject); | |
4151 Handle<String> first = Handle<String>(cons->first()); | |
4152 Handle<String> second = Handle<String>(cons->second()); | |
4153 Handle<String> new_first; | |
4154 if (!StringReplaceOneCharWithString( | |
4155 isolate, first, search, replace, found, recursion_limit) | |
4156 .ToHandle(&new_first)) { | |
4157 return MaybeHandle<String>(); | |
4158 } | |
4159 if (*found) return isolate->factory()->NewConsString(new_first, second); | |
4160 | |
4161 Handle<String> new_second; | |
4162 if (!StringReplaceOneCharWithString( | |
4163 isolate, second, search, replace, found, recursion_limit) | |
4164 .ToHandle(&new_second)) { | |
4165 return MaybeHandle<String>(); | |
4166 } | |
4167 if (*found) return isolate->factory()->NewConsString(first, new_second); | |
4168 | |
4169 return subject; | |
4170 } else { | |
4171 int index = Runtime::StringMatch(isolate, subject, search, 0); | |
4172 if (index == -1) return subject; | |
4173 *found = true; | |
4174 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); | |
4175 Handle<String> cons1; | |
4176 ASSIGN_RETURN_ON_EXCEPTION( | |
4177 isolate, cons1, | |
4178 isolate->factory()->NewConsString(first, replace), | |
4179 String); | |
4180 Handle<String> second = | |
4181 isolate->factory()->NewSubString(subject, index + 1, subject->length()); | |
4182 return isolate->factory()->NewConsString(cons1, second); | |
4183 } | |
4184 } | |
4185 | |
4186 | |
4187 RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) { | |
4188 HandleScope scope(isolate); | |
4189 DCHECK(args.length() == 3); | |
4190 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
4191 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); | |
4192 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); | |
4193 | |
4194 // If the cons string tree is too deep, we simply abort the recursion and | |
4195 // retry with a flattened subject string. | |
4196 const int kRecursionLimit = 0x1000; | |
4197 bool found = false; | |
4198 Handle<String> result; | |
4199 if (StringReplaceOneCharWithString( | |
4200 isolate, subject, search, replace, &found, kRecursionLimit) | |
4201 .ToHandle(&result)) { | |
4202 return *result; | |
4203 } | |
4204 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | |
4205 | |
4206 subject = String::Flatten(subject); | |
4207 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
4208 isolate, result, | |
4209 StringReplaceOneCharWithString( | |
4210 isolate, subject, search, replace, &found, kRecursionLimit)); | |
4211 return *result; | |
4212 } | |
4213 | |
4214 | |
4215 // Perform string match of pattern on subject, starting at start index. | |
4216 // Caller must ensure that 0 <= start_index <= sub->length(), | |
4217 // and should check that pat->length() + start_index <= sub->length(). | |
4218 int Runtime::StringMatch(Isolate* isolate, | |
4219 Handle<String> sub, | |
4220 Handle<String> pat, | |
4221 int start_index) { | |
4222 DCHECK(0 <= start_index); | |
4223 DCHECK(start_index <= sub->length()); | |
4224 | |
4225 int pattern_length = pat->length(); | |
4226 if (pattern_length == 0) return start_index; | |
4227 | |
4228 int subject_length = sub->length(); | |
4229 if (start_index + pattern_length > subject_length) return -1; | |
4230 | |
4231 sub = String::Flatten(sub); | |
4232 pat = String::Flatten(pat); | |
4233 | |
4234 DisallowHeapAllocation no_gc; // ensure vectors stay valid | |
4235 // Extract flattened substrings of cons strings before getting encoding. | |
4236 String::FlatContent seq_sub = sub->GetFlatContent(); | |
4237 String::FlatContent seq_pat = pat->GetFlatContent(); | |
4238 | |
4239 // dispatch on type of strings | |
4240 if (seq_pat.IsOneByte()) { | |
4241 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector(); | |
4242 if (seq_sub.IsOneByte()) { | |
4243 return SearchString(isolate, | |
4244 seq_sub.ToOneByteVector(), | |
4245 pat_vector, | |
4246 start_index); | |
4247 } | |
4248 return SearchString(isolate, | |
4249 seq_sub.ToUC16Vector(), | |
4250 pat_vector, | |
4251 start_index); | |
4252 } | |
4253 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); | |
4254 if (seq_sub.IsOneByte()) { | |
4255 return SearchString(isolate, | |
4256 seq_sub.ToOneByteVector(), | |
4257 pat_vector, | |
4258 start_index); | |
4259 } | |
4260 return SearchString(isolate, | |
4261 seq_sub.ToUC16Vector(), | |
4262 pat_vector, | |
4263 start_index); | |
4264 } | |
4265 | |
4266 | |
4267 RUNTIME_FUNCTION(Runtime_StringIndexOf) { | |
4268 HandleScope scope(isolate); | |
4269 DCHECK(args.length() == 3); | |
4270 | |
4271 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); | |
4272 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); | |
4273 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); | |
4274 | |
4275 uint32_t start_index; | |
4276 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); | |
4277 | |
4278 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); | |
4279 int position = Runtime::StringMatch(isolate, sub, pat, start_index); | |
4280 return Smi::FromInt(position); | |
4281 } | |
4282 | |
4283 | |
4284 template <typename schar, typename pchar> | |
4285 static int StringMatchBackwards(Vector<const schar> subject, | |
4286 Vector<const pchar> pattern, | |
4287 int idx) { | |
4288 int pattern_length = pattern.length(); | |
4289 DCHECK(pattern_length >= 1); | |
4290 DCHECK(idx + pattern_length <= subject.length()); | |
4291 | |
4292 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { | |
4293 for (int i = 0; i < pattern_length; i++) { | |
4294 uc16 c = pattern[i]; | |
4295 if (c > String::kMaxOneByteCharCode) { | |
4296 return -1; | |
4297 } | |
4298 } | |
4299 } | |
4300 | |
4301 pchar pattern_first_char = pattern[0]; | |
4302 for (int i = idx; i >= 0; i--) { | |
4303 if (subject[i] != pattern_first_char) continue; | |
4304 int j = 1; | |
4305 while (j < pattern_length) { | |
4306 if (pattern[j] != subject[i+j]) { | |
4307 break; | |
4308 } | |
4309 j++; | |
4310 } | |
4311 if (j == pattern_length) { | |
4312 return i; | |
4313 } | |
4314 } | |
4315 return -1; | |
4316 } | |
4317 | |
4318 | |
4319 RUNTIME_FUNCTION(Runtime_StringLastIndexOf) { | |
4320 HandleScope scope(isolate); | |
4321 DCHECK(args.length() == 3); | |
4322 | |
4323 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); | |
4324 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); | |
4325 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); | |
4326 | |
4327 uint32_t start_index; | |
4328 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); | |
4329 | |
4330 uint32_t pat_length = pat->length(); | |
4331 uint32_t sub_length = sub->length(); | |
4332 | |
4333 if (start_index + pat_length > sub_length) { | |
4334 start_index = sub_length - pat_length; | |
4335 } | |
4336 | |
4337 if (pat_length == 0) { | |
4338 return Smi::FromInt(start_index); | |
4339 } | |
4340 | |
4341 sub = String::Flatten(sub); | |
4342 pat = String::Flatten(pat); | |
4343 | |
4344 int position = -1; | |
4345 DisallowHeapAllocation no_gc; // ensure vectors stay valid | |
4346 | |
4347 String::FlatContent sub_content = sub->GetFlatContent(); | |
4348 String::FlatContent pat_content = pat->GetFlatContent(); | |
4349 | |
4350 if (pat_content.IsOneByte()) { | |
4351 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector(); | |
4352 if (sub_content.IsOneByte()) { | |
4353 position = StringMatchBackwards(sub_content.ToOneByteVector(), | |
4354 pat_vector, | |
4355 start_index); | |
4356 } else { | |
4357 position = StringMatchBackwards(sub_content.ToUC16Vector(), | |
4358 pat_vector, | |
4359 start_index); | |
4360 } | |
4361 } else { | |
4362 Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); | |
4363 if (sub_content.IsOneByte()) { | |
4364 position = StringMatchBackwards(sub_content.ToOneByteVector(), | |
4365 pat_vector, | |
4366 start_index); | |
4367 } else { | |
4368 position = StringMatchBackwards(sub_content.ToUC16Vector(), | |
4369 pat_vector, | |
4370 start_index); | |
4371 } | |
4372 } | |
4373 | |
4374 return Smi::FromInt(position); | |
4375 } | |
4376 | |
4377 | |
4378 RUNTIME_FUNCTION(Runtime_StringLocaleCompare) { | |
4379 HandleScope handle_scope(isolate); | |
4380 DCHECK(args.length() == 2); | |
4381 | |
4382 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); | |
4383 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); | |
4384 | |
4385 if (str1.is_identical_to(str2)) return Smi::FromInt(0); // Equal. | |
4386 int str1_length = str1->length(); | |
4387 int str2_length = str2->length(); | |
4388 | |
4389 // Decide trivial cases without flattening. | |
4390 if (str1_length == 0) { | |
4391 if (str2_length == 0) return Smi::FromInt(0); // Equal. | |
4392 return Smi::FromInt(-str2_length); | |
4393 } else { | |
4394 if (str2_length == 0) return Smi::FromInt(str1_length); | |
4395 } | |
4396 | |
4397 int end = str1_length < str2_length ? str1_length : str2_length; | |
4398 | |
4399 // No need to flatten if we are going to find the answer on the first | |
4400 // character. At this point we know there is at least one character | |
4401 // in each string, due to the trivial case handling above. | |
4402 int d = str1->Get(0) - str2->Get(0); | |
4403 if (d != 0) return Smi::FromInt(d); | |
4404 | |
4405 str1 = String::Flatten(str1); | |
4406 str2 = String::Flatten(str2); | |
4407 | |
4408 DisallowHeapAllocation no_gc; | |
4409 String::FlatContent flat1 = str1->GetFlatContent(); | |
4410 String::FlatContent flat2 = str2->GetFlatContent(); | |
4411 | |
4412 for (int i = 0; i < end; i++) { | |
4413 if (flat1.Get(i) != flat2.Get(i)) { | |
4414 return Smi::FromInt(flat1.Get(i) - flat2.Get(i)); | |
4415 } | |
4416 } | |
4417 | |
4418 return Smi::FromInt(str1_length - str2_length); | |
4419 } | |
4420 | |
4421 | |
4422 RUNTIME_FUNCTION(Runtime_SubString) { | |
4423 HandleScope scope(isolate); | |
4424 DCHECK(args.length() == 3); | |
4425 | |
4426 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); | |
4427 int start, end; | |
4428 // We have a fast integer-only case here to avoid a conversion to double in | |
4429 // the common case where from and to are Smis. | |
4430 if (args[1]->IsSmi() && args[2]->IsSmi()) { | |
4431 CONVERT_SMI_ARG_CHECKED(from_number, 1); | |
4432 CONVERT_SMI_ARG_CHECKED(to_number, 2); | |
4433 start = from_number; | |
4434 end = to_number; | |
4435 } else { | |
4436 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); | |
4437 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); | |
4438 start = FastD2IChecked(from_number); | |
4439 end = FastD2IChecked(to_number); | |
4440 } | |
4441 RUNTIME_ASSERT(end >= start); | |
4442 RUNTIME_ASSERT(start >= 0); | |
4443 RUNTIME_ASSERT(end <= string->length()); | |
4444 isolate->counters()->sub_string_runtime()->Increment(); | |
4445 | |
4446 return *isolate->factory()->NewSubString(string, start, end); | |
4447 } | |
4448 | |
4449 | |
4450 RUNTIME_FUNCTION(Runtime_InternalizeString) { | |
4451 HandleScope handles(isolate); | |
4452 RUNTIME_ASSERT(args.length() == 1); | |
4453 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); | |
4454 return *isolate->factory()->InternalizeString(string); | |
4455 } | |
4456 | |
4457 | |
4458 RUNTIME_FUNCTION(Runtime_StringMatch) { | |
4459 HandleScope handles(isolate); | |
4460 DCHECK(args.length() == 3); | |
4461 | |
4462 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
4463 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | |
4464 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); | |
4465 | |
4466 RUNTIME_ASSERT(regexp_info->HasFastObjectElements()); | |
4467 | |
4468 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); | |
4469 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4470 | |
4471 int capture_count = regexp->CaptureCount(); | |
4472 | |
4473 ZoneScope zone_scope(isolate->runtime_zone()); | |
4474 ZoneList<int> offsets(8, zone_scope.zone()); | |
4475 | |
4476 while (true) { | |
4477 int32_t* match = global_cache.FetchNext(); | |
4478 if (match == NULL) break; | |
4479 offsets.Add(match[0], zone_scope.zone()); // start | |
4480 offsets.Add(match[1], zone_scope.zone()); // end | |
4481 } | |
4482 | |
4483 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4484 | |
4485 if (offsets.length() == 0) { | |
4486 // Not a single match. | |
4487 return isolate->heap()->null_value(); | |
4488 } | |
4489 | |
4490 RegExpImpl::SetLastMatchInfo(regexp_info, | |
4491 subject, | |
4492 capture_count, | |
4493 global_cache.LastSuccessfulMatch()); | |
4494 | |
4495 int matches = offsets.length() / 2; | |
4496 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); | |
4497 Handle<String> substring = | |
4498 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); | |
4499 elements->set(0, *substring); | |
4500 for (int i = 1; i < matches; i++) { | |
4501 HandleScope temp_scope(isolate); | |
4502 int from = offsets.at(i * 2); | |
4503 int to = offsets.at(i * 2 + 1); | |
4504 Handle<String> substring = | |
4505 isolate->factory()->NewProperSubString(subject, from, to); | |
4506 elements->set(i, *substring); | |
4507 } | |
4508 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); | |
4509 result->set_length(Smi::FromInt(matches)); | |
4510 return *result; | |
4511 } | |
4512 | |
4513 | |
4514 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain | |
4515 // separate last match info. See comment on that function. | |
4516 template<bool has_capture> | |
4517 static Object* SearchRegExpMultiple( | |
4518 Isolate* isolate, | |
4519 Handle<String> subject, | |
4520 Handle<JSRegExp> regexp, | |
4521 Handle<JSArray> last_match_array, | |
4522 Handle<JSArray> result_array) { | |
4523 DCHECK(subject->IsFlat()); | |
4524 DCHECK_NE(has_capture, regexp->CaptureCount() == 0); | |
4525 | |
4526 int capture_count = regexp->CaptureCount(); | |
4527 int subject_length = subject->length(); | |
4528 | |
4529 static const int kMinLengthToCache = 0x1000; | |
4530 | |
4531 if (subject_length > kMinLengthToCache) { | |
4532 Handle<Object> cached_answer(RegExpResultsCache::Lookup( | |
4533 isolate->heap(), | |
4534 *subject, | |
4535 regexp->data(), | |
4536 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate); | |
4537 if (*cached_answer != Smi::FromInt(0)) { | |
4538 Handle<FixedArray> cached_fixed_array = | |
4539 Handle<FixedArray>(FixedArray::cast(*cached_answer)); | |
4540 // The cache FixedArray is a COW-array and can therefore be reused. | |
4541 JSArray::SetContent(result_array, cached_fixed_array); | |
4542 // The actual length of the result array is stored in the last element of | |
4543 // the backing store (the backing FixedArray may have a larger capacity). | |
4544 Object* cached_fixed_array_last_element = | |
4545 cached_fixed_array->get(cached_fixed_array->length() - 1); | |
4546 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element); | |
4547 result_array->set_length(js_array_length); | |
4548 RegExpImpl::SetLastMatchInfo( | |
4549 last_match_array, subject, capture_count, NULL); | |
4550 return *result_array; | |
4551 } | |
4552 } | |
4553 | |
4554 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); | |
4555 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4556 | |
4557 // Ensured in Runtime_RegExpExecMultiple. | |
4558 DCHECK(result_array->HasFastObjectElements()); | |
4559 Handle<FixedArray> result_elements( | |
4560 FixedArray::cast(result_array->elements())); | |
4561 if (result_elements->length() < 16) { | |
4562 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); | |
4563 } | |
4564 | |
4565 FixedArrayBuilder builder(result_elements); | |
4566 | |
4567 // Position to search from. | |
4568 int match_start = -1; | |
4569 int match_end = 0; | |
4570 bool first = true; | |
4571 | |
4572 // Two smis before and after the match, for very long strings. | |
4573 static const int kMaxBuilderEntriesPerRegExpMatch = 5; | |
4574 | |
4575 while (true) { | |
4576 int32_t* current_match = global_cache.FetchNext(); | |
4577 if (current_match == NULL) break; | |
4578 match_start = current_match[0]; | |
4579 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
4580 if (match_end < match_start) { | |
4581 ReplacementStringBuilder::AddSubjectSlice(&builder, | |
4582 match_end, | |
4583 match_start); | |
4584 } | |
4585 match_end = current_match[1]; | |
4586 { | |
4587 // Avoid accumulating new handles inside loop. | |
4588 HandleScope temp_scope(isolate); | |
4589 Handle<String> match; | |
4590 if (!first) { | |
4591 match = isolate->factory()->NewProperSubString(subject, | |
4592 match_start, | |
4593 match_end); | |
4594 } else { | |
4595 match = isolate->factory()->NewSubString(subject, | |
4596 match_start, | |
4597 match_end); | |
4598 first = false; | |
4599 } | |
4600 | |
4601 if (has_capture) { | |
4602 // Arguments array to replace function is match, captures, index and | |
4603 // subject, i.e., 3 + capture count in total. | |
4604 Handle<FixedArray> elements = | |
4605 isolate->factory()->NewFixedArray(3 + capture_count); | |
4606 | |
4607 elements->set(0, *match); | |
4608 for (int i = 1; i <= capture_count; i++) { | |
4609 int start = current_match[i * 2]; | |
4610 if (start >= 0) { | |
4611 int end = current_match[i * 2 + 1]; | |
4612 DCHECK(start <= end); | |
4613 Handle<String> substring = | |
4614 isolate->factory()->NewSubString(subject, start, end); | |
4615 elements->set(i, *substring); | |
4616 } else { | |
4617 DCHECK(current_match[i * 2 + 1] < 0); | |
4618 elements->set(i, isolate->heap()->undefined_value()); | |
4619 } | |
4620 } | |
4621 elements->set(capture_count + 1, Smi::FromInt(match_start)); | |
4622 elements->set(capture_count + 2, *subject); | |
4623 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); | |
4624 } else { | |
4625 builder.Add(*match); | |
4626 } | |
4627 } | |
4628 } | |
4629 | |
4630 if (global_cache.HasException()) return isolate->heap()->exception(); | |
4631 | |
4632 if (match_start >= 0) { | |
4633 // Finished matching, with at least one match. | |
4634 if (match_end < subject_length) { | |
4635 ReplacementStringBuilder::AddSubjectSlice(&builder, | |
4636 match_end, | |
4637 subject_length); | |
4638 } | |
4639 | |
4640 RegExpImpl::SetLastMatchInfo( | |
4641 last_match_array, subject, capture_count, NULL); | |
4642 | |
4643 if (subject_length > kMinLengthToCache) { | |
4644 // Store the length of the result array into the last element of the | |
4645 // backing FixedArray. | |
4646 builder.EnsureCapacity(1); | |
4647 Handle<FixedArray> fixed_array = builder.array(); | |
4648 fixed_array->set(fixed_array->length() - 1, | |
4649 Smi::FromInt(builder.length())); | |
4650 // Cache the result and turn the FixedArray into a COW array. | |
4651 RegExpResultsCache::Enter(isolate, | |
4652 subject, | |
4653 handle(regexp->data(), isolate), | |
4654 fixed_array, | |
4655 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); | |
4656 } | |
4657 return *builder.ToJSArray(result_array); | |
4658 } else { | |
4659 return isolate->heap()->null_value(); // No matches at all. | |
4660 } | |
4661 } | |
4662 | |
4663 | |
4664 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets | |
4665 // lastMatchInfoOverride to maintain the last match info, so we don't need to | |
4666 // set any other last match array info. | |
4667 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { | |
4668 HandleScope handles(isolate); | |
4669 DCHECK(args.length() == 4); | |
4670 | |
4671 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | |
4672 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | |
4673 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); | |
4674 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); | |
4675 RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); | |
4676 RUNTIME_ASSERT(result_array->HasFastObjectElements()); | |
4677 | |
4678 subject = String::Flatten(subject); | |
4679 RUNTIME_ASSERT(regexp->GetFlags().is_global()); | |
4680 | |
4681 if (regexp->CaptureCount() == 0) { | |
4682 return SearchRegExpMultiple<false>( | |
4683 isolate, subject, regexp, last_match_info, result_array); | |
4684 } else { | |
4685 return SearchRegExpMultiple<true>( | |
4686 isolate, subject, regexp, last_match_info, result_array); | |
4687 } | |
4688 } | |
4689 | |
4690 | |
4691 RUNTIME_FUNCTION(Runtime_NumberToRadixString) { | |
4692 HandleScope scope(isolate); | |
4693 DCHECK(args.length() == 2); | |
4694 CONVERT_SMI_ARG_CHECKED(radix, 1); | |
4695 RUNTIME_ASSERT(2 <= radix && radix <= 36); | |
4696 | |
4697 // Fast case where the result is a one character string. | |
4698 if (args[0]->IsSmi()) { | |
4699 int value = args.smi_at(0); | |
4700 if (value >= 0 && value < radix) { | |
4701 // Character array used for conversion. | |
4702 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
4703 return *isolate->factory()-> | |
4704 LookupSingleCharacterStringFromCode(kCharTable[value]); | |
4705 } | |
4706 } | |
4707 | |
4708 // Slow case. | |
4709 CONVERT_DOUBLE_ARG_CHECKED(value, 0); | |
4710 if (std::isnan(value)) { | |
4711 return isolate->heap()->nan_string(); | |
4712 } | |
4713 if (std::isinf(value)) { | |
4714 if (value < 0) { | |
4715 return isolate->heap()->minus_infinity_string(); | |
4716 } | |
4717 return isolate->heap()->infinity_string(); | |
4718 } | |
4719 char* str = DoubleToRadixCString(value, radix); | |
4720 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
4721 DeleteArray(str); | |
4722 return *result; | |
4723 } | |
4724 | |
4725 | |
4726 RUNTIME_FUNCTION(Runtime_NumberToFixed) { | |
4727 HandleScope scope(isolate); | |
4728 DCHECK(args.length() == 2); | |
4729 | |
4730 CONVERT_DOUBLE_ARG_CHECKED(value, 0); | |
4731 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); | |
4732 int f = FastD2IChecked(f_number); | |
4733 // See DoubleToFixedCString for these constants: | |
4734 RUNTIME_ASSERT(f >= 0 && f <= 20); | |
4735 RUNTIME_ASSERT(!Double(value).IsSpecial()); | |
4736 char* str = DoubleToFixedCString(value, f); | |
4737 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
4738 DeleteArray(str); | |
4739 return *result; | |
4740 } | |
4741 | |
4742 | |
4743 RUNTIME_FUNCTION(Runtime_NumberToExponential) { | |
4744 HandleScope scope(isolate); | |
4745 DCHECK(args.length() == 2); | |
4746 | |
4747 CONVERT_DOUBLE_ARG_CHECKED(value, 0); | |
4748 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); | |
4749 int f = FastD2IChecked(f_number); | |
4750 RUNTIME_ASSERT(f >= -1 && f <= 20); | |
4751 RUNTIME_ASSERT(!Double(value).IsSpecial()); | |
4752 char* str = DoubleToExponentialCString(value, f); | |
4753 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
4754 DeleteArray(str); | |
4755 return *result; | |
4756 } | |
4757 | |
4758 | |
4759 RUNTIME_FUNCTION(Runtime_NumberToPrecision) { | |
4760 HandleScope scope(isolate); | |
4761 DCHECK(args.length() == 2); | |
4762 | |
4763 CONVERT_DOUBLE_ARG_CHECKED(value, 0); | |
4764 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); | |
4765 int f = FastD2IChecked(f_number); | |
4766 RUNTIME_ASSERT(f >= 1 && f <= 21); | |
4767 RUNTIME_ASSERT(!Double(value).IsSpecial()); | |
4768 char* str = DoubleToPrecisionCString(value, f); | |
4769 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
4770 DeleteArray(str); | |
4771 return *result; | |
4772 } | |
4773 | |
4774 | |
4775 RUNTIME_FUNCTION(Runtime_IsValidSmi) { | |
4776 SealHandleScope shs(isolate); | |
4777 DCHECK(args.length() == 1); | |
4778 | |
4779 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]); | |
4780 return isolate->heap()->ToBoolean(Smi::IsValid(number)); | |
4781 } | |
4782 | |
4783 | |
4784 // Returns a single character string where first character equals | |
4785 // string->Get(index). | |
4786 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | |
4787 if (index < static_cast<uint32_t>(string->length())) { | |
4788 Factory* factory = string->GetIsolate()->factory(); | |
4789 return factory->LookupSingleCharacterStringFromCode( | |
4790 String::Flatten(string)->Get(index)); | |
4791 } | |
4792 return Execution::CharAt(string, index); | |
4793 } | |
4794 | |
4795 | |
4796 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, | |
4797 Handle<Object> object, | |
4798 uint32_t index) { | |
4799 // Handle [] indexing on Strings | |
4800 if (object->IsString()) { | |
4801 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | |
4802 if (!result->IsUndefined()) return result; | |
4803 } | |
4804 | |
4805 // Handle [] indexing on String objects | |
4806 if (object->IsStringObjectWithCharacterAt(index)) { | |
4807 Handle<JSValue> js_value = Handle<JSValue>::cast(object); | |
4808 Handle<Object> result = | |
4809 GetCharAt(Handle<String>(String::cast(js_value->value())), index); | |
4810 if (!result->IsUndefined()) return result; | |
4811 } | |
4812 | |
4813 Handle<Object> result; | |
4814 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | |
4815 PrototypeIterator iter(isolate, object); | |
4816 return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter), | |
4817 index); | |
4818 } else { | |
4819 return Object::GetElement(isolate, object, index); | |
4820 } | |
4821 } | |
4822 | |
4823 | |
4824 MUST_USE_RESULT | |
4825 static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) { | |
4826 if (key->IsName()) { | |
4827 return Handle<Name>::cast(key); | |
4828 } else { | |
4829 Handle<Object> converted; | |
4830 ASSIGN_RETURN_ON_EXCEPTION( | |
4831 isolate, converted, Execution::ToString(isolate, key), Name); | |
4832 return Handle<Name>::cast(converted); | |
4833 } | |
4834 } | |
4835 | |
4836 | |
4837 MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate, | |
4838 Handle<JSReceiver> object, | |
4839 Handle<Object> key) { | |
4840 Maybe<bool> maybe; | |
4841 // Check if the given key is an array index. | |
4842 uint32_t index; | |
4843 if (key->ToArrayIndex(&index)) { | |
4844 maybe = JSReceiver::HasElement(object, index); | |
4845 } else { | |
4846 // Convert the key to a name - possibly by calling back into JavaScript. | |
4847 Handle<Name> name; | |
4848 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); | |
4849 | |
4850 maybe = JSReceiver::HasProperty(object, name); | |
4851 } | |
4852 | |
4853 if (!maybe.has_value) return MaybeHandle<Object>(); | |
4854 return isolate->factory()->ToBoolean(maybe.value); | |
4855 } | |
4856 | |
4857 | |
4858 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, | |
4859 Handle<Object> object, | |
4860 Handle<Object> key) { | |
4861 if (object->IsUndefined() || object->IsNull()) { | |
4862 Handle<Object> args[2] = { key, object }; | |
4863 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load", | |
4864 HandleVector(args, 2)), | |
4865 Object); | |
4866 } | |
4867 | |
4868 // Check if the given key is an array index. | |
4869 uint32_t index; | |
4870 if (key->ToArrayIndex(&index)) { | |
4871 return GetElementOrCharAt(isolate, object, index); | |
4872 } | |
4873 | |
4874 // Convert the key to a name - possibly by calling back into JavaScript. | |
4875 Handle<Name> name; | |
4876 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); | |
4877 | |
4878 // Check if the name is trivially convertible to an index and get | |
4879 // the element if so. | |
4880 if (name->AsArrayIndex(&index)) { | |
4881 return GetElementOrCharAt(isolate, object, index); | |
4882 } else { | |
4883 return Object::GetProperty(object, name); | |
4884 } | |
4885 } | |
4886 | |
4887 | |
4888 RUNTIME_FUNCTION(Runtime_GetProperty) { | |
4889 HandleScope scope(isolate); | |
4890 DCHECK(args.length() == 2); | |
4891 | |
4892 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
4893 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
4894 Handle<Object> result; | |
4895 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
4896 isolate, result, | |
4897 Runtime::GetObjectProperty(isolate, object, key)); | |
4898 return *result; | |
4899 } | |
4900 | |
4901 | |
4902 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. | |
4903 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { | |
4904 HandleScope scope(isolate); | |
4905 DCHECK(args.length() == 2); | |
4906 | |
4907 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); | |
4908 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); | |
4909 | |
4910 // Fast cases for getting named properties of the receiver JSObject | |
4911 // itself. | |
4912 // | |
4913 // The global proxy objects has to be excluded since LookupOwn on | |
4914 // the global proxy object can return a valid result even though the | |
4915 // global proxy object never has properties. This is the case | |
4916 // because the global proxy object forwards everything to its hidden | |
4917 // prototype including own lookups. | |
4918 // | |
4919 // Additionally, we need to make sure that we do not cache results | |
4920 // for objects that require access checks. | |
4921 if (receiver_obj->IsJSObject()) { | |
4922 if (!receiver_obj->IsJSGlobalProxy() && | |
4923 !receiver_obj->IsAccessCheckNeeded() && | |
4924 key_obj->IsName()) { | |
4925 DisallowHeapAllocation no_allocation; | |
4926 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); | |
4927 Handle<Name> key = Handle<Name>::cast(key_obj); | |
4928 if (receiver->HasFastProperties()) { | |
4929 // Attempt to use lookup cache. | |
4930 Handle<Map> receiver_map(receiver->map(), isolate); | |
4931 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); | |
4932 int index = keyed_lookup_cache->Lookup(receiver_map, key); | |
4933 if (index != -1) { | |
4934 // Doubles are not cached, so raw read the value. | |
4935 return receiver->RawFastPropertyAt( | |
4936 FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index)); | |
4937 } | |
4938 // Lookup cache miss. Perform lookup and update the cache if | |
4939 // appropriate. | |
4940 LookupIterator it(receiver, key, LookupIterator::OWN); | |
4941 if (it.state() == LookupIterator::DATA && | |
4942 it.property_details().type() == FIELD) { | |
4943 FieldIndex field_index = it.GetFieldIndex(); | |
4944 // Do not track double fields in the keyed lookup cache. Reading | |
4945 // double values requires boxing. | |
4946 if (!it.representation().IsDouble()) { | |
4947 keyed_lookup_cache->Update(receiver_map, key, | |
4948 field_index.GetKeyedLookupCacheIndex()); | |
4949 } | |
4950 AllowHeapAllocation allow_allocation; | |
4951 return *JSObject::FastPropertyAt(receiver, it.representation(), | |
4952 field_index); | |
4953 } | |
4954 } else { | |
4955 // Attempt dictionary lookup. | |
4956 NameDictionary* dictionary = receiver->property_dictionary(); | |
4957 int entry = dictionary->FindEntry(key); | |
4958 if ((entry != NameDictionary::kNotFound) && | |
4959 (dictionary->DetailsAt(entry).type() == NORMAL)) { | |
4960 Object* value = dictionary->ValueAt(entry); | |
4961 if (!receiver->IsGlobalObject()) return value; | |
4962 value = PropertyCell::cast(value)->value(); | |
4963 if (!value->IsTheHole()) return value; | |
4964 // If value is the hole (meaning, absent) do the general lookup. | |
4965 } | |
4966 } | |
4967 } else if (key_obj->IsSmi()) { | |
4968 // JSObject without a name key. If the key is a Smi, check for a | |
4969 // definite out-of-bounds access to elements, which is a strong indicator | |
4970 // that subsequent accesses will also call the runtime. Proactively | |
4971 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of | |
4972 // doubles for those future calls in the case that the elements would | |
4973 // become FAST_DOUBLE_ELEMENTS. | |
4974 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); | |
4975 ElementsKind elements_kind = js_object->GetElementsKind(); | |
4976 if (IsFastDoubleElementsKind(elements_kind)) { | |
4977 Handle<Smi> key = Handle<Smi>::cast(key_obj); | |
4978 if (key->value() >= js_object->elements()->length()) { | |
4979 if (IsFastHoleyElementsKind(elements_kind)) { | |
4980 elements_kind = FAST_HOLEY_ELEMENTS; | |
4981 } else { | |
4982 elements_kind = FAST_ELEMENTS; | |
4983 } | |
4984 RETURN_FAILURE_ON_EXCEPTION( | |
4985 isolate, TransitionElements(js_object, elements_kind, isolate)); | |
4986 } | |
4987 } else { | |
4988 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
4989 !IsFastElementsKind(elements_kind)); | |
4990 } | |
4991 } | |
4992 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { | |
4993 // Fast case for string indexing using [] with a smi index. | |
4994 Handle<String> str = Handle<String>::cast(receiver_obj); | |
4995 int index = args.smi_at(1); | |
4996 if (index >= 0 && index < str->length()) { | |
4997 return *GetCharAt(str, index); | |
4998 } | |
4999 } | |
5000 | |
5001 // Fall back to GetObjectProperty. | |
5002 Handle<Object> result; | |
5003 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5004 isolate, result, | |
5005 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); | |
5006 return *result; | |
5007 } | |
5008 | |
5009 | |
5010 static bool IsValidAccessor(Handle<Object> obj) { | |
5011 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull(); | |
5012 } | |
5013 | |
5014 | |
5015 // Transform getter or setter into something DefineAccessor can handle. | |
5016 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate, | |
5017 Handle<Object> component) { | |
5018 if (component->IsUndefined()) return isolate->factory()->undefined_value(); | |
5019 Handle<FunctionTemplateInfo> info = | |
5020 Handle<FunctionTemplateInfo>::cast(component); | |
5021 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction()); | |
5022 } | |
5023 | |
5024 | |
5025 RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) { | |
5026 HandleScope scope(isolate); | |
5027 DCHECK(args.length() == 5); | |
5028 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5029 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
5030 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); | |
5031 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); | |
5032 CONVERT_SMI_ARG_CHECKED(attribute, 4); | |
5033 RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo()); | |
5034 RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo()); | |
5035 RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid( | |
5036 static_cast<PropertyAttributes>(attribute))); | |
5037 RETURN_FAILURE_ON_EXCEPTION( | |
5038 isolate, JSObject::DefineAccessor( | |
5039 object, name, InstantiateAccessorComponent(isolate, getter), | |
5040 InstantiateAccessorComponent(isolate, setter), | |
5041 static_cast<PropertyAttributes>(attribute))); | |
5042 return isolate->heap()->undefined_value(); | |
5043 } | |
5044 | |
5045 | |
5046 // Implements part of 8.12.9 DefineOwnProperty. | |
5047 // There are 3 cases that lead here: | |
5048 // Step 4b - define a new accessor property. | |
5049 // Steps 9c & 12 - replace an existing data property with an accessor property. | |
5050 // Step 12 - update an existing accessor property with an accessor or generic | |
5051 // descriptor. | |
5052 RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) { | |
5053 HandleScope scope(isolate); | |
5054 DCHECK(args.length() == 5); | |
5055 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5056 RUNTIME_ASSERT(!obj->IsNull()); | |
5057 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
5058 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); | |
5059 RUNTIME_ASSERT(IsValidAccessor(getter)); | |
5060 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); | |
5061 RUNTIME_ASSERT(IsValidAccessor(setter)); | |
5062 CONVERT_SMI_ARG_CHECKED(unchecked, 4); | |
5063 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
5064 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); | |
5065 | |
5066 bool fast = obj->HasFastProperties(); | |
5067 RETURN_FAILURE_ON_EXCEPTION( | |
5068 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr)); | |
5069 if (fast) JSObject::MigrateSlowToFast(obj, 0); | |
5070 return isolate->heap()->undefined_value(); | |
5071 } | |
5072 | |
5073 | |
5074 // Implements part of 8.12.9 DefineOwnProperty. | |
5075 // There are 3 cases that lead here: | |
5076 // Step 4a - define a new data property. | |
5077 // Steps 9b & 12 - replace an existing accessor property with a data property. | |
5078 // Step 12 - update an existing data property with a data or generic | |
5079 // descriptor. | |
5080 RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) { | |
5081 HandleScope scope(isolate); | |
5082 DCHECK(args.length() == 4); | |
5083 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); | |
5084 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
5085 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2); | |
5086 CONVERT_SMI_ARG_CHECKED(unchecked, 3); | |
5087 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
5088 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); | |
5089 | |
5090 LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | |
5091 if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) { | |
5092 if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) { | |
5093 return isolate->heap()->undefined_value(); | |
5094 } | |
5095 it.Next(); | |
5096 } | |
5097 | |
5098 // Take special care when attributes are different and there is already | |
5099 // a property. | |
5100 if (it.state() == LookupIterator::ACCESSOR) { | |
5101 // Use IgnoreAttributes version since a readonly property may be | |
5102 // overridden and SetProperty does not allow this. | |
5103 Handle<Object> result; | |
5104 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5105 isolate, result, | |
5106 JSObject::SetOwnPropertyIgnoreAttributes( | |
5107 js_object, name, obj_value, attr, | |
5108 JSObject::DONT_FORCE_FIELD)); | |
5109 return *result; | |
5110 } | |
5111 | |
5112 Handle<Object> result; | |
5113 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5114 isolate, result, | |
5115 Runtime::DefineObjectProperty(js_object, name, obj_value, attr)); | |
5116 return *result; | |
5117 } | |
5118 | |
5119 | |
5120 // Return property without being observable by accessors or interceptors. | |
5121 RUNTIME_FUNCTION(Runtime_GetDataProperty) { | |
5122 HandleScope scope(isolate); | |
5123 DCHECK(args.length() == 2); | |
5124 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5125 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5126 return *JSObject::GetDataProperty(object, key); | |
5127 } | |
5128 | |
5129 | |
5130 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, | |
5131 Handle<Object> object, | |
5132 Handle<Object> key, | |
5133 Handle<Object> value, | |
5134 StrictMode strict_mode) { | |
5135 if (object->IsUndefined() || object->IsNull()) { | |
5136 Handle<Object> args[2] = { key, object }; | |
5137 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store", | |
5138 HandleVector(args, 2)), | |
5139 Object); | |
5140 } | |
5141 | |
5142 if (object->IsJSProxy()) { | |
5143 Handle<Object> name_object; | |
5144 if (key->IsSymbol()) { | |
5145 name_object = key; | |
5146 } else { | |
5147 ASSIGN_RETURN_ON_EXCEPTION( | |
5148 isolate, name_object, Execution::ToString(isolate, key), Object); | |
5149 } | |
5150 Handle<Name> name = Handle<Name>::cast(name_object); | |
5151 return Object::SetProperty(Handle<JSProxy>::cast(object), name, value, | |
5152 strict_mode); | |
5153 } | |
5154 | |
5155 // Check if the given key is an array index. | |
5156 uint32_t index; | |
5157 if (key->ToArrayIndex(&index)) { | |
5158 // TODO(verwaest): Support non-JSObject receivers. | |
5159 if (!object->IsJSObject()) return value; | |
5160 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | |
5161 | |
5162 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | |
5163 // of a string using [] notation. We need to support this too in | |
5164 // JavaScript. | |
5165 // In the case of a String object we just need to redirect the assignment to | |
5166 // the underlying string if the index is in range. Since the underlying | |
5167 // string does nothing with the assignment then we can ignore such | |
5168 // assignments. | |
5169 if (js_object->IsStringObjectWithCharacterAt(index)) { | |
5170 return value; | |
5171 } | |
5172 | |
5173 JSObject::ValidateElements(js_object); | |
5174 if (js_object->HasExternalArrayElements() || | |
5175 js_object->HasFixedTypedArrayElements()) { | |
5176 if (!value->IsNumber() && !value->IsUndefined()) { | |
5177 ASSIGN_RETURN_ON_EXCEPTION( | |
5178 isolate, value, Execution::ToNumber(isolate, value), Object); | |
5179 } | |
5180 } | |
5181 | |
5182 MaybeHandle<Object> result = JSObject::SetElement( | |
5183 js_object, index, value, NONE, strict_mode, true, SET_PROPERTY); | |
5184 JSObject::ValidateElements(js_object); | |
5185 | |
5186 return result.is_null() ? result : value; | |
5187 } | |
5188 | |
5189 if (key->IsName()) { | |
5190 Handle<Name> name = Handle<Name>::cast(key); | |
5191 if (name->AsArrayIndex(&index)) { | |
5192 // TODO(verwaest): Support non-JSObject receivers. | |
5193 if (!object->IsJSObject()) return value; | |
5194 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | |
5195 if (js_object->HasExternalArrayElements()) { | |
5196 if (!value->IsNumber() && !value->IsUndefined()) { | |
5197 ASSIGN_RETURN_ON_EXCEPTION( | |
5198 isolate, value, Execution::ToNumber(isolate, value), Object); | |
5199 } | |
5200 } | |
5201 return JSObject::SetElement(js_object, index, value, NONE, strict_mode, | |
5202 true, SET_PROPERTY); | |
5203 } else { | |
5204 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); | |
5205 return Object::SetProperty(object, name, value, strict_mode); | |
5206 } | |
5207 } | |
5208 | |
5209 // Call-back into JavaScript to convert the key to a string. | |
5210 Handle<Object> converted; | |
5211 ASSIGN_RETURN_ON_EXCEPTION( | |
5212 isolate, converted, Execution::ToString(isolate, key), Object); | |
5213 Handle<String> name = Handle<String>::cast(converted); | |
5214 | |
5215 if (name->AsArrayIndex(&index)) { | |
5216 // TODO(verwaest): Support non-JSObject receivers. | |
5217 if (!object->IsJSObject()) return value; | |
5218 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | |
5219 return JSObject::SetElement(js_object, index, value, NONE, strict_mode, | |
5220 true, SET_PROPERTY); | |
5221 } | |
5222 return Object::SetProperty(object, name, value, strict_mode); | |
5223 } | |
5224 | |
5225 | |
5226 MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object, | |
5227 Handle<Object> key, | |
5228 Handle<Object> value, | |
5229 PropertyAttributes attr) { | |
5230 Isolate* isolate = js_object->GetIsolate(); | |
5231 // Check if the given key is an array index. | |
5232 uint32_t index; | |
5233 if (key->ToArrayIndex(&index)) { | |
5234 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | |
5235 // of a string using [] notation. We need to support this too in | |
5236 // JavaScript. | |
5237 // In the case of a String object we just need to redirect the assignment to | |
5238 // the underlying string if the index is in range. Since the underlying | |
5239 // string does nothing with the assignment then we can ignore such | |
5240 // assignments. | |
5241 if (js_object->IsStringObjectWithCharacterAt(index)) { | |
5242 return value; | |
5243 } | |
5244 | |
5245 return JSObject::SetElement(js_object, index, value, attr, | |
5246 SLOPPY, false, DEFINE_PROPERTY); | |
5247 } | |
5248 | |
5249 if (key->IsName()) { | |
5250 Handle<Name> name = Handle<Name>::cast(key); | |
5251 if (name->AsArrayIndex(&index)) { | |
5252 return JSObject::SetElement(js_object, index, value, attr, | |
5253 SLOPPY, false, DEFINE_PROPERTY); | |
5254 } else { | |
5255 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); | |
5256 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value, | |
5257 attr); | |
5258 } | |
5259 } | |
5260 | |
5261 // Call-back into JavaScript to convert the key to a string. | |
5262 Handle<Object> converted; | |
5263 ASSIGN_RETURN_ON_EXCEPTION( | |
5264 isolate, converted, Execution::ToString(isolate, key), Object); | |
5265 Handle<String> name = Handle<String>::cast(converted); | |
5266 | |
5267 if (name->AsArrayIndex(&index)) { | |
5268 return JSObject::SetElement(js_object, index, value, attr, | |
5269 SLOPPY, false, DEFINE_PROPERTY); | |
5270 } else { | |
5271 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value, | |
5272 attr); | |
5273 } | |
5274 } | |
5275 | |
5276 | |
5277 MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate, | |
5278 Handle<JSReceiver> receiver, | |
5279 Handle<Object> key, | |
5280 JSReceiver::DeleteMode mode) { | |
5281 // Check if the given key is an array index. | |
5282 uint32_t index; | |
5283 if (key->ToArrayIndex(&index)) { | |
5284 // In Firefox/SpiderMonkey, Safari and Opera you can access the | |
5285 // characters of a string using [] notation. In the case of a | |
5286 // String object we just need to redirect the deletion to the | |
5287 // underlying string if the index is in range. Since the | |
5288 // underlying string does nothing with the deletion, we can ignore | |
5289 // such deletions. | |
5290 if (receiver->IsStringObjectWithCharacterAt(index)) { | |
5291 return isolate->factory()->true_value(); | |
5292 } | |
5293 | |
5294 return JSReceiver::DeleteElement(receiver, index, mode); | |
5295 } | |
5296 | |
5297 Handle<Name> name; | |
5298 if (key->IsName()) { | |
5299 name = Handle<Name>::cast(key); | |
5300 } else { | |
5301 // Call-back into JavaScript to convert the key to a string. | |
5302 Handle<Object> converted; | |
5303 ASSIGN_RETURN_ON_EXCEPTION( | |
5304 isolate, converted, Execution::ToString(isolate, key), Object); | |
5305 name = Handle<String>::cast(converted); | |
5306 } | |
5307 | |
5308 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); | |
5309 return JSReceiver::DeleteProperty(receiver, name, mode); | |
5310 } | |
5311 | |
5312 | |
5313 RUNTIME_FUNCTION(Runtime_SetHiddenProperty) { | |
5314 HandleScope scope(isolate); | |
5315 RUNTIME_ASSERT(args.length() == 3); | |
5316 | |
5317 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5318 CONVERT_ARG_HANDLE_CHECKED(String, key, 1); | |
5319 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5320 RUNTIME_ASSERT(key->IsUniqueName()); | |
5321 return *JSObject::SetHiddenProperty(object, key, value); | |
5322 } | |
5323 | |
5324 | |
5325 RUNTIME_FUNCTION(Runtime_AddNamedProperty) { | |
5326 HandleScope scope(isolate); | |
5327 RUNTIME_ASSERT(args.length() == 4); | |
5328 | |
5329 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5330 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5331 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5332 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); | |
5333 RUNTIME_ASSERT( | |
5334 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
5335 // Compute attributes. | |
5336 PropertyAttributes attributes = | |
5337 static_cast<PropertyAttributes>(unchecked_attributes); | |
5338 | |
5339 #ifdef DEBUG | |
5340 uint32_t index = 0; | |
5341 DCHECK(!key->ToArrayIndex(&index)); | |
5342 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR); | |
5343 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
5344 if (!maybe.has_value) return isolate->heap()->exception(); | |
5345 RUNTIME_ASSERT(!it.IsFound()); | |
5346 #endif | |
5347 | |
5348 Handle<Object> result; | |
5349 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5350 isolate, result, | |
5351 JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes)); | |
5352 return *result; | |
5353 } | |
5354 | |
5355 | |
5356 RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) { | |
5357 HandleScope scope(isolate); | |
5358 RUNTIME_ASSERT(args.length() == 4); | |
5359 | |
5360 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5361 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
5362 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5363 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); | |
5364 RUNTIME_ASSERT( | |
5365 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
5366 // Compute attributes. | |
5367 PropertyAttributes attributes = | |
5368 static_cast<PropertyAttributes>(unchecked_attributes); | |
5369 | |
5370 #ifdef DEBUG | |
5371 bool duplicate; | |
5372 if (key->IsName()) { | |
5373 LookupIterator it(object, Handle<Name>::cast(key), | |
5374 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
5375 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
5376 DCHECK(maybe.has_value); | |
5377 duplicate = it.IsFound(); | |
5378 } else { | |
5379 uint32_t index = 0; | |
5380 RUNTIME_ASSERT(key->ToArrayIndex(&index)); | |
5381 Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index); | |
5382 if (!maybe.has_value) return isolate->heap()->exception(); | |
5383 duplicate = maybe.value; | |
5384 } | |
5385 if (duplicate) { | |
5386 Handle<Object> args[1] = { key }; | |
5387 THROW_NEW_ERROR_RETURN_FAILURE( | |
5388 isolate, | |
5389 NewTypeError("duplicate_template_property", HandleVector(args, 1))); | |
5390 } | |
5391 #endif | |
5392 | |
5393 Handle<Object> result; | |
5394 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5395 isolate, result, | |
5396 Runtime::DefineObjectProperty(object, key, value, attributes)); | |
5397 return *result; | |
5398 } | |
5399 | |
5400 | |
5401 RUNTIME_FUNCTION(Runtime_SetProperty) { | |
5402 HandleScope scope(isolate); | |
5403 RUNTIME_ASSERT(args.length() == 4); | |
5404 | |
5405 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
5406 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
5407 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5408 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3); | |
5409 StrictMode strict_mode = strict_mode_arg; | |
5410 | |
5411 Handle<Object> result; | |
5412 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5413 isolate, result, | |
5414 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); | |
5415 return *result; | |
5416 } | |
5417 | |
5418 | |
5419 // Adds an element to an array. | |
5420 // This is used to create an indexed data property into an array. | |
5421 RUNTIME_FUNCTION(Runtime_AddElement) { | |
5422 HandleScope scope(isolate); | |
5423 RUNTIME_ASSERT(args.length() == 4); | |
5424 | |
5425 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5426 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); | |
5427 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5428 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); | |
5429 RUNTIME_ASSERT( | |
5430 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
5431 // Compute attributes. | |
5432 PropertyAttributes attributes = | |
5433 static_cast<PropertyAttributes>(unchecked_attributes); | |
5434 | |
5435 uint32_t index = 0; | |
5436 key->ToArrayIndex(&index); | |
5437 | |
5438 Handle<Object> result; | |
5439 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5440 isolate, result, JSObject::SetElement(object, index, value, attributes, | |
5441 SLOPPY, false, DEFINE_PROPERTY)); | |
5442 return *result; | |
5443 } | |
5444 | |
5445 | |
5446 RUNTIME_FUNCTION(Runtime_TransitionElementsKind) { | |
5447 HandleScope scope(isolate); | |
5448 RUNTIME_ASSERT(args.length() == 2); | |
5449 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | |
5450 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1); | |
5451 JSObject::TransitionElementsKind(array, map->elements_kind()); | |
5452 return *array; | |
5453 } | |
5454 | |
5455 | |
5456 // Set the native flag on the function. | |
5457 // This is used to decide if we should transform null and undefined | |
5458 // into the global object when doing call and apply. | |
5459 RUNTIME_FUNCTION(Runtime_SetNativeFlag) { | |
5460 SealHandleScope shs(isolate); | |
5461 RUNTIME_ASSERT(args.length() == 1); | |
5462 | |
5463 CONVERT_ARG_CHECKED(Object, object, 0); | |
5464 | |
5465 if (object->IsJSFunction()) { | |
5466 JSFunction* func = JSFunction::cast(object); | |
5467 func->shared()->set_native(true); | |
5468 } | |
5469 return isolate->heap()->undefined_value(); | |
5470 } | |
5471 | |
5472 | |
5473 RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) { | |
5474 SealHandleScope shs(isolate); | |
5475 RUNTIME_ASSERT(args.length() == 1); | |
5476 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
5477 | |
5478 if (object->IsJSFunction()) { | |
5479 JSFunction* func = JSFunction::cast(*object); | |
5480 func->shared()->set_inline_builtin(true); | |
5481 } | |
5482 return isolate->heap()->undefined_value(); | |
5483 } | |
5484 | |
5485 | |
5486 RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) { | |
5487 HandleScope scope(isolate); | |
5488 RUNTIME_ASSERT(args.length() == 5); | |
5489 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5490 CONVERT_SMI_ARG_CHECKED(store_index, 1); | |
5491 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); | |
5492 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); | |
5493 CONVERT_SMI_ARG_CHECKED(literal_index, 4); | |
5494 | |
5495 Object* raw_literal_cell = literals->get(literal_index); | |
5496 JSArray* boilerplate = NULL; | |
5497 if (raw_literal_cell->IsAllocationSite()) { | |
5498 AllocationSite* site = AllocationSite::cast(raw_literal_cell); | |
5499 boilerplate = JSArray::cast(site->transition_info()); | |
5500 } else { | |
5501 boilerplate = JSArray::cast(raw_literal_cell); | |
5502 } | |
5503 Handle<JSArray> boilerplate_object(boilerplate); | |
5504 ElementsKind elements_kind = object->GetElementsKind(); | |
5505 DCHECK(IsFastElementsKind(elements_kind)); | |
5506 // Smis should never trigger transitions. | |
5507 DCHECK(!value->IsSmi()); | |
5508 | |
5509 if (value->IsNumber()) { | |
5510 DCHECK(IsFastSmiElementsKind(elements_kind)); | |
5511 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) | |
5512 ? FAST_HOLEY_DOUBLE_ELEMENTS | |
5513 : FAST_DOUBLE_ELEMENTS; | |
5514 if (IsMoreGeneralElementsKindTransition( | |
5515 boilerplate_object->GetElementsKind(), | |
5516 transitioned_kind)) { | |
5517 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); | |
5518 } | |
5519 JSObject::TransitionElementsKind(object, transitioned_kind); | |
5520 DCHECK(IsFastDoubleElementsKind(object->GetElementsKind())); | |
5521 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements()); | |
5522 HeapNumber* number = HeapNumber::cast(*value); | |
5523 double_array->set(store_index, number->Number()); | |
5524 } else { | |
5525 if (!IsFastObjectElementsKind(elements_kind)) { | |
5526 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) | |
5527 ? FAST_HOLEY_ELEMENTS | |
5528 : FAST_ELEMENTS; | |
5529 JSObject::TransitionElementsKind(object, transitioned_kind); | |
5530 ElementsKind boilerplate_elements_kind = | |
5531 boilerplate_object->GetElementsKind(); | |
5532 if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind, | |
5533 transitioned_kind)) { | |
5534 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); | |
5535 } | |
5536 } | |
5537 FixedArray* object_array = FixedArray::cast(object->elements()); | |
5538 object_array->set(store_index, *value); | |
5539 } | |
5540 return *object; | |
5541 } | |
5542 | |
5543 | |
5544 // Check whether debugger and is about to step into the callback that is passed | |
5545 // to a built-in function such as Array.forEach. | |
5546 RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) { | |
5547 DCHECK(args.length() == 1); | |
5548 if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) { | |
5549 return isolate->heap()->false_value(); | |
5550 } | |
5551 CONVERT_ARG_CHECKED(Object, callback, 0); | |
5552 // We do not step into the callback if it's a builtin or not even a function. | |
5553 return isolate->heap()->ToBoolean( | |
5554 callback->IsJSFunction() && !JSFunction::cast(callback)->IsBuiltin()); | |
5555 } | |
5556 | |
5557 | |
5558 // Set one shot breakpoints for the callback function that is passed to a | |
5559 // built-in function such as Array.forEach to enable stepping into the callback. | |
5560 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { | |
5561 DCHECK(args.length() == 1); | |
5562 Debug* debug = isolate->debug(); | |
5563 if (!debug->IsStepping()) return isolate->heap()->undefined_value(); | |
5564 | |
5565 HandleScope scope(isolate); | |
5566 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
5567 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject()); | |
5568 Handle<JSFunction> fun; | |
5569 if (object->IsJSFunction()) { | |
5570 fun = Handle<JSFunction>::cast(object); | |
5571 } else { | |
5572 fun = Handle<JSFunction>( | |
5573 Handle<JSGeneratorObject>::cast(object)->function(), isolate); | |
5574 } | |
5575 // When leaving the function, step out has been activated, but not performed | |
5576 // if we do not leave the builtin. To be able to step into the function | |
5577 // again, we need to clear the step out at this point. | |
5578 debug->ClearStepOut(); | |
5579 debug->FloodWithOneShot(fun); | |
5580 return isolate->heap()->undefined_value(); | |
5581 } | |
5582 | |
5583 | |
5584 RUNTIME_FUNCTION(Runtime_DebugPushPromise) { | |
5585 DCHECK(args.length() == 1); | |
5586 HandleScope scope(isolate); | |
5587 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | |
5588 isolate->PushPromise(promise); | |
5589 return isolate->heap()->undefined_value(); | |
5590 } | |
5591 | |
5592 | |
5593 RUNTIME_FUNCTION(Runtime_DebugPopPromise) { | |
5594 DCHECK(args.length() == 0); | |
5595 SealHandleScope shs(isolate); | |
5596 isolate->PopPromise(); | |
5597 return isolate->heap()->undefined_value(); | |
5598 } | |
5599 | |
5600 | |
5601 RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) { | |
5602 DCHECK(args.length() == 1); | |
5603 HandleScope scope(isolate); | |
5604 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); | |
5605 isolate->debug()->OnPromiseEvent(data); | |
5606 return isolate->heap()->undefined_value(); | |
5607 } | |
5608 | |
5609 | |
5610 RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) { | |
5611 DCHECK(args.length() == 2); | |
5612 HandleScope scope(isolate); | |
5613 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | |
5614 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | |
5615 isolate->debug()->OnPromiseReject(promise, value); | |
5616 return isolate->heap()->undefined_value(); | |
5617 } | |
5618 | |
5619 | |
5620 RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) { | |
5621 DCHECK(args.length() == 1); | |
5622 HandleScope scope(isolate); | |
5623 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); | |
5624 isolate->debug()->OnAsyncTaskEvent(data); | |
5625 return isolate->heap()->undefined_value(); | |
5626 } | |
5627 | |
5628 | |
5629 RUNTIME_FUNCTION(Runtime_DeleteProperty) { | |
5630 HandleScope scope(isolate); | |
5631 DCHECK(args.length() == 3); | |
5632 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); | |
5633 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5634 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); | |
5635 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT | |
5636 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION; | |
5637 Handle<Object> result; | |
5638 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5639 isolate, result, | |
5640 JSReceiver::DeleteProperty(object, key, delete_mode)); | |
5641 return *result; | |
5642 } | |
5643 | |
5644 | |
5645 static Object* HasOwnPropertyImplementation(Isolate* isolate, | |
5646 Handle<JSObject> object, | |
5647 Handle<Name> key) { | |
5648 Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key); | |
5649 if (!maybe.has_value) return isolate->heap()->exception(); | |
5650 if (maybe.value) return isolate->heap()->true_value(); | |
5651 // Handle hidden prototypes. If there's a hidden prototype above this thing | |
5652 // then we have to check it for properties, because they are supposed to | |
5653 // look like they are on this object. | |
5654 PrototypeIterator iter(isolate, object); | |
5655 if (!iter.IsAtEnd() && | |
5656 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)) | |
5657 ->map() | |
5658 ->is_hidden_prototype()) { | |
5659 // TODO(verwaest): The recursion is not necessary for keys that are array | |
5660 // indices. Removing this. | |
5661 return HasOwnPropertyImplementation( | |
5662 isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), | |
5663 key); | |
5664 } | |
5665 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
5666 return isolate->heap()->false_value(); | |
5667 } | |
5668 | |
5669 | |
5670 RUNTIME_FUNCTION(Runtime_HasOwnProperty) { | |
5671 HandleScope scope(isolate); | |
5672 DCHECK(args.length() == 2); | |
5673 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0) | |
5674 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5675 | |
5676 uint32_t index; | |
5677 const bool key_is_array_index = key->AsArrayIndex(&index); | |
5678 | |
5679 // Only JS objects can have properties. | |
5680 if (object->IsJSObject()) { | |
5681 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); | |
5682 // Fast case: either the key is a real named property or it is not | |
5683 // an array index and there are no interceptors or hidden | |
5684 // prototypes. | |
5685 Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key); | |
5686 if (!maybe.has_value) return isolate->heap()->exception(); | |
5687 DCHECK(!isolate->has_pending_exception()); | |
5688 if (maybe.value) { | |
5689 return isolate->heap()->true_value(); | |
5690 } | |
5691 Map* map = js_obj->map(); | |
5692 if (!key_is_array_index && | |
5693 !map->has_named_interceptor() && | |
5694 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) { | |
5695 return isolate->heap()->false_value(); | |
5696 } | |
5697 // Slow case. | |
5698 return HasOwnPropertyImplementation(isolate, | |
5699 Handle<JSObject>(js_obj), | |
5700 Handle<Name>(key)); | |
5701 } else if (object->IsString() && key_is_array_index) { | |
5702 // Well, there is one exception: Handle [] on strings. | |
5703 Handle<String> string = Handle<String>::cast(object); | |
5704 if (index < static_cast<uint32_t>(string->length())) { | |
5705 return isolate->heap()->true_value(); | |
5706 } | |
5707 } | |
5708 return isolate->heap()->false_value(); | |
5709 } | |
5710 | |
5711 | |
5712 RUNTIME_FUNCTION(Runtime_HasProperty) { | |
5713 HandleScope scope(isolate); | |
5714 DCHECK(args.length() == 2); | |
5715 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); | |
5716 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5717 | |
5718 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key); | |
5719 if (!maybe.has_value) return isolate->heap()->exception(); | |
5720 return isolate->heap()->ToBoolean(maybe.value); | |
5721 } | |
5722 | |
5723 | |
5724 RUNTIME_FUNCTION(Runtime_HasElement) { | |
5725 HandleScope scope(isolate); | |
5726 DCHECK(args.length() == 2); | |
5727 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); | |
5728 CONVERT_SMI_ARG_CHECKED(index, 1); | |
5729 | |
5730 Maybe<bool> maybe = JSReceiver::HasElement(receiver, index); | |
5731 if (!maybe.has_value) return isolate->heap()->exception(); | |
5732 return isolate->heap()->ToBoolean(maybe.value); | |
5733 } | |
5734 | |
5735 | |
5736 RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) { | |
5737 HandleScope scope(isolate); | |
5738 DCHECK(args.length() == 2); | |
5739 | |
5740 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
5741 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | |
5742 | |
5743 Maybe<PropertyAttributes> maybe = | |
5744 JSReceiver::GetOwnPropertyAttributes(object, key); | |
5745 if (!maybe.has_value) return isolate->heap()->exception(); | |
5746 if (maybe.value == ABSENT) maybe.value = DONT_ENUM; | |
5747 return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0); | |
5748 } | |
5749 | |
5750 | |
5751 RUNTIME_FUNCTION(Runtime_GetPropertyNames) { | |
5752 HandleScope scope(isolate); | |
5753 DCHECK(args.length() == 1); | |
5754 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); | |
5755 Handle<JSArray> result; | |
5756 | |
5757 isolate->counters()->for_in()->Increment(); | |
5758 Handle<FixedArray> elements; | |
5759 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5760 isolate, elements, | |
5761 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); | |
5762 return *isolate->factory()->NewJSArrayWithElements(elements); | |
5763 } | |
5764 | |
5765 | |
5766 // Returns either a FixedArray as Runtime_GetPropertyNames, | |
5767 // or, if the given object has an enum cache that contains | |
5768 // all enumerable properties of the object and its prototypes | |
5769 // have none, the map of the object. This is used to speed up | |
5770 // the check for deletions during a for-in. | |
5771 RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { | |
5772 SealHandleScope shs(isolate); | |
5773 DCHECK(args.length() == 1); | |
5774 | |
5775 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0); | |
5776 | |
5777 if (raw_object->IsSimpleEnum()) return raw_object->map(); | |
5778 | |
5779 HandleScope scope(isolate); | |
5780 Handle<JSReceiver> object(raw_object); | |
5781 Handle<FixedArray> content; | |
5782 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
5783 isolate, content, | |
5784 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); | |
5785 | |
5786 // Test again, since cache may have been built by preceding call. | |
5787 if (object->IsSimpleEnum()) return object->map(); | |
5788 | |
5789 return *content; | |
5790 } | |
5791 | |
5792 | |
5793 // Find the length of the prototype chain that is to be handled as one. If a | |
5794 // prototype object is hidden it is to be viewed as part of the the object it | |
5795 // is prototype for. | |
5796 static int OwnPrototypeChainLength(JSObject* obj) { | |
5797 int count = 1; | |
5798 for (PrototypeIterator iter(obj->GetIsolate(), obj); | |
5799 !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) { | |
5800 count++; | |
5801 } | |
5802 return count; | |
5803 } | |
5804 | |
5805 | |
5806 // Return the names of the own named properties. | |
5807 // args[0]: object | |
5808 // args[1]: PropertyAttributes as int | |
5809 RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { | |
5810 HandleScope scope(isolate); | |
5811 DCHECK(args.length() == 2); | |
5812 if (!args[0]->IsJSObject()) { | |
5813 return isolate->heap()->undefined_value(); | |
5814 } | |
5815 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5816 CONVERT_SMI_ARG_CHECKED(filter_value, 1); | |
5817 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value); | |
5818 | |
5819 // Skip the global proxy as it has no properties and always delegates to the | |
5820 // real global object. | |
5821 if (obj->IsJSGlobalProxy()) { | |
5822 // Only collect names if access is permitted. | |
5823 if (obj->IsAccessCheckNeeded() && | |
5824 !isolate->MayNamedAccess( | |
5825 obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { | |
5826 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS); | |
5827 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
5828 return *isolate->factory()->NewJSArray(0); | |
5829 } | |
5830 PrototypeIterator iter(isolate, obj); | |
5831 obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
5832 } | |
5833 | |
5834 // Find the number of objects making up this. | |
5835 int length = OwnPrototypeChainLength(*obj); | |
5836 | |
5837 // Find the number of own properties for each of the objects. | |
5838 ScopedVector<int> own_property_count(length); | |
5839 int total_property_count = 0; | |
5840 { | |
5841 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); | |
5842 for (int i = 0; i < length; i++) { | |
5843 DCHECK(!iter.IsAtEnd()); | |
5844 Handle<JSObject> jsproto = | |
5845 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
5846 // Only collect names if access is permitted. | |
5847 if (jsproto->IsAccessCheckNeeded() && | |
5848 !isolate->MayNamedAccess(jsproto, | |
5849 isolate->factory()->undefined_value(), | |
5850 v8::ACCESS_KEYS)) { | |
5851 isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS); | |
5852 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
5853 return *isolate->factory()->NewJSArray(0); | |
5854 } | |
5855 int n; | |
5856 n = jsproto->NumberOfOwnProperties(filter); | |
5857 own_property_count[i] = n; | |
5858 total_property_count += n; | |
5859 iter.Advance(); | |
5860 } | |
5861 } | |
5862 | |
5863 // Allocate an array with storage for all the property names. | |
5864 Handle<FixedArray> names = | |
5865 isolate->factory()->NewFixedArray(total_property_count); | |
5866 | |
5867 // Get the property names. | |
5868 int next_copy_index = 0; | |
5869 int hidden_strings = 0; | |
5870 { | |
5871 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); | |
5872 for (int i = 0; i < length; i++) { | |
5873 DCHECK(!iter.IsAtEnd()); | |
5874 Handle<JSObject> jsproto = | |
5875 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
5876 jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); | |
5877 if (i > 0) { | |
5878 // Names from hidden prototypes may already have been added | |
5879 // for inherited function template instances. Count the duplicates | |
5880 // and stub them out; the final copy pass at the end ignores holes. | |
5881 for (int j = next_copy_index; | |
5882 j < next_copy_index + own_property_count[i]; j++) { | |
5883 Object* name_from_hidden_proto = names->get(j); | |
5884 for (int k = 0; k < next_copy_index; k++) { | |
5885 if (names->get(k) != isolate->heap()->hidden_string()) { | |
5886 Object* name = names->get(k); | |
5887 if (name_from_hidden_proto == name) { | |
5888 names->set(j, isolate->heap()->hidden_string()); | |
5889 hidden_strings++; | |
5890 break; | |
5891 } | |
5892 } | |
5893 } | |
5894 } | |
5895 } | |
5896 next_copy_index += own_property_count[i]; | |
5897 | |
5898 // Hidden properties only show up if the filter does not skip strings. | |
5899 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { | |
5900 hidden_strings++; | |
5901 } | |
5902 iter.Advance(); | |
5903 } | |
5904 } | |
5905 | |
5906 // Filter out name of hidden properties object and | |
5907 // hidden prototype duplicates. | |
5908 if (hidden_strings > 0) { | |
5909 Handle<FixedArray> old_names = names; | |
5910 names = isolate->factory()->NewFixedArray( | |
5911 names->length() - hidden_strings); | |
5912 int dest_pos = 0; | |
5913 for (int i = 0; i < total_property_count; i++) { | |
5914 Object* name = old_names->get(i); | |
5915 if (name == isolate->heap()->hidden_string()) { | |
5916 hidden_strings--; | |
5917 continue; | |
5918 } | |
5919 names->set(dest_pos++, name); | |
5920 } | |
5921 DCHECK_EQ(0, hidden_strings); | |
5922 } | |
5923 | |
5924 return *isolate->factory()->NewJSArrayWithElements(names); | |
5925 } | |
5926 | |
5927 | |
5928 // Return the names of the own indexed properties. | |
5929 // args[0]: object | |
5930 RUNTIME_FUNCTION(Runtime_GetOwnElementNames) { | |
5931 HandleScope scope(isolate); | |
5932 DCHECK(args.length() == 1); | |
5933 if (!args[0]->IsJSObject()) { | |
5934 return isolate->heap()->undefined_value(); | |
5935 } | |
5936 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5937 | |
5938 int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE)); | |
5939 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); | |
5940 obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE)); | |
5941 return *isolate->factory()->NewJSArrayWithElements(names); | |
5942 } | |
5943 | |
5944 | |
5945 // Return information on whether an object has a named or indexed interceptor. | |
5946 // args[0]: object | |
5947 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { | |
5948 HandleScope scope(isolate); | |
5949 DCHECK(args.length() == 1); | |
5950 if (!args[0]->IsJSObject()) { | |
5951 return Smi::FromInt(0); | |
5952 } | |
5953 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5954 | |
5955 int result = 0; | |
5956 if (obj->HasNamedInterceptor()) result |= 2; | |
5957 if (obj->HasIndexedInterceptor()) result |= 1; | |
5958 | |
5959 return Smi::FromInt(result); | |
5960 } | |
5961 | |
5962 | |
5963 // Return property names from named interceptor. | |
5964 // args[0]: object | |
5965 RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) { | |
5966 HandleScope scope(isolate); | |
5967 DCHECK(args.length() == 1); | |
5968 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5969 | |
5970 if (obj->HasNamedInterceptor()) { | |
5971 Handle<JSObject> result; | |
5972 if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) { | |
5973 return *result; | |
5974 } | |
5975 } | |
5976 return isolate->heap()->undefined_value(); | |
5977 } | |
5978 | |
5979 | |
5980 // Return element names from indexed interceptor. | |
5981 // args[0]: object | |
5982 RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) { | |
5983 HandleScope scope(isolate); | |
5984 DCHECK(args.length() == 1); | |
5985 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
5986 | |
5987 if (obj->HasIndexedInterceptor()) { | |
5988 Handle<JSObject> result; | |
5989 if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) { | |
5990 return *result; | |
5991 } | |
5992 } | |
5993 return isolate->heap()->undefined_value(); | |
5994 } | |
5995 | |
5996 | |
5997 RUNTIME_FUNCTION(Runtime_OwnKeys) { | |
5998 HandleScope scope(isolate); | |
5999 DCHECK(args.length() == 1); | |
6000 CONVERT_ARG_CHECKED(JSObject, raw_object, 0); | |
6001 Handle<JSObject> object(raw_object); | |
6002 | |
6003 if (object->IsJSGlobalProxy()) { | |
6004 // Do access checks before going to the global object. | |
6005 if (object->IsAccessCheckNeeded() && | |
6006 !isolate->MayNamedAccess( | |
6007 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { | |
6008 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS); | |
6009 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
6010 return *isolate->factory()->NewJSArray(0); | |
6011 } | |
6012 | |
6013 PrototypeIterator iter(isolate, object); | |
6014 // If proxy is detached we simply return an empty array. | |
6015 if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0); | |
6016 object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
6017 } | |
6018 | |
6019 Handle<FixedArray> contents; | |
6020 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6021 isolate, contents, | |
6022 JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY)); | |
6023 | |
6024 // Some fast paths through GetKeysInFixedArrayFor reuse a cached | |
6025 // property array and since the result is mutable we have to create | |
6026 // a fresh clone on each invocation. | |
6027 int length = contents->length(); | |
6028 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); | |
6029 for (int i = 0; i < length; i++) { | |
6030 Object* entry = contents->get(i); | |
6031 if (entry->IsString()) { | |
6032 copy->set(i, entry); | |
6033 } else { | |
6034 DCHECK(entry->IsNumber()); | |
6035 HandleScope scope(isolate); | |
6036 Handle<Object> entry_handle(entry, isolate); | |
6037 Handle<Object> entry_str = | |
6038 isolate->factory()->NumberToString(entry_handle); | |
6039 copy->set(i, *entry_str); | |
6040 } | |
6041 } | |
6042 return *isolate->factory()->NewJSArrayWithElements(copy); | |
6043 } | |
6044 | |
6045 | |
6046 RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) { | |
6047 SealHandleScope shs(isolate); | |
6048 DCHECK(args.length() == 1); | |
6049 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0); | |
6050 | |
6051 // Compute the frame holding the arguments. | |
6052 JavaScriptFrameIterator it(isolate); | |
6053 it.AdvanceToArgumentsFrame(); | |
6054 JavaScriptFrame* frame = it.frame(); | |
6055 | |
6056 // Get the actual number of provided arguments. | |
6057 const uint32_t n = frame->ComputeParametersCount(); | |
6058 | |
6059 // Try to convert the key to an index. If successful and within | |
6060 // index return the the argument from the frame. | |
6061 uint32_t index; | |
6062 if (raw_key->ToArrayIndex(&index) && index < n) { | |
6063 return frame->GetParameter(index); | |
6064 } | |
6065 | |
6066 HandleScope scope(isolate); | |
6067 if (raw_key->IsSymbol()) { | |
6068 Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key); | |
6069 if (symbol->Equals(isolate->native_context()->iterator_symbol())) { | |
6070 return isolate->native_context()->array_values_iterator(); | |
6071 } | |
6072 // Lookup in the initial Object.prototype object. | |
6073 Handle<Object> result; | |
6074 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6075 isolate, result, | |
6076 Object::GetProperty(isolate->initial_object_prototype(), | |
6077 Handle<Symbol>::cast(raw_key))); | |
6078 return *result; | |
6079 } | |
6080 | |
6081 // Convert the key to a string. | |
6082 Handle<Object> converted; | |
6083 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6084 isolate, converted, Execution::ToString(isolate, raw_key)); | |
6085 Handle<String> key = Handle<String>::cast(converted); | |
6086 | |
6087 // Try to convert the string key into an array index. | |
6088 if (key->AsArrayIndex(&index)) { | |
6089 if (index < n) { | |
6090 return frame->GetParameter(index); | |
6091 } else { | |
6092 Handle<Object> initial_prototype(isolate->initial_object_prototype()); | |
6093 Handle<Object> result; | |
6094 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6095 isolate, result, | |
6096 Object::GetElement(isolate, initial_prototype, index)); | |
6097 return *result; | |
6098 } | |
6099 } | |
6100 | |
6101 // Handle special arguments properties. | |
6102 if (String::Equals(isolate->factory()->length_string(), key)) { | |
6103 return Smi::FromInt(n); | |
6104 } | |
6105 if (String::Equals(isolate->factory()->callee_string(), key)) { | |
6106 JSFunction* function = frame->function(); | |
6107 if (function->shared()->strict_mode() == STRICT) { | |
6108 THROW_NEW_ERROR_RETURN_FAILURE( | |
6109 isolate, NewTypeError("strict_arguments_callee", | |
6110 HandleVector<Object>(NULL, 0))); | |
6111 } | |
6112 return function; | |
6113 } | |
6114 | |
6115 // Lookup in the initial Object.prototype object. | |
6116 Handle<Object> result; | |
6117 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6118 isolate, result, | |
6119 Object::GetProperty(isolate->initial_object_prototype(), key)); | |
6120 return *result; | |
6121 } | |
6122 | |
6123 | |
6124 RUNTIME_FUNCTION(Runtime_ToFastProperties) { | |
6125 HandleScope scope(isolate); | |
6126 DCHECK(args.length() == 1); | |
6127 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
6128 if (object->IsJSObject() && !object->IsGlobalObject()) { | |
6129 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0); | |
6130 } | |
6131 return *object; | |
6132 } | |
6133 | |
6134 | |
6135 RUNTIME_FUNCTION(Runtime_ToBool) { | |
6136 SealHandleScope shs(isolate); | |
6137 DCHECK(args.length() == 1); | |
6138 CONVERT_ARG_CHECKED(Object, object, 0); | |
6139 | |
6140 return isolate->heap()->ToBoolean(object->BooleanValue()); | |
6141 } | |
6142 | |
6143 | |
6144 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). | |
6145 // Possible optimizations: put the type string into the oddballs. | |
6146 RUNTIME_FUNCTION(Runtime_Typeof) { | |
6147 SealHandleScope shs(isolate); | |
6148 DCHECK(args.length() == 1); | |
6149 CONVERT_ARG_CHECKED(Object, obj, 0); | |
6150 if (obj->IsNumber()) return isolate->heap()->number_string(); | |
6151 HeapObject* heap_obj = HeapObject::cast(obj); | |
6152 | |
6153 // typeof an undetectable object is 'undefined' | |
6154 if (heap_obj->map()->is_undetectable()) { | |
6155 return isolate->heap()->undefined_string(); | |
6156 } | |
6157 | |
6158 InstanceType instance_type = heap_obj->map()->instance_type(); | |
6159 if (instance_type < FIRST_NONSTRING_TYPE) { | |
6160 return isolate->heap()->string_string(); | |
6161 } | |
6162 | |
6163 switch (instance_type) { | |
6164 case ODDBALL_TYPE: | |
6165 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { | |
6166 return isolate->heap()->boolean_string(); | |
6167 } | |
6168 if (heap_obj->IsNull()) { | |
6169 return isolate->heap()->object_string(); | |
6170 } | |
6171 DCHECK(heap_obj->IsUndefined()); | |
6172 return isolate->heap()->undefined_string(); | |
6173 case SYMBOL_TYPE: | |
6174 return isolate->heap()->symbol_string(); | |
6175 case JS_FUNCTION_TYPE: | |
6176 case JS_FUNCTION_PROXY_TYPE: | |
6177 return isolate->heap()->function_string(); | |
6178 default: | |
6179 // For any kind of object not handled above, the spec rule for | |
6180 // host objects gives that it is okay to return "object" | |
6181 return isolate->heap()->object_string(); | |
6182 } | |
6183 } | |
6184 | |
6185 | |
6186 RUNTIME_FUNCTION(Runtime_Booleanize) { | |
6187 SealHandleScope shs(isolate); | |
6188 DCHECK(args.length() == 2); | |
6189 CONVERT_ARG_CHECKED(Object, value_raw, 0); | |
6190 CONVERT_SMI_ARG_CHECKED(token_raw, 1); | |
6191 intptr_t value = reinterpret_cast<intptr_t>(value_raw); | |
6192 Token::Value token = static_cast<Token::Value>(token_raw); | |
6193 switch (token) { | |
6194 case Token::EQ: | |
6195 case Token::EQ_STRICT: | |
6196 return isolate->heap()->ToBoolean(value == 0); | |
6197 case Token::NE: | |
6198 case Token::NE_STRICT: | |
6199 return isolate->heap()->ToBoolean(value != 0); | |
6200 case Token::LT: | |
6201 return isolate->heap()->ToBoolean(value < 0); | |
6202 case Token::GT: | |
6203 return isolate->heap()->ToBoolean(value > 0); | |
6204 case Token::LTE: | |
6205 return isolate->heap()->ToBoolean(value <= 0); | |
6206 case Token::GTE: | |
6207 return isolate->heap()->ToBoolean(value >= 0); | |
6208 default: | |
6209 // This should only happen during natives fuzzing. | |
6210 return isolate->heap()->undefined_value(); | |
6211 } | |
6212 } | |
6213 | |
6214 | |
6215 static bool AreDigits(const uint8_t*s, int from, int to) { | |
6216 for (int i = from; i < to; i++) { | |
6217 if (s[i] < '0' || s[i] > '9') return false; | |
6218 } | |
6219 | |
6220 return true; | |
6221 } | |
6222 | |
6223 | |
6224 static int ParseDecimalInteger(const uint8_t*s, int from, int to) { | |
6225 DCHECK(to - from < 10); // Overflow is not possible. | |
6226 DCHECK(from < to); | |
6227 int d = s[from] - '0'; | |
6228 | |
6229 for (int i = from + 1; i < to; i++) { | |
6230 d = 10 * d + (s[i] - '0'); | |
6231 } | |
6232 | |
6233 return d; | |
6234 } | |
6235 | |
6236 | |
6237 RUNTIME_FUNCTION(Runtime_StringToNumber) { | |
6238 HandleScope handle_scope(isolate); | |
6239 DCHECK(args.length() == 1); | |
6240 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
6241 subject = String::Flatten(subject); | |
6242 | |
6243 // Fast case: short integer or some sorts of junk values. | |
6244 if (subject->IsSeqOneByteString()) { | |
6245 int len = subject->length(); | |
6246 if (len == 0) return Smi::FromInt(0); | |
6247 | |
6248 DisallowHeapAllocation no_gc; | |
6249 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); | |
6250 bool minus = (data[0] == '-'); | |
6251 int start_pos = (minus ? 1 : 0); | |
6252 | |
6253 if (start_pos == len) { | |
6254 return isolate->heap()->nan_value(); | |
6255 } else if (data[start_pos] > '9') { | |
6256 // Fast check for a junk value. A valid string may start from a | |
6257 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit | |
6258 // or the 'I' character ('Infinity'). All of that have codes not greater | |
6259 // than '9' except 'I' and . | |
6260 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { | |
6261 return isolate->heap()->nan_value(); | |
6262 } | |
6263 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { | |
6264 // The maximal/minimal smi has 10 digits. If the string has less digits | |
6265 // we know it will fit into the smi-data type. | |
6266 int d = ParseDecimalInteger(data, start_pos, len); | |
6267 if (minus) { | |
6268 if (d == 0) return isolate->heap()->minus_zero_value(); | |
6269 d = -d; | |
6270 } else if (!subject->HasHashCode() && | |
6271 len <= String::kMaxArrayIndexSize && | |
6272 (len == 1 || data[0] != '0')) { | |
6273 // String hash is not calculated yet but all the data are present. | |
6274 // Update the hash field to speed up sequential convertions. | |
6275 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); | |
6276 #ifdef DEBUG | |
6277 subject->Hash(); // Force hash calculation. | |
6278 DCHECK_EQ(static_cast<int>(subject->hash_field()), | |
6279 static_cast<int>(hash)); | |
6280 #endif | |
6281 subject->set_hash_field(hash); | |
6282 } | |
6283 return Smi::FromInt(d); | |
6284 } | |
6285 } | |
6286 | |
6287 // Slower case. | |
6288 int flags = ALLOW_HEX; | |
6289 if (FLAG_harmony_numeric_literals) { | |
6290 // The current spec draft has not updated "ToNumber Applied to the String | |
6291 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 | |
6292 flags |= ALLOW_OCTAL | ALLOW_BINARY; | |
6293 } | |
6294 | |
6295 return *isolate->factory()->NewNumber(StringToDouble( | |
6296 isolate->unicode_cache(), *subject, flags)); | |
6297 } | |
6298 | |
6299 | |
6300 RUNTIME_FUNCTION(Runtime_NewString) { | |
6301 HandleScope scope(isolate); | |
6302 DCHECK(args.length() == 2); | |
6303 CONVERT_INT32_ARG_CHECKED(length, 0); | |
6304 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); | |
6305 if (length == 0) return isolate->heap()->empty_string(); | |
6306 Handle<String> result; | |
6307 if (is_one_byte) { | |
6308 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6309 isolate, result, isolate->factory()->NewRawOneByteString(length)); | |
6310 } else { | |
6311 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6312 isolate, result, isolate->factory()->NewRawTwoByteString(length)); | |
6313 } | |
6314 return *result; | |
6315 } | |
6316 | |
6317 | |
6318 RUNTIME_FUNCTION(Runtime_TruncateString) { | |
6319 HandleScope scope(isolate); | |
6320 DCHECK(args.length() == 2); | |
6321 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); | |
6322 CONVERT_INT32_ARG_CHECKED(new_length, 1); | |
6323 RUNTIME_ASSERT(new_length >= 0); | |
6324 return *SeqString::Truncate(string, new_length); | |
6325 } | |
6326 | |
6327 | |
6328 RUNTIME_FUNCTION(Runtime_URIEscape) { | |
6329 HandleScope scope(isolate); | |
6330 DCHECK(args.length() == 1); | |
6331 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | |
6332 Handle<String> string = String::Flatten(source); | |
6333 DCHECK(string->IsFlat()); | |
6334 Handle<String> result; | |
6335 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6336 isolate, result, | |
6337 string->IsOneByteRepresentationUnderneath() | |
6338 ? URIEscape::Escape<uint8_t>(isolate, source) | |
6339 : URIEscape::Escape<uc16>(isolate, source)); | |
6340 return *result; | |
6341 } | |
6342 | |
6343 | |
6344 RUNTIME_FUNCTION(Runtime_URIUnescape) { | |
6345 HandleScope scope(isolate); | |
6346 DCHECK(args.length() == 1); | |
6347 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | |
6348 Handle<String> string = String::Flatten(source); | |
6349 DCHECK(string->IsFlat()); | |
6350 Handle<String> result; | |
6351 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6352 isolate, result, | |
6353 string->IsOneByteRepresentationUnderneath() | |
6354 ? URIUnescape::Unescape<uint8_t>(isolate, source) | |
6355 : URIUnescape::Unescape<uc16>(isolate, source)); | |
6356 return *result; | |
6357 } | |
6358 | |
6359 | |
6360 RUNTIME_FUNCTION(Runtime_QuoteJSONString) { | |
6361 HandleScope scope(isolate); | |
6362 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); | |
6363 DCHECK(args.length() == 1); | |
6364 Handle<Object> result; | |
6365 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6366 isolate, result, BasicJsonStringifier::StringifyString(isolate, string)); | |
6367 return *result; | |
6368 } | |
6369 | |
6370 | |
6371 RUNTIME_FUNCTION(Runtime_BasicJSONStringify) { | |
6372 HandleScope scope(isolate); | |
6373 DCHECK(args.length() == 1); | |
6374 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
6375 BasicJsonStringifier stringifier(isolate); | |
6376 Handle<Object> result; | |
6377 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6378 isolate, result, stringifier.Stringify(object)); | |
6379 return *result; | |
6380 } | |
6381 | |
6382 | |
6383 RUNTIME_FUNCTION(Runtime_StringParseInt) { | |
6384 HandleScope handle_scope(isolate); | |
6385 DCHECK(args.length() == 2); | |
6386 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
6387 CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); | |
6388 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); | |
6389 | |
6390 subject = String::Flatten(subject); | |
6391 double value; | |
6392 | |
6393 { DisallowHeapAllocation no_gc; | |
6394 String::FlatContent flat = subject->GetFlatContent(); | |
6395 | |
6396 // ECMA-262 section 15.1.2.3, empty string is NaN | |
6397 if (flat.IsOneByte()) { | |
6398 value = StringToInt( | |
6399 isolate->unicode_cache(), flat.ToOneByteVector(), radix); | |
6400 } else { | |
6401 value = StringToInt( | |
6402 isolate->unicode_cache(), flat.ToUC16Vector(), radix); | |
6403 } | |
6404 } | |
6405 | |
6406 return *isolate->factory()->NewNumber(value); | |
6407 } | |
6408 | |
6409 | |
6410 RUNTIME_FUNCTION(Runtime_StringParseFloat) { | |
6411 HandleScope shs(isolate); | |
6412 DCHECK(args.length() == 1); | |
6413 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
6414 | |
6415 subject = String::Flatten(subject); | |
6416 double value = StringToDouble(isolate->unicode_cache(), *subject, | |
6417 ALLOW_TRAILING_JUNK, base::OS::nan_value()); | |
6418 | |
6419 return *isolate->factory()->NewNumber(value); | |
6420 } | |
6421 | |
6422 | |
6423 static inline bool ToUpperOverflows(uc32 character) { | |
6424 // y with umlauts and the micro sign are the only characters that stop | |
6425 // fitting into one-byte when converting to uppercase. | |
6426 static const uc32 yuml_code = 0xff; | |
6427 static const uc32 micro_code = 0xb5; | |
6428 return (character == yuml_code || character == micro_code); | |
6429 } | |
6430 | |
6431 | |
6432 template <class Converter> | |
6433 MUST_USE_RESULT static Object* ConvertCaseHelper( | |
6434 Isolate* isolate, | |
6435 String* string, | |
6436 SeqString* result, | |
6437 int result_length, | |
6438 unibrow::Mapping<Converter, 128>* mapping) { | |
6439 DisallowHeapAllocation no_gc; | |
6440 // We try this twice, once with the assumption that the result is no longer | |
6441 // than the input and, if that assumption breaks, again with the exact | |
6442 // length. This may not be pretty, but it is nicer than what was here before | |
6443 // and I hereby claim my vaffel-is. | |
6444 // | |
6445 // NOTE: This assumes that the upper/lower case of an ASCII | |
6446 // character is also ASCII. This is currently the case, but it | |
6447 // might break in the future if we implement more context and locale | |
6448 // dependent upper/lower conversions. | |
6449 bool has_changed_character = false; | |
6450 | |
6451 // Convert all characters to upper case, assuming that they will fit | |
6452 // in the buffer | |
6453 Access<ConsStringIteratorOp> op( | |
6454 isolate->runtime_state()->string_iterator()); | |
6455 StringCharacterStream stream(string, op.value()); | |
6456 unibrow::uchar chars[Converter::kMaxWidth]; | |
6457 // We can assume that the string is not empty | |
6458 uc32 current = stream.GetNext(); | |
6459 bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString(); | |
6460 for (int i = 0; i < result_length;) { | |
6461 bool has_next = stream.HasMore(); | |
6462 uc32 next = has_next ? stream.GetNext() : 0; | |
6463 int char_length = mapping->get(current, next, chars); | |
6464 if (char_length == 0) { | |
6465 // The case conversion of this character is the character itself. | |
6466 result->Set(i, current); | |
6467 i++; | |
6468 } else if (char_length == 1 && | |
6469 (ignore_overflow || !ToUpperOverflows(current))) { | |
6470 // Common case: converting the letter resulted in one character. | |
6471 DCHECK(static_cast<uc32>(chars[0]) != current); | |
6472 result->Set(i, chars[0]); | |
6473 has_changed_character = true; | |
6474 i++; | |
6475 } else if (result_length == string->length()) { | |
6476 bool overflows = ToUpperOverflows(current); | |
6477 // We've assumed that the result would be as long as the | |
6478 // input but here is a character that converts to several | |
6479 // characters. No matter, we calculate the exact length | |
6480 // of the result and try the whole thing again. | |
6481 // | |
6482 // Note that this leaves room for optimization. We could just | |
6483 // memcpy what we already have to the result string. Also, | |
6484 // the result string is the last object allocated we could | |
6485 // "realloc" it and probably, in the vast majority of cases, | |
6486 // extend the existing string to be able to hold the full | |
6487 // result. | |
6488 int next_length = 0; | |
6489 if (has_next) { | |
6490 next_length = mapping->get(next, 0, chars); | |
6491 if (next_length == 0) next_length = 1; | |
6492 } | |
6493 int current_length = i + char_length + next_length; | |
6494 while (stream.HasMore()) { | |
6495 current = stream.GetNext(); | |
6496 overflows |= ToUpperOverflows(current); | |
6497 // NOTE: we use 0 as the next character here because, while | |
6498 // the next character may affect what a character converts to, | |
6499 // it does not in any case affect the length of what it convert | |
6500 // to. | |
6501 int char_length = mapping->get(current, 0, chars); | |
6502 if (char_length == 0) char_length = 1; | |
6503 current_length += char_length; | |
6504 if (current_length > String::kMaxLength) { | |
6505 AllowHeapAllocation allocate_error_and_return; | |
6506 THROW_NEW_ERROR_RETURN_FAILURE(isolate, | |
6507 NewInvalidStringLengthError()); | |
6508 } | |
6509 } | |
6510 // Try again with the real length. Return signed if we need | |
6511 // to allocate a two-byte string for to uppercase. | |
6512 return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length) | |
6513 : Smi::FromInt(current_length); | |
6514 } else { | |
6515 for (int j = 0; j < char_length; j++) { | |
6516 result->Set(i, chars[j]); | |
6517 i++; | |
6518 } | |
6519 has_changed_character = true; | |
6520 } | |
6521 current = next; | |
6522 } | |
6523 if (has_changed_character) { | |
6524 return result; | |
6525 } else { | |
6526 // If we didn't actually change anything in doing the conversion | |
6527 // we simple return the result and let the converted string | |
6528 // become garbage; there is no reason to keep two identical strings | |
6529 // alive. | |
6530 return string; | |
6531 } | |
6532 } | |
6533 | |
6534 | |
6535 namespace { | |
6536 | |
6537 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; | |
6538 static const uintptr_t kAsciiMask = kOneInEveryByte << 7; | |
6539 | |
6540 // Given a word and two range boundaries returns a word with high bit | |
6541 // set in every byte iff the corresponding input byte was strictly in | |
6542 // the range (m, n). All the other bits in the result are cleared. | |
6543 // This function is only useful when it can be inlined and the | |
6544 // boundaries are statically known. | |
6545 // Requires: all bytes in the input word and the boundaries must be | |
6546 // ASCII (less than 0x7F). | |
6547 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { | |
6548 // Use strict inequalities since in edge cases the function could be | |
6549 // further simplified. | |
6550 DCHECK(0 < m && m < n); | |
6551 // Has high bit set in every w byte less than n. | |
6552 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; | |
6553 // Has high bit set in every w byte greater than m. | |
6554 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); | |
6555 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); | |
6556 } | |
6557 | |
6558 | |
6559 #ifdef DEBUG | |
6560 static bool CheckFastAsciiConvert(char* dst, | |
6561 const char* src, | |
6562 int length, | |
6563 bool changed, | |
6564 bool is_to_lower) { | |
6565 bool expected_changed = false; | |
6566 for (int i = 0; i < length; i++) { | |
6567 if (dst[i] == src[i]) continue; | |
6568 expected_changed = true; | |
6569 if (is_to_lower) { | |
6570 DCHECK('A' <= src[i] && src[i] <= 'Z'); | |
6571 DCHECK(dst[i] == src[i] + ('a' - 'A')); | |
6572 } else { | |
6573 DCHECK('a' <= src[i] && src[i] <= 'z'); | |
6574 DCHECK(dst[i] == src[i] - ('a' - 'A')); | |
6575 } | |
6576 } | |
6577 return (expected_changed == changed); | |
6578 } | |
6579 #endif | |
6580 | |
6581 | |
6582 template<class Converter> | |
6583 static bool FastAsciiConvert(char* dst, | |
6584 const char* src, | |
6585 int length, | |
6586 bool* changed_out) { | |
6587 #ifdef DEBUG | |
6588 char* saved_dst = dst; | |
6589 const char* saved_src = src; | |
6590 #endif | |
6591 DisallowHeapAllocation no_gc; | |
6592 // We rely on the distance between upper and lower case letters | |
6593 // being a known power of 2. | |
6594 DCHECK('a' - 'A' == (1 << 5)); | |
6595 // Boundaries for the range of input characters than require conversion. | |
6596 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; | |
6597 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; | |
6598 bool changed = false; | |
6599 uintptr_t or_acc = 0; | |
6600 const char* const limit = src + length; | |
6601 | |
6602 // dst is newly allocated and always aligned. | |
6603 DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t))); | |
6604 // Only attempt processing one word at a time if src is also aligned. | |
6605 if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) { | |
6606 // Process the prefix of the input that requires no conversion one aligned | |
6607 // (machine) word at a time. | |
6608 while (src <= limit - sizeof(uintptr_t)) { | |
6609 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); | |
6610 or_acc |= w; | |
6611 if (AsciiRangeMask(w, lo, hi) != 0) { | |
6612 changed = true; | |
6613 break; | |
6614 } | |
6615 *reinterpret_cast<uintptr_t*>(dst) = w; | |
6616 src += sizeof(uintptr_t); | |
6617 dst += sizeof(uintptr_t); | |
6618 } | |
6619 // Process the remainder of the input performing conversion when | |
6620 // required one word at a time. | |
6621 while (src <= limit - sizeof(uintptr_t)) { | |
6622 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); | |
6623 or_acc |= w; | |
6624 uintptr_t m = AsciiRangeMask(w, lo, hi); | |
6625 // The mask has high (7th) bit set in every byte that needs | |
6626 // conversion and we know that the distance between cases is | |
6627 // 1 << 5. | |
6628 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); | |
6629 src += sizeof(uintptr_t); | |
6630 dst += sizeof(uintptr_t); | |
6631 } | |
6632 } | |
6633 // Process the last few bytes of the input (or the whole input if | |
6634 // unaligned access is not supported). | |
6635 while (src < limit) { | |
6636 char c = *src; | |
6637 or_acc |= c; | |
6638 if (lo < c && c < hi) { | |
6639 c ^= (1 << 5); | |
6640 changed = true; | |
6641 } | |
6642 *dst = c; | |
6643 ++src; | |
6644 ++dst; | |
6645 } | |
6646 | |
6647 if ((or_acc & kAsciiMask) != 0) return false; | |
6648 | |
6649 DCHECK(CheckFastAsciiConvert( | |
6650 saved_dst, saved_src, length, changed, Converter::kIsToLower)); | |
6651 | |
6652 *changed_out = changed; | |
6653 return true; | |
6654 } | |
6655 | |
6656 } // namespace | |
6657 | |
6658 | |
6659 template <class Converter> | |
6660 MUST_USE_RESULT static Object* ConvertCase( | |
6661 Handle<String> s, | |
6662 Isolate* isolate, | |
6663 unibrow::Mapping<Converter, 128>* mapping) { | |
6664 s = String::Flatten(s); | |
6665 int length = s->length(); | |
6666 // Assume that the string is not empty; we need this assumption later | |
6667 if (length == 0) return *s; | |
6668 | |
6669 // Simpler handling of ASCII strings. | |
6670 // | |
6671 // NOTE: This assumes that the upper/lower case of an ASCII | |
6672 // character is also ASCII. This is currently the case, but it | |
6673 // might break in the future if we implement more context and locale | |
6674 // dependent upper/lower conversions. | |
6675 if (s->IsOneByteRepresentationUnderneath()) { | |
6676 // Same length as input. | |
6677 Handle<SeqOneByteString> result = | |
6678 isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); | |
6679 DisallowHeapAllocation no_gc; | |
6680 String::FlatContent flat_content = s->GetFlatContent(); | |
6681 DCHECK(flat_content.IsFlat()); | |
6682 bool has_changed_character = false; | |
6683 bool is_ascii = FastAsciiConvert<Converter>( | |
6684 reinterpret_cast<char*>(result->GetChars()), | |
6685 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()), | |
6686 length, | |
6687 &has_changed_character); | |
6688 // If not ASCII, we discard the result and take the 2 byte path. | |
6689 if (is_ascii) return has_changed_character ? *result : *s; | |
6690 } | |
6691 | |
6692 Handle<SeqString> result; // Same length as input. | |
6693 if (s->IsOneByteRepresentation()) { | |
6694 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); | |
6695 } else { | |
6696 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked(); | |
6697 } | |
6698 | |
6699 Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping); | |
6700 if (answer->IsException() || answer->IsString()) return answer; | |
6701 | |
6702 DCHECK(answer->IsSmi()); | |
6703 length = Smi::cast(answer)->value(); | |
6704 if (s->IsOneByteRepresentation() && length > 0) { | |
6705 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6706 isolate, result, isolate->factory()->NewRawOneByteString(length)); | |
6707 } else { | |
6708 if (length < 0) length = -length; | |
6709 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
6710 isolate, result, isolate->factory()->NewRawTwoByteString(length)); | |
6711 } | |
6712 return ConvertCaseHelper(isolate, *s, *result, length, mapping); | |
6713 } | |
6714 | |
6715 | |
6716 RUNTIME_FUNCTION(Runtime_StringToLowerCase) { | |
6717 HandleScope scope(isolate); | |
6718 DCHECK(args.length() == 1); | |
6719 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); | |
6720 return ConvertCase( | |
6721 s, isolate, isolate->runtime_state()->to_lower_mapping()); | |
6722 } | |
6723 | |
6724 | |
6725 RUNTIME_FUNCTION(Runtime_StringToUpperCase) { | |
6726 HandleScope scope(isolate); | |
6727 DCHECK(args.length() == 1); | |
6728 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); | |
6729 return ConvertCase( | |
6730 s, isolate, isolate->runtime_state()->to_upper_mapping()); | |
6731 } | |
6732 | |
6733 | |
6734 RUNTIME_FUNCTION(Runtime_StringTrim) { | |
6735 HandleScope scope(isolate); | |
6736 DCHECK(args.length() == 3); | |
6737 | |
6738 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); | |
6739 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); | |
6740 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); | |
6741 | |
6742 string = String::Flatten(string); | |
6743 int length = string->length(); | |
6744 | |
6745 int left = 0; | |
6746 UnicodeCache* unicode_cache = isolate->unicode_cache(); | |
6747 if (trimLeft) { | |
6748 while (left < length && | |
6749 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { | |
6750 left++; | |
6751 } | |
6752 } | |
6753 | |
6754 int right = length; | |
6755 if (trimRight) { | |
6756 while (right > left && | |
6757 unicode_cache->IsWhiteSpaceOrLineTerminator( | |
6758 string->Get(right - 1))) { | |
6759 right--; | |
6760 } | |
6761 } | |
6762 | |
6763 return *isolate->factory()->NewSubString(string, left, right); | |
6764 } | |
6765 | |
6766 | |
6767 RUNTIME_FUNCTION(Runtime_StringSplit) { | |
6768 HandleScope handle_scope(isolate); | |
6769 DCHECK(args.length() == 3); | |
6770 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | |
6771 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); | |
6772 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); | |
6773 RUNTIME_ASSERT(limit > 0); | |
6774 | |
6775 int subject_length = subject->length(); | |
6776 int pattern_length = pattern->length(); | |
6777 RUNTIME_ASSERT(pattern_length > 0); | |
6778 | |
6779 if (limit == 0xffffffffu) { | |
6780 Handle<Object> cached_answer( | |
6781 RegExpResultsCache::Lookup(isolate->heap(), | |
6782 *subject, | |
6783 *pattern, | |
6784 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS), | |
6785 isolate); | |
6786 if (*cached_answer != Smi::FromInt(0)) { | |
6787 // The cache FixedArray is a COW-array and can therefore be reused. | |
6788 Handle<JSArray> result = | |
6789 isolate->factory()->NewJSArrayWithElements( | |
6790 Handle<FixedArray>::cast(cached_answer)); | |
6791 return *result; | |
6792 } | |
6793 } | |
6794 | |
6795 // The limit can be very large (0xffffffffu), but since the pattern | |
6796 // isn't empty, we can never create more parts than ~half the length | |
6797 // of the subject. | |
6798 | |
6799 subject = String::Flatten(subject); | |
6800 pattern = String::Flatten(pattern); | |
6801 | |
6802 static const int kMaxInitialListCapacity = 16; | |
6803 | |
6804 ZoneScope zone_scope(isolate->runtime_zone()); | |
6805 | |
6806 // Find (up to limit) indices of separator and end-of-string in subject | |
6807 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); | |
6808 ZoneList<int> indices(initial_capacity, zone_scope.zone()); | |
6809 | |
6810 FindStringIndicesDispatch(isolate, *subject, *pattern, | |
6811 &indices, limit, zone_scope.zone()); | |
6812 | |
6813 if (static_cast<uint32_t>(indices.length()) < limit) { | |
6814 indices.Add(subject_length, zone_scope.zone()); | |
6815 } | |
6816 | |
6817 // The list indices now contains the end of each part to create. | |
6818 | |
6819 // Create JSArray of substrings separated by separator. | |
6820 int part_count = indices.length(); | |
6821 | |
6822 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); | |
6823 JSObject::EnsureCanContainHeapObjectElements(result); | |
6824 result->set_length(Smi::FromInt(part_count)); | |
6825 | |
6826 DCHECK(result->HasFastObjectElements()); | |
6827 | |
6828 if (part_count == 1 && indices.at(0) == subject_length) { | |
6829 FixedArray::cast(result->elements())->set(0, *subject); | |
6830 return *result; | |
6831 } | |
6832 | |
6833 Handle<FixedArray> elements(FixedArray::cast(result->elements())); | |
6834 int part_start = 0; | |
6835 for (int i = 0; i < part_count; i++) { | |
6836 HandleScope local_loop_handle(isolate); | |
6837 int part_end = indices.at(i); | |
6838 Handle<String> substring = | |
6839 isolate->factory()->NewProperSubString(subject, part_start, part_end); | |
6840 elements->set(i, *substring); | |
6841 part_start = part_end + pattern_length; | |
6842 } | |
6843 | |
6844 if (limit == 0xffffffffu) { | |
6845 if (result->HasFastObjectElements()) { | |
6846 RegExpResultsCache::Enter(isolate, | |
6847 subject, | |
6848 pattern, | |
6849 elements, | |
6850 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); | |
6851 } | |
6852 } | |
6853 | |
6854 return *result; | |
6855 } | |
6856 | |
6857 | |
6858 // Copies Latin1 characters to the given fixed array looking up | |
6859 // one-char strings in the cache. Gives up on the first char that is | |
6860 // not in the cache and fills the remainder with smi zeros. Returns | |
6861 // the length of the successfully copied prefix. | |
6862 static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars, | |
6863 FixedArray* elements, int length) { | |
6864 DisallowHeapAllocation no_gc; | |
6865 FixedArray* one_byte_cache = heap->single_character_string_cache(); | |
6866 Object* undefined = heap->undefined_value(); | |
6867 int i; | |
6868 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); | |
6869 for (i = 0; i < length; ++i) { | |
6870 Object* value = one_byte_cache->get(chars[i]); | |
6871 if (value == undefined) break; | |
6872 elements->set(i, value, mode); | |
6873 } | |
6874 if (i < length) { | |
6875 DCHECK(Smi::FromInt(0) == 0); | |
6876 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); | |
6877 } | |
6878 #ifdef DEBUG | |
6879 for (int j = 0; j < length; ++j) { | |
6880 Object* element = elements->get(j); | |
6881 DCHECK(element == Smi::FromInt(0) || | |
6882 (element->IsString() && String::cast(element)->LooksValid())); | |
6883 } | |
6884 #endif | |
6885 return i; | |
6886 } | |
6887 | |
6888 | |
6889 // Converts a String to JSArray. | |
6890 // For example, "foo" => ["f", "o", "o"]. | |
6891 RUNTIME_FUNCTION(Runtime_StringToArray) { | |
6892 HandleScope scope(isolate); | |
6893 DCHECK(args.length() == 2); | |
6894 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); | |
6895 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); | |
6896 | |
6897 s = String::Flatten(s); | |
6898 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); | |
6899 | |
6900 Handle<FixedArray> elements; | |
6901 int position = 0; | |
6902 if (s->IsFlat() && s->IsOneByteRepresentation()) { | |
6903 // Try using cached chars where possible. | |
6904 elements = isolate->factory()->NewUninitializedFixedArray(length); | |
6905 | |
6906 DisallowHeapAllocation no_gc; | |
6907 String::FlatContent content = s->GetFlatContent(); | |
6908 if (content.IsOneByte()) { | |
6909 Vector<const uint8_t> chars = content.ToOneByteVector(); | |
6910 // Note, this will initialize all elements (not only the prefix) | |
6911 // to prevent GC from seeing partially initialized array. | |
6912 position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.start(), | |
6913 *elements, length); | |
6914 } else { | |
6915 MemsetPointer(elements->data_start(), | |
6916 isolate->heap()->undefined_value(), | |
6917 length); | |
6918 } | |
6919 } else { | |
6920 elements = isolate->factory()->NewFixedArray(length); | |
6921 } | |
6922 for (int i = position; i < length; ++i) { | |
6923 Handle<Object> str = | |
6924 isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i)); | |
6925 elements->set(i, *str); | |
6926 } | |
6927 | |
6928 #ifdef DEBUG | |
6929 for (int i = 0; i < length; ++i) { | |
6930 DCHECK(String::cast(elements->get(i))->length() == 1); | |
6931 } | |
6932 #endif | |
6933 | |
6934 return *isolate->factory()->NewJSArrayWithElements(elements); | |
6935 } | |
6936 | |
6937 | |
6938 RUNTIME_FUNCTION(Runtime_NewStringWrapper) { | |
6939 HandleScope scope(isolate); | |
6940 DCHECK(args.length() == 1); | |
6941 CONVERT_ARG_HANDLE_CHECKED(String, value, 0); | |
6942 return *Object::ToObject(isolate, value).ToHandleChecked(); | |
6943 } | |
6944 | |
6945 | |
6946 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { | |
6947 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; | |
6948 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); | |
6949 return char_length == 0; | |
6950 } | |
6951 | |
6952 | |
6953 RUNTIME_FUNCTION(Runtime_NumberToStringRT) { | |
6954 HandleScope scope(isolate); | |
6955 DCHECK(args.length() == 1); | |
6956 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); | |
6957 | |
6958 return *isolate->factory()->NumberToString(number); | |
6959 } | |
6960 | |
6961 | |
6962 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) { | |
6963 HandleScope scope(isolate); | |
6964 DCHECK(args.length() == 1); | |
6965 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); | |
6966 | |
6967 return *isolate->factory()->NumberToString(number, false); | |
6968 } | |
6969 | |
6970 | |
6971 RUNTIME_FUNCTION(Runtime_NumberToInteger) { | |
6972 HandleScope scope(isolate); | |
6973 DCHECK(args.length() == 1); | |
6974 | |
6975 CONVERT_DOUBLE_ARG_CHECKED(number, 0); | |
6976 return *isolate->factory()->NewNumber(DoubleToInteger(number)); | |
6977 } | |
6978 | |
6979 | |
6980 RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) { | |
6981 HandleScope scope(isolate); | |
6982 DCHECK(args.length() == 1); | |
6983 | |
6984 CONVERT_DOUBLE_ARG_CHECKED(number, 0); | |
6985 double double_value = DoubleToInteger(number); | |
6986 // Map both -0 and +0 to +0. | |
6987 if (double_value == 0) double_value = 0; | |
6988 | |
6989 return *isolate->factory()->NewNumber(double_value); | |
6990 } | |
6991 | |
6992 | |
6993 RUNTIME_FUNCTION(Runtime_NumberToJSUint32) { | |
6994 HandleScope scope(isolate); | |
6995 DCHECK(args.length() == 1); | |
6996 | |
6997 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); | |
6998 return *isolate->factory()->NewNumberFromUint(number); | |
6999 } | |
7000 | |
7001 | |
7002 RUNTIME_FUNCTION(Runtime_NumberToJSInt32) { | |
7003 HandleScope scope(isolate); | |
7004 DCHECK(args.length() == 1); | |
7005 | |
7006 CONVERT_DOUBLE_ARG_CHECKED(number, 0); | |
7007 return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number)); | |
7008 } | |
7009 | |
7010 | |
7011 // Converts a Number to a Smi, if possible. Returns NaN if the number is not | |
7012 // a small integer. | |
7013 RUNTIME_FUNCTION(Runtime_NumberToSmi) { | |
7014 SealHandleScope shs(isolate); | |
7015 DCHECK(args.length() == 1); | |
7016 CONVERT_ARG_CHECKED(Object, obj, 0); | |
7017 if (obj->IsSmi()) { | |
7018 return obj; | |
7019 } | |
7020 if (obj->IsHeapNumber()) { | |
7021 double value = HeapNumber::cast(obj)->value(); | |
7022 int int_value = FastD2I(value); | |
7023 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { | |
7024 return Smi::FromInt(int_value); | |
7025 } | |
7026 } | |
7027 return isolate->heap()->nan_value(); | |
7028 } | |
7029 | |
7030 | |
7031 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { | |
7032 HandleScope scope(isolate); | |
7033 DCHECK(args.length() == 0); | |
7034 return *isolate->factory()->NewHeapNumber(0); | |
7035 } | |
7036 | |
7037 | |
7038 RUNTIME_FUNCTION(Runtime_NumberAdd) { | |
7039 HandleScope scope(isolate); | |
7040 DCHECK(args.length() == 2); | |
7041 | |
7042 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7043 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7044 return *isolate->factory()->NewNumber(x + y); | |
7045 } | |
7046 | |
7047 | |
7048 RUNTIME_FUNCTION(Runtime_NumberSub) { | |
7049 HandleScope scope(isolate); | |
7050 DCHECK(args.length() == 2); | |
7051 | |
7052 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7053 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7054 return *isolate->factory()->NewNumber(x - y); | |
7055 } | |
7056 | |
7057 | |
7058 RUNTIME_FUNCTION(Runtime_NumberMul) { | |
7059 HandleScope scope(isolate); | |
7060 DCHECK(args.length() == 2); | |
7061 | |
7062 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7063 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7064 return *isolate->factory()->NewNumber(x * y); | |
7065 } | |
7066 | |
7067 | |
7068 RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) { | |
7069 HandleScope scope(isolate); | |
7070 DCHECK(args.length() == 1); | |
7071 | |
7072 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7073 return *isolate->factory()->NewNumber(-x); | |
7074 } | |
7075 | |
7076 | |
7077 RUNTIME_FUNCTION(Runtime_NumberDiv) { | |
7078 HandleScope scope(isolate); | |
7079 DCHECK(args.length() == 2); | |
7080 | |
7081 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7082 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7083 return *isolate->factory()->NewNumber(x / y); | |
7084 } | |
7085 | |
7086 | |
7087 RUNTIME_FUNCTION(Runtime_NumberMod) { | |
7088 HandleScope scope(isolate); | |
7089 DCHECK(args.length() == 2); | |
7090 | |
7091 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7092 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7093 return *isolate->factory()->NewNumber(modulo(x, y)); | |
7094 } | |
7095 | |
7096 | |
7097 RUNTIME_FUNCTION(Runtime_NumberImul) { | |
7098 HandleScope scope(isolate); | |
7099 DCHECK(args.length() == 2); | |
7100 | |
7101 // We rely on implementation-defined behavior below, but at least not on | |
7102 // undefined behavior. | |
7103 CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]); | |
7104 CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]); | |
7105 int32_t product = static_cast<int32_t>(x * y); | |
7106 return *isolate->factory()->NewNumberFromInt(product); | |
7107 } | |
7108 | |
7109 | |
7110 RUNTIME_FUNCTION(Runtime_StringAdd) { | |
7111 HandleScope scope(isolate); | |
7112 DCHECK(args.length() == 2); | |
7113 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); | |
7114 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); | |
7115 isolate->counters()->string_add_runtime()->Increment(); | |
7116 Handle<String> result; | |
7117 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
7118 isolate, result, isolate->factory()->NewConsString(str1, str2)); | |
7119 return *result; | |
7120 } | |
7121 | |
7122 | |
7123 template <typename sinkchar> | |
7124 static inline void StringBuilderConcatHelper(String* special, | |
7125 sinkchar* sink, | |
7126 FixedArray* fixed_array, | |
7127 int array_length) { | |
7128 DisallowHeapAllocation no_gc; | |
7129 int position = 0; | |
7130 for (int i = 0; i < array_length; i++) { | |
7131 Object* element = fixed_array->get(i); | |
7132 if (element->IsSmi()) { | |
7133 // Smi encoding of position and length. | |
7134 int encoded_slice = Smi::cast(element)->value(); | |
7135 int pos; | |
7136 int len; | |
7137 if (encoded_slice > 0) { | |
7138 // Position and length encoded in one smi. | |
7139 pos = StringBuilderSubstringPosition::decode(encoded_slice); | |
7140 len = StringBuilderSubstringLength::decode(encoded_slice); | |
7141 } else { | |
7142 // Position and length encoded in two smis. | |
7143 Object* obj = fixed_array->get(++i); | |
7144 DCHECK(obj->IsSmi()); | |
7145 pos = Smi::cast(obj)->value(); | |
7146 len = -encoded_slice; | |
7147 } | |
7148 String::WriteToFlat(special, | |
7149 sink + position, | |
7150 pos, | |
7151 pos + len); | |
7152 position += len; | |
7153 } else { | |
7154 String* string = String::cast(element); | |
7155 int element_length = string->length(); | |
7156 String::WriteToFlat(string, sink + position, 0, element_length); | |
7157 position += element_length; | |
7158 } | |
7159 } | |
7160 } | |
7161 | |
7162 | |
7163 // Returns the result length of the concatenation. | |
7164 // On illegal argument, -1 is returned. | |
7165 static inline int StringBuilderConcatLength(int special_length, | |
7166 FixedArray* fixed_array, | |
7167 int array_length, | |
7168 bool* one_byte) { | |
7169 DisallowHeapAllocation no_gc; | |
7170 int position = 0; | |
7171 for (int i = 0; i < array_length; i++) { | |
7172 int increment = 0; | |
7173 Object* elt = fixed_array->get(i); | |
7174 if (elt->IsSmi()) { | |
7175 // Smi encoding of position and length. | |
7176 int smi_value = Smi::cast(elt)->value(); | |
7177 int pos; | |
7178 int len; | |
7179 if (smi_value > 0) { | |
7180 // Position and length encoded in one smi. | |
7181 pos = StringBuilderSubstringPosition::decode(smi_value); | |
7182 len = StringBuilderSubstringLength::decode(smi_value); | |
7183 } else { | |
7184 // Position and length encoded in two smis. | |
7185 len = -smi_value; | |
7186 // Get the position and check that it is a positive smi. | |
7187 i++; | |
7188 if (i >= array_length) return -1; | |
7189 Object* next_smi = fixed_array->get(i); | |
7190 if (!next_smi->IsSmi()) return -1; | |
7191 pos = Smi::cast(next_smi)->value(); | |
7192 if (pos < 0) return -1; | |
7193 } | |
7194 DCHECK(pos >= 0); | |
7195 DCHECK(len >= 0); | |
7196 if (pos > special_length || len > special_length - pos) return -1; | |
7197 increment = len; | |
7198 } else if (elt->IsString()) { | |
7199 String* element = String::cast(elt); | |
7200 int element_length = element->length(); | |
7201 increment = element_length; | |
7202 if (*one_byte && !element->HasOnlyOneByteChars()) { | |
7203 *one_byte = false; | |
7204 } | |
7205 } else { | |
7206 return -1; | |
7207 } | |
7208 if (increment > String::kMaxLength - position) { | |
7209 return kMaxInt; // Provoke throw on allocation. | |
7210 } | |
7211 position += increment; | |
7212 } | |
7213 return position; | |
7214 } | |
7215 | |
7216 | |
7217 RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { | |
7218 HandleScope scope(isolate); | |
7219 DCHECK(args.length() == 3); | |
7220 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | |
7221 int32_t array_length; | |
7222 if (!args[1]->ToInt32(&array_length)) { | |
7223 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); | |
7224 } | |
7225 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); | |
7226 | |
7227 size_t actual_array_length = 0; | |
7228 RUNTIME_ASSERT( | |
7229 TryNumberToSize(isolate, array->length(), &actual_array_length)); | |
7230 RUNTIME_ASSERT(array_length >= 0); | |
7231 RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length); | |
7232 | |
7233 // This assumption is used by the slice encoding in one or two smis. | |
7234 DCHECK(Smi::kMaxValue >= String::kMaxLength); | |
7235 | |
7236 RUNTIME_ASSERT(array->HasFastElements()); | |
7237 JSObject::EnsureCanContainHeapObjectElements(array); | |
7238 | |
7239 int special_length = special->length(); | |
7240 if (!array->HasFastObjectElements()) { | |
7241 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
7242 } | |
7243 | |
7244 int length; | |
7245 bool one_byte = special->HasOnlyOneByteChars(); | |
7246 | |
7247 { DisallowHeapAllocation no_gc; | |
7248 FixedArray* fixed_array = FixedArray::cast(array->elements()); | |
7249 if (fixed_array->length() < array_length) { | |
7250 array_length = fixed_array->length(); | |
7251 } | |
7252 | |
7253 if (array_length == 0) { | |
7254 return isolate->heap()->empty_string(); | |
7255 } else if (array_length == 1) { | |
7256 Object* first = fixed_array->get(0); | |
7257 if (first->IsString()) return first; | |
7258 } | |
7259 length = StringBuilderConcatLength( | |
7260 special_length, fixed_array, array_length, &one_byte); | |
7261 } | |
7262 | |
7263 if (length == -1) { | |
7264 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
7265 } | |
7266 | |
7267 if (one_byte) { | |
7268 Handle<SeqOneByteString> answer; | |
7269 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
7270 isolate, answer, | |
7271 isolate->factory()->NewRawOneByteString(length)); | |
7272 StringBuilderConcatHelper(*special, | |
7273 answer->GetChars(), | |
7274 FixedArray::cast(array->elements()), | |
7275 array_length); | |
7276 return *answer; | |
7277 } else { | |
7278 Handle<SeqTwoByteString> answer; | |
7279 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
7280 isolate, answer, | |
7281 isolate->factory()->NewRawTwoByteString(length)); | |
7282 StringBuilderConcatHelper(*special, | |
7283 answer->GetChars(), | |
7284 FixedArray::cast(array->elements()), | |
7285 array_length); | |
7286 return *answer; | |
7287 } | |
7288 } | |
7289 | |
7290 | |
7291 RUNTIME_FUNCTION(Runtime_StringBuilderJoin) { | |
7292 HandleScope scope(isolate); | |
7293 DCHECK(args.length() == 3); | |
7294 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | |
7295 int32_t array_length; | |
7296 if (!args[1]->ToInt32(&array_length)) { | |
7297 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); | |
7298 } | |
7299 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); | |
7300 RUNTIME_ASSERT(array->HasFastObjectElements()); | |
7301 RUNTIME_ASSERT(array_length >= 0); | |
7302 | |
7303 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); | |
7304 if (fixed_array->length() < array_length) { | |
7305 array_length = fixed_array->length(); | |
7306 } | |
7307 | |
7308 if (array_length == 0) { | |
7309 return isolate->heap()->empty_string(); | |
7310 } else if (array_length == 1) { | |
7311 Object* first = fixed_array->get(0); | |
7312 RUNTIME_ASSERT(first->IsString()); | |
7313 return first; | |
7314 } | |
7315 | |
7316 int separator_length = separator->length(); | |
7317 RUNTIME_ASSERT(separator_length > 0); | |
7318 int max_nof_separators = | |
7319 (String::kMaxLength + separator_length - 1) / separator_length; | |
7320 if (max_nof_separators < (array_length - 1)) { | |
7321 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); | |
7322 } | |
7323 int length = (array_length - 1) * separator_length; | |
7324 for (int i = 0; i < array_length; i++) { | |
7325 Object* element_obj = fixed_array->get(i); | |
7326 RUNTIME_ASSERT(element_obj->IsString()); | |
7327 String* element = String::cast(element_obj); | |
7328 int increment = element->length(); | |
7329 if (increment > String::kMaxLength - length) { | |
7330 STATIC_ASSERT(String::kMaxLength < kMaxInt); | |
7331 length = kMaxInt; // Provoke exception; | |
7332 break; | |
7333 } | |
7334 length += increment; | |
7335 } | |
7336 | |
7337 Handle<SeqTwoByteString> answer; | |
7338 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
7339 isolate, answer, | |
7340 isolate->factory()->NewRawTwoByteString(length)); | |
7341 | |
7342 DisallowHeapAllocation no_gc; | |
7343 | |
7344 uc16* sink = answer->GetChars(); | |
7345 #ifdef DEBUG | |
7346 uc16* end = sink + length; | |
7347 #endif | |
7348 | |
7349 RUNTIME_ASSERT(fixed_array->get(0)->IsString()); | |
7350 String* first = String::cast(fixed_array->get(0)); | |
7351 String* separator_raw = *separator; | |
7352 int first_length = first->length(); | |
7353 String::WriteToFlat(first, sink, 0, first_length); | |
7354 sink += first_length; | |
7355 | |
7356 for (int i = 1; i < array_length; i++) { | |
7357 DCHECK(sink + separator_length <= end); | |
7358 String::WriteToFlat(separator_raw, sink, 0, separator_length); | |
7359 sink += separator_length; | |
7360 | |
7361 RUNTIME_ASSERT(fixed_array->get(i)->IsString()); | |
7362 String* element = String::cast(fixed_array->get(i)); | |
7363 int element_length = element->length(); | |
7364 DCHECK(sink + element_length <= end); | |
7365 String::WriteToFlat(element, sink, 0, element_length); | |
7366 sink += element_length; | |
7367 } | |
7368 DCHECK(sink == end); | |
7369 | |
7370 // Use %_FastOneByteArrayJoin instead. | |
7371 DCHECK(!answer->IsOneByteRepresentation()); | |
7372 return *answer; | |
7373 } | |
7374 | |
7375 template <typename Char> | |
7376 static void JoinSparseArrayWithSeparator(FixedArray* elements, | |
7377 int elements_length, | |
7378 uint32_t array_length, | |
7379 String* separator, | |
7380 Vector<Char> buffer) { | |
7381 DisallowHeapAllocation no_gc; | |
7382 int previous_separator_position = 0; | |
7383 int separator_length = separator->length(); | |
7384 int cursor = 0; | |
7385 for (int i = 0; i < elements_length; i += 2) { | |
7386 int position = NumberToInt32(elements->get(i)); | |
7387 String* string = String::cast(elements->get(i + 1)); | |
7388 int string_length = string->length(); | |
7389 if (string->length() > 0) { | |
7390 while (previous_separator_position < position) { | |
7391 String::WriteToFlat<Char>(separator, &buffer[cursor], | |
7392 0, separator_length); | |
7393 cursor += separator_length; | |
7394 previous_separator_position++; | |
7395 } | |
7396 String::WriteToFlat<Char>(string, &buffer[cursor], | |
7397 0, string_length); | |
7398 cursor += string->length(); | |
7399 } | |
7400 } | |
7401 if (separator_length > 0) { | |
7402 // Array length must be representable as a signed 32-bit number, | |
7403 // otherwise the total string length would have been too large. | |
7404 DCHECK(array_length <= 0x7fffffff); // Is int32_t. | |
7405 int last_array_index = static_cast<int>(array_length - 1); | |
7406 while (previous_separator_position < last_array_index) { | |
7407 String::WriteToFlat<Char>(separator, &buffer[cursor], | |
7408 0, separator_length); | |
7409 cursor += separator_length; | |
7410 previous_separator_position++; | |
7411 } | |
7412 } | |
7413 DCHECK(cursor <= buffer.length()); | |
7414 } | |
7415 | |
7416 | |
7417 RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { | |
7418 HandleScope scope(isolate); | |
7419 DCHECK(args.length() == 3); | |
7420 CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0); | |
7421 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); | |
7422 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); | |
7423 // elements_array is fast-mode JSarray of alternating positions | |
7424 // (increasing order) and strings. | |
7425 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); | |
7426 // array_length is length of original array (used to add separators); | |
7427 // separator is string to put between elements. Assumed to be non-empty. | |
7428 RUNTIME_ASSERT(array_length > 0); | |
7429 | |
7430 // Find total length of join result. | |
7431 int string_length = 0; | |
7432 bool is_one_byte = separator->IsOneByteRepresentation(); | |
7433 bool overflow = false; | |
7434 CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length()); | |
7435 RUNTIME_ASSERT(elements_length <= elements_array->elements()->length()); | |
7436 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. | |
7437 FixedArray* elements = FixedArray::cast(elements_array->elements()); | |
7438 for (int i = 0; i < elements_length; i += 2) { | |
7439 RUNTIME_ASSERT(elements->get(i)->IsNumber()); | |
7440 CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i)); | |
7441 RUNTIME_ASSERT(position < array_length); | |
7442 RUNTIME_ASSERT(elements->get(i + 1)->IsString()); | |
7443 } | |
7444 | |
7445 { DisallowHeapAllocation no_gc; | |
7446 for (int i = 0; i < elements_length; i += 2) { | |
7447 String* string = String::cast(elements->get(i + 1)); | |
7448 int length = string->length(); | |
7449 if (is_one_byte && !string->IsOneByteRepresentation()) { | |
7450 is_one_byte = false; | |
7451 } | |
7452 if (length > String::kMaxLength || | |
7453 String::kMaxLength - length < string_length) { | |
7454 overflow = true; | |
7455 break; | |
7456 } | |
7457 string_length += length; | |
7458 } | |
7459 } | |
7460 | |
7461 int separator_length = separator->length(); | |
7462 if (!overflow && separator_length > 0) { | |
7463 if (array_length <= 0x7fffffffu) { | |
7464 int separator_count = static_cast<int>(array_length) - 1; | |
7465 int remaining_length = String::kMaxLength - string_length; | |
7466 if ((remaining_length / separator_length) >= separator_count) { | |
7467 string_length += separator_length * (array_length - 1); | |
7468 } else { | |
7469 // Not room for the separators within the maximal string length. | |
7470 overflow = true; | |
7471 } | |
7472 } else { | |
7473 // Nonempty separator and at least 2^31-1 separators necessary | |
7474 // means that the string is too large to create. | |
7475 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | |
7476 overflow = true; | |
7477 } | |
7478 } | |
7479 if (overflow) { | |
7480 // Throw an exception if the resulting string is too large. See | |
7481 // https://code.google.com/p/chromium/issues/detail?id=336820 | |
7482 // for details. | |
7483 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); | |
7484 } | |
7485 | |
7486 if (is_one_byte) { | |
7487 Handle<SeqOneByteString> result = isolate->factory()->NewRawOneByteString( | |
7488 string_length).ToHandleChecked(); | |
7489 JoinSparseArrayWithSeparator<uint8_t>( | |
7490 FixedArray::cast(elements_array->elements()), | |
7491 elements_length, | |
7492 array_length, | |
7493 *separator, | |
7494 Vector<uint8_t>(result->GetChars(), string_length)); | |
7495 return *result; | |
7496 } else { | |
7497 Handle<SeqTwoByteString> result = isolate->factory()->NewRawTwoByteString( | |
7498 string_length).ToHandleChecked(); | |
7499 JoinSparseArrayWithSeparator<uc16>( | |
7500 FixedArray::cast(elements_array->elements()), | |
7501 elements_length, | |
7502 array_length, | |
7503 *separator, | |
7504 Vector<uc16>(result->GetChars(), string_length)); | |
7505 return *result; | |
7506 } | |
7507 } | |
7508 | |
7509 | |
7510 RUNTIME_FUNCTION(Runtime_NumberOr) { | |
7511 HandleScope scope(isolate); | |
7512 DCHECK(args.length() == 2); | |
7513 | |
7514 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | |
7515 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7516 return *isolate->factory()->NewNumberFromInt(x | y); | |
7517 } | |
7518 | |
7519 | |
7520 RUNTIME_FUNCTION(Runtime_NumberAnd) { | |
7521 HandleScope scope(isolate); | |
7522 DCHECK(args.length() == 2); | |
7523 | |
7524 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | |
7525 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7526 return *isolate->factory()->NewNumberFromInt(x & y); | |
7527 } | |
7528 | |
7529 | |
7530 RUNTIME_FUNCTION(Runtime_NumberXor) { | |
7531 HandleScope scope(isolate); | |
7532 DCHECK(args.length() == 2); | |
7533 | |
7534 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | |
7535 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7536 return *isolate->factory()->NewNumberFromInt(x ^ y); | |
7537 } | |
7538 | |
7539 | |
7540 RUNTIME_FUNCTION(Runtime_NumberShl) { | |
7541 HandleScope scope(isolate); | |
7542 DCHECK(args.length() == 2); | |
7543 | |
7544 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | |
7545 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7546 return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f)); | |
7547 } | |
7548 | |
7549 | |
7550 RUNTIME_FUNCTION(Runtime_NumberShr) { | |
7551 HandleScope scope(isolate); | |
7552 DCHECK(args.length() == 2); | |
7553 | |
7554 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); | |
7555 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7556 return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f)); | |
7557 } | |
7558 | |
7559 | |
7560 RUNTIME_FUNCTION(Runtime_NumberSar) { | |
7561 HandleScope scope(isolate); | |
7562 DCHECK(args.length() == 2); | |
7563 | |
7564 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); | |
7565 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); | |
7566 return *isolate->factory()->NewNumberFromInt( | |
7567 ArithmeticShiftRight(x, y & 0x1f)); | |
7568 } | |
7569 | |
7570 | |
7571 RUNTIME_FUNCTION(Runtime_NumberEquals) { | |
7572 SealHandleScope shs(isolate); | |
7573 DCHECK(args.length() == 2); | |
7574 | |
7575 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7576 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7577 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL); | |
7578 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL); | |
7579 if (x == y) return Smi::FromInt(EQUAL); | |
7580 Object* result; | |
7581 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { | |
7582 result = Smi::FromInt(EQUAL); | |
7583 } else { | |
7584 result = Smi::FromInt(NOT_EQUAL); | |
7585 } | |
7586 return result; | |
7587 } | |
7588 | |
7589 | |
7590 RUNTIME_FUNCTION(Runtime_StringEquals) { | |
7591 HandleScope handle_scope(isolate); | |
7592 DCHECK(args.length() == 2); | |
7593 | |
7594 CONVERT_ARG_HANDLE_CHECKED(String, x, 0); | |
7595 CONVERT_ARG_HANDLE_CHECKED(String, y, 1); | |
7596 | |
7597 bool not_equal = !String::Equals(x, y); | |
7598 // This is slightly convoluted because the value that signifies | |
7599 // equality is 0 and inequality is 1 so we have to negate the result | |
7600 // from String::Equals. | |
7601 DCHECK(not_equal == 0 || not_equal == 1); | |
7602 STATIC_ASSERT(EQUAL == 0); | |
7603 STATIC_ASSERT(NOT_EQUAL == 1); | |
7604 return Smi::FromInt(not_equal); | |
7605 } | |
7606 | |
7607 | |
7608 RUNTIME_FUNCTION(Runtime_NumberCompare) { | |
7609 SealHandleScope shs(isolate); | |
7610 DCHECK(args.length() == 3); | |
7611 | |
7612 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7613 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7614 CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) | |
7615 if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; | |
7616 if (x == y) return Smi::FromInt(EQUAL); | |
7617 if (isless(x, y)) return Smi::FromInt(LESS); | |
7618 return Smi::FromInt(GREATER); | |
7619 } | |
7620 | |
7621 | |
7622 // Compare two Smis as if they were converted to strings and then | |
7623 // compared lexicographically. | |
7624 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) { | |
7625 SealHandleScope shs(isolate); | |
7626 DCHECK(args.length() == 2); | |
7627 CONVERT_SMI_ARG_CHECKED(x_value, 0); | |
7628 CONVERT_SMI_ARG_CHECKED(y_value, 1); | |
7629 | |
7630 // If the integers are equal so are the string representations. | |
7631 if (x_value == y_value) return Smi::FromInt(EQUAL); | |
7632 | |
7633 // If one of the integers is zero the normal integer order is the | |
7634 // same as the lexicographic order of the string representations. | |
7635 if (x_value == 0 || y_value == 0) | |
7636 return Smi::FromInt(x_value < y_value ? LESS : GREATER); | |
7637 | |
7638 // If only one of the integers is negative the negative number is | |
7639 // smallest because the char code of '-' is less than the char code | |
7640 // of any digit. Otherwise, we make both values positive. | |
7641 | |
7642 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on | |
7643 // architectures using 32-bit Smis. | |
7644 uint32_t x_scaled = x_value; | |
7645 uint32_t y_scaled = y_value; | |
7646 if (x_value < 0 || y_value < 0) { | |
7647 if (y_value >= 0) return Smi::FromInt(LESS); | |
7648 if (x_value >= 0) return Smi::FromInt(GREATER); | |
7649 x_scaled = -x_value; | |
7650 y_scaled = -y_value; | |
7651 } | |
7652 | |
7653 static const uint32_t kPowersOf10[] = { | |
7654 1, 10, 100, 1000, 10*1000, 100*1000, | |
7655 1000*1000, 10*1000*1000, 100*1000*1000, | |
7656 1000*1000*1000 | |
7657 }; | |
7658 | |
7659 // If the integers have the same number of decimal digits they can be | |
7660 // compared directly as the numeric order is the same as the | |
7661 // lexicographic order. If one integer has fewer digits, it is scaled | |
7662 // by some power of 10 to have the same number of digits as the longer | |
7663 // integer. If the scaled integers are equal it means the shorter | |
7664 // integer comes first in the lexicographic order. | |
7665 | |
7666 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 | |
7667 int x_log2 = IntegerLog2(x_scaled); | |
7668 int x_log10 = ((x_log2 + 1) * 1233) >> 12; | |
7669 x_log10 -= x_scaled < kPowersOf10[x_log10]; | |
7670 | |
7671 int y_log2 = IntegerLog2(y_scaled); | |
7672 int y_log10 = ((y_log2 + 1) * 1233) >> 12; | |
7673 y_log10 -= y_scaled < kPowersOf10[y_log10]; | |
7674 | |
7675 int tie = EQUAL; | |
7676 | |
7677 if (x_log10 < y_log10) { | |
7678 // X has fewer digits. We would like to simply scale up X but that | |
7679 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would | |
7680 // be scaled up to 9_000_000_000. So we scale up by the next | |
7681 // smallest power and scale down Y to drop one digit. It is OK to | |
7682 // drop one digit from the longer integer since the final digit is | |
7683 // past the length of the shorter integer. | |
7684 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; | |
7685 y_scaled /= 10; | |
7686 tie = LESS; | |
7687 } else if (y_log10 < x_log10) { | |
7688 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; | |
7689 x_scaled /= 10; | |
7690 tie = GREATER; | |
7691 } | |
7692 | |
7693 if (x_scaled < y_scaled) return Smi::FromInt(LESS); | |
7694 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); | |
7695 return Smi::FromInt(tie); | |
7696 } | |
7697 | |
7698 | |
7699 RUNTIME_FUNCTION(Runtime_StringCompare) { | |
7700 HandleScope handle_scope(isolate); | |
7701 DCHECK(args.length() == 2); | |
7702 | |
7703 CONVERT_ARG_HANDLE_CHECKED(String, x, 0); | |
7704 CONVERT_ARG_HANDLE_CHECKED(String, y, 1); | |
7705 | |
7706 isolate->counters()->string_compare_runtime()->Increment(); | |
7707 | |
7708 // A few fast case tests before we flatten. | |
7709 if (x.is_identical_to(y)) return Smi::FromInt(EQUAL); | |
7710 if (y->length() == 0) { | |
7711 if (x->length() == 0) return Smi::FromInt(EQUAL); | |
7712 return Smi::FromInt(GREATER); | |
7713 } else if (x->length() == 0) { | |
7714 return Smi::FromInt(LESS); | |
7715 } | |
7716 | |
7717 int d = x->Get(0) - y->Get(0); | |
7718 if (d < 0) return Smi::FromInt(LESS); | |
7719 else if (d > 0) return Smi::FromInt(GREATER); | |
7720 | |
7721 // Slow case. | |
7722 x = String::Flatten(x); | |
7723 y = String::Flatten(y); | |
7724 | |
7725 DisallowHeapAllocation no_gc; | |
7726 Object* equal_prefix_result = Smi::FromInt(EQUAL); | |
7727 int prefix_length = x->length(); | |
7728 if (y->length() < prefix_length) { | |
7729 prefix_length = y->length(); | |
7730 equal_prefix_result = Smi::FromInt(GREATER); | |
7731 } else if (y->length() > prefix_length) { | |
7732 equal_prefix_result = Smi::FromInt(LESS); | |
7733 } | |
7734 int r; | |
7735 String::FlatContent x_content = x->GetFlatContent(); | |
7736 String::FlatContent y_content = y->GetFlatContent(); | |
7737 if (x_content.IsOneByte()) { | |
7738 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); | |
7739 if (y_content.IsOneByte()) { | |
7740 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); | |
7741 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | |
7742 } else { | |
7743 Vector<const uc16> y_chars = y_content.ToUC16Vector(); | |
7744 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | |
7745 } | |
7746 } else { | |
7747 Vector<const uc16> x_chars = x_content.ToUC16Vector(); | |
7748 if (y_content.IsOneByte()) { | |
7749 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); | |
7750 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | |
7751 } else { | |
7752 Vector<const uc16> y_chars = y_content.ToUC16Vector(); | |
7753 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); | |
7754 } | |
7755 } | |
7756 Object* result; | |
7757 if (r == 0) { | |
7758 result = equal_prefix_result; | |
7759 } else { | |
7760 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); | |
7761 } | |
7762 return result; | |
7763 } | |
7764 | |
7765 | |
7766 #define RUNTIME_UNARY_MATH(Name, name) \ | |
7767 RUNTIME_FUNCTION(Runtime_Math##Name) { \ | |
7768 HandleScope scope(isolate); \ | |
7769 DCHECK(args.length() == 1); \ | |
7770 isolate->counters()->math_##name()->Increment(); \ | |
7771 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \ | |
7772 return *isolate->factory()->NewHeapNumber(std::name(x)); \ | |
7773 } | |
7774 | |
7775 RUNTIME_UNARY_MATH(Acos, acos) | |
7776 RUNTIME_UNARY_MATH(Asin, asin) | |
7777 RUNTIME_UNARY_MATH(Atan, atan) | |
7778 RUNTIME_UNARY_MATH(LogRT, log) | |
7779 #undef RUNTIME_UNARY_MATH | |
7780 | |
7781 | |
7782 RUNTIME_FUNCTION(Runtime_DoubleHi) { | |
7783 HandleScope scope(isolate); | |
7784 DCHECK(args.length() == 1); | |
7785 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7786 uint64_t integer = double_to_uint64(x); | |
7787 integer = (integer >> 32) & 0xFFFFFFFFu; | |
7788 return *isolate->factory()->NewNumber(static_cast<int32_t>(integer)); | |
7789 } | |
7790 | |
7791 | |
7792 RUNTIME_FUNCTION(Runtime_DoubleLo) { | |
7793 HandleScope scope(isolate); | |
7794 DCHECK(args.length() == 1); | |
7795 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7796 return *isolate->factory()->NewNumber( | |
7797 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu)); | |
7798 } | |
7799 | |
7800 | |
7801 RUNTIME_FUNCTION(Runtime_ConstructDouble) { | |
7802 HandleScope scope(isolate); | |
7803 DCHECK(args.length() == 2); | |
7804 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); | |
7805 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); | |
7806 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; | |
7807 return *isolate->factory()->NewNumber(uint64_to_double(result)); | |
7808 } | |
7809 | |
7810 | |
7811 RUNTIME_FUNCTION(Runtime_RemPiO2) { | |
7812 HandleScope handle_scope(isolate); | |
7813 DCHECK(args.length() == 1); | |
7814 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7815 Factory* factory = isolate->factory(); | |
7816 double y[2]; | |
7817 int n = fdlibm::rempio2(x, y); | |
7818 Handle<FixedArray> array = factory->NewFixedArray(3); | |
7819 Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]); | |
7820 Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]); | |
7821 array->set(0, Smi::FromInt(n)); | |
7822 array->set(1, *y0); | |
7823 array->set(2, *y1); | |
7824 return *factory->NewJSArrayWithElements(array); | |
7825 } | |
7826 | |
7827 | |
7828 static const double kPiDividedBy4 = 0.78539816339744830962; | |
7829 | |
7830 | |
7831 RUNTIME_FUNCTION(Runtime_MathAtan2) { | |
7832 HandleScope scope(isolate); | |
7833 DCHECK(args.length() == 2); | |
7834 isolate->counters()->math_atan2()->Increment(); | |
7835 | |
7836 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7837 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7838 double result; | |
7839 if (std::isinf(x) && std::isinf(y)) { | |
7840 // Make sure that the result in case of two infinite arguments | |
7841 // is a multiple of Pi / 4. The sign of the result is determined | |
7842 // by the first argument (x) and the sign of the second argument | |
7843 // determines the multiplier: one or three. | |
7844 int multiplier = (x < 0) ? -1 : 1; | |
7845 if (y < 0) multiplier *= 3; | |
7846 result = multiplier * kPiDividedBy4; | |
7847 } else { | |
7848 result = std::atan2(x, y); | |
7849 } | |
7850 return *isolate->factory()->NewNumber(result); | |
7851 } | |
7852 | |
7853 | |
7854 RUNTIME_FUNCTION(Runtime_MathExpRT) { | |
7855 HandleScope scope(isolate); | |
7856 DCHECK(args.length() == 1); | |
7857 isolate->counters()->math_exp()->Increment(); | |
7858 | |
7859 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7860 lazily_initialize_fast_exp(); | |
7861 return *isolate->factory()->NewNumber(fast_exp(x)); | |
7862 } | |
7863 | |
7864 | |
7865 RUNTIME_FUNCTION(Runtime_MathFloorRT) { | |
7866 HandleScope scope(isolate); | |
7867 DCHECK(args.length() == 1); | |
7868 isolate->counters()->math_floor()->Increment(); | |
7869 | |
7870 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7871 return *isolate->factory()->NewNumber(Floor(x)); | |
7872 } | |
7873 | |
7874 | |
7875 // Slow version of Math.pow. We check for fast paths for special cases. | |
7876 // Used if VFP3 is not available. | |
7877 RUNTIME_FUNCTION(Runtime_MathPowSlow) { | |
7878 HandleScope scope(isolate); | |
7879 DCHECK(args.length() == 2); | |
7880 isolate->counters()->math_pow()->Increment(); | |
7881 | |
7882 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7883 | |
7884 // If the second argument is a smi, it is much faster to call the | |
7885 // custom powi() function than the generic pow(). | |
7886 if (args[1]->IsSmi()) { | |
7887 int y = args.smi_at(1); | |
7888 return *isolate->factory()->NewNumber(power_double_int(x, y)); | |
7889 } | |
7890 | |
7891 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7892 double result = power_helper(x, y); | |
7893 if (std::isnan(result)) return isolate->heap()->nan_value(); | |
7894 return *isolate->factory()->NewNumber(result); | |
7895 } | |
7896 | |
7897 | |
7898 // Fast version of Math.pow if we know that y is not an integer and y is not | |
7899 // -0.5 or 0.5. Used as slow case from full codegen. | |
7900 RUNTIME_FUNCTION(Runtime_MathPowRT) { | |
7901 HandleScope scope(isolate); | |
7902 DCHECK(args.length() == 2); | |
7903 isolate->counters()->math_pow()->Increment(); | |
7904 | |
7905 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7906 CONVERT_DOUBLE_ARG_CHECKED(y, 1); | |
7907 if (y == 0) { | |
7908 return Smi::FromInt(1); | |
7909 } else { | |
7910 double result = power_double_double(x, y); | |
7911 if (std::isnan(result)) return isolate->heap()->nan_value(); | |
7912 return *isolate->factory()->NewNumber(result); | |
7913 } | |
7914 } | |
7915 | |
7916 | |
7917 RUNTIME_FUNCTION(Runtime_RoundNumber) { | |
7918 HandleScope scope(isolate); | |
7919 DCHECK(args.length() == 1); | |
7920 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); | |
7921 isolate->counters()->math_round()->Increment(); | |
7922 | |
7923 if (!input->IsHeapNumber()) { | |
7924 DCHECK(input->IsSmi()); | |
7925 return *input; | |
7926 } | |
7927 | |
7928 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input); | |
7929 | |
7930 double value = number->value(); | |
7931 int exponent = number->get_exponent(); | |
7932 int sign = number->get_sign(); | |
7933 | |
7934 if (exponent < -1) { | |
7935 // Number in range ]-0.5..0.5[. These always round to +/-zero. | |
7936 if (sign) return isolate->heap()->minus_zero_value(); | |
7937 return Smi::FromInt(0); | |
7938 } | |
7939 | |
7940 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and | |
7941 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar | |
7942 // argument holds for 32-bit smis). | |
7943 if (!sign && exponent < kSmiValueSize - 2) { | |
7944 return Smi::FromInt(static_cast<int>(value + 0.5)); | |
7945 } | |
7946 | |
7947 // If the magnitude is big enough, there's no place for fraction part. If we | |
7948 // try to add 0.5 to this number, 1.0 will be added instead. | |
7949 if (exponent >= 52) { | |
7950 return *number; | |
7951 } | |
7952 | |
7953 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); | |
7954 | |
7955 // Do not call NumberFromDouble() to avoid extra checks. | |
7956 return *isolate->factory()->NewNumber(Floor(value + 0.5)); | |
7957 } | |
7958 | |
7959 | |
7960 RUNTIME_FUNCTION(Runtime_MathSqrtRT) { | |
7961 HandleScope scope(isolate); | |
7962 DCHECK(args.length() == 1); | |
7963 isolate->counters()->math_sqrt()->Increment(); | |
7964 | |
7965 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7966 return *isolate->factory()->NewNumber(fast_sqrt(x)); | |
7967 } | |
7968 | |
7969 | |
7970 RUNTIME_FUNCTION(Runtime_MathFround) { | |
7971 HandleScope scope(isolate); | |
7972 DCHECK(args.length() == 1); | |
7973 | |
7974 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
7975 float xf = DoubleToFloat32(x); | |
7976 return *isolate->factory()->NewNumber(xf); | |
7977 } | |
7978 | |
7979 | |
7980 RUNTIME_FUNCTION(Runtime_DateMakeDay) { | |
7981 SealHandleScope shs(isolate); | |
7982 DCHECK(args.length() == 2); | |
7983 | |
7984 CONVERT_SMI_ARG_CHECKED(year, 0); | |
7985 CONVERT_SMI_ARG_CHECKED(month, 1); | |
7986 | |
7987 int days = isolate->date_cache()->DaysFromYearMonth(year, month); | |
7988 RUNTIME_ASSERT(Smi::IsValid(days)); | |
7989 return Smi::FromInt(days); | |
7990 } | |
7991 | |
7992 | |
7993 RUNTIME_FUNCTION(Runtime_DateSetValue) { | |
7994 HandleScope scope(isolate); | |
7995 DCHECK(args.length() == 3); | |
7996 | |
7997 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); | |
7998 CONVERT_DOUBLE_ARG_CHECKED(time, 1); | |
7999 CONVERT_SMI_ARG_CHECKED(is_utc, 2); | |
8000 | |
8001 DateCache* date_cache = isolate->date_cache(); | |
8002 | |
8003 Handle<Object> value;; | |
8004 bool is_value_nan = false; | |
8005 if (std::isnan(time)) { | |
8006 value = isolate->factory()->nan_value(); | |
8007 is_value_nan = true; | |
8008 } else if (!is_utc && | |
8009 (time < -DateCache::kMaxTimeBeforeUTCInMs || | |
8010 time > DateCache::kMaxTimeBeforeUTCInMs)) { | |
8011 value = isolate->factory()->nan_value(); | |
8012 is_value_nan = true; | |
8013 } else { | |
8014 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); | |
8015 if (time < -DateCache::kMaxTimeInMs || | |
8016 time > DateCache::kMaxTimeInMs) { | |
8017 value = isolate->factory()->nan_value(); | |
8018 is_value_nan = true; | |
8019 } else { | |
8020 value = isolate->factory()->NewNumber(DoubleToInteger(time)); | |
8021 } | |
8022 } | |
8023 date->SetValue(*value, is_value_nan); | |
8024 return *value; | |
8025 } | |
8026 | |
8027 | |
8028 static Handle<JSObject> NewSloppyArguments(Isolate* isolate, | |
8029 Handle<JSFunction> callee, | |
8030 Object** parameters, | |
8031 int argument_count) { | |
8032 Handle<JSObject> result = | |
8033 isolate->factory()->NewArgumentsObject(callee, argument_count); | |
8034 | |
8035 // Allocate the elements if needed. | |
8036 int parameter_count = callee->shared()->formal_parameter_count(); | |
8037 if (argument_count > 0) { | |
8038 if (parameter_count > 0) { | |
8039 int mapped_count = Min(argument_count, parameter_count); | |
8040 Handle<FixedArray> parameter_map = | |
8041 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); | |
8042 parameter_map->set_map( | |
8043 isolate->heap()->sloppy_arguments_elements_map()); | |
8044 | |
8045 Handle<Map> map = Map::Copy(handle(result->map())); | |
8046 map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS); | |
8047 | |
8048 result->set_map(*map); | |
8049 result->set_elements(*parameter_map); | |
8050 | |
8051 // Store the context and the arguments array at the beginning of the | |
8052 // parameter map. | |
8053 Handle<Context> context(isolate->context()); | |
8054 Handle<FixedArray> arguments = | |
8055 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); | |
8056 parameter_map->set(0, *context); | |
8057 parameter_map->set(1, *arguments); | |
8058 | |
8059 // Loop over the actual parameters backwards. | |
8060 int index = argument_count - 1; | |
8061 while (index >= mapped_count) { | |
8062 // These go directly in the arguments array and have no | |
8063 // corresponding slot in the parameter map. | |
8064 arguments->set(index, *(parameters - index - 1)); | |
8065 --index; | |
8066 } | |
8067 | |
8068 Handle<ScopeInfo> scope_info(callee->shared()->scope_info()); | |
8069 while (index >= 0) { | |
8070 // Detect duplicate names to the right in the parameter list. | |
8071 Handle<String> name(scope_info->ParameterName(index)); | |
8072 int context_local_count = scope_info->ContextLocalCount(); | |
8073 bool duplicate = false; | |
8074 for (int j = index + 1; j < parameter_count; ++j) { | |
8075 if (scope_info->ParameterName(j) == *name) { | |
8076 duplicate = true; | |
8077 break; | |
8078 } | |
8079 } | |
8080 | |
8081 if (duplicate) { | |
8082 // This goes directly in the arguments array with a hole in the | |
8083 // parameter map. | |
8084 arguments->set(index, *(parameters - index - 1)); | |
8085 parameter_map->set_the_hole(index + 2); | |
8086 } else { | |
8087 // The context index goes in the parameter map with a hole in the | |
8088 // arguments array. | |
8089 int context_index = -1; | |
8090 for (int j = 0; j < context_local_count; ++j) { | |
8091 if (scope_info->ContextLocalName(j) == *name) { | |
8092 context_index = j; | |
8093 break; | |
8094 } | |
8095 } | |
8096 DCHECK(context_index >= 0); | |
8097 arguments->set_the_hole(index); | |
8098 parameter_map->set(index + 2, Smi::FromInt( | |
8099 Context::MIN_CONTEXT_SLOTS + context_index)); | |
8100 } | |
8101 | |
8102 --index; | |
8103 } | |
8104 } else { | |
8105 // If there is no aliasing, the arguments object elements are not | |
8106 // special in any way. | |
8107 Handle<FixedArray> elements = | |
8108 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); | |
8109 result->set_elements(*elements); | |
8110 for (int i = 0; i < argument_count; ++i) { | |
8111 elements->set(i, *(parameters - i - 1)); | |
8112 } | |
8113 } | |
8114 } | |
8115 return result; | |
8116 } | |
8117 | |
8118 | |
8119 static Handle<JSObject> NewStrictArguments(Isolate* isolate, | |
8120 Handle<JSFunction> callee, | |
8121 Object** parameters, | |
8122 int argument_count) { | |
8123 Handle<JSObject> result = | |
8124 isolate->factory()->NewArgumentsObject(callee, argument_count); | |
8125 | |
8126 if (argument_count > 0) { | |
8127 Handle<FixedArray> array = | |
8128 isolate->factory()->NewUninitializedFixedArray(argument_count); | |
8129 DisallowHeapAllocation no_gc; | |
8130 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); | |
8131 for (int i = 0; i < argument_count; i++) { | |
8132 array->set(i, *--parameters, mode); | |
8133 } | |
8134 result->set_elements(*array); | |
8135 } | |
8136 return result; | |
8137 } | |
8138 | |
8139 | |
8140 RUNTIME_FUNCTION(Runtime_NewArguments) { | |
8141 HandleScope scope(isolate); | |
8142 DCHECK(args.length() == 1); | |
8143 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0); | |
8144 JavaScriptFrameIterator it(isolate); | |
8145 | |
8146 // Find the frame that holds the actual arguments passed to the function. | |
8147 it.AdvanceToArgumentsFrame(); | |
8148 JavaScriptFrame* frame = it.frame(); | |
8149 | |
8150 // Determine parameter location on the stack and dispatch on language mode. | |
8151 int argument_count = frame->GetArgumentsLength(); | |
8152 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1)); | |
8153 return callee->shared()->strict_mode() == STRICT | |
8154 ? *NewStrictArguments(isolate, callee, parameters, argument_count) | |
8155 : *NewSloppyArguments(isolate, callee, parameters, argument_count); | |
8156 } | |
8157 | |
8158 | |
8159 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) { | |
8160 HandleScope scope(isolate); | |
8161 DCHECK(args.length() == 3); | |
8162 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0); | |
8163 Object** parameters = reinterpret_cast<Object**>(args[1]); | |
8164 CONVERT_SMI_ARG_CHECKED(argument_count, 2); | |
8165 return *NewSloppyArguments(isolate, callee, parameters, argument_count); | |
8166 } | |
8167 | |
8168 | |
8169 RUNTIME_FUNCTION(Runtime_NewStrictArguments) { | |
8170 HandleScope scope(isolate); | |
8171 DCHECK(args.length() == 3); | |
8172 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0) | |
8173 Object** parameters = reinterpret_cast<Object**>(args[1]); | |
8174 CONVERT_SMI_ARG_CHECKED(argument_count, 2); | |
8175 return *NewStrictArguments(isolate, callee, parameters, argument_count); | |
8176 } | |
8177 | |
8178 | |
8179 RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) { | |
8180 HandleScope scope(isolate); | |
8181 DCHECK(args.length() == 1); | |
8182 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0); | |
8183 Handle<Context> context(isolate->context()); | |
8184 PretenureFlag pretenure_flag = NOT_TENURED; | |
8185 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context, | |
8186 pretenure_flag); | |
8187 } | |
8188 | |
8189 | |
8190 RUNTIME_FUNCTION(Runtime_NewClosure) { | |
8191 HandleScope scope(isolate); | |
8192 DCHECK(args.length() == 3); | |
8193 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); | |
8194 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1); | |
8195 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2); | |
8196 | |
8197 // The caller ensures that we pretenure closures that are assigned | |
8198 // directly to properties. | |
8199 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; | |
8200 return *isolate->factory()->NewFunctionFromSharedFunctionInfo( | |
8201 shared, context, pretenure_flag); | |
8202 } | |
8203 | |
8204 | |
8205 // Find the arguments of the JavaScript function invocation that called | |
8206 // into C++ code. Collect these in a newly allocated array of handles (possibly | |
8207 // prefixed by a number of empty handles). | |
8208 static SmartArrayPointer<Handle<Object> > GetCallerArguments( | |
8209 Isolate* isolate, | |
8210 int prefix_argc, | |
8211 int* total_argc) { | |
8212 // Find frame containing arguments passed to the caller. | |
8213 JavaScriptFrameIterator it(isolate); | |
8214 JavaScriptFrame* frame = it.frame(); | |
8215 List<JSFunction*> functions(2); | |
8216 frame->GetFunctions(&functions); | |
8217 if (functions.length() > 1) { | |
8218 int inlined_jsframe_index = functions.length() - 1; | |
8219 JSFunction* inlined_function = functions[inlined_jsframe_index]; | |
8220 SlotRefValueBuilder slot_refs( | |
8221 frame, | |
8222 inlined_jsframe_index, | |
8223 inlined_function->shared()->formal_parameter_count()); | |
8224 | |
8225 int args_count = slot_refs.args_length(); | |
8226 | |
8227 *total_argc = prefix_argc + args_count; | |
8228 SmartArrayPointer<Handle<Object> > param_data( | |
8229 NewArray<Handle<Object> >(*total_argc)); | |
8230 slot_refs.Prepare(isolate); | |
8231 for (int i = 0; i < args_count; i++) { | |
8232 Handle<Object> val = slot_refs.GetNext(isolate, 0); | |
8233 param_data[prefix_argc + i] = val; | |
8234 } | |
8235 slot_refs.Finish(isolate); | |
8236 | |
8237 return param_data; | |
8238 } else { | |
8239 it.AdvanceToArgumentsFrame(); | |
8240 frame = it.frame(); | |
8241 int args_count = frame->ComputeParametersCount(); | |
8242 | |
8243 *total_argc = prefix_argc + args_count; | |
8244 SmartArrayPointer<Handle<Object> > param_data( | |
8245 NewArray<Handle<Object> >(*total_argc)); | |
8246 for (int i = 0; i < args_count; i++) { | |
8247 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate); | |
8248 param_data[prefix_argc + i] = val; | |
8249 } | |
8250 return param_data; | |
8251 } | |
8252 } | |
8253 | |
8254 | |
8255 RUNTIME_FUNCTION(Runtime_FunctionBindArguments) { | |
8256 HandleScope scope(isolate); | |
8257 DCHECK(args.length() == 4); | |
8258 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); | |
8259 CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1); | |
8260 CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2); | |
8261 CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3); | |
8262 | |
8263 // TODO(lrn): Create bound function in C++ code from premade shared info. | |
8264 bound_function->shared()->set_bound(true); | |
8265 // Get all arguments of calling function (Function.prototype.bind). | |
8266 int argc = 0; | |
8267 SmartArrayPointer<Handle<Object> > arguments = | |
8268 GetCallerArguments(isolate, 0, &argc); | |
8269 // Don't count the this-arg. | |
8270 if (argc > 0) { | |
8271 RUNTIME_ASSERT(arguments[0].is_identical_to(this_object)); | |
8272 argc--; | |
8273 } else { | |
8274 RUNTIME_ASSERT(this_object->IsUndefined()); | |
8275 } | |
8276 // Initialize array of bindings (function, this, and any existing arguments | |
8277 // if the function was already bound). | |
8278 Handle<FixedArray> new_bindings; | |
8279 int i; | |
8280 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { | |
8281 Handle<FixedArray> old_bindings( | |
8282 JSFunction::cast(*bindee)->function_bindings()); | |
8283 RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex); | |
8284 new_bindings = | |
8285 isolate->factory()->NewFixedArray(old_bindings->length() + argc); | |
8286 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex), | |
8287 isolate); | |
8288 i = 0; | |
8289 for (int n = old_bindings->length(); i < n; i++) { | |
8290 new_bindings->set(i, old_bindings->get(i)); | |
8291 } | |
8292 } else { | |
8293 int array_size = JSFunction::kBoundArgumentsStartIndex + argc; | |
8294 new_bindings = isolate->factory()->NewFixedArray(array_size); | |
8295 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); | |
8296 new_bindings->set(JSFunction::kBoundThisIndex, *this_object); | |
8297 i = 2; | |
8298 } | |
8299 // Copy arguments, skipping the first which is "this_arg". | |
8300 for (int j = 0; j < argc; j++, i++) { | |
8301 new_bindings->set(i, *arguments[j + 1]); | |
8302 } | |
8303 new_bindings->set_map_no_write_barrier( | |
8304 isolate->heap()->fixed_cow_array_map()); | |
8305 bound_function->set_function_bindings(*new_bindings); | |
8306 | |
8307 // Update length. Have to remove the prototype first so that map migration | |
8308 // is happy about the number of fields. | |
8309 RUNTIME_ASSERT(bound_function->RemovePrototype()); | |
8310 Handle<Map> bound_function_map( | |
8311 isolate->native_context()->bound_function_map()); | |
8312 JSObject::MigrateToMap(bound_function, bound_function_map); | |
8313 Handle<String> length_string = isolate->factory()->length_string(); | |
8314 PropertyAttributes attr = | |
8315 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); | |
8316 RETURN_FAILURE_ON_EXCEPTION( | |
8317 isolate, | |
8318 JSObject::SetOwnPropertyIgnoreAttributes( | |
8319 bound_function, length_string, new_length, attr)); | |
8320 return *bound_function; | |
8321 } | |
8322 | |
8323 | |
8324 RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) { | |
8325 HandleScope handles(isolate); | |
8326 DCHECK(args.length() == 1); | |
8327 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); | |
8328 if (callable->IsJSFunction()) { | |
8329 Handle<JSFunction> function = Handle<JSFunction>::cast(callable); | |
8330 if (function->shared()->bound()) { | |
8331 Handle<FixedArray> bindings(function->function_bindings()); | |
8332 RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); | |
8333 return *isolate->factory()->NewJSArrayWithElements(bindings); | |
8334 } | |
8335 } | |
8336 return isolate->heap()->undefined_value(); | |
8337 } | |
8338 | |
8339 | |
8340 RUNTIME_FUNCTION(Runtime_NewObjectFromBound) { | |
8341 HandleScope scope(isolate); | |
8342 DCHECK(args.length() == 1); | |
8343 // First argument is a function to use as a constructor. | |
8344 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8345 RUNTIME_ASSERT(function->shared()->bound()); | |
8346 | |
8347 // The argument is a bound function. Extract its bound arguments | |
8348 // and callable. | |
8349 Handle<FixedArray> bound_args = | |
8350 Handle<FixedArray>(FixedArray::cast(function->function_bindings())); | |
8351 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; | |
8352 Handle<Object> bound_function( | |
8353 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)), | |
8354 isolate); | |
8355 DCHECK(!bound_function->IsJSFunction() || | |
8356 !Handle<JSFunction>::cast(bound_function)->shared()->bound()); | |
8357 | |
8358 int total_argc = 0; | |
8359 SmartArrayPointer<Handle<Object> > param_data = | |
8360 GetCallerArguments(isolate, bound_argc, &total_argc); | |
8361 for (int i = 0; i < bound_argc; i++) { | |
8362 param_data[i] = Handle<Object>(bound_args->get( | |
8363 JSFunction::kBoundArgumentsStartIndex + i), isolate); | |
8364 } | |
8365 | |
8366 if (!bound_function->IsJSFunction()) { | |
8367 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
8368 isolate, bound_function, | |
8369 Execution::TryGetConstructorDelegate(isolate, bound_function)); | |
8370 } | |
8371 DCHECK(bound_function->IsJSFunction()); | |
8372 | |
8373 Handle<Object> result; | |
8374 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
8375 isolate, result, | |
8376 Execution::New(Handle<JSFunction>::cast(bound_function), | |
8377 total_argc, param_data.get())); | |
8378 return *result; | |
8379 } | |
8380 | |
8381 | |
8382 static Object* Runtime_NewObjectHelper(Isolate* isolate, | |
8383 Handle<Object> constructor, | |
8384 Handle<AllocationSite> site) { | |
8385 // If the constructor isn't a proper function we throw a type error. | |
8386 if (!constructor->IsJSFunction()) { | |
8387 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); | |
8388 THROW_NEW_ERROR_RETURN_FAILURE(isolate, | |
8389 NewTypeError("not_constructor", arguments)); | |
8390 } | |
8391 | |
8392 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); | |
8393 | |
8394 // If function should not have prototype, construction is not allowed. In this | |
8395 // case generated code bailouts here, since function has no initial_map. | |
8396 if (!function->should_have_prototype() && !function->shared()->bound()) { | |
8397 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); | |
8398 THROW_NEW_ERROR_RETURN_FAILURE(isolate, | |
8399 NewTypeError("not_constructor", arguments)); | |
8400 } | |
8401 | |
8402 Debug* debug = isolate->debug(); | |
8403 // Handle stepping into constructors if step into is active. | |
8404 if (debug->StepInActive()) { | |
8405 debug->HandleStepIn(function, Handle<Object>::null(), 0, true); | |
8406 } | |
8407 | |
8408 if (function->has_initial_map()) { | |
8409 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { | |
8410 // The 'Function' function ignores the receiver object when | |
8411 // called using 'new' and creates a new JSFunction object that | |
8412 // is returned. The receiver object is only used for error | |
8413 // reporting if an error occurs when constructing the new | |
8414 // JSFunction. Factory::NewJSObject() should not be used to | |
8415 // allocate JSFunctions since it does not properly initialize | |
8416 // the shared part of the function. Since the receiver is | |
8417 // ignored anyway, we use the global object as the receiver | |
8418 // instead of a new JSFunction object. This way, errors are | |
8419 // reported the same way whether or not 'Function' is called | |
8420 // using 'new'. | |
8421 return isolate->global_proxy(); | |
8422 } | |
8423 } | |
8424 | |
8425 // The function should be compiled for the optimization hints to be | |
8426 // available. | |
8427 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); | |
8428 | |
8429 Handle<JSObject> result; | |
8430 if (site.is_null()) { | |
8431 result = isolate->factory()->NewJSObject(function); | |
8432 } else { | |
8433 result = isolate->factory()->NewJSObjectWithMemento(function, site); | |
8434 } | |
8435 | |
8436 isolate->counters()->constructed_objects()->Increment(); | |
8437 isolate->counters()->constructed_objects_runtime()->Increment(); | |
8438 | |
8439 return *result; | |
8440 } | |
8441 | |
8442 | |
8443 RUNTIME_FUNCTION(Runtime_NewObject) { | |
8444 HandleScope scope(isolate); | |
8445 DCHECK(args.length() == 1); | |
8446 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0); | |
8447 return Runtime_NewObjectHelper(isolate, | |
8448 constructor, | |
8449 Handle<AllocationSite>::null()); | |
8450 } | |
8451 | |
8452 | |
8453 RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) { | |
8454 HandleScope scope(isolate); | |
8455 DCHECK(args.length() == 2); | |
8456 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1); | |
8457 CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0); | |
8458 Handle<AllocationSite> site; | |
8459 if (feedback->IsAllocationSite()) { | |
8460 // The feedback can be an AllocationSite or undefined. | |
8461 site = Handle<AllocationSite>::cast(feedback); | |
8462 } | |
8463 return Runtime_NewObjectHelper(isolate, constructor, site); | |
8464 } | |
8465 | |
8466 | |
8467 RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) { | |
8468 HandleScope scope(isolate); | |
8469 DCHECK(args.length() == 1); | |
8470 | |
8471 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8472 function->CompleteInobjectSlackTracking(); | |
8473 | |
8474 return isolate->heap()->undefined_value(); | |
8475 } | |
8476 | |
8477 | |
8478 RUNTIME_FUNCTION(Runtime_CompileLazy) { | |
8479 HandleScope scope(isolate); | |
8480 DCHECK(args.length() == 1); | |
8481 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8482 #ifdef DEBUG | |
8483 if (FLAG_trace_lazy && !function->shared()->is_compiled()) { | |
8484 PrintF("[unoptimized: "); | |
8485 function->PrintName(); | |
8486 PrintF("]\n"); | |
8487 } | |
8488 #endif | |
8489 | |
8490 // Compile the target function. | |
8491 DCHECK(function->shared()->allows_lazy_compilation()); | |
8492 | |
8493 Handle<Code> code; | |
8494 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code, | |
8495 Compiler::GetLazyCode(function)); | |
8496 DCHECK(code->kind() == Code::FUNCTION || | |
8497 code->kind() == Code::OPTIMIZED_FUNCTION); | |
8498 function->ReplaceCode(*code); | |
8499 return *code; | |
8500 } | |
8501 | |
8502 | |
8503 RUNTIME_FUNCTION(Runtime_CompileOptimized) { | |
8504 HandleScope scope(isolate); | |
8505 DCHECK(args.length() == 2); | |
8506 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8507 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1); | |
8508 | |
8509 Handle<Code> unoptimized(function->shared()->code()); | |
8510 if (!isolate->use_crankshaft() || | |
8511 function->shared()->optimization_disabled() || | |
8512 isolate->DebuggerHasBreakPoints()) { | |
8513 // If the function is not optimizable or debugger is active continue | |
8514 // using the code from the full compiler. | |
8515 if (FLAG_trace_opt) { | |
8516 PrintF("[failed to optimize "); | |
8517 function->PrintName(); | |
8518 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", | |
8519 function->shared()->optimization_disabled() ? "F" : "T", | |
8520 isolate->DebuggerHasBreakPoints() ? "T" : "F"); | |
8521 } | |
8522 function->ReplaceCode(*unoptimized); | |
8523 return function->code(); | |
8524 } | |
8525 | |
8526 Compiler::ConcurrencyMode mode = | |
8527 concurrent ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT; | |
8528 Handle<Code> code; | |
8529 if (Compiler::GetOptimizedCode(function, unoptimized, mode).ToHandle(&code)) { | |
8530 function->ReplaceCode(*code); | |
8531 } else { | |
8532 function->ReplaceCode(function->shared()->code()); | |
8533 } | |
8534 | |
8535 DCHECK(function->code()->kind() == Code::FUNCTION || | |
8536 function->code()->kind() == Code::OPTIMIZED_FUNCTION || | |
8537 function->IsInOptimizationQueue()); | |
8538 return function->code(); | |
8539 } | |
8540 | |
8541 | |
8542 class ActivationsFinder : public ThreadVisitor { | |
8543 public: | |
8544 Code* code_; | |
8545 bool has_code_activations_; | |
8546 | |
8547 explicit ActivationsFinder(Code* code) | |
8548 : code_(code), | |
8549 has_code_activations_(false) { } | |
8550 | |
8551 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | |
8552 JavaScriptFrameIterator it(isolate, top); | |
8553 VisitFrames(&it); | |
8554 } | |
8555 | |
8556 void VisitFrames(JavaScriptFrameIterator* it) { | |
8557 for (; !it->done(); it->Advance()) { | |
8558 JavaScriptFrame* frame = it->frame(); | |
8559 if (code_->contains(frame->pc())) has_code_activations_ = true; | |
8560 } | |
8561 } | |
8562 }; | |
8563 | |
8564 | |
8565 RUNTIME_FUNCTION(Runtime_NotifyStubFailure) { | |
8566 HandleScope scope(isolate); | |
8567 DCHECK(args.length() == 0); | |
8568 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); | |
8569 DCHECK(AllowHeapAllocation::IsAllowed()); | |
8570 delete deoptimizer; | |
8571 return isolate->heap()->undefined_value(); | |
8572 } | |
8573 | |
8574 | |
8575 RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) { | |
8576 HandleScope scope(isolate); | |
8577 DCHECK(args.length() == 1); | |
8578 CONVERT_SMI_ARG_CHECKED(type_arg, 0); | |
8579 Deoptimizer::BailoutType type = | |
8580 static_cast<Deoptimizer::BailoutType>(type_arg); | |
8581 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); | |
8582 DCHECK(AllowHeapAllocation::IsAllowed()); | |
8583 | |
8584 Handle<JSFunction> function = deoptimizer->function(); | |
8585 Handle<Code> optimized_code = deoptimizer->compiled_code(); | |
8586 | |
8587 DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION); | |
8588 DCHECK(type == deoptimizer->bailout_type()); | |
8589 | |
8590 // Make sure to materialize objects before causing any allocation. | |
8591 JavaScriptFrameIterator it(isolate); | |
8592 deoptimizer->MaterializeHeapObjects(&it); | |
8593 delete deoptimizer; | |
8594 | |
8595 JavaScriptFrame* frame = it.frame(); | |
8596 RUNTIME_ASSERT(frame->function()->IsJSFunction()); | |
8597 DCHECK(frame->function() == *function); | |
8598 | |
8599 // Avoid doing too much work when running with --always-opt and keep | |
8600 // the optimized code around. | |
8601 if (FLAG_always_opt || type == Deoptimizer::LAZY) { | |
8602 return isolate->heap()->undefined_value(); | |
8603 } | |
8604 | |
8605 // Search for other activations of the same function and code. | |
8606 ActivationsFinder activations_finder(*optimized_code); | |
8607 activations_finder.VisitFrames(&it); | |
8608 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); | |
8609 | |
8610 if (!activations_finder.has_code_activations_) { | |
8611 if (function->code() == *optimized_code) { | |
8612 if (FLAG_trace_deopt) { | |
8613 PrintF("[removing optimized code for: "); | |
8614 function->PrintName(); | |
8615 PrintF("]\n"); | |
8616 } | |
8617 function->ReplaceCode(function->shared()->code()); | |
8618 // Evict optimized code for this function from the cache so that it | |
8619 // doesn't get used for new closures. | |
8620 function->shared()->EvictFromOptimizedCodeMap(*optimized_code, | |
8621 "notify deoptimized"); | |
8622 } | |
8623 } else { | |
8624 // TODO(titzer): we should probably do DeoptimizeCodeList(code) | |
8625 // unconditionally if the code is not already marked for deoptimization. | |
8626 // If there is an index by shared function info, all the better. | |
8627 Deoptimizer::DeoptimizeFunction(*function); | |
8628 } | |
8629 | |
8630 return isolate->heap()->undefined_value(); | |
8631 } | |
8632 | |
8633 | |
8634 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { | |
8635 HandleScope scope(isolate); | |
8636 DCHECK(args.length() == 1); | |
8637 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8638 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); | |
8639 | |
8640 // TODO(turbofan): Deoptimization is not supported yet. | |
8641 if (function->code()->is_turbofanned() && !FLAG_turbo_deoptimization) { | |
8642 return isolate->heap()->undefined_value(); | |
8643 } | |
8644 | |
8645 Deoptimizer::DeoptimizeFunction(*function); | |
8646 | |
8647 return isolate->heap()->undefined_value(); | |
8648 } | |
8649 | |
8650 | |
8651 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) { | |
8652 HandleScope scope(isolate); | |
8653 DCHECK(args.length() == 1); | |
8654 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8655 function->shared()->ClearTypeFeedbackInfo(); | |
8656 Code* unoptimized = function->shared()->code(); | |
8657 if (unoptimized->kind() == Code::FUNCTION) { | |
8658 unoptimized->ClearInlineCaches(); | |
8659 } | |
8660 return isolate->heap()->undefined_value(); | |
8661 } | |
8662 | |
8663 | |
8664 RUNTIME_FUNCTION(Runtime_RunningInSimulator) { | |
8665 SealHandleScope shs(isolate); | |
8666 DCHECK(args.length() == 0); | |
8667 #if defined(USE_SIMULATOR) | |
8668 return isolate->heap()->true_value(); | |
8669 #else | |
8670 return isolate->heap()->false_value(); | |
8671 #endif | |
8672 } | |
8673 | |
8674 | |
8675 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { | |
8676 SealHandleScope shs(isolate); | |
8677 DCHECK(args.length() == 0); | |
8678 return isolate->heap()->ToBoolean( | |
8679 isolate->concurrent_recompilation_enabled()); | |
8680 } | |
8681 | |
8682 | |
8683 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { | |
8684 HandleScope scope(isolate); | |
8685 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); | |
8686 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8687 // The following two assertions are lifted from the DCHECKs inside | |
8688 // JSFunction::MarkForOptimization(). | |
8689 RUNTIME_ASSERT(!function->shared()->is_generator()); | |
8690 RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() || | |
8691 (function->code()->kind() == Code::FUNCTION && | |
8692 function->code()->optimizable())); | |
8693 | |
8694 // If the function is optimized, just return. | |
8695 if (function->IsOptimized()) return isolate->heap()->undefined_value(); | |
8696 | |
8697 function->MarkForOptimization(); | |
8698 | |
8699 Code* unoptimized = function->shared()->code(); | |
8700 if (args.length() == 2 && | |
8701 unoptimized->kind() == Code::FUNCTION) { | |
8702 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); | |
8703 if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("osr")) && FLAG_use_osr) { | |
8704 // Start patching from the currently patched loop nesting level. | |
8705 DCHECK(BackEdgeTable::Verify(isolate, unoptimized)); | |
8706 isolate->runtime_profiler()->AttemptOnStackReplacement( | |
8707 *function, Code::kMaxLoopNestingMarker); | |
8708 } else if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) && | |
8709 isolate->concurrent_recompilation_enabled()) { | |
8710 function->MarkForConcurrentOptimization(); | |
8711 } | |
8712 } | |
8713 | |
8714 return isolate->heap()->undefined_value(); | |
8715 } | |
8716 | |
8717 | |
8718 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { | |
8719 HandleScope scope(isolate); | |
8720 DCHECK(args.length() == 1); | |
8721 CONVERT_ARG_CHECKED(JSFunction, function, 0); | |
8722 function->shared()->set_optimization_disabled(true); | |
8723 return isolate->heap()->undefined_value(); | |
8724 } | |
8725 | |
8726 | |
8727 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) { | |
8728 HandleScope scope(isolate); | |
8729 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); | |
8730 if (!isolate->use_crankshaft()) { | |
8731 return Smi::FromInt(4); // 4 == "never". | |
8732 } | |
8733 bool sync_with_compiler_thread = true; | |
8734 if (args.length() == 2) { | |
8735 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1); | |
8736 if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) { | |
8737 sync_with_compiler_thread = false; | |
8738 } | |
8739 } | |
8740 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8741 if (isolate->concurrent_recompilation_enabled() && | |
8742 sync_with_compiler_thread) { | |
8743 while (function->IsInOptimizationQueue()) { | |
8744 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); | |
8745 base::OS::Sleep(50); | |
8746 } | |
8747 } | |
8748 if (FLAG_always_opt) { | |
8749 // We may have always opt, but that is more best-effort than a real | |
8750 // promise, so we still say "no" if it is not optimized. | |
8751 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always". | |
8752 : Smi::FromInt(2); // 2 == "no". | |
8753 } | |
8754 if (FLAG_deopt_every_n_times) { | |
8755 return Smi::FromInt(6); // 6 == "maybe deopted". | |
8756 } | |
8757 if (function->IsOptimized() && function->code()->is_turbofanned()) { | |
8758 return Smi::FromInt(7); // 7 == "TurboFan compiler". | |
8759 } | |
8760 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". | |
8761 : Smi::FromInt(2); // 2 == "no". | |
8762 } | |
8763 | |
8764 | |
8765 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) { | |
8766 DCHECK(args.length() == 0); | |
8767 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); | |
8768 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled()); | |
8769 isolate->optimizing_compiler_thread()->Unblock(); | |
8770 return isolate->heap()->undefined_value(); | |
8771 } | |
8772 | |
8773 | |
8774 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { | |
8775 HandleScope scope(isolate); | |
8776 DCHECK(args.length() == 1); | |
8777 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8778 return Smi::FromInt(function->shared()->opt_count()); | |
8779 } | |
8780 | |
8781 | |
8782 static bool IsSuitableForOnStackReplacement(Isolate* isolate, | |
8783 Handle<JSFunction> function, | |
8784 Handle<Code> current_code) { | |
8785 // Keep track of whether we've succeeded in optimizing. | |
8786 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false; | |
8787 // If we are trying to do OSR when there are already optimized | |
8788 // activations of the function, it means (a) the function is directly or | |
8789 // indirectly recursive and (b) an optimized invocation has been | |
8790 // deoptimized so that we are currently in an unoptimized activation. | |
8791 // Check for optimized activations of this function. | |
8792 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { | |
8793 JavaScriptFrame* frame = it.frame(); | |
8794 if (frame->is_optimized() && frame->function() == *function) return false; | |
8795 } | |
8796 | |
8797 return true; | |
8798 } | |
8799 | |
8800 | |
8801 RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) { | |
8802 HandleScope scope(isolate); | |
8803 DCHECK(args.length() == 1); | |
8804 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
8805 Handle<Code> caller_code(function->shared()->code()); | |
8806 | |
8807 // We're not prepared to handle a function with arguments object. | |
8808 DCHECK(!function->shared()->uses_arguments()); | |
8809 | |
8810 RUNTIME_ASSERT(FLAG_use_osr); | |
8811 | |
8812 // Passing the PC in the javascript frame from the caller directly is | |
8813 // not GC safe, so we walk the stack to get it. | |
8814 JavaScriptFrameIterator it(isolate); | |
8815 JavaScriptFrame* frame = it.frame(); | |
8816 if (!caller_code->contains(frame->pc())) { | |
8817 // Code on the stack may not be the code object referenced by the shared | |
8818 // function info. It may have been replaced to include deoptimization data. | |
8819 caller_code = Handle<Code>(frame->LookupCode()); | |
8820 } | |
8821 | |
8822 uint32_t pc_offset = static_cast<uint32_t>( | |
8823 frame->pc() - caller_code->instruction_start()); | |
8824 | |
8825 #ifdef DEBUG | |
8826 DCHECK_EQ(frame->function(), *function); | |
8827 DCHECK_EQ(frame->LookupCode(), *caller_code); | |
8828 DCHECK(caller_code->contains(frame->pc())); | |
8829 #endif // DEBUG | |
8830 | |
8831 | |
8832 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset); | |
8833 DCHECK(!ast_id.IsNone()); | |
8834 | |
8835 Compiler::ConcurrencyMode mode = | |
8836 isolate->concurrent_osr_enabled() && | |
8837 (function->shared()->ast_node_count() > 512) ? Compiler::CONCURRENT | |
8838 : Compiler::NOT_CONCURRENT; | |
8839 Handle<Code> result = Handle<Code>::null(); | |
8840 | |
8841 OptimizedCompileJob* job = NULL; | |
8842 if (mode == Compiler::CONCURRENT) { | |
8843 // Gate the OSR entry with a stack check. | |
8844 BackEdgeTable::AddStackCheck(caller_code, pc_offset); | |
8845 // Poll already queued compilation jobs. | |
8846 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread(); | |
8847 if (thread->IsQueuedForOSR(function, ast_id)) { | |
8848 if (FLAG_trace_osr) { | |
8849 PrintF("[OSR - Still waiting for queued: "); | |
8850 function->PrintName(); | |
8851 PrintF(" at AST id %d]\n", ast_id.ToInt()); | |
8852 } | |
8853 return NULL; | |
8854 } | |
8855 | |
8856 job = thread->FindReadyOSRCandidate(function, ast_id); | |
8857 } | |
8858 | |
8859 if (job != NULL) { | |
8860 if (FLAG_trace_osr) { | |
8861 PrintF("[OSR - Found ready: "); | |
8862 function->PrintName(); | |
8863 PrintF(" at AST id %d]\n", ast_id.ToInt()); | |
8864 } | |
8865 result = Compiler::GetConcurrentlyOptimizedCode(job); | |
8866 } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) { | |
8867 if (FLAG_trace_osr) { | |
8868 PrintF("[OSR - Compiling: "); | |
8869 function->PrintName(); | |
8870 PrintF(" at AST id %d]\n", ast_id.ToInt()); | |
8871 } | |
8872 MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode( | |
8873 function, caller_code, mode, ast_id); | |
8874 if (maybe_result.ToHandle(&result) && | |
8875 result.is_identical_to(isolate->builtins()->InOptimizationQueue())) { | |
8876 // Optimization is queued. Return to check later. | |
8877 return NULL; | |
8878 } | |
8879 } | |
8880 | |
8881 // Revert the patched back edge table, regardless of whether OSR succeeds. | |
8882 BackEdgeTable::Revert(isolate, *caller_code); | |
8883 | |
8884 // Check whether we ended up with usable optimized code. | |
8885 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) { | |
8886 DeoptimizationInputData* data = | |
8887 DeoptimizationInputData::cast(result->deoptimization_data()); | |
8888 | |
8889 if (data->OsrPcOffset()->value() >= 0) { | |
8890 DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id); | |
8891 if (FLAG_trace_osr) { | |
8892 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n", | |
8893 ast_id.ToInt(), data->OsrPcOffset()->value()); | |
8894 } | |
8895 // TODO(titzer): this is a massive hack to make the deopt counts | |
8896 // match. Fix heuristics for reenabling optimizations! | |
8897 function->shared()->increment_deopt_count(); | |
8898 | |
8899 // TODO(titzer): Do not install code into the function. | |
8900 function->ReplaceCode(*result); | |
8901 return *result; | |
8902 } | |
8903 } | |
8904 | |
8905 // Failed. | |
8906 if (FLAG_trace_osr) { | |
8907 PrintF("[OSR - Failed: "); | |
8908 function->PrintName(); | |
8909 PrintF(" at AST id %d]\n", ast_id.ToInt()); | |
8910 } | |
8911 | |
8912 if (!function->IsOptimized()) { | |
8913 function->ReplaceCode(function->shared()->code()); | |
8914 } | |
8915 return NULL; | |
8916 } | |
8917 | |
8918 | |
8919 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) { | |
8920 SealHandleScope shs(isolate); | |
8921 DCHECK(args.length() == 2 || args.length() == 3); | |
8922 #ifdef DEBUG | |
8923 CONVERT_SMI_ARG_CHECKED(interval, 0); | |
8924 CONVERT_SMI_ARG_CHECKED(timeout, 1); | |
8925 isolate->heap()->set_allocation_timeout(timeout); | |
8926 FLAG_gc_interval = interval; | |
8927 if (args.length() == 3) { | |
8928 // Enable/disable inline allocation if requested. | |
8929 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2); | |
8930 if (inline_allocation) { | |
8931 isolate->heap()->EnableInlineAllocation(); | |
8932 } else { | |
8933 isolate->heap()->DisableInlineAllocation(); | |
8934 } | |
8935 } | |
8936 #endif | |
8937 return isolate->heap()->undefined_value(); | |
8938 } | |
8939 | |
8940 | |
8941 RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) { | |
8942 SealHandleScope shs(isolate); | |
8943 DCHECK(args.length() == 0); | |
8944 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); | |
8945 return isolate->heap()->undefined_value(); | |
8946 } | |
8947 | |
8948 | |
8949 RUNTIME_FUNCTION(Runtime_GetRootNaN) { | |
8950 SealHandleScope shs(isolate); | |
8951 DCHECK(args.length() == 0); | |
8952 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); | |
8953 return isolate->heap()->nan_value(); | |
8954 } | |
8955 | |
8956 | |
8957 RUNTIME_FUNCTION(Runtime_Call) { | |
8958 HandleScope scope(isolate); | |
8959 DCHECK(args.length() >= 2); | |
8960 int argc = args.length() - 2; | |
8961 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1); | |
8962 Object* receiver = args[0]; | |
8963 | |
8964 // If there are too many arguments, allocate argv via malloc. | |
8965 const int argv_small_size = 10; | |
8966 Handle<Object> argv_small_buffer[argv_small_size]; | |
8967 SmartArrayPointer<Handle<Object> > argv_large_buffer; | |
8968 Handle<Object>* argv = argv_small_buffer; | |
8969 if (argc > argv_small_size) { | |
8970 argv = new Handle<Object>[argc]; | |
8971 if (argv == NULL) return isolate->StackOverflow(); | |
8972 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); | |
8973 } | |
8974 | |
8975 for (int i = 0; i < argc; ++i) { | |
8976 argv[i] = Handle<Object>(args[1 + i], isolate); | |
8977 } | |
8978 | |
8979 Handle<JSReceiver> hfun(fun); | |
8980 Handle<Object> hreceiver(receiver, isolate); | |
8981 Handle<Object> result; | |
8982 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
8983 isolate, result, | |
8984 Execution::Call(isolate, hfun, hreceiver, argc, argv, true)); | |
8985 return *result; | |
8986 } | |
8987 | |
8988 | |
8989 RUNTIME_FUNCTION(Runtime_Apply) { | |
8990 HandleScope scope(isolate); | |
8991 DCHECK(args.length() == 5); | |
8992 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); | |
8993 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); | |
8994 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); | |
8995 CONVERT_INT32_ARG_CHECKED(offset, 3); | |
8996 CONVERT_INT32_ARG_CHECKED(argc, 4); | |
8997 RUNTIME_ASSERT(offset >= 0); | |
8998 // Loose upper bound to allow fuzzing. We'll most likely run out of | |
8999 // stack space before hitting this limit. | |
9000 static int kMaxArgc = 1000000; | |
9001 RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc); | |
9002 | |
9003 // If there are too many arguments, allocate argv via malloc. | |
9004 const int argv_small_size = 10; | |
9005 Handle<Object> argv_small_buffer[argv_small_size]; | |
9006 SmartArrayPointer<Handle<Object> > argv_large_buffer; | |
9007 Handle<Object>* argv = argv_small_buffer; | |
9008 if (argc > argv_small_size) { | |
9009 argv = new Handle<Object>[argc]; | |
9010 if (argv == NULL) return isolate->StackOverflow(); | |
9011 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); | |
9012 } | |
9013 | |
9014 for (int i = 0; i < argc; ++i) { | |
9015 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
9016 isolate, argv[i], | |
9017 Object::GetElement(isolate, arguments, offset + i)); | |
9018 } | |
9019 | |
9020 Handle<Object> result; | |
9021 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
9022 isolate, result, | |
9023 Execution::Call(isolate, fun, receiver, argc, argv, true)); | |
9024 return *result; | |
9025 } | |
9026 | |
9027 | |
9028 RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) { | |
9029 HandleScope scope(isolate); | |
9030 DCHECK(args.length() == 1); | |
9031 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
9032 RUNTIME_ASSERT(!object->IsJSFunction()); | |
9033 return *Execution::GetFunctionDelegate(isolate, object); | |
9034 } | |
9035 | |
9036 | |
9037 RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) { | |
9038 HandleScope scope(isolate); | |
9039 DCHECK(args.length() == 1); | |
9040 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
9041 RUNTIME_ASSERT(!object->IsJSFunction()); | |
9042 return *Execution::GetConstructorDelegate(isolate, object); | |
9043 } | |
9044 | |
9045 | |
9046 RUNTIME_FUNCTION(Runtime_NewGlobalContext) { | |
9047 HandleScope scope(isolate); | |
9048 DCHECK(args.length() == 2); | |
9049 | |
9050 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
9051 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); | |
9052 Handle<Context> result = | |
9053 isolate->factory()->NewGlobalContext(function, scope_info); | |
9054 | |
9055 DCHECK(function->context() == isolate->context()); | |
9056 DCHECK(function->context()->global_object() == result->global_object()); | |
9057 result->global_object()->set_global_context(*result); | |
9058 return *result; | |
9059 } | |
9060 | |
9061 | |
9062 RUNTIME_FUNCTION(Runtime_NewFunctionContext) { | |
9063 HandleScope scope(isolate); | |
9064 DCHECK(args.length() == 1); | |
9065 | |
9066 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
9067 | |
9068 DCHECK(function->context() == isolate->context()); | |
9069 int length = function->shared()->scope_info()->ContextLength(); | |
9070 return *isolate->factory()->NewFunctionContext(length, function); | |
9071 } | |
9072 | |
9073 | |
9074 RUNTIME_FUNCTION(Runtime_PushWithContext) { | |
9075 HandleScope scope(isolate); | |
9076 DCHECK(args.length() == 2); | |
9077 Handle<JSReceiver> extension_object; | |
9078 if (args[0]->IsJSReceiver()) { | |
9079 extension_object = args.at<JSReceiver>(0); | |
9080 } else { | |
9081 // Try to convert the object to a proper JavaScript object. | |
9082 MaybeHandle<JSReceiver> maybe_object = | |
9083 Object::ToObject(isolate, args.at<Object>(0)); | |
9084 if (!maybe_object.ToHandle(&extension_object)) { | |
9085 Handle<Object> handle = args.at<Object>(0); | |
9086 THROW_NEW_ERROR_RETURN_FAILURE( | |
9087 isolate, NewTypeError("with_expression", HandleVector(&handle, 1))); | |
9088 } | |
9089 } | |
9090 | |
9091 Handle<JSFunction> function; | |
9092 if (args[1]->IsSmi()) { | |
9093 // A smi sentinel indicates a context nested inside global code rather | |
9094 // than some function. There is a canonical empty function that can be | |
9095 // gotten from the native context. | |
9096 function = handle(isolate->native_context()->closure()); | |
9097 } else { | |
9098 function = args.at<JSFunction>(1); | |
9099 } | |
9100 | |
9101 Handle<Context> current(isolate->context()); | |
9102 Handle<Context> context = isolate->factory()->NewWithContext( | |
9103 function, current, extension_object); | |
9104 isolate->set_context(*context); | |
9105 return *context; | |
9106 } | |
9107 | |
9108 | |
9109 RUNTIME_FUNCTION(Runtime_PushCatchContext) { | |
9110 HandleScope scope(isolate); | |
9111 DCHECK(args.length() == 3); | |
9112 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
9113 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1); | |
9114 Handle<JSFunction> function; | |
9115 if (args[2]->IsSmi()) { | |
9116 // A smi sentinel indicates a context nested inside global code rather | |
9117 // than some function. There is a canonical empty function that can be | |
9118 // gotten from the native context. | |
9119 function = handle(isolate->native_context()->closure()); | |
9120 } else { | |
9121 function = args.at<JSFunction>(2); | |
9122 } | |
9123 Handle<Context> current(isolate->context()); | |
9124 Handle<Context> context = isolate->factory()->NewCatchContext( | |
9125 function, current, name, thrown_object); | |
9126 isolate->set_context(*context); | |
9127 return *context; | |
9128 } | |
9129 | |
9130 | |
9131 RUNTIME_FUNCTION(Runtime_PushBlockContext) { | |
9132 HandleScope scope(isolate); | |
9133 DCHECK(args.length() == 2); | |
9134 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0); | |
9135 Handle<JSFunction> function; | |
9136 if (args[1]->IsSmi()) { | |
9137 // A smi sentinel indicates a context nested inside global code rather | |
9138 // than some function. There is a canonical empty function that can be | |
9139 // gotten from the native context. | |
9140 function = handle(isolate->native_context()->closure()); | |
9141 } else { | |
9142 function = args.at<JSFunction>(1); | |
9143 } | |
9144 Handle<Context> current(isolate->context()); | |
9145 Handle<Context> context = isolate->factory()->NewBlockContext( | |
9146 function, current, scope_info); | |
9147 isolate->set_context(*context); | |
9148 return *context; | |
9149 } | |
9150 | |
9151 | |
9152 RUNTIME_FUNCTION(Runtime_IsJSModule) { | |
9153 SealHandleScope shs(isolate); | |
9154 DCHECK(args.length() == 1); | |
9155 CONVERT_ARG_CHECKED(Object, obj, 0); | |
9156 return isolate->heap()->ToBoolean(obj->IsJSModule()); | |
9157 } | |
9158 | |
9159 | |
9160 RUNTIME_FUNCTION(Runtime_PushModuleContext) { | |
9161 SealHandleScope shs(isolate); | |
9162 DCHECK(args.length() == 2); | |
9163 CONVERT_SMI_ARG_CHECKED(index, 0); | |
9164 | |
9165 if (!args[1]->IsScopeInfo()) { | |
9166 // Module already initialized. Find hosting context and retrieve context. | |
9167 Context* host = Context::cast(isolate->context())->global_context(); | |
9168 Context* context = Context::cast(host->get(index)); | |
9169 DCHECK(context->previous() == isolate->context()); | |
9170 isolate->set_context(context); | |
9171 return context; | |
9172 } | |
9173 | |
9174 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); | |
9175 | |
9176 // Allocate module context. | |
9177 HandleScope scope(isolate); | |
9178 Factory* factory = isolate->factory(); | |
9179 Handle<Context> context = factory->NewModuleContext(scope_info); | |
9180 Handle<JSModule> module = factory->NewJSModule(context, scope_info); | |
9181 context->set_module(*module); | |
9182 Context* previous = isolate->context(); | |
9183 context->set_previous(previous); | |
9184 context->set_closure(previous->closure()); | |
9185 context->set_global_object(previous->global_object()); | |
9186 isolate->set_context(*context); | |
9187 | |
9188 // Find hosting scope and initialize internal variable holding module there. | |
9189 previous->global_context()->set(index, *context); | |
9190 | |
9191 return *context; | |
9192 } | |
9193 | |
9194 | |
9195 RUNTIME_FUNCTION(Runtime_DeclareModules) { | |
9196 HandleScope scope(isolate); | |
9197 DCHECK(args.length() == 1); | |
9198 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); | |
9199 Context* host_context = isolate->context(); | |
9200 | |
9201 for (int i = 0; i < descriptions->length(); ++i) { | |
9202 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i))); | |
9203 int host_index = description->host_index(); | |
9204 Handle<Context> context(Context::cast(host_context->get(host_index))); | |
9205 Handle<JSModule> module(context->module()); | |
9206 | |
9207 for (int j = 0; j < description->length(); ++j) { | |
9208 Handle<String> name(description->name(j)); | |
9209 VariableMode mode = description->mode(j); | |
9210 int index = description->index(j); | |
9211 switch (mode) { | |
9212 case VAR: | |
9213 case LET: | |
9214 case CONST: | |
9215 case CONST_LEGACY: { | |
9216 PropertyAttributes attr = | |
9217 IsImmutableVariableMode(mode) ? FROZEN : SEALED; | |
9218 Handle<AccessorInfo> info = | |
9219 Accessors::MakeModuleExport(name, index, attr); | |
9220 Handle<Object> result = | |
9221 JSObject::SetAccessor(module, info).ToHandleChecked(); | |
9222 DCHECK(!result->IsUndefined()); | |
9223 USE(result); | |
9224 break; | |
9225 } | |
9226 case MODULE: { | |
9227 Object* referenced_context = Context::cast(host_context)->get(index); | |
9228 Handle<JSModule> value(Context::cast(referenced_context)->module()); | |
9229 JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN) | |
9230 .Assert(); | |
9231 break; | |
9232 } | |
9233 case INTERNAL: | |
9234 case TEMPORARY: | |
9235 case DYNAMIC: | |
9236 case DYNAMIC_GLOBAL: | |
9237 case DYNAMIC_LOCAL: | |
9238 UNREACHABLE(); | |
9239 } | |
9240 } | |
9241 | |
9242 JSObject::PreventExtensions(module).Assert(); | |
9243 } | |
9244 | |
9245 DCHECK(!isolate->has_pending_exception()); | |
9246 return isolate->heap()->undefined_value(); | |
9247 } | |
9248 | |
9249 | |
9250 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) { | |
9251 HandleScope scope(isolate); | |
9252 DCHECK(args.length() == 2); | |
9253 | |
9254 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); | |
9255 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); | |
9256 | |
9257 int index; | |
9258 PropertyAttributes attributes; | |
9259 ContextLookupFlags flags = FOLLOW_CHAINS; | |
9260 BindingFlags binding_flags; | |
9261 Handle<Object> holder = context->Lookup(name, | |
9262 flags, | |
9263 &index, | |
9264 &attributes, | |
9265 &binding_flags); | |
9266 | |
9267 // If the slot was not found the result is true. | |
9268 if (holder.is_null()) { | |
9269 return isolate->heap()->true_value(); | |
9270 } | |
9271 | |
9272 // If the slot was found in a context, it should be DONT_DELETE. | |
9273 if (holder->IsContext()) { | |
9274 return isolate->heap()->false_value(); | |
9275 } | |
9276 | |
9277 // The slot was found in a JSObject, either a context extension object, | |
9278 // the global object, or the subject of a with. Try to delete it | |
9279 // (respecting DONT_DELETE). | |
9280 Handle<JSObject> object = Handle<JSObject>::cast(holder); | |
9281 Handle<Object> result; | |
9282 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
9283 isolate, result, | |
9284 JSReceiver::DeleteProperty(object, name)); | |
9285 return *result; | |
9286 } | |
9287 | |
9288 | |
9289 // A mechanism to return a pair of Object pointers in registers (if possible). | |
9290 // How this is achieved is calling convention-dependent. | |
9291 // All currently supported x86 compiles uses calling conventions that are cdecl | |
9292 // variants where a 64-bit value is returned in two 32-bit registers | |
9293 // (edx:eax on ia32, r1:r0 on ARM). | |
9294 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. | |
9295 // In Win64 calling convention, a struct of two pointers is returned in memory, | |
9296 // allocated by the caller, and passed as a pointer in a hidden first parameter. | |
9297 #ifdef V8_HOST_ARCH_64_BIT | |
9298 struct ObjectPair { | |
9299 Object* x; | |
9300 Object* y; | |
9301 }; | |
9302 | |
9303 | |
9304 static inline ObjectPair MakePair(Object* x, Object* y) { | |
9305 ObjectPair result = {x, y}; | |
9306 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. | |
9307 // In Win64 they are assigned to a hidden first argument. | |
9308 return result; | |
9309 } | |
9310 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT | |
9311 // For x32 a 128-bit struct return is done as rax and rdx from the ObjectPair | |
9312 // are used in the full codegen and Crankshaft compiler. An alternative is | |
9313 // using uint64_t and modifying full codegen and Crankshaft compiler. | |
9314 struct ObjectPair { | |
9315 Object* x; | |
9316 uint32_t x_upper; | |
9317 Object* y; | |
9318 uint32_t y_upper; | |
9319 }; | |
9320 | |
9321 | |
9322 static inline ObjectPair MakePair(Object* x, Object* y) { | |
9323 ObjectPair result = {x, 0, y, 0}; | |
9324 // Pointers x and y returned in rax and rdx, in x32-abi. | |
9325 return result; | |
9326 } | |
9327 #else | |
9328 typedef uint64_t ObjectPair; | |
9329 static inline ObjectPair MakePair(Object* x, Object* y) { | |
9330 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
9331 return reinterpret_cast<uint32_t>(x) | | |
9332 (reinterpret_cast<ObjectPair>(y) << 32); | |
9333 #elif defined(V8_TARGET_BIG_ENDIAN) | |
9334 return reinterpret_cast<uint32_t>(y) | | |
9335 (reinterpret_cast<ObjectPair>(x) << 32); | |
9336 #else | |
9337 #error Unknown endianness | |
9338 #endif | |
9339 } | |
9340 #endif | |
9341 | |
9342 | |
9343 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, | |
9344 JSObject* holder) { | |
9345 DCHECK(!holder->IsGlobalObject()); | |
9346 Context* top = isolate->context(); | |
9347 // Get the context extension function. | |
9348 JSFunction* context_extension_function = | |
9349 top->native_context()->context_extension_function(); | |
9350 // If the holder isn't a context extension object, we just return it | |
9351 // as the receiver. This allows arguments objects to be used as | |
9352 // receivers, but only if they are put in the context scope chain | |
9353 // explicitly via a with-statement. | |
9354 Object* constructor = holder->map()->constructor(); | |
9355 if (constructor != context_extension_function) return holder; | |
9356 // Fall back to using the global object as the implicit receiver if | |
9357 // the property turns out to be a local variable allocated in a | |
9358 // context extension object - introduced via eval. | |
9359 return isolate->heap()->undefined_value(); | |
9360 } | |
9361 | |
9362 | |
9363 static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate, | |
9364 bool throw_error) { | |
9365 HandleScope scope(isolate); | |
9366 DCHECK_EQ(2, args.length()); | |
9367 | |
9368 if (!args[0]->IsContext() || !args[1]->IsString()) { | |
9369 return MakePair(isolate->ThrowIllegalOperation(), NULL); | |
9370 } | |
9371 Handle<Context> context = args.at<Context>(0); | |
9372 Handle<String> name = args.at<String>(1); | |
9373 | |
9374 int index; | |
9375 PropertyAttributes attributes; | |
9376 ContextLookupFlags flags = FOLLOW_CHAINS; | |
9377 BindingFlags binding_flags; | |
9378 Handle<Object> holder = context->Lookup(name, | |
9379 flags, | |
9380 &index, | |
9381 &attributes, | |
9382 &binding_flags); | |
9383 if (isolate->has_pending_exception()) { | |
9384 return MakePair(isolate->heap()->exception(), NULL); | |
9385 } | |
9386 | |
9387 // If the index is non-negative, the slot has been found in a context. | |
9388 if (index >= 0) { | |
9389 DCHECK(holder->IsContext()); | |
9390 // If the "property" we were looking for is a local variable, the | |
9391 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. | |
9392 Handle<Object> receiver = isolate->factory()->undefined_value(); | |
9393 Object* value = Context::cast(*holder)->get(index); | |
9394 // Check for uninitialized bindings. | |
9395 switch (binding_flags) { | |
9396 case MUTABLE_CHECK_INITIALIZED: | |
9397 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: | |
9398 if (value->IsTheHole()) { | |
9399 Handle<Object> error; | |
9400 MaybeHandle<Object> maybe_error = | |
9401 isolate->factory()->NewReferenceError("not_defined", | |
9402 HandleVector(&name, 1)); | |
9403 if (maybe_error.ToHandle(&error)) isolate->Throw(*error); | |
9404 return MakePair(isolate->heap()->exception(), NULL); | |
9405 } | |
9406 // FALLTHROUGH | |
9407 case MUTABLE_IS_INITIALIZED: | |
9408 case IMMUTABLE_IS_INITIALIZED: | |
9409 case IMMUTABLE_IS_INITIALIZED_HARMONY: | |
9410 DCHECK(!value->IsTheHole()); | |
9411 return MakePair(value, *receiver); | |
9412 case IMMUTABLE_CHECK_INITIALIZED: | |
9413 if (value->IsTheHole()) { | |
9414 DCHECK((attributes & READ_ONLY) != 0); | |
9415 value = isolate->heap()->undefined_value(); | |
9416 } | |
9417 return MakePair(value, *receiver); | |
9418 case MISSING_BINDING: | |
9419 UNREACHABLE(); | |
9420 return MakePair(NULL, NULL); | |
9421 } | |
9422 } | |
9423 | |
9424 // Otherwise, if the slot was found the holder is a context extension | |
9425 // object, subject of a with, or a global object. We read the named | |
9426 // property from it. | |
9427 if (!holder.is_null()) { | |
9428 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); | |
9429 #ifdef DEBUG | |
9430 if (!object->IsJSProxy()) { | |
9431 Maybe<bool> maybe = JSReceiver::HasProperty(object, name); | |
9432 DCHECK(maybe.has_value); | |
9433 DCHECK(maybe.value); | |
9434 } | |
9435 #endif | |
9436 // GetProperty below can cause GC. | |
9437 Handle<Object> receiver_handle( | |
9438 object->IsGlobalObject() | |
9439 ? Object::cast(isolate->heap()->undefined_value()) | |
9440 : object->IsJSProxy() ? static_cast<Object*>(*object) | |
9441 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)), | |
9442 isolate); | |
9443 | |
9444 // No need to unhole the value here. This is taken care of by the | |
9445 // GetProperty function. | |
9446 Handle<Object> value; | |
9447 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
9448 isolate, value, | |
9449 Object::GetProperty(object, name), | |
9450 MakePair(isolate->heap()->exception(), NULL)); | |
9451 return MakePair(*value, *receiver_handle); | |
9452 } | |
9453 | |
9454 if (throw_error) { | |
9455 // The property doesn't exist - throw exception. | |
9456 Handle<Object> error; | |
9457 MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError( | |
9458 "not_defined", HandleVector(&name, 1)); | |
9459 if (maybe_error.ToHandle(&error)) isolate->Throw(*error); | |
9460 return MakePair(isolate->heap()->exception(), NULL); | |
9461 } else { | |
9462 // The property doesn't exist - return undefined. | |
9463 return MakePair(isolate->heap()->undefined_value(), | |
9464 isolate->heap()->undefined_value()); | |
9465 } | |
9466 } | |
9467 | |
9468 | |
9469 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) { | |
9470 return LoadLookupSlotHelper(args, isolate, true); | |
9471 } | |
9472 | |
9473 | |
9474 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) { | |
9475 return LoadLookupSlotHelper(args, isolate, false); | |
9476 } | |
9477 | |
9478 | |
9479 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) { | |
9480 HandleScope scope(isolate); | |
9481 DCHECK(args.length() == 4); | |
9482 | |
9483 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); | |
9484 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); | |
9485 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); | |
9486 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3); | |
9487 | |
9488 int index; | |
9489 PropertyAttributes attributes; | |
9490 ContextLookupFlags flags = FOLLOW_CHAINS; | |
9491 BindingFlags binding_flags; | |
9492 Handle<Object> holder = context->Lookup(name, | |
9493 flags, | |
9494 &index, | |
9495 &attributes, | |
9496 &binding_flags); | |
9497 // In case of JSProxy, an exception might have been thrown. | |
9498 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | |
9499 | |
9500 // The property was found in a context slot. | |
9501 if (index >= 0) { | |
9502 if ((attributes & READ_ONLY) == 0) { | |
9503 Handle<Context>::cast(holder)->set(index, *value); | |
9504 } else if (strict_mode == STRICT) { | |
9505 // Setting read only property in strict mode. | |
9506 THROW_NEW_ERROR_RETURN_FAILURE( | |
9507 isolate, | |
9508 NewTypeError("strict_cannot_assign", HandleVector(&name, 1))); | |
9509 } | |
9510 return *value; | |
9511 } | |
9512 | |
9513 // Slow case: The property is not in a context slot. It is either in a | |
9514 // context extension object, a property of the subject of a with, or a | |
9515 // property of the global object. | |
9516 Handle<JSReceiver> object; | |
9517 if (attributes != ABSENT) { | |
9518 // The property exists on the holder. | |
9519 object = Handle<JSReceiver>::cast(holder); | |
9520 } else if (strict_mode == STRICT) { | |
9521 // If absent in strict mode: throw. | |
9522 THROW_NEW_ERROR_RETURN_FAILURE( | |
9523 isolate, NewReferenceError("not_defined", HandleVector(&name, 1))); | |
9524 } else { | |
9525 // If absent in sloppy mode: add the property to the global object. | |
9526 object = Handle<JSReceiver>(context->global_object()); | |
9527 } | |
9528 | |
9529 RETURN_FAILURE_ON_EXCEPTION( | |
9530 isolate, Object::SetProperty(object, name, value, strict_mode)); | |
9531 | |
9532 return *value; | |
9533 } | |
9534 | |
9535 | |
9536 RUNTIME_FUNCTION(Runtime_Throw) { | |
9537 HandleScope scope(isolate); | |
9538 DCHECK(args.length() == 1); | |
9539 | |
9540 return isolate->Throw(args[0]); | |
9541 } | |
9542 | |
9543 | |
9544 RUNTIME_FUNCTION(Runtime_ReThrow) { | |
9545 HandleScope scope(isolate); | |
9546 DCHECK(args.length() == 1); | |
9547 | |
9548 return isolate->ReThrow(args[0]); | |
9549 } | |
9550 | |
9551 | |
9552 RUNTIME_FUNCTION(Runtime_PromoteScheduledException) { | |
9553 SealHandleScope shs(isolate); | |
9554 DCHECK(args.length() == 0); | |
9555 return isolate->PromoteScheduledException(); | |
9556 } | |
9557 | |
9558 | |
9559 RUNTIME_FUNCTION(Runtime_ThrowReferenceError) { | |
9560 HandleScope scope(isolate); | |
9561 DCHECK(args.length() == 1); | |
9562 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); | |
9563 THROW_NEW_ERROR_RETURN_FAILURE( | |
9564 isolate, NewReferenceError("not_defined", HandleVector(&name, 1))); | |
9565 } | |
9566 | |
9567 | |
9568 RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) { | |
9569 HandleScope scope(isolate); | |
9570 DCHECK(args.length() == 0); | |
9571 THROW_NEW_ERROR_RETURN_FAILURE( | |
9572 isolate, NewReferenceError("non_method", HandleVector<Object>(NULL, 0))); | |
9573 } | |
9574 | |
9575 | |
9576 RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) { | |
9577 HandleScope scope(isolate); | |
9578 DCHECK(args.length() == 0); | |
9579 THROW_NEW_ERROR_RETURN_FAILURE( | |
9580 isolate, | |
9581 NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0))); | |
9582 } | |
9583 | |
9584 | |
9585 RUNTIME_FUNCTION(Runtime_ThrowNotDateError) { | |
9586 HandleScope scope(isolate); | |
9587 DCHECK(args.length() == 0); | |
9588 THROW_NEW_ERROR_RETURN_FAILURE( | |
9589 isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | |
9590 } | |
9591 | |
9592 | |
9593 RUNTIME_FUNCTION(Runtime_StackGuard) { | |
9594 SealHandleScope shs(isolate); | |
9595 DCHECK(args.length() == 0); | |
9596 | |
9597 // First check if this is a real stack overflow. | |
9598 StackLimitCheck check(isolate); | |
9599 if (check.JsHasOverflowed()) { | |
9600 return isolate->StackOverflow(); | |
9601 } | |
9602 | |
9603 return isolate->stack_guard()->HandleInterrupts(); | |
9604 } | |
9605 | |
9606 | |
9607 RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) { | |
9608 HandleScope scope(isolate); | |
9609 DCHECK(args.length() == 1); | |
9610 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
9611 | |
9612 // First check if this is a real stack overflow. | |
9613 StackLimitCheck check(isolate); | |
9614 if (check.JsHasOverflowed()) { | |
9615 SealHandleScope shs(isolate); | |
9616 return isolate->StackOverflow(); | |
9617 } | |
9618 | |
9619 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); | |
9620 return (function->IsOptimized()) ? function->code() | |
9621 : function->shared()->code(); | |
9622 } | |
9623 | |
9624 | |
9625 RUNTIME_FUNCTION(Runtime_Interrupt) { | |
9626 SealHandleScope shs(isolate); | |
9627 DCHECK(args.length() == 0); | |
9628 return isolate->stack_guard()->HandleInterrupts(); | |
9629 } | |
9630 | |
9631 | |
9632 static int StackSize(Isolate* isolate) { | |
9633 int n = 0; | |
9634 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; | |
9635 return n; | |
9636 } | |
9637 | |
9638 | |
9639 static void PrintTransition(Isolate* isolate, Object* result) { | |
9640 // indentation | |
9641 { const int nmax = 80; | |
9642 int n = StackSize(isolate); | |
9643 if (n <= nmax) | |
9644 PrintF("%4d:%*s", n, n, ""); | |
9645 else | |
9646 PrintF("%4d:%*s", n, nmax, "..."); | |
9647 } | |
9648 | |
9649 if (result == NULL) { | |
9650 JavaScriptFrame::PrintTop(isolate, stdout, true, false); | |
9651 PrintF(" {\n"); | |
9652 } else { | |
9653 // function result | |
9654 PrintF("} -> "); | |
9655 result->ShortPrint(); | |
9656 PrintF("\n"); | |
9657 } | |
9658 } | |
9659 | |
9660 | |
9661 RUNTIME_FUNCTION(Runtime_TraceEnter) { | |
9662 SealHandleScope shs(isolate); | |
9663 DCHECK(args.length() == 0); | |
9664 PrintTransition(isolate, NULL); | |
9665 return isolate->heap()->undefined_value(); | |
9666 } | |
9667 | |
9668 | |
9669 RUNTIME_FUNCTION(Runtime_TraceExit) { | |
9670 SealHandleScope shs(isolate); | |
9671 DCHECK(args.length() == 1); | |
9672 CONVERT_ARG_CHECKED(Object, obj, 0); | |
9673 PrintTransition(isolate, obj); | |
9674 return obj; // return TOS | |
9675 } | |
9676 | |
9677 | |
9678 RUNTIME_FUNCTION(Runtime_DebugPrint) { | |
9679 SealHandleScope shs(isolate); | |
9680 DCHECK(args.length() == 1); | |
9681 | |
9682 OFStream os(stdout); | |
9683 #ifdef DEBUG | |
9684 if (args[0]->IsString()) { | |
9685 // If we have a string, assume it's a code "marker" | |
9686 // and print some interesting cpu debugging info. | |
9687 JavaScriptFrameIterator it(isolate); | |
9688 JavaScriptFrame* frame = it.frame(); | |
9689 os << "fp = " << frame->fp() << ", sp = " << frame->sp() | |
9690 << ", caller_sp = " << frame->caller_sp() << ": "; | |
9691 } else { | |
9692 os << "DebugPrint: "; | |
9693 } | |
9694 args[0]->Print(os); | |
9695 if (args[0]->IsHeapObject()) { | |
9696 os << "\n"; | |
9697 HeapObject::cast(args[0])->map()->Print(os); | |
9698 } | |
9699 #else | |
9700 // ShortPrint is available in release mode. Print is not. | |
9701 os << Brief(args[0]); | |
9702 #endif | |
9703 os << endl; | |
9704 | |
9705 return args[0]; // return TOS | |
9706 } | |
9707 | |
9708 | |
9709 RUNTIME_FUNCTION(Runtime_DebugTrace) { | |
9710 SealHandleScope shs(isolate); | |
9711 DCHECK(args.length() == 0); | |
9712 isolate->PrintStack(stdout); | |
9713 return isolate->heap()->undefined_value(); | |
9714 } | |
9715 | |
9716 | |
9717 RUNTIME_FUNCTION(Runtime_DateCurrentTime) { | |
9718 HandleScope scope(isolate); | |
9719 DCHECK(args.length() == 0); | |
9720 if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent()); | |
9721 | |
9722 // According to ECMA-262, section 15.9.1, page 117, the precision of | |
9723 // the number in a Date object representing a particular instant in | |
9724 // time is milliseconds. Therefore, we floor the result of getting | |
9725 // the OS time. | |
9726 double millis; | |
9727 if (FLAG_verify_predictable) { | |
9728 millis = 1388534400000.0; // Jan 1 2014 00:00:00 GMT+0000 | |
9729 millis += Floor(isolate->heap()->synthetic_time()); | |
9730 } else { | |
9731 millis = Floor(base::OS::TimeCurrentMillis()); | |
9732 } | |
9733 return *isolate->factory()->NewNumber(millis); | |
9734 } | |
9735 | |
9736 | |
9737 RUNTIME_FUNCTION(Runtime_DateParseString) { | |
9738 HandleScope scope(isolate); | |
9739 DCHECK(args.length() == 2); | |
9740 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); | |
9741 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); | |
9742 | |
9743 RUNTIME_ASSERT(output->HasFastElements()); | |
9744 JSObject::EnsureCanContainHeapObjectElements(output); | |
9745 RUNTIME_ASSERT(output->HasFastObjectElements()); | |
9746 Handle<FixedArray> output_array(FixedArray::cast(output->elements())); | |
9747 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); | |
9748 | |
9749 str = String::Flatten(str); | |
9750 DisallowHeapAllocation no_gc; | |
9751 | |
9752 bool result; | |
9753 String::FlatContent str_content = str->GetFlatContent(); | |
9754 if (str_content.IsOneByte()) { | |
9755 result = DateParser::Parse(str_content.ToOneByteVector(), | |
9756 *output_array, | |
9757 isolate->unicode_cache()); | |
9758 } else { | |
9759 DCHECK(str_content.IsTwoByte()); | |
9760 result = DateParser::Parse(str_content.ToUC16Vector(), | |
9761 *output_array, | |
9762 isolate->unicode_cache()); | |
9763 } | |
9764 | |
9765 if (result) { | |
9766 return *output; | |
9767 } else { | |
9768 return isolate->heap()->null_value(); | |
9769 } | |
9770 } | |
9771 | |
9772 | |
9773 RUNTIME_FUNCTION(Runtime_DateLocalTimezone) { | |
9774 HandleScope scope(isolate); | |
9775 DCHECK(args.length() == 1); | |
9776 | |
9777 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
9778 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && | |
9779 x <= DateCache::kMaxTimeBeforeUTCInMs); | |
9780 const char* zone = | |
9781 isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x)); | |
9782 Handle<String> result = isolate->factory()->NewStringFromUtf8( | |
9783 CStrVector(zone)).ToHandleChecked(); | |
9784 return *result; | |
9785 } | |
9786 | |
9787 | |
9788 RUNTIME_FUNCTION(Runtime_DateToUTC) { | |
9789 HandleScope scope(isolate); | |
9790 DCHECK(args.length() == 1); | |
9791 | |
9792 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
9793 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && | |
9794 x <= DateCache::kMaxTimeBeforeUTCInMs); | |
9795 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); | |
9796 | |
9797 return *isolate->factory()->NewNumber(static_cast<double>(time)); | |
9798 } | |
9799 | |
9800 | |
9801 RUNTIME_FUNCTION(Runtime_DateCacheVersion) { | |
9802 HandleScope hs(isolate); | |
9803 DCHECK(args.length() == 0); | |
9804 if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) { | |
9805 Handle<FixedArray> date_cache_version = | |
9806 isolate->factory()->NewFixedArray(1, TENURED); | |
9807 date_cache_version->set(0, Smi::FromInt(0)); | |
9808 isolate->eternal_handles()->CreateSingleton( | |
9809 isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION); | |
9810 } | |
9811 Handle<FixedArray> date_cache_version = | |
9812 Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton( | |
9813 EternalHandles::DATE_CACHE_VERSION)); | |
9814 // Return result as a JS array. | |
9815 Handle<JSObject> result = | |
9816 isolate->factory()->NewJSObject(isolate->array_function()); | |
9817 JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version); | |
9818 return *result; | |
9819 } | |
9820 | |
9821 | |
9822 RUNTIME_FUNCTION(Runtime_GlobalProxy) { | |
9823 SealHandleScope shs(isolate); | |
9824 DCHECK(args.length() == 1); | |
9825 CONVERT_ARG_CHECKED(Object, global, 0); | |
9826 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); | |
9827 return JSGlobalObject::cast(global)->global_proxy(); | |
9828 } | |
9829 | |
9830 | |
9831 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { | |
9832 SealHandleScope shs(isolate); | |
9833 DCHECK(args.length() == 1); | |
9834 CONVERT_ARG_CHECKED(Object, global, 0); | |
9835 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); | |
9836 return isolate->heap()->ToBoolean( | |
9837 !JSGlobalObject::cast(global)->IsDetached()); | |
9838 } | |
9839 | |
9840 | |
9841 RUNTIME_FUNCTION(Runtime_ParseJson) { | |
9842 HandleScope scope(isolate); | |
9843 DCHECK(args.length() == 1); | |
9844 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | |
9845 | |
9846 source = String::Flatten(source); | |
9847 // Optimized fast case where we only have Latin1 characters. | |
9848 Handle<Object> result; | |
9849 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
9850 isolate, result, | |
9851 source->IsSeqOneByteString() ? JsonParser<true>::Parse(source) | |
9852 : JsonParser<false>::Parse(source)); | |
9853 return *result; | |
9854 } | |
9855 | |
9856 | |
9857 bool CodeGenerationFromStringsAllowed(Isolate* isolate, | |
9858 Handle<Context> context) { | |
9859 DCHECK(context->allow_code_gen_from_strings()->IsFalse()); | |
9860 // Check with callback if set. | |
9861 AllowCodeGenerationFromStringsCallback callback = | |
9862 isolate->allow_code_gen_callback(); | |
9863 if (callback == NULL) { | |
9864 // No callback set and code generation disallowed. | |
9865 return false; | |
9866 } else { | |
9867 // Callback set. Let it decide if code generation is allowed. | |
9868 VMState<EXTERNAL> state(isolate); | |
9869 return callback(v8::Utils::ToLocal(context)); | |
9870 } | |
9871 } | |
9872 | |
9873 | |
9874 RUNTIME_FUNCTION(Runtime_CompileString) { | |
9875 HandleScope scope(isolate); | |
9876 DCHECK(args.length() == 2); | |
9877 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); | |
9878 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); | |
9879 | |
9880 // Extract native context. | |
9881 Handle<Context> context(isolate->native_context()); | |
9882 | |
9883 // Check if native context allows code generation from | |
9884 // strings. Throw an exception if it doesn't. | |
9885 if (context->allow_code_gen_from_strings()->IsFalse() && | |
9886 !CodeGenerationFromStringsAllowed(isolate, context)) { | |
9887 Handle<Object> error_message = | |
9888 context->ErrorMessageForCodeGenerationFromStrings(); | |
9889 THROW_NEW_ERROR_RETURN_FAILURE( | |
9890 isolate, NewEvalError("code_gen_from_strings", | |
9891 HandleVector<Object>(&error_message, 1))); | |
9892 } | |
9893 | |
9894 // Compile source string in the native context. | |
9895 ParseRestriction restriction = function_literal_only | |
9896 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; | |
9897 Handle<JSFunction> fun; | |
9898 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
9899 isolate, fun, | |
9900 Compiler::GetFunctionFromEval( | |
9901 source, context, SLOPPY, restriction, RelocInfo::kNoPosition)); | |
9902 return *fun; | |
9903 } | |
9904 | |
9905 | |
9906 static ObjectPair CompileGlobalEval(Isolate* isolate, | |
9907 Handle<String> source, | |
9908 Handle<Object> receiver, | |
9909 StrictMode strict_mode, | |
9910 int scope_position) { | |
9911 Handle<Context> context = Handle<Context>(isolate->context()); | |
9912 Handle<Context> native_context = Handle<Context>(context->native_context()); | |
9913 | |
9914 // Check if native context allows code generation from | |
9915 // strings. Throw an exception if it doesn't. | |
9916 if (native_context->allow_code_gen_from_strings()->IsFalse() && | |
9917 !CodeGenerationFromStringsAllowed(isolate, native_context)) { | |
9918 Handle<Object> error_message = | |
9919 native_context->ErrorMessageForCodeGenerationFromStrings(); | |
9920 Handle<Object> error; | |
9921 MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError( | |
9922 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)); | |
9923 if (maybe_error.ToHandle(&error)) isolate->Throw(*error); | |
9924 return MakePair(isolate->heap()->exception(), NULL); | |
9925 } | |
9926 | |
9927 // Deal with a normal eval call with a string argument. Compile it | |
9928 // and return the compiled function bound in the local context. | |
9929 static const ParseRestriction restriction = NO_PARSE_RESTRICTION; | |
9930 Handle<JSFunction> compiled; | |
9931 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
9932 isolate, compiled, | |
9933 Compiler::GetFunctionFromEval( | |
9934 source, context, strict_mode, restriction, scope_position), | |
9935 MakePair(isolate->heap()->exception(), NULL)); | |
9936 return MakePair(*compiled, *receiver); | |
9937 } | |
9938 | |
9939 | |
9940 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) { | |
9941 HandleScope scope(isolate); | |
9942 DCHECK(args.length() == 5); | |
9943 | |
9944 Handle<Object> callee = args.at<Object>(0); | |
9945 | |
9946 // If "eval" didn't refer to the original GlobalEval, it's not a | |
9947 // direct call to eval. | |
9948 // (And even if it is, but the first argument isn't a string, just let | |
9949 // execution default to an indirect call to eval, which will also return | |
9950 // the first argument without doing anything). | |
9951 if (*callee != isolate->native_context()->global_eval_fun() || | |
9952 !args[1]->IsString()) { | |
9953 return MakePair(*callee, isolate->heap()->undefined_value()); | |
9954 } | |
9955 | |
9956 DCHECK(args[3]->IsSmi()); | |
9957 DCHECK(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT); | |
9958 StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3)); | |
9959 DCHECK(args[4]->IsSmi()); | |
9960 return CompileGlobalEval(isolate, | |
9961 args.at<String>(1), | |
9962 args.at<Object>(2), | |
9963 strict_mode, | |
9964 args.smi_at(4)); | |
9965 } | |
9966 | |
9967 | |
9968 RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) { | |
9969 HandleScope scope(isolate); | |
9970 DCHECK(args.length() == 1); | |
9971 CONVERT_SMI_ARG_CHECKED(size, 0); | |
9972 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); | |
9973 RUNTIME_ASSERT(size > 0); | |
9974 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); | |
9975 return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE); | |
9976 } | |
9977 | |
9978 | |
9979 RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) { | |
9980 HandleScope scope(isolate); | |
9981 DCHECK(args.length() == 2); | |
9982 CONVERT_SMI_ARG_CHECKED(size, 0); | |
9983 CONVERT_SMI_ARG_CHECKED(flags, 1); | |
9984 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); | |
9985 RUNTIME_ASSERT(size > 0); | |
9986 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); | |
9987 bool double_align = AllocateDoubleAlignFlag::decode(flags); | |
9988 AllocationSpace space = AllocateTargetSpace::decode(flags); | |
9989 return *isolate->factory()->NewFillerObject(size, double_align, space); | |
9990 } | |
9991 | |
9992 | |
9993 // Push an object unto an array of objects if it is not already in the | |
9994 // array. Returns true if the element was pushed on the stack and | |
9995 // false otherwise. | |
9996 RUNTIME_FUNCTION(Runtime_PushIfAbsent) { | |
9997 HandleScope scope(isolate); | |
9998 DCHECK(args.length() == 2); | |
9999 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | |
10000 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1); | |
10001 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements()); | |
10002 int length = Smi::cast(array->length())->value(); | |
10003 FixedArray* elements = FixedArray::cast(array->elements()); | |
10004 for (int i = 0; i < length; i++) { | |
10005 if (elements->get(i) == *element) return isolate->heap()->false_value(); | |
10006 } | |
10007 | |
10008 // Strict not needed. Used for cycle detection in Array join implementation. | |
10009 RETURN_FAILURE_ON_EXCEPTION( | |
10010 isolate, | |
10011 JSObject::SetFastElement(array, length, element, SLOPPY, true)); | |
10012 return isolate->heap()->true_value(); | |
10013 } | |
10014 | |
10015 | |
10016 /** | |
10017 * A simple visitor visits every element of Array's. | |
10018 * The backend storage can be a fixed array for fast elements case, | |
10019 * or a dictionary for sparse array. Since Dictionary is a subtype | |
10020 * of FixedArray, the class can be used by both fast and slow cases. | |
10021 * The second parameter of the constructor, fast_elements, specifies | |
10022 * whether the storage is a FixedArray or Dictionary. | |
10023 * | |
10024 * An index limit is used to deal with the situation that a result array | |
10025 * length overflows 32-bit non-negative integer. | |
10026 */ | |
10027 class ArrayConcatVisitor { | |
10028 public: | |
10029 ArrayConcatVisitor(Isolate* isolate, | |
10030 Handle<FixedArray> storage, | |
10031 bool fast_elements) : | |
10032 isolate_(isolate), | |
10033 storage_(Handle<FixedArray>::cast( | |
10034 isolate->global_handles()->Create(*storage))), | |
10035 index_offset_(0u), | |
10036 fast_elements_(fast_elements), | |
10037 exceeds_array_limit_(false) { } | |
10038 | |
10039 ~ArrayConcatVisitor() { | |
10040 clear_storage(); | |
10041 } | |
10042 | |
10043 void visit(uint32_t i, Handle<Object> elm) { | |
10044 if (i > JSObject::kMaxElementCount - index_offset_) { | |
10045 exceeds_array_limit_ = true; | |
10046 return; | |
10047 } | |
10048 uint32_t index = index_offset_ + i; | |
10049 | |
10050 if (fast_elements_) { | |
10051 if (index < static_cast<uint32_t>(storage_->length())) { | |
10052 storage_->set(index, *elm); | |
10053 return; | |
10054 } | |
10055 // Our initial estimate of length was foiled, possibly by | |
10056 // getters on the arrays increasing the length of later arrays | |
10057 // during iteration. | |
10058 // This shouldn't happen in anything but pathological cases. | |
10059 SetDictionaryMode(); | |
10060 // Fall-through to dictionary mode. | |
10061 } | |
10062 DCHECK(!fast_elements_); | |
10063 Handle<SeededNumberDictionary> dict( | |
10064 SeededNumberDictionary::cast(*storage_)); | |
10065 Handle<SeededNumberDictionary> result = | |
10066 SeededNumberDictionary::AtNumberPut(dict, index, elm); | |
10067 if (!result.is_identical_to(dict)) { | |
10068 // Dictionary needed to grow. | |
10069 clear_storage(); | |
10070 set_storage(*result); | |
10071 } | |
10072 } | |
10073 | |
10074 void increase_index_offset(uint32_t delta) { | |
10075 if (JSObject::kMaxElementCount - index_offset_ < delta) { | |
10076 index_offset_ = JSObject::kMaxElementCount; | |
10077 } else { | |
10078 index_offset_ += delta; | |
10079 } | |
10080 // If the initial length estimate was off (see special case in visit()), | |
10081 // but the array blowing the limit didn't contain elements beyond the | |
10082 // provided-for index range, go to dictionary mode now. | |
10083 if (fast_elements_ && | |
10084 index_offset_ > | |
10085 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { | |
10086 SetDictionaryMode(); | |
10087 } | |
10088 } | |
10089 | |
10090 bool exceeds_array_limit() { | |
10091 return exceeds_array_limit_; | |
10092 } | |
10093 | |
10094 Handle<JSArray> ToArray() { | |
10095 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | |
10096 Handle<Object> length = | |
10097 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); | |
10098 Handle<Map> map = JSObject::GetElementsTransitionMap( | |
10099 array, | |
10100 fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); | |
10101 array->set_map(*map); | |
10102 array->set_length(*length); | |
10103 array->set_elements(*storage_); | |
10104 return array; | |
10105 } | |
10106 | |
10107 private: | |
10108 // Convert storage to dictionary mode. | |
10109 void SetDictionaryMode() { | |
10110 DCHECK(fast_elements_); | |
10111 Handle<FixedArray> current_storage(*storage_); | |
10112 Handle<SeededNumberDictionary> slow_storage( | |
10113 SeededNumberDictionary::New(isolate_, current_storage->length())); | |
10114 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); | |
10115 for (uint32_t i = 0; i < current_length; i++) { | |
10116 HandleScope loop_scope(isolate_); | |
10117 Handle<Object> element(current_storage->get(i), isolate_); | |
10118 if (!element->IsTheHole()) { | |
10119 Handle<SeededNumberDictionary> new_storage = | |
10120 SeededNumberDictionary::AtNumberPut(slow_storage, i, element); | |
10121 if (!new_storage.is_identical_to(slow_storage)) { | |
10122 slow_storage = loop_scope.CloseAndEscape(new_storage); | |
10123 } | |
10124 } | |
10125 } | |
10126 clear_storage(); | |
10127 set_storage(*slow_storage); | |
10128 fast_elements_ = false; | |
10129 } | |
10130 | |
10131 inline void clear_storage() { | |
10132 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); | |
10133 } | |
10134 | |
10135 inline void set_storage(FixedArray* storage) { | |
10136 storage_ = Handle<FixedArray>::cast( | |
10137 isolate_->global_handles()->Create(storage)); | |
10138 } | |
10139 | |
10140 Isolate* isolate_; | |
10141 Handle<FixedArray> storage_; // Always a global handle. | |
10142 // Index after last seen index. Always less than or equal to | |
10143 // JSObject::kMaxElementCount. | |
10144 uint32_t index_offset_; | |
10145 bool fast_elements_ : 1; | |
10146 bool exceeds_array_limit_ : 1; | |
10147 }; | |
10148 | |
10149 | |
10150 static uint32_t EstimateElementCount(Handle<JSArray> array) { | |
10151 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | |
10152 int element_count = 0; | |
10153 switch (array->GetElementsKind()) { | |
10154 case FAST_SMI_ELEMENTS: | |
10155 case FAST_HOLEY_SMI_ELEMENTS: | |
10156 case FAST_ELEMENTS: | |
10157 case FAST_HOLEY_ELEMENTS: { | |
10158 // Fast elements can't have lengths that are not representable by | |
10159 // a 32-bit signed integer. | |
10160 DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); | |
10161 int fast_length = static_cast<int>(length); | |
10162 Handle<FixedArray> elements(FixedArray::cast(array->elements())); | |
10163 for (int i = 0; i < fast_length; i++) { | |
10164 if (!elements->get(i)->IsTheHole()) element_count++; | |
10165 } | |
10166 break; | |
10167 } | |
10168 case FAST_DOUBLE_ELEMENTS: | |
10169 case FAST_HOLEY_DOUBLE_ELEMENTS: { | |
10170 // Fast elements can't have lengths that are not representable by | |
10171 // a 32-bit signed integer. | |
10172 DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); | |
10173 int fast_length = static_cast<int>(length); | |
10174 if (array->elements()->IsFixedArray()) { | |
10175 DCHECK(FixedArray::cast(array->elements())->length() == 0); | |
10176 break; | |
10177 } | |
10178 Handle<FixedDoubleArray> elements( | |
10179 FixedDoubleArray::cast(array->elements())); | |
10180 for (int i = 0; i < fast_length; i++) { | |
10181 if (!elements->is_the_hole(i)) element_count++; | |
10182 } | |
10183 break; | |
10184 } | |
10185 case DICTIONARY_ELEMENTS: { | |
10186 Handle<SeededNumberDictionary> dictionary( | |
10187 SeededNumberDictionary::cast(array->elements())); | |
10188 int capacity = dictionary->Capacity(); | |
10189 for (int i = 0; i < capacity; i++) { | |
10190 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate()); | |
10191 if (dictionary->IsKey(*key)) { | |
10192 element_count++; | |
10193 } | |
10194 } | |
10195 break; | |
10196 } | |
10197 case SLOPPY_ARGUMENTS_ELEMENTS: | |
10198 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
10199 case EXTERNAL_##TYPE##_ELEMENTS: \ | |
10200 case TYPE##_ELEMENTS: \ | |
10201 | |
10202 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
10203 #undef TYPED_ARRAY_CASE | |
10204 // External arrays are always dense. | |
10205 return length; | |
10206 } | |
10207 // As an estimate, we assume that the prototype doesn't contain any | |
10208 // inherited elements. | |
10209 return element_count; | |
10210 } | |
10211 | |
10212 | |
10213 | |
10214 template<class ExternalArrayClass, class ElementType> | |
10215 static void IterateExternalArrayElements(Isolate* isolate, | |
10216 Handle<JSObject> receiver, | |
10217 bool elements_are_ints, | |
10218 bool elements_are_guaranteed_smis, | |
10219 ArrayConcatVisitor* visitor) { | |
10220 Handle<ExternalArrayClass> array( | |
10221 ExternalArrayClass::cast(receiver->elements())); | |
10222 uint32_t len = static_cast<uint32_t>(array->length()); | |
10223 | |
10224 DCHECK(visitor != NULL); | |
10225 if (elements_are_ints) { | |
10226 if (elements_are_guaranteed_smis) { | |
10227 for (uint32_t j = 0; j < len; j++) { | |
10228 HandleScope loop_scope(isolate); | |
10229 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), | |
10230 isolate); | |
10231 visitor->visit(j, e); | |
10232 } | |
10233 } else { | |
10234 for (uint32_t j = 0; j < len; j++) { | |
10235 HandleScope loop_scope(isolate); | |
10236 int64_t val = static_cast<int64_t>(array->get_scalar(j)); | |
10237 if (Smi::IsValid(static_cast<intptr_t>(val))) { | |
10238 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); | |
10239 visitor->visit(j, e); | |
10240 } else { | |
10241 Handle<Object> e = | |
10242 isolate->factory()->NewNumber(static_cast<ElementType>(val)); | |
10243 visitor->visit(j, e); | |
10244 } | |
10245 } | |
10246 } | |
10247 } else { | |
10248 for (uint32_t j = 0; j < len; j++) { | |
10249 HandleScope loop_scope(isolate); | |
10250 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); | |
10251 visitor->visit(j, e); | |
10252 } | |
10253 } | |
10254 } | |
10255 | |
10256 | |
10257 // Used for sorting indices in a List<uint32_t>. | |
10258 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { | |
10259 uint32_t a = *ap; | |
10260 uint32_t b = *bp; | |
10261 return (a == b) ? 0 : (a < b) ? -1 : 1; | |
10262 } | |
10263 | |
10264 | |
10265 static void CollectElementIndices(Handle<JSObject> object, | |
10266 uint32_t range, | |
10267 List<uint32_t>* indices) { | |
10268 Isolate* isolate = object->GetIsolate(); | |
10269 ElementsKind kind = object->GetElementsKind(); | |
10270 switch (kind) { | |
10271 case FAST_SMI_ELEMENTS: | |
10272 case FAST_ELEMENTS: | |
10273 case FAST_HOLEY_SMI_ELEMENTS: | |
10274 case FAST_HOLEY_ELEMENTS: { | |
10275 Handle<FixedArray> elements(FixedArray::cast(object->elements())); | |
10276 uint32_t length = static_cast<uint32_t>(elements->length()); | |
10277 if (range < length) length = range; | |
10278 for (uint32_t i = 0; i < length; i++) { | |
10279 if (!elements->get(i)->IsTheHole()) { | |
10280 indices->Add(i); | |
10281 } | |
10282 } | |
10283 break; | |
10284 } | |
10285 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
10286 case FAST_DOUBLE_ELEMENTS: { | |
10287 if (object->elements()->IsFixedArray()) { | |
10288 DCHECK(object->elements()->length() == 0); | |
10289 break; | |
10290 } | |
10291 Handle<FixedDoubleArray> elements( | |
10292 FixedDoubleArray::cast(object->elements())); | |
10293 uint32_t length = static_cast<uint32_t>(elements->length()); | |
10294 if (range < length) length = range; | |
10295 for (uint32_t i = 0; i < length; i++) { | |
10296 if (!elements->is_the_hole(i)) { | |
10297 indices->Add(i); | |
10298 } | |
10299 } | |
10300 break; | |
10301 } | |
10302 case DICTIONARY_ELEMENTS: { | |
10303 Handle<SeededNumberDictionary> dict( | |
10304 SeededNumberDictionary::cast(object->elements())); | |
10305 uint32_t capacity = dict->Capacity(); | |
10306 for (uint32_t j = 0; j < capacity; j++) { | |
10307 HandleScope loop_scope(isolate); | |
10308 Handle<Object> k(dict->KeyAt(j), isolate); | |
10309 if (dict->IsKey(*k)) { | |
10310 DCHECK(k->IsNumber()); | |
10311 uint32_t index = static_cast<uint32_t>(k->Number()); | |
10312 if (index < range) { | |
10313 indices->Add(index); | |
10314 } | |
10315 } | |
10316 } | |
10317 break; | |
10318 } | |
10319 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
10320 case TYPE##_ELEMENTS: \ | |
10321 case EXTERNAL_##TYPE##_ELEMENTS: | |
10322 | |
10323 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
10324 #undef TYPED_ARRAY_CASE | |
10325 { | |
10326 uint32_t length = static_cast<uint32_t>( | |
10327 FixedArrayBase::cast(object->elements())->length()); | |
10328 if (range <= length) { | |
10329 length = range; | |
10330 // We will add all indices, so we might as well clear it first | |
10331 // and avoid duplicates. | |
10332 indices->Clear(); | |
10333 } | |
10334 for (uint32_t i = 0; i < length; i++) { | |
10335 indices->Add(i); | |
10336 } | |
10337 if (length == range) return; // All indices accounted for already. | |
10338 break; | |
10339 } | |
10340 case SLOPPY_ARGUMENTS_ELEMENTS: { | |
10341 MaybeHandle<Object> length_obj = | |
10342 Object::GetProperty(object, isolate->factory()->length_string()); | |
10343 double length_num = length_obj.ToHandleChecked()->Number(); | |
10344 uint32_t length = static_cast<uint32_t>(DoubleToInt32(length_num)); | |
10345 ElementsAccessor* accessor = object->GetElementsAccessor(); | |
10346 for (uint32_t i = 0; i < length; i++) { | |
10347 if (accessor->HasElement(object, object, i)) { | |
10348 indices->Add(i); | |
10349 } | |
10350 } | |
10351 break; | |
10352 } | |
10353 } | |
10354 | |
10355 PrototypeIterator iter(isolate, object); | |
10356 if (!iter.IsAtEnd()) { | |
10357 // The prototype will usually have no inherited element indices, | |
10358 // but we have to check. | |
10359 CollectElementIndices( | |
10360 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range, | |
10361 indices); | |
10362 } | |
10363 } | |
10364 | |
10365 | |
10366 /** | |
10367 * A helper function that visits elements of a JSArray in numerical | |
10368 * order. | |
10369 * | |
10370 * The visitor argument called for each existing element in the array | |
10371 * with the element index and the element's value. | |
10372 * Afterwards it increments the base-index of the visitor by the array | |
10373 * length. | |
10374 * Returns false if any access threw an exception, otherwise true. | |
10375 */ | |
10376 static bool IterateElements(Isolate* isolate, | |
10377 Handle<JSArray> receiver, | |
10378 ArrayConcatVisitor* visitor) { | |
10379 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); | |
10380 switch (receiver->GetElementsKind()) { | |
10381 case FAST_SMI_ELEMENTS: | |
10382 case FAST_ELEMENTS: | |
10383 case FAST_HOLEY_SMI_ELEMENTS: | |
10384 case FAST_HOLEY_ELEMENTS: { | |
10385 // Run through the elements FixedArray and use HasElement and GetElement | |
10386 // to check the prototype for missing elements. | |
10387 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); | |
10388 int fast_length = static_cast<int>(length); | |
10389 DCHECK(fast_length <= elements->length()); | |
10390 for (int j = 0; j < fast_length; j++) { | |
10391 HandleScope loop_scope(isolate); | |
10392 Handle<Object> element_value(elements->get(j), isolate); | |
10393 if (!element_value->IsTheHole()) { | |
10394 visitor->visit(j, element_value); | |
10395 } else { | |
10396 Maybe<bool> maybe = JSReceiver::HasElement(receiver, j); | |
10397 if (!maybe.has_value) return false; | |
10398 if (maybe.value) { | |
10399 // Call GetElement on receiver, not its prototype, or getters won't | |
10400 // have the correct receiver. | |
10401 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
10402 isolate, element_value, | |
10403 Object::GetElement(isolate, receiver, j), false); | |
10404 visitor->visit(j, element_value); | |
10405 } | |
10406 } | |
10407 } | |
10408 break; | |
10409 } | |
10410 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
10411 case FAST_DOUBLE_ELEMENTS: { | |
10412 // Empty array is FixedArray but not FixedDoubleArray. | |
10413 if (length == 0) break; | |
10414 // Run through the elements FixedArray and use HasElement and GetElement | |
10415 // to check the prototype for missing elements. | |
10416 if (receiver->elements()->IsFixedArray()) { | |
10417 DCHECK(receiver->elements()->length() == 0); | |
10418 break; | |
10419 } | |
10420 Handle<FixedDoubleArray> elements( | |
10421 FixedDoubleArray::cast(receiver->elements())); | |
10422 int fast_length = static_cast<int>(length); | |
10423 DCHECK(fast_length <= elements->length()); | |
10424 for (int j = 0; j < fast_length; j++) { | |
10425 HandleScope loop_scope(isolate); | |
10426 if (!elements->is_the_hole(j)) { | |
10427 double double_value = elements->get_scalar(j); | |
10428 Handle<Object> element_value = | |
10429 isolate->factory()->NewNumber(double_value); | |
10430 visitor->visit(j, element_value); | |
10431 } else { | |
10432 Maybe<bool> maybe = JSReceiver::HasElement(receiver, j); | |
10433 if (!maybe.has_value) return false; | |
10434 if (maybe.value) { | |
10435 // Call GetElement on receiver, not its prototype, or getters won't | |
10436 // have the correct receiver. | |
10437 Handle<Object> element_value; | |
10438 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
10439 isolate, element_value, | |
10440 Object::GetElement(isolate, receiver, j), false); | |
10441 visitor->visit(j, element_value); | |
10442 } | |
10443 } | |
10444 } | |
10445 break; | |
10446 } | |
10447 case DICTIONARY_ELEMENTS: { | |
10448 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); | |
10449 List<uint32_t> indices(dict->Capacity() / 2); | |
10450 // Collect all indices in the object and the prototypes less | |
10451 // than length. This might introduce duplicates in the indices list. | |
10452 CollectElementIndices(receiver, length, &indices); | |
10453 indices.Sort(&compareUInt32); | |
10454 int j = 0; | |
10455 int n = indices.length(); | |
10456 while (j < n) { | |
10457 HandleScope loop_scope(isolate); | |
10458 uint32_t index = indices[j]; | |
10459 Handle<Object> element; | |
10460 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
10461 isolate, element, | |
10462 Object::GetElement(isolate, receiver, index), | |
10463 false); | |
10464 visitor->visit(index, element); | |
10465 // Skip to next different index (i.e., omit duplicates). | |
10466 do { | |
10467 j++; | |
10468 } while (j < n && indices[j] == index); | |
10469 } | |
10470 break; | |
10471 } | |
10472 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { | |
10473 Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast( | |
10474 receiver->elements())); | |
10475 for (uint32_t j = 0; j < length; j++) { | |
10476 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); | |
10477 visitor->visit(j, e); | |
10478 } | |
10479 break; | |
10480 } | |
10481 case EXTERNAL_INT8_ELEMENTS: { | |
10482 IterateExternalArrayElements<ExternalInt8Array, int8_t>( | |
10483 isolate, receiver, true, true, visitor); | |
10484 break; | |
10485 } | |
10486 case EXTERNAL_UINT8_ELEMENTS: { | |
10487 IterateExternalArrayElements<ExternalUint8Array, uint8_t>( | |
10488 isolate, receiver, true, true, visitor); | |
10489 break; | |
10490 } | |
10491 case EXTERNAL_INT16_ELEMENTS: { | |
10492 IterateExternalArrayElements<ExternalInt16Array, int16_t>( | |
10493 isolate, receiver, true, true, visitor); | |
10494 break; | |
10495 } | |
10496 case EXTERNAL_UINT16_ELEMENTS: { | |
10497 IterateExternalArrayElements<ExternalUint16Array, uint16_t>( | |
10498 isolate, receiver, true, true, visitor); | |
10499 break; | |
10500 } | |
10501 case EXTERNAL_INT32_ELEMENTS: { | |
10502 IterateExternalArrayElements<ExternalInt32Array, int32_t>( | |
10503 isolate, receiver, true, false, visitor); | |
10504 break; | |
10505 } | |
10506 case EXTERNAL_UINT32_ELEMENTS: { | |
10507 IterateExternalArrayElements<ExternalUint32Array, uint32_t>( | |
10508 isolate, receiver, true, false, visitor); | |
10509 break; | |
10510 } | |
10511 case EXTERNAL_FLOAT32_ELEMENTS: { | |
10512 IterateExternalArrayElements<ExternalFloat32Array, float>( | |
10513 isolate, receiver, false, false, visitor); | |
10514 break; | |
10515 } | |
10516 case EXTERNAL_FLOAT64_ELEMENTS: { | |
10517 IterateExternalArrayElements<ExternalFloat64Array, double>( | |
10518 isolate, receiver, false, false, visitor); | |
10519 break; | |
10520 } | |
10521 default: | |
10522 UNREACHABLE(); | |
10523 break; | |
10524 } | |
10525 visitor->increase_index_offset(length); | |
10526 return true; | |
10527 } | |
10528 | |
10529 | |
10530 /** | |
10531 * Array::concat implementation. | |
10532 * See ECMAScript 262, 15.4.4.4. | |
10533 * TODO(581): Fix non-compliance for very large concatenations and update to | |
10534 * following the ECMAScript 5 specification. | |
10535 */ | |
10536 RUNTIME_FUNCTION(Runtime_ArrayConcat) { | |
10537 HandleScope handle_scope(isolate); | |
10538 DCHECK(args.length() == 1); | |
10539 | |
10540 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); | |
10541 int argument_count = static_cast<int>(arguments->length()->Number()); | |
10542 RUNTIME_ASSERT(arguments->HasFastObjectElements()); | |
10543 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); | |
10544 | |
10545 // Pass 1: estimate the length and number of elements of the result. | |
10546 // The actual length can be larger if any of the arguments have getters | |
10547 // that mutate other arguments (but will otherwise be precise). | |
10548 // The number of elements is precise if there are no inherited elements. | |
10549 | |
10550 ElementsKind kind = FAST_SMI_ELEMENTS; | |
10551 | |
10552 uint32_t estimate_result_length = 0; | |
10553 uint32_t estimate_nof_elements = 0; | |
10554 for (int i = 0; i < argument_count; i++) { | |
10555 HandleScope loop_scope(isolate); | |
10556 Handle<Object> obj(elements->get(i), isolate); | |
10557 uint32_t length_estimate; | |
10558 uint32_t element_estimate; | |
10559 if (obj->IsJSArray()) { | |
10560 Handle<JSArray> array(Handle<JSArray>::cast(obj)); | |
10561 length_estimate = static_cast<uint32_t>(array->length()->Number()); | |
10562 if (length_estimate != 0) { | |
10563 ElementsKind array_kind = | |
10564 GetPackedElementsKind(array->map()->elements_kind()); | |
10565 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { | |
10566 kind = array_kind; | |
10567 } | |
10568 } | |
10569 element_estimate = EstimateElementCount(array); | |
10570 } else { | |
10571 if (obj->IsHeapObject()) { | |
10572 if (obj->IsNumber()) { | |
10573 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { | |
10574 kind = FAST_DOUBLE_ELEMENTS; | |
10575 } | |
10576 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { | |
10577 kind = FAST_ELEMENTS; | |
10578 } | |
10579 } | |
10580 length_estimate = 1; | |
10581 element_estimate = 1; | |
10582 } | |
10583 // Avoid overflows by capping at kMaxElementCount. | |
10584 if (JSObject::kMaxElementCount - estimate_result_length < | |
10585 length_estimate) { | |
10586 estimate_result_length = JSObject::kMaxElementCount; | |
10587 } else { | |
10588 estimate_result_length += length_estimate; | |
10589 } | |
10590 if (JSObject::kMaxElementCount - estimate_nof_elements < | |
10591 element_estimate) { | |
10592 estimate_nof_elements = JSObject::kMaxElementCount; | |
10593 } else { | |
10594 estimate_nof_elements += element_estimate; | |
10595 } | |
10596 } | |
10597 | |
10598 // If estimated number of elements is more than half of length, a | |
10599 // fixed array (fast case) is more time and space-efficient than a | |
10600 // dictionary. | |
10601 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; | |
10602 | |
10603 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { | |
10604 Handle<FixedArrayBase> storage = | |
10605 isolate->factory()->NewFixedDoubleArray(estimate_result_length); | |
10606 int j = 0; | |
10607 bool failure = false; | |
10608 if (estimate_result_length > 0) { | |
10609 Handle<FixedDoubleArray> double_storage = | |
10610 Handle<FixedDoubleArray>::cast(storage); | |
10611 for (int i = 0; i < argument_count; i++) { | |
10612 Handle<Object> obj(elements->get(i), isolate); | |
10613 if (obj->IsSmi()) { | |
10614 double_storage->set(j, Smi::cast(*obj)->value()); | |
10615 j++; | |
10616 } else if (obj->IsNumber()) { | |
10617 double_storage->set(j, obj->Number()); | |
10618 j++; | |
10619 } else { | |
10620 JSArray* array = JSArray::cast(*obj); | |
10621 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | |
10622 switch (array->map()->elements_kind()) { | |
10623 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
10624 case FAST_DOUBLE_ELEMENTS: { | |
10625 // Empty array is FixedArray but not FixedDoubleArray. | |
10626 if (length == 0) break; | |
10627 FixedDoubleArray* elements = | |
10628 FixedDoubleArray::cast(array->elements()); | |
10629 for (uint32_t i = 0; i < length; i++) { | |
10630 if (elements->is_the_hole(i)) { | |
10631 // TODO(jkummerow/verwaest): We could be a bit more clever | |
10632 // here: Check if there are no elements/getters on the | |
10633 // prototype chain, and if so, allow creation of a holey | |
10634 // result array. | |
10635 // Same thing below (holey smi case). | |
10636 failure = true; | |
10637 break; | |
10638 } | |
10639 double double_value = elements->get_scalar(i); | |
10640 double_storage->set(j, double_value); | |
10641 j++; | |
10642 } | |
10643 break; | |
10644 } | |
10645 case FAST_HOLEY_SMI_ELEMENTS: | |
10646 case FAST_SMI_ELEMENTS: { | |
10647 FixedArray* elements( | |
10648 FixedArray::cast(array->elements())); | |
10649 for (uint32_t i = 0; i < length; i++) { | |
10650 Object* element = elements->get(i); | |
10651 if (element->IsTheHole()) { | |
10652 failure = true; | |
10653 break; | |
10654 } | |
10655 int32_t int_value = Smi::cast(element)->value(); | |
10656 double_storage->set(j, int_value); | |
10657 j++; | |
10658 } | |
10659 break; | |
10660 } | |
10661 case FAST_HOLEY_ELEMENTS: | |
10662 case FAST_ELEMENTS: | |
10663 DCHECK_EQ(0, length); | |
10664 break; | |
10665 default: | |
10666 UNREACHABLE(); | |
10667 } | |
10668 } | |
10669 if (failure) break; | |
10670 } | |
10671 } | |
10672 if (!failure) { | |
10673 Handle<JSArray> array = isolate->factory()->NewJSArray(0); | |
10674 Smi* length = Smi::FromInt(j); | |
10675 Handle<Map> map; | |
10676 map = JSObject::GetElementsTransitionMap(array, kind); | |
10677 array->set_map(*map); | |
10678 array->set_length(length); | |
10679 array->set_elements(*storage); | |
10680 return *array; | |
10681 } | |
10682 // In case of failure, fall through. | |
10683 } | |
10684 | |
10685 Handle<FixedArray> storage; | |
10686 if (fast_case) { | |
10687 // The backing storage array must have non-existing elements to preserve | |
10688 // holes across concat operations. | |
10689 storage = isolate->factory()->NewFixedArrayWithHoles( | |
10690 estimate_result_length); | |
10691 } else { | |
10692 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | |
10693 uint32_t at_least_space_for = estimate_nof_elements + | |
10694 (estimate_nof_elements >> 2); | |
10695 storage = Handle<FixedArray>::cast( | |
10696 SeededNumberDictionary::New(isolate, at_least_space_for)); | |
10697 } | |
10698 | |
10699 ArrayConcatVisitor visitor(isolate, storage, fast_case); | |
10700 | |
10701 for (int i = 0; i < argument_count; i++) { | |
10702 Handle<Object> obj(elements->get(i), isolate); | |
10703 if (obj->IsJSArray()) { | |
10704 Handle<JSArray> array = Handle<JSArray>::cast(obj); | |
10705 if (!IterateElements(isolate, array, &visitor)) { | |
10706 return isolate->heap()->exception(); | |
10707 } | |
10708 } else { | |
10709 visitor.visit(0, obj); | |
10710 visitor.increase_index_offset(1); | |
10711 } | |
10712 } | |
10713 | |
10714 if (visitor.exceeds_array_limit()) { | |
10715 THROW_NEW_ERROR_RETURN_FAILURE( | |
10716 isolate, | |
10717 NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0))); | |
10718 } | |
10719 return *visitor.ToArray(); | |
10720 } | |
10721 | |
10722 | |
10723 // This will not allocate (flatten the string), but it may run | |
10724 // very slowly for very deeply nested ConsStrings. For debugging use only. | |
10725 RUNTIME_FUNCTION(Runtime_GlobalPrint) { | |
10726 SealHandleScope shs(isolate); | |
10727 DCHECK(args.length() == 1); | |
10728 | |
10729 CONVERT_ARG_CHECKED(String, string, 0); | |
10730 ConsStringIteratorOp op; | |
10731 StringCharacterStream stream(string, &op); | |
10732 while (stream.HasMore()) { | |
10733 uint16_t character = stream.GetNext(); | |
10734 PrintF("%c", character); | |
10735 } | |
10736 return string; | |
10737 } | |
10738 | |
10739 | |
10740 // Moves all own elements of an object, that are below a limit, to positions | |
10741 // starting at zero. All undefined values are placed after non-undefined values, | |
10742 // and are followed by non-existing element. Does not change the length | |
10743 // property. | |
10744 // Returns the number of non-undefined elements collected. | |
10745 // Returns -1 if hole removal is not supported by this method. | |
10746 RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) { | |
10747 HandleScope scope(isolate); | |
10748 DCHECK(args.length() == 2); | |
10749 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
10750 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); | |
10751 return *JSObject::PrepareElementsForSort(object, limit); | |
10752 } | |
10753 | |
10754 | |
10755 // Move contents of argument 0 (an array) to argument 1 (an array) | |
10756 RUNTIME_FUNCTION(Runtime_MoveArrayContents) { | |
10757 HandleScope scope(isolate); | |
10758 DCHECK(args.length() == 2); | |
10759 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0); | |
10760 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1); | |
10761 JSObject::ValidateElements(from); | |
10762 JSObject::ValidateElements(to); | |
10763 | |
10764 Handle<FixedArrayBase> new_elements(from->elements()); | |
10765 ElementsKind from_kind = from->GetElementsKind(); | |
10766 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind); | |
10767 JSObject::SetMapAndElements(to, new_map, new_elements); | |
10768 to->set_length(from->length()); | |
10769 | |
10770 JSObject::ResetElements(from); | |
10771 from->set_length(Smi::FromInt(0)); | |
10772 | |
10773 JSObject::ValidateElements(to); | |
10774 return *to; | |
10775 } | |
10776 | |
10777 | |
10778 // How many elements does this object/array have? | |
10779 RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) { | |
10780 HandleScope scope(isolate); | |
10781 DCHECK(args.length() == 1); | |
10782 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); | |
10783 Handle<FixedArrayBase> elements(array->elements(), isolate); | |
10784 SealHandleScope shs(isolate); | |
10785 if (elements->IsDictionary()) { | |
10786 int result = | |
10787 Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements(); | |
10788 return Smi::FromInt(result); | |
10789 } else { | |
10790 DCHECK(array->length()->IsSmi()); | |
10791 // For packed elements, we know the exact number of elements | |
10792 int length = elements->length(); | |
10793 ElementsKind kind = array->GetElementsKind(); | |
10794 if (IsFastPackedElementsKind(kind)) { | |
10795 return Smi::FromInt(length); | |
10796 } | |
10797 // For holey elements, take samples from the buffer checking for holes | |
10798 // to generate the estimate. | |
10799 const int kNumberOfHoleCheckSamples = 97; | |
10800 int increment = (length < kNumberOfHoleCheckSamples) | |
10801 ? 1 | |
10802 : static_cast<int>(length / kNumberOfHoleCheckSamples); | |
10803 ElementsAccessor* accessor = array->GetElementsAccessor(); | |
10804 int holes = 0; | |
10805 for (int i = 0; i < length; i += increment) { | |
10806 if (!accessor->HasElement(array, array, i, elements)) { | |
10807 ++holes; | |
10808 } | |
10809 } | |
10810 int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) / | |
10811 kNumberOfHoleCheckSamples * length); | |
10812 return Smi::FromInt(estimate); | |
10813 } | |
10814 } | |
10815 | |
10816 | |
10817 // Returns an array that tells you where in the [0, length) interval an array | |
10818 // might have elements. Can either return an array of keys (positive integers | |
10819 // or undefined) or a number representing the positive length of an interval | |
10820 // starting at index 0. | |
10821 // Intervals can span over some keys that are not in the object. | |
10822 RUNTIME_FUNCTION(Runtime_GetArrayKeys) { | |
10823 HandleScope scope(isolate); | |
10824 DCHECK(args.length() == 2); | |
10825 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); | |
10826 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); | |
10827 if (array->elements()->IsDictionary()) { | |
10828 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); | |
10829 for (PrototypeIterator iter(isolate, array, | |
10830 PrototypeIterator::START_AT_RECEIVER); | |
10831 !iter.IsAtEnd(); iter.Advance()) { | |
10832 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() || | |
10833 JSObject::cast(*PrototypeIterator::GetCurrent(iter)) | |
10834 ->HasIndexedInterceptor()) { | |
10835 // Bail out if we find a proxy or interceptor, likely not worth | |
10836 // collecting keys in that case. | |
10837 return *isolate->factory()->NewNumberFromUint(length); | |
10838 } | |
10839 Handle<JSObject> current = | |
10840 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
10841 Handle<FixedArray> current_keys = | |
10842 isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE)); | |
10843 current->GetOwnElementKeys(*current_keys, NONE); | |
10844 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
10845 isolate, keys, FixedArray::UnionOfKeys(keys, current_keys)); | |
10846 } | |
10847 // Erase any keys >= length. | |
10848 // TODO(adamk): Remove this step when the contract of %GetArrayKeys | |
10849 // is changed to let this happen on the JS side. | |
10850 for (int i = 0; i < keys->length(); i++) { | |
10851 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); | |
10852 } | |
10853 return *isolate->factory()->NewJSArrayWithElements(keys); | |
10854 } else { | |
10855 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() || | |
10856 array->HasFastDoubleElements()); | |
10857 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); | |
10858 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); | |
10859 } | |
10860 } | |
10861 | |
10862 | |
10863 RUNTIME_FUNCTION(Runtime_LookupAccessor) { | |
10864 HandleScope scope(isolate); | |
10865 DCHECK(args.length() == 3); | |
10866 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); | |
10867 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
10868 CONVERT_SMI_ARG_CHECKED(flag, 2); | |
10869 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; | |
10870 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); | |
10871 Handle<Object> result; | |
10872 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
10873 isolate, result, | |
10874 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component)); | |
10875 return *result; | |
10876 } | |
10877 | |
10878 | |
10879 RUNTIME_FUNCTION(Runtime_DebugBreak) { | |
10880 SealHandleScope shs(isolate); | |
10881 DCHECK(args.length() == 0); | |
10882 isolate->debug()->HandleDebugBreak(); | |
10883 return isolate->heap()->undefined_value(); | |
10884 } | |
10885 | |
10886 | |
10887 // Helper functions for wrapping and unwrapping stack frame ids. | |
10888 static Smi* WrapFrameId(StackFrame::Id id) { | |
10889 DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); | |
10890 return Smi::FromInt(id >> 2); | |
10891 } | |
10892 | |
10893 | |
10894 static StackFrame::Id UnwrapFrameId(int wrapped) { | |
10895 return static_cast<StackFrame::Id>(wrapped << 2); | |
10896 } | |
10897 | |
10898 | |
10899 // Adds a JavaScript function as a debug event listener. | |
10900 // args[0]: debug event listener function to set or null or undefined for | |
10901 // clearing the event listener function | |
10902 // args[1]: object supplied during callback | |
10903 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { | |
10904 SealHandleScope shs(isolate); | |
10905 DCHECK(args.length() == 2); | |
10906 RUNTIME_ASSERT(args[0]->IsJSFunction() || | |
10907 args[0]->IsUndefined() || | |
10908 args[0]->IsNull()); | |
10909 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); | |
10910 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); | |
10911 isolate->debug()->SetEventListener(callback, data); | |
10912 | |
10913 return isolate->heap()->undefined_value(); | |
10914 } | |
10915 | |
10916 | |
10917 RUNTIME_FUNCTION(Runtime_Break) { | |
10918 SealHandleScope shs(isolate); | |
10919 DCHECK(args.length() == 0); | |
10920 isolate->stack_guard()->RequestDebugBreak(); | |
10921 return isolate->heap()->undefined_value(); | |
10922 } | |
10923 | |
10924 | |
10925 static Handle<Object> DebugGetProperty(LookupIterator* it, | |
10926 bool* has_caught = NULL) { | |
10927 for (; it->IsFound(); it->Next()) { | |
10928 switch (it->state()) { | |
10929 case LookupIterator::NOT_FOUND: | |
10930 case LookupIterator::TRANSITION: | |
10931 UNREACHABLE(); | |
10932 case LookupIterator::ACCESS_CHECK: | |
10933 // Ignore access checks. | |
10934 break; | |
10935 case LookupIterator::INTERCEPTOR: | |
10936 case LookupIterator::JSPROXY: | |
10937 return it->isolate()->factory()->undefined_value(); | |
10938 case LookupIterator::ACCESSOR: { | |
10939 Handle<Object> accessors = it->GetAccessors(); | |
10940 if (!accessors->IsAccessorInfo()) { | |
10941 return it->isolate()->factory()->undefined_value(); | |
10942 } | |
10943 MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor( | |
10944 it->GetReceiver(), it->name(), it->GetHolder<JSObject>(), | |
10945 accessors); | |
10946 Handle<Object> result; | |
10947 if (!maybe_result.ToHandle(&result)) { | |
10948 result = handle(it->isolate()->pending_exception(), it->isolate()); | |
10949 it->isolate()->clear_pending_exception(); | |
10950 if (has_caught != NULL) *has_caught = true; | |
10951 } | |
10952 return result; | |
10953 } | |
10954 | |
10955 case LookupIterator::DATA: | |
10956 return it->GetDataValue(); | |
10957 } | |
10958 } | |
10959 | |
10960 return it->isolate()->factory()->undefined_value(); | |
10961 } | |
10962 | |
10963 | |
10964 // Get debugger related details for an object property, in the following format: | |
10965 // 0: Property value | |
10966 // 1: Property details | |
10967 // 2: Property value is exception | |
10968 // 3: Getter function if defined | |
10969 // 4: Setter function if defined | |
10970 // Items 2-4 are only filled if the property has either a getter or a setter. | |
10971 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { | |
10972 HandleScope scope(isolate); | |
10973 | |
10974 DCHECK(args.length() == 2); | |
10975 | |
10976 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
10977 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
10978 | |
10979 // Make sure to set the current context to the context before the debugger was | |
10980 // entered (if the debugger is entered). The reason for switching context here | |
10981 // is that for some property lookups (accessors and interceptors) callbacks | |
10982 // into the embedding application can occour, and the embedding application | |
10983 // could have the assumption that its own native context is the current | |
10984 // context and not some internal debugger context. | |
10985 SaveContext save(isolate); | |
10986 if (isolate->debug()->in_debug_scope()) { | |
10987 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); | |
10988 } | |
10989 | |
10990 // Check if the name is trivially convertible to an index and get the element | |
10991 // if so. | |
10992 uint32_t index; | |
10993 if (name->AsArrayIndex(&index)) { | |
10994 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); | |
10995 Handle<Object> element_or_char; | |
10996 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
10997 isolate, element_or_char, | |
10998 Runtime::GetElementOrCharAt(isolate, obj, index)); | |
10999 details->set(0, *element_or_char); | |
11000 details->set( | |
11001 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); | |
11002 return *isolate->factory()->NewJSArrayWithElements(details); | |
11003 } | |
11004 | |
11005 LookupIterator it(obj, name, LookupIterator::HIDDEN); | |
11006 bool has_caught = false; | |
11007 Handle<Object> value = DebugGetProperty(&it, &has_caught); | |
11008 if (!it.IsFound()) return isolate->heap()->undefined_value(); | |
11009 | |
11010 Handle<Object> maybe_pair; | |
11011 if (it.state() == LookupIterator::ACCESSOR) { | |
11012 maybe_pair = it.GetAccessors(); | |
11013 } | |
11014 | |
11015 // If the callback object is a fixed array then it contains JavaScript | |
11016 // getter and/or setter. | |
11017 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair(); | |
11018 Handle<FixedArray> details = | |
11019 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3); | |
11020 details->set(0, *value); | |
11021 // TODO(verwaest): Get rid of this random way of handling interceptors. | |
11022 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR | |
11023 ? PropertyDetails(NONE, NORMAL, 0) | |
11024 : it.property_details(); | |
11025 details->set(1, d.AsSmi()); | |
11026 details->set( | |
11027 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR)); | |
11028 if (has_js_accessors) { | |
11029 AccessorPair* accessors = AccessorPair::cast(*maybe_pair); | |
11030 details->set(3, isolate->heap()->ToBoolean(has_caught)); | |
11031 details->set(4, accessors->GetComponent(ACCESSOR_GETTER)); | |
11032 details->set(5, accessors->GetComponent(ACCESSOR_SETTER)); | |
11033 } | |
11034 | |
11035 return *isolate->factory()->NewJSArrayWithElements(details); | |
11036 } | |
11037 | |
11038 | |
11039 RUNTIME_FUNCTION(Runtime_DebugGetProperty) { | |
11040 HandleScope scope(isolate); | |
11041 | |
11042 DCHECK(args.length() == 2); | |
11043 | |
11044 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
11045 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
11046 | |
11047 LookupIterator it(obj, name); | |
11048 return *DebugGetProperty(&it); | |
11049 } | |
11050 | |
11051 | |
11052 // Return the property type calculated from the property details. | |
11053 // args[0]: smi with property details. | |
11054 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) { | |
11055 SealHandleScope shs(isolate); | |
11056 DCHECK(args.length() == 1); | |
11057 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
11058 return Smi::FromInt(static_cast<int>(details.type())); | |
11059 } | |
11060 | |
11061 | |
11062 // Return the property attribute calculated from the property details. | |
11063 // args[0]: smi with property details. | |
11064 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { | |
11065 SealHandleScope shs(isolate); | |
11066 DCHECK(args.length() == 1); | |
11067 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
11068 return Smi::FromInt(static_cast<int>(details.attributes())); | |
11069 } | |
11070 | |
11071 | |
11072 // Return the property insertion index calculated from the property details. | |
11073 // args[0]: smi with property details. | |
11074 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) { | |
11075 SealHandleScope shs(isolate); | |
11076 DCHECK(args.length() == 1); | |
11077 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
11078 // TODO(verwaest): Depends on the type of details. | |
11079 return Smi::FromInt(details.dictionary_index()); | |
11080 } | |
11081 | |
11082 | |
11083 // Return property value from named interceptor. | |
11084 // args[0]: object | |
11085 // args[1]: property name | |
11086 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { | |
11087 HandleScope scope(isolate); | |
11088 DCHECK(args.length() == 2); | |
11089 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
11090 RUNTIME_ASSERT(obj->HasNamedInterceptor()); | |
11091 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
11092 | |
11093 Handle<Object> result; | |
11094 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
11095 isolate, result, JSObject::GetProperty(obj, name)); | |
11096 return *result; | |
11097 } | |
11098 | |
11099 | |
11100 // Return element value from indexed interceptor. | |
11101 // args[0]: object | |
11102 // args[1]: index | |
11103 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) { | |
11104 HandleScope scope(isolate); | |
11105 DCHECK(args.length() == 2); | |
11106 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
11107 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); | |
11108 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); | |
11109 Handle<Object> result; | |
11110 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
11111 isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index)); | |
11112 return *result; | |
11113 } | |
11114 | |
11115 | |
11116 static bool CheckExecutionState(Isolate* isolate, int break_id) { | |
11117 return !isolate->debug()->debug_context().is_null() && | |
11118 isolate->debug()->break_id() != 0 && | |
11119 isolate->debug()->break_id() == break_id; | |
11120 } | |
11121 | |
11122 | |
11123 RUNTIME_FUNCTION(Runtime_CheckExecutionState) { | |
11124 SealHandleScope shs(isolate); | |
11125 DCHECK(args.length() == 1); | |
11126 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
11127 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
11128 return isolate->heap()->true_value(); | |
11129 } | |
11130 | |
11131 | |
11132 RUNTIME_FUNCTION(Runtime_GetFrameCount) { | |
11133 HandleScope scope(isolate); | |
11134 DCHECK(args.length() == 1); | |
11135 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
11136 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
11137 | |
11138 // Count all frames which are relevant to debugging stack trace. | |
11139 int n = 0; | |
11140 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
11141 if (id == StackFrame::NO_ID) { | |
11142 // If there is no JavaScript stack frame count is 0. | |
11143 return Smi::FromInt(0); | |
11144 } | |
11145 | |
11146 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { | |
11147 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
11148 it.frame()->Summarize(&frames); | |
11149 for (int i = frames.length() - 1; i >= 0; i--) { | |
11150 // Omit functions from native scripts. | |
11151 if (!frames[i].function()->IsFromNativeScript()) n++; | |
11152 } | |
11153 } | |
11154 return Smi::FromInt(n); | |
11155 } | |
11156 | |
11157 | |
11158 class FrameInspector { | |
11159 public: | |
11160 FrameInspector(JavaScriptFrame* frame, | |
11161 int inlined_jsframe_index, | |
11162 Isolate* isolate) | |
11163 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { | |
11164 // Calculate the deoptimized frame. | |
11165 if (frame->is_optimized()) { | |
11166 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( | |
11167 frame, inlined_jsframe_index, isolate); | |
11168 } | |
11169 has_adapted_arguments_ = frame_->has_adapted_arguments(); | |
11170 is_bottommost_ = inlined_jsframe_index == 0; | |
11171 is_optimized_ = frame_->is_optimized(); | |
11172 } | |
11173 | |
11174 ~FrameInspector() { | |
11175 // Get rid of the calculated deoptimized frame if any. | |
11176 if (deoptimized_frame_ != NULL) { | |
11177 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, | |
11178 isolate_); | |
11179 } | |
11180 } | |
11181 | |
11182 int GetParametersCount() { | |
11183 return is_optimized_ | |
11184 ? deoptimized_frame_->parameters_count() | |
11185 : frame_->ComputeParametersCount(); | |
11186 } | |
11187 int expression_count() { return deoptimized_frame_->expression_count(); } | |
11188 Object* GetFunction() { | |
11189 return is_optimized_ | |
11190 ? deoptimized_frame_->GetFunction() | |
11191 : frame_->function(); | |
11192 } | |
11193 Object* GetParameter(int index) { | |
11194 return is_optimized_ | |
11195 ? deoptimized_frame_->GetParameter(index) | |
11196 : frame_->GetParameter(index); | |
11197 } | |
11198 Object* GetExpression(int index) { | |
11199 return is_optimized_ | |
11200 ? deoptimized_frame_->GetExpression(index) | |
11201 : frame_->GetExpression(index); | |
11202 } | |
11203 int GetSourcePosition() { | |
11204 return is_optimized_ | |
11205 ? deoptimized_frame_->GetSourcePosition() | |
11206 : frame_->LookupCode()->SourcePosition(frame_->pc()); | |
11207 } | |
11208 bool IsConstructor() { | |
11209 return is_optimized_ && !is_bottommost_ | |
11210 ? deoptimized_frame_->HasConstructStub() | |
11211 : frame_->IsConstructor(); | |
11212 } | |
11213 Object* GetContext() { | |
11214 return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context(); | |
11215 } | |
11216 | |
11217 // To inspect all the provided arguments the frame might need to be | |
11218 // replaced with the arguments frame. | |
11219 void SetArgumentsFrame(JavaScriptFrame* frame) { | |
11220 DCHECK(has_adapted_arguments_); | |
11221 frame_ = frame; | |
11222 is_optimized_ = frame_->is_optimized(); | |
11223 DCHECK(!is_optimized_); | |
11224 } | |
11225 | |
11226 private: | |
11227 JavaScriptFrame* frame_; | |
11228 DeoptimizedFrameInfo* deoptimized_frame_; | |
11229 Isolate* isolate_; | |
11230 bool is_optimized_; | |
11231 bool is_bottommost_; | |
11232 bool has_adapted_arguments_; | |
11233 | |
11234 DISALLOW_COPY_AND_ASSIGN(FrameInspector); | |
11235 }; | |
11236 | |
11237 | |
11238 static const int kFrameDetailsFrameIdIndex = 0; | |
11239 static const int kFrameDetailsReceiverIndex = 1; | |
11240 static const int kFrameDetailsFunctionIndex = 2; | |
11241 static const int kFrameDetailsArgumentCountIndex = 3; | |
11242 static const int kFrameDetailsLocalCountIndex = 4; | |
11243 static const int kFrameDetailsSourcePositionIndex = 5; | |
11244 static const int kFrameDetailsConstructCallIndex = 6; | |
11245 static const int kFrameDetailsAtReturnIndex = 7; | |
11246 static const int kFrameDetailsFlagsIndex = 8; | |
11247 static const int kFrameDetailsFirstDynamicIndex = 9; | |
11248 | |
11249 | |
11250 static SaveContext* FindSavedContextForFrame(Isolate* isolate, | |
11251 JavaScriptFrame* frame) { | |
11252 SaveContext* save = isolate->save_context(); | |
11253 while (save != NULL && !save->IsBelowFrame(frame)) { | |
11254 save = save->prev(); | |
11255 } | |
11256 DCHECK(save != NULL); | |
11257 return save; | |
11258 } | |
11259 | |
11260 | |
11261 // Advances the iterator to the frame that matches the index and returns the | |
11262 // inlined frame index, or -1 if not found. Skips native JS functions. | |
11263 static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) { | |
11264 int count = -1; | |
11265 for (; !it->done(); it->Advance()) { | |
11266 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
11267 it->frame()->Summarize(&frames); | |
11268 for (int i = frames.length() - 1; i >= 0; i--) { | |
11269 // Omit functions from native scripts. | |
11270 if (frames[i].function()->IsFromNativeScript()) continue; | |
11271 if (++count == index) return i; | |
11272 } | |
11273 } | |
11274 return -1; | |
11275 } | |
11276 | |
11277 | |
11278 // Return an array with frame details | |
11279 // args[0]: number: break id | |
11280 // args[1]: number: frame index | |
11281 // | |
11282 // The array returned contains the following information: | |
11283 // 0: Frame id | |
11284 // 1: Receiver | |
11285 // 2: Function | |
11286 // 3: Argument count | |
11287 // 4: Local count | |
11288 // 5: Source position | |
11289 // 6: Constructor call | |
11290 // 7: Is at return | |
11291 // 8: Flags | |
11292 // Arguments name, value | |
11293 // Locals name, value | |
11294 // Return value if any | |
11295 RUNTIME_FUNCTION(Runtime_GetFrameDetails) { | |
11296 HandleScope scope(isolate); | |
11297 DCHECK(args.length() == 2); | |
11298 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
11299 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
11300 | |
11301 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
11302 Heap* heap = isolate->heap(); | |
11303 | |
11304 // Find the relevant frame with the requested index. | |
11305 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
11306 if (id == StackFrame::NO_ID) { | |
11307 // If there are no JavaScript stack frames return undefined. | |
11308 return heap->undefined_value(); | |
11309 } | |
11310 | |
11311 JavaScriptFrameIterator it(isolate, id); | |
11312 // Inlined frame index in optimized frame, starting from outer function. | |
11313 int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index); | |
11314 if (inlined_jsframe_index == -1) return heap->undefined_value(); | |
11315 | |
11316 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); | |
11317 bool is_optimized = it.frame()->is_optimized(); | |
11318 | |
11319 // Traverse the saved contexts chain to find the active context for the | |
11320 // selected frame. | |
11321 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); | |
11322 | |
11323 // Get the frame id. | |
11324 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); | |
11325 | |
11326 // Find source position in unoptimized code. | |
11327 int position = frame_inspector.GetSourcePosition(); | |
11328 | |
11329 // Check for constructor frame. | |
11330 bool constructor = frame_inspector.IsConstructor(); | |
11331 | |
11332 // Get scope info and read from it for local variable information. | |
11333 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
11334 Handle<SharedFunctionInfo> shared(function->shared()); | |
11335 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11336 DCHECK(*scope_info != ScopeInfo::Empty(isolate)); | |
11337 | |
11338 // Get the locals names and values into a temporary array. | |
11339 int local_count = scope_info->LocalCount(); | |
11340 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { | |
11341 // Hide compiler-introduced temporary variables, whether on the stack or on | |
11342 // the context. | |
11343 if (scope_info->LocalIsSynthetic(slot)) | |
11344 local_count--; | |
11345 } | |
11346 | |
11347 Handle<FixedArray> locals = | |
11348 isolate->factory()->NewFixedArray(local_count * 2); | |
11349 | |
11350 // Fill in the values of the locals. | |
11351 int local = 0; | |
11352 int i = 0; | |
11353 for (; i < scope_info->StackLocalCount(); ++i) { | |
11354 // Use the value from the stack. | |
11355 if (scope_info->LocalIsSynthetic(i)) | |
11356 continue; | |
11357 locals->set(local * 2, scope_info->LocalName(i)); | |
11358 locals->set(local * 2 + 1, frame_inspector.GetExpression(i)); | |
11359 local++; | |
11360 } | |
11361 if (local < local_count) { | |
11362 // Get the context containing declarations. | |
11363 Handle<Context> context( | |
11364 Context::cast(frame_inspector.GetContext())->declaration_context()); | |
11365 for (; i < scope_info->LocalCount(); ++i) { | |
11366 if (scope_info->LocalIsSynthetic(i)) | |
11367 continue; | |
11368 Handle<String> name(scope_info->LocalName(i)); | |
11369 VariableMode mode; | |
11370 InitializationFlag init_flag; | |
11371 MaybeAssignedFlag maybe_assigned_flag; | |
11372 locals->set(local * 2, *name); | |
11373 int context_slot_index = ScopeInfo::ContextSlotIndex( | |
11374 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); | |
11375 Object* value = context->get(context_slot_index); | |
11376 locals->set(local * 2 + 1, value); | |
11377 local++; | |
11378 } | |
11379 } | |
11380 | |
11381 // Check whether this frame is positioned at return. If not top | |
11382 // frame or if the frame is optimized it cannot be at a return. | |
11383 bool at_return = false; | |
11384 if (!is_optimized && index == 0) { | |
11385 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); | |
11386 } | |
11387 | |
11388 // If positioned just before return find the value to be returned and add it | |
11389 // to the frame information. | |
11390 Handle<Object> return_value = isolate->factory()->undefined_value(); | |
11391 if (at_return) { | |
11392 StackFrameIterator it2(isolate); | |
11393 Address internal_frame_sp = NULL; | |
11394 while (!it2.done()) { | |
11395 if (it2.frame()->is_internal()) { | |
11396 internal_frame_sp = it2.frame()->sp(); | |
11397 } else { | |
11398 if (it2.frame()->is_java_script()) { | |
11399 if (it2.frame()->id() == it.frame()->id()) { | |
11400 // The internal frame just before the JavaScript frame contains the | |
11401 // value to return on top. A debug break at return will create an | |
11402 // internal frame to store the return value (eax/rax/r0) before | |
11403 // entering the debug break exit frame. | |
11404 if (internal_frame_sp != NULL) { | |
11405 return_value = | |
11406 Handle<Object>(Memory::Object_at(internal_frame_sp), | |
11407 isolate); | |
11408 break; | |
11409 } | |
11410 } | |
11411 } | |
11412 | |
11413 // Indicate that the previous frame was not an internal frame. | |
11414 internal_frame_sp = NULL; | |
11415 } | |
11416 it2.Advance(); | |
11417 } | |
11418 } | |
11419 | |
11420 // Now advance to the arguments adapter frame (if any). It contains all | |
11421 // the provided parameters whereas the function frame always have the number | |
11422 // of arguments matching the functions parameters. The rest of the | |
11423 // information (except for what is collected above) is the same. | |
11424 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { | |
11425 it.AdvanceToArgumentsFrame(); | |
11426 frame_inspector.SetArgumentsFrame(it.frame()); | |
11427 } | |
11428 | |
11429 // Find the number of arguments to fill. At least fill the number of | |
11430 // parameters for the function and fill more if more parameters are provided. | |
11431 int argument_count = scope_info->ParameterCount(); | |
11432 if (argument_count < frame_inspector.GetParametersCount()) { | |
11433 argument_count = frame_inspector.GetParametersCount(); | |
11434 } | |
11435 | |
11436 // Calculate the size of the result. | |
11437 int details_size = kFrameDetailsFirstDynamicIndex + | |
11438 2 * (argument_count + local_count) + | |
11439 (at_return ? 1 : 0); | |
11440 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | |
11441 | |
11442 // Add the frame id. | |
11443 details->set(kFrameDetailsFrameIdIndex, *frame_id); | |
11444 | |
11445 // Add the function (same as in function frame). | |
11446 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); | |
11447 | |
11448 // Add the arguments count. | |
11449 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); | |
11450 | |
11451 // Add the locals count | |
11452 details->set(kFrameDetailsLocalCountIndex, | |
11453 Smi::FromInt(local_count)); | |
11454 | |
11455 // Add the source position. | |
11456 if (position != RelocInfo::kNoPosition) { | |
11457 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); | |
11458 } else { | |
11459 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); | |
11460 } | |
11461 | |
11462 // Add the constructor information. | |
11463 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); | |
11464 | |
11465 // Add the at return information. | |
11466 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); | |
11467 | |
11468 // Add flags to indicate information on whether this frame is | |
11469 // bit 0: invoked in the debugger context. | |
11470 // bit 1: optimized frame. | |
11471 // bit 2: inlined in optimized frame | |
11472 int flags = 0; | |
11473 if (*save->context() == *isolate->debug()->debug_context()) { | |
11474 flags |= 1 << 0; | |
11475 } | |
11476 if (is_optimized) { | |
11477 flags |= 1 << 1; | |
11478 flags |= inlined_jsframe_index << 2; | |
11479 } | |
11480 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); | |
11481 | |
11482 // Fill the dynamic part. | |
11483 int details_index = kFrameDetailsFirstDynamicIndex; | |
11484 | |
11485 // Add arguments name and value. | |
11486 for (int i = 0; i < argument_count; i++) { | |
11487 // Name of the argument. | |
11488 if (i < scope_info->ParameterCount()) { | |
11489 details->set(details_index++, scope_info->ParameterName(i)); | |
11490 } else { | |
11491 details->set(details_index++, heap->undefined_value()); | |
11492 } | |
11493 | |
11494 // Parameter value. | |
11495 if (i < frame_inspector.GetParametersCount()) { | |
11496 // Get the value from the stack. | |
11497 details->set(details_index++, frame_inspector.GetParameter(i)); | |
11498 } else { | |
11499 details->set(details_index++, heap->undefined_value()); | |
11500 } | |
11501 } | |
11502 | |
11503 // Add locals name and value from the temporary copy from the function frame. | |
11504 for (int i = 0; i < local_count * 2; i++) { | |
11505 details->set(details_index++, locals->get(i)); | |
11506 } | |
11507 | |
11508 // Add the value being returned. | |
11509 if (at_return) { | |
11510 details->set(details_index++, *return_value); | |
11511 } | |
11512 | |
11513 // Add the receiver (same as in function frame). | |
11514 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE | |
11515 // THE FRAME ITERATOR TO WRAP THE RECEIVER. | |
11516 Handle<Object> receiver(it.frame()->receiver(), isolate); | |
11517 if (!receiver->IsJSObject() && | |
11518 shared->strict_mode() == SLOPPY && | |
11519 !function->IsBuiltin()) { | |
11520 // If the receiver is not a JSObject and the function is not a | |
11521 // builtin or strict-mode we have hit an optimization where a | |
11522 // value object is not converted into a wrapped JS objects. To | |
11523 // hide this optimization from the debugger, we wrap the receiver | |
11524 // by creating correct wrapper object based on the calling frame's | |
11525 // native context. | |
11526 it.Advance(); | |
11527 if (receiver->IsUndefined()) { | |
11528 receiver = handle(function->global_proxy()); | |
11529 } else { | |
11530 Context* context = Context::cast(it.frame()->context()); | |
11531 Handle<Context> native_context(Context::cast(context->native_context())); | |
11532 if (!Object::ToObject(isolate, receiver, native_context) | |
11533 .ToHandle(&receiver)) { | |
11534 // This only happens if the receiver is forcibly set in %_CallFunction. | |
11535 return heap->undefined_value(); | |
11536 } | |
11537 } | |
11538 } | |
11539 details->set(kFrameDetailsReceiverIndex, *receiver); | |
11540 | |
11541 DCHECK_EQ(details_size, details_index); | |
11542 return *isolate->factory()->NewJSArrayWithElements(details); | |
11543 } | |
11544 | |
11545 | |
11546 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info, | |
11547 Handle<String> parameter_name) { | |
11548 VariableMode mode; | |
11549 InitializationFlag init_flag; | |
11550 MaybeAssignedFlag maybe_assigned_flag; | |
11551 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag, | |
11552 &maybe_assigned_flag) != -1; | |
11553 } | |
11554 | |
11555 | |
11556 // Create a plain JSObject which materializes the local scope for the specified | |
11557 // frame. | |
11558 MUST_USE_RESULT | |
11559 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( | |
11560 Isolate* isolate, | |
11561 Handle<JSObject> target, | |
11562 Handle<JSFunction> function, | |
11563 FrameInspector* frame_inspector) { | |
11564 Handle<SharedFunctionInfo> shared(function->shared()); | |
11565 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11566 | |
11567 // First fill all parameters. | |
11568 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
11569 // Do not materialize the parameter if it is shadowed by a context local. | |
11570 Handle<String> name(scope_info->ParameterName(i)); | |
11571 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
11572 | |
11573 HandleScope scope(isolate); | |
11574 Handle<Object> value(i < frame_inspector->GetParametersCount() | |
11575 ? frame_inspector->GetParameter(i) | |
11576 : isolate->heap()->undefined_value(), | |
11577 isolate); | |
11578 DCHECK(!value->IsTheHole()); | |
11579 | |
11580 RETURN_ON_EXCEPTION( | |
11581 isolate, | |
11582 Runtime::SetObjectProperty(isolate, target, name, value, SLOPPY), | |
11583 JSObject); | |
11584 } | |
11585 | |
11586 // Second fill all stack locals. | |
11587 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
11588 if (scope_info->LocalIsSynthetic(i)) continue; | |
11589 Handle<String> name(scope_info->StackLocalName(i)); | |
11590 Handle<Object> value(frame_inspector->GetExpression(i), isolate); | |
11591 if (value->IsTheHole()) continue; | |
11592 | |
11593 RETURN_ON_EXCEPTION( | |
11594 isolate, | |
11595 Runtime::SetObjectProperty(isolate, target, name, value, SLOPPY), | |
11596 JSObject); | |
11597 } | |
11598 | |
11599 return target; | |
11600 } | |
11601 | |
11602 | |
11603 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, | |
11604 Handle<JSObject> target, | |
11605 Handle<JSFunction> function, | |
11606 JavaScriptFrame* frame, | |
11607 int inlined_jsframe_index) { | |
11608 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | |
11609 // Optimized frames are not supported. | |
11610 // TODO(yangguo): make sure all code deoptimized when debugger is active | |
11611 // and assert that this cannot happen. | |
11612 return; | |
11613 } | |
11614 | |
11615 Handle<SharedFunctionInfo> shared(function->shared()); | |
11616 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11617 | |
11618 // Parameters. | |
11619 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
11620 // Shadowed parameters were not materialized. | |
11621 Handle<String> name(scope_info->ParameterName(i)); | |
11622 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
11623 | |
11624 DCHECK(!frame->GetParameter(i)->IsTheHole()); | |
11625 HandleScope scope(isolate); | |
11626 Handle<Object> value = | |
11627 Object::GetPropertyOrElement(target, name).ToHandleChecked(); | |
11628 frame->SetParameterValue(i, *value); | |
11629 } | |
11630 | |
11631 // Stack locals. | |
11632 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
11633 if (scope_info->LocalIsSynthetic(i)) continue; | |
11634 if (frame->GetExpression(i)->IsTheHole()) continue; | |
11635 HandleScope scope(isolate); | |
11636 Handle<Object> value = Object::GetPropertyOrElement( | |
11637 target, | |
11638 handle(scope_info->StackLocalName(i), isolate)).ToHandleChecked(); | |
11639 frame->SetExpression(i, *value); | |
11640 } | |
11641 } | |
11642 | |
11643 | |
11644 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( | |
11645 Isolate* isolate, | |
11646 Handle<JSObject> target, | |
11647 Handle<JSFunction> function, | |
11648 JavaScriptFrame* frame) { | |
11649 HandleScope scope(isolate); | |
11650 Handle<SharedFunctionInfo> shared(function->shared()); | |
11651 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11652 | |
11653 if (!scope_info->HasContext()) return target; | |
11654 | |
11655 // Third fill all context locals. | |
11656 Handle<Context> frame_context(Context::cast(frame->context())); | |
11657 Handle<Context> function_context(frame_context->declaration_context()); | |
11658 if (!ScopeInfo::CopyContextLocalsToScopeObject( | |
11659 scope_info, function_context, target)) { | |
11660 return MaybeHandle<JSObject>(); | |
11661 } | |
11662 | |
11663 // Finally copy any properties from the function context extension. | |
11664 // These will be variables introduced by eval. | |
11665 if (function_context->closure() == *function) { | |
11666 if (function_context->has_extension() && | |
11667 !function_context->IsNativeContext()) { | |
11668 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
11669 Handle<FixedArray> keys; | |
11670 ASSIGN_RETURN_ON_EXCEPTION( | |
11671 isolate, keys, | |
11672 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), | |
11673 JSObject); | |
11674 | |
11675 for (int i = 0; i < keys->length(); i++) { | |
11676 // Names of variables introduced by eval are strings. | |
11677 DCHECK(keys->get(i)->IsString()); | |
11678 Handle<String> key(String::cast(keys->get(i))); | |
11679 Handle<Object> value; | |
11680 ASSIGN_RETURN_ON_EXCEPTION( | |
11681 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); | |
11682 RETURN_ON_EXCEPTION( | |
11683 isolate, | |
11684 Runtime::SetObjectProperty(isolate, target, key, value, SLOPPY), | |
11685 JSObject); | |
11686 } | |
11687 } | |
11688 } | |
11689 | |
11690 return target; | |
11691 } | |
11692 | |
11693 | |
11694 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( | |
11695 Isolate* isolate, | |
11696 JavaScriptFrame* frame, | |
11697 int inlined_jsframe_index) { | |
11698 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
11699 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
11700 | |
11701 Handle<JSObject> local_scope = | |
11702 isolate->factory()->NewJSObject(isolate->object_function()); | |
11703 ASSIGN_RETURN_ON_EXCEPTION( | |
11704 isolate, local_scope, | |
11705 MaterializeStackLocalsWithFrameInspector( | |
11706 isolate, local_scope, function, &frame_inspector), | |
11707 JSObject); | |
11708 | |
11709 return MaterializeLocalContext(isolate, local_scope, function, frame); | |
11710 } | |
11711 | |
11712 | |
11713 // Set the context local variable value. | |
11714 static bool SetContextLocalValue(Isolate* isolate, | |
11715 Handle<ScopeInfo> scope_info, | |
11716 Handle<Context> context, | |
11717 Handle<String> variable_name, | |
11718 Handle<Object> new_value) { | |
11719 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { | |
11720 Handle<String> next_name(scope_info->ContextLocalName(i)); | |
11721 if (String::Equals(variable_name, next_name)) { | |
11722 VariableMode mode; | |
11723 InitializationFlag init_flag; | |
11724 MaybeAssignedFlag maybe_assigned_flag; | |
11725 int context_index = ScopeInfo::ContextSlotIndex( | |
11726 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag); | |
11727 context->set(context_index, *new_value); | |
11728 return true; | |
11729 } | |
11730 } | |
11731 | |
11732 return false; | |
11733 } | |
11734 | |
11735 | |
11736 static bool SetLocalVariableValue(Isolate* isolate, | |
11737 JavaScriptFrame* frame, | |
11738 int inlined_jsframe_index, | |
11739 Handle<String> variable_name, | |
11740 Handle<Object> new_value) { | |
11741 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | |
11742 // Optimized frames are not supported. | |
11743 return false; | |
11744 } | |
11745 | |
11746 Handle<JSFunction> function(frame->function()); | |
11747 Handle<SharedFunctionInfo> shared(function->shared()); | |
11748 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11749 | |
11750 bool default_result = false; | |
11751 | |
11752 // Parameters. | |
11753 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
11754 HandleScope scope(isolate); | |
11755 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { | |
11756 frame->SetParameterValue(i, *new_value); | |
11757 // Argument might be shadowed in heap context, don't stop here. | |
11758 default_result = true; | |
11759 } | |
11760 } | |
11761 | |
11762 // Stack locals. | |
11763 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
11764 HandleScope scope(isolate); | |
11765 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { | |
11766 frame->SetExpression(i, *new_value); | |
11767 return true; | |
11768 } | |
11769 } | |
11770 | |
11771 if (scope_info->HasContext()) { | |
11772 // Context locals. | |
11773 Handle<Context> frame_context(Context::cast(frame->context())); | |
11774 Handle<Context> function_context(frame_context->declaration_context()); | |
11775 if (SetContextLocalValue( | |
11776 isolate, scope_info, function_context, variable_name, new_value)) { | |
11777 return true; | |
11778 } | |
11779 | |
11780 // Function context extension. These are variables introduced by eval. | |
11781 if (function_context->closure() == *function) { | |
11782 if (function_context->has_extension() && | |
11783 !function_context->IsNativeContext()) { | |
11784 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
11785 | |
11786 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name); | |
11787 DCHECK(maybe.has_value); | |
11788 if (maybe.value) { | |
11789 // We don't expect this to do anything except replacing | |
11790 // property value. | |
11791 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, | |
11792 SLOPPY).Assert(); | |
11793 return true; | |
11794 } | |
11795 } | |
11796 } | |
11797 } | |
11798 | |
11799 return default_result; | |
11800 } | |
11801 | |
11802 | |
11803 // Create a plain JSObject which materializes the closure content for the | |
11804 // context. | |
11805 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( | |
11806 Isolate* isolate, | |
11807 Handle<Context> context) { | |
11808 DCHECK(context->IsFunctionContext()); | |
11809 | |
11810 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
11811 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11812 | |
11813 // Allocate and initialize a JSObject with all the content of this function | |
11814 // closure. | |
11815 Handle<JSObject> closure_scope = | |
11816 isolate->factory()->NewJSObject(isolate->object_function()); | |
11817 | |
11818 // Fill all context locals to the context extension. | |
11819 if (!ScopeInfo::CopyContextLocalsToScopeObject( | |
11820 scope_info, context, closure_scope)) { | |
11821 return MaybeHandle<JSObject>(); | |
11822 } | |
11823 | |
11824 // Finally copy any properties from the function context extension. This will | |
11825 // be variables introduced by eval. | |
11826 if (context->has_extension()) { | |
11827 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
11828 Handle<FixedArray> keys; | |
11829 ASSIGN_RETURN_ON_EXCEPTION( | |
11830 isolate, keys, | |
11831 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), JSObject); | |
11832 | |
11833 for (int i = 0; i < keys->length(); i++) { | |
11834 HandleScope scope(isolate); | |
11835 // Names of variables introduced by eval are strings. | |
11836 DCHECK(keys->get(i)->IsString()); | |
11837 Handle<String> key(String::cast(keys->get(i))); | |
11838 Handle<Object> value; | |
11839 ASSIGN_RETURN_ON_EXCEPTION( | |
11840 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); | |
11841 RETURN_ON_EXCEPTION( | |
11842 isolate, | |
11843 Runtime::DefineObjectProperty(closure_scope, key, value, NONE), | |
11844 JSObject); | |
11845 } | |
11846 } | |
11847 | |
11848 return closure_scope; | |
11849 } | |
11850 | |
11851 | |
11852 // This method copies structure of MaterializeClosure method above. | |
11853 static bool SetClosureVariableValue(Isolate* isolate, | |
11854 Handle<Context> context, | |
11855 Handle<String> variable_name, | |
11856 Handle<Object> new_value) { | |
11857 DCHECK(context->IsFunctionContext()); | |
11858 | |
11859 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
11860 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
11861 | |
11862 // Context locals to the context extension. | |
11863 if (SetContextLocalValue( | |
11864 isolate, scope_info, context, variable_name, new_value)) { | |
11865 return true; | |
11866 } | |
11867 | |
11868 // Properties from the function context extension. This will | |
11869 // be variables introduced by eval. | |
11870 if (context->has_extension()) { | |
11871 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
11872 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name); | |
11873 DCHECK(maybe.has_value); | |
11874 if (maybe.value) { | |
11875 // We don't expect this to do anything except replacing property value. | |
11876 Runtime::DefineObjectProperty( | |
11877 ext, variable_name, new_value, NONE).Assert(); | |
11878 return true; | |
11879 } | |
11880 } | |
11881 | |
11882 return false; | |
11883 } | |
11884 | |
11885 | |
11886 // Create a plain JSObject which materializes the scope for the specified | |
11887 // catch context. | |
11888 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope( | |
11889 Isolate* isolate, | |
11890 Handle<Context> context) { | |
11891 DCHECK(context->IsCatchContext()); | |
11892 Handle<String> name(String::cast(context->extension())); | |
11893 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), | |
11894 isolate); | |
11895 Handle<JSObject> catch_scope = | |
11896 isolate->factory()->NewJSObject(isolate->object_function()); | |
11897 RETURN_ON_EXCEPTION( | |
11898 isolate, | |
11899 Runtime::DefineObjectProperty(catch_scope, name, thrown_object, NONE), | |
11900 JSObject); | |
11901 return catch_scope; | |
11902 } | |
11903 | |
11904 | |
11905 static bool SetCatchVariableValue(Isolate* isolate, | |
11906 Handle<Context> context, | |
11907 Handle<String> variable_name, | |
11908 Handle<Object> new_value) { | |
11909 DCHECK(context->IsCatchContext()); | |
11910 Handle<String> name(String::cast(context->extension())); | |
11911 if (!String::Equals(name, variable_name)) { | |
11912 return false; | |
11913 } | |
11914 context->set(Context::THROWN_OBJECT_INDEX, *new_value); | |
11915 return true; | |
11916 } | |
11917 | |
11918 | |
11919 // Create a plain JSObject which materializes the block scope for the specified | |
11920 // block context. | |
11921 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( | |
11922 Isolate* isolate, | |
11923 Handle<Context> context) { | |
11924 DCHECK(context->IsBlockContext()); | |
11925 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
11926 | |
11927 // Allocate and initialize a JSObject with all the arguments, stack locals | |
11928 // heap locals and extension properties of the debugged function. | |
11929 Handle<JSObject> block_scope = | |
11930 isolate->factory()->NewJSObject(isolate->object_function()); | |
11931 | |
11932 // Fill all context locals. | |
11933 if (!ScopeInfo::CopyContextLocalsToScopeObject( | |
11934 scope_info, context, block_scope)) { | |
11935 return MaybeHandle<JSObject>(); | |
11936 } | |
11937 | |
11938 return block_scope; | |
11939 } | |
11940 | |
11941 | |
11942 // Create a plain JSObject which materializes the module scope for the specified | |
11943 // module context. | |
11944 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( | |
11945 Isolate* isolate, | |
11946 Handle<Context> context) { | |
11947 DCHECK(context->IsModuleContext()); | |
11948 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
11949 | |
11950 // Allocate and initialize a JSObject with all the members of the debugged | |
11951 // module. | |
11952 Handle<JSObject> module_scope = | |
11953 isolate->factory()->NewJSObject(isolate->object_function()); | |
11954 | |
11955 // Fill all context locals. | |
11956 if (!ScopeInfo::CopyContextLocalsToScopeObject( | |
11957 scope_info, context, module_scope)) { | |
11958 return MaybeHandle<JSObject>(); | |
11959 } | |
11960 | |
11961 return module_scope; | |
11962 } | |
11963 | |
11964 | |
11965 // Iterate over the actual scopes visible from a stack frame or from a closure. | |
11966 // The iteration proceeds from the innermost visible nested scope outwards. | |
11967 // All scopes are backed by an actual context except the local scope, | |
11968 // which is inserted "artificially" in the context chain. | |
11969 class ScopeIterator { | |
11970 public: | |
11971 enum ScopeType { | |
11972 ScopeTypeGlobal = 0, | |
11973 ScopeTypeLocal, | |
11974 ScopeTypeWith, | |
11975 ScopeTypeClosure, | |
11976 ScopeTypeCatch, | |
11977 ScopeTypeBlock, | |
11978 ScopeTypeModule | |
11979 }; | |
11980 | |
11981 ScopeIterator(Isolate* isolate, | |
11982 JavaScriptFrame* frame, | |
11983 int inlined_jsframe_index, | |
11984 bool ignore_nested_scopes = false) | |
11985 : isolate_(isolate), | |
11986 frame_(frame), | |
11987 inlined_jsframe_index_(inlined_jsframe_index), | |
11988 function_(frame->function()), | |
11989 context_(Context::cast(frame->context())), | |
11990 nested_scope_chain_(4), | |
11991 failed_(false) { | |
11992 | |
11993 // Catch the case when the debugger stops in an internal function. | |
11994 Handle<SharedFunctionInfo> shared_info(function_->shared()); | |
11995 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
11996 if (shared_info->script() == isolate->heap()->undefined_value()) { | |
11997 while (context_->closure() == *function_) { | |
11998 context_ = Handle<Context>(context_->previous(), isolate_); | |
11999 } | |
12000 return; | |
12001 } | |
12002 | |
12003 // Get the debug info (create it if it does not exist). | |
12004 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) { | |
12005 // Return if ensuring debug info failed. | |
12006 return; | |
12007 } | |
12008 | |
12009 // Currently it takes too much time to find nested scopes due to script | |
12010 // parsing. Sometimes we want to run the ScopeIterator as fast as possible | |
12011 // (for example, while collecting async call stacks on every | |
12012 // addEventListener call), even if we drop some nested scopes. | |
12013 // Later we may optimize getting the nested scopes (cache the result?) | |
12014 // and include nested scopes into the "fast" iteration case as well. | |
12015 if (!ignore_nested_scopes) { | |
12016 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); | |
12017 | |
12018 // Find the break point where execution has stopped. | |
12019 BreakLocationIterator break_location_iterator(debug_info, | |
12020 ALL_BREAK_LOCATIONS); | |
12021 // pc points to the instruction after the current one, possibly a break | |
12022 // location as well. So the "- 1" to exclude it from the search. | |
12023 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); | |
12024 | |
12025 // Within the return sequence at the moment it is not possible to | |
12026 // get a source position which is consistent with the current scope chain. | |
12027 // Thus all nested with, catch and block contexts are skipped and we only | |
12028 // provide the function scope. | |
12029 ignore_nested_scopes = break_location_iterator.IsExit(); | |
12030 } | |
12031 | |
12032 if (ignore_nested_scopes) { | |
12033 if (scope_info->HasContext()) { | |
12034 context_ = Handle<Context>(context_->declaration_context(), isolate_); | |
12035 } else { | |
12036 while (context_->closure() == *function_) { | |
12037 context_ = Handle<Context>(context_->previous(), isolate_); | |
12038 } | |
12039 } | |
12040 if (scope_info->scope_type() == FUNCTION_SCOPE) { | |
12041 nested_scope_chain_.Add(scope_info); | |
12042 } | |
12043 } else { | |
12044 // Reparse the code and analyze the scopes. | |
12045 Handle<Script> script(Script::cast(shared_info->script())); | |
12046 Scope* scope = NULL; | |
12047 | |
12048 // Check whether we are in global, eval or function code. | |
12049 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
12050 if (scope_info->scope_type() != FUNCTION_SCOPE) { | |
12051 // Global or eval code. | |
12052 CompilationInfoWithZone info(script); | |
12053 if (scope_info->scope_type() == GLOBAL_SCOPE) { | |
12054 info.MarkAsGlobal(); | |
12055 } else { | |
12056 DCHECK(scope_info->scope_type() == EVAL_SCOPE); | |
12057 info.MarkAsEval(); | |
12058 info.SetContext(Handle<Context>(function_->context())); | |
12059 } | |
12060 if (Parser::Parse(&info) && Scope::Analyze(&info)) { | |
12061 scope = info.function()->scope(); | |
12062 } | |
12063 RetrieveScopeChain(scope, shared_info); | |
12064 } else { | |
12065 // Function code | |
12066 CompilationInfoWithZone info(shared_info); | |
12067 if (Parser::Parse(&info) && Scope::Analyze(&info)) { | |
12068 scope = info.function()->scope(); | |
12069 } | |
12070 RetrieveScopeChain(scope, shared_info); | |
12071 } | |
12072 } | |
12073 } | |
12074 | |
12075 ScopeIterator(Isolate* isolate, | |
12076 Handle<JSFunction> function) | |
12077 : isolate_(isolate), | |
12078 frame_(NULL), | |
12079 inlined_jsframe_index_(0), | |
12080 function_(function), | |
12081 context_(function->context()), | |
12082 failed_(false) { | |
12083 if (function->IsBuiltin()) { | |
12084 context_ = Handle<Context>(); | |
12085 } | |
12086 } | |
12087 | |
12088 // More scopes? | |
12089 bool Done() { | |
12090 DCHECK(!failed_); | |
12091 return context_.is_null(); | |
12092 } | |
12093 | |
12094 bool Failed() { return failed_; } | |
12095 | |
12096 // Move to the next scope. | |
12097 void Next() { | |
12098 DCHECK(!failed_); | |
12099 ScopeType scope_type = Type(); | |
12100 if (scope_type == ScopeTypeGlobal) { | |
12101 // The global scope is always the last in the chain. | |
12102 DCHECK(context_->IsNativeContext()); | |
12103 context_ = Handle<Context>(); | |
12104 return; | |
12105 } | |
12106 if (nested_scope_chain_.is_empty()) { | |
12107 context_ = Handle<Context>(context_->previous(), isolate_); | |
12108 } else { | |
12109 if (nested_scope_chain_.last()->HasContext()) { | |
12110 DCHECK(context_->previous() != NULL); | |
12111 context_ = Handle<Context>(context_->previous(), isolate_); | |
12112 } | |
12113 nested_scope_chain_.RemoveLast(); | |
12114 } | |
12115 } | |
12116 | |
12117 // Return the type of the current scope. | |
12118 ScopeType Type() { | |
12119 DCHECK(!failed_); | |
12120 if (!nested_scope_chain_.is_empty()) { | |
12121 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); | |
12122 switch (scope_info->scope_type()) { | |
12123 case FUNCTION_SCOPE: | |
12124 DCHECK(context_->IsFunctionContext() || | |
12125 !scope_info->HasContext()); | |
12126 return ScopeTypeLocal; | |
12127 case MODULE_SCOPE: | |
12128 DCHECK(context_->IsModuleContext()); | |
12129 return ScopeTypeModule; | |
12130 case GLOBAL_SCOPE: | |
12131 DCHECK(context_->IsNativeContext()); | |
12132 return ScopeTypeGlobal; | |
12133 case WITH_SCOPE: | |
12134 DCHECK(context_->IsWithContext()); | |
12135 return ScopeTypeWith; | |
12136 case CATCH_SCOPE: | |
12137 DCHECK(context_->IsCatchContext()); | |
12138 return ScopeTypeCatch; | |
12139 case BLOCK_SCOPE: | |
12140 DCHECK(!scope_info->HasContext() || | |
12141 context_->IsBlockContext()); | |
12142 return ScopeTypeBlock; | |
12143 case EVAL_SCOPE: | |
12144 UNREACHABLE(); | |
12145 } | |
12146 } | |
12147 if (context_->IsNativeContext()) { | |
12148 DCHECK(context_->global_object()->IsGlobalObject()); | |
12149 return ScopeTypeGlobal; | |
12150 } | |
12151 if (context_->IsFunctionContext()) { | |
12152 return ScopeTypeClosure; | |
12153 } | |
12154 if (context_->IsCatchContext()) { | |
12155 return ScopeTypeCatch; | |
12156 } | |
12157 if (context_->IsBlockContext()) { | |
12158 return ScopeTypeBlock; | |
12159 } | |
12160 if (context_->IsModuleContext()) { | |
12161 return ScopeTypeModule; | |
12162 } | |
12163 DCHECK(context_->IsWithContext()); | |
12164 return ScopeTypeWith; | |
12165 } | |
12166 | |
12167 // Return the JavaScript object with the content of the current scope. | |
12168 MaybeHandle<JSObject> ScopeObject() { | |
12169 DCHECK(!failed_); | |
12170 switch (Type()) { | |
12171 case ScopeIterator::ScopeTypeGlobal: | |
12172 return Handle<JSObject>(CurrentContext()->global_object()); | |
12173 case ScopeIterator::ScopeTypeLocal: | |
12174 // Materialize the content of the local scope into a JSObject. | |
12175 DCHECK(nested_scope_chain_.length() == 1); | |
12176 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); | |
12177 case ScopeIterator::ScopeTypeWith: | |
12178 // Return the with object. | |
12179 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); | |
12180 case ScopeIterator::ScopeTypeCatch: | |
12181 return MaterializeCatchScope(isolate_, CurrentContext()); | |
12182 case ScopeIterator::ScopeTypeClosure: | |
12183 // Materialize the content of the closure scope into a JSObject. | |
12184 return MaterializeClosure(isolate_, CurrentContext()); | |
12185 case ScopeIterator::ScopeTypeBlock: | |
12186 return MaterializeBlockScope(isolate_, CurrentContext()); | |
12187 case ScopeIterator::ScopeTypeModule: | |
12188 return MaterializeModuleScope(isolate_, CurrentContext()); | |
12189 } | |
12190 UNREACHABLE(); | |
12191 return Handle<JSObject>(); | |
12192 } | |
12193 | |
12194 bool SetVariableValue(Handle<String> variable_name, | |
12195 Handle<Object> new_value) { | |
12196 DCHECK(!failed_); | |
12197 switch (Type()) { | |
12198 case ScopeIterator::ScopeTypeGlobal: | |
12199 break; | |
12200 case ScopeIterator::ScopeTypeLocal: | |
12201 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, | |
12202 variable_name, new_value); | |
12203 case ScopeIterator::ScopeTypeWith: | |
12204 break; | |
12205 case ScopeIterator::ScopeTypeCatch: | |
12206 return SetCatchVariableValue(isolate_, CurrentContext(), | |
12207 variable_name, new_value); | |
12208 case ScopeIterator::ScopeTypeClosure: | |
12209 return SetClosureVariableValue(isolate_, CurrentContext(), | |
12210 variable_name, new_value); | |
12211 case ScopeIterator::ScopeTypeBlock: | |
12212 // TODO(2399): should we implement it? | |
12213 break; | |
12214 case ScopeIterator::ScopeTypeModule: | |
12215 // TODO(2399): should we implement it? | |
12216 break; | |
12217 } | |
12218 return false; | |
12219 } | |
12220 | |
12221 Handle<ScopeInfo> CurrentScopeInfo() { | |
12222 DCHECK(!failed_); | |
12223 if (!nested_scope_chain_.is_empty()) { | |
12224 return nested_scope_chain_.last(); | |
12225 } else if (context_->IsBlockContext()) { | |
12226 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); | |
12227 } else if (context_->IsFunctionContext()) { | |
12228 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); | |
12229 } | |
12230 return Handle<ScopeInfo>::null(); | |
12231 } | |
12232 | |
12233 // Return the context for this scope. For the local context there might not | |
12234 // be an actual context. | |
12235 Handle<Context> CurrentContext() { | |
12236 DCHECK(!failed_); | |
12237 if (Type() == ScopeTypeGlobal || | |
12238 nested_scope_chain_.is_empty()) { | |
12239 return context_; | |
12240 } else if (nested_scope_chain_.last()->HasContext()) { | |
12241 return context_; | |
12242 } else { | |
12243 return Handle<Context>(); | |
12244 } | |
12245 } | |
12246 | |
12247 #ifdef DEBUG | |
12248 // Debug print of the content of the current scope. | |
12249 void DebugPrint() { | |
12250 OFStream os(stdout); | |
12251 DCHECK(!failed_); | |
12252 switch (Type()) { | |
12253 case ScopeIterator::ScopeTypeGlobal: | |
12254 os << "Global:\n"; | |
12255 CurrentContext()->Print(os); | |
12256 break; | |
12257 | |
12258 case ScopeIterator::ScopeTypeLocal: { | |
12259 os << "Local:\n"; | |
12260 function_->shared()->scope_info()->Print(); | |
12261 if (!CurrentContext().is_null()) { | |
12262 CurrentContext()->Print(os); | |
12263 if (CurrentContext()->has_extension()) { | |
12264 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
12265 if (extension->IsJSContextExtensionObject()) { | |
12266 extension->Print(os); | |
12267 } | |
12268 } | |
12269 } | |
12270 break; | |
12271 } | |
12272 | |
12273 case ScopeIterator::ScopeTypeWith: | |
12274 os << "With:\n"; | |
12275 CurrentContext()->extension()->Print(os); | |
12276 break; | |
12277 | |
12278 case ScopeIterator::ScopeTypeCatch: | |
12279 os << "Catch:\n"; | |
12280 CurrentContext()->extension()->Print(os); | |
12281 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os); | |
12282 break; | |
12283 | |
12284 case ScopeIterator::ScopeTypeClosure: | |
12285 os << "Closure:\n"; | |
12286 CurrentContext()->Print(os); | |
12287 if (CurrentContext()->has_extension()) { | |
12288 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
12289 if (extension->IsJSContextExtensionObject()) { | |
12290 extension->Print(os); | |
12291 } | |
12292 } | |
12293 break; | |
12294 | |
12295 default: | |
12296 UNREACHABLE(); | |
12297 } | |
12298 PrintF("\n"); | |
12299 } | |
12300 #endif | |
12301 | |
12302 private: | |
12303 Isolate* isolate_; | |
12304 JavaScriptFrame* frame_; | |
12305 int inlined_jsframe_index_; | |
12306 Handle<JSFunction> function_; | |
12307 Handle<Context> context_; | |
12308 List<Handle<ScopeInfo> > nested_scope_chain_; | |
12309 bool failed_; | |
12310 | |
12311 void RetrieveScopeChain(Scope* scope, | |
12312 Handle<SharedFunctionInfo> shared_info) { | |
12313 if (scope != NULL) { | |
12314 int source_position = shared_info->code()->SourcePosition(frame_->pc()); | |
12315 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); | |
12316 } else { | |
12317 // A failed reparse indicates that the preparser has diverged from the | |
12318 // parser or that the preparse data given to the initial parse has been | |
12319 // faulty. We fail in debug mode but in release mode we only provide the | |
12320 // information we get from the context chain but nothing about | |
12321 // completely stack allocated scopes or stack allocated locals. | |
12322 // Or it could be due to stack overflow. | |
12323 DCHECK(isolate_->has_pending_exception()); | |
12324 failed_ = true; | |
12325 } | |
12326 } | |
12327 | |
12328 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); | |
12329 }; | |
12330 | |
12331 | |
12332 RUNTIME_FUNCTION(Runtime_GetScopeCount) { | |
12333 HandleScope scope(isolate); | |
12334 DCHECK(args.length() == 2); | |
12335 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12336 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12337 | |
12338 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
12339 | |
12340 // Get the frame where the debugging is performed. | |
12341 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
12342 JavaScriptFrameIterator it(isolate, id); | |
12343 JavaScriptFrame* frame = it.frame(); | |
12344 | |
12345 // Count the visible scopes. | |
12346 int n = 0; | |
12347 for (ScopeIterator it(isolate, frame, 0); | |
12348 !it.Done(); | |
12349 it.Next()) { | |
12350 n++; | |
12351 } | |
12352 | |
12353 return Smi::FromInt(n); | |
12354 } | |
12355 | |
12356 | |
12357 // Returns the list of step-in positions (text offset) in a function of the | |
12358 // stack frame in a range from the current debug break position to the end | |
12359 // of the corresponding statement. | |
12360 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { | |
12361 HandleScope scope(isolate); | |
12362 DCHECK(args.length() == 2); | |
12363 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12364 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12365 | |
12366 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
12367 | |
12368 // Get the frame where the debugging is performed. | |
12369 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
12370 JavaScriptFrameIterator frame_it(isolate, id); | |
12371 RUNTIME_ASSERT(!frame_it.done()); | |
12372 | |
12373 JavaScriptFrame* frame = frame_it.frame(); | |
12374 | |
12375 Handle<JSFunction> fun = | |
12376 Handle<JSFunction>(frame->function()); | |
12377 Handle<SharedFunctionInfo> shared = | |
12378 Handle<SharedFunctionInfo>(fun->shared()); | |
12379 | |
12380 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { | |
12381 return isolate->heap()->undefined_value(); | |
12382 } | |
12383 | |
12384 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); | |
12385 | |
12386 int len = 0; | |
12387 Handle<JSArray> array(isolate->factory()->NewJSArray(10)); | |
12388 // Find the break point where execution has stopped. | |
12389 BreakLocationIterator break_location_iterator(debug_info, | |
12390 ALL_BREAK_LOCATIONS); | |
12391 | |
12392 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); | |
12393 int current_statement_pos = break_location_iterator.statement_position(); | |
12394 | |
12395 while (!break_location_iterator.Done()) { | |
12396 bool accept; | |
12397 if (break_location_iterator.pc() > frame->pc()) { | |
12398 accept = true; | |
12399 } else { | |
12400 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id(); | |
12401 // The break point is near our pc. Could be a step-in possibility, | |
12402 // that is currently taken by active debugger call. | |
12403 if (break_frame_id == StackFrame::NO_ID) { | |
12404 // We are not stepping. | |
12405 accept = false; | |
12406 } else { | |
12407 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id); | |
12408 // If our frame is a top frame and we are stepping, we can do step-in | |
12409 // at this place. | |
12410 accept = additional_frame_it.frame()->id() == id; | |
12411 } | |
12412 } | |
12413 if (accept) { | |
12414 if (break_location_iterator.IsStepInLocation(isolate)) { | |
12415 Smi* position_value = Smi::FromInt(break_location_iterator.position()); | |
12416 RETURN_FAILURE_ON_EXCEPTION( | |
12417 isolate, | |
12418 JSObject::SetElement(array, len, | |
12419 Handle<Object>(position_value, isolate), | |
12420 NONE, SLOPPY)); | |
12421 len++; | |
12422 } | |
12423 } | |
12424 // Advance iterator. | |
12425 break_location_iterator.Next(); | |
12426 if (current_statement_pos != | |
12427 break_location_iterator.statement_position()) { | |
12428 break; | |
12429 } | |
12430 } | |
12431 return *array; | |
12432 } | |
12433 | |
12434 | |
12435 static const int kScopeDetailsTypeIndex = 0; | |
12436 static const int kScopeDetailsObjectIndex = 1; | |
12437 static const int kScopeDetailsSize = 2; | |
12438 | |
12439 | |
12440 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails( | |
12441 Isolate* isolate, | |
12442 ScopeIterator* it) { | |
12443 // Calculate the size of the result. | |
12444 int details_size = kScopeDetailsSize; | |
12445 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | |
12446 | |
12447 // Fill in scope details. | |
12448 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); | |
12449 Handle<JSObject> scope_object; | |
12450 ASSIGN_RETURN_ON_EXCEPTION( | |
12451 isolate, scope_object, it->ScopeObject(), JSObject); | |
12452 details->set(kScopeDetailsObjectIndex, *scope_object); | |
12453 | |
12454 return isolate->factory()->NewJSArrayWithElements(details); | |
12455 } | |
12456 | |
12457 | |
12458 // Return an array with scope details | |
12459 // args[0]: number: break id | |
12460 // args[1]: number: frame index | |
12461 // args[2]: number: inlined frame index | |
12462 // args[3]: number: scope index | |
12463 // | |
12464 // The array returned contains the following information: | |
12465 // 0: Scope type | |
12466 // 1: Scope object | |
12467 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { | |
12468 HandleScope scope(isolate); | |
12469 DCHECK(args.length() == 4); | |
12470 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12471 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12472 | |
12473 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
12474 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
12475 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); | |
12476 | |
12477 // Get the frame where the debugging is performed. | |
12478 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
12479 JavaScriptFrameIterator frame_it(isolate, id); | |
12480 JavaScriptFrame* frame = frame_it.frame(); | |
12481 | |
12482 // Find the requested scope. | |
12483 int n = 0; | |
12484 ScopeIterator it(isolate, frame, inlined_jsframe_index); | |
12485 for (; !it.Done() && n < index; it.Next()) { | |
12486 n++; | |
12487 } | |
12488 if (it.Done()) { | |
12489 return isolate->heap()->undefined_value(); | |
12490 } | |
12491 Handle<JSObject> details; | |
12492 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
12493 isolate, details, MaterializeScopeDetails(isolate, &it)); | |
12494 return *details; | |
12495 } | |
12496 | |
12497 | |
12498 // Return an array of scope details | |
12499 // args[0]: number: break id | |
12500 // args[1]: number: frame index | |
12501 // args[2]: number: inlined frame index | |
12502 // args[3]: boolean: ignore nested scopes | |
12503 // | |
12504 // The array returned contains arrays with the following information: | |
12505 // 0: Scope type | |
12506 // 1: Scope object | |
12507 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { | |
12508 HandleScope scope(isolate); | |
12509 DCHECK(args.length() == 3 || args.length() == 4); | |
12510 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12511 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12512 | |
12513 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
12514 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
12515 | |
12516 bool ignore_nested_scopes = false; | |
12517 if (args.length() == 4) { | |
12518 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); | |
12519 ignore_nested_scopes = flag; | |
12520 } | |
12521 | |
12522 // Get the frame where the debugging is performed. | |
12523 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
12524 JavaScriptFrameIterator frame_it(isolate, id); | |
12525 JavaScriptFrame* frame = frame_it.frame(); | |
12526 | |
12527 List<Handle<JSObject> > result(4); | |
12528 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes); | |
12529 for (; !it.Done(); it.Next()) { | |
12530 Handle<JSObject> details; | |
12531 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
12532 isolate, details, MaterializeScopeDetails(isolate, &it)); | |
12533 result.Add(details); | |
12534 } | |
12535 | |
12536 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); | |
12537 for (int i = 0; i < result.length(); ++i) { | |
12538 array->set(i, *result[i]); | |
12539 } | |
12540 return *isolate->factory()->NewJSArrayWithElements(array); | |
12541 } | |
12542 | |
12543 | |
12544 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { | |
12545 HandleScope scope(isolate); | |
12546 DCHECK(args.length() == 1); | |
12547 | |
12548 // Check arguments. | |
12549 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
12550 | |
12551 // Count the visible scopes. | |
12552 int n = 0; | |
12553 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { | |
12554 n++; | |
12555 } | |
12556 | |
12557 return Smi::FromInt(n); | |
12558 } | |
12559 | |
12560 | |
12561 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { | |
12562 HandleScope scope(isolate); | |
12563 DCHECK(args.length() == 2); | |
12564 | |
12565 // Check arguments. | |
12566 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
12567 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
12568 | |
12569 // Find the requested scope. | |
12570 int n = 0; | |
12571 ScopeIterator it(isolate, fun); | |
12572 for (; !it.Done() && n < index; it.Next()) { | |
12573 n++; | |
12574 } | |
12575 if (it.Done()) { | |
12576 return isolate->heap()->undefined_value(); | |
12577 } | |
12578 | |
12579 Handle<JSObject> details; | |
12580 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
12581 isolate, details, MaterializeScopeDetails(isolate, &it)); | |
12582 return *details; | |
12583 } | |
12584 | |
12585 | |
12586 static bool SetScopeVariableValue(ScopeIterator* it, int index, | |
12587 Handle<String> variable_name, | |
12588 Handle<Object> new_value) { | |
12589 for (int n = 0; !it->Done() && n < index; it->Next()) { | |
12590 n++; | |
12591 } | |
12592 if (it->Done()) { | |
12593 return false; | |
12594 } | |
12595 return it->SetVariableValue(variable_name, new_value); | |
12596 } | |
12597 | |
12598 | |
12599 // Change variable value in closure or local scope | |
12600 // args[0]: number or JsFunction: break id or function | |
12601 // args[1]: number: frame index (when arg[0] is break id) | |
12602 // args[2]: number: inlined frame index (when arg[0] is break id) | |
12603 // args[3]: number: scope index | |
12604 // args[4]: string: variable name | |
12605 // args[5]: object: new value | |
12606 // | |
12607 // Return true if success and false otherwise | |
12608 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { | |
12609 HandleScope scope(isolate); | |
12610 DCHECK(args.length() == 6); | |
12611 | |
12612 // Check arguments. | |
12613 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); | |
12614 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); | |
12615 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); | |
12616 | |
12617 bool res; | |
12618 if (args[0]->IsNumber()) { | |
12619 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12620 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12621 | |
12622 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
12623 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
12624 | |
12625 // Get the frame where the debugging is performed. | |
12626 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
12627 JavaScriptFrameIterator frame_it(isolate, id); | |
12628 JavaScriptFrame* frame = frame_it.frame(); | |
12629 | |
12630 ScopeIterator it(isolate, frame, inlined_jsframe_index); | |
12631 res = SetScopeVariableValue(&it, index, variable_name, new_value); | |
12632 } else { | |
12633 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
12634 ScopeIterator it(isolate, fun); | |
12635 res = SetScopeVariableValue(&it, index, variable_name, new_value); | |
12636 } | |
12637 | |
12638 return isolate->heap()->ToBoolean(res); | |
12639 } | |
12640 | |
12641 | |
12642 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { | |
12643 HandleScope scope(isolate); | |
12644 DCHECK(args.length() == 0); | |
12645 | |
12646 #ifdef DEBUG | |
12647 // Print the scopes for the top frame. | |
12648 StackFrameLocator locator(isolate); | |
12649 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | |
12650 for (ScopeIterator it(isolate, frame, 0); | |
12651 !it.Done(); | |
12652 it.Next()) { | |
12653 it.DebugPrint(); | |
12654 } | |
12655 #endif | |
12656 return isolate->heap()->undefined_value(); | |
12657 } | |
12658 | |
12659 | |
12660 RUNTIME_FUNCTION(Runtime_GetThreadCount) { | |
12661 HandleScope scope(isolate); | |
12662 DCHECK(args.length() == 1); | |
12663 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12664 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12665 | |
12666 // Count all archived V8 threads. | |
12667 int n = 0; | |
12668 for (ThreadState* thread = | |
12669 isolate->thread_manager()->FirstThreadStateInUse(); | |
12670 thread != NULL; | |
12671 thread = thread->Next()) { | |
12672 n++; | |
12673 } | |
12674 | |
12675 // Total number of threads is current thread and archived threads. | |
12676 return Smi::FromInt(n + 1); | |
12677 } | |
12678 | |
12679 | |
12680 static const int kThreadDetailsCurrentThreadIndex = 0; | |
12681 static const int kThreadDetailsThreadIdIndex = 1; | |
12682 static const int kThreadDetailsSize = 2; | |
12683 | |
12684 // Return an array with thread details | |
12685 // args[0]: number: break id | |
12686 // args[1]: number: thread index | |
12687 // | |
12688 // The array returned contains the following information: | |
12689 // 0: Is current thread? | |
12690 // 1: Thread id | |
12691 RUNTIME_FUNCTION(Runtime_GetThreadDetails) { | |
12692 HandleScope scope(isolate); | |
12693 DCHECK(args.length() == 2); | |
12694 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12695 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12696 | |
12697 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
12698 | |
12699 // Allocate array for result. | |
12700 Handle<FixedArray> details = | |
12701 isolate->factory()->NewFixedArray(kThreadDetailsSize); | |
12702 | |
12703 // Thread index 0 is current thread. | |
12704 if (index == 0) { | |
12705 // Fill the details. | |
12706 details->set(kThreadDetailsCurrentThreadIndex, | |
12707 isolate->heap()->true_value()); | |
12708 details->set(kThreadDetailsThreadIdIndex, | |
12709 Smi::FromInt(ThreadId::Current().ToInteger())); | |
12710 } else { | |
12711 // Find the thread with the requested index. | |
12712 int n = 1; | |
12713 ThreadState* thread = | |
12714 isolate->thread_manager()->FirstThreadStateInUse(); | |
12715 while (index != n && thread != NULL) { | |
12716 thread = thread->Next(); | |
12717 n++; | |
12718 } | |
12719 if (thread == NULL) { | |
12720 return isolate->heap()->undefined_value(); | |
12721 } | |
12722 | |
12723 // Fill the details. | |
12724 details->set(kThreadDetailsCurrentThreadIndex, | |
12725 isolate->heap()->false_value()); | |
12726 details->set(kThreadDetailsThreadIdIndex, | |
12727 Smi::FromInt(thread->id().ToInteger())); | |
12728 } | |
12729 | |
12730 // Convert to JS array and return. | |
12731 return *isolate->factory()->NewJSArrayWithElements(details); | |
12732 } | |
12733 | |
12734 | |
12735 // Sets the disable break state | |
12736 // args[0]: disable break state | |
12737 RUNTIME_FUNCTION(Runtime_SetDisableBreak) { | |
12738 HandleScope scope(isolate); | |
12739 DCHECK(args.length() == 1); | |
12740 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); | |
12741 isolate->debug()->set_disable_break(disable_break); | |
12742 return isolate->heap()->undefined_value(); | |
12743 } | |
12744 | |
12745 | |
12746 static bool IsPositionAlignmentCodeCorrect(int alignment) { | |
12747 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; | |
12748 } | |
12749 | |
12750 | |
12751 RUNTIME_FUNCTION(Runtime_GetBreakLocations) { | |
12752 HandleScope scope(isolate); | |
12753 DCHECK(args.length() == 2); | |
12754 | |
12755 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
12756 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); | |
12757 | |
12758 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { | |
12759 return isolate->ThrowIllegalOperation(); | |
12760 } | |
12761 BreakPositionAlignment alignment = | |
12762 static_cast<BreakPositionAlignment>(statement_aligned_code); | |
12763 | |
12764 Handle<SharedFunctionInfo> shared(fun->shared()); | |
12765 // Find the number of break points | |
12766 Handle<Object> break_locations = | |
12767 Debug::GetSourceBreakLocations(shared, alignment); | |
12768 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); | |
12769 // Return array as JS array | |
12770 return *isolate->factory()->NewJSArrayWithElements( | |
12771 Handle<FixedArray>::cast(break_locations)); | |
12772 } | |
12773 | |
12774 | |
12775 // Set a break point in a function. | |
12776 // args[0]: function | |
12777 // args[1]: number: break source position (within the function source) | |
12778 // args[2]: number: break point object | |
12779 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { | |
12780 HandleScope scope(isolate); | |
12781 DCHECK(args.length() == 3); | |
12782 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
12783 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
12784 RUNTIME_ASSERT(source_position >= function->shared()->start_position() && | |
12785 source_position <= function->shared()->end_position()); | |
12786 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); | |
12787 | |
12788 // Set break point. | |
12789 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint( | |
12790 function, break_point_object_arg, &source_position)); | |
12791 | |
12792 return Smi::FromInt(source_position); | |
12793 } | |
12794 | |
12795 | |
12796 // Changes the state of a break point in a script and returns source position | |
12797 // where break point was set. NOTE: Regarding performance see the NOTE for | |
12798 // GetScriptFromScriptData. | |
12799 // args[0]: script to set break point in | |
12800 // args[1]: number: break source position (within the script source) | |
12801 // args[2]: number, breakpoint position alignment | |
12802 // args[3]: number: break point object | |
12803 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { | |
12804 HandleScope scope(isolate); | |
12805 DCHECK(args.length() == 4); | |
12806 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); | |
12807 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
12808 RUNTIME_ASSERT(source_position >= 0); | |
12809 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); | |
12810 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); | |
12811 | |
12812 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { | |
12813 return isolate->ThrowIllegalOperation(); | |
12814 } | |
12815 BreakPositionAlignment alignment = | |
12816 static_cast<BreakPositionAlignment>(statement_aligned_code); | |
12817 | |
12818 // Get the script from the script wrapper. | |
12819 RUNTIME_ASSERT(wrapper->value()->IsScript()); | |
12820 Handle<Script> script(Script::cast(wrapper->value())); | |
12821 | |
12822 // Set break point. | |
12823 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, | |
12824 &source_position, | |
12825 alignment)) { | |
12826 return isolate->heap()->undefined_value(); | |
12827 } | |
12828 | |
12829 return Smi::FromInt(source_position); | |
12830 } | |
12831 | |
12832 | |
12833 // Clear a break point | |
12834 // args[0]: number: break point object | |
12835 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { | |
12836 HandleScope scope(isolate); | |
12837 DCHECK(args.length() == 1); | |
12838 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); | |
12839 | |
12840 // Clear break point. | |
12841 isolate->debug()->ClearBreakPoint(break_point_object_arg); | |
12842 | |
12843 return isolate->heap()->undefined_value(); | |
12844 } | |
12845 | |
12846 | |
12847 // Change the state of break on exceptions. | |
12848 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. | |
12849 // args[1]: Boolean indicating on/off. | |
12850 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { | |
12851 HandleScope scope(isolate); | |
12852 DCHECK(args.length() == 2); | |
12853 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); | |
12854 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); | |
12855 | |
12856 // If the number doesn't match an enum value, the ChangeBreakOnException | |
12857 // function will default to affecting caught exceptions. | |
12858 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); | |
12859 // Update break point state. | |
12860 isolate->debug()->ChangeBreakOnException(type, enable); | |
12861 return isolate->heap()->undefined_value(); | |
12862 } | |
12863 | |
12864 | |
12865 // Returns the state of break on exceptions | |
12866 // args[0]: boolean indicating uncaught exceptions | |
12867 RUNTIME_FUNCTION(Runtime_IsBreakOnException) { | |
12868 HandleScope scope(isolate); | |
12869 DCHECK(args.length() == 1); | |
12870 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); | |
12871 | |
12872 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); | |
12873 bool result = isolate->debug()->IsBreakOnException(type); | |
12874 return Smi::FromInt(result); | |
12875 } | |
12876 | |
12877 | |
12878 // Prepare for stepping | |
12879 // args[0]: break id for checking execution state | |
12880 // args[1]: step action from the enumeration StepAction | |
12881 // args[2]: number of times to perform the step, for step out it is the number | |
12882 // of frames to step down. | |
12883 RUNTIME_FUNCTION(Runtime_PrepareStep) { | |
12884 HandleScope scope(isolate); | |
12885 DCHECK(args.length() == 4); | |
12886 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
12887 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
12888 | |
12889 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { | |
12890 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
12891 } | |
12892 | |
12893 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); | |
12894 | |
12895 StackFrame::Id frame_id; | |
12896 if (wrapped_frame_id == 0) { | |
12897 frame_id = StackFrame::NO_ID; | |
12898 } else { | |
12899 frame_id = UnwrapFrameId(wrapped_frame_id); | |
12900 } | |
12901 | |
12902 // Get the step action and check validity. | |
12903 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); | |
12904 if (step_action != StepIn && | |
12905 step_action != StepNext && | |
12906 step_action != StepOut && | |
12907 step_action != StepInMin && | |
12908 step_action != StepMin) { | |
12909 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
12910 } | |
12911 | |
12912 if (frame_id != StackFrame::NO_ID && step_action != StepNext && | |
12913 step_action != StepMin && step_action != StepOut) { | |
12914 return isolate->ThrowIllegalOperation(); | |
12915 } | |
12916 | |
12917 // Get the number of steps. | |
12918 int step_count = NumberToInt32(args[2]); | |
12919 if (step_count < 1) { | |
12920 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
12921 } | |
12922 | |
12923 // Clear all current stepping setup. | |
12924 isolate->debug()->ClearStepping(); | |
12925 | |
12926 // Prepare step. | |
12927 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), | |
12928 step_count, | |
12929 frame_id); | |
12930 return isolate->heap()->undefined_value(); | |
12931 } | |
12932 | |
12933 | |
12934 // Clear all stepping set by PrepareStep. | |
12935 RUNTIME_FUNCTION(Runtime_ClearStepping) { | |
12936 HandleScope scope(isolate); | |
12937 DCHECK(args.length() == 0); | |
12938 isolate->debug()->ClearStepping(); | |
12939 return isolate->heap()->undefined_value(); | |
12940 } | |
12941 | |
12942 | |
12943 // Helper function to find or create the arguments object for | |
12944 // Runtime_DebugEvaluate. | |
12945 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject( | |
12946 Isolate* isolate, | |
12947 Handle<JSObject> target, | |
12948 Handle<JSFunction> function) { | |
12949 // Do not materialize the arguments object for eval or top-level code. | |
12950 // Skip if "arguments" is already taken. | |
12951 if (!function->shared()->is_function()) return target; | |
12952 Maybe<bool> maybe = JSReceiver::HasOwnProperty( | |
12953 target, isolate->factory()->arguments_string()); | |
12954 if (!maybe.has_value) return MaybeHandle<JSObject>(); | |
12955 if (maybe.value) return target; | |
12956 | |
12957 // FunctionGetArguments can't throw an exception. | |
12958 Handle<JSObject> arguments = Handle<JSObject>::cast( | |
12959 Accessors::FunctionGetArguments(function)); | |
12960 Handle<String> arguments_str = isolate->factory()->arguments_string(); | |
12961 RETURN_ON_EXCEPTION( | |
12962 isolate, | |
12963 Runtime::DefineObjectProperty(target, arguments_str, arguments, NONE), | |
12964 JSObject); | |
12965 return target; | |
12966 } | |
12967 | |
12968 | |
12969 // Compile and evaluate source for the given context. | |
12970 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate, | |
12971 Handle<Context> context, | |
12972 Handle<Object> context_extension, | |
12973 Handle<Object> receiver, | |
12974 Handle<String> source) { | |
12975 if (context_extension->IsJSObject()) { | |
12976 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); | |
12977 Handle<JSFunction> closure(context->closure(), isolate); | |
12978 context = isolate->factory()->NewWithContext(closure, context, extension); | |
12979 } | |
12980 | |
12981 Handle<JSFunction> eval_fun; | |
12982 ASSIGN_RETURN_ON_EXCEPTION( | |
12983 isolate, eval_fun, | |
12984 Compiler::GetFunctionFromEval(source, | |
12985 context, | |
12986 SLOPPY, | |
12987 NO_PARSE_RESTRICTION, | |
12988 RelocInfo::kNoPosition), | |
12989 Object); | |
12990 | |
12991 Handle<Object> result; | |
12992 ASSIGN_RETURN_ON_EXCEPTION( | |
12993 isolate, result, | |
12994 Execution::Call(isolate, eval_fun, receiver, 0, NULL), | |
12995 Object); | |
12996 | |
12997 // Skip the global proxy as it has no properties and always delegates to the | |
12998 // real global object. | |
12999 if (result->IsJSGlobalProxy()) { | |
13000 PrototypeIterator iter(isolate, result); | |
13001 // TODO(verwaest): This will crash when the global proxy is detached. | |
13002 result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
13003 } | |
13004 | |
13005 // Clear the oneshot breakpoints so that the debugger does not step further. | |
13006 isolate->debug()->ClearStepping(); | |
13007 return result; | |
13008 } | |
13009 | |
13010 | |
13011 static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) { | |
13012 Handle<JSObject> result = | |
13013 isolate->factory()->NewJSObject(isolate->object_function()); | |
13014 Handle<Map> new_map = Map::Copy(Handle<Map>(result->map())); | |
13015 new_map->set_prototype(*isolate->factory()->null_value()); | |
13016 JSObject::MigrateToMap(result, new_map); | |
13017 return result; | |
13018 } | |
13019 | |
13020 | |
13021 // Evaluate a piece of JavaScript in the context of a stack frame for | |
13022 // debugging. Things that need special attention are: | |
13023 // - Parameters and stack-allocated locals need to be materialized. Altered | |
13024 // values need to be written back to the stack afterwards. | |
13025 // - The arguments object needs to materialized. | |
13026 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { | |
13027 HandleScope scope(isolate); | |
13028 | |
13029 // Check the execution state and decode arguments frame and source to be | |
13030 // evaluated. | |
13031 DCHECK(args.length() == 6); | |
13032 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
13033 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
13034 | |
13035 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
13036 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
13037 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); | |
13038 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); | |
13039 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); | |
13040 | |
13041 // Handle the processing of break. | |
13042 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
13043 | |
13044 // Get the frame where the debugging is performed. | |
13045 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
13046 JavaScriptFrameIterator it(isolate, id); | |
13047 JavaScriptFrame* frame = it.frame(); | |
13048 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
13049 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
13050 | |
13051 // Traverse the saved contexts chain to find the active context for the | |
13052 // selected frame. | |
13053 SaveContext* save = FindSavedContextForFrame(isolate, frame); | |
13054 | |
13055 SaveContext savex(isolate); | |
13056 isolate->set_context(*(save->context())); | |
13057 | |
13058 // Evaluate on the context of the frame. | |
13059 Handle<Context> context(Context::cast(frame_inspector.GetContext())); | |
13060 DCHECK(!context.is_null()); | |
13061 | |
13062 // Materialize stack locals and the arguments object. | |
13063 Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate); | |
13064 | |
13065 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13066 isolate, materialized, | |
13067 MaterializeStackLocalsWithFrameInspector( | |
13068 isolate, materialized, function, &frame_inspector)); | |
13069 | |
13070 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13071 isolate, materialized, | |
13072 MaterializeArgumentsObject(isolate, materialized, function)); | |
13073 | |
13074 // Add the materialized object in a with-scope to shadow the stack locals. | |
13075 context = isolate->factory()->NewWithContext(function, context, materialized); | |
13076 | |
13077 Handle<Object> receiver(frame->receiver(), isolate); | |
13078 Handle<Object> result; | |
13079 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13080 isolate, result, | |
13081 DebugEvaluate(isolate, context, context_extension, receiver, source)); | |
13082 | |
13083 // Write back potential changes to materialized stack locals to the stack. | |
13084 UpdateStackLocalsFromMaterializedObject( | |
13085 isolate, materialized, function, frame, inlined_jsframe_index); | |
13086 | |
13087 return *result; | |
13088 } | |
13089 | |
13090 | |
13091 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { | |
13092 HandleScope scope(isolate); | |
13093 | |
13094 // Check the execution state and decode arguments frame and source to be | |
13095 // evaluated. | |
13096 DCHECK(args.length() == 4); | |
13097 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
13098 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
13099 | |
13100 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
13101 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); | |
13102 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); | |
13103 | |
13104 // Handle the processing of break. | |
13105 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
13106 | |
13107 // Enter the top context from before the debugger was invoked. | |
13108 SaveContext save(isolate); | |
13109 SaveContext* top = &save; | |
13110 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { | |
13111 top = top->prev(); | |
13112 } | |
13113 if (top != NULL) { | |
13114 isolate->set_context(*top->context()); | |
13115 } | |
13116 | |
13117 // Get the native context now set to the top context from before the | |
13118 // debugger was invoked. | |
13119 Handle<Context> context = isolate->native_context(); | |
13120 Handle<JSObject> receiver(context->global_proxy()); | |
13121 Handle<Object> result; | |
13122 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13123 isolate, result, | |
13124 DebugEvaluate(isolate, context, context_extension, receiver, source)); | |
13125 return *result; | |
13126 } | |
13127 | |
13128 | |
13129 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { | |
13130 HandleScope scope(isolate); | |
13131 DCHECK(args.length() == 0); | |
13132 | |
13133 // Fill the script objects. | |
13134 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); | |
13135 | |
13136 // Convert the script objects to proper JS objects. | |
13137 for (int i = 0; i < instances->length(); i++) { | |
13138 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); | |
13139 // Get the script wrapper in a local handle before calling GetScriptWrapper, | |
13140 // because using | |
13141 // instances->set(i, *GetScriptWrapper(script)) | |
13142 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might | |
13143 // already have dereferenced the instances handle. | |
13144 Handle<JSObject> wrapper = Script::GetWrapper(script); | |
13145 instances->set(i, *wrapper); | |
13146 } | |
13147 | |
13148 // Return result as a JS array. | |
13149 Handle<JSObject> result = | |
13150 isolate->factory()->NewJSObject(isolate->array_function()); | |
13151 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
13152 return *result; | |
13153 } | |
13154 | |
13155 | |
13156 // Helper function used by Runtime_DebugReferencedBy below. | |
13157 static int DebugReferencedBy(HeapIterator* iterator, | |
13158 JSObject* target, | |
13159 Object* instance_filter, int max_references, | |
13160 FixedArray* instances, int instances_size, | |
13161 JSFunction* arguments_function) { | |
13162 Isolate* isolate = target->GetIsolate(); | |
13163 SealHandleScope shs(isolate); | |
13164 DisallowHeapAllocation no_allocation; | |
13165 | |
13166 // Iterate the heap. | |
13167 int count = 0; | |
13168 JSObject* last = NULL; | |
13169 HeapObject* heap_obj = NULL; | |
13170 while (((heap_obj = iterator->next()) != NULL) && | |
13171 (max_references == 0 || count < max_references)) { | |
13172 // Only look at all JSObjects. | |
13173 if (heap_obj->IsJSObject()) { | |
13174 // Skip context extension objects and argument arrays as these are | |
13175 // checked in the context of functions using them. | |
13176 JSObject* obj = JSObject::cast(heap_obj); | |
13177 if (obj->IsJSContextExtensionObject() || | |
13178 obj->map()->constructor() == arguments_function) { | |
13179 continue; | |
13180 } | |
13181 | |
13182 // Check if the JS object has a reference to the object looked for. | |
13183 if (obj->ReferencesObject(target)) { | |
13184 // Check instance filter if supplied. This is normally used to avoid | |
13185 // references from mirror objects (see Runtime_IsInPrototypeChain). | |
13186 if (!instance_filter->IsUndefined()) { | |
13187 for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd(); | |
13188 iter.Advance()) { | |
13189 if (iter.GetCurrent() == instance_filter) { | |
13190 obj = NULL; // Don't add this object. | |
13191 break; | |
13192 } | |
13193 } | |
13194 } | |
13195 | |
13196 if (obj != NULL) { | |
13197 // Valid reference found add to instance array if supplied an update | |
13198 // count. | |
13199 if (instances != NULL && count < instances_size) { | |
13200 instances->set(count, obj); | |
13201 } | |
13202 last = obj; | |
13203 count++; | |
13204 } | |
13205 } | |
13206 } | |
13207 } | |
13208 | |
13209 // Check for circular reference only. This can happen when the object is only | |
13210 // referenced from mirrors and has a circular reference in which case the | |
13211 // object is not really alive and would have been garbage collected if not | |
13212 // referenced from the mirror. | |
13213 if (count == 1 && last == target) { | |
13214 count = 0; | |
13215 } | |
13216 | |
13217 // Return the number of referencing objects found. | |
13218 return count; | |
13219 } | |
13220 | |
13221 | |
13222 // Scan the heap for objects with direct references to an object | |
13223 // args[0]: the object to find references to | |
13224 // args[1]: constructor function for instances to exclude (Mirror) | |
13225 // args[2]: the the maximum number of objects to return | |
13226 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { | |
13227 HandleScope scope(isolate); | |
13228 DCHECK(args.length() == 3); | |
13229 | |
13230 // Check parameters. | |
13231 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); | |
13232 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1); | |
13233 RUNTIME_ASSERT(instance_filter->IsUndefined() || | |
13234 instance_filter->IsJSObject()); | |
13235 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); | |
13236 RUNTIME_ASSERT(max_references >= 0); | |
13237 | |
13238 | |
13239 // Get the constructor function for context extension and arguments array. | |
13240 Handle<JSFunction> arguments_function( | |
13241 JSFunction::cast(isolate->sloppy_arguments_map()->constructor())); | |
13242 | |
13243 // Get the number of referencing objects. | |
13244 int count; | |
13245 // First perform a full GC in order to avoid dead objects and to make the heap | |
13246 // iterable. | |
13247 Heap* heap = isolate->heap(); | |
13248 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); | |
13249 { | |
13250 HeapIterator heap_iterator(heap); | |
13251 count = DebugReferencedBy(&heap_iterator, | |
13252 *target, *instance_filter, max_references, | |
13253 NULL, 0, *arguments_function); | |
13254 } | |
13255 | |
13256 // Allocate an array to hold the result. | |
13257 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); | |
13258 | |
13259 // Fill the referencing objects. | |
13260 { | |
13261 HeapIterator heap_iterator(heap); | |
13262 count = DebugReferencedBy(&heap_iterator, | |
13263 *target, *instance_filter, max_references, | |
13264 *instances, count, *arguments_function); | |
13265 } | |
13266 | |
13267 // Return result as JS array. | |
13268 Handle<JSFunction> constructor = isolate->array_function(); | |
13269 | |
13270 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); | |
13271 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
13272 return *result; | |
13273 } | |
13274 | |
13275 | |
13276 // Helper function used by Runtime_DebugConstructedBy below. | |
13277 static int DebugConstructedBy(HeapIterator* iterator, | |
13278 JSFunction* constructor, | |
13279 int max_references, | |
13280 FixedArray* instances, | |
13281 int instances_size) { | |
13282 DisallowHeapAllocation no_allocation; | |
13283 | |
13284 // Iterate the heap. | |
13285 int count = 0; | |
13286 HeapObject* heap_obj = NULL; | |
13287 while (((heap_obj = iterator->next()) != NULL) && | |
13288 (max_references == 0 || count < max_references)) { | |
13289 // Only look at all JSObjects. | |
13290 if (heap_obj->IsJSObject()) { | |
13291 JSObject* obj = JSObject::cast(heap_obj); | |
13292 if (obj->map()->constructor() == constructor) { | |
13293 // Valid reference found add to instance array if supplied an update | |
13294 // count. | |
13295 if (instances != NULL && count < instances_size) { | |
13296 instances->set(count, obj); | |
13297 } | |
13298 count++; | |
13299 } | |
13300 } | |
13301 } | |
13302 | |
13303 // Return the number of referencing objects found. | |
13304 return count; | |
13305 } | |
13306 | |
13307 | |
13308 // Scan the heap for objects constructed by a specific function. | |
13309 // args[0]: the constructor to find instances of | |
13310 // args[1]: the the maximum number of objects to return | |
13311 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { | |
13312 HandleScope scope(isolate); | |
13313 DCHECK(args.length() == 2); | |
13314 | |
13315 | |
13316 // Check parameters. | |
13317 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); | |
13318 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); | |
13319 RUNTIME_ASSERT(max_references >= 0); | |
13320 | |
13321 // Get the number of referencing objects. | |
13322 int count; | |
13323 // First perform a full GC in order to avoid dead objects and to make the heap | |
13324 // iterable. | |
13325 Heap* heap = isolate->heap(); | |
13326 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); | |
13327 { | |
13328 HeapIterator heap_iterator(heap); | |
13329 count = DebugConstructedBy(&heap_iterator, | |
13330 *constructor, | |
13331 max_references, | |
13332 NULL, | |
13333 0); | |
13334 } | |
13335 | |
13336 // Allocate an array to hold the result. | |
13337 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); | |
13338 | |
13339 // Fill the referencing objects. | |
13340 { | |
13341 HeapIterator heap_iterator2(heap); | |
13342 count = DebugConstructedBy(&heap_iterator2, | |
13343 *constructor, | |
13344 max_references, | |
13345 *instances, | |
13346 count); | |
13347 } | |
13348 | |
13349 // Return result as JS array. | |
13350 Handle<JSFunction> array_function = isolate->array_function(); | |
13351 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function); | |
13352 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
13353 return *result; | |
13354 } | |
13355 | |
13356 | |
13357 // Find the effective prototype object as returned by __proto__. | |
13358 // args[0]: the object to find the prototype for. | |
13359 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { | |
13360 HandleScope shs(isolate); | |
13361 DCHECK(args.length() == 1); | |
13362 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
13363 return *GetPrototypeSkipHiddenPrototypes(isolate, obj); | |
13364 } | |
13365 | |
13366 | |
13367 // Patches script source (should be called upon BeforeCompile event). | |
13368 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { | |
13369 HandleScope scope(isolate); | |
13370 DCHECK(args.length() == 2); | |
13371 | |
13372 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); | |
13373 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
13374 | |
13375 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); | |
13376 Handle<Script> script(Script::cast(script_wrapper->value())); | |
13377 | |
13378 int compilation_state = script->compilation_state(); | |
13379 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); | |
13380 script->set_source(*source); | |
13381 | |
13382 return isolate->heap()->undefined_value(); | |
13383 } | |
13384 | |
13385 | |
13386 RUNTIME_FUNCTION(Runtime_SystemBreak) { | |
13387 SealHandleScope shs(isolate); | |
13388 DCHECK(args.length() == 0); | |
13389 base::OS::DebugBreak(); | |
13390 return isolate->heap()->undefined_value(); | |
13391 } | |
13392 | |
13393 | |
13394 RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) { | |
13395 HandleScope scope(isolate); | |
13396 #ifdef DEBUG | |
13397 DCHECK(args.length() == 1); | |
13398 // Get the function and make sure it is compiled. | |
13399 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); | |
13400 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { | |
13401 return isolate->heap()->exception(); | |
13402 } | |
13403 OFStream os(stdout); | |
13404 func->code()->Print(os); | |
13405 os << endl; | |
13406 #endif // DEBUG | |
13407 return isolate->heap()->undefined_value(); | |
13408 } | |
13409 | |
13410 | |
13411 RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) { | |
13412 HandleScope scope(isolate); | |
13413 #ifdef DEBUG | |
13414 DCHECK(args.length() == 1); | |
13415 // Get the function and make sure it is compiled. | |
13416 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); | |
13417 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { | |
13418 return isolate->heap()->exception(); | |
13419 } | |
13420 OFStream os(stdout); | |
13421 func->shared()->construct_stub()->Print(os); | |
13422 os << endl; | |
13423 #endif // DEBUG | |
13424 return isolate->heap()->undefined_value(); | |
13425 } | |
13426 | |
13427 | |
13428 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { | |
13429 SealHandleScope shs(isolate); | |
13430 DCHECK(args.length() == 1); | |
13431 | |
13432 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
13433 return f->shared()->inferred_name(); | |
13434 } | |
13435 | |
13436 | |
13437 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, | |
13438 Script* script, | |
13439 FixedArray* buffer) { | |
13440 DisallowHeapAllocation no_allocation; | |
13441 int counter = 0; | |
13442 int buffer_size = buffer->length(); | |
13443 for (HeapObject* obj = iterator->next(); | |
13444 obj != NULL; | |
13445 obj = iterator->next()) { | |
13446 DCHECK(obj != NULL); | |
13447 if (!obj->IsSharedFunctionInfo()) { | |
13448 continue; | |
13449 } | |
13450 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); | |
13451 if (shared->script() != script) { | |
13452 continue; | |
13453 } | |
13454 if (counter < buffer_size) { | |
13455 buffer->set(counter, shared); | |
13456 } | |
13457 counter++; | |
13458 } | |
13459 return counter; | |
13460 } | |
13461 | |
13462 | |
13463 // For a script finds all SharedFunctionInfo's in the heap that points | |
13464 // to this script. Returns JSArray of SharedFunctionInfo wrapped | |
13465 // in OpaqueReferences. | |
13466 RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) { | |
13467 HandleScope scope(isolate); | |
13468 CHECK(isolate->debug()->live_edit_enabled()); | |
13469 DCHECK(args.length() == 1); | |
13470 CONVERT_ARG_CHECKED(JSValue, script_value, 0); | |
13471 | |
13472 RUNTIME_ASSERT(script_value->value()->IsScript()); | |
13473 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); | |
13474 | |
13475 const int kBufferSize = 32; | |
13476 | |
13477 Handle<FixedArray> array; | |
13478 array = isolate->factory()->NewFixedArray(kBufferSize); | |
13479 int number; | |
13480 Heap* heap = isolate->heap(); | |
13481 { | |
13482 HeapIterator heap_iterator(heap); | |
13483 Script* scr = *script; | |
13484 FixedArray* arr = *array; | |
13485 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); | |
13486 } | |
13487 if (number > kBufferSize) { | |
13488 array = isolate->factory()->NewFixedArray(number); | |
13489 HeapIterator heap_iterator(heap); | |
13490 Script* scr = *script; | |
13491 FixedArray* arr = *array; | |
13492 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); | |
13493 } | |
13494 | |
13495 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); | |
13496 result->set_length(Smi::FromInt(number)); | |
13497 | |
13498 LiveEdit::WrapSharedFunctionInfos(result); | |
13499 | |
13500 return *result; | |
13501 } | |
13502 | |
13503 | |
13504 // For a script calculates compilation information about all its functions. | |
13505 // The script source is explicitly specified by the second argument. | |
13506 // The source of the actual script is not used, however it is important that | |
13507 // all generated code keeps references to this particular instance of script. | |
13508 // Returns a JSArray of compilation infos. The array is ordered so that | |
13509 // each function with all its descendant is always stored in a continues range | |
13510 // with the function itself going first. The root function is a script function. | |
13511 RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) { | |
13512 HandleScope scope(isolate); | |
13513 CHECK(isolate->debug()->live_edit_enabled()); | |
13514 DCHECK(args.length() == 2); | |
13515 CONVERT_ARG_CHECKED(JSValue, script, 0); | |
13516 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
13517 | |
13518 RUNTIME_ASSERT(script->value()->IsScript()); | |
13519 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); | |
13520 | |
13521 Handle<JSArray> result; | |
13522 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13523 isolate, result, LiveEdit::GatherCompileInfo(script_handle, source)); | |
13524 return *result; | |
13525 } | |
13526 | |
13527 | |
13528 // Changes the source of the script to a new_source. | |
13529 // If old_script_name is provided (i.e. is a String), also creates a copy of | |
13530 // the script with its original source and sends notification to debugger. | |
13531 RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) { | |
13532 HandleScope scope(isolate); | |
13533 CHECK(isolate->debug()->live_edit_enabled()); | |
13534 DCHECK(args.length() == 3); | |
13535 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); | |
13536 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); | |
13537 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2); | |
13538 | |
13539 RUNTIME_ASSERT(original_script_value->value()->IsScript()); | |
13540 Handle<Script> original_script(Script::cast(original_script_value->value())); | |
13541 | |
13542 Handle<Object> old_script = LiveEdit::ChangeScriptSource( | |
13543 original_script, new_source, old_script_name); | |
13544 | |
13545 if (old_script->IsScript()) { | |
13546 Handle<Script> script_handle = Handle<Script>::cast(old_script); | |
13547 return *Script::GetWrapper(script_handle); | |
13548 } else { | |
13549 return isolate->heap()->null_value(); | |
13550 } | |
13551 } | |
13552 | |
13553 | |
13554 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) { | |
13555 HandleScope scope(isolate); | |
13556 CHECK(isolate->debug()->live_edit_enabled()); | |
13557 DCHECK(args.length() == 1); | |
13558 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); | |
13559 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); | |
13560 | |
13561 LiveEdit::FunctionSourceUpdated(shared_info); | |
13562 return isolate->heap()->undefined_value(); | |
13563 } | |
13564 | |
13565 | |
13566 // Replaces code of SharedFunctionInfo with a new one. | |
13567 RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) { | |
13568 HandleScope scope(isolate); | |
13569 CHECK(isolate->debug()->live_edit_enabled()); | |
13570 DCHECK(args.length() == 2); | |
13571 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); | |
13572 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); | |
13573 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); | |
13574 | |
13575 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); | |
13576 return isolate->heap()->undefined_value(); | |
13577 } | |
13578 | |
13579 | |
13580 // Connects SharedFunctionInfo to another script. | |
13581 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) { | |
13582 HandleScope scope(isolate); | |
13583 CHECK(isolate->debug()->live_edit_enabled()); | |
13584 DCHECK(args.length() == 2); | |
13585 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); | |
13586 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1); | |
13587 | |
13588 if (function_object->IsJSValue()) { | |
13589 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); | |
13590 if (script_object->IsJSValue()) { | |
13591 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); | |
13592 Script* script = Script::cast(JSValue::cast(*script_object)->value()); | |
13593 script_object = Handle<Object>(script, isolate); | |
13594 } | |
13595 RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo()); | |
13596 LiveEdit::SetFunctionScript(function_wrapper, script_object); | |
13597 } else { | |
13598 // Just ignore this. We may not have a SharedFunctionInfo for some functions | |
13599 // and we check it in this function. | |
13600 } | |
13601 | |
13602 return isolate->heap()->undefined_value(); | |
13603 } | |
13604 | |
13605 | |
13606 // In a code of a parent function replaces original function as embedded object | |
13607 // with a substitution one. | |
13608 RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) { | |
13609 HandleScope scope(isolate); | |
13610 CHECK(isolate->debug()->live_edit_enabled()); | |
13611 DCHECK(args.length() == 3); | |
13612 | |
13613 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); | |
13614 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); | |
13615 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); | |
13616 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo()); | |
13617 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo()); | |
13618 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo()); | |
13619 | |
13620 LiveEdit::ReplaceRefToNestedFunction( | |
13621 parent_wrapper, orig_wrapper, subst_wrapper); | |
13622 return isolate->heap()->undefined_value(); | |
13623 } | |
13624 | |
13625 | |
13626 // Updates positions of a shared function info (first parameter) according | |
13627 // to script source change. Text change is described in second parameter as | |
13628 // array of groups of 3 numbers: | |
13629 // (change_begin, change_end, change_end_new_position). | |
13630 // Each group describes a change in text; groups are sorted by change_begin. | |
13631 RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) { | |
13632 HandleScope scope(isolate); | |
13633 CHECK(isolate->debug()->live_edit_enabled()); | |
13634 DCHECK(args.length() == 2); | |
13635 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); | |
13636 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); | |
13637 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array)) | |
13638 | |
13639 LiveEdit::PatchFunctionPositions(shared_array, position_change_array); | |
13640 return isolate->heap()->undefined_value(); | |
13641 } | |
13642 | |
13643 | |
13644 // For array of SharedFunctionInfo's (each wrapped in JSValue) | |
13645 // checks that none of them have activations on stacks (of any thread). | |
13646 // Returns array of the same length with corresponding results of | |
13647 // LiveEdit::FunctionPatchabilityStatus type. | |
13648 RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) { | |
13649 HandleScope scope(isolate); | |
13650 CHECK(isolate->debug()->live_edit_enabled()); | |
13651 DCHECK(args.length() == 2); | |
13652 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); | |
13653 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); | |
13654 RUNTIME_ASSERT(shared_array->length()->IsSmi()); | |
13655 RUNTIME_ASSERT(shared_array->HasFastElements()) | |
13656 int array_length = Smi::cast(shared_array->length())->value(); | |
13657 for (int i = 0; i < array_length; i++) { | |
13658 Handle<Object> element = | |
13659 Object::GetElement(isolate, shared_array, i).ToHandleChecked(); | |
13660 RUNTIME_ASSERT( | |
13661 element->IsJSValue() && | |
13662 Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo()); | |
13663 } | |
13664 | |
13665 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); | |
13666 } | |
13667 | |
13668 | |
13669 // Compares 2 strings line-by-line, then token-wise and returns diff in form | |
13670 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list | |
13671 // of diff chunks. | |
13672 RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) { | |
13673 HandleScope scope(isolate); | |
13674 CHECK(isolate->debug()->live_edit_enabled()); | |
13675 DCHECK(args.length() == 2); | |
13676 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); | |
13677 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); | |
13678 | |
13679 return *LiveEdit::CompareStrings(s1, s2); | |
13680 } | |
13681 | |
13682 | |
13683 // Restarts a call frame and completely drops all frames above. | |
13684 // Returns true if successful. Otherwise returns undefined or an error message. | |
13685 RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) { | |
13686 HandleScope scope(isolate); | |
13687 CHECK(isolate->debug()->live_edit_enabled()); | |
13688 DCHECK(args.length() == 2); | |
13689 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
13690 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
13691 | |
13692 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
13693 Heap* heap = isolate->heap(); | |
13694 | |
13695 // Find the relevant frame with the requested index. | |
13696 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
13697 if (id == StackFrame::NO_ID) { | |
13698 // If there are no JavaScript stack frames return undefined. | |
13699 return heap->undefined_value(); | |
13700 } | |
13701 | |
13702 JavaScriptFrameIterator it(isolate, id); | |
13703 int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index); | |
13704 if (inlined_jsframe_index == -1) return heap->undefined_value(); | |
13705 // We don't really care what the inlined frame index is, since we are | |
13706 // throwing away the entire frame anyways. | |
13707 const char* error_message = LiveEdit::RestartFrame(it.frame()); | |
13708 if (error_message) { | |
13709 return *(isolate->factory()->InternalizeUtf8String(error_message)); | |
13710 } | |
13711 return heap->true_value(); | |
13712 } | |
13713 | |
13714 | |
13715 // A testing entry. Returns statement position which is the closest to | |
13716 // source_position. | |
13717 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) { | |
13718 HandleScope scope(isolate); | |
13719 CHECK(isolate->debug()->live_edit_enabled()); | |
13720 DCHECK(args.length() == 2); | |
13721 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
13722 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
13723 | |
13724 Handle<Code> code(function->code(), isolate); | |
13725 | |
13726 if (code->kind() != Code::FUNCTION && | |
13727 code->kind() != Code::OPTIMIZED_FUNCTION) { | |
13728 return isolate->heap()->undefined_value(); | |
13729 } | |
13730 | |
13731 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); | |
13732 int closest_pc = 0; | |
13733 int distance = kMaxInt; | |
13734 while (!it.done()) { | |
13735 int statement_position = static_cast<int>(it.rinfo()->data()); | |
13736 // Check if this break point is closer that what was previously found. | |
13737 if (source_position <= statement_position && | |
13738 statement_position - source_position < distance) { | |
13739 closest_pc = | |
13740 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); | |
13741 distance = statement_position - source_position; | |
13742 // Check whether we can't get any closer. | |
13743 if (distance == 0) break; | |
13744 } | |
13745 it.next(); | |
13746 } | |
13747 | |
13748 return Smi::FromInt(closest_pc); | |
13749 } | |
13750 | |
13751 | |
13752 // Calls specified function with or without entering the debugger. | |
13753 // This is used in unit tests to run code as if debugger is entered or simply | |
13754 // to have a stack with C++ frame in the middle. | |
13755 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) { | |
13756 HandleScope scope(isolate); | |
13757 DCHECK(args.length() == 2); | |
13758 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
13759 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); | |
13760 | |
13761 MaybeHandle<Object> maybe_result; | |
13762 if (without_debugger) { | |
13763 maybe_result = Execution::Call(isolate, | |
13764 function, | |
13765 handle(function->global_proxy()), | |
13766 0, | |
13767 NULL); | |
13768 } else { | |
13769 DebugScope debug_scope(isolate->debug()); | |
13770 maybe_result = Execution::Call(isolate, | |
13771 function, | |
13772 handle(function->global_proxy()), | |
13773 0, | |
13774 NULL); | |
13775 } | |
13776 Handle<Object> result; | |
13777 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); | |
13778 return *result; | |
13779 } | |
13780 | |
13781 | |
13782 // Sets a v8 flag. | |
13783 RUNTIME_FUNCTION(Runtime_SetFlags) { | |
13784 SealHandleScope shs(isolate); | |
13785 DCHECK(args.length() == 1); | |
13786 CONVERT_ARG_CHECKED(String, arg, 0); | |
13787 SmartArrayPointer<char> flags = | |
13788 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); | |
13789 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get())); | |
13790 return isolate->heap()->undefined_value(); | |
13791 } | |
13792 | |
13793 | |
13794 // Performs a GC. | |
13795 // Presently, it only does a full GC. | |
13796 RUNTIME_FUNCTION(Runtime_CollectGarbage) { | |
13797 SealHandleScope shs(isolate); | |
13798 DCHECK(args.length() == 1); | |
13799 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); | |
13800 return isolate->heap()->undefined_value(); | |
13801 } | |
13802 | |
13803 | |
13804 // Gets the current heap usage. | |
13805 RUNTIME_FUNCTION(Runtime_GetHeapUsage) { | |
13806 SealHandleScope shs(isolate); | |
13807 DCHECK(args.length() == 0); | |
13808 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); | |
13809 if (!Smi::IsValid(usage)) { | |
13810 return *isolate->factory()->NewNumberFromInt(usage); | |
13811 } | |
13812 return Smi::FromInt(usage); | |
13813 } | |
13814 | |
13815 | |
13816 #ifdef V8_I18N_SUPPORT | |
13817 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { | |
13818 HandleScope scope(isolate); | |
13819 Factory* factory = isolate->factory(); | |
13820 | |
13821 DCHECK(args.length() == 1); | |
13822 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); | |
13823 | |
13824 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); | |
13825 | |
13826 // Return value which denotes invalid language tag. | |
13827 const char* const kInvalidTag = "invalid-tag"; | |
13828 | |
13829 UErrorCode error = U_ZERO_ERROR; | |
13830 char icu_result[ULOC_FULLNAME_CAPACITY]; | |
13831 int icu_length = 0; | |
13832 | |
13833 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, | |
13834 &icu_length, &error); | |
13835 if (U_FAILURE(error) || icu_length == 0) { | |
13836 return *factory->NewStringFromAsciiChecked(kInvalidTag); | |
13837 } | |
13838 | |
13839 char result[ULOC_FULLNAME_CAPACITY]; | |
13840 | |
13841 // Force strict BCP47 rules. | |
13842 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); | |
13843 | |
13844 if (U_FAILURE(error)) { | |
13845 return *factory->NewStringFromAsciiChecked(kInvalidTag); | |
13846 } | |
13847 | |
13848 return *factory->NewStringFromAsciiChecked(result); | |
13849 } | |
13850 | |
13851 | |
13852 RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) { | |
13853 HandleScope scope(isolate); | |
13854 Factory* factory = isolate->factory(); | |
13855 | |
13856 DCHECK(args.length() == 1); | |
13857 CONVERT_ARG_HANDLE_CHECKED(String, service, 0); | |
13858 | |
13859 const icu::Locale* available_locales = NULL; | |
13860 int32_t count = 0; | |
13861 | |
13862 if (service->IsUtf8EqualTo(CStrVector("collator"))) { | |
13863 available_locales = icu::Collator::getAvailableLocales(count); | |
13864 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { | |
13865 available_locales = icu::NumberFormat::getAvailableLocales(count); | |
13866 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { | |
13867 available_locales = icu::DateFormat::getAvailableLocales(count); | |
13868 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { | |
13869 available_locales = icu::BreakIterator::getAvailableLocales(count); | |
13870 } | |
13871 | |
13872 UErrorCode error = U_ZERO_ERROR; | |
13873 char result[ULOC_FULLNAME_CAPACITY]; | |
13874 Handle<JSObject> locales = | |
13875 factory->NewJSObject(isolate->object_function()); | |
13876 | |
13877 for (int32_t i = 0; i < count; ++i) { | |
13878 const char* icu_name = available_locales[i].getName(); | |
13879 | |
13880 error = U_ZERO_ERROR; | |
13881 // No need to force strict BCP47 rules. | |
13882 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); | |
13883 if (U_FAILURE(error)) { | |
13884 // This shouldn't happen, but lets not break the user. | |
13885 continue; | |
13886 } | |
13887 | |
13888 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
13889 JSObject::SetOwnPropertyIgnoreAttributes( | |
13890 locales, | |
13891 factory->NewStringFromAsciiChecked(result), | |
13892 factory->NewNumber(i), | |
13893 NONE)); | |
13894 } | |
13895 | |
13896 return *locales; | |
13897 } | |
13898 | |
13899 | |
13900 RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) { | |
13901 HandleScope scope(isolate); | |
13902 Factory* factory = isolate->factory(); | |
13903 | |
13904 DCHECK(args.length() == 0); | |
13905 | |
13906 icu::Locale default_locale; | |
13907 | |
13908 // Set the locale | |
13909 char result[ULOC_FULLNAME_CAPACITY]; | |
13910 UErrorCode status = U_ZERO_ERROR; | |
13911 uloc_toLanguageTag( | |
13912 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); | |
13913 if (U_SUCCESS(status)) { | |
13914 return *factory->NewStringFromAsciiChecked(result); | |
13915 } | |
13916 | |
13917 return *factory->NewStringFromStaticChars("und"); | |
13918 } | |
13919 | |
13920 | |
13921 RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) { | |
13922 HandleScope scope(isolate); | |
13923 Factory* factory = isolate->factory(); | |
13924 | |
13925 DCHECK(args.length() == 1); | |
13926 | |
13927 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); | |
13928 | |
13929 uint32_t length = static_cast<uint32_t>(input->length()->Number()); | |
13930 // Set some limit to prevent fuzz tests from going OOM. | |
13931 // Can be bumped when callers' requirements change. | |
13932 RUNTIME_ASSERT(length < 100); | |
13933 Handle<FixedArray> output = factory->NewFixedArray(length); | |
13934 Handle<Name> maximized = factory->NewStringFromStaticChars("maximized"); | |
13935 Handle<Name> base = factory->NewStringFromStaticChars("base"); | |
13936 for (unsigned int i = 0; i < length; ++i) { | |
13937 Handle<Object> locale_id; | |
13938 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
13939 isolate, locale_id, Object::GetElement(isolate, input, i)); | |
13940 if (!locale_id->IsString()) { | |
13941 return isolate->Throw(*factory->illegal_argument_string()); | |
13942 } | |
13943 | |
13944 v8::String::Utf8Value utf8_locale_id( | |
13945 v8::Utils::ToLocal(Handle<String>::cast(locale_id))); | |
13946 | |
13947 UErrorCode error = U_ZERO_ERROR; | |
13948 | |
13949 // Convert from BCP47 to ICU format. | |
13950 // de-DE-u-co-phonebk -> de_DE@collation=phonebook | |
13951 char icu_locale[ULOC_FULLNAME_CAPACITY]; | |
13952 int icu_locale_length = 0; | |
13953 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, | |
13954 &icu_locale_length, &error); | |
13955 if (U_FAILURE(error) || icu_locale_length == 0) { | |
13956 return isolate->Throw(*factory->illegal_argument_string()); | |
13957 } | |
13958 | |
13959 // Maximize the locale. | |
13960 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook | |
13961 char icu_max_locale[ULOC_FULLNAME_CAPACITY]; | |
13962 uloc_addLikelySubtags( | |
13963 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); | |
13964 | |
13965 // Remove extensions from maximized locale. | |
13966 // de_Latn_DE@collation=phonebook -> de_Latn_DE | |
13967 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; | |
13968 uloc_getBaseName( | |
13969 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); | |
13970 | |
13971 // Get original name without extensions. | |
13972 // de_DE@collation=phonebook -> de_DE | |
13973 char icu_base_locale[ULOC_FULLNAME_CAPACITY]; | |
13974 uloc_getBaseName( | |
13975 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); | |
13976 | |
13977 // Convert from ICU locale format to BCP47 format. | |
13978 // de_Latn_DE -> de-Latn-DE | |
13979 char base_max_locale[ULOC_FULLNAME_CAPACITY]; | |
13980 uloc_toLanguageTag(icu_base_max_locale, base_max_locale, | |
13981 ULOC_FULLNAME_CAPACITY, FALSE, &error); | |
13982 | |
13983 // de_DE -> de-DE | |
13984 char base_locale[ULOC_FULLNAME_CAPACITY]; | |
13985 uloc_toLanguageTag( | |
13986 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); | |
13987 | |
13988 if (U_FAILURE(error)) { | |
13989 return isolate->Throw(*factory->illegal_argument_string()); | |
13990 } | |
13991 | |
13992 Handle<JSObject> result = factory->NewJSObject(isolate->object_function()); | |
13993 Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale); | |
13994 JSObject::AddProperty(result, maximized, value, NONE); | |
13995 value = factory->NewStringFromAsciiChecked(base_locale); | |
13996 JSObject::AddProperty(result, base, value, NONE); | |
13997 output->set(i, *result); | |
13998 } | |
13999 | |
14000 Handle<JSArray> result = factory->NewJSArrayWithElements(output); | |
14001 result->set_length(Smi::FromInt(length)); | |
14002 return *result; | |
14003 } | |
14004 | |
14005 | |
14006 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) { | |
14007 HandleScope scope(isolate); | |
14008 | |
14009 DCHECK(args.length() == 1); | |
14010 | |
14011 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); | |
14012 | |
14013 if (!input->IsJSObject()) return isolate->heap()->false_value(); | |
14014 Handle<JSObject> obj = Handle<JSObject>::cast(input); | |
14015 | |
14016 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); | |
14017 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); | |
14018 return isolate->heap()->ToBoolean(!tag->IsTheHole()); | |
14019 } | |
14020 | |
14021 | |
14022 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) { | |
14023 HandleScope scope(isolate); | |
14024 | |
14025 DCHECK(args.length() == 2); | |
14026 | |
14027 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); | |
14028 CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1); | |
14029 | |
14030 if (!input->IsJSObject()) return isolate->heap()->false_value(); | |
14031 Handle<JSObject> obj = Handle<JSObject>::cast(input); | |
14032 | |
14033 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); | |
14034 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); | |
14035 return isolate->heap()->ToBoolean( | |
14036 tag->IsString() && String::cast(*tag)->Equals(*expected_type)); | |
14037 } | |
14038 | |
14039 | |
14040 RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) { | |
14041 HandleScope scope(isolate); | |
14042 | |
14043 DCHECK(args.length() == 3); | |
14044 | |
14045 CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0); | |
14046 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); | |
14047 CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2); | |
14048 | |
14049 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); | |
14050 JSObject::SetHiddenProperty(input, marker, type); | |
14051 | |
14052 marker = isolate->factory()->intl_impl_object_string(); | |
14053 JSObject::SetHiddenProperty(input, marker, impl); | |
14054 | |
14055 return isolate->heap()->undefined_value(); | |
14056 } | |
14057 | |
14058 | |
14059 RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) { | |
14060 HandleScope scope(isolate); | |
14061 | |
14062 DCHECK(args.length() == 1); | |
14063 | |
14064 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); | |
14065 | |
14066 if (!input->IsJSObject()) { | |
14067 Vector< Handle<Object> > arguments = HandleVector(&input, 1); | |
14068 THROW_NEW_ERROR_RETURN_FAILURE(isolate, | |
14069 NewTypeError("not_intl_object", arguments)); | |
14070 } | |
14071 | |
14072 Handle<JSObject> obj = Handle<JSObject>::cast(input); | |
14073 | |
14074 Handle<String> marker = isolate->factory()->intl_impl_object_string(); | |
14075 Handle<Object> impl(obj->GetHiddenProperty(marker), isolate); | |
14076 if (impl->IsTheHole()) { | |
14077 Vector< Handle<Object> > arguments = HandleVector(&obj, 1); | |
14078 THROW_NEW_ERROR_RETURN_FAILURE(isolate, | |
14079 NewTypeError("not_intl_object", arguments)); | |
14080 } | |
14081 return *impl; | |
14082 } | |
14083 | |
14084 | |
14085 RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) { | |
14086 HandleScope scope(isolate); | |
14087 | |
14088 DCHECK(args.length() == 3); | |
14089 | |
14090 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); | |
14091 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); | |
14092 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); | |
14093 | |
14094 Handle<ObjectTemplateInfo> date_format_template = | |
14095 I18N::GetTemplate(isolate); | |
14096 | |
14097 // Create an empty object wrapper. | |
14098 Handle<JSObject> local_object; | |
14099 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14100 isolate, local_object, | |
14101 Execution::InstantiateObject(date_format_template)); | |
14102 | |
14103 // Set date time formatter as internal field of the resulting JS object. | |
14104 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( | |
14105 isolate, locale, options, resolved); | |
14106 | |
14107 if (!date_format) return isolate->ThrowIllegalOperation(); | |
14108 | |
14109 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); | |
14110 | |
14111 Factory* factory = isolate->factory(); | |
14112 Handle<String> key = factory->NewStringFromStaticChars("dateFormat"); | |
14113 Handle<String> value = factory->NewStringFromStaticChars("valid"); | |
14114 JSObject::AddProperty(local_object, key, value, NONE); | |
14115 | |
14116 // Make object handle weak so we can delete the data format once GC kicks in. | |
14117 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); | |
14118 GlobalHandles::MakeWeak(wrapper.location(), | |
14119 reinterpret_cast<void*>(wrapper.location()), | |
14120 DateFormat::DeleteDateFormat); | |
14121 return *local_object; | |
14122 } | |
14123 | |
14124 | |
14125 RUNTIME_FUNCTION(Runtime_InternalDateFormat) { | |
14126 HandleScope scope(isolate); | |
14127 | |
14128 DCHECK(args.length() == 2); | |
14129 | |
14130 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); | |
14131 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); | |
14132 | |
14133 Handle<Object> value; | |
14134 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14135 isolate, value, Execution::ToNumber(isolate, date)); | |
14136 | |
14137 icu::SimpleDateFormat* date_format = | |
14138 DateFormat::UnpackDateFormat(isolate, date_format_holder); | |
14139 if (!date_format) return isolate->ThrowIllegalOperation(); | |
14140 | |
14141 icu::UnicodeString result; | |
14142 date_format->format(value->Number(), result); | |
14143 | |
14144 Handle<String> result_str; | |
14145 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14146 isolate, result_str, | |
14147 isolate->factory()->NewStringFromTwoByte( | |
14148 Vector<const uint16_t>( | |
14149 reinterpret_cast<const uint16_t*>(result.getBuffer()), | |
14150 result.length()))); | |
14151 return *result_str; | |
14152 } | |
14153 | |
14154 | |
14155 RUNTIME_FUNCTION(Runtime_InternalDateParse) { | |
14156 HandleScope scope(isolate); | |
14157 | |
14158 DCHECK(args.length() == 2); | |
14159 | |
14160 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); | |
14161 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1); | |
14162 | |
14163 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string)); | |
14164 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date)); | |
14165 icu::SimpleDateFormat* date_format = | |
14166 DateFormat::UnpackDateFormat(isolate, date_format_holder); | |
14167 if (!date_format) return isolate->ThrowIllegalOperation(); | |
14168 | |
14169 UErrorCode status = U_ZERO_ERROR; | |
14170 UDate date = date_format->parse(u_date, status); | |
14171 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); | |
14172 | |
14173 Handle<Object> result; | |
14174 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14175 isolate, result, | |
14176 Execution::NewDate(isolate, static_cast<double>(date))); | |
14177 DCHECK(result->IsJSDate()); | |
14178 return *result; | |
14179 } | |
14180 | |
14181 | |
14182 RUNTIME_FUNCTION(Runtime_CreateNumberFormat) { | |
14183 HandleScope scope(isolate); | |
14184 | |
14185 DCHECK(args.length() == 3); | |
14186 | |
14187 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); | |
14188 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); | |
14189 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); | |
14190 | |
14191 Handle<ObjectTemplateInfo> number_format_template = | |
14192 I18N::GetTemplate(isolate); | |
14193 | |
14194 // Create an empty object wrapper. | |
14195 Handle<JSObject> local_object; | |
14196 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14197 isolate, local_object, | |
14198 Execution::InstantiateObject(number_format_template)); | |
14199 | |
14200 // Set number formatter as internal field of the resulting JS object. | |
14201 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( | |
14202 isolate, locale, options, resolved); | |
14203 | |
14204 if (!number_format) return isolate->ThrowIllegalOperation(); | |
14205 | |
14206 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); | |
14207 | |
14208 Factory* factory = isolate->factory(); | |
14209 Handle<String> key = factory->NewStringFromStaticChars("numberFormat"); | |
14210 Handle<String> value = factory->NewStringFromStaticChars("valid"); | |
14211 JSObject::AddProperty(local_object, key, value, NONE); | |
14212 | |
14213 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); | |
14214 GlobalHandles::MakeWeak(wrapper.location(), | |
14215 reinterpret_cast<void*>(wrapper.location()), | |
14216 NumberFormat::DeleteNumberFormat); | |
14217 return *local_object; | |
14218 } | |
14219 | |
14220 | |
14221 RUNTIME_FUNCTION(Runtime_InternalNumberFormat) { | |
14222 HandleScope scope(isolate); | |
14223 | |
14224 DCHECK(args.length() == 2); | |
14225 | |
14226 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); | |
14227 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); | |
14228 | |
14229 Handle<Object> value; | |
14230 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14231 isolate, value, Execution::ToNumber(isolate, number)); | |
14232 | |
14233 icu::DecimalFormat* number_format = | |
14234 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); | |
14235 if (!number_format) return isolate->ThrowIllegalOperation(); | |
14236 | |
14237 icu::UnicodeString result; | |
14238 number_format->format(value->Number(), result); | |
14239 | |
14240 Handle<String> result_str; | |
14241 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14242 isolate, result_str, | |
14243 isolate->factory()->NewStringFromTwoByte( | |
14244 Vector<const uint16_t>( | |
14245 reinterpret_cast<const uint16_t*>(result.getBuffer()), | |
14246 result.length()))); | |
14247 return *result_str; | |
14248 } | |
14249 | |
14250 | |
14251 RUNTIME_FUNCTION(Runtime_InternalNumberParse) { | |
14252 HandleScope scope(isolate); | |
14253 | |
14254 DCHECK(args.length() == 2); | |
14255 | |
14256 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); | |
14257 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1); | |
14258 | |
14259 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string)); | |
14260 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number)); | |
14261 icu::DecimalFormat* number_format = | |
14262 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); | |
14263 if (!number_format) return isolate->ThrowIllegalOperation(); | |
14264 | |
14265 UErrorCode status = U_ZERO_ERROR; | |
14266 icu::Formattable result; | |
14267 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 | |
14268 // to be part of Chrome. | |
14269 // TODO(cira): Include currency parsing code using parseCurrency call. | |
14270 // We need to check if the formatter parses all currencies or only the | |
14271 // one it was constructed with (it will impact the API - how to return ISO | |
14272 // code and the value). | |
14273 number_format->parse(u_number, result, status); | |
14274 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); | |
14275 | |
14276 switch (result.getType()) { | |
14277 case icu::Formattable::kDouble: | |
14278 return *isolate->factory()->NewNumber(result.getDouble()); | |
14279 case icu::Formattable::kLong: | |
14280 return *isolate->factory()->NewNumberFromInt(result.getLong()); | |
14281 case icu::Formattable::kInt64: | |
14282 return *isolate->factory()->NewNumber( | |
14283 static_cast<double>(result.getInt64())); | |
14284 default: | |
14285 return isolate->heap()->undefined_value(); | |
14286 } | |
14287 } | |
14288 | |
14289 | |
14290 RUNTIME_FUNCTION(Runtime_CreateCollator) { | |
14291 HandleScope scope(isolate); | |
14292 | |
14293 DCHECK(args.length() == 3); | |
14294 | |
14295 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); | |
14296 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); | |
14297 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); | |
14298 | |
14299 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); | |
14300 | |
14301 // Create an empty object wrapper. | |
14302 Handle<JSObject> local_object; | |
14303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14304 isolate, local_object, Execution::InstantiateObject(collator_template)); | |
14305 | |
14306 // Set collator as internal field of the resulting JS object. | |
14307 icu::Collator* collator = Collator::InitializeCollator( | |
14308 isolate, locale, options, resolved); | |
14309 | |
14310 if (!collator) return isolate->ThrowIllegalOperation(); | |
14311 | |
14312 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); | |
14313 | |
14314 Factory* factory = isolate->factory(); | |
14315 Handle<String> key = factory->NewStringFromStaticChars("collator"); | |
14316 Handle<String> value = factory->NewStringFromStaticChars("valid"); | |
14317 JSObject::AddProperty(local_object, key, value, NONE); | |
14318 | |
14319 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); | |
14320 GlobalHandles::MakeWeak(wrapper.location(), | |
14321 reinterpret_cast<void*>(wrapper.location()), | |
14322 Collator::DeleteCollator); | |
14323 return *local_object; | |
14324 } | |
14325 | |
14326 | |
14327 RUNTIME_FUNCTION(Runtime_InternalCompare) { | |
14328 HandleScope scope(isolate); | |
14329 | |
14330 DCHECK(args.length() == 3); | |
14331 | |
14332 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0); | |
14333 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1); | |
14334 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2); | |
14335 | |
14336 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder); | |
14337 if (!collator) return isolate->ThrowIllegalOperation(); | |
14338 | |
14339 v8::String::Value string_value1(v8::Utils::ToLocal(string1)); | |
14340 v8::String::Value string_value2(v8::Utils::ToLocal(string2)); | |
14341 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1); | |
14342 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2); | |
14343 UErrorCode status = U_ZERO_ERROR; | |
14344 UCollationResult result = collator->compare(u_string1, | |
14345 string_value1.length(), | |
14346 u_string2, | |
14347 string_value2.length(), | |
14348 status); | |
14349 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation(); | |
14350 | |
14351 return *isolate->factory()->NewNumberFromInt(result); | |
14352 } | |
14353 | |
14354 | |
14355 RUNTIME_FUNCTION(Runtime_StringNormalize) { | |
14356 HandleScope scope(isolate); | |
14357 static const UNormalizationMode normalizationForms[] = | |
14358 { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD }; | |
14359 | |
14360 DCHECK(args.length() == 2); | |
14361 | |
14362 CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0); | |
14363 CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]); | |
14364 RUNTIME_ASSERT(form_id >= 0 && | |
14365 static_cast<size_t>(form_id) < arraysize(normalizationForms)); | |
14366 | |
14367 v8::String::Value string_value(v8::Utils::ToLocal(stringValue)); | |
14368 const UChar* u_value = reinterpret_cast<const UChar*>(*string_value); | |
14369 | |
14370 // TODO(mnita): check Normalizer2 (not available in ICU 46) | |
14371 UErrorCode status = U_ZERO_ERROR; | |
14372 icu::UnicodeString result; | |
14373 icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0, | |
14374 result, status); | |
14375 if (U_FAILURE(status)) { | |
14376 return isolate->heap()->undefined_value(); | |
14377 } | |
14378 | |
14379 Handle<String> result_str; | |
14380 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14381 isolate, result_str, | |
14382 isolate->factory()->NewStringFromTwoByte( | |
14383 Vector<const uint16_t>( | |
14384 reinterpret_cast<const uint16_t*>(result.getBuffer()), | |
14385 result.length()))); | |
14386 return *result_str; | |
14387 } | |
14388 | |
14389 | |
14390 RUNTIME_FUNCTION(Runtime_CreateBreakIterator) { | |
14391 HandleScope scope(isolate); | |
14392 | |
14393 DCHECK(args.length() == 3); | |
14394 | |
14395 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); | |
14396 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); | |
14397 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); | |
14398 | |
14399 Handle<ObjectTemplateInfo> break_iterator_template = | |
14400 I18N::GetTemplate2(isolate); | |
14401 | |
14402 // Create an empty object wrapper. | |
14403 Handle<JSObject> local_object; | |
14404 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14405 isolate, local_object, | |
14406 Execution::InstantiateObject(break_iterator_template)); | |
14407 | |
14408 // Set break iterator as internal field of the resulting JS object. | |
14409 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator( | |
14410 isolate, locale, options, resolved); | |
14411 | |
14412 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14413 | |
14414 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator)); | |
14415 // Make sure that the pointer to adopted text is NULL. | |
14416 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL)); | |
14417 | |
14418 Factory* factory = isolate->factory(); | |
14419 Handle<String> key = factory->NewStringFromStaticChars("breakIterator"); | |
14420 Handle<String> value = factory->NewStringFromStaticChars("valid"); | |
14421 JSObject::AddProperty(local_object, key, value, NONE); | |
14422 | |
14423 // Make object handle weak so we can delete the break iterator once GC kicks | |
14424 // in. | |
14425 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); | |
14426 GlobalHandles::MakeWeak(wrapper.location(), | |
14427 reinterpret_cast<void*>(wrapper.location()), | |
14428 BreakIterator::DeleteBreakIterator); | |
14429 return *local_object; | |
14430 } | |
14431 | |
14432 | |
14433 RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) { | |
14434 HandleScope scope(isolate); | |
14435 | |
14436 DCHECK(args.length() == 2); | |
14437 | |
14438 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); | |
14439 CONVERT_ARG_HANDLE_CHECKED(String, text, 1); | |
14440 | |
14441 icu::BreakIterator* break_iterator = | |
14442 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); | |
14443 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14444 | |
14445 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>( | |
14446 break_iterator_holder->GetInternalField(1)); | |
14447 delete u_text; | |
14448 | |
14449 v8::String::Value text_value(v8::Utils::ToLocal(text)); | |
14450 u_text = new icu::UnicodeString( | |
14451 reinterpret_cast<const UChar*>(*text_value), text_value.length()); | |
14452 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text)); | |
14453 | |
14454 break_iterator->setText(*u_text); | |
14455 | |
14456 return isolate->heap()->undefined_value(); | |
14457 } | |
14458 | |
14459 | |
14460 RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) { | |
14461 HandleScope scope(isolate); | |
14462 | |
14463 DCHECK(args.length() == 1); | |
14464 | |
14465 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); | |
14466 | |
14467 icu::BreakIterator* break_iterator = | |
14468 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); | |
14469 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14470 | |
14471 return *isolate->factory()->NewNumberFromInt(break_iterator->first()); | |
14472 } | |
14473 | |
14474 | |
14475 RUNTIME_FUNCTION(Runtime_BreakIteratorNext) { | |
14476 HandleScope scope(isolate); | |
14477 | |
14478 DCHECK(args.length() == 1); | |
14479 | |
14480 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); | |
14481 | |
14482 icu::BreakIterator* break_iterator = | |
14483 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); | |
14484 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14485 | |
14486 return *isolate->factory()->NewNumberFromInt(break_iterator->next()); | |
14487 } | |
14488 | |
14489 | |
14490 RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) { | |
14491 HandleScope scope(isolate); | |
14492 | |
14493 DCHECK(args.length() == 1); | |
14494 | |
14495 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); | |
14496 | |
14497 icu::BreakIterator* break_iterator = | |
14498 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); | |
14499 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14500 | |
14501 return *isolate->factory()->NewNumberFromInt(break_iterator->current()); | |
14502 } | |
14503 | |
14504 | |
14505 RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) { | |
14506 HandleScope scope(isolate); | |
14507 | |
14508 DCHECK(args.length() == 1); | |
14509 | |
14510 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); | |
14511 | |
14512 icu::BreakIterator* break_iterator = | |
14513 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); | |
14514 if (!break_iterator) return isolate->ThrowIllegalOperation(); | |
14515 | |
14516 // TODO(cira): Remove cast once ICU fixes base BreakIterator class. | |
14517 icu::RuleBasedBreakIterator* rule_based_iterator = | |
14518 static_cast<icu::RuleBasedBreakIterator*>(break_iterator); | |
14519 int32_t status = rule_based_iterator->getRuleStatus(); | |
14520 // Keep return values in sync with JavaScript BreakType enum. | |
14521 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { | |
14522 return *isolate->factory()->NewStringFromStaticChars("none"); | |
14523 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { | |
14524 return *isolate->factory()->number_string(); | |
14525 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { | |
14526 return *isolate->factory()->NewStringFromStaticChars("letter"); | |
14527 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { | |
14528 return *isolate->factory()->NewStringFromStaticChars("kana"); | |
14529 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { | |
14530 return *isolate->factory()->NewStringFromStaticChars("ideo"); | |
14531 } else { | |
14532 return *isolate->factory()->NewStringFromStaticChars("unknown"); | |
14533 } | |
14534 } | |
14535 #endif // V8_I18N_SUPPORT | |
14536 | |
14537 | |
14538 // Finds the script object from the script data. NOTE: This operation uses | |
14539 // heap traversal to find the function generated for the source position | |
14540 // for the requested break point. For lazily compiled functions several heap | |
14541 // traversals might be required rendering this operation as a rather slow | |
14542 // operation. However for setting break points which is normally done through | |
14543 // some kind of user interaction the performance is not crucial. | |
14544 static Handle<Object> Runtime_GetScriptFromScriptName( | |
14545 Handle<String> script_name) { | |
14546 // Scan the heap for Script objects to find the script with the requested | |
14547 // script data. | |
14548 Handle<Script> script; | |
14549 Factory* factory = script_name->GetIsolate()->factory(); | |
14550 Heap* heap = script_name->GetHeap(); | |
14551 HeapIterator iterator(heap); | |
14552 HeapObject* obj = NULL; | |
14553 while (script.is_null() && ((obj = iterator.next()) != NULL)) { | |
14554 // If a script is found check if it has the script data requested. | |
14555 if (obj->IsScript()) { | |
14556 if (Script::cast(obj)->name()->IsString()) { | |
14557 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { | |
14558 script = Handle<Script>(Script::cast(obj)); | |
14559 } | |
14560 } | |
14561 } | |
14562 } | |
14563 | |
14564 // If no script with the requested script data is found return undefined. | |
14565 if (script.is_null()) return factory->undefined_value(); | |
14566 | |
14567 // Return the script found. | |
14568 return Script::GetWrapper(script); | |
14569 } | |
14570 | |
14571 | |
14572 // Get the script object from script data. NOTE: Regarding performance | |
14573 // see the NOTE for GetScriptFromScriptData. | |
14574 // args[0]: script data for the script to find the source for | |
14575 RUNTIME_FUNCTION(Runtime_GetScript) { | |
14576 HandleScope scope(isolate); | |
14577 | |
14578 DCHECK(args.length() == 1); | |
14579 | |
14580 CONVERT_ARG_CHECKED(String, script_name, 0); | |
14581 | |
14582 // Find the requested script. | |
14583 Handle<Object> result = | |
14584 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); | |
14585 return *result; | |
14586 } | |
14587 | |
14588 | |
14589 // Collect the raw data for a stack trace. Returns an array of 4 | |
14590 // element segments each containing a receiver, function, code and | |
14591 // native code offset. | |
14592 RUNTIME_FUNCTION(Runtime_CollectStackTrace) { | |
14593 HandleScope scope(isolate); | |
14594 DCHECK(args.length() == 2); | |
14595 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); | |
14596 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); | |
14597 | |
14598 if (!isolate->bootstrapper()->IsActive()) { | |
14599 // Optionally capture a more detailed stack trace for the message. | |
14600 isolate->CaptureAndSetDetailedStackTrace(error_object); | |
14601 // Capture a simple stack trace for the stack property. | |
14602 isolate->CaptureAndSetSimpleStackTrace(error_object, caller); | |
14603 } | |
14604 return isolate->heap()->undefined_value(); | |
14605 } | |
14606 | |
14607 | |
14608 // Returns V8 version as a string. | |
14609 RUNTIME_FUNCTION(Runtime_GetV8Version) { | |
14610 HandleScope scope(isolate); | |
14611 DCHECK(args.length() == 0); | |
14612 | |
14613 const char* version_string = v8::V8::GetVersion(); | |
14614 | |
14615 return *isolate->factory()->NewStringFromAsciiChecked(version_string); | |
14616 } | |
14617 | |
14618 | |
14619 // Returns function of generator activation. | |
14620 RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) { | |
14621 HandleScope scope(isolate); | |
14622 DCHECK(args.length() == 1); | |
14623 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
14624 | |
14625 return generator->function(); | |
14626 } | |
14627 | |
14628 | |
14629 // Returns context of generator activation. | |
14630 RUNTIME_FUNCTION(Runtime_GeneratorGetContext) { | |
14631 HandleScope scope(isolate); | |
14632 DCHECK(args.length() == 1); | |
14633 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
14634 | |
14635 return generator->context(); | |
14636 } | |
14637 | |
14638 | |
14639 // Returns receiver of generator activation. | |
14640 RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) { | |
14641 HandleScope scope(isolate); | |
14642 DCHECK(args.length() == 1); | |
14643 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
14644 | |
14645 return generator->receiver(); | |
14646 } | |
14647 | |
14648 | |
14649 // Returns generator continuation as a PC offset, or the magic -1 or 0 values. | |
14650 RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) { | |
14651 HandleScope scope(isolate); | |
14652 DCHECK(args.length() == 1); | |
14653 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
14654 | |
14655 return Smi::FromInt(generator->continuation()); | |
14656 } | |
14657 | |
14658 | |
14659 RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) { | |
14660 HandleScope scope(isolate); | |
14661 DCHECK(args.length() == 1); | |
14662 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
14663 | |
14664 if (generator->is_suspended()) { | |
14665 Handle<Code> code(generator->function()->code(), isolate); | |
14666 int offset = generator->continuation(); | |
14667 | |
14668 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); | |
14669 Address pc = code->address() + offset; | |
14670 | |
14671 return Smi::FromInt(code->SourcePosition(pc)); | |
14672 } | |
14673 | |
14674 return isolate->heap()->undefined_value(); | |
14675 } | |
14676 | |
14677 | |
14678 RUNTIME_FUNCTION(Runtime_Abort) { | |
14679 SealHandleScope shs(isolate); | |
14680 DCHECK(args.length() == 1); | |
14681 CONVERT_SMI_ARG_CHECKED(message_id, 0); | |
14682 const char* message = GetBailoutReason( | |
14683 static_cast<BailoutReason>(message_id)); | |
14684 base::OS::PrintError("abort: %s\n", message); | |
14685 isolate->PrintStack(stderr); | |
14686 base::OS::Abort(); | |
14687 UNREACHABLE(); | |
14688 return NULL; | |
14689 } | |
14690 | |
14691 | |
14692 RUNTIME_FUNCTION(Runtime_AbortJS) { | |
14693 HandleScope scope(isolate); | |
14694 DCHECK(args.length() == 1); | |
14695 CONVERT_ARG_HANDLE_CHECKED(String, message, 0); | |
14696 base::OS::PrintError("abort: %s\n", message->ToCString().get()); | |
14697 isolate->PrintStack(stderr); | |
14698 base::OS::Abort(); | |
14699 UNREACHABLE(); | |
14700 return NULL; | |
14701 } | |
14702 | |
14703 | |
14704 RUNTIME_FUNCTION(Runtime_FlattenString) { | |
14705 HandleScope scope(isolate); | |
14706 DCHECK(args.length() == 1); | |
14707 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); | |
14708 return *String::Flatten(str); | |
14709 } | |
14710 | |
14711 | |
14712 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) { | |
14713 HandleScope scope(isolate); | |
14714 DCHECK(args.length() == 0); | |
14715 isolate->heap()->NotifyContextDisposed(); | |
14716 return isolate->heap()->undefined_value(); | |
14717 } | |
14718 | |
14719 | |
14720 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { | |
14721 HandleScope scope(isolate); | |
14722 DCHECK(args.length() == 2); | |
14723 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
14724 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); | |
14725 RUNTIME_ASSERT((index->value() & 1) == 1); | |
14726 FieldIndex field_index = | |
14727 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); | |
14728 if (field_index.is_inobject()) { | |
14729 RUNTIME_ASSERT(field_index.property_index() < | |
14730 object->map()->inobject_properties()); | |
14731 } else { | |
14732 RUNTIME_ASSERT(field_index.outobject_array_index() < | |
14733 object->properties()->length()); | |
14734 } | |
14735 Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate); | |
14736 RUNTIME_ASSERT(raw_value->IsMutableHeapNumber()); | |
14737 return *Object::WrapForRead(isolate, raw_value, Representation::Double()); | |
14738 } | |
14739 | |
14740 | |
14741 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { | |
14742 HandleScope scope(isolate); | |
14743 DCHECK(args.length() == 1); | |
14744 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
14745 if (!object->IsJSObject()) return Smi::FromInt(0); | |
14746 Handle<JSObject> js_object = Handle<JSObject>::cast(object); | |
14747 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); | |
14748 // This call must not cause lazy deopts, because it's called from deferred | |
14749 // code where we can't handle lazy deopts for lack of a suitable bailout | |
14750 // ID. So we just try migration and signal failure if necessary, | |
14751 // which will also trigger a deopt. | |
14752 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0); | |
14753 return *object; | |
14754 } | |
14755 | |
14756 | |
14757 RUNTIME_FUNCTION(Runtime_GetFromCache) { | |
14758 SealHandleScope shs(isolate); | |
14759 // This is only called from codegen, so checks might be more lax. | |
14760 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); | |
14761 CONVERT_ARG_CHECKED(Object, key, 1); | |
14762 | |
14763 { | |
14764 DisallowHeapAllocation no_alloc; | |
14765 | |
14766 int finger_index = cache->finger_index(); | |
14767 Object* o = cache->get(finger_index); | |
14768 if (o == key) { | |
14769 // The fastest case: hit the same place again. | |
14770 return cache->get(finger_index + 1); | |
14771 } | |
14772 | |
14773 for (int i = finger_index - 2; | |
14774 i >= JSFunctionResultCache::kEntriesIndex; | |
14775 i -= 2) { | |
14776 o = cache->get(i); | |
14777 if (o == key) { | |
14778 cache->set_finger_index(i); | |
14779 return cache->get(i + 1); | |
14780 } | |
14781 } | |
14782 | |
14783 int size = cache->size(); | |
14784 DCHECK(size <= cache->length()); | |
14785 | |
14786 for (int i = size - 2; i > finger_index; i -= 2) { | |
14787 o = cache->get(i); | |
14788 if (o == key) { | |
14789 cache->set_finger_index(i); | |
14790 return cache->get(i + 1); | |
14791 } | |
14792 } | |
14793 } | |
14794 | |
14795 // There is no value in the cache. Invoke the function and cache result. | |
14796 HandleScope scope(isolate); | |
14797 | |
14798 Handle<JSFunctionResultCache> cache_handle(cache); | |
14799 Handle<Object> key_handle(key, isolate); | |
14800 Handle<Object> value; | |
14801 { | |
14802 Handle<JSFunction> factory(JSFunction::cast( | |
14803 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); | |
14804 // TODO(antonm): consider passing a receiver when constructing a cache. | |
14805 Handle<JSObject> receiver(isolate->global_proxy()); | |
14806 // This handle is nor shared, nor used later, so it's safe. | |
14807 Handle<Object> argv[] = { key_handle }; | |
14808 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
14809 isolate, value, | |
14810 Execution::Call(isolate, factory, receiver, arraysize(argv), argv)); | |
14811 } | |
14812 | |
14813 #ifdef VERIFY_HEAP | |
14814 if (FLAG_verify_heap) { | |
14815 cache_handle->JSFunctionResultCacheVerify(); | |
14816 } | |
14817 #endif | |
14818 | |
14819 // Function invocation may have cleared the cache. Reread all the data. | |
14820 int finger_index = cache_handle->finger_index(); | |
14821 int size = cache_handle->size(); | |
14822 | |
14823 // If we have spare room, put new data into it, otherwise evict post finger | |
14824 // entry which is likely to be the least recently used. | |
14825 int index = -1; | |
14826 if (size < cache_handle->length()) { | |
14827 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); | |
14828 index = size; | |
14829 } else { | |
14830 index = finger_index + JSFunctionResultCache::kEntrySize; | |
14831 if (index == cache_handle->length()) { | |
14832 index = JSFunctionResultCache::kEntriesIndex; | |
14833 } | |
14834 } | |
14835 | |
14836 DCHECK(index % 2 == 0); | |
14837 DCHECK(index >= JSFunctionResultCache::kEntriesIndex); | |
14838 DCHECK(index < cache_handle->length()); | |
14839 | |
14840 cache_handle->set(index, *key_handle); | |
14841 cache_handle->set(index + 1, *value); | |
14842 cache_handle->set_finger_index(index); | |
14843 | |
14844 #ifdef VERIFY_HEAP | |
14845 if (FLAG_verify_heap) { | |
14846 cache_handle->JSFunctionResultCacheVerify(); | |
14847 } | |
14848 #endif | |
14849 | |
14850 return *value; | |
14851 } | |
14852 | |
14853 | |
14854 RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) { | |
14855 SealHandleScope shs(isolate); | |
14856 DCHECK(args.length() == 1); | |
14857 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); | |
14858 return Smi::FromInt(message->start_position()); | |
14859 } | |
14860 | |
14861 | |
14862 RUNTIME_FUNCTION(Runtime_MessageGetScript) { | |
14863 SealHandleScope shs(isolate); | |
14864 DCHECK(args.length() == 1); | |
14865 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); | |
14866 return message->script(); | |
14867 } | |
14868 | |
14869 | |
14870 #ifdef DEBUG | |
14871 // ListNatives is ONLY used by the fuzz-natives.js in debug mode | |
14872 // Exclude the code in release mode. | |
14873 RUNTIME_FUNCTION(Runtime_ListNatives) { | |
14874 HandleScope scope(isolate); | |
14875 DCHECK(args.length() == 0); | |
14876 #define COUNT_ENTRY(Name, argc, ressize) + 1 | |
14877 int entry_count = 0 | |
14878 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) | |
14879 INLINE_FUNCTION_LIST(COUNT_ENTRY) | |
14880 INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY); | |
14881 #undef COUNT_ENTRY | |
14882 Factory* factory = isolate->factory(); | |
14883 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); | |
14884 int index = 0; | |
14885 bool inline_runtime_functions = false; | |
14886 #define ADD_ENTRY(Name, argc, ressize) \ | |
14887 { \ | |
14888 HandleScope inner(isolate); \ | |
14889 Handle<String> name; \ | |
14890 /* Inline runtime functions have an underscore in front of the name. */ \ | |
14891 if (inline_runtime_functions) { \ | |
14892 name = factory->NewStringFromStaticChars("_" #Name); \ | |
14893 } else { \ | |
14894 name = factory->NewStringFromStaticChars(#Name); \ | |
14895 } \ | |
14896 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ | |
14897 pair_elements->set(0, *name); \ | |
14898 pair_elements->set(1, Smi::FromInt(argc)); \ | |
14899 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ | |
14900 elements->set(index++, *pair); \ | |
14901 } | |
14902 inline_runtime_functions = false; | |
14903 RUNTIME_FUNCTION_LIST(ADD_ENTRY) | |
14904 INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY) | |
14905 inline_runtime_functions = true; | |
14906 INLINE_FUNCTION_LIST(ADD_ENTRY) | |
14907 #undef ADD_ENTRY | |
14908 DCHECK_EQ(index, entry_count); | |
14909 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); | |
14910 return *result; | |
14911 } | |
14912 #endif | |
14913 | |
14914 | |
14915 RUNTIME_FUNCTION(Runtime_IS_VAR) { | |
14916 UNREACHABLE(); // implemented as macro in the parser | |
14917 return NULL; | |
14918 } | |
14919 | |
14920 | |
14921 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ | |
14922 RUNTIME_FUNCTION(Runtime_Has##Name) { \ | |
14923 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ | |
14924 return isolate->heap()->ToBoolean(obj->Has##Name()); \ | |
14925 } | |
14926 | |
14927 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) | |
14928 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) | |
14929 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) | |
14930 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) | |
14931 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) | |
14932 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) | |
14933 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) | |
14934 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) | |
14935 // Properties test sitting with elements tests - not fooling anyone. | |
14936 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) | |
14937 | |
14938 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION | |
14939 | |
14940 | |
14941 #define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \ | |
14942 RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \ | |
14943 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ | |
14944 return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \ | |
14945 } | |
14946 | |
14947 TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) | |
14948 | |
14949 #undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION | |
14950 | |
14951 | |
14952 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ | |
14953 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ | |
14954 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ | |
14955 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ | |
14956 } | |
14957 | |
14958 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) | |
14959 | |
14960 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION | |
14961 | |
14962 | |
14963 RUNTIME_FUNCTION(Runtime_HaveSameMap) { | |
14964 SealHandleScope shs(isolate); | |
14965 DCHECK(args.length() == 2); | |
14966 CONVERT_ARG_CHECKED(JSObject, obj1, 0); | |
14967 CONVERT_ARG_CHECKED(JSObject, obj2, 1); | |
14968 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); | |
14969 } | |
14970 | |
14971 | |
14972 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { | |
14973 SealHandleScope shs(isolate); | |
14974 DCHECK(args.length() == 1); | |
14975 CONVERT_ARG_CHECKED(Object, obj, 0); | |
14976 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); | |
14977 } | |
14978 | |
14979 | |
14980 RUNTIME_FUNCTION(Runtime_IsObserved) { | |
14981 SealHandleScope shs(isolate); | |
14982 DCHECK(args.length() == 1); | |
14983 | |
14984 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value(); | |
14985 CONVERT_ARG_CHECKED(JSReceiver, obj, 0); | |
14986 DCHECK(!obj->IsJSGlobalProxy() || !obj->map()->is_observed()); | |
14987 return isolate->heap()->ToBoolean(obj->map()->is_observed()); | |
14988 } | |
14989 | |
14990 | |
14991 RUNTIME_FUNCTION(Runtime_SetIsObserved) { | |
14992 HandleScope scope(isolate); | |
14993 DCHECK(args.length() == 1); | |
14994 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); | |
14995 RUNTIME_ASSERT(!obj->IsJSGlobalProxy()); | |
14996 if (obj->IsJSProxy()) return isolate->heap()->undefined_value(); | |
14997 RUNTIME_ASSERT(!obj->map()->is_observed()); | |
14998 | |
14999 DCHECK(obj->IsJSObject()); | |
15000 JSObject::SetObserved(Handle<JSObject>::cast(obj)); | |
15001 return isolate->heap()->undefined_value(); | |
15002 } | |
15003 | |
15004 | |
15005 RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) { | |
15006 HandleScope scope(isolate); | |
15007 DCHECK(args.length() == 1); | |
15008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0); | |
15009 isolate->EnqueueMicrotask(microtask); | |
15010 return isolate->heap()->undefined_value(); | |
15011 } | |
15012 | |
15013 | |
15014 RUNTIME_FUNCTION(Runtime_RunMicrotasks) { | |
15015 HandleScope scope(isolate); | |
15016 DCHECK(args.length() == 0); | |
15017 isolate->RunMicrotasks(); | |
15018 return isolate->heap()->undefined_value(); | |
15019 } | |
15020 | |
15021 | |
15022 RUNTIME_FUNCTION(Runtime_GetObservationState) { | |
15023 SealHandleScope shs(isolate); | |
15024 DCHECK(args.length() == 0); | |
15025 return isolate->heap()->observation_state(); | |
15026 } | |
15027 | |
15028 | |
15029 RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) { | |
15030 HandleScope scope(isolate); | |
15031 DCHECK(args.length() == 0); | |
15032 // TODO(adamk): Currently this runtime function is only called three times per | |
15033 // isolate. If it's called more often, the map should be moved into the | |
15034 // strong root list. | |
15035 Handle<Map> map = | |
15036 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); | |
15037 Handle<JSWeakMap> weakmap = | |
15038 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map)); | |
15039 return *WeakCollectionInitialize(isolate, weakmap); | |
15040 } | |
15041 | |
15042 | |
15043 static bool ContextsHaveSameOrigin(Handle<Context> context1, | |
15044 Handle<Context> context2) { | |
15045 return context1->security_token() == context2->security_token(); | |
15046 } | |
15047 | |
15048 | |
15049 RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) { | |
15050 HandleScope scope(isolate); | |
15051 DCHECK(args.length() == 3); | |
15052 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0); | |
15053 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1); | |
15054 CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2); | |
15055 | |
15056 Handle<Context> observer_context(observer->context()->native_context()); | |
15057 Handle<Context> object_context(object->GetCreationContext()); | |
15058 Handle<Context> record_context(record->GetCreationContext()); | |
15059 | |
15060 return isolate->heap()->ToBoolean( | |
15061 ContextsHaveSameOrigin(object_context, observer_context) && | |
15062 ContextsHaveSameOrigin(object_context, record_context)); | |
15063 } | |
15064 | |
15065 | |
15066 RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) { | |
15067 HandleScope scope(isolate); | |
15068 DCHECK(args.length() == 1); | |
15069 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
15070 | |
15071 Handle<Context> creation_context(object->GetCreationContext(), isolate); | |
15072 return isolate->heap()->ToBoolean( | |
15073 ContextsHaveSameOrigin(creation_context, isolate->native_context())); | |
15074 } | |
15075 | |
15076 | |
15077 RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) { | |
15078 HandleScope scope(isolate); | |
15079 DCHECK(args.length() == 1); | |
15080 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
15081 | |
15082 Handle<Context> context(object->GetCreationContext(), isolate); | |
15083 return context->native_object_observe(); | |
15084 } | |
15085 | |
15086 | |
15087 RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) { | |
15088 HandleScope scope(isolate); | |
15089 DCHECK(args.length() == 1); | |
15090 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | |
15091 | |
15092 Handle<Context> context(object->GetCreationContext(), isolate); | |
15093 return context->native_object_get_notifier(); | |
15094 } | |
15095 | |
15096 | |
15097 RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) { | |
15098 HandleScope scope(isolate); | |
15099 DCHECK(args.length() == 1); | |
15100 CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0); | |
15101 | |
15102 Handle<Context> context(object_info->GetCreationContext(), isolate); | |
15103 return context->native_object_notifier_perform_change(); | |
15104 } | |
15105 | |
15106 | |
15107 static Object* ArrayConstructorCommon(Isolate* isolate, | |
15108 Handle<JSFunction> constructor, | |
15109 Handle<AllocationSite> site, | |
15110 Arguments* caller_args) { | |
15111 Factory* factory = isolate->factory(); | |
15112 | |
15113 bool holey = false; | |
15114 bool can_use_type_feedback = true; | |
15115 if (caller_args->length() == 1) { | |
15116 Handle<Object> argument_one = caller_args->at<Object>(0); | |
15117 if (argument_one->IsSmi()) { | |
15118 int value = Handle<Smi>::cast(argument_one)->value(); | |
15119 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) { | |
15120 // the array is a dictionary in this case. | |
15121 can_use_type_feedback = false; | |
15122 } else if (value != 0) { | |
15123 holey = true; | |
15124 } | |
15125 } else { | |
15126 // Non-smi length argument produces a dictionary | |
15127 can_use_type_feedback = false; | |
15128 } | |
15129 } | |
15130 | |
15131 Handle<JSArray> array; | |
15132 if (!site.is_null() && can_use_type_feedback) { | |
15133 ElementsKind to_kind = site->GetElementsKind(); | |
15134 if (holey && !IsFastHoleyElementsKind(to_kind)) { | |
15135 to_kind = GetHoleyElementsKind(to_kind); | |
15136 // Update the allocation site info to reflect the advice alteration. | |
15137 site->SetElementsKind(to_kind); | |
15138 } | |
15139 | |
15140 // We should allocate with an initial map that reflects the allocation site | |
15141 // advice. Therefore we use AllocateJSObjectFromMap instead of passing | |
15142 // the constructor. | |
15143 Handle<Map> initial_map(constructor->initial_map(), isolate); | |
15144 if (to_kind != initial_map->elements_kind()) { | |
15145 initial_map = Map::AsElementsKind(initial_map, to_kind); | |
15146 } | |
15147 | |
15148 // If we don't care to track arrays of to_kind ElementsKind, then | |
15149 // don't emit a memento for them. | |
15150 Handle<AllocationSite> allocation_site; | |
15151 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) { | |
15152 allocation_site = site; | |
15153 } | |
15154 | |
15155 array = Handle<JSArray>::cast(factory->NewJSObjectFromMap( | |
15156 initial_map, NOT_TENURED, true, allocation_site)); | |
15157 } else { | |
15158 array = Handle<JSArray>::cast(factory->NewJSObject(constructor)); | |
15159 | |
15160 // We might need to transition to holey | |
15161 ElementsKind kind = constructor->initial_map()->elements_kind(); | |
15162 if (holey && !IsFastHoleyElementsKind(kind)) { | |
15163 kind = GetHoleyElementsKind(kind); | |
15164 JSObject::TransitionElementsKind(array, kind); | |
15165 } | |
15166 } | |
15167 | |
15168 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS); | |
15169 | |
15170 ElementsKind old_kind = array->GetElementsKind(); | |
15171 RETURN_FAILURE_ON_EXCEPTION( | |
15172 isolate, ArrayConstructInitializeElements(array, caller_args)); | |
15173 if (!site.is_null() && | |
15174 (old_kind != array->GetElementsKind() || | |
15175 !can_use_type_feedback)) { | |
15176 // The arguments passed in caused a transition. This kind of complexity | |
15177 // can't be dealt with in the inlined hydrogen array constructor case. | |
15178 // We must mark the allocationsite as un-inlinable. | |
15179 site->SetDoNotInlineCall(); | |
15180 } | |
15181 return *array; | |
15182 } | |
15183 | |
15184 | |
15185 RUNTIME_FUNCTION(Runtime_ArrayConstructor) { | |
15186 HandleScope scope(isolate); | |
15187 // If we get 2 arguments then they are the stub parameters (constructor, type | |
15188 // info). If we get 4, then the first one is a pointer to the arguments | |
15189 // passed by the caller, and the last one is the length of the arguments | |
15190 // passed to the caller (redundant, but useful to check on the deoptimizer | |
15191 // with an assert). | |
15192 Arguments empty_args(0, NULL); | |
15193 bool no_caller_args = args.length() == 2; | |
15194 DCHECK(no_caller_args || args.length() == 4); | |
15195 int parameters_start = no_caller_args ? 0 : 1; | |
15196 Arguments* caller_args = no_caller_args | |
15197 ? &empty_args | |
15198 : reinterpret_cast<Arguments*>(args[0]); | |
15199 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); | |
15200 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1); | |
15201 #ifdef DEBUG | |
15202 if (!no_caller_args) { | |
15203 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2); | |
15204 DCHECK(arg_count == caller_args->length()); | |
15205 } | |
15206 #endif | |
15207 | |
15208 Handle<AllocationSite> site; | |
15209 if (!type_info.is_null() && | |
15210 *type_info != isolate->heap()->undefined_value()) { | |
15211 site = Handle<AllocationSite>::cast(type_info); | |
15212 DCHECK(!site->SitePointsToLiteral()); | |
15213 } | |
15214 | |
15215 return ArrayConstructorCommon(isolate, | |
15216 constructor, | |
15217 site, | |
15218 caller_args); | |
15219 } | |
15220 | |
15221 | |
15222 RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) { | |
15223 HandleScope scope(isolate); | |
15224 Arguments empty_args(0, NULL); | |
15225 bool no_caller_args = args.length() == 1; | |
15226 DCHECK(no_caller_args || args.length() == 3); | |
15227 int parameters_start = no_caller_args ? 0 : 1; | |
15228 Arguments* caller_args = no_caller_args | |
15229 ? &empty_args | |
15230 : reinterpret_cast<Arguments*>(args[0]); | |
15231 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); | |
15232 #ifdef DEBUG | |
15233 if (!no_caller_args) { | |
15234 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1); | |
15235 DCHECK(arg_count == caller_args->length()); | |
15236 } | |
15237 #endif | |
15238 return ArrayConstructorCommon(isolate, | |
15239 constructor, | |
15240 Handle<AllocationSite>::null(), | |
15241 caller_args); | |
15242 } | |
15243 | |
15244 | |
15245 RUNTIME_FUNCTION(Runtime_NormalizeElements) { | |
15246 HandleScope scope(isolate); | |
15247 DCHECK(args.length() == 1); | |
15248 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); | |
15249 RUNTIME_ASSERT(!array->HasExternalArrayElements() && | |
15250 !array->HasFixedTypedArrayElements()); | |
15251 JSObject::NormalizeElements(array); | |
15252 return *array; | |
15253 } | |
15254 | |
15255 | |
15256 RUNTIME_FUNCTION(Runtime_MaxSmi) { | |
15257 SealHandleScope shs(isolate); | |
15258 DCHECK(args.length() == 0); | |
15259 return Smi::FromInt(Smi::kMaxValue); | |
15260 } | |
15261 | |
15262 | |
15263 // TODO(dcarney): remove this function when TurboFan supports it. | |
15264 // Takes the object to be iterated over and the result of GetPropertyNamesFast | |
15265 // Returns pair (cache_array, cache_type). | |
15266 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInInit) { | |
15267 SealHandleScope scope(isolate); | |
15268 DCHECK(args.length() == 2); | |
15269 // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs. | |
15270 // Not worth creating a macro atm as this function should be removed. | |
15271 if (!args[0]->IsJSReceiver() || !args[1]->IsObject()) { | |
15272 Object* error = isolate->ThrowIllegalOperation(); | |
15273 return MakePair(error, isolate->heap()->undefined_value()); | |
15274 } | |
15275 Handle<JSReceiver> object = args.at<JSReceiver>(0); | |
15276 Handle<Object> cache_type = args.at<Object>(1); | |
15277 if (cache_type->IsMap()) { | |
15278 // Enum cache case. | |
15279 if (Map::EnumLengthBits::decode(Map::cast(*cache_type)->bit_field3()) == | |
15280 0) { | |
15281 // 0 length enum. | |
15282 // Can't handle this case in the graph builder, | |
15283 // so transform it into the empty fixed array case. | |
15284 return MakePair(isolate->heap()->empty_fixed_array(), Smi::FromInt(1)); | |
15285 } | |
15286 return MakePair(object->map()->instance_descriptors()->GetEnumCache(), | |
15287 *cache_type); | |
15288 } else { | |
15289 // FixedArray case. | |
15290 Smi* new_cache_type = Smi::FromInt(object->IsJSProxy() ? 0 : 1); | |
15291 return MakePair(*Handle<FixedArray>::cast(cache_type), new_cache_type); | |
15292 } | |
15293 } | |
15294 | |
15295 | |
15296 // TODO(dcarney): remove this function when TurboFan supports it. | |
15297 RUNTIME_FUNCTION(Runtime_ForInCacheArrayLength) { | |
15298 SealHandleScope shs(isolate); | |
15299 DCHECK(args.length() == 2); | |
15300 CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 0); | |
15301 CONVERT_ARG_HANDLE_CHECKED(FixedArray, array, 1); | |
15302 int length = 0; | |
15303 if (cache_type->IsMap()) { | |
15304 length = Map::cast(*cache_type)->EnumLength(); | |
15305 } else { | |
15306 DCHECK(cache_type->IsSmi()); | |
15307 length = array->length(); | |
15308 } | |
15309 return Smi::FromInt(length); | |
15310 } | |
15311 | |
15312 | |
15313 // TODO(dcarney): remove this function when TurboFan supports it. | |
15314 // Takes (the object to be iterated over, | |
15315 // cache_array from ForInInit, | |
15316 // cache_type from ForInInit, | |
15317 // the current index) | |
15318 // Returns pair (array[index], needs_filtering). | |
15319 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInNext) { | |
15320 SealHandleScope scope(isolate); | |
15321 DCHECK(args.length() == 4); | |
15322 int32_t index; | |
15323 // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs. | |
15324 // Not worth creating a macro atm as this function should be removed. | |
15325 if (!args[0]->IsJSReceiver() || !args[1]->IsFixedArray() || | |
15326 !args[2]->IsObject() || !args[3]->ToInt32(&index)) { | |
15327 Object* error = isolate->ThrowIllegalOperation(); | |
15328 return MakePair(error, isolate->heap()->undefined_value()); | |
15329 } | |
15330 Handle<JSReceiver> object = args.at<JSReceiver>(0); | |
15331 Handle<FixedArray> array = args.at<FixedArray>(1); | |
15332 Handle<Object> cache_type = args.at<Object>(2); | |
15333 // Figure out first if a slow check is needed for this object. | |
15334 bool slow_check_needed = false; | |
15335 if (cache_type->IsMap()) { | |
15336 if (object->map() != Map::cast(*cache_type)) { | |
15337 // Object transitioned. Need slow check. | |
15338 slow_check_needed = true; | |
15339 } | |
15340 } else { | |
15341 // No slow check needed for proxies. | |
15342 slow_check_needed = Smi::cast(*cache_type)->value() == 1; | |
15343 } | |
15344 return MakePair(array->get(index), | |
15345 isolate->heap()->ToBoolean(slow_check_needed)); | |
15346 } | |
15347 | |
15348 | |
15349 // ---------------------------------------------------------------------------- | |
15350 // Reference implementation for inlined runtime functions. Only used when the | |
15351 // compiler does not support a certain intrinsic. Don't optimize these, but | |
15352 // implement the intrinsic in the respective compiler instead. | |
15353 | |
15354 // TODO(mstarzinger): These are place-holder stubs for TurboFan and will | |
15355 // eventually all have a C++ implementation and this macro will be gone. | |
15356 #define U(name) \ | |
15357 RUNTIME_FUNCTION(RuntimeReference_##name) { \ | |
15358 UNIMPLEMENTED(); \ | |
15359 return NULL; \ | |
15360 } | |
15361 | |
15362 U(IsStringWrapperSafeForDefaultValueOf) | |
15363 U(DebugBreakInOptimizedCode) | |
15364 | |
15365 #undef U | |
15366 | |
15367 | |
15368 RUNTIME_FUNCTION(RuntimeReference_IsSmi) { | |
15369 SealHandleScope shs(isolate); | |
15370 DCHECK(args.length() == 1); | |
15371 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15372 return isolate->heap()->ToBoolean(obj->IsSmi()); | |
15373 } | |
15374 | |
15375 | |
15376 RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) { | |
15377 SealHandleScope shs(isolate); | |
15378 DCHECK(args.length() == 1); | |
15379 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15380 return isolate->heap()->ToBoolean(obj->IsSmi() && | |
15381 Smi::cast(obj)->value() >= 0); | |
15382 } | |
15383 | |
15384 | |
15385 RUNTIME_FUNCTION(RuntimeReference_IsArray) { | |
15386 SealHandleScope shs(isolate); | |
15387 DCHECK(args.length() == 1); | |
15388 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15389 return isolate->heap()->ToBoolean(obj->IsJSArray()); | |
15390 } | |
15391 | |
15392 | |
15393 RUNTIME_FUNCTION(RuntimeReference_IsRegExp) { | |
15394 SealHandleScope shs(isolate); | |
15395 DCHECK(args.length() == 1); | |
15396 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15397 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | |
15398 } | |
15399 | |
15400 | |
15401 RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) { | |
15402 SealHandleScope shs(isolate); | |
15403 DCHECK(args.length() == 0); | |
15404 JavaScriptFrameIterator it(isolate); | |
15405 JavaScriptFrame* frame = it.frame(); | |
15406 return isolate->heap()->ToBoolean(frame->IsConstructor()); | |
15407 } | |
15408 | |
15409 | |
15410 RUNTIME_FUNCTION(RuntimeReference_CallFunction) { | |
15411 SealHandleScope shs(isolate); | |
15412 return __RT_impl_Runtime_Call(args, isolate); | |
15413 } | |
15414 | |
15415 | |
15416 RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) { | |
15417 SealHandleScope shs(isolate); | |
15418 DCHECK(args.length() == 0); | |
15419 JavaScriptFrameIterator it(isolate); | |
15420 JavaScriptFrame* frame = it.frame(); | |
15421 return Smi::FromInt(frame->GetArgumentsLength()); | |
15422 } | |
15423 | |
15424 | |
15425 RUNTIME_FUNCTION(RuntimeReference_Arguments) { | |
15426 SealHandleScope shs(isolate); | |
15427 return __RT_impl_Runtime_GetArgumentsProperty(args, isolate); | |
15428 } | |
15429 | |
15430 | |
15431 RUNTIME_FUNCTION(RuntimeReference_ValueOf) { | |
15432 SealHandleScope shs(isolate); | |
15433 DCHECK(args.length() == 1); | |
15434 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15435 if (!obj->IsJSValue()) return obj; | |
15436 return JSValue::cast(obj)->value(); | |
15437 } | |
15438 | |
15439 | |
15440 RUNTIME_FUNCTION(RuntimeReference_SetValueOf) { | |
15441 SealHandleScope shs(isolate); | |
15442 DCHECK(args.length() == 2); | |
15443 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15444 CONVERT_ARG_CHECKED(Object, value, 1); | |
15445 if (!obj->IsJSValue()) return value; | |
15446 JSValue::cast(obj)->set_value(value); | |
15447 return value; | |
15448 } | |
15449 | |
15450 | |
15451 RUNTIME_FUNCTION(RuntimeReference_DateField) { | |
15452 SealHandleScope shs(isolate); | |
15453 DCHECK(args.length() == 2); | |
15454 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15455 CONVERT_SMI_ARG_CHECKED(index, 1); | |
15456 if (!obj->IsJSDate()) { | |
15457 HandleScope scope(isolate); | |
15458 THROW_NEW_ERROR_RETURN_FAILURE( | |
15459 isolate, | |
15460 NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | |
15461 } | |
15462 JSDate* date = JSDate::cast(obj); | |
15463 if (index == 0) return date->value(); | |
15464 return JSDate::GetField(date, Smi::FromInt(index)); | |
15465 } | |
15466 | |
15467 | |
15468 RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) { | |
15469 SealHandleScope shs(isolate); | |
15470 return __RT_impl_Runtime_CharFromCode(args, isolate); | |
15471 } | |
15472 | |
15473 | |
15474 RUNTIME_FUNCTION(RuntimeReference_StringCharAt) { | |
15475 SealHandleScope shs(isolate); | |
15476 DCHECK(args.length() == 2); | |
15477 if (!args[0]->IsString()) return Smi::FromInt(0); | |
15478 if (!args[1]->IsNumber()) return Smi::FromInt(0); | |
15479 if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string(); | |
15480 Object* code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); | |
15481 if (code->IsNaN()) return isolate->heap()->empty_string(); | |
15482 return __RT_impl_Runtime_CharFromCode(Arguments(1, &code), isolate); | |
15483 } | |
15484 | |
15485 | |
15486 RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) { | |
15487 SealHandleScope shs(isolate); | |
15488 DCHECK(args.length() == 3); | |
15489 CONVERT_INT32_ARG_CHECKED(index, 0); | |
15490 CONVERT_INT32_ARG_CHECKED(value, 1); | |
15491 CONVERT_ARG_CHECKED(SeqOneByteString, string, 2); | |
15492 string->SeqOneByteStringSet(index, value); | |
15493 return string; | |
15494 } | |
15495 | |
15496 | |
15497 RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) { | |
15498 SealHandleScope shs(isolate); | |
15499 DCHECK(args.length() == 3); | |
15500 CONVERT_INT32_ARG_CHECKED(index, 0); | |
15501 CONVERT_INT32_ARG_CHECKED(value, 1); | |
15502 CONVERT_ARG_CHECKED(SeqTwoByteString, string, 2); | |
15503 string->SeqTwoByteStringSet(index, value); | |
15504 return string; | |
15505 } | |
15506 | |
15507 | |
15508 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) { | |
15509 SealHandleScope shs(isolate); | |
15510 DCHECK(args.length() == 2); | |
15511 CONVERT_ARG_CHECKED(Object, obj1, 0); | |
15512 CONVERT_ARG_CHECKED(Object, obj2, 1); | |
15513 return isolate->heap()->ToBoolean(obj1 == obj2); | |
15514 } | |
15515 | |
15516 | |
15517 RUNTIME_FUNCTION(RuntimeReference_IsObject) { | |
15518 SealHandleScope shs(isolate); | |
15519 DCHECK(args.length() == 1); | |
15520 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15521 if (!obj->IsHeapObject()) return isolate->heap()->false_value(); | |
15522 if (obj->IsNull()) return isolate->heap()->true_value(); | |
15523 if (obj->IsUndetectableObject()) return isolate->heap()->false_value(); | |
15524 Map* map = HeapObject::cast(obj)->map(); | |
15525 bool is_non_callable_spec_object = | |
15526 map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE && | |
15527 map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE; | |
15528 return isolate->heap()->ToBoolean(is_non_callable_spec_object); | |
15529 } | |
15530 | |
15531 | |
15532 RUNTIME_FUNCTION(RuntimeReference_IsFunction) { | |
15533 SealHandleScope shs(isolate); | |
15534 DCHECK(args.length() == 1); | |
15535 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15536 return isolate->heap()->ToBoolean(obj->IsJSFunction()); | |
15537 } | |
15538 | |
15539 | |
15540 RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) { | |
15541 SealHandleScope shs(isolate); | |
15542 DCHECK(args.length() == 1); | |
15543 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15544 return isolate->heap()->ToBoolean(obj->IsUndetectableObject()); | |
15545 } | |
15546 | |
15547 | |
15548 RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) { | |
15549 SealHandleScope shs(isolate); | |
15550 DCHECK(args.length() == 1); | |
15551 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15552 return isolate->heap()->ToBoolean(obj->IsSpecObject()); | |
15553 } | |
15554 | |
15555 | |
15556 RUNTIME_FUNCTION(RuntimeReference_MathPow) { | |
15557 SealHandleScope shs(isolate); | |
15558 return __RT_impl_Runtime_MathPowSlow(args, isolate); | |
15559 } | |
15560 | |
15561 | |
15562 RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) { | |
15563 SealHandleScope shs(isolate); | |
15564 DCHECK(args.length() == 1); | |
15565 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15566 if (!obj->IsHeapNumber()) return isolate->heap()->false_value(); | |
15567 HeapNumber* number = HeapNumber::cast(obj); | |
15568 return isolate->heap()->ToBoolean(IsMinusZero(number->value())); | |
15569 } | |
15570 | |
15571 | |
15572 RUNTIME_FUNCTION(RuntimeReference_HasCachedArrayIndex) { | |
15573 SealHandleScope shs(isolate); | |
15574 DCHECK(args.length() == 1); | |
15575 return isolate->heap()->false_value(); | |
15576 } | |
15577 | |
15578 | |
15579 RUNTIME_FUNCTION(RuntimeReference_GetCachedArrayIndex) { | |
15580 SealHandleScope shs(isolate); | |
15581 DCHECK(args.length() == 1); | |
15582 return isolate->heap()->undefined_value(); | |
15583 } | |
15584 | |
15585 | |
15586 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { | |
15587 SealHandleScope shs(isolate); | |
15588 DCHECK(args.length() == 2); | |
15589 return isolate->heap()->undefined_value(); | |
15590 } | |
15591 | |
15592 | |
15593 RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) { | |
15594 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). | |
15595 return NULL; | |
15596 } | |
15597 | |
15598 | |
15599 RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) { | |
15600 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). | |
15601 return NULL; | |
15602 } | |
15603 | |
15604 | |
15605 RUNTIME_FUNCTION(RuntimeReference_ClassOf) { | |
15606 SealHandleScope shs(isolate); | |
15607 DCHECK(args.length() == 1); | |
15608 CONVERT_ARG_CHECKED(Object, obj, 0); | |
15609 if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); | |
15610 return JSReceiver::cast(obj)->class_name(); | |
15611 } | |
15612 | |
15613 | |
15614 RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) { | |
15615 SealHandleScope shs(isolate); | |
15616 DCHECK(args.length() == 2); | |
15617 if (!args[0]->IsString()) return isolate->heap()->undefined_value(); | |
15618 if (!args[1]->IsNumber()) return isolate->heap()->undefined_value(); | |
15619 if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value(); | |
15620 return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); | |
15621 } | |
15622 | |
15623 | |
15624 RUNTIME_FUNCTION(RuntimeReference_StringAdd) { | |
15625 SealHandleScope shs(isolate); | |
15626 return __RT_impl_Runtime_StringAdd(args, isolate); | |
15627 } | |
15628 | |
15629 | |
15630 RUNTIME_FUNCTION(RuntimeReference_SubString) { | |
15631 SealHandleScope shs(isolate); | |
15632 return __RT_impl_Runtime_SubString(args, isolate); | |
15633 } | |
15634 | |
15635 | |
15636 RUNTIME_FUNCTION(RuntimeReference_StringCompare) { | |
15637 SealHandleScope shs(isolate); | |
15638 return __RT_impl_Runtime_StringCompare(args, isolate); | |
15639 } | |
15640 | |
15641 | |
15642 RUNTIME_FUNCTION(RuntimeReference_RegExpExec) { | |
15643 SealHandleScope shs(isolate); | |
15644 return __RT_impl_Runtime_RegExpExecRT(args, isolate); | |
15645 } | |
15646 | |
15647 | |
15648 RUNTIME_FUNCTION(RuntimeReference_RegExpConstructResult) { | |
15649 SealHandleScope shs(isolate); | |
15650 return __RT_impl_Runtime_RegExpConstructResult(args, isolate); | |
15651 } | |
15652 | |
15653 | |
15654 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) { | |
15655 HandleScope scope(isolate); | |
15656 DCHECK(args.length() == 2); | |
15657 CONVERT_SMI_ARG_CHECKED(id, 0); | |
15658 args[0] = isolate->native_context()->jsfunction_result_caches()->get(id); | |
15659 return __RT_impl_Runtime_GetFromCache(args, isolate); | |
15660 } | |
15661 | |
15662 | |
15663 RUNTIME_FUNCTION(RuntimeReference_NumberToString) { | |
15664 SealHandleScope shs(isolate); | |
15665 return __RT_impl_Runtime_NumberToStringRT(args, isolate); | |
15666 } | |
15667 | |
15668 | |
15669 RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) { | |
15670 SealHandleScope shs(isolate); | |
15671 return Smi::FromInt(isolate->debug()->is_active()); | |
15672 } | |
15673 | |
15674 | |
15675 // ---------------------------------------------------------------------------- | |
15676 // Implementation of Runtime | |
15677 | |
15678 #define F(name, number_of_args, result_size) \ | |
15679 { \ | |
15680 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \ | |
15681 number_of_args, result_size \ | |
15682 } \ | |
15683 , | |
15684 | |
15685 | |
15686 #define I(name, number_of_args, result_size) \ | |
15687 { \ | |
15688 Runtime::kInline##name, Runtime::INLINE, "_" #name, \ | |
15689 FUNCTION_ADDR(RuntimeReference_##name), number_of_args, result_size \ | |
15690 } \ | |
15691 , | |
15692 | |
15693 | |
15694 #define IO(name, number_of_args, result_size) \ | |
15695 { \ | |
15696 Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, "_" #name, \ | |
15697 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size \ | |
15698 } \ | |
15699 , | |
15700 | |
15701 | |
15702 static const Runtime::Function kIntrinsicFunctions[] = { | |
15703 RUNTIME_FUNCTION_LIST(F) | |
15704 INLINE_OPTIMIZED_FUNCTION_LIST(F) | |
15705 INLINE_FUNCTION_LIST(I) | |
15706 INLINE_OPTIMIZED_FUNCTION_LIST(IO) | |
15707 }; | |
15708 | |
15709 #undef IO | |
15710 #undef I | |
15711 #undef F | |
15712 | |
15713 | |
15714 void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate, | |
15715 Handle<NameDictionary> dict) { | |
15716 DCHECK(dict->NumberOfElements() == 0); | |
15717 HandleScope scope(isolate); | |
15718 for (int i = 0; i < kNumFunctions; ++i) { | |
15719 const char* name = kIntrinsicFunctions[i].name; | |
15720 if (name == NULL) continue; | |
15721 Handle<NameDictionary> new_dict = NameDictionary::Add( | |
15722 dict, | |
15723 isolate->factory()->InternalizeUtf8String(name), | |
15724 Handle<Smi>(Smi::FromInt(i), isolate), | |
15725 PropertyDetails(NONE, NORMAL, Representation::None())); | |
15726 // The dictionary does not need to grow. | |
15727 CHECK(new_dict.is_identical_to(dict)); | |
15728 } | |
15729 } | |
15730 | |
15731 | |
15732 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) { | |
15733 Heap* heap = name->GetHeap(); | |
15734 int entry = heap->intrinsic_function_names()->FindEntry(name); | |
15735 if (entry != kNotFound) { | |
15736 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); | |
15737 int function_index = Smi::cast(smi_index)->value(); | |
15738 return &(kIntrinsicFunctions[function_index]); | |
15739 } | |
15740 return NULL; | |
15741 } | |
15742 | |
15743 | |
15744 const Runtime::Function* Runtime::FunctionForEntry(Address entry) { | |
15745 for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) { | |
15746 if (entry == kIntrinsicFunctions[i].entry) { | |
15747 return &(kIntrinsicFunctions[i]); | |
15748 } | |
15749 } | |
15750 return NULL; | |
15751 } | |
15752 | |
15753 | |
15754 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | |
15755 return &(kIntrinsicFunctions[static_cast<int>(id)]); | |
15756 } | |
15757 | |
15758 } } // namespace v8::internal | |
OLD | NEW |