1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <stdlib.h>
29 #include <limits>
30
31 #include "v8.h"
32
33 #include "accessors.h"
34 #include "allocation-site-scopes.h"
35 #include "api.h"
36 #include "arguments.h"
37 #include "bootstrapper.h"
38 #include "codegen.h"
39 #include "compilation-cache.h"
40 #include "compiler.h"
41 #include "cpu.h"
42 #include "cpu-profiler.h"
43 #include "dateparser-inl.h"
44 #include "debug.h"
45 #include "deoptimizer.h"
46 #include "date.h"
47 #include "execution.h"
48 #include "full-codegen.h"
49 #include "global-handles.h"
50 #include "isolate-inl.h"
51 #include "jsregexp.h"
52 #include "jsregexp-inl.h"
53 #include "json-parser.h"
54 #include "json-stringifier.h"
55 #include "liveedit.h"
56 #include "misc-intrinsics.h"
57 #include "parser.h"
58 #include "platform.h"
59 #include "runtime-profiler.h"
60 #include "runtime.h"
61 #include "scopeinfo.h"
62 #include "smart-pointers.h"
63 #include "string-search.h"
64 #include "stub-cache.h"
65 #include "uri.h"
66 #include "v8conversions.h"
67 #include "v8threads.h"
68 #include "vm-state-inl.h"
69
70 #ifdef V8_I18N_SUPPORT
71 #include "i18n.h"
72 #include "unicode/brkiter.h"
73 #include "unicode/calendar.h"
74 #include "unicode/coll.h"
75 #include "unicode/curramt.h"
76 #include "unicode/datefmt.h"
77 #include "unicode/dcfmtsym.h"
78 #include "unicode/decimfmt.h"
79 #include "unicode/dtfmtsym.h"
80 #include "unicode/dtptngen.h"
81 #include "unicode/locid.h"
82 #include "unicode/numfmt.h"
83 #include "unicode/numsys.h"
84 #include "unicode/rbbi.h"
85 #include "unicode/smpdtfmt.h"
86 #include "unicode/timezone.h"
87 #include "unicode/uchar.h"
88 #include "unicode/ucol.h"
89 #include "unicode/ucurr.h"
90 #include "unicode/uloc.h"
91 #include "unicode/unum.h"
92 #include "unicode/uversion.h"
93 #endif
94
95 #ifndef _STLP_VENDOR_CSTD
96 // STLPort doesn't import fpclassify and isless into the std namespace.
97 using std::fpclassify;
98 using std::isless;
99 #endif
100
101 namespace v8 {
102 namespace internal {
103
104
105 #define RUNTIME_ASSERT(value) \
106 if (!(value)) return isolate->ThrowIllegalOperation();
107
108 // Cast the given object to a value of the specified type and store
109 // it in a variable with the given name. If the object is not of the
110 // expected type call IllegalOperation and return.
111 #define CONVERT_ARG_CHECKED(Type, name, index) \
112 RUNTIME_ASSERT(args[index]->Is##Type()); \
113 Type* name = Type::cast(args[index]);
114
115 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
116 RUNTIME_ASSERT(args[index]->Is##Type()); \
117 Handle<Type> name = args.at<Type>(index);
118
119 // Cast the given object to a boolean and store it in a variable with
120 // the given name. If the object is not a boolean call IllegalOperation
121 // and return.
122 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
123 RUNTIME_ASSERT(args[index]->IsBoolean()); \
124 bool name = args[index]->IsTrue();
125
126 // Cast the given argument to a Smi and store its value in an int variable
127 // with the given name. If the argument is not a Smi call IllegalOperation
128 // and return.
129 #define CONVERT_SMI_ARG_CHECKED(name, index) \
130 RUNTIME_ASSERT(args[index]->IsSmi()); \
131 int name = args.smi_at(index);
132
133 // Cast the given argument to a double and store it in a variable with
134 // the given name. If the argument is not a number (as opposed to
135 // the number not-a-number) call IllegalOperation and return.
136 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
137 RUNTIME_ASSERT(args[index]->IsNumber()); \
138 double name = args.number_at(index);
139
140 // Call the specified converter on the object *comand store the result in
141 // a variable of the specified type with the given name. If the
142 // object is not a Number call IllegalOperation and return.
143 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
144 RUNTIME_ASSERT(obj->IsNumber()); \
145 type name = NumberTo##Type(obj);
146
147
148 // Cast the given argument to PropertyDetails and store its value in a
149 // variable with the given name. If the argument is not a Smi call
150 // IllegalOperation and return.
151 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
152 RUNTIME_ASSERT(args[index]->IsSmi()); \
153 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
154
155
156 // Assert that the given argument has a valid value for a StrictModeFlag
157 // and store it in a StrictModeFlag variable with the given name.
158 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
159 RUNTIME_ASSERT(args[index]->IsSmi()); \
160 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
161 args.smi_at(index) == kNonStrictMode); \
162 StrictModeFlag name = \
163 static_cast<StrictModeFlag>(args.smi_at(index));
164
165
166 // Assert that the given argument has a valid value for a LanguageMode
167 // and store it in a LanguageMode variable with the given name.
168 #define CONVERT_LANGUAGE_MODE_ARG(name, index) \
169 ASSERT(args[index]->IsSmi()); \
170 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
171 args.smi_at(index) == STRICT_MODE || \
172 args.smi_at(index) == EXTENDED_MODE); \
173 LanguageMode name = \
174 static_cast<LanguageMode>(args.smi_at(index));
175
176
ComputeObjectLiteralMap(Handle<Context> context,Handle<FixedArray> constant_properties,bool * is_result_from_cache)177 static Handle<Map> ComputeObjectLiteralMap(
178 Handle<Context> context,
179 Handle<FixedArray> constant_properties,
180 bool* is_result_from_cache) {
181 Isolate* isolate = context->GetIsolate();
182 int properties_length = constant_properties->length();
183 int number_of_properties = properties_length / 2;
184 // Check that there are only internal strings and array indices among keys.
185 int number_of_string_keys = 0;
186 for (int p = 0; p != properties_length; p += 2) {
187 Object* key = constant_properties->get(p);
188 uint32_t element_index = 0;
189 if (key->IsInternalizedString()) {
190 number_of_string_keys++;
191 } else if (key->ToArrayIndex(&element_index)) {
192 // An index key does not require space in the property backing store.
193 number_of_properties--;
194 } else {
195 // Bail out as a non-internalized-string non-index key makes caching
196 // impossible.
197 // ASSERT to make sure that the if condition after the loop is false.
198 ASSERT(number_of_string_keys != number_of_properties);
199 break;
200 }
201 }
202 // If we only have internalized strings and array indices among keys then we
203 // can use the map cache in the native context.
204 const int kMaxKeys = 10;
205 if ((number_of_string_keys == number_of_properties) &&
206 (number_of_string_keys < kMaxKeys)) {
207 // Create the fixed array with the key.
208 Handle<FixedArray> keys =
209 isolate->factory()->NewFixedArray(number_of_string_keys);
210 if (number_of_string_keys > 0) {
211 int index = 0;
212 for (int p = 0; p < properties_length; p += 2) {
213 Object* key = constant_properties->get(p);
214 if (key->IsInternalizedString()) {
215 keys->set(index++, key);
216 }
217 }
218 ASSERT(index == number_of_string_keys);
219 }
220 *is_result_from_cache = true;
221 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
222 }
223 *is_result_from_cache = false;
224 return isolate->factory()->CopyMap(
225 Handle<Map>(context->object_function()->initial_map()),
226 number_of_properties);
227 }
228
229
230 static Handle<Object> CreateLiteralBoilerplate(
231 Isolate* isolate,
232 Handle<FixedArray> literals,
233 Handle<FixedArray> constant_properties);
234
235
CreateObjectLiteralBoilerplate(Isolate * isolate,Handle<FixedArray> literals,Handle<FixedArray> constant_properties,bool should_have_fast_elements,bool has_function_literal)236 static Handle<Object> CreateObjectLiteralBoilerplate(
237 Isolate* isolate,
238 Handle<FixedArray> literals,
239 Handle<FixedArray> constant_properties,
240 bool should_have_fast_elements,
241 bool has_function_literal) {
242 // Get the native context from the literals array. This is the
243 // context in which the function was created and we use the object
244 // function from this context to create the object literal. We do
245 // not use the object function from the current native context
246 // because this might be the object function from another context
247 // which we should not have access to.
248 Handle<Context> context =
249 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
250
251 // In case we have function literals, we want the object to be in
252 // slow properties mode for now. We don't go in the map cache because
253 // maps with constant functions can't be shared if the functions are
254 // not the same (which is the common case).
255 bool is_result_from_cache = false;
256 Handle<Map> map = has_function_literal
257 ? Handle<Map>(context->object_function()->initial_map())
258 : ComputeObjectLiteralMap(context,
259 constant_properties,
260 &is_result_from_cache);
261
262 Handle<JSObject> boilerplate =
263 isolate->factory()->NewJSObjectFromMap(
264 map, isolate->heap()->GetPretenureMode());
265
266 // Normalize the elements of the boilerplate to save space if needed.
267 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
268
269 // Add the constant properties to the boilerplate.
270 int length = constant_properties->length();
271 bool should_transform =
272 !is_result_from_cache && boilerplate->HasFastProperties();
273 if (should_transform || has_function_literal) {
274 // Normalize the properties of object to avoid n^2 behavior
275 // when extending the object multiple properties. Indicate the number of
276 // properties to be added.
277 JSObject::NormalizeProperties(
278 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
279 }
280
281 // TODO(verwaest): Support tracking representations in the boilerplate.
282 for (int index = 0; index < length; index +=2) {
283 Handle<Object> key(constant_properties->get(index+0), isolate);
284 Handle<Object> value(constant_properties->get(index+1), isolate);
285 if (value->IsFixedArray()) {
286 // The value contains the constant_properties of a
287 // simple object or array literal.
288 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
289 value = CreateLiteralBoilerplate(isolate, literals, array);
290 if (value.is_null()) return value;
291 }
292 Handle<Object> result;
293 uint32_t element_index = 0;
294 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT;
295 if (key->IsInternalizedString()) {
296 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
297 // Array index as string (uint32).
298 result = JSObject::SetOwnElement(
299 boilerplate, element_index, value, kNonStrictMode);
300 } else {
301 Handle<String> name(String::cast(*key));
302 ASSERT(!name->AsArrayIndex(&element_index));
303 result = JSObject::SetLocalPropertyIgnoreAttributes(
304 boilerplate, name, value, NONE,
305 Object::OPTIMAL_REPRESENTATION, mode);
306 }
307 } else if (key->ToArrayIndex(&element_index)) {
308 // Array index (uint32).
309 result = JSObject::SetOwnElement(
310 boilerplate, element_index, value, kNonStrictMode);
311 } else {
312 // Non-uint32 number.
313 ASSERT(key->IsNumber());
314 double num = key->Number();
315 char arr[100];
316 Vector<char> buffer(arr, ARRAY_SIZE(arr));
317 const char* str = DoubleToCString(num, buffer);
318 Handle<String> name =
319 isolate->factory()->NewStringFromAscii(CStrVector(str));
320 result = JSObject::SetLocalPropertyIgnoreAttributes(
321 boilerplate, name, value, NONE,
322 Object::OPTIMAL_REPRESENTATION, mode);
323 }
324 // If setting the property on the boilerplate throws an
325 // exception, the exception is converted to an empty handle in
326 // the handle based operations. In that case, we need to
327 // convert back to an exception.
328 if (result.is_null()) return result;
329 }
330
331 // Transform to fast properties if necessary. For object literals with
332 // containing function literals we defer this operation until after all
333 // computed properties have been assigned so that we can generate
334 // constant function properties.
335 if (should_transform && !has_function_literal) {
336 JSObject::TransformToFastProperties(
337 boilerplate, boilerplate->map()->unused_property_fields());
338 }
339
340 return boilerplate;
341 }
342
343
TransitionElements(Handle<Object> object,ElementsKind to_kind,Isolate * isolate)344 MaybeObject* TransitionElements(Handle<Object> object,
345 ElementsKind to_kind,
346 Isolate* isolate) {
347 HandleScope scope(isolate);
348 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
349 ElementsKind from_kind =
350 Handle<JSObject>::cast(object)->map()->elements_kind();
351 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
352 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
353 return *object;
354 }
355 return isolate->ThrowIllegalOperation();
356 }
357
358
359 static const int kSmiLiteralMinimumLength = 1024;
360
361
CreateArrayLiteralBoilerplate(Isolate * isolate,Handle<FixedArray> literals,Handle<FixedArray> elements)362 Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
363 Isolate* isolate,
364 Handle<FixedArray> literals,
365 Handle<FixedArray> elements) {
366 // Create the JSArray.
367 Handle<JSFunction> constructor(
368 JSFunction::NativeContextFromLiterals(*literals)->array_function());
369
370 Handle<JSArray> object = Handle<JSArray>::cast(
371 isolate->factory()->NewJSObject(
372 constructor, isolate->heap()->GetPretenureMode()));
373
374 ElementsKind constant_elements_kind =
375 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
376 Handle<FixedArrayBase> constant_elements_values(
377 FixedArrayBase::cast(elements->get(1)));
378
379 ASSERT(IsFastElementsKind(constant_elements_kind));
380 Context* native_context = isolate->context()->native_context();
381 Object* maybe_maps_array = native_context->js_array_maps();
382 ASSERT(!maybe_maps_array->IsUndefined());
383 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
384 constant_elements_kind);
385 ASSERT(maybe_map->IsMap());
386 object->set_map(Map::cast(maybe_map));
387
388 Handle<FixedArrayBase> copied_elements_values;
389 if (IsFastDoubleElementsKind(constant_elements_kind)) {
390 ASSERT(FLAG_smi_only_arrays);
391 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
392 Handle<FixedDoubleArray>::cast(constant_elements_values));
393 } else {
394 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
395 const bool is_cow =
396 (constant_elements_values->map() ==
397 isolate->heap()->fixed_cow_array_map());
398 if (is_cow) {
399 copied_elements_values = constant_elements_values;
400 #if DEBUG
401 Handle<FixedArray> fixed_array_values =
402 Handle<FixedArray>::cast(copied_elements_values);
403 for (int i = 0; i < fixed_array_values->length(); i++) {
404 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
405 }
406 #endif
407 } else {
408 Handle<FixedArray> fixed_array_values =
409 Handle<FixedArray>::cast(constant_elements_values);
410 Handle<FixedArray> fixed_array_values_copy =
411 isolate->factory()->CopyFixedArray(fixed_array_values);
412 copied_elements_values = fixed_array_values_copy;
413 for (int i = 0; i < fixed_array_values->length(); i++) {
414 Object* current = fixed_array_values->get(i);
415 if (current->IsFixedArray()) {
416 // The value contains the constant_properties of a
417 // simple object or array literal.
418 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
419 Handle<Object> result =
420 CreateLiteralBoilerplate(isolate, literals, fa);
421 if (result.is_null()) return result;
422 fixed_array_values_copy->set(i, *result);
423 }
424 }
425 }
426 }
427 object->set_elements(*copied_elements_values);
428 object->set_length(Smi::FromInt(copied_elements_values->length()));
429
430 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
431 // on or the object is larger than the threshold.
432 if (!FLAG_smi_only_arrays &&
433 constant_elements_values->length() < kSmiLiteralMinimumLength) {
434 ElementsKind elements_kind = object->GetElementsKind();
435 if (!IsFastObjectElementsKind(elements_kind)) {
436 if (IsFastHoleyElementsKind(elements_kind)) {
437 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
438 isolate)->IsFailure());
439 } else {
440 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
441 }
442 }
443 }
444
445 object->ValidateElements();
446 return object;
447 }
448
449
CreateLiteralBoilerplate(Isolate * isolate,Handle<FixedArray> literals,Handle<FixedArray> array)450 static Handle<Object> CreateLiteralBoilerplate(
451 Isolate* isolate,
452 Handle<FixedArray> literals,
453 Handle<FixedArray> array) {
454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
455 const bool kHasNoFunctionLiteral = false;
456 switch (CompileTimeValue::GetLiteralType(array)) {
457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
458 return CreateObjectLiteralBoilerplate(isolate,
459 literals,
460 elements,
461 true,
462 kHasNoFunctionLiteral);
463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
464 return CreateObjectLiteralBoilerplate(isolate,
465 literals,
466 elements,
467 false,
468 kHasNoFunctionLiteral);
469 case CompileTimeValue::ARRAY_LITERAL:
470 return Runtime::CreateArrayLiteralBoilerplate(
471 isolate, literals, elements);
472 default:
473 UNREACHABLE();
474 return Handle<Object>::null();
475 }
476 }
477
478
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateObjectLiteral)479 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
480 HandleScope scope(isolate);
481 ASSERT(args.length() == 4);
482 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
484 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
485 CONVERT_SMI_ARG_CHECKED(flags, 3);
486 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
487 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
488
489 // Check if boilerplate exists. If not, create it first.
490 Handle<Object> literal_site(literals->get(literals_index), isolate);
491 Handle<AllocationSite> site;
492 Handle<JSObject> boilerplate;
493 if (*literal_site == isolate->heap()->undefined_value()) {
494 Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
495 isolate,
496 literals,
497 constant_properties,
498 should_have_fast_elements,
499 has_function_literal);
500 RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
501 boilerplate = Handle<JSObject>::cast(raw_boilerplate);
502
503 AllocationSiteCreationContext creation_context(isolate);
504 site = creation_context.EnterNewScope();
505 RETURN_IF_EMPTY_HANDLE(isolate,
506 JSObject::DeepWalk(boilerplate, &creation_context));
507 creation_context.ExitScope(site, boilerplate);
508
509 // Update the functions literal and return the boilerplate.
510 literals->set(literals_index, *site);
511 } else {
512 site = Handle<AllocationSite>::cast(literal_site);
513 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
514 isolate);
515 }
516
517 AllocationSiteUsageContext usage_context(isolate, site, true);
518 usage_context.EnterNewScope();
519 Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
520 usage_context.ExitScope(site, boilerplate);
521 RETURN_IF_EMPTY_HANDLE(isolate, copy);
522 return *copy;
523 }
524
525
GetLiteralAllocationSite(Isolate * isolate,Handle<FixedArray> literals,int literals_index,Handle<FixedArray> elements)526 static Handle<AllocationSite> GetLiteralAllocationSite(
527 Isolate* isolate,
528 Handle<FixedArray> literals,
529 int literals_index,
530 Handle<FixedArray> elements) {
531 // Check if boilerplate exists. If not, create it first.
532 Handle<Object> literal_site(literals->get(literals_index), isolate);
533 Handle<AllocationSite> site;
534 if (*literal_site == isolate->heap()->undefined_value()) {
535 ASSERT(*elements != isolate->heap()->empty_fixed_array());
536 Handle<Object> boilerplate =
537 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
538 if (boilerplate.is_null()) return Handle<AllocationSite>::null();
539
540 AllocationSiteCreationContext creation_context(isolate);
541 site = creation_context.EnterNewScope();
542 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
543 &creation_context).is_null()) {
544 return Handle<AllocationSite>::null();
545 }
546 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
547
548 literals->set(literals_index, *site);
549 } else {
550 site = Handle<AllocationSite>::cast(literal_site);
551 }
552
553 return site;
554 }
555
556
CreateArrayLiteralImpl(Isolate * isolate,Handle<FixedArray> literals,int literals_index,Handle<FixedArray> elements,int flags)557 static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate,
558 Handle<FixedArray> literals,
559 int literals_index,
560 Handle<FixedArray> elements,
561 int flags) {
562 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
563 literals_index, elements);
564 RETURN_IF_EMPTY_HANDLE(isolate, site);
565
566 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
567 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
568 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
569 usage_context.EnterNewScope();
570 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
571 ? JSObject::kNoHints
572 : JSObject::kObjectIsShallowArray;
573 Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
574 hints);
575 usage_context.ExitScope(site, boilerplate);
576 RETURN_IF_EMPTY_HANDLE(isolate, copy);
577 return *copy;
578 }
579
580
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateArrayLiteral)581 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
582 HandleScope scope(isolate);
583 ASSERT(args.length() == 4);
584 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
585 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
586 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
587 CONVERT_SMI_ARG_CHECKED(flags, 3);
588
589 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
590 flags);
591 }
592
593
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateArrayLiteralStubBailout)594 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralStubBailout) {
595 HandleScope scope(isolate);
596 ASSERT(args.length() == 3);
597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
598 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
599 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
600
601 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
602 ArrayLiteral::kShallowElements);
603 }
604
605
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateSymbol)606 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
607 HandleScope scope(isolate);
608 ASSERT(args.length() == 1);
609 Handle<Object> name(args[0], isolate);
610 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
611 Symbol* symbol;
612 MaybeObject* maybe = isolate->heap()->AllocateSymbol();
613 if (!maybe->To(&symbol)) return maybe;
614 if (name->IsString()) symbol->set_name(*name);
615 return symbol;
616 }
617
618
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreatePrivateSymbol)619 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) {
620 HandleScope scope(isolate);
621 ASSERT(args.length() == 1);
622 Handle<Object> name(args[0], isolate);
623 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
624 Symbol* symbol;
625 MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol();
626 if (!maybe->To(&symbol)) return maybe;
627 if (name->IsString()) symbol->set_name(*name);
628 return symbol;
629 }
630
631
RUNTIME_FUNCTION(MaybeObject *,Runtime_SymbolName)632 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
633 SealHandleScope shs(isolate);
634 ASSERT(args.length() == 1);
635 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
636 return symbol->name();
637 }
638
639
RUNTIME_FUNCTION(MaybeObject *,Runtime_SymbolIsPrivate)640 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) {
641 SealHandleScope shs(isolate);
642 ASSERT(args.length() == 1);
643 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
644 return isolate->heap()->ToBoolean(symbol->is_private());
645 }
646
647
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateJSProxy)648 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
649 SealHandleScope shs(isolate);
650 ASSERT(args.length() == 2);
651 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
652 Object* prototype = args[1];
653 Object* used_prototype =
654 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
655 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
656 }
657
658
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateJSFunctionProxy)659 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
660 SealHandleScope shs(isolate);
661 ASSERT(args.length() == 4);
662 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
663 Object* call_trap = args[1];
664 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
665 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
666 Object* prototype = args[3];
667 Object* used_prototype =
668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
669 return isolate->heap()->AllocateJSFunctionProxy(
670 handler, call_trap, construct_trap, used_prototype);
671 }
672
673
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsJSProxy)674 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
675 SealHandleScope shs(isolate);
676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
678 return isolate->heap()->ToBoolean(obj->IsJSProxy());
679 }
680
681
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsJSFunctionProxy)682 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
683 SealHandleScope shs(isolate);
684 ASSERT(args.length() == 1);
685 Object* obj = args[0];
686 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
687 }
688
689
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetHandler)690 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
691 SealHandleScope shs(isolate);
692 ASSERT(args.length() == 1);
693 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
694 return proxy->handler();
695 }
696
697
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetCallTrap)698 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
699 SealHandleScope shs(isolate);
700 ASSERT(args.length() == 1);
701 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
702 return proxy->call_trap();
703 }
704
705
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetConstructTrap)706 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
707 SealHandleScope shs(isolate);
708 ASSERT(args.length() == 1);
709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
710 return proxy->construct_trap();
711 }
712
713
RUNTIME_FUNCTION(MaybeObject *,Runtime_Fix)714 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
715 HandleScope scope(isolate);
716 ASSERT(args.length() == 1);
717 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
718 JSProxy::Fix(proxy);
719 return isolate->heap()->undefined_value();
720 }
721
722
FreeArrayBuffer(Isolate * isolate,JSArrayBuffer * phantom_array_buffer)723 void Runtime::FreeArrayBuffer(Isolate* isolate,
724 JSArrayBuffer* phantom_array_buffer) {
725 if (phantom_array_buffer->should_be_freed()) {
726 ASSERT(phantom_array_buffer->is_external());
727 free(phantom_array_buffer->backing_store());
728 }
729 if (phantom_array_buffer->is_external()) return;
730
731 size_t allocated_length = NumberToSize(
732 isolate, phantom_array_buffer->byte_length());
733
734 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
735 -static_cast<int64_t>(allocated_length));
736 CHECK(V8::ArrayBufferAllocator() != NULL);
737 V8::ArrayBufferAllocator()->Free(
738 phantom_array_buffer->backing_store(),
739 allocated_length);
740 }
741
742
SetupArrayBuffer(Isolate * isolate,Handle<JSArrayBuffer> array_buffer,bool is_external,void * data,size_t allocated_length)743 void Runtime::SetupArrayBuffer(Isolate* isolate,
744 Handle<JSArrayBuffer> array_buffer,
745 bool is_external,
746 void* data,
747 size_t allocated_length) {
748 ASSERT(array_buffer->GetInternalFieldCount() ==
749 v8::ArrayBuffer::kInternalFieldCount);
750 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
751 array_buffer->SetInternalField(i, Smi::FromInt(0));
752 }
753 array_buffer->set_backing_store(data);
754 array_buffer->set_flag(Smi::FromInt(0));
755 array_buffer->set_is_external(is_external);
756
757 Handle<Object> byte_length =
758 isolate->factory()->NewNumberFromSize(allocated_length);
759 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
760 array_buffer->set_byte_length(*byte_length);
761
762 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
763 isolate->heap()->set_array_buffers_list(*array_buffer);
764 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
765 }
766
767
SetupArrayBufferAllocatingData(Isolate * isolate,Handle<JSArrayBuffer> array_buffer,size_t allocated_length,bool initialize)768 bool Runtime::SetupArrayBufferAllocatingData(
769 Isolate* isolate,
770 Handle<JSArrayBuffer> array_buffer,
771 size_t allocated_length,
772 bool initialize) {
773 void* data;
774 CHECK(V8::ArrayBufferAllocator() != NULL);
775 if (allocated_length != 0) {
776 if (initialize) {
777 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
778 } else {
779 data =
780 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
781 }
782 if (data == NULL) return false;
783 } else {
784 data = NULL;
785 }
786
787 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
788
789 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
790
791 return true;
792 }
793
794
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayBufferInitialize)795 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
796 HandleScope scope(isolate);
797 ASSERT(args.length() == 2);
798 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
799 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
800 size_t allocated_length;
801 if (byteLength->IsSmi()) {
802 allocated_length = Smi::cast(*byteLength)->value();
803 } else {
804 ASSERT(byteLength->IsHeapNumber());
805 double value = HeapNumber::cast(*byteLength)->value();
806
807 ASSERT(value >= 0);
808
809 if (value > std::numeric_limits<size_t>::max()) {
810 return isolate->Throw(
811 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
812 HandleVector<Object>(NULL, 0)));
813 }
814
815 allocated_length = static_cast<size_t>(value);
816 }
817
818 if (!Runtime::SetupArrayBufferAllocatingData(isolate,
819 holder, allocated_length)) {
820 return isolate->Throw(*isolate->factory()->
821 NewRangeError("invalid_array_buffer_length",
822 HandleVector<Object>(NULL, 0)));
823 }
824
825 return *holder;
826 }
827
828
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayBufferGetByteLength)829 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
830 SealHandleScope shs(isolate);
831 ASSERT(args.length() == 1);
832 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
833 return holder->byte_length();
834 }
835
836
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayBufferSliceImpl)837 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
838 HandleScope scope(isolate);
839 ASSERT(args.length() == 3);
840 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
841 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
842 CONVERT_DOUBLE_ARG_CHECKED(first, 2);
843 size_t start = static_cast<size_t>(first);
844 size_t target_length = NumberToSize(isolate, target->byte_length());
845
846 if (target_length == 0) return isolate->heap()->undefined_value();
847
848 ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
849 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
850 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
851 CopyBytes(target_data, source_data + start, target_length);
852 return isolate->heap()->undefined_value();
853 }
854
855
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayBufferIsView)856 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) {
857 HandleScope scope(isolate);
858 ASSERT(args.length() == 1);
859 CONVERT_ARG_CHECKED(Object, object, 0);
860 return object->IsJSArrayBufferView()
861 ? isolate->heap()->true_value()
862 : isolate->heap()->false_value();
863 }
864
865
ArrayIdToTypeAndSize(int arrayId,ExternalArrayType * array_type,size_t * element_size)866 void Runtime::ArrayIdToTypeAndSize(
867 int arrayId, ExternalArrayType* array_type, size_t* element_size) {
868 switch (arrayId) {
869 case ARRAY_ID_UINT8:
870 *array_type = kExternalUnsignedByteArray;
871 *element_size = 1;
872 break;
873 case ARRAY_ID_INT8:
874 *array_type = kExternalByteArray;
875 *element_size = 1;
876 break;
877 case ARRAY_ID_UINT16:
878 *array_type = kExternalUnsignedShortArray;
879 *element_size = 2;
880 break;
881 case ARRAY_ID_INT16:
882 *array_type = kExternalShortArray;
883 *element_size = 2;
884 break;
885 case ARRAY_ID_UINT32:
886 *array_type = kExternalUnsignedIntArray;
887 *element_size = 4;
888 break;
889 case ARRAY_ID_INT32:
890 *array_type = kExternalIntArray;
891 *element_size = 4;
892 break;
893 case ARRAY_ID_FLOAT32:
894 *array_type = kExternalFloatArray;
895 *element_size = 4;
896 break;
897 case ARRAY_ID_FLOAT64:
898 *array_type = kExternalDoubleArray;
899 *element_size = 8;
900 break;
901 case ARRAY_ID_UINT8C:
902 *array_type = kExternalPixelArray;
903 *element_size = 1;
904 break;
905 default:
906 UNREACHABLE();
907 }
908 }
909
910
RUNTIME_FUNCTION(MaybeObject *,Runtime_TypedArrayInitialize)911 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
912 HandleScope scope(isolate);
913 ASSERT(args.length() == 5);
914 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
915 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
916 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
917 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
918 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
919
920 ASSERT(holder->GetInternalFieldCount() ==
921 v8::ArrayBufferView::kInternalFieldCount);
922 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
923 holder->SetInternalField(i, Smi::FromInt(0));
924 }
925
926 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
927 size_t element_size = 1; // Bogus initialization.
928 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
929
930 holder->set_buffer(*buffer);
931 holder->set_byte_offset(*byte_offset_object);
932 holder->set_byte_length(*byte_length_object);
933
934 size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
935 size_t byte_length = NumberToSize(isolate, *byte_length_object);
936 ASSERT(byte_length % element_size == 0);
937 size_t length = byte_length / element_size;
938
939 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
940 return isolate->Throw(*isolate->factory()->
941 NewRangeError("invalid_typed_array_length",
942 HandleVector<Object>(NULL, 0)));
943 }
944
945 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
946 holder->set_length(*length_obj);
947 holder->set_weak_next(buffer->weak_first_view());
948 buffer->set_weak_first_view(*holder);
949
950 Handle<ExternalArray> elements =
951 isolate->factory()->NewExternalArray(
952 static_cast<int>(length), array_type,
953 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
954 holder->set_elements(*elements);
955 return isolate->heap()->undefined_value();
956 }
957
958
959 // Initializes a typed array from an array-like object.
960 // If an array-like object happens to be a typed array of the same type,
961 // initializes backing store using memove.
962 //
963 // Returns true if backing store was initialized or false otherwise.
RUNTIME_FUNCTION(MaybeObject *,Runtime_TypedArrayInitializeFromArrayLike)964 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
965 HandleScope scope(isolate);
966 ASSERT(args.length() == 4);
967 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
968 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
969 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
970 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
971
972 ASSERT(holder->GetInternalFieldCount() ==
973 v8::ArrayBufferView::kInternalFieldCount);
974 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
975 holder->SetInternalField(i, Smi::FromInt(0));
976 }
977
978 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
979 size_t element_size = 1; // Bogus initialization.
980 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
981
982 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
983 if (source->IsJSTypedArray() &&
984 JSTypedArray::cast(*source)->type() == array_type) {
985 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
986 }
987 size_t length = NumberToSize(isolate, *length_obj);
988
989 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
990 (length > (kMaxInt / element_size))) {
991 return isolate->Throw(*isolate->factory()->
992 NewRangeError("invalid_typed_array_length",
993 HandleVector<Object>(NULL, 0)));
994 }
995 size_t byte_length = length * element_size;
996
997 // NOTE: not initializing backing store.
998 // We assume that the caller of this function will initialize holder
999 // with the loop
1000 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
1001 // We assume that the caller of this function is always a typed array
1002 // constructor.
1003 // If source is a typed array, this loop will always run to completion,
1004 // so we are sure that the backing store will be initialized.
1005 // Otherwise, the indexing operation might throw, so the loop will not
1006 // run to completion and the typed array might remain partly initialized.
1007 // However we further assume that the caller of this function is a typed array
1008 // constructor, and the exception will propagate out of the constructor,
1009 // therefore uninitialized memory will not be accessible by a user program.
1010 //
1011 // TODO(dslomov): revise this once we support subclassing.
1012
1013 if (!Runtime::SetupArrayBufferAllocatingData(
1014 isolate, buffer, byte_length, false)) {
1015 return isolate->Throw(*isolate->factory()->
1016 NewRangeError("invalid_array_buffer_length",
1017 HandleVector<Object>(NULL, 0)));
1018 }
1019
1020 holder->set_buffer(*buffer);
1021 holder->set_byte_offset(Smi::FromInt(0));
1022 Handle<Object> byte_length_obj(
1023 isolate->factory()->NewNumberFromSize(byte_length));
1024 holder->set_byte_length(*byte_length_obj);
1025 holder->set_length(*length_obj);
1026 holder->set_weak_next(buffer->weak_first_view());
1027 buffer->set_weak_first_view(*holder);
1028
1029 Handle<ExternalArray> elements =
1030 isolate->factory()->NewExternalArray(
1031 static_cast<int>(length), array_type,
1032 static_cast<uint8_t*>(buffer->backing_store()));
1033 holder->set_elements(*elements);
1034
1035 if (source->IsJSTypedArray()) {
1036 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1037
1038 if (typed_array->type() == holder->type()) {
1039 uint8_t* backing_store =
1040 static_cast<uint8_t*>(
1041 JSArrayBuffer::cast(typed_array->buffer())->backing_store());
1042 size_t source_byte_offset =
1043 NumberToSize(isolate, typed_array->byte_offset());
1044 memcpy(
1045 buffer->backing_store(),
1046 backing_store + source_byte_offset,
1047 byte_length);
1048 return *isolate->factory()->true_value();
1049 } else {
1050 return *isolate->factory()->false_value();
1051 }
1052 }
1053
1054 return *isolate->factory()->false_value();
1055 }
1056
1057
1058 #define TYPED_ARRAY_GETTER(getter, accessor) \
1059 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
1060 HandleScope scope(isolate); \
1061 ASSERT(args.length() == 1); \
1062 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
1063 if (!holder->IsJSTypedArray()) \
1064 return isolate->Throw(*isolate->factory()->NewTypeError( \
1065 "not_typed_array", HandleVector<Object>(NULL, 0))); \
1066 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
1067 return typed_array->accessor(); \
1068 }
1069
1070 TYPED_ARRAY_GETTER(Buffer, buffer)
1071 TYPED_ARRAY_GETTER(ByteLength, byte_length)
1072 TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
1073 TYPED_ARRAY_GETTER(Length, length)
1074
1075 #undef TYPED_ARRAY_GETTER
1076
1077 // Return codes for Runtime_TypedArraySetFastCases.
1078 // Should be synchronized with typedarray.js natives.
1079 enum TypedArraySetResultCodes {
1080 // Set from typed array of the same type.
1081 // This is processed by TypedArraySetFastCases
1082 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1083 // Set from typed array of the different type, overlapping in memory.
1084 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1085 // Set from typed array of the different type, non-overlapping.
1086 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1087 // Set from non-typed array.
1088 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1089 };
1090
1091
RUNTIME_FUNCTION(MaybeObject *,Runtime_TypedArraySetFastCases)1092 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
1093 HandleScope scope(isolate);
1094 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
1095 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1);
1096 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2);
1097
1098 if (!target_obj->IsJSTypedArray())
1099 return isolate->Throw(*isolate->factory()->NewTypeError(
1100 "not_typed_array", HandleVector<Object>(NULL, 0)));
1101
1102 if (!source_obj->IsJSTypedArray())
1103 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
1104
1105 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1106 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1107 size_t offset = NumberToSize(isolate, *offset_obj);
1108 size_t target_length = NumberToSize(isolate, target->length());
1109 size_t source_length = NumberToSize(isolate, source->length());
1110 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1111 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1112 if (offset > target_length ||
1113 offset + source_length > target_length ||
1114 offset + source_length < offset) // overflow
1115 return isolate->Throw(*isolate->factory()->NewRangeError(
1116 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
1117
1118 size_t target_offset = NumberToSize(isolate, target->byte_offset());
1119 size_t source_offset = NumberToSize(isolate, source->byte_offset());
1120 uint8_t* target_base =
1121 static_cast<uint8_t*>(
1122 JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
1123 uint8_t* source_base =
1124 static_cast<uint8_t*>(
1125 JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset;
1126
1127 // Typed arrays of the same type: use memmove.
1128 if (target->type() == source->type()) {
1129 memmove(target_base + offset * target->element_size(),
1130 source_base, source_byte_length);
1131 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
1132 }
1133
1134 // Typed arrays of different types over the same backing store
1135 if ((source_base <= target_base &&
1136 source_base + source_byte_length > target_base) ||
1137 (target_base <= source_base &&
1138 target_base + target_byte_length > source_base)) {
1139 // We do not support overlapping ArrayBuffers
1140 ASSERT(
1141 JSArrayBuffer::cast(target->buffer())->backing_store() ==
1142 JSArrayBuffer::cast(source->buffer())->backing_store());
1143 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
1144 } else { // Non-overlapping typed arrays
1145 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
1146 }
1147 }
1148
1149
RUNTIME_FUNCTION(MaybeObject *,Runtime_DataViewInitialize)1150 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
1151 HandleScope scope(isolate);
1152 ASSERT(args.length() == 4);
1153 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1154 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1155 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
1156 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
1157
1158 ASSERT(holder->GetInternalFieldCount() ==
1159 v8::ArrayBufferView::kInternalFieldCount);
1160 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1161 holder->SetInternalField(i, Smi::FromInt(0));
1162 }
1163
1164 holder->set_buffer(*buffer);
1165 ASSERT(byte_offset->IsNumber());
1166 ASSERT(
1167 NumberToSize(isolate, buffer->byte_length()) >=
1168 NumberToSize(isolate, *byte_offset)
1169 + NumberToSize(isolate, *byte_length));
1170 holder->set_byte_offset(*byte_offset);
1171 ASSERT(byte_length->IsNumber());
1172 holder->set_byte_length(*byte_length);
1173
1174 holder->set_weak_next(buffer->weak_first_view());
1175 buffer->set_weak_first_view(*holder);
1176
1177 return isolate->heap()->undefined_value();
1178 }
1179
1180
RUNTIME_FUNCTION(MaybeObject *,Runtime_DataViewGetBuffer)1181 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
1182 HandleScope scope(isolate);
1183 ASSERT(args.length() == 1);
1184 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1185 return data_view->buffer();
1186 }
1187
1188
RUNTIME_FUNCTION(MaybeObject *,Runtime_DataViewGetByteOffset)1189 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
1190 HandleScope scope(isolate);
1191 ASSERT(args.length() == 1);
1192 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1193 return data_view->byte_offset();
1194 }
1195
1196
RUNTIME_FUNCTION(MaybeObject *,Runtime_DataViewGetByteLength)1197 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
1198 HandleScope scope(isolate);
1199 ASSERT(args.length() == 1);
1200 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1201 return data_view->byte_length();
1202 }
1203
1204
NeedToFlipBytes(bool is_little_endian)1205 inline static bool NeedToFlipBytes(bool is_little_endian) {
1206 #ifdef V8_TARGET_LITTLE_ENDIAN
1207 return !is_little_endian;
1208 #else
1209 return is_little_endian;
1210 #endif
1211 }
1212
1213
1214 template<int n>
CopyBytes(uint8_t * target,uint8_t * source)1215 inline void CopyBytes(uint8_t* target, uint8_t* source) {
1216 for (int i = 0; i < n; i++) {
1217 *(target++) = *(source++);
1218 }
1219 }
1220
1221
1222 template<int n>
FlipBytes(uint8_t * target,uint8_t * source)1223 inline void FlipBytes(uint8_t* target, uint8_t* source) {
1224 source = source + (n-1);
1225 for (int i = 0; i < n; i++) {
1226 *(target++) = *(source--);
1227 }
1228 }
1229
1230
1231 template<typename T>
DataViewGetValue(Isolate * isolate,Handle<JSDataView> data_view,Handle<Object> byte_offset_obj,bool is_little_endian,T * result)1232 inline static bool DataViewGetValue(
1233 Isolate* isolate,
1234 Handle<JSDataView> data_view,
1235 Handle<Object> byte_offset_obj,
1236 bool is_little_endian,
1237 T* result) {
1238 size_t byte_offset = 0;
1239 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1240 return false;
1241 }
1242 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1243
1244 size_t data_view_byte_offset =
1245 NumberToSize(isolate, data_view->byte_offset());
1246 size_t data_view_byte_length =
1247 NumberToSize(isolate, data_view->byte_length());
1248 if (byte_offset + sizeof(T) > data_view_byte_length ||
1249 byte_offset + sizeof(T) < byte_offset) { // overflow
1250 return false;
1251 }
1252
1253 union Value {
1254 T data;
1255 uint8_t bytes[sizeof(T)];
1256 };
1257
1258 Value value;
1259 size_t buffer_offset = data_view_byte_offset + byte_offset;
1260 ASSERT(
1261 NumberToSize(isolate, buffer->byte_length())
1262 >= buffer_offset + sizeof(T));
1263 uint8_t* source =
1264 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1265 if (NeedToFlipBytes(is_little_endian)) {
1266 FlipBytes<sizeof(T)>(value.bytes, source);
1267 } else {
1268 CopyBytes<sizeof(T)>(value.bytes, source);
1269 }
1270 *result = value.data;
1271 return true;
1272 }
1273
1274
1275 template<typename T>
DataViewSetValue(Isolate * isolate,Handle<JSDataView> data_view,Handle<Object> byte_offset_obj,bool is_little_endian,T data)1276 static bool DataViewSetValue(
1277 Isolate* isolate,
1278 Handle<JSDataView> data_view,
1279 Handle<Object> byte_offset_obj,
1280 bool is_little_endian,
1281 T data) {
1282 size_t byte_offset = 0;
1283 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1284 return false;
1285 }
1286 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1287
1288 size_t data_view_byte_offset =
1289 NumberToSize(isolate, data_view->byte_offset());
1290 size_t data_view_byte_length =
1291 NumberToSize(isolate, data_view->byte_length());
1292 if (byte_offset + sizeof(T) > data_view_byte_length ||
1293 byte_offset + sizeof(T) < byte_offset) { // overflow
1294 return false;
1295 }
1296
1297 union Value {
1298 T data;
1299 uint8_t bytes[sizeof(T)];
1300 };
1301
1302 Value value;
1303 value.data = data;
1304 size_t buffer_offset = data_view_byte_offset + byte_offset;
1305 ASSERT(
1306 NumberToSize(isolate, buffer->byte_length())
1307 >= buffer_offset + sizeof(T));
1308 uint8_t* target =
1309 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1310 if (NeedToFlipBytes(is_little_endian)) {
1311 FlipBytes<sizeof(T)>(target, value.bytes);
1312 } else {
1313 CopyBytes<sizeof(T)>(target, value.bytes);
1314 }
1315 return true;
1316 }
1317
1318
1319 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
1320 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \
1321 HandleScope scope(isolate); \
1322 ASSERT(args.length() == 3); \
1323 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1324 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1325 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
1326 Type result; \
1327 if (DataViewGetValue( \
1328 isolate, holder, offset, is_little_endian, &result)) { \
1329 return isolate->heap()->Converter(result); \
1330 } else { \
1331 return isolate->Throw(*isolate->factory()->NewRangeError( \
1332 "invalid_data_view_accessor_offset", \
1333 HandleVector<Object>(NULL, 0))); \
1334 } \
1335 }
1336
1337 DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32)
1338 DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32)
1339 DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32)
1340 DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32)
1341 DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32)
1342 DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32)
1343 DATA_VIEW_GETTER(Float32, float, NumberFromDouble)
1344 DATA_VIEW_GETTER(Float64, double, NumberFromDouble)
1345
1346 #undef DATA_VIEW_GETTER
1347
1348
1349 template <typename T>
1350 static T DataViewConvertValue(double value);
1351
1352
1353 template <>
DataViewConvertValue(double value)1354 int8_t DataViewConvertValue<int8_t>(double value) {
1355 return static_cast<int8_t>(DoubleToInt32(value));
1356 }
1357
1358
1359 template <>
DataViewConvertValue(double value)1360 int16_t DataViewConvertValue<int16_t>(double value) {
1361 return static_cast<int16_t>(DoubleToInt32(value));
1362 }
1363
1364
1365 template <>
DataViewConvertValue(double value)1366 int32_t DataViewConvertValue<int32_t>(double value) {
1367 return DoubleToInt32(value);
1368 }
1369
1370
1371 template <>
DataViewConvertValue(double value)1372 uint8_t DataViewConvertValue<uint8_t>(double value) {
1373 return static_cast<uint8_t>(DoubleToUint32(value));
1374 }
1375
1376
1377 template <>
DataViewConvertValue(double value)1378 uint16_t DataViewConvertValue<uint16_t>(double value) {
1379 return static_cast<uint16_t>(DoubleToUint32(value));
1380 }
1381
1382
1383 template <>
DataViewConvertValue(double value)1384 uint32_t DataViewConvertValue<uint32_t>(double value) {
1385 return DoubleToUint32(value);
1386 }
1387
1388
1389 template <>
DataViewConvertValue(double value)1390 float DataViewConvertValue<float>(double value) {
1391 return static_cast<float>(value);
1392 }
1393
1394
1395 template <>
DataViewConvertValue(double value)1396 double DataViewConvertValue<double>(double value) {
1397 return value;
1398 }
1399
1400
1401 #define DATA_VIEW_SETTER(TypeName, Type) \
1402 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \
1403 HandleScope scope(isolate); \
1404 ASSERT(args.length() == 4); \
1405 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1406 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1407 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
1408 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
1409 Type v = DataViewConvertValue<Type>(value->Number()); \
1410 if (DataViewSetValue( \
1411 isolate, holder, offset, is_little_endian, v)) { \
1412 return isolate->heap()->undefined_value(); \
1413 } else { \
1414 return isolate->Throw(*isolate->factory()->NewRangeError( \
1415 "invalid_data_view_accessor_offset", \
1416 HandleVector<Object>(NULL, 0))); \
1417 } \
1418 }
1419
DATA_VIEW_SETTER(Uint8,uint8_t)1420 DATA_VIEW_SETTER(Uint8, uint8_t)
1421 DATA_VIEW_SETTER(Int8, int8_t)
1422 DATA_VIEW_SETTER(Uint16, uint16_t)
1423 DATA_VIEW_SETTER(Int16, int16_t)
1424 DATA_VIEW_SETTER(Uint32, uint32_t)
1425 DATA_VIEW_SETTER(Int32, int32_t)
1426 DATA_VIEW_SETTER(Float32, float)
1427 DATA_VIEW_SETTER(Float64, double)
1428
1429 #undef DATA_VIEW_SETTER
1430
1431
1432 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
1433 HandleScope scope(isolate);
1434 ASSERT(args.length() == 1);
1435 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1436 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
1437 holder->set_table(*table);
1438 return *holder;
1439 }
1440
1441
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetAdd)1442 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
1443 HandleScope scope(isolate);
1444 ASSERT(args.length() == 2);
1445 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1446 Handle<Object> key(args[1], isolate);
1447 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1448 table = ObjectHashSet::Add(table, key);
1449 holder->set_table(*table);
1450 return isolate->heap()->undefined_value();
1451 }
1452
1453
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetHas)1454 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
1455 HandleScope scope(isolate);
1456 ASSERT(args.length() == 2);
1457 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1458 Handle<Object> key(args[1], isolate);
1459 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1460 return isolate->heap()->ToBoolean(table->Contains(*key));
1461 }
1462
1463
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetDelete)1464 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
1465 HandleScope scope(isolate);
1466 ASSERT(args.length() == 2);
1467 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1468 Handle<Object> key(args[1], isolate);
1469 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1470 table = ObjectHashSet::Remove(table, key);
1471 holder->set_table(*table);
1472 return isolate->heap()->undefined_value();
1473 }
1474
1475
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetGetSize)1476 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
1477 HandleScope scope(isolate);
1478 ASSERT(args.length() == 1);
1479 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1480 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1481 return Smi::FromInt(table->NumberOfElements());
1482 }
1483
1484
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapInitialize)1485 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
1486 HandleScope scope(isolate);
1487 ASSERT(args.length() == 1);
1488 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1489 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1490 holder->set_table(*table);
1491 return *holder;
1492 }
1493
1494
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapGet)1495 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
1496 HandleScope scope(isolate);
1497 ASSERT(args.length() == 2);
1498 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1499 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1500 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1501 Handle<Object> lookup(table->Lookup(*key), isolate);
1502 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1503 }
1504
1505
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapHas)1506 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) {
1507 HandleScope scope(isolate);
1508 ASSERT(args.length() == 2);
1509 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1510 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1511 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1512 Handle<Object> lookup(table->Lookup(*key), isolate);
1513 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1514 }
1515
1516
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapDelete)1517 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) {
1518 HandleScope scope(isolate);
1519 ASSERT(args.length() == 2);
1520 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1521 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1522 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1523 Handle<Object> lookup(table->Lookup(*key), isolate);
1524 Handle<ObjectHashTable> new_table =
1525 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
1526 holder->set_table(*new_table);
1527 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1528 }
1529
1530
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapSet)1531 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
1532 HandleScope scope(isolate);
1533 ASSERT(args.length() == 3);
1534 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1535 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1536 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1537 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1538 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1539 holder->set_table(*new_table);
1540 return isolate->heap()->undefined_value();
1541 }
1542
1543
RUNTIME_FUNCTION(MaybeObject *,Runtime_MapGetSize)1544 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
1545 HandleScope scope(isolate);
1546 ASSERT(args.length() == 1);
1547 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1548 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1549 return Smi::FromInt(table->NumberOfElements());
1550 }
1551
1552
WeakCollectionInitialize(Isolate * isolate,Handle<JSWeakCollection> weak_collection)1553 static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate,
1554 Handle<JSWeakCollection> weak_collection) {
1555 ASSERT(weak_collection->map()->inobject_properties() == 0);
1556 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1557 weak_collection->set_table(*table);
1558 weak_collection->set_next(Smi::FromInt(0));
1559 return *weak_collection;
1560 }
1561
1562
RUNTIME_FUNCTION(MaybeObject *,Runtime_WeakCollectionInitialize)1563 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) {
1564 HandleScope scope(isolate);
1565 ASSERT(args.length() == 1);
1566 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1567 return WeakCollectionInitialize(isolate, weak_collection);
1568 }
1569
1570
RUNTIME_FUNCTION(MaybeObject *,Runtime_WeakCollectionGet)1571 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) {
1572 HandleScope scope(isolate);
1573 ASSERT(args.length() == 2);
1574 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1575 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1576 Handle<ObjectHashTable> table(
1577 ObjectHashTable::cast(weak_collection->table()));
1578 Handle<Object> lookup(table->Lookup(*key), isolate);
1579 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1580 }
1581
1582
RUNTIME_FUNCTION(MaybeObject *,Runtime_WeakCollectionHas)1583 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) {
1584 HandleScope scope(isolate);
1585 ASSERT(args.length() == 2);
1586 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1587 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1588 Handle<ObjectHashTable> table(
1589 ObjectHashTable::cast(weak_collection->table()));
1590 Handle<Object> lookup(table->Lookup(*key), isolate);
1591 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1592 }
1593
1594
RUNTIME_FUNCTION(MaybeObject *,Runtime_WeakCollectionDelete)1595 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) {
1596 HandleScope scope(isolate);
1597 ASSERT(args.length() == 2);
1598 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1599 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1600 Handle<ObjectHashTable> table(ObjectHashTable::cast(
1601 weak_collection->table()));
1602 Handle<Object> lookup(table->Lookup(*key), isolate);
1603 Handle<ObjectHashTable> new_table =
1604 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
1605 weak_collection->set_table(*new_table);
1606 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1607 }
1608
1609
RUNTIME_FUNCTION(MaybeObject *,Runtime_WeakCollectionSet)1610 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) {
1611 HandleScope scope(isolate);
1612 ASSERT(args.length() == 3);
1613 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1614 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1615 Handle<Object> value(args[2], isolate);
1616 Handle<ObjectHashTable> table(
1617 ObjectHashTable::cast(weak_collection->table()));
1618 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1619 weak_collection->set_table(*new_table);
1620 return isolate->heap()->undefined_value();
1621 }
1622
1623
RUNTIME_FUNCTION(MaybeObject *,Runtime_ClassOf)1624 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
1625 SealHandleScope shs(isolate);
1626 ASSERT(args.length() == 1);
1627 Object* obj = args[0];
1628 if (!obj->IsJSObject()) return isolate->heap()->null_value();
1629 return JSObject::cast(obj)->class_name();
1630 }
1631
1632
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetPrototype)1633 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
1634 HandleScope scope(isolate);
1635 ASSERT(args.length() == 1);
1636 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
1637 // We don't expect access checks to be needed on JSProxy objects.
1638 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
1639 do {
1640 if (obj->IsAccessCheckNeeded() &&
1641 !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj),
1642 isolate->factory()->proto_string(),
1643 v8::ACCESS_GET)) {
1644 isolate->ReportFailedAccessCheck(JSObject::cast(*obj), v8::ACCESS_GET);
1645 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1646 return isolate->heap()->undefined_value();
1647 }
1648 obj = handle(obj->GetPrototype(isolate), isolate);
1649 } while (obj->IsJSObject() &&
1650 JSObject::cast(*obj)->map()->is_hidden_prototype());
1651 return *obj;
1652 }
1653
1654
GetPrototypeSkipHiddenPrototypes(Isolate * isolate,Object * receiver)1655 static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
1656 Object* receiver) {
1657 Object* current = receiver->GetPrototype(isolate);
1658 while (current->IsJSObject() &&
1659 JSObject::cast(current)->map()->is_hidden_prototype()) {
1660 current = current->GetPrototype(isolate);
1661 }
1662 return current;
1663 }
1664
1665
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetPrototype)1666 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
1667 HandleScope scope(isolate);
1668 ASSERT(args.length() == 2);
1669 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1670 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
1671 if (FLAG_harmony_observation && obj->map()->is_observed()) {
1672 Handle<Object> old_value(
1673 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
1674
1675 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
1676 RETURN_IF_EMPTY_HANDLE(isolate, result);
1677
1678 Handle<Object> new_value(
1679 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
1680 if (!new_value->SameValue(*old_value)) {
1681 JSObject::EnqueueChangeRecord(obj, "setPrototype",
1682 isolate->factory()->proto_string(),
1683 old_value);
1684 }
1685 return *result;
1686 }
1687 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
1688 RETURN_IF_EMPTY_HANDLE(isolate, result);
1689 return *result;
1690 }
1691
1692
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsInPrototypeChain)1693 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
1694 SealHandleScope shs(isolate);
1695 ASSERT(args.length() == 2);
1696 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1697 Object* O = args[0];
1698 Object* V = args[1];
1699 while (true) {
1700 Object* prototype = V->GetPrototype(isolate);
1701 if (prototype->IsNull()) return isolate->heap()->false_value();
1702 if (O == prototype) return isolate->heap()->true_value();
1703 V = prototype;
1704 }
1705 }
1706
1707
CheckAccessException(Object * callback,v8::AccessType access_type)1708 static bool CheckAccessException(Object* callback,
1709 v8::AccessType access_type) {
1710 DisallowHeapAllocation no_gc;
1711 if (callback->IsAccessorInfo()) {
1712 AccessorInfo* info = AccessorInfo::cast(callback);
1713 return
1714 (access_type == v8::ACCESS_HAS &&
1715 (info->all_can_read() || info->all_can_write())) ||
1716 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1717 (access_type == v8::ACCESS_SET && info->all_can_write());
1718 }
1719 if (callback->IsAccessorPair()) {
1720 AccessorPair* info = AccessorPair::cast(callback);
1721 return
1722 (access_type == v8::ACCESS_HAS &&
1723 (info->all_can_read() || info->all_can_write())) ||
1724 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1725 (access_type == v8::ACCESS_SET && info->all_can_write());
1726 }
1727 return false;
1728 }
1729
1730
1731 template<class Key>
CheckGenericAccess(Handle<JSObject> receiver,Handle<JSObject> holder,Key key,v8::AccessType access_type,bool (Isolate::* mayAccess)(Handle<JSObject>,Key,v8::AccessType))1732 static bool CheckGenericAccess(
1733 Handle<JSObject> receiver,
1734 Handle<JSObject> holder,
1735 Key key,
1736 v8::AccessType access_type,
1737 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) {
1738 Isolate* isolate = receiver->GetIsolate();
1739 for (Handle<JSObject> current = receiver;
1740 true;
1741 current = handle(JSObject::cast(current->GetPrototype()), isolate)) {
1742 if (current->IsAccessCheckNeeded() &&
1743 !(isolate->*mayAccess)(current, key, access_type)) {
1744 return false;
1745 }
1746 if (current.is_identical_to(holder)) break;
1747 }
1748 return true;
1749 }
1750
1751
1752 enum AccessCheckResult {
1753 ACCESS_FORBIDDEN,
1754 ACCESS_ALLOWED,
1755 ACCESS_ABSENT
1756 };
1757
1758
CheckPropertyAccess(Handle<JSObject> obj,Handle<Name> name,v8::AccessType access_type)1759 static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj,
1760 Handle<Name> name,
1761 v8::AccessType access_type) {
1762 uint32_t index;
1763 if (name->AsArrayIndex(&index)) {
1764 // TODO(1095): we should traverse hidden prototype hierachy as well.
1765 if (CheckGenericAccess(
1766 obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) {
1767 return ACCESS_ALLOWED;
1768 }
1769
1770 obj->GetIsolate()->ReportFailedAccessCheck(*obj, access_type);
1771 return ACCESS_FORBIDDEN;
1772 }
1773
1774 Isolate* isolate = obj->GetIsolate();
1775 LookupResult lookup(isolate);
1776 obj->LocalLookup(*name, &lookup, true);
1777
1778 if (!lookup.IsProperty()) return ACCESS_ABSENT;
1779 Handle<JSObject> holder(lookup.holder(), isolate);
1780 if (CheckGenericAccess<Handle<Object> >(
1781 obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) {
1782 return ACCESS_ALLOWED;
1783 }
1784
1785 // Access check callback denied the access, but some properties
1786 // can have a special permissions which override callbacks descision
1787 // (currently see v8::AccessControl).
1788 // API callbacks can have per callback access exceptions.
1789 switch (lookup.type()) {
1790 case CALLBACKS:
1791 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1792 return ACCESS_ALLOWED;
1793 }
1794 break;
1795 case INTERCEPTOR:
1796 // If the object has an interceptor, try real named properties.
1797 // Overwrite the result to fetch the correct property later.
1798 holder->LookupRealNamedProperty(*name, &lookup);
1799 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1800 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1801 return ACCESS_ALLOWED;
1802 }
1803 }
1804 break;
1805 default:
1806 break;
1807 }
1808
1809 isolate->ReportFailedAccessCheck(*obj, access_type);
1810 return ACCESS_FORBIDDEN;
1811 }
1812
1813
1814 // Enumerator used as indices into the array returned from GetOwnProperty
1815 enum PropertyDescriptorIndices {
1816 IS_ACCESSOR_INDEX,
1817 VALUE_INDEX,
1818 GETTER_INDEX,
1819 SETTER_INDEX,
1820 WRITABLE_INDEX,
1821 ENUMERABLE_INDEX,
1822 CONFIGURABLE_INDEX,
1823 DESCRIPTOR_SIZE
1824 };
1825
1826
GetOwnProperty(Isolate * isolate,Handle<JSObject> obj,Handle<Name> name)1827 static Handle<Object> GetOwnProperty(Isolate* isolate,
1828 Handle<JSObject> obj,
1829 Handle<Name> name) {
1830 Heap* heap = isolate->heap();
1831 Factory* factory = isolate->factory();
1832 // Due to some WebKit tests, we want to make sure that we do not log
1833 // more than one access failure here.
1834 AccessCheckResult access_check_result =
1835 CheckPropertyAccess(obj, name, v8::ACCESS_HAS);
1836 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1837 switch (access_check_result) {
1838 case ACCESS_FORBIDDEN: return factory->false_value();
1839 case ACCESS_ALLOWED: break;
1840 case ACCESS_ABSENT: return factory->undefined_value();
1841 }
1842
1843 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name);
1844 if (attrs == ABSENT) {
1845 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1846 return factory->undefined_value();
1847 }
1848 ASSERT(!isolate->has_scheduled_exception());
1849 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name);
1850 Handle<AccessorPair> accessors(raw_accessors, isolate);
1851 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1852 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1853 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
1854 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL));
1855
1856 if (raw_accessors == NULL) {
1857 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1858 // GetProperty does access check.
1859 Handle<Object> value = GetProperty(isolate, obj, name);
1860 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null());
1861 elms->set(VALUE_INDEX, *value);
1862 } else {
1863 // Access checks are performed for both accessors separately.
1864 // When they fail, the respective field is not set in the descriptor.
1865 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
1866 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
1867
1868 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) {
1869 ASSERT(!isolate->has_scheduled_exception());
1870 elms->set(GETTER_INDEX, *getter);
1871 } else {
1872 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1873 }
1874
1875 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) {
1876 ASSERT(!isolate->has_scheduled_exception());
1877 elms->set(SETTER_INDEX, *setter);
1878 } else {
1879 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1880 }
1881 }
1882
1883 return isolate->factory()->NewJSArrayWithElements(elms);
1884 }
1885
1886
1887 // Returns an array with the property description:
1888 // if args[1] is not a property on args[0]
1889 // returns undefined
1890 // if args[1] is a data property on args[0]
1891 // [false, value, Writeable, Enumerable, Configurable]
1892 // if args[1] is an accessor on args[0]
1893 // [true, GetFunction, SetFunction, Enumerable, Configurable]
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetOwnProperty)1894 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1895 HandleScope scope(isolate);
1896 ASSERT(args.length() == 2);
1897 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1898 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
1899 Handle<Object> result = GetOwnProperty(isolate, obj, name);
1900 RETURN_IF_EMPTY_HANDLE(isolate, result);
1901 return *result;
1902 }
1903
1904
RUNTIME_FUNCTION(MaybeObject *,Runtime_PreventExtensions)1905 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
1906 HandleScope scope(isolate);
1907 ASSERT(args.length() == 1);
1908 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1909 Handle<Object> result = JSObject::PreventExtensions(obj);
1910 RETURN_IF_EMPTY_HANDLE(isolate, result);
1911 return *result;
1912 }
1913
1914
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsExtensible)1915 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
1916 SealHandleScope shs(isolate);
1917 ASSERT(args.length() == 1);
1918 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1919 if (obj->IsJSGlobalProxy()) {
1920 Object* proto = obj->GetPrototype();
1921 if (proto->IsNull()) return isolate->heap()->false_value();
1922 ASSERT(proto->IsJSGlobalObject());
1923 obj = JSObject::cast(proto);
1924 }
1925 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
1926 }
1927
1928
RUNTIME_FUNCTION(MaybeObject *,Runtime_RegExpCompile)1929 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
1930 HandleScope scope(isolate);
1931 ASSERT(args.length() == 3);
1932 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1933 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1934 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
1935 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1936 RETURN_IF_EMPTY_HANDLE(isolate, result);
1937 return *result;
1938 }
1939
1940
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateApiFunction)1941 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
1942 HandleScope scope(isolate);
1943 ASSERT(args.length() == 1);
1944 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
1945 return *isolate->factory()->CreateApiFunction(data);
1946 }
1947
1948
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsTemplate)1949 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
1950 SealHandleScope shs(isolate);
1951 ASSERT(args.length() == 1);
1952 Object* arg = args[0];
1953 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
1954 return isolate->heap()->ToBoolean(result);
1955 }
1956
1957
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetTemplateField)1958 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
1959 SealHandleScope shs(isolate);
1960 ASSERT(args.length() == 2);
1961 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1962 CONVERT_SMI_ARG_CHECKED(index, 1)
1963 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1964 InstanceType type = templ->map()->instance_type();
1965 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1966 type == OBJECT_TEMPLATE_INFO_TYPE);
1967 RUNTIME_ASSERT(offset > 0);
1968 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
1969 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1970 } else {
1971 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1972 }
1973 return *HeapObject::RawField(templ, offset);
1974 }
1975
1976
RUNTIME_FUNCTION(MaybeObject *,Runtime_DisableAccessChecks)1977 RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
1978 SealHandleScope shs(isolate);
1979 ASSERT(args.length() == 1);
1980 CONVERT_ARG_CHECKED(HeapObject, object, 0);
1981 Map* old_map = object->map();
1982 bool needs_access_checks = old_map->is_access_check_needed();
1983 if (needs_access_checks) {
1984 // Copy map so it won't interfere constructor's initial map.
1985 Map* new_map;
1986 MaybeObject* maybe_new_map = old_map->Copy();
1987 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
1988
1989 new_map->set_is_access_check_needed(false);
1990 object->set_map(new_map);
1991 }
1992 return isolate->heap()->ToBoolean(needs_access_checks);
1993 }
1994
1995
RUNTIME_FUNCTION(MaybeObject *,Runtime_EnableAccessChecks)1996 RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
1997 SealHandleScope shs(isolate);
1998 ASSERT(args.length() == 1);
1999 CONVERT_ARG_CHECKED(HeapObject, object, 0);
2000 Map* old_map = object->map();
2001 if (!old_map->is_access_check_needed()) {
2002 // Copy map so it won't interfere constructor's initial map.
2003 Map* new_map;
2004 MaybeObject* maybe_new_map = old_map->Copy();
2005 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
2006
2007 new_map->set_is_access_check_needed(true);
2008 object->set_map(new_map);
2009 }
2010 return isolate->heap()->undefined_value();
2011 }
2012
2013
2014 // Transform getter or setter into something DefineAccessor can handle.
InstantiateAccessorComponent(Isolate * isolate,Handle<Object> component)2015 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
2016 Handle<Object> component) {
2017 if (component->IsUndefined()) return isolate->factory()->null_value();
2018 Handle<FunctionTemplateInfo> info =
2019 Handle<FunctionTemplateInfo>::cast(component);
2020 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
2021 }
2022
2023
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetAccessorProperty)2024 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) {
2025 HandleScope scope(isolate);
2026 ASSERT(args.length() == 6);
2027 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2028 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2029 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
2030 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
2031 CONVERT_SMI_ARG_CHECKED(attribute, 4);
2032 CONVERT_SMI_ARG_CHECKED(access_control, 5);
2033 JSObject::DefineAccessor(object,
2034 name,
2035 InstantiateAccessorComponent(isolate, getter),
2036 InstantiateAccessorComponent(isolate, setter),
2037 static_cast<PropertyAttributes>(attribute),
2038 static_cast<v8::AccessControl>(access_control));
2039 return isolate->heap()->undefined_value();
2040 }
2041
2042
ThrowRedeclarationError(Isolate * isolate,const char * type,Handle<String> name)2043 static Failure* ThrowRedeclarationError(Isolate* isolate,
2044 const char* type,
2045 Handle<String> name) {
2046 HandleScope scope(isolate);
2047 Handle<Object> type_handle =
2048 isolate->factory()->NewStringFromAscii(CStrVector(type));
2049 Handle<Object> args[2] = { type_handle, name };
2050 Handle<Object> error =
2051 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
2052 return isolate->Throw(*error);
2053 }
2054
2055
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeclareGlobals)2056 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
2057 HandleScope scope(isolate);
2058 ASSERT(args.length() == 3);
2059 Handle<GlobalObject> global = Handle<GlobalObject>(
2060 isolate->context()->global_object());
2061
2062 Handle<Context> context = args.at<Context>(0);
2063 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
2064 CONVERT_SMI_ARG_CHECKED(flags, 2);
2065
2066 // Traverse the name/value pairs and set the properties.
2067 int length = pairs->length();
2068 for (int i = 0; i < length; i += 2) {
2069 HandleScope scope(isolate);
2070 Handle<String> name(String::cast(pairs->get(i)));
2071 Handle<Object> value(pairs->get(i + 1), isolate);
2072
2073 // We have to declare a global const property. To capture we only
2074 // assign to it when evaluating the assignment for "const x =
2075 // <expr>" the initial value is the hole.
2076 bool is_var = value->IsUndefined();
2077 bool is_const = value->IsTheHole();
2078 bool is_function = value->IsSharedFunctionInfo();
2079 ASSERT(is_var + is_const + is_function == 1);
2080
2081 if (is_var || is_const) {
2082 // Lookup the property in the global object, and don't set the
2083 // value of the variable if the property is already there.
2084 // Do the lookup locally only, see ES5 erratum.
2085 LookupResult lookup(isolate);
2086 if (FLAG_es52_globals) {
2087 global->LocalLookup(*name, &lookup, true);
2088 } else {
2089 global->Lookup(*name, &lookup);
2090 }
2091 if (lookup.IsFound()) {
2092 // We found an existing property. Unless it was an interceptor
2093 // that claims the property is absent, skip this declaration.
2094 if (!lookup.IsInterceptor()) continue;
2095 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
2096 if (attributes != ABSENT) continue;
2097 // Fall-through and introduce the absent property by using
2098 // SetProperty.
2099 }
2100 } else if (is_function) {
2101 // Copy the function and update its context. Use it as value.
2102 Handle<SharedFunctionInfo> shared =
2103 Handle<SharedFunctionInfo>::cast(value);
2104 Handle<JSFunction> function =
2105 isolate->factory()->NewFunctionFromSharedFunctionInfo(
2106 shared, context, TENURED);
2107 value = function;
2108 }
2109
2110 LookupResult lookup(isolate);
2111 global->LocalLookup(*name, &lookup, true);
2112
2113 // Compute the property attributes. According to ECMA-262,
2114 // the property must be non-configurable except in eval.
2115 int attr = NONE;
2116 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
2117 if (!is_eval) {
2118 attr |= DONT_DELETE;
2119 }
2120 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
2121 if (is_const || (is_native && is_function)) {
2122 attr |= READ_ONLY;
2123 }
2124
2125 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
2126
2127 if (!lookup.IsFound() || is_function) {
2128 // If the local property exists, check that we can reconfigure it
2129 // as required for function declarations.
2130 if (lookup.IsFound() && lookup.IsDontDelete()) {
2131 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
2132 lookup.IsPropertyCallbacks()) {
2133 return ThrowRedeclarationError(isolate, "function", name);
2134 }
2135 // If the existing property is not configurable, keep its attributes.
2136 attr = lookup.GetAttributes();
2137 }
2138 // Define or redefine own property.
2139 RETURN_IF_EMPTY_HANDLE(isolate,
2140 JSObject::SetLocalPropertyIgnoreAttributes(
2141 global, name, value, static_cast<PropertyAttributes>(attr)));
2142 } else {
2143 // Do a [[Put]] on the existing (own) property.
2144 RETURN_IF_EMPTY_HANDLE(isolate,
2145 JSObject::SetProperty(
2146 global, name, value, static_cast<PropertyAttributes>(attr),
2147 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
2148 }
2149 }
2150
2151 ASSERT(!isolate->has_pending_exception());
2152 return isolate->heap()->undefined_value();
2153 }
2154
2155
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeclareContextSlot)2156 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
2157 HandleScope scope(isolate);
2158 ASSERT(args.length() == 4);
2159
2160 // Declarations are always made in a function or native context. In the
2161 // case of eval code, the context passed is the context of the caller,
2162 // which may be some nested context and not the declaration context.
2163 RUNTIME_ASSERT(args[0]->IsContext());
2164 Handle<Context> context(Context::cast(args[0])->declaration_context());
2165
2166 Handle<String> name(String::cast(args[1]));
2167 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
2168 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
2169 Handle<Object> initial_value(args[3], isolate);
2170
2171 int index;
2172 PropertyAttributes attributes;
2173 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
2174 BindingFlags binding_flags;
2175 Handle<Object> holder =
2176 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2177
2178 if (attributes != ABSENT) {
2179 // The name was declared before; check for conflicting re-declarations.
2180 // Note: this is actually inconsistent with what happens for globals (where
2181 // we silently ignore such declarations).
2182 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
2183 // Functions are not read-only.
2184 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
2185 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
2186 return ThrowRedeclarationError(isolate, type, name);
2187 }
2188
2189 // Initialize it if necessary.
2190 if (*initial_value != NULL) {
2191 if (index >= 0) {
2192 ASSERT(holder.is_identical_to(context));
2193 if (((attributes & READ_ONLY) == 0) ||
2194 context->get(index)->IsTheHole()) {
2195 context->set(index, *initial_value);
2196 }
2197 } else {
2198 // Slow case: The property is in the context extension object of a
2199 // function context or the global object of a native context.
2200 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2201 RETURN_IF_EMPTY_HANDLE(
2202 isolate,
2203 JSReceiver::SetProperty(object, name, initial_value, mode,
2204 kNonStrictMode));
2205 }
2206 }
2207
2208 } else {
2209 // The property is not in the function context. It needs to be
2210 // "declared" in the function context's extension context or as a
2211 // property of the the global object.
2212 Handle<JSObject> object;
2213 if (context->has_extension()) {
2214 object = Handle<JSObject>(JSObject::cast(context->extension()));
2215 } else {
2216 // Context extension objects are allocated lazily.
2217 ASSERT(context->IsFunctionContext());
2218 object = isolate->factory()->NewJSObject(
2219 isolate->context_extension_function());
2220 context->set_extension(*object);
2221 }
2222 ASSERT(*object != NULL);
2223
2224 // Declare the property by setting it to the initial value if provided,
2225 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
2226 // constant declarations).
2227 ASSERT(!JSReceiver::HasLocalProperty(object, name));
2228 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
2229 if (*initial_value != NULL) value = initial_value;
2230 // Declaring a const context slot is a conflicting declaration if
2231 // there is a callback with that name in a prototype. It is
2232 // allowed to introduce const variables in
2233 // JSContextExtensionObjects. They are treated specially in
2234 // SetProperty and no setters are invoked for those since they are
2235 // not real JSObjects.
2236 if (initial_value->IsTheHole() &&
2237 !object->IsJSContextExtensionObject()) {
2238 LookupResult lookup(isolate);
2239 object->Lookup(*name, &lookup);
2240 if (lookup.IsPropertyCallbacks()) {
2241 return ThrowRedeclarationError(isolate, "const", name);
2242 }
2243 }
2244 if (object->IsJSGlobalObject()) {
2245 // Define own property on the global object.
2246 RETURN_IF_EMPTY_HANDLE(isolate,
2247 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
2248 } else {
2249 RETURN_IF_EMPTY_HANDLE(isolate,
2250 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
2251 }
2252 }
2253
2254 return isolate->heap()->undefined_value();
2255 }
2256
2257
RUNTIME_FUNCTION(MaybeObject *,Runtime_InitializeVarGlobal)2258 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
2259 HandleScope scope(isolate);
2260 // args[0] == name
2261 // args[1] == language_mode
2262 // args[2] == value (optional)
2263
2264 // Determine if we need to assign to the variable if it already
2265 // exists (based on the number of arguments).
2266 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
2267 bool assign = args.length() == 3;
2268
2269 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2270 RUNTIME_ASSERT(args[1]->IsSmi());
2271 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
2272 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
2273 ? kNonStrictMode : kStrictMode;
2274
2275 // According to ECMA-262, section 12.2, page 62, the property must
2276 // not be deletable.
2277 PropertyAttributes attributes = DONT_DELETE;
2278
2279 // Lookup the property locally in the global object. If it isn't
2280 // there, there is a property with this name in the prototype chain.
2281 // We follow Safari and Firefox behavior and only set the property
2282 // locally if there is an explicit initialization value that we have
2283 // to assign to the property.
2284 // Note that objects can have hidden prototypes, so we need to traverse
2285 // the whole chain of hidden prototypes to do a 'local' lookup.
2286 LookupResult lookup(isolate);
2287 isolate->context()->global_object()->LocalLookup(*name, &lookup, true);
2288 if (lookup.IsInterceptor()) {
2289 PropertyAttributes intercepted =
2290 lookup.holder()->GetPropertyAttribute(*name);
2291 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
2292 // Found an interceptor that's not read only.
2293 if (assign) {
2294 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2295 Handle<Object> result = JSObject::SetPropertyForResult(
2296 handle(lookup.holder()), &lookup, name, value, attributes,
2297 strict_mode_flag);
2298 RETURN_IF_EMPTY_HANDLE(isolate, result);
2299 return *result;
2300 } else {
2301 return isolate->heap()->undefined_value();
2302 }
2303 }
2304 }
2305
2306 if (assign) {
2307 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2308 Handle<GlobalObject> global(isolate->context()->global_object());
2309 Handle<Object> result = JSReceiver::SetProperty(
2310 global, name, value, attributes, strict_mode_flag);
2311 RETURN_IF_EMPTY_HANDLE(isolate, result);
2312 return *result;
2313 }
2314 return isolate->heap()->undefined_value();
2315 }
2316
2317
RUNTIME_FUNCTION(MaybeObject *,Runtime_InitializeConstGlobal)2318 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
2319 SealHandleScope shs(isolate);
2320 // All constants are declared with an initial value. The name
2321 // of the constant is the first argument and the initial value
2322 // is the second.
2323 RUNTIME_ASSERT(args.length() == 2);
2324 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2325 Handle<Object> value = args.at<Object>(1);
2326
2327 // Get the current global object from top.
2328 GlobalObject* global = isolate->context()->global_object();
2329
2330 // According to ECMA-262, section 12.2, page 62, the property must
2331 // not be deletable. Since it's a const, it must be READ_ONLY too.
2332 PropertyAttributes attributes =
2333 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2334
2335 // Lookup the property locally in the global object. If it isn't
2336 // there, we add the property and take special precautions to always
2337 // add it as a local property even in case of callbacks in the
2338 // prototype chain (this rules out using SetProperty).
2339 // We use SetLocalPropertyIgnoreAttributes instead
2340 LookupResult lookup(isolate);
2341 global->LocalLookup(*name, &lookup);
2342 if (!lookup.IsFound()) {
2343 HandleScope handle_scope(isolate);
2344 Handle<GlobalObject> global(isolate->context()->global_object());
2345 RETURN_IF_EMPTY_HANDLE(
2346 isolate,
2347 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
2348 attributes));
2349 return *value;
2350 }
2351
2352 if (!lookup.IsReadOnly()) {
2353 // Restore global object from context (in case of GC) and continue
2354 // with setting the value.
2355 HandleScope handle_scope(isolate);
2356 Handle<GlobalObject> global(isolate->context()->global_object());
2357
2358 // BUG 1213575: Handle the case where we have to set a read-only
2359 // property through an interceptor and only do it if it's
2360 // uninitialized, e.g. the hole. Nirk...
2361 // Passing non-strict mode because the property is writable.
2362 RETURN_IF_EMPTY_HANDLE(
2363 isolate,
2364 JSReceiver::SetProperty(global, name, value, attributes,
2365 kNonStrictMode));
2366 return *value;
2367 }
2368
2369 // Set the value, but only if we're assigning the initial value to a
2370 // constant. For now, we determine this by checking if the
2371 // current value is the hole.
2372 // Strict mode handling not needed (const is disallowed in strict mode).
2373 if (lookup.IsField()) {
2374 FixedArray* properties = global->properties();
2375 int index = lookup.GetFieldIndex().field_index();
2376 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
2377 properties->set(index, *value);
2378 }
2379 } else if (lookup.IsNormal()) {
2380 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
2381 !lookup.IsReadOnly()) {
2382 HandleScope scope(isolate);
2383 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
2384 }
2385 } else {
2386 // Ignore re-initialization of constants that have already been
2387 // assigned a constant value.
2388 ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
2389 }
2390
2391 // Use the set value as the result of the operation.
2392 return *value;
2393 }
2394
2395
RUNTIME_FUNCTION(MaybeObject *,Runtime_InitializeConstContextSlot)2396 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
2397 HandleScope scope(isolate);
2398 ASSERT(args.length() == 3);
2399
2400 Handle<Object> value(args[0], isolate);
2401 ASSERT(!value->IsTheHole());
2402
2403 // Initializations are always done in a function or native context.
2404 RUNTIME_ASSERT(args[1]->IsContext());
2405 Handle<Context> context(Context::cast(args[1])->declaration_context());
2406
2407 Handle<String> name(String::cast(args[2]));
2408
2409 int index;
2410 PropertyAttributes attributes;
2411 ContextLookupFlags flags = FOLLOW_CHAINS;
2412 BindingFlags binding_flags;
2413 Handle<Object> holder =
2414 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2415
2416 if (index >= 0) {
2417 ASSERT(holder->IsContext());
2418 // Property was found in a context. Perform the assignment if we
2419 // found some non-constant or an uninitialized constant.
2420 Handle<Context> context = Handle<Context>::cast(holder);
2421 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
2422 context->set(index, *value);
2423 }
2424 return *value;
2425 }
2426
2427 // The property could not be found, we introduce it as a property of the
2428 // global object.
2429 if (attributes == ABSENT) {
2430 Handle<JSObject> global = Handle<JSObject>(
2431 isolate->context()->global_object());
2432 // Strict mode not needed (const disallowed in strict mode).
2433 RETURN_IF_EMPTY_HANDLE(
2434 isolate,
2435 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
2436 return *value;
2437 }
2438
2439 // The property was present in some function's context extension object,
2440 // as a property on the subject of a with, or as a property of the global
2441 // object.
2442 //
2443 // In most situations, eval-introduced consts should still be present in
2444 // the context extension object. However, because declaration and
2445 // initialization are separate, the property might have been deleted
2446 // before we reach the initialization point.
2447 //
2448 // Example:
2449 //
2450 // function f() { eval("delete x; const x;"); }
2451 //
2452 // In that case, the initialization behaves like a normal assignment.
2453 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2454
2455 if (*object == context->extension()) {
2456 // This is the property that was introduced by the const declaration.
2457 // Set it if it hasn't been set before. NOTE: We cannot use
2458 // GetProperty() to get the current value as it 'unholes' the value.
2459 LookupResult lookup(isolate);
2460 object->LocalLookupRealNamedProperty(*name, &lookup);
2461 ASSERT(lookup.IsFound()); // the property was declared
2462 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
2463
2464 if (lookup.IsField()) {
2465 FixedArray* properties = object->properties();
2466 int index = lookup.GetFieldIndex().field_index();
2467 if (properties->get(index)->IsTheHole()) {
2468 properties->set(index, *value);
2469 }
2470 } else if (lookup.IsNormal()) {
2471 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
2472 JSObject::SetNormalizedProperty(object, &lookup, value);
2473 }
2474 } else {
2475 // We should not reach here. Any real, named property should be
2476 // either a field or a dictionary slot.
2477 UNREACHABLE();
2478 }
2479 } else {
2480 // The property was found on some other object. Set it if it is not a
2481 // read-only property.
2482 if ((attributes & READ_ONLY) == 0) {
2483 // Strict mode not needed (const disallowed in strict mode).
2484 RETURN_IF_EMPTY_HANDLE(
2485 isolate,
2486 JSReceiver::SetProperty(object, name, value, attributes,
2487 kNonStrictMode));
2488 }
2489 }
2490
2491 return *value;
2492 }
2493
2494
RUNTIME_FUNCTION(MaybeObject *,Runtime_OptimizeObjectForAddingMultipleProperties)2495 RUNTIME_FUNCTION(MaybeObject*,
2496 Runtime_OptimizeObjectForAddingMultipleProperties) {
2497 HandleScope scope(isolate);
2498 ASSERT(args.length() == 2);
2499 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2500 CONVERT_SMI_ARG_CHECKED(properties, 1);
2501 if (object->HasFastProperties()) {
2502 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
2503 }
2504 return *object;
2505 }
2506
2507
RUNTIME_FUNCTION(MaybeObject *,Runtime_RegExpExec)2508 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
2509 HandleScope scope(isolate);
2510 ASSERT(args.length() == 4);
2511 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2512 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
2513 // Due to the way the JS calls are constructed this must be less than the
2514 // length of a string, i.e. it is always a Smi. We check anyway for security.
2515 CONVERT_SMI_ARG_CHECKED(index, 2);
2516 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
2517 RUNTIME_ASSERT(index >= 0);
2518 RUNTIME_ASSERT(index <= subject->length());
2519 isolate->counters()->regexp_entry_runtime()->Increment();
2520 Handle<Object> result = RegExpImpl::Exec(regexp,
2521 subject,
2522 index,
2523 last_match_info);
2524 RETURN_IF_EMPTY_HANDLE(isolate, result);
2525 return *result;
2526 }
2527
2528
RUNTIME_FUNCTION(MaybeObject *,Runtime_RegExpConstructResult)2529 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
2530 SealHandleScope shs(isolate);
2531 ASSERT(args.length() == 3);
2532 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
2533 if (elements_count < 0 ||
2534 elements_count > FixedArray::kMaxLength ||
2535 !Smi::IsValid(elements_count)) {
2536 return isolate->ThrowIllegalOperation();
2537 }
2538 Object* new_object;
2539 { MaybeObject* maybe_new_object =
2540 isolate->heap()->AllocateFixedArray(elements_count);
2541 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2542 }
2543 FixedArray* elements = FixedArray::cast(new_object);
2544 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
2545 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
2546 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2547 }
2548 {
2549 DisallowHeapAllocation no_gc;
2550 HandleScope scope(isolate);
2551 reinterpret_cast<HeapObject*>(new_object)->
2552 set_map(isolate->native_context()->regexp_result_map());
2553 }
2554 JSArray* array = JSArray::cast(new_object);
2555 array->set_properties(isolate->heap()->empty_fixed_array());
2556 array->set_elements(elements);
2557 array->set_length(Smi::FromInt(elements_count));
2558 // Write in-object properties after the length of the array.
2559 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
2560 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
2561 return array;
2562 }
2563
2564
RUNTIME_FUNCTION(MaybeObject *,Runtime_RegExpInitializeObject)2565 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
2566 HandleScope scope(isolate);
2567 DisallowHeapAllocation no_allocation;
2568 ASSERT(args.length() == 5);
2569 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2570 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2571 // If source is the empty string we set it to "(?:)" instead as
2572 // suggested by ECMA-262, 5th, section 15.10.4.1.
2573 if (source->length() == 0) source = isolate->factory()->query_colon_string();
2574
2575 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2576 if (!global->IsTrue()) global = isolate->factory()->false_value();
2577
2578 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2579 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
2580
2581 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2582 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
2583
2584 Map* map = regexp->map();
2585 Object* constructor = map->constructor();
2586 if (constructor->IsJSFunction() &&
2587 JSFunction::cast(constructor)->initial_map() == map) {
2588 // If we still have the original map, set in-object properties directly.
2589 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
2590 // Both true and false are immovable immortal objects so no need for write
2591 // barrier.
2592 regexp->InObjectPropertyAtPut(
2593 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
2594 regexp->InObjectPropertyAtPut(
2595 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
2596 regexp->InObjectPropertyAtPut(
2597 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
2598 regexp->InObjectPropertyAtPut(
2599 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
2600 return *regexp;
2601 }
2602
2603 // Map has changed, so use generic, but slower, method.
2604 PropertyAttributes final =
2605 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2606 PropertyAttributes writable =
2607 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
2608 Handle<Object> zero(Smi::FromInt(0), isolate);
2609 Factory* factory = isolate->factory();
2610 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2611 regexp, factory->source_string(), source, final));
2612 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2613 regexp, factory->global_string(), global, final));
2614 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2615 regexp, factory->ignore_case_string(), ignoreCase, final));
2616 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2617 regexp, factory->multiline_string(), multiline, final));
2618 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2619 regexp, factory->last_index_string(), zero, writable));
2620 return *regexp;
2621 }
2622
2623
RUNTIME_FUNCTION(MaybeObject *,Runtime_FinishArrayPrototypeSetup)2624 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
2625 HandleScope scope(isolate);
2626 ASSERT(args.length() == 1);
2627 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
2628 // This is necessary to enable fast checks for absence of elements
2629 // on Array.prototype and below.
2630 prototype->set_elements(isolate->heap()->empty_fixed_array());
2631 return Smi::FromInt(0);
2632 }
2633
2634
InstallBuiltin(Isolate * isolate,Handle<JSObject> holder,const char * name,Builtins::Name builtin_name)2635 static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
2636 Handle<JSObject> holder,
2637 const char* name,
2638 Builtins::Name builtin_name) {
2639 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
2640 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2641 Handle<JSFunction> optimized =
2642 isolate->factory()->NewFunction(key,
2643 JS_OBJECT_TYPE,
2644 JSObject::kHeaderSize,
2645 code,
2646 false);
2647 optimized->shared()->DontAdaptArguments();
2648 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
2649 return optimized;
2650 }
2651
2652
RUNTIME_FUNCTION(MaybeObject *,Runtime_SpecialArrayFunctions)2653 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
2654 HandleScope scope(isolate);
2655 ASSERT(args.length() == 1);
2656 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
2657
2658 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2659 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2660 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2661 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2662 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2663 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2664 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
2665
2666 return *holder;
2667 }
2668
2669
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsCallable)2670 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsCallable) {
2671 SealHandleScope shs(isolate);
2672 ASSERT(args.length() == 1);
2673 CONVERT_ARG_CHECKED(Object, obj, 0);
2674 return isolate->heap()->ToBoolean(obj->IsCallable());
2675 }
2676
2677
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsClassicModeFunction)2678 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) {
2679 SealHandleScope shs(isolate);
2680 ASSERT(args.length() == 1);
2681 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2682 if (!callable->IsJSFunction()) {
2683 HandleScope scope(isolate);
2684 bool threw = false;
2685 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2686 isolate, Handle<JSReceiver>(callable), &threw);
2687 if (threw) return Failure::Exception();
2688 callable = JSFunction::cast(*delegate);
2689 }
2690 JSFunction* function = JSFunction::cast(callable);
2691 SharedFunctionInfo* shared = function->shared();
2692 return isolate->heap()->ToBoolean(shared->is_classic_mode());
2693 }
2694
2695
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetDefaultReceiver)2696 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
2697 SealHandleScope shs(isolate);
2698 ASSERT(args.length() == 1);
2699 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2700
2701 if (!callable->IsJSFunction()) {
2702 HandleScope scope(isolate);
2703 bool threw = false;
2704 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2705 isolate, Handle<JSReceiver>(callable), &threw);
2706 if (threw) return Failure::Exception();
2707 callable = JSFunction::cast(*delegate);
2708 }
2709 JSFunction* function = JSFunction::cast(callable);
2710
2711 SharedFunctionInfo* shared = function->shared();
2712 if (shared->native() || !shared->is_classic_mode()) {
2713 return isolate->heap()->undefined_value();
2714 }
2715 // Returns undefined for strict or native functions, or
2716 // the associated global receiver for "normal" functions.
2717
2718 Context* native_context =
2719 function->context()->global_object()->native_context();
2720 return native_context->global_object()->global_receiver();
2721 }
2722
2723
RUNTIME_FUNCTION(MaybeObject *,Runtime_MaterializeRegExpLiteral)2724 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
2725 HandleScope scope(isolate);
2726 ASSERT(args.length() == 4);
2727 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
2728 int index = args.smi_at(1);
2729 Handle<String> pattern = args.at<String>(2);
2730 Handle<String> flags = args.at<String>(3);
2731
2732 // Get the RegExp function from the context in the literals array.
2733 // This is the RegExp function from the context in which the
2734 // function was created. We do not use the RegExp function from the
2735 // current native context because this might be the RegExp function
2736 // from another context which we should not have access to.
2737 Handle<JSFunction> constructor =
2738 Handle<JSFunction>(
2739 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
2740 // Compute the regular expression literal.
2741 bool has_pending_exception;
2742 Handle<Object> regexp =
2743 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
2744 &has_pending_exception);
2745 if (has_pending_exception) {
2746 ASSERT(isolate->has_pending_exception());
2747 return Failure::Exception();
2748 }
2749 literals->set(index, *regexp);
2750 return *regexp;
2751 }
2752
2753
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetName)2754 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
2755 SealHandleScope shs(isolate);
2756 ASSERT(args.length() == 1);
2757
2758 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2759 return f->shared()->name();
2760 }
2761
2762
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionSetName)2763 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
2764 SealHandleScope shs(isolate);
2765 ASSERT(args.length() == 2);
2766
2767 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2768 CONVERT_ARG_CHECKED(String, name, 1);
2769 f->shared()->set_name(name);
2770 return isolate->heap()->undefined_value();
2771 }
2772
2773
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionNameShouldPrintAsAnonymous)2774 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
2775 SealHandleScope shs(isolate);
2776 ASSERT(args.length() == 1);
2777 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2778 return isolate->heap()->ToBoolean(
2779 f->shared()->name_should_print_as_anonymous());
2780 }
2781
2782
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionMarkNameShouldPrintAsAnonymous)2783 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2784 SealHandleScope shs(isolate);
2785 ASSERT(args.length() == 1);
2786 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2787 f->shared()->set_name_should_print_as_anonymous(true);
2788 return isolate->heap()->undefined_value();
2789 }
2790
2791
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionIsGenerator)2792 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) {
2793 SealHandleScope shs(isolate);
2794 ASSERT(args.length() == 1);
2795 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2796 return isolate->heap()->ToBoolean(f->shared()->is_generator());
2797 }
2798
2799
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionRemovePrototype)2800 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
2801 SealHandleScope shs(isolate);
2802 ASSERT(args.length() == 1);
2803
2804 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2805 f->RemovePrototype();
2806
2807 return isolate->heap()->undefined_value();
2808 }
2809
2810
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetScript)2811 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
2812 HandleScope scope(isolate);
2813 ASSERT(args.length() == 1);
2814
2815 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2816 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2817 if (!script->IsScript()) return isolate->heap()->undefined_value();
2818
2819 return *GetScriptWrapper(Handle<Script>::cast(script));
2820 }
2821
2822
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetSourceCode)2823 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
2824 HandleScope scope(isolate);
2825 ASSERT(args.length() == 1);
2826
2827 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2828 Handle<SharedFunctionInfo> shared(f->shared());
2829 return *shared->GetSourceCode();
2830 }
2831
2832
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetScriptSourcePosition)2833 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
2834 SealHandleScope shs(isolate);
2835 ASSERT(args.length() == 1);
2836
2837 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2838 int pos = fun->shared()->start_position();
2839 return Smi::FromInt(pos);
2840 }
2841
2842
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetPositionForOffset)2843 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
2844 SealHandleScope shs(isolate);
2845 ASSERT(args.length() == 2);
2846
2847 CONVERT_ARG_CHECKED(Code, code, 0);
2848 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2849
2850 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2851
2852 Address pc = code->address() + offset;
2853 return Smi::FromInt(code->SourcePosition(pc));
2854 }
2855
2856
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionSetInstanceClassName)2857 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
2858 SealHandleScope shs(isolate);
2859 ASSERT(args.length() == 2);
2860
2861 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2862 CONVERT_ARG_CHECKED(String, name, 1);
2863 fun->SetInstanceClassName(name);
2864 return isolate->heap()->undefined_value();
2865 }
2866
2867
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionSetLength)2868 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
2869 SealHandleScope shs(isolate);
2870 ASSERT(args.length() == 2);
2871
2872 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2873 CONVERT_SMI_ARG_CHECKED(length, 1);
2874 fun->shared()->set_length(length);
2875 return isolate->heap()->undefined_value();
2876 }
2877
2878
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionSetPrototype)2879 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
2880 HandleScope scope(isolate);
2881 ASSERT(args.length() == 2);
2882
2883 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2884 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
2885 ASSERT(fun->should_have_prototype());
2886 Accessors::FunctionSetPrototype(fun, value);
2887 return args[0]; // return TOS
2888 }
2889
2890
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionSetReadOnlyPrototype)2891 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2892 SealHandleScope shs(isolate);
2893 RUNTIME_ASSERT(args.length() == 1);
2894 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2895
2896 String* name = isolate->heap()->prototype_string();
2897
2898 if (function->HasFastProperties()) {
2899 // Construct a new field descriptor with updated attributes.
2900 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2901
2902 int index = instance_desc->SearchWithCache(name, function->map());
2903 ASSERT(index != DescriptorArray::kNotFound);
2904 PropertyDetails details = instance_desc->GetDetails(index);
2905
2906 CallbacksDescriptor new_desc(name,
2907 instance_desc->GetValue(index),
2908 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY));
2909
2910 // Create a new map featuring the new field descriptors array.
2911 Map* new_map;
2912 MaybeObject* maybe_map =
2913 function->map()->CopyReplaceDescriptor(
2914 instance_desc, &new_desc, index, OMIT_TRANSITION);
2915 if (!maybe_map->To(&new_map)) return maybe_map;
2916
2917 function->set_map(new_map);
2918 } else { // Dictionary properties.
2919 // Directly manipulate the property details.
2920 int entry = function->property_dictionary()->FindEntry(name);
2921 ASSERT(entry != NameDictionary::kNotFound);
2922 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2923 PropertyDetails new_details(
2924 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2925 details.type(),
2926 details.dictionary_index());
2927 function->property_dictionary()->DetailsAtPut(entry, new_details);
2928 }
2929 return function;
2930 }
2931
2932
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionIsAPIFunction)2933 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
2934 SealHandleScope shs(isolate);
2935 ASSERT(args.length() == 1);
2936
2937 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2938 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
2939 }
2940
2941
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionIsBuiltin)2942 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
2943 SealHandleScope shs(isolate);
2944 ASSERT(args.length() == 1);
2945
2946 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2947 return isolate->heap()->ToBoolean(f->IsBuiltin());
2948 }
2949
2950
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetCode)2951 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
2952 HandleScope scope(isolate);
2953 ASSERT(args.length() == 2);
2954
2955 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
2956 Handle<Object> code = args.at<Object>(1);
2957
2958 if (code->IsNull()) return *target;
2959 RUNTIME_ASSERT(code->IsJSFunction());
2960 Handle<JSFunction> source = Handle<JSFunction>::cast(code);
2961 Handle<SharedFunctionInfo> target_shared(target->shared());
2962 Handle<SharedFunctionInfo> source_shared(source->shared());
2963
2964 if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) {
2965 return Failure::Exception();
2966 }
2967
2968 // Mark both, the source and the target, as un-flushable because the
2969 // shared unoptimized code makes them impossible to enqueue in a list.
2970 ASSERT(target_shared->code()->gc_metadata() == NULL);
2971 ASSERT(source_shared->code()->gc_metadata() == NULL);
2972 target_shared->set_dont_flush(true);
2973 source_shared->set_dont_flush(true);
2974
2975 // Set the code, scope info, formal parameter count, and the length
2976 // of the target shared function info.
2977 target_shared->ReplaceCode(source_shared->code());
2978 target_shared->set_scope_info(source_shared->scope_info());
2979 target_shared->set_length(source_shared->length());
2980 target_shared->set_formal_parameter_count(
2981 source_shared->formal_parameter_count());
2982 target_shared->set_script(source_shared->script());
2983 target_shared->set_start_position_and_type(
2984 source_shared->start_position_and_type());
2985 target_shared->set_end_position(source_shared->end_position());
2986 bool was_native = target_shared->native();
2987 target_shared->set_compiler_hints(source_shared->compiler_hints());
2988 target_shared->set_native(was_native);
2989
2990 // Set the code of the target function.
2991 target->ReplaceCode(source_shared->code());
2992 ASSERT(target->next_function_link()->IsUndefined());
2993
2994 // Make sure we get a fresh copy of the literal vector to avoid cross
2995 // context contamination.
2996 Handle<Context> context(source->context());
2997 int number_of_literals = source->NumberOfLiterals();
2998 Handle<FixedArray> literals =
2999 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
3000 if (number_of_literals > 0) {
3001 literals->set(JSFunction::kLiteralNativeContextIndex,
3002 context->native_context());
3003 }
3004 target->set_context(*context);
3005 target->set_literals(*literals);
3006
3007 if (isolate->logger()->is_logging_code_events() ||
3008 isolate->cpu_profiler()->is_profiling()) {
3009 isolate->logger()->LogExistingFunction(
3010 source_shared, Handle<Code>(source_shared->code()));
3011 }
3012
3013 return *target;
3014 }
3015
3016
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetExpectedNumberOfProperties)3017 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
3018 HandleScope scope(isolate);
3019 ASSERT(args.length() == 2);
3020 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
3021 CONVERT_SMI_ARG_CHECKED(num, 1);
3022 RUNTIME_ASSERT(num >= 0);
3023 // If objects constructed from this function exist then changing
3024 // 'estimated_nof_properties' is dangerous since the previous value might
3025 // have been compiled into the fast construct stub. Moreover, the inobject
3026 // slack tracking logic might have adjusted the previous value, so even
3027 // passing the same value is risky.
3028 if (!func->shared()->live_objects_may_exist()) {
3029 func->shared()->set_expected_nof_properties(num);
3030 if (func->has_initial_map()) {
3031 Handle<Map> new_initial_map =
3032 func->GetIsolate()->factory()->CopyMap(
3033 Handle<Map>(func->initial_map()));
3034 new_initial_map->set_unused_property_fields(num);
3035 func->set_initial_map(*new_initial_map);
3036 }
3037 }
3038 return isolate->heap()->undefined_value();
3039 }
3040
3041
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateJSGeneratorObject)3042 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) {
3043 HandleScope scope(isolate);
3044 ASSERT(args.length() == 0);
3045
3046 JavaScriptFrameIterator it(isolate);
3047 JavaScriptFrame* frame = it.frame();
3048 Handle<JSFunction> function(frame->function());
3049 RUNTIME_ASSERT(function->shared()->is_generator());
3050
3051 Handle<JSGeneratorObject> generator;
3052 if (frame->IsConstructor()) {
3053 generator = handle(JSGeneratorObject::cast(frame->receiver()));
3054 } else {
3055 generator = isolate->factory()->NewJSGeneratorObject(function);
3056 }
3057 generator->set_function(*function);
3058 generator->set_context(Context::cast(frame->context()));
3059 generator->set_receiver(frame->receiver());
3060 generator->set_continuation(0);
3061 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
3062 generator->set_stack_handler_index(-1);
3063
3064 return *generator;
3065 }
3066
3067
RUNTIME_FUNCTION(MaybeObject *,Runtime_SuspendJSGeneratorObject)3068 RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) {
3069 SealHandleScope shs(isolate);
3070 ASSERT(args.length() == 1);
3071 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3072
3073 JavaScriptFrameIterator stack_iterator(isolate);
3074 JavaScriptFrame* frame = stack_iterator.frame();
3075 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3076 ASSERT_EQ(frame->function(), generator_object->function());
3077
3078 // The caller should have saved the context and continuation already.
3079 ASSERT_EQ(generator_object->context(), Context::cast(frame->context()));
3080 ASSERT_LT(0, generator_object->continuation());
3081
3082 // We expect there to be at least two values on the operand stack: the return
3083 // value of the yield expression, and the argument to this runtime call.
3084 // Neither of those should be saved.
3085 int operands_count = frame->ComputeOperandsCount();
3086 ASSERT_GE(operands_count, 2);
3087 operands_count -= 2;
3088
3089 if (operands_count == 0) {
3090 // Although it's semantically harmless to call this function with an
3091 // operands_count of zero, it is also unnecessary.
3092 ASSERT_EQ(generator_object->operand_stack(),
3093 isolate->heap()->empty_fixed_array());
3094 ASSERT_EQ(generator_object->stack_handler_index(), -1);
3095 // If there are no operands on the stack, there shouldn't be a handler
3096 // active either.
3097 ASSERT(!frame->HasHandler());
3098 } else {
3099 int stack_handler_index = -1;
3100 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count);
3101 FixedArray* operand_stack;
3102 if (!alloc->To(&operand_stack)) return alloc;
3103 frame->SaveOperandStack(operand_stack, &stack_handler_index);
3104 generator_object->set_operand_stack(operand_stack);
3105 generator_object->set_stack_handler_index(stack_handler_index);
3106 }
3107
3108 return isolate->heap()->undefined_value();
3109 }
3110
3111
3112 // Note that this function is the slow path for resuming generators. It is only
3113 // called if the suspended activation had operands on the stack, stack handlers
3114 // needing rewinding, or if the resume should throw an exception. The fast path
3115 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
3116 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
3117 // called in any case, as it needs to reconstruct the stack frame and make space
3118 // for arguments and operands.
RUNTIME_FUNCTION(MaybeObject *,Runtime_ResumeJSGeneratorObject)3119 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) {
3120 SealHandleScope shs(isolate);
3121 ASSERT(args.length() == 3);
3122 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3123 CONVERT_ARG_CHECKED(Object, value, 1);
3124 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3125 JavaScriptFrameIterator stack_iterator(isolate);
3126 JavaScriptFrame* frame = stack_iterator.frame();
3127
3128 ASSERT_EQ(frame->function(), generator_object->function());
3129 ASSERT(frame->function()->is_compiled());
3130
3131 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0);
3132 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0);
3133
3134 Address pc = generator_object->function()->code()->instruction_start();
3135 int offset = generator_object->continuation();
3136 ASSERT(offset > 0);
3137 frame->set_pc(pc + offset);
3138 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3139
3140 FixedArray* operand_stack = generator_object->operand_stack();
3141 int operands_count = operand_stack->length();
3142 if (operands_count != 0) {
3143 frame->RestoreOperandStack(operand_stack,
3144 generator_object->stack_handler_index());
3145 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
3146 generator_object->set_stack_handler_index(-1);
3147 }
3148
3149 JSGeneratorObject::ResumeMode resume_mode =
3150 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3151 switch (resume_mode) {
3152 case JSGeneratorObject::NEXT:
3153 return value;
3154 case JSGeneratorObject::THROW:
3155 return isolate->Throw(value);
3156 }
3157
3158 UNREACHABLE();
3159 return isolate->ThrowIllegalOperation();
3160 }
3161
3162
RUNTIME_FUNCTION(MaybeObject *,Runtime_ThrowGeneratorStateError)3163 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) {
3164 HandleScope scope(isolate);
3165 ASSERT(args.length() == 1);
3166 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3167 int continuation = generator->continuation();
3168 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
3169 "generator_finished" : "generator_running";
3170 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3171 Handle<Object> error = isolate->factory()->NewError(message, argv);
3172 return isolate->Throw(*error);
3173 }
3174
3175
RUNTIME_FUNCTION(MaybeObject *,Runtime_ObjectFreeze)3176 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
3177 HandleScope scope(isolate);
3178 ASSERT(args.length() == 1);
3179 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3180 Handle<Object> result = JSObject::Freeze(object);
3181 RETURN_IF_EMPTY_HANDLE(isolate, result);
3182 return *result;
3183 }
3184
3185
CharFromCode(Isolate * isolate,Object * char_code)3186 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
3187 Object* char_code) {
3188 if (char_code->IsNumber()) {
3189 return isolate->heap()->LookupSingleCharacterStringFromCode(
3190 NumberToUint32(char_code) & 0xffff);
3191 }
3192 return isolate->heap()->empty_string();
3193 }
3194
3195
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringCharCodeAt)3196 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
3197 SealHandleScope shs(isolate);
3198 ASSERT(args.length() == 2);
3199
3200 CONVERT_ARG_CHECKED(String, subject, 0);
3201 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
3202
3203 // Flatten the string. If someone wants to get a char at an index
3204 // in a cons string, it is likely that more indices will be
3205 // accessed.
3206 Object* flat;
3207 { MaybeObject* maybe_flat = subject->TryFlatten();
3208 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
3209 }
3210 subject = String::cast(flat);
3211
3212 if (i >= static_cast<uint32_t>(subject->length())) {
3213 return isolate->heap()->nan_value();
3214 }
3215
3216 return Smi::FromInt(subject->Get(i));
3217 }
3218
3219
RUNTIME_FUNCTION(MaybeObject *,Runtime_CharFromCode)3220 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
3221 SealHandleScope shs(isolate);
3222 ASSERT(args.length() == 1);
3223 return CharFromCode(isolate, args[0]);
3224 }
3225
3226
3227 class FixedArrayBuilder {
3228 public:
FixedArrayBuilder(Isolate * isolate,int initial_capacity)3229 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3230 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
3231 length_(0),
3232 has_non_smi_elements_(false) {
3233 // Require a non-zero initial size. Ensures that doubling the size to
3234 // extend the array will work.
3235 ASSERT(initial_capacity > 0);
3236 }
3237
FixedArrayBuilder(Handle<FixedArray> backing_store)3238 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3239 : array_(backing_store),
3240 length_(0),
3241 has_non_smi_elements_(false) {
3242 // Require a non-zero initial size. Ensures that doubling the size to
3243 // extend the array will work.
3244 ASSERT(backing_store->length() > 0);
3245 }
3246
HasCapacity(int elements)3247 bool HasCapacity(int elements) {
3248 int length = array_->length();
3249 int required_length = length_ + elements;
3250 return (length >= required_length);
3251 }
3252
EnsureCapacity(int elements)3253 void EnsureCapacity(int elements) {
3254 int length = array_->length();
3255 int required_length = length_ + elements;
3256 if (length < required_length) {
3257 int new_length = length;
3258 do {
3259 new_length *= 2;
3260 } while (new_length < required_length);
3261 Handle<FixedArray> extended_array =
3262 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
3263 array_->CopyTo(0, *extended_array, 0, length_);
3264 array_ = extended_array;
3265 }
3266 }
3267
Add(Object * value)3268 void Add(Object* value) {
3269 ASSERT(!value->IsSmi());
3270 ASSERT(length_ < capacity());
3271 array_->set(length_, value);
3272 length_++;
3273 has_non_smi_elements_ = true;
3274 }
3275
Add(Smi * value)3276 void Add(Smi* value) {
3277 ASSERT(value->IsSmi());
3278 ASSERT(length_ < capacity());
3279 array_->set(length_, value);
3280 length_++;
3281 }
3282
array()3283 Handle<FixedArray> array() {
3284 return array_;
3285 }
3286
length()3287 int length() {
3288 return length_;
3289 }
3290
capacity()3291 int capacity() {
3292 return array_->length();
3293 }
3294
ToJSArray(Handle<JSArray> target_array)3295 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
3296 Factory* factory = target_array->GetIsolate()->factory();
3297 factory->SetContent(target_array, array_);
3298 target_array->set_length(Smi::FromInt(length_));
3299 return target_array;
3300 }
3301
3302
3303 private:
3304 Handle<FixedArray> array_;
3305 int length_;
3306 bool has_non_smi_elements_;
3307 };
3308
3309
3310 // Forward declarations.
3311 const int kStringBuilderConcatHelperLengthBits = 11;
3312 const int kStringBuilderConcatHelperPositionBits = 19;
3313
3314 template <typename schar>
3315 static inline void StringBuilderConcatHelper(String*,
3316 schar*,
3317 FixedArray*,
3318 int);
3319
3320 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3321 StringBuilderSubstringLength;
3322 typedef BitField<int,
3323 kStringBuilderConcatHelperLengthBits,
3324 kStringBuilderConcatHelperPositionBits>
3325 StringBuilderSubstringPosition;
3326
3327
3328 class ReplacementStringBuilder {
3329 public:
ReplacementStringBuilder(Heap * heap,Handle<String> subject,int estimated_part_count)3330 ReplacementStringBuilder(Heap* heap,
3331 Handle<String> subject,
3332 int estimated_part_count)
3333 : heap_(heap),
3334 array_builder_(heap->isolate(), estimated_part_count),
3335 subject_(subject),
3336 character_count_(0),
3337 is_ascii_(subject->IsOneByteRepresentation()) {
3338 // Require a non-zero initial size. Ensures that doubling the size to
3339 // extend the array will work.
3340 ASSERT(estimated_part_count > 0);
3341 }
3342
AddSubjectSlice(FixedArrayBuilder * builder,int from,int to)3343 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3344 int from,
3345 int to) {
3346 ASSERT(from >= 0);
3347 int length = to - from;
3348 ASSERT(length > 0);
3349 if (StringBuilderSubstringLength::is_valid(length) &&
3350 StringBuilderSubstringPosition::is_valid(from)) {
3351 int encoded_slice = StringBuilderSubstringLength::encode(length) |
3352 StringBuilderSubstringPosition::encode(from);
3353 builder->Add(Smi::FromInt(encoded_slice));
3354 } else {
3355 // Otherwise encode as two smis.
3356 builder->Add(Smi::FromInt(-length));
3357 builder->Add(Smi::FromInt(from));
3358 }
3359 }
3360
3361
EnsureCapacity(int elements)3362 void EnsureCapacity(int elements) {
3363 array_builder_.EnsureCapacity(elements);
3364 }
3365
3366
AddSubjectSlice(int from,int to)3367 void AddSubjectSlice(int from, int to) {
3368 AddSubjectSlice(&array_builder_, from, to);
3369 IncrementCharacterCount(to - from);
3370 }
3371
3372
AddString(Handle<String> string)3373 void AddString(Handle<String> string) {
3374 int length = string->length();
3375 ASSERT(length > 0);
3376 AddElement(*string);
3377 if (!string->IsOneByteRepresentation()) {
3378 is_ascii_ = false;
3379 }
3380 IncrementCharacterCount(length);
3381 }
3382
3383
ToString()3384 Handle<String> ToString() {
3385 if (array_builder_.length() == 0) {
3386 return heap_->isolate()->factory()->empty_string();
3387 }
3388
3389 Handle<String> joined_string;
3390 if (is_ascii_) {
3391 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
3392 DisallowHeapAllocation no_gc;
3393 uint8_t* char_buffer = seq->GetChars();
3394 StringBuilderConcatHelper(*subject_,
3395 char_buffer,
3396 *array_builder_.array(),
3397 array_builder_.length());
3398 joined_string = Handle<String>::cast(seq);
3399 } else {
3400 // Non-ASCII.
3401 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
3402 DisallowHeapAllocation no_gc;
3403 uc16* char_buffer = seq->GetChars();
3404 StringBuilderConcatHelper(*subject_,
3405 char_buffer,
3406 *array_builder_.array(),
3407 array_builder_.length());
3408 joined_string = Handle<String>::cast(seq);
3409 }
3410 return joined_string;
3411 }
3412
3413
IncrementCharacterCount(int by)3414 void IncrementCharacterCount(int by) {
3415 if (character_count_ > String::kMaxLength - by) {
3416 V8::FatalProcessOutOfMemory("String.replace result too large.");
3417 }
3418 character_count_ += by;
3419 }
3420
3421 private:
NewRawOneByteString(int length)3422 Handle<SeqOneByteString> NewRawOneByteString(int length) {
3423 return heap_->isolate()->factory()->NewRawOneByteString(length);
3424 }
3425
3426
NewRawTwoByteString(int length)3427 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
3428 return heap_->isolate()->factory()->NewRawTwoByteString(length);
3429 }
3430
3431
AddElement(Object * element)3432 void AddElement(Object* element) {
3433 ASSERT(element->IsSmi() || element->IsString());
3434 ASSERT(array_builder_.capacity() > array_builder_.length());
3435 array_builder_.Add(element);
3436 }
3437
3438 Heap* heap_;
3439 FixedArrayBuilder array_builder_;
3440 Handle<String> subject_;
3441 int character_count_;
3442 bool is_ascii_;
3443 };
3444
3445
3446 class CompiledReplacement {
3447 public:
CompiledReplacement(Zone * zone)3448 explicit CompiledReplacement(Zone* zone)
3449 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
3450
3451 // Return whether the replacement is simple.
3452 bool Compile(Handle<String> replacement,
3453 int capture_count,
3454 int subject_length);
3455
3456 // Use Apply only if Compile returned false.
3457 void Apply(ReplacementStringBuilder* builder,
3458 int match_from,
3459 int match_to,
3460 int32_t* match);
3461
3462 // Number of distinct parts of the replacement pattern.
parts()3463 int parts() {
3464 return parts_.length();
3465 }
3466
zone() const3467 Zone* zone() const { return zone_; }
3468
3469 private:
3470 enum PartType {
3471 SUBJECT_PREFIX = 1,
3472 SUBJECT_SUFFIX,
3473 SUBJECT_CAPTURE,
3474 REPLACEMENT_SUBSTRING,
3475 REPLACEMENT_STRING,
3476
3477 NUMBER_OF_PART_TYPES
3478 };
3479
3480 struct ReplacementPart {
SubjectMatchv8::internal::CompiledReplacement::ReplacementPart3481 static inline ReplacementPart SubjectMatch() {
3482 return ReplacementPart(SUBJECT_CAPTURE, 0);
3483 }
SubjectCapturev8::internal::CompiledReplacement::ReplacementPart3484 static inline ReplacementPart SubjectCapture(int capture_index) {
3485 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3486 }
SubjectPrefixv8::internal::CompiledReplacement::ReplacementPart3487 static inline ReplacementPart SubjectPrefix() {
3488 return ReplacementPart(SUBJECT_PREFIX, 0);
3489 }
SubjectSuffixv8::internal::CompiledReplacement::ReplacementPart3490 static inline ReplacementPart SubjectSuffix(int subject_length) {
3491 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3492 }
ReplacementStringv8::internal::CompiledReplacement::ReplacementPart3493 static inline ReplacementPart ReplacementString() {
3494 return ReplacementPart(REPLACEMENT_STRING, 0);
3495 }
ReplacementSubStringv8::internal::CompiledReplacement::ReplacementPart3496 static inline ReplacementPart ReplacementSubString(int from, int to) {
3497 ASSERT(from >= 0);
3498 ASSERT(to > from);
3499 return ReplacementPart(-from, to);
3500 }
3501
3502 // If tag <= 0 then it is the negation of a start index of a substring of
3503 // the replacement pattern, otherwise it's a value from PartType.
ReplacementPartv8::internal::CompiledReplacement::ReplacementPart3504 ReplacementPart(int tag, int data)
3505 : tag(tag), data(data) {
3506 // Must be non-positive or a PartType value.
3507 ASSERT(tag < NUMBER_OF_PART_TYPES);
3508 }
3509 // Either a value of PartType or a non-positive number that is
3510 // the negation of an index into the replacement string.
3511 int tag;
3512 // The data value's interpretation depends on the value of tag:
3513 // tag == SUBJECT_PREFIX ||
3514 // tag == SUBJECT_SUFFIX: data is unused.
3515 // tag == SUBJECT_CAPTURE: data is the number of the capture.
3516 // tag == REPLACEMENT_SUBSTRING ||
3517 // tag == REPLACEMENT_STRING: data is index into array of substrings
3518 // of the replacement string.
3519 // tag <= 0: Temporary representation of the substring of the replacement
3520 // string ranging over -tag .. data.
3521 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3522 // substring objects.
3523 int data;
3524 };
3525
3526 template<typename Char>
ParseReplacementPattern(ZoneList<ReplacementPart> * parts,Vector<Char> characters,int capture_count,int subject_length,Zone * zone)3527 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3528 Vector<Char> characters,
3529 int capture_count,
3530 int subject_length,
3531 Zone* zone) {
3532 int length = characters.length();
3533 int last = 0;
3534 for (int i = 0; i < length; i++) {
3535 Char c = characters[i];
3536 if (c == '$') {
3537 int next_index = i + 1;
3538 if (next_index == length) { // No next character!
3539 break;
3540 }
3541 Char c2 = characters[next_index];
3542 switch (c2) {
3543 case '$':
3544 if (i > last) {
3545 // There is a substring before. Include the first "$".
3546 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3547 zone);
3548 last = next_index + 1; // Continue after the second "$".
3549 } else {
3550 // Let the next substring start with the second "$".
3551 last = next_index;
3552 }
3553 i = next_index;
3554 break;
3555 case '`':
3556 if (i > last) {
3557 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3558 }
3559 parts->Add(ReplacementPart::SubjectPrefix(), zone);
3560 i = next_index;
3561 last = i + 1;
3562 break;
3563 case '\'':
3564 if (i > last) {
3565 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3566 }
3567 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
3568 i = next_index;
3569 last = i + 1;
3570 break;
3571 case '&':
3572 if (i > last) {
3573 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3574 }
3575 parts->Add(ReplacementPart::SubjectMatch(), zone);
3576 i = next_index;
3577 last = i + 1;
3578 break;
3579 case '0':
3580 case '1':
3581 case '2':
3582 case '3':
3583 case '4':
3584 case '5':
3585 case '6':
3586 case '7':
3587 case '8':
3588 case '9': {
3589 int capture_ref = c2 - '0';
3590 if (capture_ref > capture_count) {
3591 i = next_index;
3592 continue;
3593 }
3594 int second_digit_index = next_index + 1;
3595 if (second_digit_index < length) {
3596 // Peek ahead to see if we have two digits.
3597 Char c3 = characters[second_digit_index];
3598 if ('0' <= c3 && c3 <= '9') { // Double digits.
3599 int double_digit_ref = capture_ref * 10 + c3 - '0';
3600 if (double_digit_ref <= capture_count) {
3601 next_index = second_digit_index;
3602 capture_ref = double_digit_ref;
3603 }
3604 }
3605 }
3606 if (capture_ref > 0) {
3607 if (i > last) {
3608 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3609 }
3610 ASSERT(capture_ref <= capture_count);
3611 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
3612 last = next_index + 1;
3613 }
3614 i = next_index;
3615 break;
3616 }
3617 default:
3618 i = next_index;
3619 break;
3620 }
3621 }
3622 }
3623 if (length > last) {
3624 if (last == 0) {
3625 // Replacement is simple. Do not use Apply to do the replacement.
3626 return true;
3627 } else {
3628 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
3629 }
3630 }
3631 return false;
3632 }
3633
3634 ZoneList<ReplacementPart> parts_;
3635 ZoneList<Handle<String> > replacement_substrings_;
3636 Zone* zone_;
3637 };
3638
3639
Compile(Handle<String> replacement,int capture_count,int subject_length)3640 bool CompiledReplacement::Compile(Handle<String> replacement,
3641 int capture_count,
3642 int subject_length) {
3643 {
3644 DisallowHeapAllocation no_gc;
3645 String::FlatContent content = replacement->GetFlatContent();
3646 ASSERT(content.IsFlat());
3647 bool simple = false;
3648 if (content.IsAscii()) {
3649 simple = ParseReplacementPattern(&parts_,
3650 content.ToOneByteVector(),
3651 capture_count,
3652 subject_length,
3653 zone());
3654 } else {
3655 ASSERT(content.IsTwoByte());
3656 simple = ParseReplacementPattern(&parts_,
3657 content.ToUC16Vector(),
3658 capture_count,
3659 subject_length,
3660 zone());
3661 }
3662 if (simple) return true;
3663 }
3664
3665 Isolate* isolate = replacement->GetIsolate();
3666 // Find substrings of replacement string and create them as String objects.
3667 int substring_index = 0;
3668 for (int i = 0, n = parts_.length(); i < n; i++) {
3669 int tag = parts_[i].tag;
3670 if (tag <= 0) { // A replacement string slice.
3671 int from = -tag;
3672 int to = parts_[i].data;
3673 replacement_substrings_.Add(
3674 isolate->factory()->NewSubString(replacement, from, to), zone());
3675 parts_[i].tag = REPLACEMENT_SUBSTRING;
3676 parts_[i].data = substring_index;
3677 substring_index++;
3678 } else if (tag == REPLACEMENT_STRING) {
3679 replacement_substrings_.Add(replacement, zone());
3680 parts_[i].data = substring_index;
3681 substring_index++;
3682 }
3683 }
3684 return false;
3685 }
3686
3687
Apply(ReplacementStringBuilder * builder,int match_from,int match_to,int32_t * match)3688 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3689 int match_from,
3690 int match_to,
3691 int32_t* match) {
3692 ASSERT_LT(0, parts_.length());
3693 for (int i = 0, n = parts_.length(); i < n; i++) {
3694 ReplacementPart part = parts_[i];
3695 switch (part.tag) {
3696 case SUBJECT_PREFIX:
3697 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3698 break;
3699 case SUBJECT_SUFFIX: {
3700 int subject_length = part.data;
3701 if (match_to < subject_length) {
3702 builder->AddSubjectSlice(match_to, subject_length);
3703 }
3704 break;
3705 }
3706 case SUBJECT_CAPTURE: {
3707 int capture = part.data;
3708 int from = match[capture * 2];
3709 int to = match[capture * 2 + 1];
3710 if (from >= 0 && to > from) {
3711 builder->AddSubjectSlice(from, to);
3712 }
3713 break;
3714 }
3715 case REPLACEMENT_SUBSTRING:
3716 case REPLACEMENT_STRING:
3717 builder->AddString(replacement_substrings_[part.data]);
3718 break;
3719 default:
3720 UNREACHABLE();
3721 }
3722 }
3723 }
3724
3725
FindAsciiStringIndices(Vector<const uint8_t> subject,char pattern,ZoneList<int> * indices,unsigned int limit,Zone * zone)3726 void FindAsciiStringIndices(Vector<const uint8_t> subject,
3727 char pattern,
3728 ZoneList<int>* indices,
3729 unsigned int limit,
3730 Zone* zone) {
3731 ASSERT(limit > 0);
3732 // Collect indices of pattern in subject using memchr.
3733 // Stop after finding at most limit values.
3734 const uint8_t* subject_start = subject.start();
3735 const uint8_t* subject_end = subject_start + subject.length();
3736 const uint8_t* pos = subject_start;
3737 while (limit > 0) {
3738 pos = reinterpret_cast<const uint8_t*>(
3739 memchr(pos, pattern, subject_end - pos));
3740 if (pos == NULL) return;
3741 indices->Add(static_cast<int>(pos - subject_start), zone);
3742 pos++;
3743 limit--;
3744 }
3745 }
3746
3747
FindTwoByteStringIndices(const Vector<const uc16> subject,uc16 pattern,ZoneList<int> * indices,unsigned int limit,Zone * zone)3748 void FindTwoByteStringIndices(const Vector<const uc16> subject,
3749 uc16 pattern,
3750 ZoneList<int>* indices,
3751 unsigned int limit,
3752 Zone* zone) {
3753 ASSERT(limit > 0);
3754 const uc16* subject_start = subject.start();
3755 const uc16* subject_end = subject_start + subject.length();
3756 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3757 if (*pos == pattern) {
3758 indices->Add(static_cast<int>(pos - subject_start), zone);
3759 limit--;
3760 }
3761 }
3762 }
3763
3764
3765 template <typename SubjectChar, typename PatternChar>
FindStringIndices(Isolate * isolate,Vector<const SubjectChar> subject,Vector<const PatternChar> pattern,ZoneList<int> * indices,unsigned int limit,Zone * zone)3766 void FindStringIndices(Isolate* isolate,
3767 Vector<const SubjectChar> subject,
3768 Vector<const PatternChar> pattern,
3769 ZoneList<int>* indices,
3770 unsigned int limit,
3771 Zone* zone) {
3772 ASSERT(limit > 0);
3773 // Collect indices of pattern in subject.
3774 // Stop after finding at most limit values.
3775 int pattern_length = pattern.length();
3776 int index = 0;
3777 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3778 while (limit > 0) {
3779 index = search.Search(subject, index);
3780 if (index < 0) return;
3781 indices->Add(index, zone);
3782 index += pattern_length;
3783 limit--;
3784 }
3785 }
3786
3787
FindStringIndicesDispatch(Isolate * isolate,String * subject,String * pattern,ZoneList<int> * indices,unsigned int limit,Zone * zone)3788 void FindStringIndicesDispatch(Isolate* isolate,
3789 String* subject,
3790 String* pattern,
3791 ZoneList<int>* indices,
3792 unsigned int limit,
3793 Zone* zone) {
3794 {
3795 DisallowHeapAllocation no_gc;
3796 String::FlatContent subject_content = subject->GetFlatContent();
3797 String::FlatContent pattern_content = pattern->GetFlatContent();
3798 ASSERT(subject_content.IsFlat());
3799 ASSERT(pattern_content.IsFlat());
3800 if (subject_content.IsAscii()) {
3801 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
3802 if (pattern_content.IsAscii()) {
3803 Vector<const uint8_t> pattern_vector =
3804 pattern_content.ToOneByteVector();
3805 if (pattern_vector.length() == 1) {
3806 FindAsciiStringIndices(subject_vector,
3807 pattern_vector[0],
3808 indices,
3809 limit,
3810 zone);
3811 } else {
3812 FindStringIndices(isolate,
3813 subject_vector,
3814 pattern_vector,
3815 indices,
3816 limit,
3817 zone);
3818 }
3819 } else {
3820 FindStringIndices(isolate,
3821 subject_vector,
3822 pattern_content.ToUC16Vector(),
3823 indices,
3824 limit,
3825 zone);
3826 }
3827 } else {
3828 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3829 if (pattern_content.IsAscii()) {
3830 Vector<const uint8_t> pattern_vector =
3831 pattern_content.ToOneByteVector();
3832 if (pattern_vector.length() == 1) {
3833 FindTwoByteStringIndices(subject_vector,
3834 pattern_vector[0],
3835 indices,
3836 limit,
3837 zone);
3838 } else {
3839 FindStringIndices(isolate,
3840 subject_vector,
3841 pattern_vector,
3842 indices,
3843 limit,
3844 zone);
3845 }
3846 } else {
3847 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3848 if (pattern_vector.length() == 1) {
3849 FindTwoByteStringIndices(subject_vector,
3850 pattern_vector[0],
3851 indices,
3852 limit,
3853 zone);
3854 } else {
3855 FindStringIndices(isolate,
3856 subject_vector,
3857 pattern_vector,
3858 indices,
3859 limit,
3860 zone);
3861 }
3862 }
3863 }
3864 }
3865 }
3866
3867
3868 template<typename ResultSeqString>
StringReplaceGlobalAtomRegExpWithString(Isolate * isolate,Handle<String> subject,Handle<JSRegExp> pattern_regexp,Handle<String> replacement,Handle<JSArray> last_match_info)3869 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
3870 Isolate* isolate,
3871 Handle<String> subject,
3872 Handle<JSRegExp> pattern_regexp,
3873 Handle<String> replacement,
3874 Handle<JSArray> last_match_info) {
3875 ASSERT(subject->IsFlat());
3876 ASSERT(replacement->IsFlat());
3877
3878 ZoneScope zone_scope(isolate->runtime_zone());
3879 ZoneList<int> indices(8, zone_scope.zone());
3880 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
3881 String* pattern =
3882 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
3883 int subject_len = subject->length();
3884 int pattern_len = pattern->length();
3885 int replacement_len = replacement->length();
3886
3887 FindStringIndicesDispatch(
3888 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
3889
3890 int matches = indices.length();
3891 if (matches == 0) return *subject;
3892
3893 // Detect integer overflow.
3894 int64_t result_len_64 =
3895 (static_cast<int64_t>(replacement_len) -
3896 static_cast<int64_t>(pattern_len)) *
3897 static_cast<int64_t>(matches) +
3898 static_cast<int64_t>(subject_len);
3899 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
3900 int result_len = static_cast<int>(result_len_64);
3901
3902 int subject_pos = 0;
3903 int result_pos = 0;
3904
3905 Handle<ResultSeqString> result;
3906 if (ResultSeqString::kHasAsciiEncoding) {
3907 result = Handle<ResultSeqString>::cast(
3908 isolate->factory()->NewRawOneByteString(result_len));
3909 } else {
3910 result = Handle<ResultSeqString>::cast(
3911 isolate->factory()->NewRawTwoByteString(result_len));
3912 }
3913
3914 for (int i = 0; i < matches; i++) {
3915 // Copy non-matched subject content.
3916 if (subject_pos < indices.at(i)) {
3917 String::WriteToFlat(*subject,
3918 result->GetChars() + result_pos,
3919 subject_pos,
3920 indices.at(i));
3921 result_pos += indices.at(i) - subject_pos;
3922 }
3923
3924 // Replace match.
3925 if (replacement_len > 0) {
3926 String::WriteToFlat(*replacement,
3927 result->GetChars() + result_pos,
3928 0,
3929 replacement_len);
3930 result_pos += replacement_len;
3931 }
3932
3933 subject_pos = indices.at(i) + pattern_len;
3934 }
3935 // Add remaining subject content at the end.
3936 if (subject_pos < subject_len) {
3937 String::WriteToFlat(*subject,
3938 result->GetChars() + result_pos,
3939 subject_pos,
3940 subject_len);
3941 }
3942
3943 int32_t match_indices[] = { indices.at(matches - 1),
3944 indices.at(matches - 1) + pattern_len };
3945 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
3946
3947 return *result;
3948 }
3949
3950
StringReplaceGlobalRegExpWithString(Isolate * isolate,Handle<String> subject,Handle<JSRegExp> regexp,Handle<String> replacement,Handle<JSArray> last_match_info)3951 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
3952 Isolate* isolate,
3953 Handle<String> subject,
3954 Handle<JSRegExp> regexp,
3955 Handle<String> replacement,
3956 Handle<JSArray> last_match_info) {
3957 ASSERT(subject->IsFlat());
3958 ASSERT(replacement->IsFlat());
3959
3960 int capture_count = regexp->CaptureCount();
3961 int subject_length = subject->length();
3962
3963 // CompiledReplacement uses zone allocation.
3964 ZoneScope zone_scope(isolate->runtime_zone());
3965 CompiledReplacement compiled_replacement(zone_scope.zone());
3966 bool simple_replace = compiled_replacement.Compile(replacement,
3967 capture_count,
3968 subject_length);
3969
3970 // Shortcut for simple non-regexp global replacements
3971 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
3972 if (subject->HasOnlyOneByteChars() &&
3973 replacement->HasOnlyOneByteChars()) {
3974 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
3975 isolate, subject, regexp, replacement, last_match_info);
3976 } else {
3977 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
3978 isolate, subject, regexp, replacement, last_match_info);
3979 }
3980 }
3981
3982 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3983 if (global_cache.HasException()) return Failure::Exception();
3984
3985 int32_t* current_match = global_cache.FetchNext();
3986 if (current_match == NULL) {
3987 if (global_cache.HasException()) return Failure::Exception();
3988 return *subject;
3989 }
3990
3991 // Guessing the number of parts that the final result string is built
3992 // from. Global regexps can match any number of times, so we guess
3993 // conservatively.
3994 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
3995 ReplacementStringBuilder builder(isolate->heap(),
3996 subject,
3997 expected_parts);
3998
3999 // Number of parts added by compiled replacement plus preceeding
4000 // string and possibly suffix after last match. It is possible for
4001 // all components to use two elements when encoded as two smis.
4002 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
4003
4004 int prev = 0;
4005
4006 do {
4007 builder.EnsureCapacity(parts_added_per_loop);
4008
4009 int start = current_match[0];
4010 int end = current_match[1];
4011
4012 if (prev < start) {
4013 builder.AddSubjectSlice(prev, start);
4014 }
4015
4016 if (simple_replace) {
4017 builder.AddString(replacement);
4018 } else {
4019 compiled_replacement.Apply(&builder,
4020 start,
4021 end,
4022 current_match);
4023 }
4024 prev = end;
4025
4026 current_match = global_cache.FetchNext();
4027 } while (current_match != NULL);
4028
4029 if (global_cache.HasException()) return Failure::Exception();
4030
4031 if (prev < subject_length) {
4032 builder.EnsureCapacity(2);
4033 builder.AddSubjectSlice(prev, subject_length);
4034 }
4035
4036 RegExpImpl::SetLastMatchInfo(last_match_info,
4037 subject,
4038 capture_count,
4039 global_cache.LastSuccessfulMatch());
4040
4041 return *(builder.ToString());
4042 }
4043
4044
4045 template <typename ResultSeqString>
StringReplaceGlobalRegExpWithEmptyString(Isolate * isolate,Handle<String> subject,Handle<JSRegExp> regexp,Handle<JSArray> last_match_info)4046 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
4047 Isolate* isolate,
4048 Handle<String> subject,
4049 Handle<JSRegExp> regexp,
4050 Handle<JSArray> last_match_info) {
4051 ASSERT(subject->IsFlat());
4052
4053 // Shortcut for simple non-regexp global replacements
4054 if (regexp->TypeTag() == JSRegExp::ATOM) {
4055 Handle<String> empty_string = isolate->factory()->empty_string();
4056 if (subject->IsOneByteRepresentation()) {
4057 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4058 isolate, subject, regexp, empty_string, last_match_info);
4059 } else {
4060 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4061 isolate, subject, regexp, empty_string, last_match_info);
4062 }
4063 }
4064
4065 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4066 if (global_cache.HasException()) return Failure::Exception();
4067
4068 int32_t* current_match = global_cache.FetchNext();
4069 if (current_match == NULL) {
4070 if (global_cache.HasException()) return Failure::Exception();
4071 return *subject;
4072 }
4073
4074 int start = current_match[0];
4075 int end = current_match[1];
4076 int capture_count = regexp->CaptureCount();
4077 int subject_length = subject->length();
4078
4079 int new_length = subject_length - (end - start);
4080 if (new_length == 0) return isolate->heap()->empty_string();
4081
4082 Handle<ResultSeqString> answer;
4083 if (ResultSeqString::kHasAsciiEncoding) {
4084 answer = Handle<ResultSeqString>::cast(
4085 isolate->factory()->NewRawOneByteString(new_length));
4086 } else {
4087 answer = Handle<ResultSeqString>::cast(
4088 isolate->factory()->NewRawTwoByteString(new_length));
4089 }
4090
4091 int prev = 0;
4092 int position = 0;
4093
4094 do {
4095 start = current_match[0];
4096 end = current_match[1];
4097 if (prev < start) {
4098 // Add substring subject[prev;start] to answer string.
4099 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
4100 position += start - prev;
4101 }
4102 prev = end;
4103
4104 current_match = global_cache.FetchNext();
4105 } while (current_match != NULL);
4106
4107 if (global_cache.HasException()) return Failure::Exception();
4108
4109 RegExpImpl::SetLastMatchInfo(last_match_info,
4110 subject,
4111 capture_count,
4112 global_cache.LastSuccessfulMatch());
4113
4114 if (prev < subject_length) {
4115 // Add substring subject[prev;length] to answer string.
4116 String::WriteToFlat(
4117 *subject, answer->GetChars() + position, prev, subject_length);
4118 position += subject_length - prev;
4119 }
4120
4121 if (position == 0) return isolate->heap()->empty_string();
4122
4123 // Shorten string and fill
4124 int string_size = ResultSeqString::SizeFor(position);
4125 int allocated_string_size = ResultSeqString::SizeFor(new_length);
4126 int delta = allocated_string_size - string_size;
4127
4128 answer->set_length(position);
4129 if (delta == 0) return *answer;
4130
4131 Address end_of_string = answer->address() + string_size;
4132 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
4133 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
4134 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
4135 }
4136
4137 return *answer;
4138 }
4139
4140
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringReplaceGlobalRegExpWithString)4141 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
4142 HandleScope scope(isolate);
4143 ASSERT(args.length() == 4);
4144
4145 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4146 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4147 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4148 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
4149
4150 ASSERT(regexp->GetFlags().is_global());
4151
4152 if (!subject->IsFlat()) subject = FlattenGetString(subject);
4153
4154 if (replacement->length() == 0) {
4155 if (subject->HasOnlyOneByteChars()) {
4156 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
4157 isolate, subject, regexp, last_match_info);
4158 } else {
4159 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
4160 isolate, subject, regexp, last_match_info);
4161 }
4162 }
4163
4164 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
4165
4166 return StringReplaceGlobalRegExpWithString(
4167 isolate, subject, regexp, replacement, last_match_info);
4168 }
4169
4170
StringReplaceOneCharWithString(Isolate * isolate,Handle<String> subject,Handle<String> search,Handle<String> replace,bool * found,int recursion_limit)4171 Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
4172 Handle<String> subject,
4173 Handle<String> search,
4174 Handle<String> replace,
4175 bool* found,
4176 int recursion_limit) {
4177 if (recursion_limit == 0) return Handle<String>::null();
4178 if (subject->IsConsString()) {
4179 ConsString* cons = ConsString::cast(*subject);
4180 Handle<String> first = Handle<String>(cons->first());
4181 Handle<String> second = Handle<String>(cons->second());
4182 Handle<String> new_first =
4183 StringReplaceOneCharWithString(isolate,
4184 first,
4185 search,
4186 replace,
4187 found,
4188 recursion_limit - 1);
4189 if (*found) return isolate->factory()->NewConsString(new_first, second);
4190 if (new_first.is_null()) return new_first;
4191
4192 Handle<String> new_second =
4193 StringReplaceOneCharWithString(isolate,
4194 second,
4195 search,
4196 replace,
4197 found,
4198 recursion_limit - 1);
4199 if (*found) return isolate->factory()->NewConsString(first, new_second);
4200 if (new_second.is_null()) return new_second;
4201
4202 return subject;
4203 } else {
4204 int index = Runtime::StringMatch(isolate, subject, search, 0);
4205 if (index == -1) return subject;
4206 *found = true;
4207 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4208 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
4209 Handle<String> second =
4210 isolate->factory()->NewSubString(subject, index + 1, subject->length());
4211 return isolate->factory()->NewConsString(cons1, second);
4212 }
4213 }
4214
4215
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringReplaceOneCharWithString)4216 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
4217 HandleScope scope(isolate);
4218 ASSERT(args.length() == 3);
4219 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4220 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4221 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
4222
4223 // If the cons string tree is too deep, we simply abort the recursion and
4224 // retry with a flattened subject string.
4225 const int kRecursionLimit = 0x1000;
4226 bool found = false;
4227 Handle<String> result = StringReplaceOneCharWithString(isolate,
4228 subject,
4229 search,
4230 replace,
4231 &found,
4232 kRecursionLimit);
4233 if (!result.is_null()) return *result;
4234 return *StringReplaceOneCharWithString(isolate,
4235 FlattenGetString(subject),
4236 search,
4237 replace,
4238 &found,
4239 kRecursionLimit);
4240 }
4241
4242
4243 // Perform string match of pattern on subject, starting at start index.
4244 // Caller must ensure that 0 <= start_index <= sub->length(),
4245 // and should check that pat->length() + start_index <= sub->length().
StringMatch(Isolate * isolate,Handle<String> sub,Handle<String> pat,int start_index)4246 int Runtime::StringMatch(Isolate* isolate,
4247 Handle<String> sub,
4248 Handle<String> pat,
4249 int start_index) {
4250 ASSERT(0 <= start_index);
4251 ASSERT(start_index <= sub->length());
4252
4253 int pattern_length = pat->length();
4254 if (pattern_length == 0) return start_index;
4255
4256 int subject_length = sub->length();
4257 if (start_index + pattern_length > subject_length) return -1;
4258
4259 if (!sub->IsFlat()) FlattenString(sub);
4260 if (!pat->IsFlat()) FlattenString(pat);
4261
4262 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4263 // Extract flattened substrings of cons strings before determining asciiness.
4264 String::FlatContent seq_sub = sub->GetFlatContent();
4265 String::FlatContent seq_pat = pat->GetFlatContent();
4266
4267 // dispatch on type of strings
4268 if (seq_pat.IsAscii()) {
4269 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
4270 if (seq_sub.IsAscii()) {
4271 return SearchString(isolate,
4272 seq_sub.ToOneByteVector(),
4273 pat_vector,
4274 start_index);
4275 }
4276 return SearchString(isolate,
4277 seq_sub.ToUC16Vector(),
4278 pat_vector,
4279 start_index);
4280 }
4281 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4282 if (seq_sub.IsAscii()) {
4283 return SearchString(isolate,
4284 seq_sub.ToOneByteVector(),
4285 pat_vector,
4286 start_index);
4287 }
4288 return SearchString(isolate,
4289 seq_sub.ToUC16Vector(),
4290 pat_vector,
4291 start_index);
4292 }
4293
4294
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringIndexOf)4295 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
4296 HandleScope scope(isolate);
4297 ASSERT(args.length() == 3);
4298
4299 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4300 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4301
4302 Object* index = args[2];
4303 uint32_t start_index;
4304 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4305
4306 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
4307 int position =
4308 Runtime::StringMatch(isolate, sub, pat, start_index);
4309 return Smi::FromInt(position);
4310 }
4311
4312
4313 template <typename schar, typename pchar>
StringMatchBackwards(Vector<const schar> subject,Vector<const pchar> pattern,int idx)4314 static int StringMatchBackwards(Vector<const schar> subject,
4315 Vector<const pchar> pattern,
4316 int idx) {
4317 int pattern_length = pattern.length();
4318 ASSERT(pattern_length >= 1);
4319 ASSERT(idx + pattern_length <= subject.length());
4320
4321 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
4322 for (int i = 0; i < pattern_length; i++) {
4323 uc16 c = pattern[i];
4324 if (c > String::kMaxOneByteCharCode) {
4325 return -1;
4326 }
4327 }
4328 }
4329
4330 pchar pattern_first_char = pattern[0];
4331 for (int i = idx; i >= 0; i--) {
4332 if (subject[i] != pattern_first_char) continue;
4333 int j = 1;
4334 while (j < pattern_length) {
4335 if (pattern[j] != subject[i+j]) {
4336 break;
4337 }
4338 j++;
4339 }
4340 if (j == pattern_length) {
4341 return i;
4342 }
4343 }
4344 return -1;
4345 }
4346
4347
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringLastIndexOf)4348 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
4349 HandleScope scope(isolate);
4350 ASSERT(args.length() == 3);
4351
4352 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4353 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4354
4355 Object* index = args[2];
4356 uint32_t start_index;
4357 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4358
4359 uint32_t pat_length = pat->length();
4360 uint32_t sub_length = sub->length();
4361
4362 if (start_index + pat_length > sub_length) {
4363 start_index = sub_length - pat_length;
4364 }
4365
4366 if (pat_length == 0) {
4367 return Smi::FromInt(start_index);
4368 }
4369
4370 if (!sub->IsFlat()) FlattenString(sub);
4371 if (!pat->IsFlat()) FlattenString(pat);
4372
4373 int position = -1;
4374 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4375
4376 String::FlatContent sub_content = sub->GetFlatContent();
4377 String::FlatContent pat_content = pat->GetFlatContent();
4378
4379 if (pat_content.IsAscii()) {
4380 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
4381 if (sub_content.IsAscii()) {
4382 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4383 pat_vector,
4384 start_index);
4385 } else {
4386 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4387 pat_vector,
4388 start_index);
4389 }
4390 } else {
4391 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4392 if (sub_content.IsAscii()) {
4393 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4394 pat_vector,
4395 start_index);
4396 } else {
4397 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4398 pat_vector,
4399 start_index);
4400 }
4401 }
4402
4403 return Smi::FromInt(position);
4404 }
4405
4406
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringLocaleCompare)4407 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
4408 SealHandleScope shs(isolate);
4409 ASSERT(args.length() == 2);
4410
4411 CONVERT_ARG_CHECKED(String, str1, 0);
4412 CONVERT_ARG_CHECKED(String, str2, 1);
4413
4414 if (str1 == str2) return Smi::FromInt(0); // Equal.
4415 int str1_length = str1->length();
4416 int str2_length = str2->length();
4417
4418 // Decide trivial cases without flattening.
4419 if (str1_length == 0) {
4420 if (str2_length == 0) return Smi::FromInt(0); // Equal.
4421 return Smi::FromInt(-str2_length);
4422 } else {
4423 if (str2_length == 0) return Smi::FromInt(str1_length);
4424 }
4425
4426 int end = str1_length < str2_length ? str1_length : str2_length;
4427
4428 // No need to flatten if we are going to find the answer on the first
4429 // character. At this point we know there is at least one character
4430 // in each string, due to the trivial case handling above.
4431 int d = str1->Get(0) - str2->Get(0);
4432 if (d != 0) return Smi::FromInt(d);
4433
4434 str1->TryFlatten();
4435 str2->TryFlatten();
4436
4437 ConsStringIteratorOp* op1 =
4438 isolate->runtime_state()->string_locale_compare_it1();
4439 ConsStringIteratorOp* op2 =
4440 isolate->runtime_state()->string_locale_compare_it2();
4441 // TODO(dcarney) Can do array compares here more efficiently.
4442 StringCharacterStream stream1(str1, op1);
4443 StringCharacterStream stream2(str2, op2);
4444
4445 for (int i = 0; i < end; i++) {
4446 uint16_t char1 = stream1.GetNext();
4447 uint16_t char2 = stream2.GetNext();
4448 if (char1 != char2) return Smi::FromInt(char1 - char2);
4449 }
4450
4451 return Smi::FromInt(str1_length - str2_length);
4452 }
4453
4454
RUNTIME_FUNCTION(MaybeObject *,Runtime_SubString)4455 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
4456 SealHandleScope shs(isolate);
4457 ASSERT(args.length() == 3);
4458
4459 CONVERT_ARG_CHECKED(String, value, 0);
4460 int start, end;
4461 // We have a fast integer-only case here to avoid a conversion to double in
4462 // the common case where from and to are Smis.
4463 if (args[1]->IsSmi() && args[2]->IsSmi()) {
4464 CONVERT_SMI_ARG_CHECKED(from_number, 1);
4465 CONVERT_SMI_ARG_CHECKED(to_number, 2);
4466 start = from_number;
4467 end = to_number;
4468 } else {
4469 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4470 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
4471 start = FastD2IChecked(from_number);
4472 end = FastD2IChecked(to_number);
4473 }
4474 RUNTIME_ASSERT(end >= start);
4475 RUNTIME_ASSERT(start >= 0);
4476 RUNTIME_ASSERT(end <= value->length());
4477 isolate->counters()->sub_string_runtime()->Increment();
4478 return value->SubString(start, end);
4479 }
4480
4481
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringMatch)4482 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
4483 HandleScope handles(isolate);
4484 ASSERT_EQ(3, args.length());
4485
4486 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4487 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4488 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
4489
4490 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4491 if (global_cache.HasException()) return Failure::Exception();
4492
4493 int capture_count = regexp->CaptureCount();
4494
4495 ZoneScope zone_scope(isolate->runtime_zone());
4496 ZoneList<int> offsets(8, zone_scope.zone());
4497
4498 while (true) {
4499 int32_t* match = global_cache.FetchNext();
4500 if (match == NULL) break;
4501 offsets.Add(match[0], zone_scope.zone()); // start
4502 offsets.Add(match[1], zone_scope.zone()); // end
4503 }
4504
4505 if (global_cache.HasException()) return Failure::Exception();
4506
4507 if (offsets.length() == 0) {
4508 // Not a single match.
4509 return isolate->heap()->null_value();
4510 }
4511
4512 RegExpImpl::SetLastMatchInfo(regexp_info,
4513 subject,
4514 capture_count,
4515 global_cache.LastSuccessfulMatch());
4516
4517 int matches = offsets.length() / 2;
4518 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
4519 Handle<String> substring =
4520 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
4521 elements->set(0, *substring);
4522 for (int i = 1; i < matches; i++) {
4523 HandleScope temp_scope(isolate);
4524 int from = offsets.at(i * 2);
4525 int to = offsets.at(i * 2 + 1);
4526 Handle<String> substring =
4527 isolate->factory()->NewProperSubString(subject, from, to);
4528 elements->set(i, *substring);
4529 }
4530 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
4531 result->set_length(Smi::FromInt(matches));
4532 return *result;
4533 }
4534
4535
4536 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4537 // separate last match info. See comment on that function.
4538 template<bool has_capture>
SearchRegExpMultiple(Isolate * isolate,Handle<String> subject,Handle<JSRegExp> regexp,Handle<JSArray> last_match_array,Handle<JSArray> result_array)4539 static MaybeObject* SearchRegExpMultiple(
4540 Isolate* isolate,
4541 Handle<String> subject,
4542 Handle<JSRegExp> regexp,
4543 Handle<JSArray> last_match_array,
4544 Handle<JSArray> result_array) {
4545 ASSERT(subject->IsFlat());
4546 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
4547
4548 int capture_count = regexp->CaptureCount();
4549 int subject_length = subject->length();
4550
4551 static const int kMinLengthToCache = 0x1000;
4552
4553 if (subject_length > kMinLengthToCache) {
4554 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4555 isolate->heap(),
4556 *subject,
4557 regexp->data(),
4558 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
4559 if (*cached_answer != Smi::FromInt(0)) {
4560 Handle<FixedArray> cached_fixed_array =
4561 Handle<FixedArray>(FixedArray::cast(*cached_answer));
4562 // The cache FixedArray is a COW-array and can therefore be reused.
4563 isolate->factory()->SetContent(result_array, cached_fixed_array);
4564 // The actual length of the result array is stored in the last element of
4565 // the backing store (the backing FixedArray may have a larger capacity).
4566 Object* cached_fixed_array_last_element =
4567 cached_fixed_array->get(cached_fixed_array->length() - 1);
4568 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4569 result_array->set_length(js_array_length);
4570 RegExpImpl::SetLastMatchInfo(
4571 last_match_array, subject, capture_count, NULL);
4572 return *result_array;
4573 }
4574 }
4575
4576 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4577 if (global_cache.HasException()) return Failure::Exception();
4578
4579 Handle<FixedArray> result_elements;
4580 if (result_array->HasFastObjectElements()) {
4581 result_elements =
4582 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4583 }
4584 if (result_elements.is_null() || result_elements->length() < 16) {
4585 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4586 }
4587
4588 FixedArrayBuilder builder(result_elements);
4589
4590 // Position to search from.
4591 int match_start = -1;
4592 int match_end = 0;
4593 bool first = true;
4594
4595 // Two smis before and after the match, for very long strings.
4596 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
4597
4598 while (true) {
4599 int32_t* current_match = global_cache.FetchNext();
4600 if (current_match == NULL) break;
4601 match_start = current_match[0];
4602 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
4603 if (match_end < match_start) {
4604 ReplacementStringBuilder::AddSubjectSlice(&builder,
4605 match_end,
4606 match_start);
4607 }
4608 match_end = current_match[1];
4609 {
4610 // Avoid accumulating new handles inside loop.
4611 HandleScope temp_scope(isolate);
4612 Handle<String> match;
4613 if (!first) {
4614 match = isolate->factory()->NewProperSubString(subject,
4615 match_start,
4616 match_end);
4617 } else {
4618 match = isolate->factory()->NewSubString(subject,
4619 match_start,
4620 match_end);
4621 first = false;
4622 }
4623
4624 if (has_capture) {
4625 // Arguments array to replace function is match, captures, index and
4626 // subject, i.e., 3 + capture count in total.
4627 Handle<FixedArray> elements =
4628 isolate->factory()->NewFixedArray(3 + capture_count);
4629
4630 elements->set(0, *match);
4631 for (int i = 1; i <= capture_count; i++) {
4632 int start = current_match[i * 2];
4633 if (start >= 0) {
4634 int end = current_match[i * 2 + 1];
4635 ASSERT(start <= end);
4636 Handle<String> substring =
4637 isolate->factory()->NewSubString(subject, start, end);
4638 elements->set(i, *substring);
4639 } else {
4640 ASSERT(current_match[i * 2 + 1] < 0);
4641 elements->set(i, isolate->heap()->undefined_value());
4642 }
4643 }
4644 elements->set(capture_count + 1, Smi::FromInt(match_start));
4645 elements->set(capture_count + 2, *subject);
4646 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
4647 } else {
4648 builder.Add(*match);
4649 }
4650 }
4651 }
4652
4653 if (global_cache.HasException()) return Failure::Exception();
4654
4655 if (match_start >= 0) {
4656 // Finished matching, with at least one match.
4657 if (match_end < subject_length) {
4658 ReplacementStringBuilder::AddSubjectSlice(&builder,
4659 match_end,
4660 subject_length);
4661 }
4662
4663 RegExpImpl::SetLastMatchInfo(
4664 last_match_array, subject, capture_count, NULL);
4665
4666 if (subject_length > kMinLengthToCache) {
4667 // Store the length of the result array into the last element of the
4668 // backing FixedArray.
4669 builder.EnsureCapacity(1);
4670 Handle<FixedArray> fixed_array = builder.array();
4671 fixed_array->set(fixed_array->length() - 1,
4672 Smi::FromInt(builder.length()));
4673 // Cache the result and turn the FixedArray into a COW array.
4674 RegExpResultsCache::Enter(isolate->heap(),
4675 *subject,
4676 regexp->data(),
4677 *fixed_array,
4678 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4679 }
4680 return *builder.ToJSArray(result_array);
4681 } else {
4682 return isolate->heap()->null_value(); // No matches at all.
4683 }
4684 }
4685
4686
4687 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4688 // lastMatchInfoOverride to maintain the last match info, so we don't need to
4689 // set any other last match array info.
RUNTIME_FUNCTION(MaybeObject *,Runtime_RegExpExecMultiple)4690 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
4691 HandleScope handles(isolate);
4692 ASSERT(args.length() == 4);
4693
4694 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
4695 if (!subject->IsFlat()) FlattenString(subject);
4696 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4697 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4698 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
4699
4700 ASSERT(regexp->GetFlags().is_global());
4701
4702 if (regexp->CaptureCount() == 0) {
4703 return SearchRegExpMultiple<false>(
4704 isolate, subject, regexp, last_match_info, result_array);
4705 } else {
4706 return SearchRegExpMultiple<true>(
4707 isolate, subject, regexp, last_match_info, result_array);
4708 }
4709 }
4710
4711
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToRadixString)4712 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
4713 SealHandleScope shs(isolate);
4714 ASSERT(args.length() == 2);
4715 CONVERT_SMI_ARG_CHECKED(radix, 1);
4716 RUNTIME_ASSERT(2 <= radix && radix <= 36);
4717
4718 // Fast case where the result is a one character string.
4719 if (args[0]->IsSmi()) {
4720 int value = args.smi_at(0);
4721 if (value >= 0 && value < radix) {
4722 // Character array used for conversion.
4723 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
4724 return isolate->heap()->
4725 LookupSingleCharacterStringFromCode(kCharTable[value]);
4726 }
4727 }
4728
4729 // Slow case.
4730 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4731 if (std::isnan(value)) {
4732 return *isolate->factory()->nan_string();
4733 }
4734 if (std::isinf(value)) {
4735 if (value < 0) {
4736 return *isolate->factory()->minus_infinity_string();
4737 }
4738 return *isolate->factory()->infinity_string();
4739 }
4740 char* str = DoubleToRadixCString(value, radix);
4741 MaybeObject* result =
4742 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4743 DeleteArray(str);
4744 return result;
4745 }
4746
4747
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToFixed)4748 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
4749 SealHandleScope shs(isolate);
4750 ASSERT(args.length() == 2);
4751
4752 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4753 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4754 int f = FastD2IChecked(f_number);
4755 RUNTIME_ASSERT(f >= 0);
4756 char* str = DoubleToFixedCString(value, f);
4757 MaybeObject* res =
4758 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4759 DeleteArray(str);
4760 return res;
4761 }
4762
4763
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToExponential)4764 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
4765 SealHandleScope shs(isolate);
4766 ASSERT(args.length() == 2);
4767
4768 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4769 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4770 int f = FastD2IChecked(f_number);
4771 RUNTIME_ASSERT(f >= -1 && f <= 20);
4772 char* str = DoubleToExponentialCString(value, f);
4773 MaybeObject* res =
4774 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4775 DeleteArray(str);
4776 return res;
4777 }
4778
4779
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToPrecision)4780 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
4781 SealHandleScope shs(isolate);
4782 ASSERT(args.length() == 2);
4783
4784 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4785 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4786 int f = FastD2IChecked(f_number);
4787 RUNTIME_ASSERT(f >= 1 && f <= 21);
4788 char* str = DoubleToPrecisionCString(value, f);
4789 MaybeObject* res =
4790 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4791 DeleteArray(str);
4792 return res;
4793 }
4794
4795
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsValidSmi)4796 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) {
4797 HandleScope shs(isolate);
4798 ASSERT(args.length() == 1);
4799
4800 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4801 if (Smi::IsValid(number)) {
4802 return isolate->heap()->true_value();
4803 } else {
4804 return isolate->heap()->false_value();
4805 }
4806 }
4807
4808
4809 // Returns a single character string where first character equals
4810 // string->Get(index).
GetCharAt(Handle<String> string,uint32_t index)4811 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4812 if (index < static_cast<uint32_t>(string->length())) {
4813 string->TryFlatten();
4814 return LookupSingleCharacterStringFromCode(
4815 string->GetIsolate(),
4816 string->Get(index));
4817 }
4818 return Execution::CharAt(string, index);
4819 }
4820
4821
GetElementOrCharAtOrFail(Isolate * isolate,Handle<Object> object,uint32_t index)4822 MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate,
4823 Handle<Object> object,
4824 uint32_t index) {
4825 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4826 GetElementOrCharAt(isolate, object, index));
4827 }
4828
4829
GetElementOrCharAt(Isolate * isolate,Handle<Object> object,uint32_t index)4830 MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4831 Handle<Object> object,
4832 uint32_t index) {
4833 // Handle [] indexing on Strings
4834 if (object->IsString()) {
4835 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4836 if (!result->IsUndefined()) return *result;
4837 }
4838
4839 // Handle [] indexing on String objects
4840 if (object->IsStringObjectWithCharacterAt(index)) {
4841 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4842 Handle<Object> result =
4843 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4844 if (!result->IsUndefined()) return *result;
4845 }
4846
4847 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
4848 return object->GetPrototype(isolate)->GetElement(isolate, index);
4849 }
4850
4851 return object->GetElement(isolate, index);
4852 }
4853
4854
ToName(Isolate * isolate,Handle<Object> key)4855 static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) {
4856 if (key->IsName()) {
4857 return Handle<Name>::cast(key);
4858 } else {
4859 bool has_pending_exception = false;
4860 Handle<Object> converted =
4861 Execution::ToString(isolate, key, &has_pending_exception);
4862 if (has_pending_exception) return Handle<Name>();
4863 return Handle<Name>::cast(converted);
4864 }
4865 }
4866
4867
HasObjectProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Object> key)4868 MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
4869 Handle<JSReceiver> object,
4870 Handle<Object> key) {
4871 HandleScope scope(isolate);
4872
4873 // Check if the given key is an array index.
4874 uint32_t index;
4875 if (key->ToArrayIndex(&index)) {
4876 return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index));
4877 }
4878
4879 // Convert the key to a name - possibly by calling back into JavaScript.
4880 Handle<Name> name = ToName(isolate, key);
4881 RETURN_IF_EMPTY_HANDLE(isolate, name);
4882
4883 return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
4884 }
4885
GetObjectPropertyOrFail(Isolate * isolate,Handle<Object> object,Handle<Object> key)4886 MaybeObject* Runtime::GetObjectPropertyOrFail(
4887 Isolate* isolate,
4888 Handle<Object> object,
4889 Handle<Object> key) {
4890 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4891 GetObjectProperty(isolate, object, key));
4892 }
4893
GetObjectProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key)4894 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4895 Handle<Object> object,
4896 Handle<Object> key) {
4897 HandleScope scope(isolate);
4898
4899 if (object->IsUndefined() || object->IsNull()) {
4900 Handle<Object> args[2] = { key, object };
4901 Handle<Object> error =
4902 isolate->factory()->NewTypeError("non_object_property_load",
4903 HandleVector(args, 2));
4904 return isolate->Throw(*error);
4905 }
4906
4907 // Check if the given key is an array index.
4908 uint32_t index;
4909 if (key->ToArrayIndex(&index)) {
4910 return GetElementOrCharAt(isolate, object, index);
4911 }
4912
4913 // Convert the key to a name - possibly by calling back into JavaScript.
4914 Handle<Name> name = ToName(isolate, key);
4915 RETURN_IF_EMPTY_HANDLE(isolate, name);
4916
4917 // Check if the name is trivially convertible to an index and get
4918 // the element if so.
4919 if (name->AsArrayIndex(&index)) {
4920 return GetElementOrCharAt(isolate, object, index);
4921 } else {
4922 return object->GetProperty(*name);
4923 }
4924 }
4925
4926
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetProperty)4927 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
4928 SealHandleScope shs(isolate);
4929 ASSERT(args.length() == 2);
4930
4931 Handle<Object> object = args.at<Object>(0);
4932 Handle<Object> key = args.at<Object>(1);
4933
4934 return Runtime::GetObjectProperty(isolate, object, key);
4935 }
4936
4937
4938 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
RUNTIME_FUNCTION(MaybeObject *,Runtime_KeyedGetProperty)4939 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
4940 SealHandleScope shs(isolate);
4941 ASSERT(args.length() == 2);
4942
4943 // Fast cases for getting named properties of the receiver JSObject
4944 // itself.
4945 //
4946 // The global proxy objects has to be excluded since LocalLookup on
4947 // the global proxy object can return a valid result even though the
4948 // global proxy object never has properties. This is the case
4949 // because the global proxy object forwards everything to its hidden
4950 // prototype including local lookups.
4951 //
4952 // Additionally, we need to make sure that we do not cache results
4953 // for objects that require access checks.
4954 if (args[0]->IsJSObject()) {
4955 if (!args[0]->IsJSGlobalProxy() &&
4956 !args[0]->IsAccessCheckNeeded() &&
4957 args[1]->IsName()) {
4958 JSObject* receiver = JSObject::cast(args[0]);
4959 Name* key = Name::cast(args[1]);
4960 if (receiver->HasFastProperties()) {
4961 // Attempt to use lookup cache.
4962 Map* receiver_map = receiver->map();
4963 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4964 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4965 if (offset != -1) {
4966 // Doubles are not cached, so raw read the value.
4967 Object* value = receiver->RawFastPropertyAt(offset);
4968 return value->IsTheHole()
4969 ? isolate->heap()->undefined_value()
4970 : value;
4971 }
4972 // Lookup cache miss. Perform lookup and update the cache if
4973 // appropriate.
4974 LookupResult result(isolate);
4975 receiver->LocalLookup(key, &result);
4976 if (result.IsField()) {
4977 int offset = result.GetFieldIndex().field_index();
4978 // Do not track double fields in the keyed lookup cache. Reading
4979 // double values requires boxing.
4980 if (!FLAG_track_double_fields ||
4981 !result.representation().IsDouble()) {
4982 keyed_lookup_cache->Update(receiver_map, key, offset);
4983 }
4984 return receiver->FastPropertyAt(result.representation(), offset);
4985 }
4986 } else {
4987 // Attempt dictionary lookup.
4988 NameDictionary* dictionary = receiver->property_dictionary();
4989 int entry = dictionary->FindEntry(key);
4990 if ((entry != NameDictionary::kNotFound) &&
4991 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4992 Object* value = dictionary->ValueAt(entry);
4993 if (!receiver->IsGlobalObject()) return value;
4994 value = PropertyCell::cast(value)->value();
4995 if (!value->IsTheHole()) return value;
4996 // If value is the hole do the general lookup.
4997 }
4998 }
4999 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
5000 // JSObject without a name key. If the key is a Smi, check for a
5001 // definite out-of-bounds access to elements, which is a strong indicator
5002 // that subsequent accesses will also call the runtime. Proactively
5003 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
5004 // doubles for those future calls in the case that the elements would
5005 // become FAST_DOUBLE_ELEMENTS.
5006 Handle<JSObject> js_object(args.at<JSObject>(0));
5007 ElementsKind elements_kind = js_object->GetElementsKind();
5008 if (IsFastDoubleElementsKind(elements_kind)) {
5009 FixedArrayBase* elements = js_object->elements();
5010 if (args.at<Smi>(1)->value() >= elements->length()) {
5011 if (IsFastHoleyElementsKind(elements_kind)) {
5012 elements_kind = FAST_HOLEY_ELEMENTS;
5013 } else {
5014 elements_kind = FAST_ELEMENTS;
5015 }
5016 MaybeObject* maybe_object = TransitionElements(js_object,
5017 elements_kind,
5018 isolate);
5019 if (maybe_object->IsFailure()) return maybe_object;
5020 }
5021 } else {
5022 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
5023 !IsFastElementsKind(elements_kind));
5024 }
5025 }
5026 } else if (args[0]->IsString() && args[1]->IsSmi()) {
5027 // Fast case for string indexing using [] with a smi index.
5028 HandleScope scope(isolate);
5029 Handle<String> str = args.at<String>(0);
5030 int index = args.smi_at(1);
5031 if (index >= 0 && index < str->length()) {
5032 Handle<Object> result = GetCharAt(str, index);
5033 return *result;
5034 }
5035 }
5036
5037 // Fall back to GetObjectProperty.
5038 return Runtime::GetObjectProperty(isolate,
5039 args.at<Object>(0),
5040 args.at<Object>(1));
5041 }
5042
5043
IsValidAccessor(Handle<Object> obj)5044 static bool IsValidAccessor(Handle<Object> obj) {
5045 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
5046 }
5047
5048
5049 // Implements part of 8.12.9 DefineOwnProperty.
5050 // There are 3 cases that lead here:
5051 // Step 4b - define a new accessor property.
5052 // Steps 9c & 12 - replace an existing data property with an accessor property.
5053 // Step 12 - update an existing accessor property with an accessor or generic
5054 // descriptor.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DefineOrRedefineAccessorProperty)5055 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
5056 HandleScope scope(isolate);
5057 ASSERT(args.length() == 5);
5058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5059 RUNTIME_ASSERT(!obj->IsNull());
5060 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5061 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
5062 RUNTIME_ASSERT(IsValidAccessor(getter));
5063 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
5064 RUNTIME_ASSERT(IsValidAccessor(setter));
5065 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
5066 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5067 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5068
5069 bool fast = obj->HasFastProperties();
5070 JSObject::DefineAccessor(obj, name, getter, setter, attr);
5071 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5072 if (fast) JSObject::TransformToFastProperties(obj, 0);
5073 return isolate->heap()->undefined_value();
5074 }
5075
5076
5077 // Implements part of 8.12.9 DefineOwnProperty.
5078 // There are 3 cases that lead here:
5079 // Step 4a - define a new data property.
5080 // Steps 9b & 12 - replace an existing accessor property with a data property.
5081 // Step 12 - update an existing data property with a data or generic
5082 // descriptor.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DefineOrRedefineDataProperty)5083 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
5084 HandleScope scope(isolate);
5085 ASSERT(args.length() == 4);
5086 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
5087 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5088 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
5089 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
5090 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5091 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5092
5093 LookupResult lookup(isolate);
5094 js_object->LocalLookupRealNamedProperty(*name, &lookup);
5095
5096 // Special case for callback properties.
5097 if (lookup.IsPropertyCallbacks()) {
5098 Handle<Object> callback(lookup.GetCallbackObject(), isolate);
5099 // To be compatible with Safari we do not change the value on API objects
5100 // in Object.defineProperty(). Firefox disagrees here, and actually changes
5101 // the value.
5102 if (callback->IsAccessorInfo()) {
5103 return isolate->heap()->undefined_value();
5104 }
5105 // Avoid redefining foreign callback as data property, just use the stored
5106 // setter to update the value instead.
5107 // TODO(mstarzinger): So far this only works if property attributes don't
5108 // change, this should be fixed once we cleanup the underlying code.
5109 if (callback->IsForeign() && lookup.GetAttributes() == attr) {
5110 Handle<Object> result_object =
5111 JSObject::SetPropertyWithCallback(js_object,
5112 callback,
5113 name,
5114 obj_value,
5115 handle(lookup.holder()),
5116 kStrictMode);
5117 RETURN_IF_EMPTY_HANDLE(isolate, result_object);
5118 return *result_object;
5119 }
5120 }
5121
5122 // Take special care when attributes are different and there is already
5123 // a property. For simplicity we normalize the property which enables us
5124 // to not worry about changing the instance_descriptor and creating a new
5125 // map. The current version of SetObjectProperty does not handle attributes
5126 // correctly in the case where a property is a field and is reset with
5127 // new attributes.
5128 if (lookup.IsFound() &&
5129 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) {
5130 // New attributes - normalize to avoid writing to instance descriptor
5131 if (js_object->IsJSGlobalProxy()) {
5132 // Since the result is a property, the prototype will exist so
5133 // we don't have to check for null.
5134 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
5135 }
5136 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
5137 // Use IgnoreAttributes version since a readonly property may be
5138 // overridden and SetProperty does not allow this.
5139 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5140 js_object, name, obj_value, attr);
5141 RETURN_IF_EMPTY_HANDLE(isolate, result);
5142 return *result;
5143 }
5144
5145 Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object,
5146 name,
5147 obj_value,
5148 attr);
5149 RETURN_IF_EMPTY_HANDLE(isolate, result);
5150 return *result;
5151 }
5152
5153
5154 // Return property without being observable by accessors or interceptors.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetDataProperty)5155 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
5156 SealHandleScope shs(isolate);
5157 ASSERT(args.length() == 2);
5158 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5159 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5160 LookupResult lookup(isolate);
5161 object->LookupRealNamedProperty(*key, &lookup);
5162 if (!lookup.IsFound()) return isolate->heap()->undefined_value();
5163 switch (lookup.type()) {
5164 case NORMAL:
5165 return lookup.holder()->GetNormalizedProperty(&lookup);
5166 case FIELD:
5167 return lookup.holder()->FastPropertyAt(
5168 lookup.representation(),
5169 lookup.GetFieldIndex().field_index());
5170 case CONSTANT:
5171 return lookup.GetConstant();
5172 case CALLBACKS:
5173 case HANDLER:
5174 case INTERCEPTOR:
5175 case TRANSITION:
5176 return isolate->heap()->undefined_value();
5177 case NONEXISTENT:
5178 UNREACHABLE();
5179 }
5180 return isolate->heap()->undefined_value();
5181 }
5182
5183
SetObjectProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> value,PropertyAttributes attr,StrictModeFlag strict_mode)5184 Handle<Object> Runtime::SetObjectProperty(Isolate* isolate,
5185 Handle<Object> object,
5186 Handle<Object> key,
5187 Handle<Object> value,
5188 PropertyAttributes attr,
5189 StrictModeFlag strict_mode) {
5190 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
5191
5192 if (object->IsUndefined() || object->IsNull()) {
5193 Handle<Object> args[2] = { key, object };
5194 Handle<Object> error =
5195 isolate->factory()->NewTypeError("non_object_property_store",
5196 HandleVector(args, 2));
5197 isolate->Throw(*error);
5198 return Handle<Object>();
5199 }
5200
5201 if (object->IsJSProxy()) {
5202 bool has_pending_exception = false;
5203 Handle<Object> name_object = key->IsSymbol()
5204 ? key : Execution::ToString(isolate, key, &has_pending_exception);
5205 if (has_pending_exception) return Handle<Object>(); // exception
5206 Handle<Name> name = Handle<Name>::cast(name_object);
5207 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
5208 attr,
5209 strict_mode);
5210 }
5211
5212 // If the object isn't a JavaScript object, we ignore the store.
5213 if (!object->IsJSObject()) return value;
5214
5215 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
5216
5217 // Check if the given key is an array index.
5218 uint32_t index;
5219 if (key->ToArrayIndex(&index)) {
5220 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5221 // of a string using [] notation. We need to support this too in
5222 // JavaScript.
5223 // In the case of a String object we just need to redirect the assignment to
5224 // the underlying string if the index is in range. Since the underlying
5225 // string does nothing with the assignment then we can ignore such
5226 // assignments.
5227 if (js_object->IsStringObjectWithCharacterAt(index)) {
5228 return value;
5229 }
5230
5231 js_object->ValidateElements();
5232 if (js_object->HasExternalArrayElements()) {
5233 if (!value->IsNumber() && !value->IsUndefined()) {
5234 bool has_exception;
5235 Handle<Object> number =
5236 Execution::ToNumber(isolate, value, &has_exception);
5237 if (has_exception) return Handle<Object>(); // exception
5238 value = number;
5239 }
5240 }
5241 Handle<Object> result = JSObject::SetElement(js_object, index, value, attr,
5242 strict_mode,
5243 true,
5244 set_mode);
5245 js_object->ValidateElements();
5246 return result.is_null() ? result : value;
5247 }
5248
5249 if (key->IsName()) {
5250 Handle<Name> name = Handle<Name>::cast(key);
5251 if (name->AsArrayIndex(&index)) {
5252 if (js_object->HasExternalArrayElements()) {
5253 if (!value->IsNumber() && !value->IsUndefined()) {
5254 bool has_exception;
5255 Handle<Object> number =
5256 Execution::ToNumber(isolate, value, &has_exception);
5257 if (has_exception) return Handle<Object>(); // exception
5258 value = number;
5259 }
5260 }
5261 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5262 true,
5263 set_mode);
5264 } else {
5265 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5266 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5267 }
5268 }
5269
5270 // Call-back into JavaScript to convert the key to a string.
5271 bool has_pending_exception = false;
5272 Handle<Object> converted =
5273 Execution::ToString(isolate, key, &has_pending_exception);
5274 if (has_pending_exception) return Handle<Object>(); // exception
5275 Handle<String> name = Handle<String>::cast(converted);
5276
5277 if (name->AsArrayIndex(&index)) {
5278 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5279 true,
5280 set_mode);
5281 } else {
5282 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5283 }
5284 }
5285
5286
ForceSetObjectProperty(Isolate * isolate,Handle<JSObject> js_object,Handle<Object> key,Handle<Object> value,PropertyAttributes attr)5287 Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate,
5288 Handle<JSObject> js_object,
5289 Handle<Object> key,
5290 Handle<Object> value,
5291 PropertyAttributes attr) {
5292 // Check if the given key is an array index.
5293 uint32_t index;
5294 if (key->ToArrayIndex(&index)) {
5295 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5296 // of a string using [] notation. We need to support this too in
5297 // JavaScript.
5298 // In the case of a String object we just need to redirect the assignment to
5299 // the underlying string if the index is in range. Since the underlying
5300 // string does nothing with the assignment then we can ignore such
5301 // assignments.
5302 if (js_object->IsStringObjectWithCharacterAt(index)) {
5303 return value;
5304 }
5305
5306 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5307 false,
5308 DEFINE_PROPERTY);
5309 }
5310
5311 if (key->IsName()) {
5312 Handle<Name> name = Handle<Name>::cast(key);
5313 if (name->AsArrayIndex(&index)) {
5314 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5315 false,
5316 DEFINE_PROPERTY);
5317 } else {
5318 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5319 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name,
5320 value, attr);
5321 }
5322 }
5323
5324 // Call-back into JavaScript to convert the key to a string.
5325 bool has_pending_exception = false;
5326 Handle<Object> converted =
5327 Execution::ToString(isolate, key, &has_pending_exception);
5328 if (has_pending_exception) return Handle<Object>(); // exception
5329 Handle<String> name = Handle<String>::cast(converted);
5330
5331 if (name->AsArrayIndex(&index)) {
5332 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5333 false,
5334 DEFINE_PROPERTY);
5335 } else {
5336 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value,
5337 attr);
5338 }
5339 }
5340
5341
DeleteObjectProperty(Isolate * isolate,Handle<JSReceiver> receiver,Handle<Object> key,JSReceiver::DeleteMode mode)5342 MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
5343 Handle<JSReceiver> receiver,
5344 Handle<Object> key,
5345 JSReceiver::DeleteMode mode) {
5346 HandleScope scope(isolate);
5347
5348 // Check if the given key is an array index.
5349 uint32_t index;
5350 if (key->ToArrayIndex(&index)) {
5351 // In Firefox/SpiderMonkey, Safari and Opera you can access the
5352 // characters of a string using [] notation. In the case of a
5353 // String object we just need to redirect the deletion to the
5354 // underlying string if the index is in range. Since the
5355 // underlying string does nothing with the deletion, we can ignore
5356 // such deletions.
5357 if (receiver->IsStringObjectWithCharacterAt(index)) {
5358 return isolate->heap()->true_value();
5359 }
5360
5361 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode);
5362 RETURN_IF_EMPTY_HANDLE(isolate, result);
5363 return *result;
5364 }
5365
5366 Handle<Name> name;
5367 if (key->IsName()) {
5368 name = Handle<Name>::cast(key);
5369 } else {
5370 // Call-back into JavaScript to convert the key to a string.
5371 bool has_pending_exception = false;
5372 Handle<Object> converted = Execution::ToString(
5373 isolate, key, &has_pending_exception);
5374 if (has_pending_exception) return Failure::Exception();
5375 name = Handle<String>::cast(converted);
5376 }
5377
5378 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5379 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode);
5380 RETURN_IF_EMPTY_HANDLE(isolate, result);
5381 return *result;
5382 }
5383
5384
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetProperty)5385 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
5386 HandleScope scope(isolate);
5387 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
5388
5389 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5390 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
5391 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5392 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
5393 RUNTIME_ASSERT(
5394 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5395 // Compute attributes.
5396 PropertyAttributes attributes =
5397 static_cast<PropertyAttributes>(unchecked_attributes);
5398
5399 StrictModeFlag strict_mode = kNonStrictMode;
5400 if (args.length() == 5) {
5401 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
5402 strict_mode = strict_mode_flag;
5403 }
5404
5405 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
5406 value,
5407 attributes,
5408 strict_mode);
5409 RETURN_IF_EMPTY_HANDLE(isolate, result);
5410 return *result;
5411 }
5412
5413
RUNTIME_FUNCTION(MaybeObject *,Runtime_TransitionElementsKind)5414 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) {
5415 HandleScope scope(isolate);
5416 RUNTIME_ASSERT(args.length() == 2);
5417 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
5418 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
5419 JSObject::TransitionElementsKind(array, map->elements_kind());
5420 return *array;
5421 }
5422
5423
5424 // Set the native flag on the function.
5425 // This is used to decide if we should transform null and undefined
5426 // into the global object when doing call and apply.
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetNativeFlag)5427 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
5428 SealHandleScope shs(isolate);
5429 RUNTIME_ASSERT(args.length() == 1);
5430
5431 CONVERT_ARG_CHECKED(Object, object, 0);
5432
5433 if (object->IsJSFunction()) {
5434 JSFunction* func = JSFunction::cast(object);
5435 func->shared()->set_native(true);
5436 }
5437 return isolate->heap()->undefined_value();
5438 }
5439
5440
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetInlineBuiltinFlag)5441 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) {
5442 SealHandleScope shs(isolate);
5443 RUNTIME_ASSERT(args.length() == 1);
5444
5445 Handle<Object> object = args.at<Object>(0);
5446
5447 if (object->IsJSFunction()) {
5448 JSFunction* func = JSFunction::cast(*object);
5449 func->shared()->set_inline_builtin(true);
5450 }
5451 return isolate->heap()->undefined_value();
5452 }
5453
5454
RUNTIME_FUNCTION(MaybeObject *,Runtime_StoreArrayLiteralElement)5455 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
5456 HandleScope scope(isolate);
5457 RUNTIME_ASSERT(args.length() == 5);
5458 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5459 CONVERT_SMI_ARG_CHECKED(store_index, 1);
5460 Handle<Object> value = args.at<Object>(2);
5461 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
5462 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
5463
5464 Object* raw_literal_cell = literals->get(literal_index);
5465 JSArray* boilerplate = NULL;
5466 if (raw_literal_cell->IsAllocationSite()) {
5467 AllocationSite* site = AllocationSite::cast(raw_literal_cell);
5468 boilerplate = JSArray::cast(site->transition_info());
5469 } else {
5470 boilerplate = JSArray::cast(raw_literal_cell);
5471 }
5472 Handle<JSArray> boilerplate_object(boilerplate);
5473 ElementsKind elements_kind = object->GetElementsKind();
5474 ASSERT(IsFastElementsKind(elements_kind));
5475 // Smis should never trigger transitions.
5476 ASSERT(!value->IsSmi());
5477
5478 if (value->IsNumber()) {
5479 ASSERT(IsFastSmiElementsKind(elements_kind));
5480 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5481 ? FAST_HOLEY_DOUBLE_ELEMENTS
5482 : FAST_DOUBLE_ELEMENTS;
5483 if (IsMoreGeneralElementsKindTransition(
5484 boilerplate_object->GetElementsKind(),
5485 transitioned_kind)) {
5486 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5487 }
5488 JSObject::TransitionElementsKind(object, transitioned_kind);
5489 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
5490 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
5491 HeapNumber* number = HeapNumber::cast(*value);
5492 double_array->set(store_index, number->Number());
5493 } else {
5494 ASSERT(IsFastSmiElementsKind(elements_kind) ||
5495 IsFastDoubleElementsKind(elements_kind));
5496 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5497 ? FAST_HOLEY_ELEMENTS
5498 : FAST_ELEMENTS;
5499 JSObject::TransitionElementsKind(object, transitioned_kind);
5500 if (IsMoreGeneralElementsKindTransition(
5501 boilerplate_object->GetElementsKind(),
5502 transitioned_kind)) {
5503 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5504 }
5505 FixedArray* object_array = FixedArray::cast(object->elements());
5506 object_array->set(store_index, *value);
5507 }
5508 return *object;
5509 }
5510
5511
5512 // Check whether debugger and is about to step into the callback that is passed
5513 // to a built-in function such as Array.forEach.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugCallbackSupportsStepping)5514 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
5515 SealHandleScope shs(isolate);
5516 #ifdef ENABLE_DEBUGGER_SUPPORT
5517 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
5518 return isolate->heap()->false_value();
5519 }
5520 CONVERT_ARG_CHECKED(Object, callback, 0);
5521 // We do not step into the callback if it's a builtin or not even a function.
5522 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
5523 return isolate->heap()->false_value();
5524 }
5525 return isolate->heap()->true_value();
5526 #else
5527 return isolate->heap()->false_value();
5528 #endif // ENABLE_DEBUGGER_SUPPORT
5529 }
5530
5531
5532 // Set one shot breakpoints for the callback function that is passed to a
5533 // built-in function such as Array.forEach to enable stepping into the callback.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPrepareStepInIfStepping)5534 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
5535 SealHandleScope shs(isolate);
5536 #ifdef ENABLE_DEBUGGER_SUPPORT
5537 Debug* debug = isolate->debug();
5538 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
5539 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
5540 HandleScope scope(isolate);
5541 // When leaving the callback, step out has been activated, but not performed
5542 // if we do not leave the builtin. To be able to step into the callback
5543 // again, we need to clear the step out at this point.
5544 debug->ClearStepOut();
5545 debug->FloodWithOneShot(callback);
5546 #endif // ENABLE_DEBUGGER_SUPPORT
5547 return isolate->heap()->undefined_value();
5548 }
5549
5550
5551 // Set a local property, even if it is READ_ONLY. If the property does not
5552 // exist, it will be added with attributes NONE.
RUNTIME_FUNCTION(MaybeObject *,Runtime_IgnoreAttributesAndSetProperty)5553 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
5554 HandleScope scope(isolate);
5555 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
5556 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5557 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5558 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5559 // Compute attributes.
5560 PropertyAttributes attributes = NONE;
5561 if (args.length() == 4) {
5562 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
5563 // Only attribute bits should be set.
5564 RUNTIME_ASSERT(
5565 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5566 attributes = static_cast<PropertyAttributes>(unchecked_value);
5567 }
5568 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5569 object, name, value, attributes);
5570 RETURN_IF_EMPTY_HANDLE(isolate, result);
5571 return *result;
5572 }
5573
5574
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeleteProperty)5575 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
5576 HandleScope scope(isolate);
5577 ASSERT(args.length() == 3);
5578 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5579 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5580 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
5581 JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode)
5582 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
5583 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode);
5584 RETURN_IF_EMPTY_HANDLE(isolate, result);
5585 return *result;
5586 }
5587
5588
HasLocalPropertyImplementation(Isolate * isolate,Handle<JSObject> object,Handle<Name> key)5589 static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate,
5590 Handle<JSObject> object,
5591 Handle<Name> key) {
5592 if (JSReceiver::HasLocalProperty(object, key)) {
5593 return isolate->heap()->true_value();
5594 }
5595 // Handle hidden prototypes. If there's a hidden prototype above this thing
5596 // then we have to check it for properties, because they are supposed to
5597 // look like they are on this object.
5598 Handle<Object> proto(object->GetPrototype(), isolate);
5599 if (proto->IsJSObject() &&
5600 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
5601 return HasLocalPropertyImplementation(isolate,
5602 Handle<JSObject>::cast(proto),
5603 key);
5604 }
5605 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5606 return isolate->heap()->false_value();
5607 }
5608
5609
RUNTIME_FUNCTION(MaybeObject *,Runtime_HasLocalProperty)5610 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
5611 HandleScope scope(isolate);
5612 ASSERT(args.length() == 2);
5613 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5614 Handle<Object> object = args.at<Object>(0);
5615
5616 uint32_t index;
5617 const bool key_is_array_index = key->AsArrayIndex(&index);
5618
5619 // Only JS objects can have properties.
5620 if (object->IsJSObject()) {
5621 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
5622 // Fast case: either the key is a real named property or it is not
5623 // an array index and there are no interceptors or hidden
5624 // prototypes.
5625 if (JSObject::HasRealNamedProperty(js_obj, key)) {
5626 ASSERT(!isolate->has_scheduled_exception());
5627 return isolate->heap()->true_value();
5628 } else {
5629 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5630 }
5631 Map* map = js_obj->map();
5632 if (!key_is_array_index &&
5633 !map->has_named_interceptor() &&
5634 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
5635 return isolate->heap()->false_value();
5636 }
5637 // Slow case.
5638 return HasLocalPropertyImplementation(isolate,
5639 Handle<JSObject>(js_obj),
5640 Handle<Name>(key));
5641 } else if (object->IsString() && key_is_array_index) {
5642 // Well, there is one exception: Handle [] on strings.
5643 Handle<String> string = Handle<String>::cast(object);
5644 if (index < static_cast<uint32_t>(string->length())) {
5645 return isolate->heap()->true_value();
5646 }
5647 }
5648 return isolate->heap()->false_value();
5649 }
5650
5651
RUNTIME_FUNCTION(MaybeObject *,Runtime_HasProperty)5652 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
5653 HandleScope scope(isolate);
5654 ASSERT(args.length() == 2);
5655 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5656 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5657
5658 bool result = JSReceiver::HasProperty(receiver, key);
5659 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5660 if (isolate->has_pending_exception()) return Failure::Exception();
5661 return isolate->heap()->ToBoolean(result);
5662 }
5663
5664
RUNTIME_FUNCTION(MaybeObject *,Runtime_HasElement)5665 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
5666 HandleScope scope(isolate);
5667 ASSERT(args.length() == 2);
5668 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5669 CONVERT_SMI_ARG_CHECKED(index, 1);
5670
5671 bool result = JSReceiver::HasElement(receiver, index);
5672 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5673 if (isolate->has_pending_exception()) return Failure::Exception();
5674 return isolate->heap()->ToBoolean(result);
5675 }
5676
5677
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsPropertyEnumerable)5678 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
5679 SealHandleScope shs(isolate);
5680 ASSERT(args.length() == 2);
5681
5682 CONVERT_ARG_CHECKED(JSObject, object, 0);
5683 CONVERT_ARG_CHECKED(Name, key, 1);
5684
5685 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
5686 if (att == ABSENT || (att & DONT_ENUM) != 0) {
5687 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5688 return isolate->heap()->false_value();
5689 }
5690 ASSERT(!isolate->has_scheduled_exception());
5691 return isolate->heap()->true_value();
5692 }
5693
5694
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetPropertyNames)5695 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
5696 HandleScope scope(isolate);
5697 ASSERT(args.length() == 1);
5698 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5699 bool threw = false;
5700 Handle<JSArray> result = GetKeysFor(object, &threw);
5701 if (threw) return Failure::Exception();
5702 return *result;
5703 }
5704
5705
5706 // Returns either a FixedArray as Runtime_GetPropertyNames,
5707 // or, if the given object has an enum cache that contains
5708 // all enumerable properties of the object and its prototypes
5709 // have none, the map of the object. This is used to speed up
5710 // the check for deletions during a for-in.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetPropertyNamesFast)5711 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
5712 SealHandleScope shs(isolate);
5713 ASSERT(args.length() == 1);
5714
5715 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
5716
5717 if (raw_object->IsSimpleEnum()) return raw_object->map();
5718
5719 HandleScope scope(isolate);
5720 Handle<JSReceiver> object(raw_object);
5721 bool threw = false;
5722 Handle<FixedArray> content =
5723 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
5724 if (threw) return Failure::Exception();
5725
5726 // Test again, since cache may have been built by preceding call.
5727 if (object->IsSimpleEnum()) return object->map();
5728
5729 return *content;
5730 }
5731
5732
5733 // Find the length of the prototype chain that is to to handled as one. If a
5734 // prototype object is hidden it is to be viewed as part of the the object it
5735 // is prototype for.
LocalPrototypeChainLength(JSObject * obj)5736 static int LocalPrototypeChainLength(JSObject* obj) {
5737 int count = 1;
5738 Object* proto = obj->GetPrototype();
5739 while (proto->IsJSObject() &&
5740 JSObject::cast(proto)->map()->is_hidden_prototype()) {
5741 count++;
5742 proto = JSObject::cast(proto)->GetPrototype();
5743 }
5744 return count;
5745 }
5746
5747
5748 // Return the names of the local named properties.
5749 // args[0]: object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetLocalPropertyNames)5750 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
5751 HandleScope scope(isolate);
5752 ASSERT(args.length() == 2);
5753 if (!args[0]->IsJSObject()) {
5754 return isolate->heap()->undefined_value();
5755 }
5756 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5757 CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1);
5758 PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC;
5759
5760 // Skip the global proxy as it has no properties and always delegates to the
5761 // real global object.
5762 if (obj->IsJSGlobalProxy()) {
5763 // Only collect names if access is permitted.
5764 if (obj->IsAccessCheckNeeded() &&
5765 !isolate->MayNamedAccess(*obj,
5766 isolate->heap()->undefined_value(),
5767 v8::ACCESS_KEYS)) {
5768 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
5769 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5770 return *isolate->factory()->NewJSArray(0);
5771 }
5772 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5773 }
5774
5775 // Find the number of objects making up this.
5776 int length = LocalPrototypeChainLength(*obj);
5777
5778 // Find the number of local properties for each of the objects.
5779 ScopedVector<int> local_property_count(length);
5780 int total_property_count = 0;
5781 Handle<JSObject> jsproto = obj;
5782 for (int i = 0; i < length; i++) {
5783 // Only collect names if access is permitted.
5784 if (jsproto->IsAccessCheckNeeded() &&
5785 !isolate->MayNamedAccess(*jsproto,
5786 isolate->heap()->undefined_value(),
5787 v8::ACCESS_KEYS)) {
5788 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5789 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5790 return *isolate->factory()->NewJSArray(0);
5791 }
5792 int n;
5793 n = jsproto->NumberOfLocalProperties(filter);
5794 local_property_count[i] = n;
5795 total_property_count += n;
5796 if (i < length - 1) {
5797 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5798 }
5799 }
5800
5801 // Allocate an array with storage for all the property names.
5802 Handle<FixedArray> names =
5803 isolate->factory()->NewFixedArray(total_property_count);
5804
5805 // Get the property names.
5806 jsproto = obj;
5807 int proto_with_hidden_properties = 0;
5808 int next_copy_index = 0;
5809 for (int i = 0; i < length; i++) {
5810 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
5811 next_copy_index += local_property_count[i];
5812 if (jsproto->HasHiddenProperties()) {
5813 proto_with_hidden_properties++;
5814 }
5815 if (i < length - 1) {
5816 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5817 }
5818 }
5819
5820 // Filter out name of hidden properties object.
5821 if (proto_with_hidden_properties > 0) {
5822 Handle<FixedArray> old_names = names;
5823 names = isolate->factory()->NewFixedArray(
5824 names->length() - proto_with_hidden_properties);
5825 int dest_pos = 0;
5826 for (int i = 0; i < total_property_count; i++) {
5827 Object* name = old_names->get(i);
5828 if (name == isolate->heap()->hidden_string()) {
5829 continue;
5830 }
5831 names->set(dest_pos++, name);
5832 }
5833 }
5834
5835 return *isolate->factory()->NewJSArrayWithElements(names);
5836 }
5837
5838
5839 // Return the names of the local indexed properties.
5840 // args[0]: object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetLocalElementNames)5841 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
5842 HandleScope scope(isolate);
5843 ASSERT(args.length() == 1);
5844 if (!args[0]->IsJSObject()) {
5845 return isolate->heap()->undefined_value();
5846 }
5847 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5848
5849 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
5850 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
5851 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
5852 return *isolate->factory()->NewJSArrayWithElements(names);
5853 }
5854
5855
5856 // Return information on whether an object has a named or indexed interceptor.
5857 // args[0]: object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetInterceptorInfo)5858 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
5859 HandleScope scope(isolate);
5860 ASSERT(args.length() == 1);
5861 if (!args[0]->IsJSObject()) {
5862 return Smi::FromInt(0);
5863 }
5864 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5865
5866 int result = 0;
5867 if (obj->HasNamedInterceptor()) result |= 2;
5868 if (obj->HasIndexedInterceptor()) result |= 1;
5869
5870 return Smi::FromInt(result);
5871 }
5872
5873
5874 // Return property names from named interceptor.
5875 // args[0]: object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetNamedInterceptorPropertyNames)5876 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
5877 HandleScope scope(isolate);
5878 ASSERT(args.length() == 1);
5879 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5880
5881 if (obj->HasNamedInterceptor()) {
5882 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5883 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5884 }
5885 return isolate->heap()->undefined_value();
5886 }
5887
5888
5889 // Return element names from indexed interceptor.
5890 // args[0]: object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetIndexedInterceptorElementNames)5891 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
5892 HandleScope scope(isolate);
5893 ASSERT(args.length() == 1);
5894 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5895
5896 if (obj->HasIndexedInterceptor()) {
5897 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5898 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5899 }
5900 return isolate->heap()->undefined_value();
5901 }
5902
5903
RUNTIME_FUNCTION(MaybeObject *,Runtime_LocalKeys)5904 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
5905 HandleScope scope(isolate);
5906 ASSERT_EQ(args.length(), 1);
5907 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
5908 Handle<JSObject> object(raw_object);
5909
5910 if (object->IsJSGlobalProxy()) {
5911 // Do access checks before going to the global object.
5912 if (object->IsAccessCheckNeeded() &&
5913 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
5914 v8::ACCESS_KEYS)) {
5915 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5916 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5917 return *isolate->factory()->NewJSArray(0);
5918 }
5919
5920 Handle<Object> proto(object->GetPrototype(), isolate);
5921 // If proxy is detached we simply return an empty array.
5922 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
5923 object = Handle<JSObject>::cast(proto);
5924 }
5925
5926 bool threw = false;
5927 Handle<FixedArray> contents =
5928 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5929 if (threw) return Failure::Exception();
5930
5931 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5932 // property array and since the result is mutable we have to create
5933 // a fresh clone on each invocation.
5934 int length = contents->length();
5935 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
5936 for (int i = 0; i < length; i++) {
5937 Object* entry = contents->get(i);
5938 if (entry->IsString()) {
5939 copy->set(i, entry);
5940 } else {
5941 ASSERT(entry->IsNumber());
5942 HandleScope scope(isolate);
5943 Handle<Object> entry_handle(entry, isolate);
5944 Handle<Object> entry_str =
5945 isolate->factory()->NumberToString(entry_handle);
5946 copy->set(i, *entry_str);
5947 }
5948 }
5949 return *isolate->factory()->NewJSArrayWithElements(copy);
5950 }
5951
5952
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetArgumentsProperty)5953 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
5954 SealHandleScope shs(isolate);
5955 ASSERT(args.length() == 1);
5956
5957 // Compute the frame holding the arguments.
5958 JavaScriptFrameIterator it(isolate);
5959 it.AdvanceToArgumentsFrame();
5960 JavaScriptFrame* frame = it.frame();
5961
5962 // Get the actual number of provided arguments.
5963 const uint32_t n = frame->ComputeParametersCount();
5964
5965 // Try to convert the key to an index. If successful and within
5966 // index return the the argument from the frame.
5967 uint32_t index;
5968 if (args[0]->ToArrayIndex(&index) && index < n) {
5969 return frame->GetParameter(index);
5970 }
5971
5972 if (args[0]->IsSymbol()) {
5973 // Lookup in the initial Object.prototype object.
5974 return isolate->initial_object_prototype()->GetProperty(
5975 Symbol::cast(args[0]));
5976 }
5977
5978 // Convert the key to a string.
5979 HandleScope scope(isolate);
5980 bool exception = false;
5981 Handle<Object> converted =
5982 Execution::ToString(isolate, args.at<Object>(0), &exception);
5983 if (exception) return Failure::Exception();
5984 Handle<String> key = Handle<String>::cast(converted);
5985
5986 // Try to convert the string key into an array index.
5987 if (key->AsArrayIndex(&index)) {
5988 if (index < n) {
5989 return frame->GetParameter(index);
5990 } else {
5991 return isolate->initial_object_prototype()->GetElement(isolate, index);
5992 }
5993 }
5994
5995 // Handle special arguments properties.
5996 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
5997 if (key->Equals(isolate->heap()->callee_string())) {
5998 JSFunction* function = frame->function();
5999 if (!function->shared()->is_classic_mode()) {
6000 return isolate->Throw(*isolate->factory()->NewTypeError(
6001 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
6002 }
6003 return function;
6004 }
6005
6006 // Lookup in the initial Object.prototype object.
6007 return isolate->initial_object_prototype()->GetProperty(*key);
6008 }
6009
6010
RUNTIME_FUNCTION(MaybeObject *,Runtime_ToFastProperties)6011 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
6012 HandleScope scope(isolate);
6013 ASSERT(args.length() == 1);
6014 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6015 if (object->IsJSObject() && !object->IsGlobalObject()) {
6016 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
6017 }
6018 return *object;
6019 }
6020
6021
RUNTIME_FUNCTION(MaybeObject *,Runtime_ToBool)6022 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
6023 SealHandleScope shs(isolate);
6024 ASSERT(args.length() == 1);
6025
6026 return isolate->heap()->ToBoolean(args[0]->BooleanValue());
6027 }
6028
6029
6030 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
6031 // Possible optimizations: put the type string into the oddballs.
RUNTIME_FUNCTION(MaybeObject *,Runtime_Typeof)6032 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
6033 SealHandleScope shs(isolate);
6034
6035 Object* obj = args[0];
6036 if (obj->IsNumber()) return isolate->heap()->number_string();
6037 HeapObject* heap_obj = HeapObject::cast(obj);
6038
6039 // typeof an undetectable object is 'undefined'
6040 if (heap_obj->map()->is_undetectable()) {
6041 return isolate->heap()->undefined_string();
6042 }
6043
6044 InstanceType instance_type = heap_obj->map()->instance_type();
6045 if (instance_type < FIRST_NONSTRING_TYPE) {
6046 return isolate->heap()->string_string();
6047 }
6048
6049 switch (instance_type) {
6050 case ODDBALL_TYPE:
6051 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
6052 return isolate->heap()->boolean_string();
6053 }
6054 if (heap_obj->IsNull()) {
6055 return FLAG_harmony_typeof
6056 ? isolate->heap()->null_string()
6057 : isolate->heap()->object_string();
6058 }
6059 ASSERT(heap_obj->IsUndefined());
6060 return isolate->heap()->undefined_string();
6061 case SYMBOL_TYPE:
6062 return isolate->heap()->symbol_string();
6063 case JS_FUNCTION_TYPE:
6064 case JS_FUNCTION_PROXY_TYPE:
6065 return isolate->heap()->function_string();
6066 default:
6067 // For any kind of object not handled above, the spec rule for
6068 // host objects gives that it is okay to return "object"
6069 return isolate->heap()->object_string();
6070 }
6071 }
6072
6073
AreDigits(const uint8_t * s,int from,int to)6074 static bool AreDigits(const uint8_t*s, int from, int to) {
6075 for (int i = from; i < to; i++) {
6076 if (s[i] < '0' || s[i] > '9') return false;
6077 }
6078
6079 return true;
6080 }
6081
6082
ParseDecimalInteger(const uint8_t * s,int from,int to)6083 static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
6084 ASSERT(to - from < 10); // Overflow is not possible.
6085 ASSERT(from < to);
6086 int d = s[from] - '0';
6087
6088 for (int i = from + 1; i < to; i++) {
6089 d = 10 * d + (s[i] - '0');
6090 }
6091
6092 return d;
6093 }
6094
6095
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringToNumber)6096 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
6097 SealHandleScope shs(isolate);
6098 ASSERT(args.length() == 1);
6099 CONVERT_ARG_CHECKED(String, subject, 0);
6100 subject->TryFlatten();
6101
6102 // Fast case: short integer or some sorts of junk values.
6103 int len = subject->length();
6104 if (subject->IsSeqOneByteString()) {
6105 if (len == 0) return Smi::FromInt(0);
6106
6107 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
6108 bool minus = (data[0] == '-');
6109 int start_pos = (minus ? 1 : 0);
6110
6111 if (start_pos == len) {
6112 return isolate->heap()->nan_value();
6113 } else if (data[start_pos] > '9') {
6114 // Fast check for a junk value. A valid string may start from a
6115 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
6116 // the 'I' character ('Infinity'). All of that have codes not greater than
6117 // '9' except 'I' and .
6118 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
6119 return isolate->heap()->nan_value();
6120 }
6121 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6122 // The maximal/minimal smi has 10 digits. If the string has less digits we
6123 // know it will fit into the smi-data type.
6124 int d = ParseDecimalInteger(data, start_pos, len);
6125 if (minus) {
6126 if (d == 0) return isolate->heap()->minus_zero_value();
6127 d = -d;
6128 } else if (!subject->HasHashCode() &&
6129 len <= String::kMaxArrayIndexSize &&
6130 (len == 1 || data[0] != '0')) {
6131 // String hash is not calculated yet but all the data are present.
6132 // Update the hash field to speed up sequential convertions.
6133 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
6134 #ifdef DEBUG
6135 subject->Hash(); // Force hash calculation.
6136 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6137 static_cast<int>(hash));
6138 #endif
6139 subject->set_hash_field(hash);
6140 }
6141 return Smi::FromInt(d);
6142 }
6143 }
6144
6145 // Slower case.
6146 int flags = ALLOW_HEX;
6147 if (FLAG_harmony_numeric_literals) {
6148 // The current spec draft has not updated "ToNumber Applied to the String
6149 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6150 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6151 }
6152 return isolate->heap()->NumberFromDouble(
6153 StringToDouble(isolate->unicode_cache(), subject, flags));
6154 }
6155
6156
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewString)6157 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
6158 SealHandleScope shs(isolate);
6159 CONVERT_SMI_ARG_CHECKED(length, 0);
6160 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6161 if (length == 0) return isolate->heap()->empty_string();
6162 if (is_one_byte) {
6163 return isolate->heap()->AllocateRawOneByteString(length);
6164 } else {
6165 return isolate->heap()->AllocateRawTwoByteString(length);
6166 }
6167 }
6168
6169
RUNTIME_FUNCTION(MaybeObject *,Runtime_TruncateString)6170 RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
6171 HandleScope scope(isolate);
6172 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
6173 CONVERT_SMI_ARG_CHECKED(new_length, 1);
6174 return *SeqString::Truncate(string, new_length);
6175 }
6176
6177
RUNTIME_FUNCTION(MaybeObject *,Runtime_URIEscape)6178 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
6179 HandleScope scope(isolate);
6180 ASSERT(args.length() == 1);
6181 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6182 Handle<String> string = FlattenGetString(source);
6183 ASSERT(string->IsFlat());
6184 Handle<String> result = string->IsOneByteRepresentationUnderneath()
6185 ? URIEscape::Escape<uint8_t>(isolate, source)
6186 : URIEscape::Escape<uc16>(isolate, source);
6187 if (result.is_null()) return Failure::OutOfMemoryException(0x12);
6188 return *result;
6189 }
6190
6191
RUNTIME_FUNCTION(MaybeObject *,Runtime_URIUnescape)6192 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
6193 HandleScope scope(isolate);
6194 ASSERT(args.length() == 1);
6195 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6196 Handle<String> string = FlattenGetString(source);
6197 ASSERT(string->IsFlat());
6198 return string->IsOneByteRepresentationUnderneath()
6199 ? *URIUnescape::Unescape<uint8_t>(isolate, source)
6200 : *URIUnescape::Unescape<uc16>(isolate, source);
6201 }
6202
6203
RUNTIME_FUNCTION(MaybeObject *,Runtime_QuoteJSONString)6204 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
6205 HandleScope scope(isolate);
6206 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
6207 ASSERT(args.length() == 1);
6208 return BasicJsonStringifier::StringifyString(isolate, string);
6209 }
6210
6211
RUNTIME_FUNCTION(MaybeObject *,Runtime_BasicJSONStringify)6212 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
6213 HandleScope scope(isolate);
6214 ASSERT(args.length() == 1);
6215 BasicJsonStringifier stringifier(isolate);
6216 return stringifier.Stringify(Handle<Object>(args[0], isolate));
6217 }
6218
6219
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringParseInt)6220 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
6221 SealHandleScope shs(isolate);
6222
6223 CONVERT_ARG_CHECKED(String, s, 0);
6224 CONVERT_SMI_ARG_CHECKED(radix, 1);
6225
6226 s->TryFlatten();
6227
6228 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
6229 double value = StringToInt(isolate->unicode_cache(), s, radix);
6230 return isolate->heap()->NumberFromDouble(value);
6231 }
6232
6233
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringParseFloat)6234 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
6235 SealHandleScope shs(isolate);
6236 CONVERT_ARG_CHECKED(String, str, 0);
6237
6238 // ECMA-262 section 15.1.2.3, empty string is NaN
6239 double value = StringToDouble(isolate->unicode_cache(),
6240 str, ALLOW_TRAILING_JUNK, OS::nan_value());
6241
6242 // Create a number object from the value.
6243 return isolate->heap()->NumberFromDouble(value);
6244 }
6245
6246
6247 template <class Converter>
ConvertCaseHelper(Isolate * isolate,String * s,String::Encoding result_encoding,int length,int input_string_length,unibrow::Mapping<Converter,128> * mapping)6248 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
6249 Isolate* isolate,
6250 String* s,
6251 String::Encoding result_encoding,
6252 int length,
6253 int input_string_length,
6254 unibrow::Mapping<Converter, 128>* mapping) {
6255 // We try this twice, once with the assumption that the result is no longer
6256 // than the input and, if that assumption breaks, again with the exact
6257 // length. This may not be pretty, but it is nicer than what was here before
6258 // and I hereby claim my vaffel-is.
6259 //
6260 // Allocate the resulting string.
6261 //
6262 // NOTE: This assumes that the upper/lower case of an ASCII
6263 // character is also ASCII. This is currently the case, but it
6264 // might break in the future if we implement more context and locale
6265 // dependent upper/lower conversions.
6266 Object* o;
6267 { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING
6268 ? isolate->heap()->AllocateRawOneByteString(length)
6269 : isolate->heap()->AllocateRawTwoByteString(length);
6270 if (!maybe_o->ToObject(&o)) return maybe_o;
6271 }
6272 String* result = String::cast(o);
6273 bool has_changed_character = false;
6274
6275 DisallowHeapAllocation no_gc;
6276
6277 // Convert all characters to upper case, assuming that they will fit
6278 // in the buffer
6279 Access<ConsStringIteratorOp> op(
6280 isolate->runtime_state()->string_iterator());
6281 StringCharacterStream stream(s, op.value());
6282 unibrow::uchar chars[Converter::kMaxWidth];
6283 // We can assume that the string is not empty
6284 uc32 current = stream.GetNext();
6285 // y with umlauts is the only character that stops fitting into one-byte
6286 // when converting to uppercase.
6287 static const uc32 yuml_code = 0xff;
6288 bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower;
6289 for (int i = 0; i < length;) {
6290 bool has_next = stream.HasMore();
6291 uc32 next = has_next ? stream.GetNext() : 0;
6292 int char_length = mapping->get(current, next, chars);
6293 if (char_length == 0) {
6294 // The case conversion of this character is the character itself.
6295 result->Set(i, current);
6296 i++;
6297 } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) {
6298 // Common case: converting the letter resulted in one character.
6299 ASSERT(static_cast<uc32>(chars[0]) != current);
6300 result->Set(i, chars[0]);
6301 has_changed_character = true;
6302 i++;
6303 } else if (length == input_string_length) {
6304 bool found_yuml = (current == yuml_code);
6305 // We've assumed that the result would be as long as the
6306 // input but here is a character that converts to several
6307 // characters. No matter, we calculate the exact length
6308 // of the result and try the whole thing again.
6309 //
6310 // Note that this leaves room for optimization. We could just
6311 // memcpy what we already have to the result string. Also,
6312 // the result string is the last object allocated we could
6313 // "realloc" it and probably, in the vast majority of cases,
6314 // extend the existing string to be able to hold the full
6315 // result.
6316 int next_length = 0;
6317 if (has_next) {
6318 next_length = mapping->get(next, 0, chars);
6319 if (next_length == 0) next_length = 1;
6320 }
6321 int current_length = i + char_length + next_length;
6322 while (stream.HasMore()) {
6323 current = stream.GetNext();
6324 found_yuml |= (current == yuml_code);
6325 // NOTE: we use 0 as the next character here because, while
6326 // the next character may affect what a character converts to,
6327 // it does not in any case affect the length of what it convert
6328 // to.
6329 int char_length = mapping->get(current, 0, chars);
6330 if (char_length == 0) char_length = 1;
6331 current_length += char_length;
6332 if (current_length > Smi::kMaxValue) {
6333 isolate->context()->mark_out_of_memory();
6334 return Failure::OutOfMemoryException(0x13);
6335 }
6336 }
6337 // Try again with the real length. Return signed if we need
6338 // to allocate a two-byte string for y-umlaut to uppercase.
6339 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length)
6340 : Smi::FromInt(current_length);
6341 } else {
6342 for (int j = 0; j < char_length; j++) {
6343 result->Set(i, chars[j]);
6344 i++;
6345 }
6346 has_changed_character = true;
6347 }
6348 current = next;
6349 }
6350 if (has_changed_character) {
6351 return result;
6352 } else {
6353 // If we didn't actually change anything in doing the conversion
6354 // we simple return the result and let the converted string
6355 // become garbage; there is no reason to keep two identical strings
6356 // alive.
6357 return s;
6358 }
6359 }
6360
6361
6362 namespace {
6363
6364 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6365 static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
6366
6367 // Given a word and two range boundaries returns a word with high bit
6368 // set in every byte iff the corresponding input byte was strictly in
6369 // the range (m, n). All the other bits in the result are cleared.
6370 // This function is only useful when it can be inlined and the
6371 // boundaries are statically known.
6372 // Requires: all bytes in the input word and the boundaries must be
6373 // ASCII (less than 0x7F).
AsciiRangeMask(uintptr_t w,char m,char n)6374 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6375 // Use strict inequalities since in edge cases the function could be
6376 // further simplified.
6377 ASSERT(0 < m && m < n);
6378 // Has high bit set in every w byte less than n.
6379 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6380 // Has high bit set in every w byte greater than m.
6381 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6382 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6383 }
6384
6385
6386 #ifdef DEBUG
CheckFastAsciiConvert(char * dst,char * src,int length,bool changed,bool is_to_lower)6387 static bool CheckFastAsciiConvert(char* dst,
6388 char* src,
6389 int length,
6390 bool changed,
6391 bool is_to_lower) {
6392 bool expected_changed = false;
6393 for (int i = 0; i < length; i++) {
6394 if (dst[i] == src[i]) continue;
6395 expected_changed = true;
6396 if (is_to_lower) {
6397 ASSERT('A' <= src[i] && src[i] <= 'Z');
6398 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6399 } else {
6400 ASSERT('a' <= src[i] && src[i] <= 'z');
6401 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6402 }
6403 }
6404 return (expected_changed == changed);
6405 }
6406 #endif
6407
6408
6409 template<class Converter>
FastAsciiConvert(char * dst,char * src,int length,bool * changed_out)6410 static bool FastAsciiConvert(char* dst,
6411 char* src,
6412 int length,
6413 bool* changed_out) {
6414 #ifdef DEBUG
6415 char* saved_dst = dst;
6416 char* saved_src = src;
6417 #endif
6418 DisallowHeapAllocation no_gc;
6419 // We rely on the distance between upper and lower case letters
6420 // being a known power of 2.
6421 ASSERT('a' - 'A' == (1 << 5));
6422 // Boundaries for the range of input characters than require conversion.
6423 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
6424 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
6425 bool changed = false;
6426 uintptr_t or_acc = 0;
6427 char* const limit = src + length;
6428 #ifdef V8_HOST_CAN_READ_UNALIGNED
6429 // Process the prefix of the input that requires no conversion one
6430 // (machine) word at a time.
6431 while (src <= limit - sizeof(uintptr_t)) {
6432 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6433 or_acc |= w;
6434 if (AsciiRangeMask(w, lo, hi) != 0) {
6435 changed = true;
6436 break;
6437 }
6438 *reinterpret_cast<uintptr_t*>(dst) = w;
6439 src += sizeof(uintptr_t);
6440 dst += sizeof(uintptr_t);
6441 }
6442 // Process the remainder of the input performing conversion when
6443 // required one word at a time.
6444 while (src <= limit - sizeof(uintptr_t)) {
6445 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6446 or_acc |= w;
6447 uintptr_t m = AsciiRangeMask(w, lo, hi);
6448 // The mask has high (7th) bit set in every byte that needs
6449 // conversion and we know that the distance between cases is
6450 // 1 << 5.
6451 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6452 src += sizeof(uintptr_t);
6453 dst += sizeof(uintptr_t);
6454 }
6455 #endif
6456 // Process the last few bytes of the input (or the whole input if
6457 // unaligned access is not supported).
6458 while (src < limit) {
6459 char c = *src;
6460 or_acc |= c;
6461 if (lo < c && c < hi) {
6462 c ^= (1 << 5);
6463 changed = true;
6464 }
6465 *dst = c;
6466 ++src;
6467 ++dst;
6468 }
6469 if ((or_acc & kAsciiMask) != 0) {
6470 return false;
6471 }
6472
6473 ASSERT(CheckFastAsciiConvert(
6474 saved_dst, saved_src, length, changed, Converter::kIsToLower));
6475
6476 *changed_out = changed;
6477 return true;
6478 }
6479
6480 } // namespace
6481
6482
6483 template <class Converter>
ConvertCase(Arguments args,Isolate * isolate,unibrow::Mapping<Converter,128> * mapping)6484 MUST_USE_RESULT static MaybeObject* ConvertCase(
6485 Arguments args,
6486 Isolate* isolate,
6487 unibrow::Mapping<Converter, 128>* mapping) {
6488 SealHandleScope shs(isolate);
6489 CONVERT_ARG_CHECKED(String, s, 0);
6490 s = s->TryFlattenGetString();
6491
6492 const int length = s->length();
6493 // Assume that the string is not empty; we need this assumption later
6494 if (length == 0) return s;
6495
6496 // Simpler handling of ASCII strings.
6497 //
6498 // NOTE: This assumes that the upper/lower case of an ASCII
6499 // character is also ASCII. This is currently the case, but it
6500 // might break in the future if we implement more context and locale
6501 // dependent upper/lower conversions.
6502 if (s->IsSeqOneByteString()) {
6503 Object* o;
6504 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length);
6505 if (!maybe_o->ToObject(&o)) return maybe_o;
6506 }
6507 SeqOneByteString* result = SeqOneByteString::cast(o);
6508 bool has_changed_character;
6509 bool is_ascii = FastAsciiConvert<Converter>(
6510 reinterpret_cast<char*>(result->GetChars()),
6511 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
6512 length,
6513 &has_changed_character);
6514 // If not ASCII, we discard the result and take the 2 byte path.
6515 if (is_ascii) {
6516 return has_changed_character ? result : s;
6517 }
6518 }
6519
6520 String::Encoding result_encoding = s->IsOneByteRepresentation()
6521 ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING;
6522 Object* answer;
6523 { MaybeObject* maybe_answer = ConvertCaseHelper(
6524 isolate, s, result_encoding, length, length, mapping);
6525 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6526 }
6527 if (answer->IsSmi()) {
6528 int new_length = Smi::cast(answer)->value();
6529 if (new_length < 0) {
6530 result_encoding = String::TWO_BYTE_ENCODING;
6531 new_length = -new_length;
6532 }
6533 MaybeObject* maybe_answer = ConvertCaseHelper(
6534 isolate, s, result_encoding, new_length, length, mapping);
6535 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6536 }
6537 return answer;
6538 }
6539
6540
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringToLowerCase)6541 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
6542 return ConvertCase(
6543 args, isolate, isolate->runtime_state()->to_lower_mapping());
6544 }
6545
6546
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringToUpperCase)6547 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
6548 return ConvertCase(
6549 args, isolate, isolate->runtime_state()->to_upper_mapping());
6550 }
6551
6552
IsTrimWhiteSpace(unibrow::uchar c)6553 static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6554 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
6555 }
6556
6557
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringTrim)6558 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
6559 SealHandleScope shs(isolate);
6560 ASSERT(args.length() == 3);
6561
6562 CONVERT_ARG_CHECKED(String, s, 0);
6563 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6564 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
6565
6566 s->TryFlatten();
6567 int length = s->length();
6568
6569 int left = 0;
6570 if (trimLeft) {
6571 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6572 left++;
6573 }
6574 }
6575
6576 int right = length;
6577 if (trimRight) {
6578 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6579 right--;
6580 }
6581 }
6582 return s->SubString(left, right);
6583 }
6584
6585
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringSplit)6586 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
6587 HandleScope handle_scope(isolate);
6588 ASSERT(args.length() == 3);
6589 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6590 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
6591 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6592
6593 int subject_length = subject->length();
6594 int pattern_length = pattern->length();
6595 RUNTIME_ASSERT(pattern_length > 0);
6596
6597 if (limit == 0xffffffffu) {
6598 Handle<Object> cached_answer(
6599 RegExpResultsCache::Lookup(isolate->heap(),
6600 *subject,
6601 *pattern,
6602 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6603 isolate);
6604 if (*cached_answer != Smi::FromInt(0)) {
6605 // The cache FixedArray is a COW-array and can therefore be reused.
6606 Handle<JSArray> result =
6607 isolate->factory()->NewJSArrayWithElements(
6608 Handle<FixedArray>::cast(cached_answer));
6609 return *result;
6610 }
6611 }
6612
6613 // The limit can be very large (0xffffffffu), but since the pattern
6614 // isn't empty, we can never create more parts than ~half the length
6615 // of the subject.
6616
6617 if (!subject->IsFlat()) FlattenString(subject);
6618
6619 static const int kMaxInitialListCapacity = 16;
6620
6621 ZoneScope zone_scope(isolate->runtime_zone());
6622
6623 // Find (up to limit) indices of separator and end-of-string in subject
6624 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6625 ZoneList<int> indices(initial_capacity, zone_scope.zone());
6626 if (!pattern->IsFlat()) FlattenString(pattern);
6627
6628 FindStringIndicesDispatch(isolate, *subject, *pattern,
6629 &indices, limit, zone_scope.zone());
6630
6631 if (static_cast<uint32_t>(indices.length()) < limit) {
6632 indices.Add(subject_length, zone_scope.zone());
6633 }
6634
6635 // The list indices now contains the end of each part to create.
6636
6637 // Create JSArray of substrings separated by separator.
6638 int part_count = indices.length();
6639
6640 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
6641 JSObject::EnsureCanContainHeapObjectElements(result);
6642 result->set_length(Smi::FromInt(part_count));
6643
6644 ASSERT(result->HasFastObjectElements());
6645
6646 if (part_count == 1 && indices.at(0) == subject_length) {
6647 FixedArray::cast(result->elements())->set(0, *subject);
6648 return *result;
6649 }
6650
6651 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6652 int part_start = 0;
6653 for (int i = 0; i < part_count; i++) {
6654 HandleScope local_loop_handle(isolate);
6655 int part_end = indices.at(i);
6656 Handle<String> substring =
6657 isolate->factory()->NewProperSubString(subject, part_start, part_end);
6658 elements->set(i, *substring);
6659 part_start = part_end + pattern_length;
6660 }
6661
6662 if (limit == 0xffffffffu) {
6663 if (result->HasFastObjectElements()) {
6664 RegExpResultsCache::Enter(isolate->heap(),
6665 *subject,
6666 *pattern,
6667 *elements,
6668 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
6669 }
6670 }
6671
6672 return *result;
6673 }
6674
6675
6676 // Copies ASCII characters to the given fixed array looking up
6677 // one-char strings in the cache. Gives up on the first char that is
6678 // not in the cache and fills the remainder with smi zeros. Returns
6679 // the length of the successfully copied prefix.
CopyCachedAsciiCharsToArray(Heap * heap,const uint8_t * chars,FixedArray * elements,int length)6680 static int CopyCachedAsciiCharsToArray(Heap* heap,
6681 const uint8_t* chars,
6682 FixedArray* elements,
6683 int length) {
6684 DisallowHeapAllocation no_gc;
6685 FixedArray* ascii_cache = heap->single_character_string_cache();
6686 Object* undefined = heap->undefined_value();
6687 int i;
6688 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
6689 for (i = 0; i < length; ++i) {
6690 Object* value = ascii_cache->get(chars[i]);
6691 if (value == undefined) break;
6692 elements->set(i, value, mode);
6693 }
6694 if (i < length) {
6695 ASSERT(Smi::FromInt(0) == 0);
6696 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6697 }
6698 #ifdef DEBUG
6699 for (int j = 0; j < length; ++j) {
6700 Object* element = elements->get(j);
6701 ASSERT(element == Smi::FromInt(0) ||
6702 (element->IsString() && String::cast(element)->LooksValid()));
6703 }
6704 #endif
6705 return i;
6706 }
6707
6708
6709 // Converts a String to JSArray.
6710 // For example, "foo" => ["f", "o", "o"].
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringToArray)6711 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
6712 HandleScope scope(isolate);
6713 ASSERT(args.length() == 2);
6714 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6715 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
6716
6717 s = FlattenGetString(s);
6718 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
6719
6720 Handle<FixedArray> elements;
6721 int position = 0;
6722 if (s->IsFlat() && s->IsOneByteRepresentation()) {
6723 // Try using cached chars where possible.
6724 Object* obj;
6725 { MaybeObject* maybe_obj =
6726 isolate->heap()->AllocateUninitializedFixedArray(length);
6727 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6728 }
6729 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
6730 DisallowHeapAllocation no_gc;
6731 String::FlatContent content = s->GetFlatContent();
6732 if (content.IsAscii()) {
6733 Vector<const uint8_t> chars = content.ToOneByteVector();
6734 // Note, this will initialize all elements (not only the prefix)
6735 // to prevent GC from seeing partially initialized array.
6736 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6737 chars.start(),
6738 *elements,
6739 length);
6740 } else {
6741 MemsetPointer(elements->data_start(),
6742 isolate->heap()->undefined_value(),
6743 length);
6744 }
6745 } else {
6746 elements = isolate->factory()->NewFixedArray(length);
6747 }
6748 for (int i = position; i < length; ++i) {
6749 Handle<Object> str =
6750 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
6751 elements->set(i, *str);
6752 }
6753
6754 #ifdef DEBUG
6755 for (int i = 0; i < length; ++i) {
6756 ASSERT(String::cast(elements->get(i))->length() == 1);
6757 }
6758 #endif
6759
6760 return *isolate->factory()->NewJSArrayWithElements(elements);
6761 }
6762
6763
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewStringWrapper)6764 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
6765 SealHandleScope shs(isolate);
6766 ASSERT(args.length() == 1);
6767 CONVERT_ARG_CHECKED(String, value, 0);
6768 return value->ToObject(isolate);
6769 }
6770
6771
IsUpperCaseChar(RuntimeState * runtime_state,uint16_t ch)6772 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
6773 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
6774 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
6775 return char_length == 0;
6776 }
6777
6778
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToString)6779 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
6780 SealHandleScope shs(isolate);
6781 ASSERT(args.length() == 1);
6782
6783 Object* number = args[0];
6784 RUNTIME_ASSERT(number->IsNumber());
6785
6786 return isolate->heap()->NumberToString(number);
6787 }
6788
6789
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToStringSkipCache)6790 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
6791 SealHandleScope shs(isolate);
6792 ASSERT(args.length() == 1);
6793
6794 Object* number = args[0];
6795 RUNTIME_ASSERT(number->IsNumber());
6796
6797 return isolate->heap()->NumberToString(
6798 number, false, isolate->heap()->GetPretenureMode());
6799 }
6800
6801
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToInteger)6802 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
6803 SealHandleScope shs(isolate);
6804 ASSERT(args.length() == 1);
6805
6806 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6807
6808 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6809 if (number > 0 && number <= Smi::kMaxValue) {
6810 return Smi::FromInt(static_cast<int>(number));
6811 }
6812 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6813 }
6814
6815
6816 // ES6 draft 9.1.11
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToPositiveInteger)6817 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) {
6818 SealHandleScope shs(isolate);
6819 ASSERT(args.length() == 1);
6820
6821 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6822
6823 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6824 if (number > 0 && number <= Smi::kMaxValue) {
6825 return Smi::FromInt(static_cast<int>(number));
6826 }
6827 if (number <= 0) {
6828 return Smi::FromInt(0);
6829 }
6830 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6831 }
6832
6833
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToIntegerMapMinusZero)6834 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
6835 SealHandleScope shs(isolate);
6836 ASSERT(args.length() == 1);
6837
6838 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6839
6840 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6841 if (number > 0 && number <= Smi::kMaxValue) {
6842 return Smi::FromInt(static_cast<int>(number));
6843 }
6844
6845 double double_value = DoubleToInteger(number);
6846 // Map both -0 and +0 to +0.
6847 if (double_value == 0) double_value = 0;
6848
6849 return isolate->heap()->NumberFromDouble(double_value);
6850 }
6851
6852
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToJSUint32)6853 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
6854 SealHandleScope shs(isolate);
6855 ASSERT(args.length() == 1);
6856
6857 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
6858 return isolate->heap()->NumberFromUint32(number);
6859 }
6860
6861
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToJSInt32)6862 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
6863 SealHandleScope shs(isolate);
6864 ASSERT(args.length() == 1);
6865
6866 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6867
6868 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6869 if (number > 0 && number <= Smi::kMaxValue) {
6870 return Smi::FromInt(static_cast<int>(number));
6871 }
6872 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
6873 }
6874
6875
6876 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
6877 // a small integer.
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberToSmi)6878 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
6879 SealHandleScope shs(isolate);
6880 ASSERT(args.length() == 1);
6881
6882 Object* obj = args[0];
6883 if (obj->IsSmi()) {
6884 return obj;
6885 }
6886 if (obj->IsHeapNumber()) {
6887 double value = HeapNumber::cast(obj)->value();
6888 int int_value = FastD2I(value);
6889 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6890 return Smi::FromInt(int_value);
6891 }
6892 }
6893 return isolate->heap()->nan_value();
6894 }
6895
6896
RUNTIME_FUNCTION(MaybeObject *,Runtime_AllocateHeapNumber)6897 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
6898 SealHandleScope shs(isolate);
6899 ASSERT(args.length() == 0);
6900 return isolate->heap()->AllocateHeapNumber(0);
6901 }
6902
6903
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberAdd)6904 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
6905 SealHandleScope shs(isolate);
6906 ASSERT(args.length() == 2);
6907
6908 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6909 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6910 return isolate->heap()->NumberFromDouble(x + y);
6911 }
6912
6913
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberSub)6914 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
6915 SealHandleScope shs(isolate);
6916 ASSERT(args.length() == 2);
6917
6918 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6919 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6920 return isolate->heap()->NumberFromDouble(x - y);
6921 }
6922
6923
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberMul)6924 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
6925 SealHandleScope shs(isolate);
6926 ASSERT(args.length() == 2);
6927
6928 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6929 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6930 return isolate->heap()->NumberFromDouble(x * y);
6931 }
6932
6933
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberUnaryMinus)6934 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
6935 SealHandleScope shs(isolate);
6936 ASSERT(args.length() == 1);
6937
6938 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6939 return isolate->heap()->NumberFromDouble(-x);
6940 }
6941
6942
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberAlloc)6943 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
6944 SealHandleScope shs(isolate);
6945 ASSERT(args.length() == 0);
6946
6947 return isolate->heap()->NumberFromDouble(9876543210.0);
6948 }
6949
6950
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberDiv)6951 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
6952 SealHandleScope shs(isolate);
6953 ASSERT(args.length() == 2);
6954
6955 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6956 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6957 return isolate->heap()->NumberFromDouble(x / y);
6958 }
6959
6960
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberMod)6961 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
6962 SealHandleScope shs(isolate);
6963 ASSERT(args.length() == 2);
6964
6965 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6966 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6967
6968 x = modulo(x, y);
6969 // NumberFromDouble may return a Smi instead of a Number object
6970 return isolate->heap()->NumberFromDouble(x);
6971 }
6972
6973
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberImul)6974 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
6975 SealHandleScope shs(isolate);
6976 ASSERT(args.length() == 2);
6977
6978 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6979 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6980 return isolate->heap()->NumberFromInt32(x * y);
6981 }
6982
6983
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringAdd)6984 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
6985 SealHandleScope shs(isolate);
6986 ASSERT(args.length() == 2);
6987 CONVERT_ARG_CHECKED(String, str1, 0);
6988 CONVERT_ARG_CHECKED(String, str2, 1);
6989 isolate->counters()->string_add_runtime()->Increment();
6990 return isolate->heap()->AllocateConsString(str1, str2);
6991 }
6992
6993
6994 template <typename sinkchar>
StringBuilderConcatHelper(String * special,sinkchar * sink,FixedArray * fixed_array,int array_length)6995 static inline void StringBuilderConcatHelper(String* special,
6996 sinkchar* sink,
6997 FixedArray* fixed_array,
6998 int array_length) {
6999 int position = 0;
7000 for (int i = 0; i < array_length; i++) {
7001 Object* element = fixed_array->get(i);
7002 if (element->IsSmi()) {
7003 // Smi encoding of position and length.
7004 int encoded_slice = Smi::cast(element)->value();
7005 int pos;
7006 int len;
7007 if (encoded_slice > 0) {
7008 // Position and length encoded in one smi.
7009 pos = StringBuilderSubstringPosition::decode(encoded_slice);
7010 len = StringBuilderSubstringLength::decode(encoded_slice);
7011 } else {
7012 // Position and length encoded in two smis.
7013 Object* obj = fixed_array->get(++i);
7014 ASSERT(obj->IsSmi());
7015 pos = Smi::cast(obj)->value();
7016 len = -encoded_slice;
7017 }
7018 String::WriteToFlat(special,
7019 sink + position,
7020 pos,
7021 pos + len);
7022 position += len;
7023 } else {
7024 String* string = String::cast(element);
7025 int element_length = string->length();
7026 String::WriteToFlat(string, sink + position, 0, element_length);
7027 position += element_length;
7028 }
7029 }
7030 }
7031
7032
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringBuilderConcat)7033 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
7034 HandleScope scope(isolate);
7035 ASSERT(args.length() == 3);
7036 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
7037 if (!args[1]->IsSmi()) {
7038 isolate->context()->mark_out_of_memory();
7039 return Failure::OutOfMemoryException(0x14);
7040 }
7041 int array_length = args.smi_at(1);
7042 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
7043
7044 // This assumption is used by the slice encoding in one or two smis.
7045 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7046
7047 JSObject::EnsureCanContainHeapObjectElements(array);
7048
7049 int special_length = special->length();
7050 if (!array->HasFastObjectElements()) {
7051 return isolate->Throw(isolate->heap()->illegal_argument_string());
7052 }
7053 FixedArray* fixed_array = FixedArray::cast(array->elements());
7054 if (fixed_array->length() < array_length) {
7055 array_length = fixed_array->length();
7056 }
7057
7058 if (array_length == 0) {
7059 return isolate->heap()->empty_string();
7060 } else if (array_length == 1) {
7061 Object* first = fixed_array->get(0);
7062 if (first->IsString()) return first;
7063 }
7064
7065 bool one_byte = special->HasOnlyOneByteChars();
7066 int position = 0;
7067 for (int i = 0; i < array_length; i++) {
7068 int increment = 0;
7069 Object* elt = fixed_array->get(i);
7070 if (elt->IsSmi()) {
7071 // Smi encoding of position and length.
7072 int smi_value = Smi::cast(elt)->value();
7073 int pos;
7074 int len;
7075 if (smi_value > 0) {
7076 // Position and length encoded in one smi.
7077 pos = StringBuilderSubstringPosition::decode(smi_value);
7078 len = StringBuilderSubstringLength::decode(smi_value);
7079 } else {
7080 // Position and length encoded in two smis.
7081 len = -smi_value;
7082 // Get the position and check that it is a positive smi.
7083 i++;
7084 if (i >= array_length) {
7085 return isolate->Throw(isolate->heap()->illegal_argument_string());
7086 }
7087 Object* next_smi = fixed_array->get(i);
7088 if (!next_smi->IsSmi()) {
7089 return isolate->Throw(isolate->heap()->illegal_argument_string());
7090 }
7091 pos = Smi::cast(next_smi)->value();
7092 if (pos < 0) {
7093 return isolate->Throw(isolate->heap()->illegal_argument_string());
7094 }
7095 }
7096 ASSERT(pos >= 0);
7097 ASSERT(len >= 0);
7098 if (pos > special_length || len > special_length - pos) {
7099 return isolate->Throw(isolate->heap()->illegal_argument_string());
7100 }
7101 increment = len;
7102 } else if (elt->IsString()) {
7103 String* element = String::cast(elt);
7104 int element_length = element->length();
7105 increment = element_length;
7106 if (one_byte && !element->HasOnlyOneByteChars()) {
7107 one_byte = false;
7108 }
7109 } else {
7110 ASSERT(!elt->IsTheHole());
7111 return isolate->Throw(isolate->heap()->illegal_argument_string());
7112 }
7113 if (increment > String::kMaxLength - position) {
7114 isolate->context()->mark_out_of_memory();
7115 return Failure::OutOfMemoryException(0x15);
7116 }
7117 position += increment;
7118 }
7119
7120 int length = position;
7121 Object* object;
7122
7123 if (one_byte) {
7124 { MaybeObject* maybe_object =
7125 isolate->heap()->AllocateRawOneByteString(length);
7126 if (!maybe_object->ToObject(&object)) return maybe_object;
7127 }
7128 SeqOneByteString* answer = SeqOneByteString::cast(object);
7129 StringBuilderConcatHelper(*special,
7130 answer->GetChars(),
7131 fixed_array,
7132 array_length);
7133 return answer;
7134 } else {
7135 { MaybeObject* maybe_object =
7136 isolate->heap()->AllocateRawTwoByteString(length);
7137 if (!maybe_object->ToObject(&object)) return maybe_object;
7138 }
7139 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7140 StringBuilderConcatHelper(*special,
7141 answer->GetChars(),
7142 fixed_array,
7143 array_length);
7144 return answer;
7145 }
7146 }
7147
7148
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringBuilderJoin)7149 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
7150 SealHandleScope shs(isolate);
7151 ASSERT(args.length() == 3);
7152 CONVERT_ARG_CHECKED(JSArray, array, 0);
7153 if (!args[1]->IsSmi()) {
7154 isolate->context()->mark_out_of_memory();
7155 return Failure::OutOfMemoryException(0x16);
7156 }
7157 int array_length = args.smi_at(1);
7158 CONVERT_ARG_CHECKED(String, separator, 2);
7159
7160 if (!array->HasFastObjectElements()) {
7161 return isolate->Throw(isolate->heap()->illegal_argument_string());
7162 }
7163 FixedArray* fixed_array = FixedArray::cast(array->elements());
7164 if (fixed_array->length() < array_length) {
7165 array_length = fixed_array->length();
7166 }
7167
7168 if (array_length == 0) {
7169 return isolate->heap()->empty_string();
7170 } else if (array_length == 1) {
7171 Object* first = fixed_array->get(0);
7172 if (first->IsString()) return first;
7173 }
7174
7175 int separator_length = separator->length();
7176 int max_nof_separators =
7177 (String::kMaxLength + separator_length - 1) / separator_length;
7178 if (max_nof_separators < (array_length - 1)) {
7179 isolate->context()->mark_out_of_memory();
7180 return Failure::OutOfMemoryException(0x17);
7181 }
7182 int length = (array_length - 1) * separator_length;
7183 for (int i = 0; i < array_length; i++) {
7184 Object* element_obj = fixed_array->get(i);
7185 if (!element_obj->IsString()) {
7186 // TODO(1161): handle this case.
7187 return isolate->Throw(isolate->heap()->illegal_argument_string());
7188 }
7189 String* element = String::cast(element_obj);
7190 int increment = element->length();
7191 if (increment > String::kMaxLength - length) {
7192 isolate->context()->mark_out_of_memory();
7193 return Failure::OutOfMemoryException(0x18);
7194 }
7195 length += increment;
7196 }
7197
7198 Object* object;
7199 { MaybeObject* maybe_object =
7200 isolate->heap()->AllocateRawTwoByteString(length);
7201 if (!maybe_object->ToObject(&object)) return maybe_object;
7202 }
7203 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7204
7205 uc16* sink = answer->GetChars();
7206 #ifdef DEBUG
7207 uc16* end = sink + length;
7208 #endif
7209
7210 String* first = String::cast(fixed_array->get(0));
7211 int first_length = first->length();
7212 String::WriteToFlat(first, sink, 0, first_length);
7213 sink += first_length;
7214
7215 for (int i = 1; i < array_length; i++) {
7216 ASSERT(sink + separator_length <= end);
7217 String::WriteToFlat(separator, sink, 0, separator_length);
7218 sink += separator_length;
7219
7220 String* element = String::cast(fixed_array->get(i));
7221 int element_length = element->length();
7222 ASSERT(sink + element_length <= end);
7223 String::WriteToFlat(element, sink, 0, element_length);
7224 sink += element_length;
7225 }
7226 ASSERT(sink == end);
7227
7228 // Use %_FastAsciiArrayJoin instead.
7229 ASSERT(!answer->IsOneByteRepresentation());
7230 return answer;
7231 }
7232
7233 template <typename Char>
JoinSparseArrayWithSeparator(FixedArray * elements,int elements_length,uint32_t array_length,String * separator,Vector<Char> buffer)7234 static void JoinSparseArrayWithSeparator(FixedArray* elements,
7235 int elements_length,
7236 uint32_t array_length,
7237 String* separator,
7238 Vector<Char> buffer) {
7239 int previous_separator_position = 0;
7240 int separator_length = separator->length();
7241 int cursor = 0;
7242 for (int i = 0; i < elements_length; i += 2) {
7243 int position = NumberToInt32(elements->get(i));
7244 String* string = String::cast(elements->get(i + 1));
7245 int string_length = string->length();
7246 if (string->length() > 0) {
7247 while (previous_separator_position < position) {
7248 String::WriteToFlat<Char>(separator, &buffer[cursor],
7249 0, separator_length);
7250 cursor += separator_length;
7251 previous_separator_position++;
7252 }
7253 String::WriteToFlat<Char>(string, &buffer[cursor],
7254 0, string_length);
7255 cursor += string->length();
7256 }
7257 }
7258 if (separator_length > 0) {
7259 // Array length must be representable as a signed 32-bit number,
7260 // otherwise the total string length would have been too large.
7261 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7262 int last_array_index = static_cast<int>(array_length - 1);
7263 while (previous_separator_position < last_array_index) {
7264 String::WriteToFlat<Char>(separator, &buffer[cursor],
7265 0, separator_length);
7266 cursor += separator_length;
7267 previous_separator_position++;
7268 }
7269 }
7270 ASSERT(cursor <= buffer.length());
7271 }
7272
7273
RUNTIME_FUNCTION(MaybeObject *,Runtime_SparseJoinWithSeparator)7274 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
7275 SealHandleScope shs(isolate);
7276 ASSERT(args.length() == 3);
7277 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
7278 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
7279 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
7280 CONVERT_ARG_CHECKED(String, separator, 2);
7281 // elements_array is fast-mode JSarray of alternating positions
7282 // (increasing order) and strings.
7283 // array_length is length of original array (used to add separators);
7284 // separator is string to put between elements. Assumed to be non-empty.
7285
7286 // Find total length of join result.
7287 int string_length = 0;
7288 bool is_ascii = separator->IsOneByteRepresentation();
7289 int max_string_length;
7290 if (is_ascii) {
7291 max_string_length = SeqOneByteString::kMaxLength;
7292 } else {
7293 max_string_length = SeqTwoByteString::kMaxLength;
7294 }
7295 bool overflow = false;
7296 CONVERT_NUMBER_CHECKED(int, elements_length,
7297 Int32, elements_array->length());
7298 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7299 FixedArray* elements = FixedArray::cast(elements_array->elements());
7300 for (int i = 0; i < elements_length; i += 2) {
7301 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7302 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7303 String* string = String::cast(elements->get(i + 1));
7304 int length = string->length();
7305 if (is_ascii && !string->IsOneByteRepresentation()) {
7306 is_ascii = false;
7307 max_string_length = SeqTwoByteString::kMaxLength;
7308 }
7309 if (length > max_string_length ||
7310 max_string_length - length < string_length) {
7311 overflow = true;
7312 break;
7313 }
7314 string_length += length;
7315 }
7316 int separator_length = separator->length();
7317 if (!overflow && separator_length > 0) {
7318 if (array_length <= 0x7fffffffu) {
7319 int separator_count = static_cast<int>(array_length) - 1;
7320 int remaining_length = max_string_length - string_length;
7321 if ((remaining_length / separator_length) >= separator_count) {
7322 string_length += separator_length * (array_length - 1);
7323 } else {
7324 // Not room for the separators within the maximal string length.
7325 overflow = true;
7326 }
7327 } else {
7328 // Nonempty separator and at least 2^31-1 separators necessary
7329 // means that the string is too large to create.
7330 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7331 overflow = true;
7332 }
7333 }
7334 if (overflow) {
7335 // Throw OutOfMemory exception for creating too large a string.
7336 V8::FatalProcessOutOfMemory("Array join result too large.");
7337 }
7338
7339 if (is_ascii) {
7340 MaybeObject* result_allocation =
7341 isolate->heap()->AllocateRawOneByteString(string_length);
7342 if (result_allocation->IsFailure()) return result_allocation;
7343 SeqOneByteString* result_string =
7344 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
7345 JoinSparseArrayWithSeparator<uint8_t>(elements,
7346 elements_length,
7347 array_length,
7348 separator,
7349 Vector<uint8_t>(
7350 result_string->GetChars(),
7351 string_length));
7352 return result_string;
7353 } else {
7354 MaybeObject* result_allocation =
7355 isolate->heap()->AllocateRawTwoByteString(string_length);
7356 if (result_allocation->IsFailure()) return result_allocation;
7357 SeqTwoByteString* result_string =
7358 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7359 JoinSparseArrayWithSeparator<uc16>(elements,
7360 elements_length,
7361 array_length,
7362 separator,
7363 Vector<uc16>(result_string->GetChars(),
7364 string_length));
7365 return result_string;
7366 }
7367 }
7368
7369
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberOr)7370 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
7371 SealHandleScope shs(isolate);
7372 ASSERT(args.length() == 2);
7373
7374 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7375 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7376 return isolate->heap()->NumberFromInt32(x | y);
7377 }
7378
7379
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberAnd)7380 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
7381 SealHandleScope shs(isolate);
7382 ASSERT(args.length() == 2);
7383
7384 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7385 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7386 return isolate->heap()->NumberFromInt32(x & y);
7387 }
7388
7389
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberXor)7390 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
7391 SealHandleScope shs(isolate);
7392 ASSERT(args.length() == 2);
7393
7394 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7395 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7396 return isolate->heap()->NumberFromInt32(x ^ y);
7397 }
7398
7399
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberShl)7400 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
7401 SealHandleScope shs(isolate);
7402 ASSERT(args.length() == 2);
7403
7404 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7405 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7406 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
7407 }
7408
7409
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberShr)7410 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
7411 SealHandleScope shs(isolate);
7412 ASSERT(args.length() == 2);
7413
7414 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7415 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7416 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
7417 }
7418
7419
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberSar)7420 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
7421 SealHandleScope shs(isolate);
7422 ASSERT(args.length() == 2);
7423
7424 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7425 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7426 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
7427 }
7428
7429
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberEquals)7430 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
7431 SealHandleScope shs(isolate);
7432 ASSERT(args.length() == 2);
7433
7434 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7435 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7436 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7437 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
7438 if (x == y) return Smi::FromInt(EQUAL);
7439 Object* result;
7440 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7441 result = Smi::FromInt(EQUAL);
7442 } else {
7443 result = Smi::FromInt(NOT_EQUAL);
7444 }
7445 return result;
7446 }
7447
7448
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringEquals)7449 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
7450 SealHandleScope shs(isolate);
7451 ASSERT(args.length() == 2);
7452
7453 CONVERT_ARG_CHECKED(String, x, 0);
7454 CONVERT_ARG_CHECKED(String, y, 1);
7455
7456 bool not_equal = !x->Equals(y);
7457 // This is slightly convoluted because the value that signifies
7458 // equality is 0 and inequality is 1 so we have to negate the result
7459 // from String::Equals.
7460 ASSERT(not_equal == 0 || not_equal == 1);
7461 STATIC_CHECK(EQUAL == 0);
7462 STATIC_CHECK(NOT_EQUAL == 1);
7463 return Smi::FromInt(not_equal);
7464 }
7465
7466
RUNTIME_FUNCTION(MaybeObject *,Runtime_NumberCompare)7467 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
7468 SealHandleScope shs(isolate);
7469 ASSERT(args.length() == 3);
7470
7471 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7472 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7473 if (std::isnan(x) || std::isnan(y)) return args[2];
7474 if (x == y) return Smi::FromInt(EQUAL);
7475 if (isless(x, y)) return Smi::FromInt(LESS);
7476 return Smi::FromInt(GREATER);
7477 }
7478
7479
7480 // Compare two Smis as if they were converted to strings and then
7481 // compared lexicographically.
RUNTIME_FUNCTION(MaybeObject *,Runtime_SmiLexicographicCompare)7482 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
7483 SealHandleScope shs(isolate);
7484 ASSERT(args.length() == 2);
7485 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7486 CONVERT_SMI_ARG_CHECKED(y_value, 1);
7487
7488 // If the integers are equal so are the string representations.
7489 if (x_value == y_value) return Smi::FromInt(EQUAL);
7490
7491 // If one of the integers is zero the normal integer order is the
7492 // same as the lexicographic order of the string representations.
7493 if (x_value == 0 || y_value == 0)
7494 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
7495
7496 // If only one of the integers is negative the negative number is
7497 // smallest because the char code of '-' is less than the char code
7498 // of any digit. Otherwise, we make both values positive.
7499
7500 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7501 // architectures using 32-bit Smis.
7502 uint32_t x_scaled = x_value;
7503 uint32_t y_scaled = y_value;
7504 if (x_value < 0 || y_value < 0) {
7505 if (y_value >= 0) return Smi::FromInt(LESS);
7506 if (x_value >= 0) return Smi::FromInt(GREATER);
7507 x_scaled = -x_value;
7508 y_scaled = -y_value;
7509 }
7510
7511 static const uint32_t kPowersOf10[] = {
7512 1, 10, 100, 1000, 10*1000, 100*1000,
7513 1000*1000, 10*1000*1000, 100*1000*1000,
7514 1000*1000*1000
7515 };
7516
7517 // If the integers have the same number of decimal digits they can be
7518 // compared directly as the numeric order is the same as the
7519 // lexicographic order. If one integer has fewer digits, it is scaled
7520 // by some power of 10 to have the same number of digits as the longer
7521 // integer. If the scaled integers are equal it means the shorter
7522 // integer comes first in the lexicographic order.
7523
7524 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7525 int x_log2 = IntegerLog2(x_scaled);
7526 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7527 x_log10 -= x_scaled < kPowersOf10[x_log10];
7528
7529 int y_log2 = IntegerLog2(y_scaled);
7530 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7531 y_log10 -= y_scaled < kPowersOf10[y_log10];
7532
7533 int tie = EQUAL;
7534
7535 if (x_log10 < y_log10) {
7536 // X has fewer digits. We would like to simply scale up X but that
7537 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7538 // be scaled up to 9_000_000_000. So we scale up by the next
7539 // smallest power and scale down Y to drop one digit. It is OK to
7540 // drop one digit from the longer integer since the final digit is
7541 // past the length of the shorter integer.
7542 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7543 y_scaled /= 10;
7544 tie = LESS;
7545 } else if (y_log10 < x_log10) {
7546 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7547 x_scaled /= 10;
7548 tie = GREATER;
7549 }
7550
7551 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7552 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7553 return Smi::FromInt(tie);
7554 }
7555
7556
StringCharacterStreamCompare(RuntimeState * state,String * x,String * y)7557 static Object* StringCharacterStreamCompare(RuntimeState* state,
7558 String* x,
7559 String* y) {
7560 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
7561 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
7562 while (stream_x.HasMore() && stream_y.HasMore()) {
7563 int d = stream_x.GetNext() - stream_y.GetNext();
7564 if (d < 0) return Smi::FromInt(LESS);
7565 else if (d > 0) return Smi::FromInt(GREATER);
7566 }
7567
7568 // x is (non-trivial) prefix of y:
7569 if (stream_y.HasMore()) return Smi::FromInt(LESS);
7570 // y is prefix of x:
7571 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
7572 }
7573
7574
FlatStringCompare(String * x,String * y)7575 static Object* FlatStringCompare(String* x, String* y) {
7576 ASSERT(x->IsFlat());
7577 ASSERT(y->IsFlat());
7578 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7579 int prefix_length = x->length();
7580 if (y->length() < prefix_length) {
7581 prefix_length = y->length();
7582 equal_prefix_result = Smi::FromInt(GREATER);
7583 } else if (y->length() > prefix_length) {
7584 equal_prefix_result = Smi::FromInt(LESS);
7585 }
7586 int r;
7587 DisallowHeapAllocation no_gc;
7588 String::FlatContent x_content = x->GetFlatContent();
7589 String::FlatContent y_content = y->GetFlatContent();
7590 if (x_content.IsAscii()) {
7591 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
7592 if (y_content.IsAscii()) {
7593 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7594 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7595 } else {
7596 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7597 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7598 }
7599 } else {
7600 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7601 if (y_content.IsAscii()) {
7602 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7603 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7604 } else {
7605 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7606 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7607 }
7608 }
7609 Object* result;
7610 if (r == 0) {
7611 result = equal_prefix_result;
7612 } else {
7613 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7614 }
7615 ASSERT(result ==
7616 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
7617 return result;
7618 }
7619
7620
RUNTIME_FUNCTION(MaybeObject *,Runtime_StringCompare)7621 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
7622 SealHandleScope shs(isolate);
7623 ASSERT(args.length() == 2);
7624
7625 CONVERT_ARG_CHECKED(String, x, 0);
7626 CONVERT_ARG_CHECKED(String, y, 1);
7627
7628 isolate->counters()->string_compare_runtime()->Increment();
7629
7630 // A few fast case tests before we flatten.
7631 if (x == y) return Smi::FromInt(EQUAL);
7632 if (y->length() == 0) {
7633 if (x->length() == 0) return Smi::FromInt(EQUAL);
7634 return Smi::FromInt(GREATER);
7635 } else if (x->length() == 0) {
7636 return Smi::FromInt(LESS);
7637 }
7638
7639 int d = x->Get(0) - y->Get(0);
7640 if (d < 0) return Smi::FromInt(LESS);
7641 else if (d > 0) return Smi::FromInt(GREATER);
7642
7643 Object* obj;
7644 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
7645 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7646 }
7647 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
7648 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7649 }
7650
7651 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
7652 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
7653 }
7654
7655
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_acos)7656 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
7657 SealHandleScope shs(isolate);
7658 ASSERT(args.length() == 1);
7659 isolate->counters()->math_acos()->Increment();
7660
7661 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7662 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
7663 }
7664
7665
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_asin)7666 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
7667 SealHandleScope shs(isolate);
7668 ASSERT(args.length() == 1);
7669 isolate->counters()->math_asin()->Increment();
7670
7671 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7672 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
7673 }
7674
7675
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_atan)7676 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
7677 SealHandleScope shs(isolate);
7678 ASSERT(args.length() == 1);
7679 isolate->counters()->math_atan()->Increment();
7680
7681 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7682 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
7683 }
7684
7685
7686 static const double kPiDividedBy4 = 0.78539816339744830962;
7687
7688
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_atan2)7689 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
7690 SealHandleScope shs(isolate);
7691 ASSERT(args.length() == 2);
7692 isolate->counters()->math_atan2()->Increment();
7693
7694 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7695 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7696 double result;
7697 if (std::isinf(x) && std::isinf(y)) {
7698 // Make sure that the result in case of two infinite arguments
7699 // is a multiple of Pi / 4. The sign of the result is determined
7700 // by the first argument (x) and the sign of the second argument
7701 // determines the multiplier: one or three.
7702 int multiplier = (x < 0) ? -1 : 1;
7703 if (y < 0) multiplier *= 3;
7704 result = multiplier * kPiDividedBy4;
7705 } else {
7706 result = atan2(x, y);
7707 }
7708 return isolate->heap()->AllocateHeapNumber(result);
7709 }
7710
7711
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_cos)7712 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
7713 SealHandleScope shs(isolate);
7714 ASSERT(args.length() == 1);
7715 isolate->counters()->math_cos()->Increment();
7716
7717 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7718 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
7719 }
7720
7721
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_exp)7722 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
7723 SealHandleScope shs(isolate);
7724 ASSERT(args.length() == 1);
7725 isolate->counters()->math_exp()->Increment();
7726
7727 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7728 lazily_initialize_fast_exp();
7729 return isolate->heap()->NumberFromDouble(fast_exp(x));
7730 }
7731
7732
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_floor)7733 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
7734 SealHandleScope shs(isolate);
7735 ASSERT(args.length() == 1);
7736 isolate->counters()->math_floor()->Increment();
7737
7738 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7739 return isolate->heap()->NumberFromDouble(floor(x));
7740 }
7741
7742
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_log)7743 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
7744 SealHandleScope shs(isolate);
7745 ASSERT(args.length() == 1);
7746 isolate->counters()->math_log()->Increment();
7747
7748 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7749 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
7750 }
7751
7752
7753 // Slow version of Math.pow. We check for fast paths for special cases.
7754 // Used if SSE2/VFP3 is not available.
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_pow)7755 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
7756 SealHandleScope shs(isolate);
7757 ASSERT(args.length() == 2);
7758 isolate->counters()->math_pow()->Increment();
7759
7760 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7761
7762 // If the second argument is a smi, it is much faster to call the
7763 // custom powi() function than the generic pow().
7764 if (args[1]->IsSmi()) {
7765 int y = args.smi_at(1);
7766 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
7767 }
7768
7769 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7770 double result = power_helper(x, y);
7771 if (std::isnan(result)) return isolate->heap()->nan_value();
7772 return isolate->heap()->AllocateHeapNumber(result);
7773 }
7774
7775
7776 // Fast version of Math.pow if we know that y is not an integer and y is not
7777 // -0.5 or 0.5. Used as slow case from full codegen.
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_pow_cfunction)7778 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
7779 SealHandleScope shs(isolate);
7780 ASSERT(args.length() == 2);
7781 isolate->counters()->math_pow()->Increment();
7782
7783 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7784 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7785 if (y == 0) {
7786 return Smi::FromInt(1);
7787 } else {
7788 double result = power_double_double(x, y);
7789 if (std::isnan(result)) return isolate->heap()->nan_value();
7790 return isolate->heap()->AllocateHeapNumber(result);
7791 }
7792 }
7793
7794
RUNTIME_FUNCTION(MaybeObject *,Runtime_RoundNumber)7795 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
7796 SealHandleScope shs(isolate);
7797 ASSERT(args.length() == 1);
7798 isolate->counters()->math_round()->Increment();
7799
7800 if (!args[0]->IsHeapNumber()) {
7801 // Must be smi. Return the argument unchanged for all the other types
7802 // to make fuzz-natives test happy.
7803 return args[0];
7804 }
7805
7806 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7807
7808 double value = number->value();
7809 int exponent = number->get_exponent();
7810 int sign = number->get_sign();
7811
7812 if (exponent < -1) {
7813 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7814 if (sign) return isolate->heap()->minus_zero_value();
7815 return Smi::FromInt(0);
7816 }
7817
7818 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7819 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7820 // argument holds for 32-bit smis).
7821 if (!sign && exponent < kSmiValueSize - 2) {
7822 return Smi::FromInt(static_cast<int>(value + 0.5));
7823 }
7824
7825 // If the magnitude is big enough, there's no place for fraction part. If we
7826 // try to add 0.5 to this number, 1.0 will be added instead.
7827 if (exponent >= 52) {
7828 return number;
7829 }
7830
7831 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
7832
7833 // Do not call NumberFromDouble() to avoid extra checks.
7834 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
7835 }
7836
7837
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_sin)7838 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
7839 SealHandleScope shs(isolate);
7840 ASSERT(args.length() == 1);
7841 isolate->counters()->math_sin()->Increment();
7842
7843 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7844 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
7845 }
7846
7847
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_sqrt)7848 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
7849 SealHandleScope shs(isolate);
7850 ASSERT(args.length() == 1);
7851 isolate->counters()->math_sqrt()->Increment();
7852
7853 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7854 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
7855 }
7856
7857
RUNTIME_FUNCTION(MaybeObject *,Runtime_Math_tan)7858 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
7859 SealHandleScope shs(isolate);
7860 ASSERT(args.length() == 1);
7861 isolate->counters()->math_tan()->Increment();
7862
7863 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7864 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
7865 }
7866
7867
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateMakeDay)7868 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
7869 SealHandleScope shs(isolate);
7870 ASSERT(args.length() == 2);
7871
7872 CONVERT_SMI_ARG_CHECKED(year, 0);
7873 CONVERT_SMI_ARG_CHECKED(month, 1);
7874
7875 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
7876 }
7877
7878
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateSetValue)7879 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7880 HandleScope scope(isolate);
7881 ASSERT(args.length() == 3);
7882
7883 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7884 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7885 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
7886
7887 DateCache* date_cache = isolate->date_cache();
7888
7889 Object* value = NULL;
7890 bool is_value_nan = false;
7891 if (std::isnan(time)) {
7892 value = isolate->heap()->nan_value();
7893 is_value_nan = true;
7894 } else if (!is_utc &&
7895 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7896 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7897 value = isolate->heap()->nan_value();
7898 is_value_nan = true;
7899 } else {
7900 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7901 if (time < -DateCache::kMaxTimeInMs ||
7902 time > DateCache::kMaxTimeInMs) {
7903 value = isolate->heap()->nan_value();
7904 is_value_nan = true;
7905 } else {
7906 MaybeObject* maybe_result =
7907 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7908 if (!maybe_result->ToObject(&value)) return maybe_result;
7909 }
7910 }
7911 date->SetValue(value, is_value_nan);
7912 return value;
7913 }
7914
7915
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewArgumentsFast)7916 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
7917 HandleScope scope(isolate);
7918 ASSERT(args.length() == 3);
7919
7920 Handle<JSFunction> callee = args.at<JSFunction>(0);
7921 Object** parameters = reinterpret_cast<Object**>(args[1]);
7922 const int argument_count = Smi::cast(args[2])->value();
7923
7924 Handle<JSObject> result =
7925 isolate->factory()->NewArgumentsObject(callee, argument_count);
7926 // Allocate the elements if needed.
7927 int parameter_count = callee->shared()->formal_parameter_count();
7928 if (argument_count > 0) {
7929 if (parameter_count > 0) {
7930 int mapped_count = Min(argument_count, parameter_count);
7931 Handle<FixedArray> parameter_map =
7932 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7933 parameter_map->set_map(
7934 isolate->heap()->non_strict_arguments_elements_map());
7935
7936 Handle<Map> old_map(result->map());
7937 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
7938 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
7939
7940 result->set_map(*new_map);
7941 result->set_elements(*parameter_map);
7942
7943 // Store the context and the arguments array at the beginning of the
7944 // parameter map.
7945 Handle<Context> context(isolate->context());
7946 Handle<FixedArray> arguments =
7947 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7948 parameter_map->set(0, *context);
7949 parameter_map->set(1, *arguments);
7950
7951 // Loop over the actual parameters backwards.
7952 int index = argument_count - 1;
7953 while (index >= mapped_count) {
7954 // These go directly in the arguments array and have no
7955 // corresponding slot in the parameter map.
7956 arguments->set(index, *(parameters - index - 1));
7957 --index;
7958 }
7959
7960 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
7961 while (index >= 0) {
7962 // Detect duplicate names to the right in the parameter list.
7963 Handle<String> name(scope_info->ParameterName(index));
7964 int context_local_count = scope_info->ContextLocalCount();
7965 bool duplicate = false;
7966 for (int j = index + 1; j < parameter_count; ++j) {
7967 if (scope_info->ParameterName(j) == *name) {
7968 duplicate = true;
7969 break;
7970 }
7971 }
7972
7973 if (duplicate) {
7974 // This goes directly in the arguments array with a hole in the
7975 // parameter map.
7976 arguments->set(index, *(parameters - index - 1));
7977 parameter_map->set_the_hole(index + 2);
7978 } else {
7979 // The context index goes in the parameter map with a hole in the
7980 // arguments array.
7981 int context_index = -1;
7982 for (int j = 0; j < context_local_count; ++j) {
7983 if (scope_info->ContextLocalName(j) == *name) {
7984 context_index = j;
7985 break;
7986 }
7987 }
7988 ASSERT(context_index >= 0);
7989 arguments->set_the_hole(index);
7990 parameter_map->set(index + 2, Smi::FromInt(
7991 Context::MIN_CONTEXT_SLOTS + context_index));
7992 }
7993
7994 --index;
7995 }
7996 } else {
7997 // If there is no aliasing, the arguments object elements are not
7998 // special in any way.
7999 Handle<FixedArray> elements =
8000 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8001 result->set_elements(*elements);
8002 for (int i = 0; i < argument_count; ++i) {
8003 elements->set(i, *(parameters - i - 1));
8004 }
8005 }
8006 }
8007 return *result;
8008 }
8009
8010
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewStrictArgumentsFast)8011 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
8012 SealHandleScope shs(isolate);
8013 ASSERT(args.length() == 3);
8014
8015 JSFunction* callee = JSFunction::cast(args[0]);
8016 Object** parameters = reinterpret_cast<Object**>(args[1]);
8017 const int length = args.smi_at(2);
8018
8019 Object* result;
8020 { MaybeObject* maybe_result =
8021 isolate->heap()->AllocateArgumentsObject(callee, length);
8022 if (!maybe_result->ToObject(&result)) return maybe_result;
8023 }
8024 // Allocate the elements if needed.
8025 if (length > 0) {
8026 // Allocate the fixed array.
8027 FixedArray* array;
8028 { MaybeObject* maybe_obj =
8029 isolate->heap()->AllocateUninitializedFixedArray(length);
8030 if (!maybe_obj->To(&array)) return maybe_obj;
8031 }
8032
8033 DisallowHeapAllocation no_gc;
8034 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
8035 for (int i = 0; i < length; i++) {
8036 array->set(i, *--parameters, mode);
8037 }
8038 JSObject::cast(result)->set_elements(array);
8039 }
8040 return result;
8041 }
8042
8043
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewClosureFromStubFailure)8044 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) {
8045 HandleScope scope(isolate);
8046 ASSERT(args.length() == 1);
8047 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8048 Handle<Context> context(isolate->context());
8049 PretenureFlag pretenure_flag = NOT_TENURED;
8050 Handle<JSFunction> result =
8051 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8052 context,
8053 pretenure_flag);
8054 return *result;
8055 }
8056
8057
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewClosure)8058 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
8059 HandleScope scope(isolate);
8060 ASSERT(args.length() == 3);
8061 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8062 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8063 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
8064
8065 // The caller ensures that we pretenure closures that are assigned
8066 // directly to properties.
8067 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
8068 Handle<JSFunction> result =
8069 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8070 context,
8071 pretenure_flag);
8072 return *result;
8073 }
8074
8075
8076 // Find the arguments of the JavaScript function invocation that called
8077 // into C++ code. Collect these in a newly allocated array of handles (possibly
8078 // prefixed by a number of empty handles).
GetCallerArguments(Isolate * isolate,int prefix_argc,int * total_argc)8079 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8080 Isolate* isolate,
8081 int prefix_argc,
8082 int* total_argc) {
8083 // Find frame containing arguments passed to the caller.
8084 JavaScriptFrameIterator it(isolate);
8085 JavaScriptFrame* frame = it.frame();
8086 List<JSFunction*> functions(2);
8087 frame->GetFunctions(&functions);
8088 if (functions.length() > 1) {
8089 int inlined_jsframe_index = functions.length() - 1;
8090 JSFunction* inlined_function = functions[inlined_jsframe_index];
8091 Vector<SlotRef> args_slots =
8092 SlotRef::ComputeSlotMappingForArguments(
8093 frame,
8094 inlined_jsframe_index,
8095 inlined_function->shared()->formal_parameter_count());
8096
8097 int args_count = args_slots.length();
8098
8099 *total_argc = prefix_argc + args_count;
8100 SmartArrayPointer<Handle<Object> > param_data(
8101 NewArray<Handle<Object> >(*total_argc));
8102 for (int i = 0; i < args_count; i++) {
8103 Handle<Object> val = args_slots[i].GetValue(isolate);
8104 param_data[prefix_argc + i] = val;
8105 }
8106
8107 args_slots.Dispose();
8108
8109 return param_data;
8110 } else {
8111 it.AdvanceToArgumentsFrame();
8112 frame = it.frame();
8113 int args_count = frame->ComputeParametersCount();
8114
8115 *total_argc = prefix_argc + args_count;
8116 SmartArrayPointer<Handle<Object> > param_data(
8117 NewArray<Handle<Object> >(*total_argc));
8118 for (int i = 0; i < args_count; i++) {
8119 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
8120 param_data[prefix_argc + i] = val;
8121 }
8122 return param_data;
8123 }
8124 }
8125
8126
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionBindArguments)8127 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8128 HandleScope scope(isolate);
8129 ASSERT(args.length() == 4);
8130 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
8131 RUNTIME_ASSERT(args[3]->IsNumber());
8132 Handle<Object> bindee = args.at<Object>(1);
8133
8134 // TODO(lrn): Create bound function in C++ code from premade shared info.
8135 bound_function->shared()->set_bound(true);
8136 // Get all arguments of calling function (Function.prototype.bind).
8137 int argc = 0;
8138 SmartArrayPointer<Handle<Object> > arguments =
8139 GetCallerArguments(isolate, 0, &argc);
8140 // Don't count the this-arg.
8141 if (argc > 0) {
8142 ASSERT(*arguments[0] == args[2]);
8143 argc--;
8144 } else {
8145 ASSERT(args[2]->IsUndefined());
8146 }
8147 // Initialize array of bindings (function, this, and any existing arguments
8148 // if the function was already bound).
8149 Handle<FixedArray> new_bindings;
8150 int i;
8151 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8152 Handle<FixedArray> old_bindings(
8153 JSFunction::cast(*bindee)->function_bindings());
8154 new_bindings =
8155 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8156 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8157 isolate);
8158 i = 0;
8159 for (int n = old_bindings->length(); i < n; i++) {
8160 new_bindings->set(i, old_bindings->get(i));
8161 }
8162 } else {
8163 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8164 new_bindings = isolate->factory()->NewFixedArray(array_size);
8165 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8166 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8167 i = 2;
8168 }
8169 // Copy arguments, skipping the first which is "this_arg".
8170 for (int j = 0; j < argc; j++, i++) {
8171 new_bindings->set(i, *arguments[j + 1]);
8172 }
8173 new_bindings->set_map_no_write_barrier(
8174 isolate->heap()->fixed_cow_array_map());
8175 bound_function->set_function_bindings(*new_bindings);
8176
8177 // Update length.
8178 Handle<String> length_string = isolate->factory()->length_string();
8179 Handle<Object> new_length(args.at<Object>(3));
8180 PropertyAttributes attr =
8181 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8182 ForceSetProperty(bound_function, length_string, new_length, attr);
8183 return *bound_function;
8184 }
8185
8186
RUNTIME_FUNCTION(MaybeObject *,Runtime_BoundFunctionGetBindings)8187 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8188 HandleScope handles(isolate);
8189 ASSERT(args.length() == 1);
8190 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
8191 if (callable->IsJSFunction()) {
8192 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8193 if (function->shared()->bound()) {
8194 Handle<FixedArray> bindings(function->function_bindings());
8195 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8196 return *isolate->factory()->NewJSArrayWithElements(bindings);
8197 }
8198 }
8199 return isolate->heap()->undefined_value();
8200 }
8201
8202
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewObjectFromBound)8203 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
8204 HandleScope scope(isolate);
8205 ASSERT(args.length() == 1);
8206 // First argument is a function to use as a constructor.
8207 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8208 RUNTIME_ASSERT(function->shared()->bound());
8209
8210 // The argument is a bound function. Extract its bound arguments
8211 // and callable.
8212 Handle<FixedArray> bound_args =
8213 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8214 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8215 Handle<Object> bound_function(
8216 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8217 isolate);
8218 ASSERT(!bound_function->IsJSFunction() ||
8219 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
8220
8221 int total_argc = 0;
8222 SmartArrayPointer<Handle<Object> > param_data =
8223 GetCallerArguments(isolate, bound_argc, &total_argc);
8224 for (int i = 0; i < bound_argc; i++) {
8225 param_data[i] = Handle<Object>(bound_args->get(
8226 JSFunction::kBoundArgumentsStartIndex + i), isolate);
8227 }
8228
8229 if (!bound_function->IsJSFunction()) {
8230 bool exception_thrown;
8231 bound_function = Execution::TryGetConstructorDelegate(isolate,
8232 bound_function,
8233 &exception_thrown);
8234 if (exception_thrown) return Failure::Exception();
8235 }
8236 ASSERT(bound_function->IsJSFunction());
8237
8238 bool exception = false;
8239 Handle<Object> result =
8240 Execution::New(Handle<JSFunction>::cast(bound_function),
8241 total_argc, *param_data, &exception);
8242 if (exception) {
8243 return Failure::Exception();
8244 }
8245 ASSERT(!result.is_null());
8246 return *result;
8247 }
8248
8249
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewObject)8250 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
8251 HandleScope scope(isolate);
8252 ASSERT(args.length() == 1);
8253
8254 Handle<Object> constructor = args.at<Object>(0);
8255
8256 // If the constructor isn't a proper function we throw a type error.
8257 if (!constructor->IsJSFunction()) {
8258 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8259 Handle<Object> type_error =
8260 isolate->factory()->NewTypeError("not_constructor", arguments);
8261 return isolate->Throw(*type_error);
8262 }
8263
8264 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
8265
8266 // If function should not have prototype, construction is not allowed. In this
8267 // case generated code bailouts here, since function has no initial_map.
8268 if (!function->should_have_prototype() && !function->shared()->bound()) {
8269 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8270 Handle<Object> type_error =
8271 isolate->factory()->NewTypeError("not_constructor", arguments);
8272 return isolate->Throw(*type_error);
8273 }
8274
8275 #ifdef ENABLE_DEBUGGER_SUPPORT
8276 Debug* debug = isolate->debug();
8277 // Handle stepping into constructors if step into is active.
8278 if (debug->StepInActive()) {
8279 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
8280 }
8281 #endif
8282
8283 if (function->has_initial_map()) {
8284 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
8285 // The 'Function' function ignores the receiver object when
8286 // called using 'new' and creates a new JSFunction object that
8287 // is returned. The receiver object is only used for error
8288 // reporting if an error occurs when constructing the new
8289 // JSFunction. Factory::NewJSObject() should not be used to
8290 // allocate JSFunctions since it does not properly initialize
8291 // the shared part of the function. Since the receiver is
8292 // ignored anyway, we use the global object as the receiver
8293 // instead of a new JSFunction object. This way, errors are
8294 // reported the same way whether or not 'Function' is called
8295 // using 'new'.
8296 return isolate->context()->global_object();
8297 }
8298 }
8299
8300 // The function should be compiled for the optimization hints to be
8301 // available.
8302 JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION);
8303
8304 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
8305 if (!function->has_initial_map() &&
8306 shared->IsInobjectSlackTrackingInProgress()) {
8307 // The tracking is already in progress for another function. We can only
8308 // track one initial_map at a time, so we force the completion before the
8309 // function is called as a constructor for the first time.
8310 shared->CompleteInobjectSlackTracking();
8311 }
8312
8313 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8314 RETURN_IF_EMPTY_HANDLE(isolate, result);
8315
8316 isolate->counters()->constructed_objects()->Increment();
8317 isolate->counters()->constructed_objects_runtime()->Increment();
8318
8319 return *result;
8320 }
8321
8322
RUNTIME_FUNCTION(MaybeObject *,Runtime_FinalizeInstanceSize)8323 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
8324 HandleScope scope(isolate);
8325 ASSERT(args.length() == 1);
8326
8327 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8328 function->shared()->CompleteInobjectSlackTracking();
8329
8330 return isolate->heap()->undefined_value();
8331 }
8332
8333
RUNTIME_FUNCTION(MaybeObject *,Runtime_LazyCompile)8334 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
8335 HandleScope scope(isolate);
8336 ASSERT(args.length() == 1);
8337
8338 Handle<JSFunction> function = args.at<JSFunction>(0);
8339 #ifdef DEBUG
8340 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
8341 PrintF("[lazy: ");
8342 function->PrintName();
8343 PrintF("]\n");
8344 }
8345 #endif
8346
8347 // Compile the target function.
8348 ASSERT(!function->is_compiled());
8349 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
8350 return Failure::Exception();
8351 }
8352
8353 // All done. Return the compiled code.
8354 ASSERT(function->is_compiled());
8355 return function->code();
8356 }
8357
8358
AllowOptimization(Isolate * isolate,Handle<JSFunction> function)8359 bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) {
8360 // If the function is not compiled ignore the lazy
8361 // recompilation. This can happen if the debugger is activated and
8362 // the function is returned to the not compiled state.
8363 if (!function->shared()->is_compiled()) return false;
8364
8365 // If the function is not optimizable or debugger is active continue using the
8366 // code from the full compiler.
8367 if (!isolate->use_crankshaft() ||
8368 function->shared()->optimization_disabled() ||
8369 isolate->DebuggerHasBreakPoints()) {
8370 if (FLAG_trace_opt) {
8371 PrintF("[failed to optimize ");
8372 function->PrintName();
8373 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8374 function->shared()->optimization_disabled() ? "F" : "T",
8375 isolate->DebuggerHasBreakPoints() ? "T" : "F");
8376 }
8377 return false;
8378 }
8379 return true;
8380 }
8381
8382
RUNTIME_FUNCTION(MaybeObject *,Runtime_LazyRecompile)8383 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
8384 HandleScope scope(isolate);
8385 ASSERT(args.length() == 1);
8386 Handle<JSFunction> function = args.at<JSFunction>(0);
8387
8388 if (!AllowOptimization(isolate, function)) {
8389 function->ReplaceCode(function->shared()->code());
8390 return function->code();
8391 }
8392 function->shared()->code()->set_profiler_ticks(0);
8393 if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) {
8394 return function->code();
8395 }
8396 if (FLAG_trace_opt) {
8397 PrintF("[failed to optimize ");
8398 function->PrintName();
8399 PrintF(": optimized compilation failed]\n");
8400 }
8401 function->ReplaceCode(function->shared()->code());
8402 return function->code();
8403 }
8404
8405
RUNTIME_FUNCTION(MaybeObject *,Runtime_ConcurrentRecompile)8406 RUNTIME_FUNCTION(MaybeObject*, Runtime_ConcurrentRecompile) {
8407 HandleScope handle_scope(isolate);
8408 ASSERT(args.length() == 1);
8409 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8410 if (!AllowOptimization(isolate, function)) {
8411 function->ReplaceCode(function->shared()->code());
8412 return isolate->heap()->undefined_value();
8413 }
8414 function->shared()->code()->set_profiler_ticks(0);
8415 ASSERT(isolate->concurrent_recompilation_enabled());
8416 if (!Compiler::RecompileConcurrent(function)) {
8417 function->ReplaceCode(function->shared()->code());
8418 }
8419 return isolate->heap()->undefined_value();
8420 }
8421
8422
8423 class ActivationsFinder : public ThreadVisitor {
8424 public:
8425 Code* code_;
8426 bool has_code_activations_;
8427
ActivationsFinder(Code * code)8428 explicit ActivationsFinder(Code* code)
8429 : code_(code),
8430 has_code_activations_(false) { }
8431
VisitThread(Isolate * isolate,ThreadLocalTop * top)8432 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8433 JavaScriptFrameIterator it(isolate, top);
8434 VisitFrames(&it);
8435 }
8436
VisitFrames(JavaScriptFrameIterator * it)8437 void VisitFrames(JavaScriptFrameIterator* it) {
8438 for (; !it->done(); it->Advance()) {
8439 JavaScriptFrame* frame = it->frame();
8440 if (code_->contains(frame->pc())) has_code_activations_ = true;
8441 }
8442 }
8443 };
8444
8445
RUNTIME_FUNCTION(MaybeObject *,Runtime_NotifyStubFailure)8446 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
8447 HandleScope scope(isolate);
8448 ASSERT(args.length() == 0);
8449 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8450 ASSERT(AllowHeapAllocation::IsAllowed());
8451 delete deoptimizer;
8452 return isolate->heap()->undefined_value();
8453 }
8454
8455
RUNTIME_FUNCTION(MaybeObject *,Runtime_NotifyDeoptimized)8456 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8457 HandleScope scope(isolate);
8458 ASSERT(args.length() == 1);
8459 RUNTIME_ASSERT(args[0]->IsSmi());
8460 Deoptimizer::BailoutType type =
8461 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8462 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8463 ASSERT(AllowHeapAllocation::IsAllowed());
8464
8465 Handle<JSFunction> function = deoptimizer->function();
8466 Handle<Code> optimized_code = deoptimizer->compiled_code();
8467
8468 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8469 ASSERT(type == deoptimizer->bailout_type());
8470
8471 // Make sure to materialize objects before causing any allocation.
8472 JavaScriptFrameIterator it(isolate);
8473 deoptimizer->MaterializeHeapObjects(&it);
8474 delete deoptimizer;
8475
8476 JavaScriptFrame* frame = it.frame();
8477 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8478 ASSERT(frame->function() == *function);
8479
8480 // Avoid doing too much work when running with --always-opt and keep
8481 // the optimized code around.
8482 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
8483 return isolate->heap()->undefined_value();
8484 }
8485
8486 // Search for other activations of the same function and code.
8487 ActivationsFinder activations_finder(*optimized_code);
8488 activations_finder.VisitFrames(&it);
8489 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8490
8491 if (!activations_finder.has_code_activations_) {
8492 if (function->code() == *optimized_code) {
8493 if (FLAG_trace_deopt) {
8494 PrintF("[removing optimized code for: ");
8495 function->PrintName();
8496 PrintF("]\n");
8497 }
8498 function->ReplaceCode(function->shared()->code());
8499 }
8500 } else {
8501 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8502 // unconditionally if the code is not already marked for deoptimization.
8503 // If there is an index by shared function info, all the better.
8504 Deoptimizer::DeoptimizeFunction(*function);
8505 }
8506 // Evict optimized code for this function from the cache so that it doesn't
8507 // get used for new closures.
8508 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8509 "notify deoptimized");
8510
8511 return isolate->heap()->undefined_value();
8512 }
8513
8514
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeoptimizeFunction)8515 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
8516 HandleScope scope(isolate);
8517 ASSERT(args.length() == 1);
8518 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8519 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
8520
8521 Deoptimizer::DeoptimizeFunction(*function);
8522
8523 return isolate->heap()->undefined_value();
8524 }
8525
8526
RUNTIME_FUNCTION(MaybeObject *,Runtime_ClearFunctionTypeFeedback)8527 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8528 HandleScope scope(isolate);
8529 ASSERT(args.length() == 1);
8530 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8531 Code* unoptimized = function->shared()->code();
8532 if (unoptimized->kind() == Code::FUNCTION) {
8533 unoptimized->ClearInlineCaches();
8534 unoptimized->ClearTypeFeedbackCells(isolate->heap());
8535 }
8536 return isolate->heap()->undefined_value();
8537 }
8538
8539
RUNTIME_FUNCTION(MaybeObject *,Runtime_RunningInSimulator)8540 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8541 SealHandleScope shs(isolate);
8542 #if defined(USE_SIMULATOR)
8543 return isolate->heap()->true_value();
8544 #else
8545 return isolate->heap()->false_value();
8546 #endif
8547 }
8548
8549
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsConcurrentRecompilationSupported)8550 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
8551 HandleScope scope(isolate);
8552 return isolate->concurrent_recompilation_enabled()
8553 ? isolate->heap()->true_value() : isolate->heap()->false_value();
8554 }
8555
8556
RUNTIME_FUNCTION(MaybeObject *,Runtime_OptimizeFunctionOnNextCall)8557 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8558 HandleScope scope(isolate);
8559 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8560 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8561
8562 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8563 function->MarkForLazyRecompilation();
8564
8565 Code* unoptimized = function->shared()->code();
8566 if (args.length() == 2 &&
8567 unoptimized->kind() == Code::FUNCTION) {
8568 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8569 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
8570 // Start patching from the currently patched loop nesting level.
8571 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
8572 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
8573 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
8574 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8575 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8576 }
8577 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) {
8578 function->MarkForConcurrentRecompilation();
8579 }
8580 }
8581
8582 return isolate->heap()->undefined_value();
8583 }
8584
8585
RUNTIME_FUNCTION(MaybeObject *,Runtime_NeverOptimizeFunction)8586 RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
8587 HandleScope scope(isolate);
8588 ASSERT(args.length() == 1);
8589 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8590 ASSERT(!function->IsOptimized());
8591 function->shared()->set_optimization_disabled(true);
8592 return isolate->heap()->undefined_value();
8593 }
8594
8595
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetOptimizationStatus)8596 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8597 HandleScope scope(isolate);
8598 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8599 if (!isolate->use_crankshaft()) {
8600 return Smi::FromInt(4); // 4 == "never".
8601 }
8602 bool sync_with_compiler_thread = true;
8603 if (args.length() == 2) {
8604 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8605 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8606 sync_with_compiler_thread = false;
8607 }
8608 }
8609 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8610 if (isolate->concurrent_recompilation_enabled() &&
8611 sync_with_compiler_thread) {
8612 while (function->IsInRecompileQueue()) {
8613 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8614 OS::Sleep(50);
8615 }
8616 }
8617 if (FLAG_always_opt) {
8618 // We may have always opt, but that is more best-effort than a real
8619 // promise, so we still say "no" if it is not optimized.
8620 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8621 : Smi::FromInt(2); // 2 == "no".
8622 }
8623 if (FLAG_deopt_every_n_times) {
8624 return Smi::FromInt(6); // 6 == "maybe deopted".
8625 }
8626 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8627 : Smi::FromInt(2); // 2 == "no".
8628 }
8629
8630
RUNTIME_FUNCTION(MaybeObject *,Runtime_UnblockConcurrentRecompilation)8631 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
8632 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8633 isolate->optimizing_compiler_thread()->Unblock();
8634 return isolate->heap()->undefined_value();
8635 }
8636
8637
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetOptimizationCount)8638 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8639 HandleScope scope(isolate);
8640 ASSERT(args.length() == 1);
8641 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8642 return Smi::FromInt(function->shared()->opt_count());
8643 }
8644
8645
IsSuitableForOnStackReplacement(Isolate * isolate,Handle<JSFunction> function,Handle<Code> unoptimized)8646 static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8647 Handle<JSFunction> function,
8648 Handle<Code> unoptimized) {
8649 // Keep track of whether we've succeeded in optimizing.
8650 if (!isolate->use_crankshaft() || !unoptimized->optimizable()) return false;
8651 // If we are trying to do OSR when there are already optimized
8652 // activations of the function, it means (a) the function is directly or
8653 // indirectly recursive and (b) an optimized invocation has been
8654 // deoptimized so that we are currently in an unoptimized activation.
8655 // Check for optimized activations of this function.
8656 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8657 JavaScriptFrame* frame = it.frame();
8658 if (frame->is_optimized() && frame->function() == *function) return false;
8659 }
8660
8661 return true;
8662 }
8663
8664
RUNTIME_FUNCTION(MaybeObject *,Runtime_CompileForOnStackReplacement)8665 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
8666 HandleScope scope(isolate);
8667 ASSERT(args.length() == 2);
8668 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8669 CONVERT_NUMBER_CHECKED(uint32_t, pc_offset, Uint32, args[1]);
8670 Handle<Code> unoptimized(function->shared()->code(), isolate);
8671
8672 #ifdef DEBUG
8673 JavaScriptFrameIterator it(isolate);
8674 JavaScriptFrame* frame = it.frame();
8675 ASSERT_EQ(frame->function(), *function);
8676 ASSERT_EQ(frame->LookupCode(), *unoptimized);
8677 ASSERT(unoptimized->contains(frame->pc()));
8678
8679 ASSERT(pc_offset ==
8680 static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start()));
8681 #endif // DEBUG
8682
8683 // We're not prepared to handle a function with arguments object.
8684 ASSERT(!function->shared()->uses_arguments());
8685
8686 Handle<Code> result = Handle<Code>::null();
8687 BailoutId ast_id = BailoutId::None();
8688
8689 if (isolate->concurrent_osr_enabled()) {
8690 if (isolate->optimizing_compiler_thread()->
8691 IsQueuedForOSR(function, pc_offset)) {
8692 // Still waiting for the optimizing compiler thread to finish. Carry on.
8693 if (FLAG_trace_osr) {
8694 PrintF("[COSR - polling recompile tasks for ");
8695 function->PrintName();
8696 PrintF("]\n");
8697 }
8698 return NULL;
8699 }
8700
8701 RecompileJob* job = isolate->optimizing_compiler_thread()->
8702 FindReadyOSRCandidate(function, pc_offset);
8703
8704 if (job == NULL) {
8705 if (IsSuitableForOnStackReplacement(isolate, function, unoptimized) &&
8706 Compiler::RecompileConcurrent(function, pc_offset)) {
8707 if (function->IsMarkedForLazyRecompilation() ||
8708 function->IsMarkedForConcurrentRecompilation()) {
8709 // Prevent regular recompilation if we queue this for OSR.
8710 // TODO(yangguo): remove this as soon as OSR becomes one-shot.
8711 function->ReplaceCode(*unoptimized);
8712 }
8713 return NULL;
8714 }
8715 // Fall through to the end in case of failure.
8716 } else {
8717 // TODO(titzer): don't install the OSR code into the function.
8718 ast_id = job->info()->osr_ast_id();
8719 result = Compiler::InstallOptimizedCode(job);
8720 }
8721 } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
8722 ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
8723 ASSERT(!ast_id.IsNone());
8724 if (FLAG_trace_osr) {
8725 PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt());
8726 function->PrintName();
8727 PrintF("]\n");
8728 }
8729 // Attempt OSR compilation.
8730 result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION);
8731 }
8732
8733 // Revert the patched back edge table, regardless of whether OSR succeeds.
8734 BackEdgeTable::Revert(isolate, *unoptimized);
8735
8736 // Check whether we ended up with usable optimized code.
8737 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8738 DeoptimizationInputData* data =
8739 DeoptimizationInputData::cast(result->deoptimization_data());
8740
8741 if (data->OsrPcOffset()->value() >= 0) {
8742 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8743 if (FLAG_trace_osr) {
8744 PrintF("[OSR - entry at AST id %d, offset %d in optimized code]\n",
8745 ast_id.ToInt(), data->OsrPcOffset()->value());
8746 }
8747 // TODO(titzer): this is a massive hack to make the deopt counts
8748 // match. Fix heuristics for reenabling optimizations!
8749 function->shared()->increment_deopt_count();
8750 return *result;
8751 }
8752 }
8753
8754 if (FLAG_trace_osr) {
8755 PrintF("[OSR - optimization failed for ");
8756 function->PrintName();
8757 PrintF("]\n");
8758 }
8759
8760 if (function->IsMarkedForLazyRecompilation() ||
8761 function->IsMarkedForConcurrentRecompilation()) {
8762 function->ReplaceCode(function->shared()->code());
8763 }
8764 return NULL;
8765 }
8766
8767
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetAllocationTimeout)8768 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) {
8769 SealHandleScope shs(isolate);
8770 ASSERT(args.length() == 2);
8771 #ifdef DEBUG
8772 CONVERT_SMI_ARG_CHECKED(interval, 0);
8773 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8774 isolate->heap()->set_allocation_timeout(timeout);
8775 FLAG_gc_interval = interval;
8776 #endif
8777 return isolate->heap()->undefined_value();
8778 }
8779
8780
RUNTIME_FUNCTION(MaybeObject *,Runtime_CheckIsBootstrapping)8781 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8782 SealHandleScope shs(isolate);
8783 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8784 return isolate->heap()->undefined_value();
8785 }
8786
8787
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetRootNaN)8788 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8789 SealHandleScope shs(isolate);
8790 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8791 return isolate->heap()->nan_value();
8792 }
8793
8794
RUNTIME_FUNCTION(MaybeObject *,Runtime_Call)8795 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8796 HandleScope scope(isolate);
8797 ASSERT(args.length() >= 2);
8798 int argc = args.length() - 2;
8799 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8800 Object* receiver = args[0];
8801
8802 // If there are too many arguments, allocate argv via malloc.
8803 const int argv_small_size = 10;
8804 Handle<Object> argv_small_buffer[argv_small_size];
8805 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8806 Handle<Object>* argv = argv_small_buffer;
8807 if (argc > argv_small_size) {
8808 argv = new Handle<Object>[argc];
8809 if (argv == NULL) return isolate->StackOverflow();
8810 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8811 }
8812
8813 for (int i = 0; i < argc; ++i) {
8814 MaybeObject* maybe = args[1 + i];
8815 Object* object;
8816 if (!maybe->To<Object>(&object)) return maybe;
8817 argv[i] = Handle<Object>(object, isolate);
8818 }
8819
8820 bool threw;
8821 Handle<JSReceiver> hfun(fun);
8822 Handle<Object> hreceiver(receiver, isolate);
8823 Handle<Object> result = Execution::Call(
8824 isolate, hfun, hreceiver, argc, argv, &threw, true);
8825
8826 if (threw) return Failure::Exception();
8827 return *result;
8828 }
8829
8830
RUNTIME_FUNCTION(MaybeObject *,Runtime_Apply)8831 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8832 HandleScope scope(isolate);
8833 ASSERT(args.length() == 5);
8834 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
8835 Handle<Object> receiver = args.at<Object>(1);
8836 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
8837 CONVERT_SMI_ARG_CHECKED(offset, 3);
8838 CONVERT_SMI_ARG_CHECKED(argc, 4);
8839 RUNTIME_ASSERT(offset >= 0);
8840 RUNTIME_ASSERT(argc >= 0);
8841
8842 // If there are too many arguments, allocate argv via malloc.
8843 const int argv_small_size = 10;
8844 Handle<Object> argv_small_buffer[argv_small_size];
8845 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8846 Handle<Object>* argv = argv_small_buffer;
8847 if (argc > argv_small_size) {
8848 argv = new Handle<Object>[argc];
8849 if (argv == NULL) return isolate->StackOverflow();
8850 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8851 }
8852
8853 for (int i = 0; i < argc; ++i) {
8854 argv[i] = Object::GetElement(isolate, arguments, offset + i);
8855 }
8856
8857 bool threw;
8858 Handle<Object> result = Execution::Call(
8859 isolate, fun, receiver, argc, argv, &threw, true);
8860
8861 if (threw) return Failure::Exception();
8862 return *result;
8863 }
8864
8865
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFunctionDelegate)8866 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
8867 HandleScope scope(isolate);
8868 ASSERT(args.length() == 1);
8869 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8870 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0));
8871 }
8872
8873
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetConstructorDelegate)8874 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
8875 HandleScope scope(isolate);
8876 ASSERT(args.length() == 1);
8877 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8878 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0));
8879 }
8880
8881
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewGlobalContext)8882 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) {
8883 SealHandleScope shs(isolate);
8884 ASSERT(args.length() == 2);
8885
8886 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8887 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
8888 Context* result;
8889 MaybeObject* maybe_result =
8890 isolate->heap()->AllocateGlobalContext(function, scope_info);
8891 if (!maybe_result->To(&result)) return maybe_result;
8892
8893 ASSERT(function->context() == isolate->context());
8894 ASSERT(function->context()->global_object() == result->global_object());
8895 isolate->set_context(result);
8896 result->global_object()->set_global_context(result);
8897
8898 return result; // non-failure
8899 }
8900
8901
RUNTIME_FUNCTION(MaybeObject *,Runtime_NewFunctionContext)8902 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
8903 SealHandleScope shs(isolate);
8904 ASSERT(args.length() == 1);
8905
8906 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8907 int length = function->shared()->scope_info()->ContextLength();
8908 Context* result;
8909 MaybeObject* maybe_result =
8910 isolate->heap()->AllocateFunctionContext(length, function);
8911 if (!maybe_result->To(&result)) return maybe_result;
8912
8913 isolate->set_context(result);
8914
8915 return result; // non-failure
8916 }
8917
8918
RUNTIME_FUNCTION(MaybeObject *,Runtime_PushWithContext)8919 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8920 SealHandleScope shs(isolate);
8921 ASSERT(args.length() == 2);
8922 JSReceiver* extension_object;
8923 if (args[0]->IsJSReceiver()) {
8924 extension_object = JSReceiver::cast(args[0]);
8925 } else {
8926 // Convert the object to a proper JavaScript object.
8927 MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
8928 if (!maybe_js_object->To(&extension_object)) {
8929 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8930 HandleScope scope(isolate);
8931 Handle<Object> handle = args.at<Object>(0);
8932 Handle<Object> result =
8933 isolate->factory()->NewTypeError("with_expression",
8934 HandleVector(&handle, 1));
8935 return isolate->Throw(*result);
8936 } else {
8937 return maybe_js_object;
8938 }
8939 }
8940 }
8941
8942 JSFunction* function;
8943 if (args[1]->IsSmi()) {
8944 // A smi sentinel indicates a context nested inside global code rather
8945 // than some function. There is a canonical empty function that can be
8946 // gotten from the native context.
8947 function = isolate->context()->native_context()->closure();
8948 } else {
8949 function = JSFunction::cast(args[1]);
8950 }
8951
8952 Context* context;
8953 MaybeObject* maybe_context =
8954 isolate->heap()->AllocateWithContext(function,
8955 isolate->context(),
8956 extension_object);
8957 if (!maybe_context->To(&context)) return maybe_context;
8958 isolate->set_context(context);
8959 return context;
8960 }
8961
8962
RUNTIME_FUNCTION(MaybeObject *,Runtime_PushCatchContext)8963 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
8964 SealHandleScope shs(isolate);
8965 ASSERT(args.length() == 3);
8966 String* name = String::cast(args[0]);
8967 Object* thrown_object = args[1];
8968 JSFunction* function;
8969 if (args[2]->IsSmi()) {
8970 // A smi sentinel indicates a context nested inside global code rather
8971 // than some function. There is a canonical empty function that can be
8972 // gotten from the native context.
8973 function = isolate->context()->native_context()->closure();
8974 } else {
8975 function = JSFunction::cast(args[2]);
8976 }
8977 Context* context;
8978 MaybeObject* maybe_context =
8979 isolate->heap()->AllocateCatchContext(function,
8980 isolate->context(),
8981 name,
8982 thrown_object);
8983 if (!maybe_context->To(&context)) return maybe_context;
8984 isolate->set_context(context);
8985 return context;
8986 }
8987
8988
RUNTIME_FUNCTION(MaybeObject *,Runtime_PushBlockContext)8989 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8990 SealHandleScope shs(isolate);
8991 ASSERT(args.length() == 2);
8992 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
8993 JSFunction* function;
8994 if (args[1]->IsSmi()) {
8995 // A smi sentinel indicates a context nested inside global code rather
8996 // than some function. There is a canonical empty function that can be
8997 // gotten from the native context.
8998 function = isolate->context()->native_context()->closure();
8999 } else {
9000 function = JSFunction::cast(args[1]);
9001 }
9002 Context* context;
9003 MaybeObject* maybe_context =
9004 isolate->heap()->AllocateBlockContext(function,
9005 isolate->context(),
9006 scope_info);
9007 if (!maybe_context->To(&context)) return maybe_context;
9008 isolate->set_context(context);
9009 return context;
9010 }
9011
9012
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsJSModule)9013 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
9014 SealHandleScope shs(isolate);
9015 ASSERT(args.length() == 1);
9016 Object* obj = args[0];
9017 return isolate->heap()->ToBoolean(obj->IsJSModule());
9018 }
9019
9020
RUNTIME_FUNCTION(MaybeObject *,Runtime_PushModuleContext)9021 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
9022 SealHandleScope shs(isolate);
9023 ASSERT(args.length() == 2);
9024 CONVERT_SMI_ARG_CHECKED(index, 0);
9025
9026 if (!args[1]->IsScopeInfo()) {
9027 // Module already initialized. Find hosting context and retrieve context.
9028 Context* host = Context::cast(isolate->context())->global_context();
9029 Context* context = Context::cast(host->get(index));
9030 ASSERT(context->previous() == isolate->context());
9031 isolate->set_context(context);
9032 return context;
9033 }
9034
9035 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9036
9037 // Allocate module context.
9038 HandleScope scope(isolate);
9039 Factory* factory = isolate->factory();
9040 Handle<Context> context = factory->NewModuleContext(scope_info);
9041 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
9042 context->set_module(*module);
9043 Context* previous = isolate->context();
9044 context->set_previous(previous);
9045 context->set_closure(previous->closure());
9046 context->set_global_object(previous->global_object());
9047 isolate->set_context(*context);
9048
9049 // Find hosting scope and initialize internal variable holding module there.
9050 previous->global_context()->set(index, *context);
9051
9052 return *context;
9053 }
9054
9055
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeclareModules)9056 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) {
9057 HandleScope scope(isolate);
9058 ASSERT(args.length() == 1);
9059 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9060 Context* host_context = isolate->context();
9061
9062 for (int i = 0; i < descriptions->length(); ++i) {
9063 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9064 int host_index = description->host_index();
9065 Handle<Context> context(Context::cast(host_context->get(host_index)));
9066 Handle<JSModule> module(context->module());
9067
9068 for (int j = 0; j < description->length(); ++j) {
9069 Handle<String> name(description->name(j));
9070 VariableMode mode = description->mode(j);
9071 int index = description->index(j);
9072 switch (mode) {
9073 case VAR:
9074 case LET:
9075 case CONST:
9076 case CONST_HARMONY: {
9077 PropertyAttributes attr =
9078 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9079 Handle<AccessorInfo> info =
9080 Accessors::MakeModuleExport(name, index, attr);
9081 Handle<Object> result = JSObject::SetAccessor(module, info);
9082 ASSERT(!(result.is_null() || result->IsUndefined()));
9083 USE(result);
9084 break;
9085 }
9086 case MODULE: {
9087 Object* referenced_context = Context::cast(host_context)->get(index);
9088 Handle<JSModule> value(Context::cast(referenced_context)->module());
9089 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode);
9090 break;
9091 }
9092 case INTERNAL:
9093 case TEMPORARY:
9094 case DYNAMIC:
9095 case DYNAMIC_GLOBAL:
9096 case DYNAMIC_LOCAL:
9097 UNREACHABLE();
9098 }
9099 }
9100
9101 JSObject::PreventExtensions(module);
9102 }
9103
9104 ASSERT(!isolate->has_pending_exception());
9105 return isolate->heap()->undefined_value();
9106 }
9107
9108
RUNTIME_FUNCTION(MaybeObject *,Runtime_DeleteContextSlot)9109 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
9110 HandleScope scope(isolate);
9111 ASSERT(args.length() == 2);
9112
9113 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9114 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
9115
9116 int index;
9117 PropertyAttributes attributes;
9118 ContextLookupFlags flags = FOLLOW_CHAINS;
9119 BindingFlags binding_flags;
9120 Handle<Object> holder = context->Lookup(name,
9121 flags,
9122 &index,
9123 &attributes,
9124 &binding_flags);
9125
9126 // If the slot was not found the result is true.
9127 if (holder.is_null()) {
9128 return isolate->heap()->true_value();
9129 }
9130
9131 // If the slot was found in a context, it should be DONT_DELETE.
9132 if (holder->IsContext()) {
9133 return isolate->heap()->false_value();
9134 }
9135
9136 // The slot was found in a JSObject, either a context extension object,
9137 // the global object, or the subject of a with. Try to delete it
9138 // (respecting DONT_DELETE).
9139 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9140 Handle<Object> result = JSReceiver::DeleteProperty(object, name);
9141 RETURN_IF_EMPTY_HANDLE(isolate, result);
9142 return *result;
9143 }
9144
9145
9146 // A mechanism to return a pair of Object pointers in registers (if possible).
9147 // How this is achieved is calling convention-dependent.
9148 // All currently supported x86 compiles uses calling conventions that are cdecl
9149 // variants where a 64-bit value is returned in two 32-bit registers
9150 // (edx:eax on ia32, r1:r0 on ARM).
9151 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9152 // In Win64 calling convention, a struct of two pointers is returned in memory,
9153 // allocated by the caller, and passed as a pointer in a hidden first parameter.
9154 #ifdef V8_HOST_ARCH_64_BIT
9155 struct ObjectPair {
9156 MaybeObject* x;
9157 MaybeObject* y;
9158 };
9159
9160
MakePair(MaybeObject * x,MaybeObject * y)9161 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
9162 ObjectPair result = {x, y};
9163 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9164 // In Win64 they are assigned to a hidden first argument.
9165 return result;
9166 }
9167 #else
9168 typedef uint64_t ObjectPair;
MakePair(MaybeObject * x,MaybeObject * y)9169 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
9170 return reinterpret_cast<uint32_t>(x) |
9171 (reinterpret_cast<ObjectPair>(y) << 32);
9172 }
9173 #endif
9174
9175
Unhole(Heap * heap,MaybeObject * x,PropertyAttributes attributes)9176 static inline MaybeObject* Unhole(Heap* heap,
9177 MaybeObject* x,
9178 PropertyAttributes attributes) {
9179 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9180 USE(attributes);
9181 return x->IsTheHole() ? heap->undefined_value() : x;
9182 }
9183
9184
ComputeReceiverForNonGlobal(Isolate * isolate,JSObject * holder)9185 static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9186 JSObject* holder) {
9187 ASSERT(!holder->IsGlobalObject());
9188 Context* top = isolate->context();
9189 // Get the context extension function.
9190 JSFunction* context_extension_function =
9191 top->native_context()->context_extension_function();
9192 // If the holder isn't a context extension object, we just return it
9193 // as the receiver. This allows arguments objects to be used as
9194 // receivers, but only if they are put in the context scope chain
9195 // explicitly via a with-statement.
9196 Object* constructor = holder->map()->constructor();
9197 if (constructor != context_extension_function) return holder;
9198 // Fall back to using the global object as the implicit receiver if
9199 // the property turns out to be a local variable allocated in a
9200 // context extension object - introduced via eval. Implicit global
9201 // receivers are indicated with the hole value.
9202 return isolate->heap()->the_hole_value();
9203 }
9204
9205
LoadContextSlotHelper(Arguments args,Isolate * isolate,bool throw_error)9206 static ObjectPair LoadContextSlotHelper(Arguments args,
9207 Isolate* isolate,
9208 bool throw_error) {
9209 HandleScope scope(isolate);
9210 ASSERT_EQ(2, args.length());
9211
9212 if (!args[0]->IsContext() || !args[1]->IsString()) {
9213 return MakePair(isolate->ThrowIllegalOperation(), NULL);
9214 }
9215 Handle<Context> context = args.at<Context>(0);
9216 Handle<String> name = args.at<String>(1);
9217
9218 int index;
9219 PropertyAttributes attributes;
9220 ContextLookupFlags flags = FOLLOW_CHAINS;
9221 BindingFlags binding_flags;
9222 Handle<Object> holder = context->Lookup(name,
9223 flags,
9224 &index,
9225 &attributes,
9226 &binding_flags);
9227 if (isolate->has_pending_exception()) {
9228 return MakePair(Failure::Exception(), NULL);
9229 }
9230
9231 // If the index is non-negative, the slot has been found in a context.
9232 if (index >= 0) {
9233 ASSERT(holder->IsContext());
9234 // If the "property" we were looking for is a local variable, the
9235 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
9236 //
9237 // Use the hole as the receiver to signal that the receiver is implicit
9238 // and that the global receiver should be used (as distinguished from an
9239 // explicit receiver that happens to be a global object).
9240 Handle<Object> receiver = isolate->factory()->the_hole_value();
9241 Object* value = Context::cast(*holder)->get(index);
9242 // Check for uninitialized bindings.
9243 switch (binding_flags) {
9244 case MUTABLE_CHECK_INITIALIZED:
9245 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9246 if (value->IsTheHole()) {
9247 Handle<Object> reference_error =
9248 isolate->factory()->NewReferenceError("not_defined",
9249 HandleVector(&name, 1));
9250 return MakePair(isolate->Throw(*reference_error), NULL);
9251 }
9252 // FALLTHROUGH
9253 case MUTABLE_IS_INITIALIZED:
9254 case IMMUTABLE_IS_INITIALIZED:
9255 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9256 ASSERT(!value->IsTheHole());
9257 return MakePair(value, *receiver);
9258 case IMMUTABLE_CHECK_INITIALIZED:
9259 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9260 case MISSING_BINDING:
9261 UNREACHABLE();
9262 return MakePair(NULL, NULL);
9263 }
9264 }
9265
9266 // Otherwise, if the slot was found the holder is a context extension
9267 // object, subject of a with, or a global object. We read the named
9268 // property from it.
9269 if (!holder.is_null()) {
9270 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
9271 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
9272 // GetProperty below can cause GC.
9273 Handle<Object> receiver_handle(
9274 object->IsGlobalObject()
9275 ? GlobalObject::cast(*object)->global_receiver()
9276 : object->IsJSProxy() ? static_cast<Object*>(*object)
9277 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
9278 isolate);
9279
9280 // No need to unhole the value here. This is taken care of by the
9281 // GetProperty function.
9282 MaybeObject* value = object->GetProperty(*name);
9283 return MakePair(value, *receiver_handle);
9284 }
9285
9286 if (throw_error) {
9287 // The property doesn't exist - throw exception.
9288 Handle<Object> reference_error =
9289 isolate->factory()->NewReferenceError("not_defined",
9290 HandleVector(&name, 1));
9291 return MakePair(isolate->Throw(*reference_error), NULL);
9292 } else {
9293 // The property doesn't exist - return undefined.
9294 return MakePair(isolate->heap()->undefined_value(),
9295 isolate->heap()->undefined_value());
9296 }
9297 }
9298
9299
RUNTIME_FUNCTION(ObjectPair,Runtime_LoadContextSlot)9300 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
9301 return LoadContextSlotHelper(args, isolate, true);
9302 }
9303
9304
RUNTIME_FUNCTION(ObjectPair,Runtime_LoadContextSlotNoReferenceError)9305 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
9306 return LoadContextSlotHelper(args, isolate, false);
9307 }
9308
9309
RUNTIME_FUNCTION(MaybeObject *,Runtime_StoreContextSlot)9310 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
9311 HandleScope scope(isolate);
9312 ASSERT(args.length() == 4);
9313
9314 Handle<Object> value(args[0], isolate);
9315 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9316 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
9317 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9318 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9319 ? kNonStrictMode : kStrictMode;
9320
9321 int index;
9322 PropertyAttributes attributes;
9323 ContextLookupFlags flags = FOLLOW_CHAINS;
9324 BindingFlags binding_flags;
9325 Handle<Object> holder = context->Lookup(name,
9326 flags,
9327 &index,
9328 &attributes,
9329 &binding_flags);
9330 if (isolate->has_pending_exception()) return Failure::Exception();
9331
9332 if (index >= 0) {
9333 // The property was found in a context slot.
9334 Handle<Context> context = Handle<Context>::cast(holder);
9335 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9336 context->get(index)->IsTheHole()) {
9337 Handle<Object> error =
9338 isolate->factory()->NewReferenceError("not_defined",
9339 HandleVector(&name, 1));
9340 return isolate->Throw(*error);
9341 }
9342 // Ignore if read_only variable.
9343 if ((attributes & READ_ONLY) == 0) {
9344 // Context is a fixed array and set cannot fail.
9345 context->set(index, *value);
9346 } else if (strict_mode == kStrictMode) {
9347 // Setting read only property in strict mode.
9348 Handle<Object> error =
9349 isolate->factory()->NewTypeError("strict_cannot_assign",
9350 HandleVector(&name, 1));
9351 return isolate->Throw(*error);
9352 }
9353 return *value;
9354 }
9355
9356 // Slow case: The property is not in a context slot. It is either in a
9357 // context extension object, a property of the subject of a with, or a
9358 // property of the global object.
9359 Handle<JSReceiver> object;
9360
9361 if (!holder.is_null()) {
9362 // The property exists on the holder.
9363 object = Handle<JSReceiver>::cast(holder);
9364 } else {
9365 // The property was not found.
9366 ASSERT(attributes == ABSENT);
9367
9368 if (strict_mode == kStrictMode) {
9369 // Throw in strict mode (assignment to undefined variable).
9370 Handle<Object> error =
9371 isolate->factory()->NewReferenceError(
9372 "not_defined", HandleVector(&name, 1));
9373 return isolate->Throw(*error);
9374 }
9375 // In non-strict mode, the property is added to the global object.
9376 attributes = NONE;
9377 object = Handle<JSReceiver>(isolate->context()->global_object());
9378 }
9379
9380 // Set the property if it's not read only or doesn't yet exist.
9381 if ((attributes & READ_ONLY) == 0 ||
9382 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
9383 RETURN_IF_EMPTY_HANDLE(
9384 isolate,
9385 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
9386 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
9387 // Setting read only property in strict mode.
9388 Handle<Object> error =
9389 isolate->factory()->NewTypeError(
9390 "strict_cannot_assign", HandleVector(&name, 1));
9391 return isolate->Throw(*error);
9392 }
9393 return *value;
9394 }
9395
9396
RUNTIME_FUNCTION(MaybeObject *,Runtime_Throw)9397 RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
9398 HandleScope scope(isolate);
9399 ASSERT(args.length() == 1);
9400
9401 return isolate->Throw(args[0]);
9402 }
9403
9404
RUNTIME_FUNCTION(MaybeObject *,Runtime_ReThrow)9405 RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
9406 HandleScope scope(isolate);
9407 ASSERT(args.length() == 1);
9408
9409 return isolate->ReThrow(args[0]);
9410 }
9411
9412
RUNTIME_FUNCTION(MaybeObject *,Runtime_PromoteScheduledException)9413 RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
9414 SealHandleScope shs(isolate);
9415 ASSERT_EQ(0, args.length());
9416 return isolate->PromoteScheduledException();
9417 }
9418
9419
RUNTIME_FUNCTION(MaybeObject *,Runtime_ThrowReferenceError)9420 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
9421 HandleScope scope(isolate);
9422 ASSERT(args.length() == 1);
9423
9424 Handle<Object> name(args[0], isolate);
9425 Handle<Object> reference_error =
9426 isolate->factory()->NewReferenceError("not_defined",
9427 HandleVector(&name, 1));
9428 return isolate->Throw(*reference_error);
9429 }
9430
9431
RUNTIME_FUNCTION(MaybeObject *,Runtime_ThrowNotDateError)9432 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) {
9433 HandleScope scope(isolate);
9434 ASSERT(args.length() == 0);
9435 return isolate->Throw(*isolate->factory()->NewTypeError(
9436 "not_date_object", HandleVector<Object>(NULL, 0)));
9437 }
9438
9439
RUNTIME_FUNCTION(MaybeObject *,Runtime_ThrowMessage)9440 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
9441 HandleScope scope(isolate);
9442 ASSERT(args.length() == 1);
9443 CONVERT_SMI_ARG_CHECKED(message_id, 0);
9444 const char* message = GetBailoutReason(
9445 static_cast<BailoutReason>(message_id));
9446 Handle<Name> message_handle =
9447 isolate->factory()->NewStringFromAscii(CStrVector(message));
9448 return isolate->Throw(*message_handle);
9449 }
9450
9451
RUNTIME_FUNCTION(MaybeObject *,Runtime_StackGuard)9452 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
9453 SealHandleScope shs(isolate);
9454 ASSERT(args.length() == 0);
9455
9456 // First check if this is a real stack overflow.
9457 if (isolate->stack_guard()->IsStackOverflow()) {
9458 return isolate->StackOverflow();
9459 }
9460
9461 return Execution::HandleStackGuardInterrupt(isolate);
9462 }
9463
9464
RUNTIME_FUNCTION(MaybeObject *,Runtime_TryInstallRecompiledCode)9465 RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) {
9466 HandleScope scope(isolate);
9467 ASSERT(args.length() == 1);
9468 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9469
9470 // First check if this is a real stack overflow.
9471 if (isolate->stack_guard()->IsStackOverflow()) {
9472 SealHandleScope shs(isolate);
9473 return isolate->StackOverflow();
9474 }
9475
9476 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9477 return (function->IsOptimized()) ? function->code()
9478 : function->shared()->code();
9479 }
9480
9481
RUNTIME_FUNCTION(MaybeObject *,Runtime_Interrupt)9482 RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9483 SealHandleScope shs(isolate);
9484 ASSERT(args.length() == 0);
9485 return Execution::HandleStackGuardInterrupt(isolate);
9486 }
9487
9488
StackSize(Isolate * isolate)9489 static int StackSize(Isolate* isolate) {
9490 int n = 0;
9491 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
9492 return n;
9493 }
9494
9495
PrintTransition(Isolate * isolate,Object * result)9496 static void PrintTransition(Isolate* isolate, Object* result) {
9497 // indentation
9498 { const int nmax = 80;
9499 int n = StackSize(isolate);
9500 if (n <= nmax)
9501 PrintF("%4d:%*s", n, n, "");
9502 else
9503 PrintF("%4d:%*s", n, nmax, "...");
9504 }
9505
9506 if (result == NULL) {
9507 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
9508 PrintF(" {\n");
9509 } else {
9510 // function result
9511 PrintF("} -> ");
9512 result->ShortPrint();
9513 PrintF("\n");
9514 }
9515 }
9516
9517
RUNTIME_FUNCTION(MaybeObject *,Runtime_TraceEnter)9518 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
9519 SealHandleScope shs(isolate);
9520 ASSERT(args.length() == 0);
9521 PrintTransition(isolate, NULL);
9522 return isolate->heap()->undefined_value();
9523 }
9524
9525
RUNTIME_FUNCTION(MaybeObject *,Runtime_TraceExit)9526 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
9527 SealHandleScope shs(isolate);
9528 PrintTransition(isolate, args[0]);
9529 return args[0]; // return TOS
9530 }
9531
9532
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPrint)9533 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
9534 SealHandleScope shs(isolate);
9535 ASSERT(args.length() == 1);
9536
9537 #ifdef DEBUG
9538 if (args[0]->IsString()) {
9539 // If we have a string, assume it's a code "marker"
9540 // and print some interesting cpu debugging info.
9541 JavaScriptFrameIterator it(isolate);
9542 JavaScriptFrame* frame = it.frame();
9543 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9544 frame->fp(), frame->sp(), frame->caller_sp());
9545 } else {
9546 PrintF("DebugPrint: ");
9547 }
9548 args[0]->Print();
9549 if (args[0]->IsHeapObject()) {
9550 PrintF("\n");
9551 HeapObject::cast(args[0])->map()->Print();
9552 }
9553 #else
9554 // ShortPrint is available in release mode. Print is not.
9555 args[0]->ShortPrint();
9556 #endif
9557 PrintF("\n");
9558 Flush();
9559
9560 return args[0]; // return TOS
9561 }
9562
9563
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugTrace)9564 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
9565 SealHandleScope shs(isolate);
9566 ASSERT(args.length() == 0);
9567 isolate->PrintStack(stdout);
9568 return isolate->heap()->undefined_value();
9569 }
9570
9571
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateCurrentTime)9572 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
9573 SealHandleScope shs(isolate);
9574 ASSERT(args.length() == 0);
9575
9576 // According to ECMA-262, section 15.9.1, page 117, the precision of
9577 // the number in a Date object representing a particular instant in
9578 // time is milliseconds. Therefore, we floor the result of getting
9579 // the OS time.
9580 double millis = floor(OS::TimeCurrentMillis());
9581 return isolate->heap()->NumberFromDouble(millis);
9582 }
9583
9584
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateParseString)9585 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
9586 HandleScope scope(isolate);
9587 ASSERT(args.length() == 2);
9588
9589 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
9590 FlattenString(str);
9591
9592 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
9593
9594 JSObject::EnsureCanContainHeapObjectElements(output);
9595 RUNTIME_ASSERT(output->HasFastObjectElements());
9596
9597 DisallowHeapAllocation no_gc;
9598
9599 FixedArray* output_array = FixedArray::cast(output->elements());
9600 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9601 bool result;
9602 String::FlatContent str_content = str->GetFlatContent();
9603 if (str_content.IsAscii()) {
9604 result = DateParser::Parse(str_content.ToOneByteVector(),
9605 output_array,
9606 isolate->unicode_cache());
9607 } else {
9608 ASSERT(str_content.IsTwoByte());
9609 result = DateParser::Parse(str_content.ToUC16Vector(),
9610 output_array,
9611 isolate->unicode_cache());
9612 }
9613
9614 if (result) {
9615 return *output;
9616 } else {
9617 return isolate->heap()->null_value();
9618 }
9619 }
9620
9621
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateLocalTimezone)9622 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
9623 SealHandleScope shs(isolate);
9624 ASSERT(args.length() == 1);
9625
9626 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9627 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9628 const char* zone = OS::LocalTimezone(static_cast<double>(time));
9629 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
9630 }
9631
9632
RUNTIME_FUNCTION(MaybeObject *,Runtime_DateToUTC)9633 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
9634 SealHandleScope shs(isolate);
9635 ASSERT(args.length() == 1);
9636
9637 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9638 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9639
9640 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
9641 }
9642
9643
RUNTIME_FUNCTION(MaybeObject *,Runtime_GlobalReceiver)9644 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
9645 SealHandleScope shs(isolate);
9646 ASSERT(args.length() == 1);
9647 Object* global = args[0];
9648 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
9649 return JSGlobalObject::cast(global)->global_receiver();
9650 }
9651
9652
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsAttachedGlobal)9653 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) {
9654 SealHandleScope shs(isolate);
9655 ASSERT(args.length() == 1);
9656 Object* global = args[0];
9657 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
9658 return isolate->heap()->ToBoolean(
9659 !JSGlobalObject::cast(global)->IsDetached());
9660 }
9661
9662
RUNTIME_FUNCTION(MaybeObject *,Runtime_ParseJson)9663 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
9664 HandleScope scope(isolate);
9665 ASSERT_EQ(1, args.length());
9666 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9667
9668 source = Handle<String>(FlattenGetString(source));
9669 // Optimized fast case where we only have ASCII characters.
9670 Handle<Object> result;
9671 if (source->IsSeqOneByteString()) {
9672 result = JsonParser<true>::Parse(source);
9673 } else {
9674 result = JsonParser<false>::Parse(source);
9675 }
9676 if (result.is_null()) {
9677 // Syntax error or stack overflow in scanner.
9678 ASSERT(isolate->has_pending_exception());
9679 return Failure::Exception();
9680 }
9681 return *result;
9682 }
9683
9684
CodeGenerationFromStringsAllowed(Isolate * isolate,Handle<Context> context)9685 bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9686 Handle<Context> context) {
9687 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9688 // Check with callback if set.
9689 AllowCodeGenerationFromStringsCallback callback =
9690 isolate->allow_code_gen_callback();
9691 if (callback == NULL) {
9692 // No callback set and code generation disallowed.
9693 return false;
9694 } else {
9695 // Callback set. Let it decide if code generation is allowed.
9696 VMState<EXTERNAL> state(isolate);
9697 return callback(v8::Utils::ToLocal(context));
9698 }
9699 }
9700
9701
RUNTIME_FUNCTION(MaybeObject *,Runtime_CompileString)9702 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
9703 HandleScope scope(isolate);
9704 ASSERT_EQ(2, args.length());
9705 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9706 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
9707
9708 // Extract native context.
9709 Handle<Context> context(isolate->context()->native_context());
9710
9711 // Check if native context allows code generation from
9712 // strings. Throw an exception if it doesn't.
9713 if (context->allow_code_gen_from_strings()->IsFalse() &&
9714 !CodeGenerationFromStringsAllowed(isolate, context)) {
9715 Handle<Object> error_message =
9716 context->ErrorMessageForCodeGenerationFromStrings();
9717 return isolate->Throw(*isolate->factory()->NewEvalError(
9718 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9719 }
9720
9721 // Compile source string in the native context.
9722 ParseRestriction restriction = function_literal_only
9723 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
9724 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9725 source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition);
9726 RETURN_IF_EMPTY_HANDLE(isolate, shared);
9727 Handle<JSFunction> fun =
9728 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9729 context,
9730 NOT_TENURED);
9731 return *fun;
9732 }
9733
9734
CompileGlobalEval(Isolate * isolate,Handle<String> source,Handle<Object> receiver,LanguageMode language_mode,int scope_position)9735 static ObjectPair CompileGlobalEval(Isolate* isolate,
9736 Handle<String> source,
9737 Handle<Object> receiver,
9738 LanguageMode language_mode,
9739 int scope_position) {
9740 Handle<Context> context = Handle<Context>(isolate->context());
9741 Handle<Context> native_context = Handle<Context>(context->native_context());
9742
9743 // Check if native context allows code generation from
9744 // strings. Throw an exception if it doesn't.
9745 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9746 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
9747 Handle<Object> error_message =
9748 native_context->ErrorMessageForCodeGenerationFromStrings();
9749 isolate->Throw(*isolate->factory()->NewEvalError(
9750 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9751 return MakePair(Failure::Exception(), NULL);
9752 }
9753
9754 // Deal with a normal eval call with a string argument. Compile it
9755 // and return the compiled function bound in the local context.
9756 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9757 source,
9758 context,
9759 context->IsNativeContext(),
9760 language_mode,
9761 NO_PARSE_RESTRICTION,
9762 scope_position);
9763 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared,
9764 MakePair(Failure::Exception(), NULL));
9765 Handle<JSFunction> compiled =
9766 isolate->factory()->NewFunctionFromSharedFunctionInfo(
9767 shared, context, NOT_TENURED);
9768 return MakePair(*compiled, *receiver);
9769 }
9770
9771
RUNTIME_FUNCTION(ObjectPair,Runtime_ResolvePossiblyDirectEval)9772 RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
9773 HandleScope scope(isolate);
9774 ASSERT(args.length() == 5);
9775
9776 Handle<Object> callee = args.at<Object>(0);
9777
9778 // If "eval" didn't refer to the original GlobalEval, it's not a
9779 // direct call to eval.
9780 // (And even if it is, but the first argument isn't a string, just let
9781 // execution default to an indirect call to eval, which will also return
9782 // the first argument without doing anything).
9783 if (*callee != isolate->native_context()->global_eval_fun() ||
9784 !args[1]->IsString()) {
9785 return MakePair(*callee, isolate->heap()->the_hole_value());
9786 }
9787
9788 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9789 ASSERT(args[4]->IsSmi());
9790 return CompileGlobalEval(isolate,
9791 args.at<String>(1),
9792 args.at<Object>(2),
9793 language_mode,
9794 args.smi_at(4));
9795 }
9796
9797
9798 // Allocate a block of memory in the given space (filled with a filler).
9799 // Used as a fall-back for generated code when the space is full.
Allocate(Isolate * isolate,int size,bool double_align,AllocationSpace space)9800 static MaybeObject* Allocate(Isolate* isolate,
9801 int size,
9802 bool double_align,
9803 AllocationSpace space) {
9804 Heap* heap = isolate->heap();
9805 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9806 RUNTIME_ASSERT(size > 0);
9807 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize());
9808 HeapObject* allocation;
9809 { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space);
9810 if (!maybe_allocation->To(&allocation)) return maybe_allocation;
9811 }
9812 #ifdef DEBUG
9813 MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address());
9814 ASSERT(chunk->owner()->identity() == space);
9815 #endif
9816 heap->CreateFillerObjectAt(allocation->address(), size);
9817 return allocation;
9818 }
9819
9820
RUNTIME_FUNCTION(MaybeObject *,Runtime_AllocateInNewSpace)9821 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
9822 SealHandleScope shs(isolate);
9823 ASSERT(args.length() == 1);
9824 CONVERT_SMI_ARG_CHECKED(size, 0);
9825 return Allocate(isolate, size, false, NEW_SPACE);
9826 }
9827
9828
RUNTIME_FUNCTION(MaybeObject *,Runtime_AllocateInTargetSpace)9829 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInTargetSpace) {
9830 SealHandleScope shs(isolate);
9831 ASSERT(args.length() == 2);
9832 CONVERT_SMI_ARG_CHECKED(size, 0);
9833 CONVERT_SMI_ARG_CHECKED(flags, 1);
9834 bool double_align = AllocateDoubleAlignFlag::decode(flags);
9835 AllocationSpace space = AllocateTargetSpace::decode(flags);
9836 return Allocate(isolate, size, double_align, space);
9837 }
9838
9839
9840 // Push an object unto an array of objects if it is not already in the
9841 // array. Returns true if the element was pushed on the stack and
9842 // false otherwise.
RUNTIME_FUNCTION(MaybeObject *,Runtime_PushIfAbsent)9843 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
9844 HandleScope scope(isolate);
9845 ASSERT(args.length() == 2);
9846 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
9847 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
9848 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
9849 int length = Smi::cast(array->length())->value();
9850 FixedArray* elements = FixedArray::cast(array->elements());
9851 for (int i = 0; i < length; i++) {
9852 if (elements->get(i) == *element) return isolate->heap()->false_value();
9853 }
9854
9855 // Strict not needed. Used for cycle detection in Array join implementation.
9856 RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length,
9857 element,
9858 kNonStrictMode,
9859 true));
9860 return isolate->heap()->true_value();
9861 }
9862
9863
9864 /**
9865 * A simple visitor visits every element of Array's.
9866 * The backend storage can be a fixed array for fast elements case,
9867 * or a dictionary for sparse array. Since Dictionary is a subtype
9868 * of FixedArray, the class can be used by both fast and slow cases.
9869 * The second parameter of the constructor, fast_elements, specifies
9870 * whether the storage is a FixedArray or Dictionary.
9871 *
9872 * An index limit is used to deal with the situation that a result array
9873 * length overflows 32-bit non-negative integer.
9874 */
9875 class ArrayConcatVisitor {
9876 public:
ArrayConcatVisitor(Isolate * isolate,Handle<FixedArray> storage,bool fast_elements)9877 ArrayConcatVisitor(Isolate* isolate,
9878 Handle<FixedArray> storage,
9879 bool fast_elements) :
9880 isolate_(isolate),
9881 storage_(Handle<FixedArray>::cast(
9882 isolate->global_handles()->Create(*storage))),
9883 index_offset_(0u),
9884 fast_elements_(fast_elements),
9885 exceeds_array_limit_(false) { }
9886
~ArrayConcatVisitor()9887 ~ArrayConcatVisitor() {
9888 clear_storage();
9889 }
9890
visit(uint32_t i,Handle<Object> elm)9891 void visit(uint32_t i, Handle<Object> elm) {
9892 if (i > JSObject::kMaxElementCount - index_offset_) {
9893 exceeds_array_limit_ = true;
9894 return;
9895 }
9896 uint32_t index = index_offset_ + i;
9897
9898 if (fast_elements_) {
9899 if (index < static_cast<uint32_t>(storage_->length())) {
9900 storage_->set(index, *elm);
9901 return;
9902 }
9903 // Our initial estimate of length was foiled, possibly by
9904 // getters on the arrays increasing the length of later arrays
9905 // during iteration.
9906 // This shouldn't happen in anything but pathological cases.
9907 SetDictionaryMode(index);
9908 // Fall-through to dictionary mode.
9909 }
9910 ASSERT(!fast_elements_);
9911 Handle<SeededNumberDictionary> dict(
9912 SeededNumberDictionary::cast(*storage_));
9913 Handle<SeededNumberDictionary> result =
9914 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
9915 if (!result.is_identical_to(dict)) {
9916 // Dictionary needed to grow.
9917 clear_storage();
9918 set_storage(*result);
9919 }
9920 }
9921
increase_index_offset(uint32_t delta)9922 void increase_index_offset(uint32_t delta) {
9923 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9924 index_offset_ = JSObject::kMaxElementCount;
9925 } else {
9926 index_offset_ += delta;
9927 }
9928 }
9929
exceeds_array_limit()9930 bool exceeds_array_limit() {
9931 return exceeds_array_limit_;
9932 }
9933
ToArray()9934 Handle<JSArray> ToArray() {
9935 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
9936 Handle<Object> length =
9937 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
9938 Handle<Map> map;
9939 if (fast_elements_) {
9940 map = isolate_->factory()->GetElementsTransitionMap(array,
9941 FAST_HOLEY_ELEMENTS);
9942 } else {
9943 map = isolate_->factory()->GetElementsTransitionMap(array,
9944 DICTIONARY_ELEMENTS);
9945 }
9946 array->set_map(*map);
9947 array->set_length(*length);
9948 array->set_elements(*storage_);
9949 return array;
9950 }
9951
9952 private:
9953 // Convert storage to dictionary mode.
SetDictionaryMode(uint32_t index)9954 void SetDictionaryMode(uint32_t index) {
9955 ASSERT(fast_elements_);
9956 Handle<FixedArray> current_storage(*storage_);
9957 Handle<SeededNumberDictionary> slow_storage(
9958 isolate_->factory()->NewSeededNumberDictionary(
9959 current_storage->length()));
9960 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9961 for (uint32_t i = 0; i < current_length; i++) {
9962 HandleScope loop_scope(isolate_);
9963 Handle<Object> element(current_storage->get(i), isolate_);
9964 if (!element->IsTheHole()) {
9965 Handle<SeededNumberDictionary> new_storage =
9966 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
9967 if (!new_storage.is_identical_to(slow_storage)) {
9968 slow_storage = loop_scope.CloseAndEscape(new_storage);
9969 }
9970 }
9971 }
9972 clear_storage();
9973 set_storage(*slow_storage);
9974 fast_elements_ = false;
9975 }
9976
clear_storage()9977 inline void clear_storage() {
9978 isolate_->global_handles()->Destroy(
9979 Handle<Object>::cast(storage_).location());
9980 }
9981
set_storage(FixedArray * storage)9982 inline void set_storage(FixedArray* storage) {
9983 storage_ = Handle<FixedArray>::cast(
9984 isolate_->global_handles()->Create(storage));
9985 }
9986
9987 Isolate* isolate_;
9988 Handle<FixedArray> storage_; // Always a global handle.
9989 // Index after last seen index. Always less than or equal to
9990 // JSObject::kMaxElementCount.
9991 uint32_t index_offset_;
9992 bool fast_elements_ : 1;
9993 bool exceeds_array_limit_ : 1;
9994 };
9995
9996
EstimateElementCount(Handle<JSArray> array)9997 static uint32_t EstimateElementCount(Handle<JSArray> array) {
9998 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9999 int element_count = 0;
10000 switch (array->GetElementsKind()) {
10001 case FAST_SMI_ELEMENTS:
10002 case FAST_HOLEY_SMI_ELEMENTS:
10003 case FAST_ELEMENTS:
10004 case FAST_HOLEY_ELEMENTS: {
10005 // Fast elements can't have lengths that are not representable by
10006 // a 32-bit signed integer.
10007 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
10008 int fast_length = static_cast<int>(length);
10009 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
10010 for (int i = 0; i < fast_length; i++) {
10011 if (!elements->get(i)->IsTheHole()) element_count++;
10012 }
10013 break;
10014 }
10015 case FAST_DOUBLE_ELEMENTS:
10016 case FAST_HOLEY_DOUBLE_ELEMENTS: {
10017 // Fast elements can't have lengths that are not representable by
10018 // a 32-bit signed integer.
10019 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
10020 int fast_length = static_cast<int>(length);
10021 if (array->elements()->IsFixedArray()) {
10022 ASSERT(FixedArray::cast(array->elements())->length() == 0);
10023 break;
10024 }
10025 Handle<FixedDoubleArray> elements(
10026 FixedDoubleArray::cast(array->elements()));
10027 for (int i = 0; i < fast_length; i++) {
10028 if (!elements->is_the_hole(i)) element_count++;
10029 }
10030 break;
10031 }
10032 case DICTIONARY_ELEMENTS: {
10033 Handle<SeededNumberDictionary> dictionary(
10034 SeededNumberDictionary::cast(array->elements()));
10035 int capacity = dictionary->Capacity();
10036 for (int i = 0; i < capacity; i++) {
10037 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
10038 if (dictionary->IsKey(*key)) {
10039 element_count++;
10040 }
10041 }
10042 break;
10043 }
10044 case NON_STRICT_ARGUMENTS_ELEMENTS:
10045 case EXTERNAL_BYTE_ELEMENTS:
10046 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10047 case EXTERNAL_SHORT_ELEMENTS:
10048 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10049 case EXTERNAL_INT_ELEMENTS:
10050 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10051 case EXTERNAL_FLOAT_ELEMENTS:
10052 case EXTERNAL_DOUBLE_ELEMENTS:
10053 case EXTERNAL_PIXEL_ELEMENTS:
10054 // External arrays are always dense.
10055 return length;
10056 }
10057 // As an estimate, we assume that the prototype doesn't contain any
10058 // inherited elements.
10059 return element_count;
10060 }
10061
10062
10063
10064 template<class ExternalArrayClass, class ElementType>
IterateExternalArrayElements(Isolate * isolate,Handle<JSObject> receiver,bool elements_are_ints,bool elements_are_guaranteed_smis,ArrayConcatVisitor * visitor)10065 static void IterateExternalArrayElements(Isolate* isolate,
10066 Handle<JSObject> receiver,
10067 bool elements_are_ints,
10068 bool elements_are_guaranteed_smis,
10069 ArrayConcatVisitor* visitor) {
10070 Handle<ExternalArrayClass> array(
10071 ExternalArrayClass::cast(receiver->elements()));
10072 uint32_t len = static_cast<uint32_t>(array->length());
10073
10074 ASSERT(visitor != NULL);
10075 if (elements_are_ints) {
10076 if (elements_are_guaranteed_smis) {
10077 for (uint32_t j = 0; j < len; j++) {
10078 HandleScope loop_scope(isolate);
10079 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10080 isolate);
10081 visitor->visit(j, e);
10082 }
10083 } else {
10084 for (uint32_t j = 0; j < len; j++) {
10085 HandleScope loop_scope(isolate);
10086 int64_t val = static_cast<int64_t>(array->get_scalar(j));
10087 if (Smi::IsValid(static_cast<intptr_t>(val))) {
10088 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
10089 visitor->visit(j, e);
10090 } else {
10091 Handle<Object> e =
10092 isolate->factory()->NewNumber(static_cast<ElementType>(val));
10093 visitor->visit(j, e);
10094 }
10095 }
10096 }
10097 } else {
10098 for (uint32_t j = 0; j < len; j++) {
10099 HandleScope loop_scope(isolate);
10100 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
10101 visitor->visit(j, e);
10102 }
10103 }
10104 }
10105
10106
10107 // Used for sorting indices in a List<uint32_t>.
compareUInt32(const uint32_t * ap,const uint32_t * bp)10108 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10109 uint32_t a = *ap;
10110 uint32_t b = *bp;
10111 return (a == b) ? 0 : (a < b) ? -1 : 1;
10112 }
10113
10114
CollectElementIndices(Handle<JSObject> object,uint32_t range,List<uint32_t> * indices)10115 static void CollectElementIndices(Handle<JSObject> object,
10116 uint32_t range,
10117 List<uint32_t>* indices) {
10118 Isolate* isolate = object->GetIsolate();
10119 ElementsKind kind = object->GetElementsKind();
10120 switch (kind) {
10121 case FAST_SMI_ELEMENTS:
10122 case FAST_ELEMENTS:
10123 case FAST_HOLEY_SMI_ELEMENTS:
10124 case FAST_HOLEY_ELEMENTS: {
10125 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10126 uint32_t length = static_cast<uint32_t>(elements->length());
10127 if (range < length) length = range;
10128 for (uint32_t i = 0; i < length; i++) {
10129 if (!elements->get(i)->IsTheHole()) {
10130 indices->Add(i);
10131 }
10132 }
10133 break;
10134 }
10135 case FAST_HOLEY_DOUBLE_ELEMENTS:
10136 case FAST_DOUBLE_ELEMENTS: {
10137 // TODO(1810): Decide if it's worthwhile to implement this.
10138 UNREACHABLE();
10139 break;
10140 }
10141 case DICTIONARY_ELEMENTS: {
10142 Handle<SeededNumberDictionary> dict(
10143 SeededNumberDictionary::cast(object->elements()));
10144 uint32_t capacity = dict->Capacity();
10145 for (uint32_t j = 0; j < capacity; j++) {
10146 HandleScope loop_scope(isolate);
10147 Handle<Object> k(dict->KeyAt(j), isolate);
10148 if (dict->IsKey(*k)) {
10149 ASSERT(k->IsNumber());
10150 uint32_t index = static_cast<uint32_t>(k->Number());
10151 if (index < range) {
10152 indices->Add(index);
10153 }
10154 }
10155 }
10156 break;
10157 }
10158 default: {
10159 int dense_elements_length;
10160 switch (kind) {
10161 case EXTERNAL_PIXEL_ELEMENTS: {
10162 dense_elements_length =
10163 ExternalPixelArray::cast(object->elements())->length();
10164 break;
10165 }
10166 case EXTERNAL_BYTE_ELEMENTS: {
10167 dense_elements_length =
10168 ExternalByteArray::cast(object->elements())->length();
10169 break;
10170 }
10171 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
10172 dense_elements_length =
10173 ExternalUnsignedByteArray::cast(object->elements())->length();
10174 break;
10175 }
10176 case EXTERNAL_SHORT_ELEMENTS: {
10177 dense_elements_length =
10178 ExternalShortArray::cast(object->elements())->length();
10179 break;
10180 }
10181 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
10182 dense_elements_length =
10183 ExternalUnsignedShortArray::cast(object->elements())->length();
10184 break;
10185 }
10186 case EXTERNAL_INT_ELEMENTS: {
10187 dense_elements_length =
10188 ExternalIntArray::cast(object->elements())->length();
10189 break;
10190 }
10191 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
10192 dense_elements_length =
10193 ExternalUnsignedIntArray::cast(object->elements())->length();
10194 break;
10195 }
10196 case EXTERNAL_FLOAT_ELEMENTS: {
10197 dense_elements_length =
10198 ExternalFloatArray::cast(object->elements())->length();
10199 break;
10200 }
10201 case EXTERNAL_DOUBLE_ELEMENTS: {
10202 dense_elements_length =
10203 ExternalDoubleArray::cast(object->elements())->length();
10204 break;
10205 }
10206 default:
10207 UNREACHABLE();
10208 dense_elements_length = 0;
10209 break;
10210 }
10211 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10212 if (range <= length) {
10213 length = range;
10214 // We will add all indices, so we might as well clear it first
10215 // and avoid duplicates.
10216 indices->Clear();
10217 }
10218 for (uint32_t i = 0; i < length; i++) {
10219 indices->Add(i);
10220 }
10221 if (length == range) return; // All indices accounted for already.
10222 break;
10223 }
10224 }
10225
10226 Handle<Object> prototype(object->GetPrototype(), isolate);
10227 if (prototype->IsJSObject()) {
10228 // The prototype will usually have no inherited element indices,
10229 // but we have to check.
10230 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10231 }
10232 }
10233
10234
10235 /**
10236 * A helper function that visits elements of a JSArray in numerical
10237 * order.
10238 *
10239 * The visitor argument called for each existing element in the array
10240 * with the element index and the element's value.
10241 * Afterwards it increments the base-index of the visitor by the array
10242 * length.
10243 * Returns false if any access threw an exception, otherwise true.
10244 */
IterateElements(Isolate * isolate,Handle<JSArray> receiver,ArrayConcatVisitor * visitor)10245 static bool IterateElements(Isolate* isolate,
10246 Handle<JSArray> receiver,
10247 ArrayConcatVisitor* visitor) {
10248 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10249 switch (receiver->GetElementsKind()) {
10250 case FAST_SMI_ELEMENTS:
10251 case FAST_ELEMENTS:
10252 case FAST_HOLEY_SMI_ELEMENTS:
10253 case FAST_HOLEY_ELEMENTS: {
10254 // Run through the elements FixedArray and use HasElement and GetElement
10255 // to check the prototype for missing elements.
10256 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10257 int fast_length = static_cast<int>(length);
10258 ASSERT(fast_length <= elements->length());
10259 for (int j = 0; j < fast_length; j++) {
10260 HandleScope loop_scope(isolate);
10261 Handle<Object> element_value(elements->get(j), isolate);
10262 if (!element_value->IsTheHole()) {
10263 visitor->visit(j, element_value);
10264 } else if (JSReceiver::HasElement(receiver, j)) {
10265 // Call GetElement on receiver, not its prototype, or getters won't
10266 // have the correct receiver.
10267 element_value = Object::GetElement(isolate, receiver, j);
10268 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10269 visitor->visit(j, element_value);
10270 }
10271 }
10272 break;
10273 }
10274 case FAST_HOLEY_DOUBLE_ELEMENTS:
10275 case FAST_DOUBLE_ELEMENTS: {
10276 // Run through the elements FixedArray and use HasElement and GetElement
10277 // to check the prototype for missing elements.
10278 Handle<FixedDoubleArray> elements(
10279 FixedDoubleArray::cast(receiver->elements()));
10280 int fast_length = static_cast<int>(length);
10281 ASSERT(fast_length <= elements->length());
10282 for (int j = 0; j < fast_length; j++) {
10283 HandleScope loop_scope(isolate);
10284 if (!elements->is_the_hole(j)) {
10285 double double_value = elements->get_scalar(j);
10286 Handle<Object> element_value =
10287 isolate->factory()->NewNumber(double_value);
10288 visitor->visit(j, element_value);
10289 } else if (JSReceiver::HasElement(receiver, j)) {
10290 // Call GetElement on receiver, not its prototype, or getters won't
10291 // have the correct receiver.
10292 Handle<Object> element_value =
10293 Object::GetElement(isolate, receiver, j);
10294 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10295 visitor->visit(j, element_value);
10296 }
10297 }
10298 break;
10299 }
10300 case DICTIONARY_ELEMENTS: {
10301 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
10302 List<uint32_t> indices(dict->Capacity() / 2);
10303 // Collect all indices in the object and the prototypes less
10304 // than length. This might introduce duplicates in the indices list.
10305 CollectElementIndices(receiver, length, &indices);
10306 indices.Sort(&compareUInt32);
10307 int j = 0;
10308 int n = indices.length();
10309 while (j < n) {
10310 HandleScope loop_scope(isolate);
10311 uint32_t index = indices[j];
10312 Handle<Object> element = Object::GetElement(isolate, receiver, index);
10313 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
10314 visitor->visit(index, element);
10315 // Skip to next different index (i.e., omit duplicates).
10316 do {
10317 j++;
10318 } while (j < n && indices[j] == index);
10319 }
10320 break;
10321 }
10322 case EXTERNAL_PIXEL_ELEMENTS: {
10323 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10324 receiver->elements()));
10325 for (uint32_t j = 0; j < length; j++) {
10326 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
10327 visitor->visit(j, e);
10328 }
10329 break;
10330 }
10331 case EXTERNAL_BYTE_ELEMENTS: {
10332 IterateExternalArrayElements<ExternalByteArray, int8_t>(
10333 isolate, receiver, true, true, visitor);
10334 break;
10335 }
10336 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
10337 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
10338 isolate, receiver, true, true, visitor);
10339 break;
10340 }
10341 case EXTERNAL_SHORT_ELEMENTS: {
10342 IterateExternalArrayElements<ExternalShortArray, int16_t>(
10343 isolate, receiver, true, true, visitor);
10344 break;
10345 }
10346 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
10347 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
10348 isolate, receiver, true, true, visitor);
10349 break;
10350 }
10351 case EXTERNAL_INT_ELEMENTS: {
10352 IterateExternalArrayElements<ExternalIntArray, int32_t>(
10353 isolate, receiver, true, false, visitor);
10354 break;
10355 }
10356 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
10357 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
10358 isolate, receiver, true, false, visitor);
10359 break;
10360 }
10361 case EXTERNAL_FLOAT_ELEMENTS: {
10362 IterateExternalArrayElements<ExternalFloatArray, float>(
10363 isolate, receiver, false, false, visitor);
10364 break;
10365 }
10366 case EXTERNAL_DOUBLE_ELEMENTS: {
10367 IterateExternalArrayElements<ExternalDoubleArray, double>(
10368 isolate, receiver, false, false, visitor);
10369 break;
10370 }
10371 default:
10372 UNREACHABLE();
10373 break;
10374 }
10375 visitor->increase_index_offset(length);
10376 return true;
10377 }
10378
10379
10380 /**
10381 * Array::concat implementation.
10382 * See ECMAScript 262, 15.4.4.4.
10383 * TODO(581): Fix non-compliance for very large concatenations and update to
10384 * following the ECMAScript 5 specification.
10385 */
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayConcat)10386 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
10387 HandleScope handle_scope(isolate);
10388 ASSERT(args.length() == 1);
10389
10390 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
10391 int argument_count = static_cast<int>(arguments->length()->Number());
10392 RUNTIME_ASSERT(arguments->HasFastObjectElements());
10393 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
10394
10395 // Pass 1: estimate the length and number of elements of the result.
10396 // The actual length can be larger if any of the arguments have getters
10397 // that mutate other arguments (but will otherwise be precise).
10398 // The number of elements is precise if there are no inherited elements.
10399
10400 ElementsKind kind = FAST_SMI_ELEMENTS;
10401
10402 uint32_t estimate_result_length = 0;
10403 uint32_t estimate_nof_elements = 0;
10404 for (int i = 0; i < argument_count; i++) {
10405 HandleScope loop_scope(isolate);
10406 Handle<Object> obj(elements->get(i), isolate);
10407 uint32_t length_estimate;
10408 uint32_t element_estimate;
10409 if (obj->IsJSArray()) {
10410 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10411 length_estimate = static_cast<uint32_t>(array->length()->Number());
10412 if (length_estimate != 0) {
10413 ElementsKind array_kind =
10414 GetPackedElementsKind(array->map()->elements_kind());
10415 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10416 kind = array_kind;
10417 }
10418 }
10419 element_estimate = EstimateElementCount(array);
10420 } else {
10421 if (obj->IsHeapObject()) {
10422 if (obj->IsNumber()) {
10423 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10424 kind = FAST_DOUBLE_ELEMENTS;
10425 }
10426 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10427 kind = FAST_ELEMENTS;
10428 }
10429 }
10430 length_estimate = 1;
10431 element_estimate = 1;
10432 }
10433 // Avoid overflows by capping at kMaxElementCount.
10434 if (JSObject::kMaxElementCount - estimate_result_length <
10435 length_estimate) {
10436 estimate_result_length = JSObject::kMaxElementCount;
10437 } else {
10438 estimate_result_length += length_estimate;
10439 }
10440 if (JSObject::kMaxElementCount - estimate_nof_elements <
10441 element_estimate) {
10442 estimate_nof_elements = JSObject::kMaxElementCount;
10443 } else {
10444 estimate_nof_elements += element_estimate;
10445 }
10446 }
10447
10448 // If estimated number of elements is more than half of length, a
10449 // fixed array (fast case) is more time and space-efficient than a
10450 // dictionary.
10451 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
10452
10453 Handle<FixedArray> storage;
10454 if (fast_case) {
10455 if (kind == FAST_DOUBLE_ELEMENTS) {
10456 Handle<FixedDoubleArray> double_storage =
10457 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10458 int j = 0;
10459 bool failure = false;
10460 for (int i = 0; i < argument_count; i++) {
10461 Handle<Object> obj(elements->get(i), isolate);
10462 if (obj->IsSmi()) {
10463 double_storage->set(j, Smi::cast(*obj)->value());
10464 j++;
10465 } else if (obj->IsNumber()) {
10466 double_storage->set(j, obj->Number());
10467 j++;
10468 } else {
10469 JSArray* array = JSArray::cast(*obj);
10470 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10471 switch (array->map()->elements_kind()) {
10472 case FAST_HOLEY_DOUBLE_ELEMENTS:
10473 case FAST_DOUBLE_ELEMENTS: {
10474 // Empty fixed array indicates that there are no elements.
10475 if (array->elements()->IsFixedArray()) break;
10476 FixedDoubleArray* elements =
10477 FixedDoubleArray::cast(array->elements());
10478 for (uint32_t i = 0; i < length; i++) {
10479 if (elements->is_the_hole(i)) {
10480 failure = true;
10481 break;
10482 }
10483 double double_value = elements->get_scalar(i);
10484 double_storage->set(j, double_value);
10485 j++;
10486 }
10487 break;
10488 }
10489 case FAST_HOLEY_SMI_ELEMENTS:
10490 case FAST_SMI_ELEMENTS: {
10491 FixedArray* elements(
10492 FixedArray::cast(array->elements()));
10493 for (uint32_t i = 0; i < length; i++) {
10494 Object* element = elements->get(i);
10495 if (element->IsTheHole()) {
10496 failure = true;
10497 break;
10498 }
10499 int32_t int_value = Smi::cast(element)->value();
10500 double_storage->set(j, int_value);
10501 j++;
10502 }
10503 break;
10504 }
10505 case FAST_HOLEY_ELEMENTS:
10506 ASSERT_EQ(0, length);
10507 break;
10508 default:
10509 UNREACHABLE();
10510 }
10511 }
10512 if (failure) break;
10513 }
10514 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10515 Smi* length = Smi::FromInt(j);
10516 Handle<Map> map;
10517 map = isolate->factory()->GetElementsTransitionMap(array, kind);
10518 array->set_map(*map);
10519 array->set_length(length);
10520 array->set_elements(*double_storage);
10521 return *array;
10522 }
10523 // The backing storage array must have non-existing elements to preserve
10524 // holes across concat operations.
10525 storage = isolate->factory()->NewFixedArrayWithHoles(
10526 estimate_result_length);
10527 } else {
10528 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10529 uint32_t at_least_space_for = estimate_nof_elements +
10530 (estimate_nof_elements >> 2);
10531 storage = Handle<FixedArray>::cast(
10532 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
10533 }
10534
10535 ArrayConcatVisitor visitor(isolate, storage, fast_case);
10536
10537 for (int i = 0; i < argument_count; i++) {
10538 Handle<Object> obj(elements->get(i), isolate);
10539 if (obj->IsJSArray()) {
10540 Handle<JSArray> array = Handle<JSArray>::cast(obj);
10541 if (!IterateElements(isolate, array, &visitor)) {
10542 return Failure::Exception();
10543 }
10544 } else {
10545 visitor.visit(0, obj);
10546 visitor.increase_index_offset(1);
10547 }
10548 }
10549
10550 if (visitor.exceeds_array_limit()) {
10551 return isolate->Throw(
10552 *isolate->factory()->NewRangeError("invalid_array_length",
10553 HandleVector<Object>(NULL, 0)));
10554 }
10555 return *visitor.ToArray();
10556 }
10557
10558
10559 // This will not allocate (flatten the string), but it may run
10560 // very slowly for very deeply nested ConsStrings. For debugging use only.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GlobalPrint)10561 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
10562 SealHandleScope shs(isolate);
10563 ASSERT(args.length() == 1);
10564
10565 CONVERT_ARG_CHECKED(String, string, 0);
10566 ConsStringIteratorOp op;
10567 StringCharacterStream stream(string, &op);
10568 while (stream.HasMore()) {
10569 uint16_t character = stream.GetNext();
10570 PrintF("%c", character);
10571 }
10572 return string;
10573 }
10574
10575
10576 // Moves all own elements of an object, that are below a limit, to positions
10577 // starting at zero. All undefined values are placed after non-undefined values,
10578 // and are followed by non-existing element. Does not change the length
10579 // property.
10580 // Returns the number of non-undefined elements collected.
RUNTIME_FUNCTION(MaybeObject *,Runtime_RemoveArrayHoles)10581 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
10582 HandleScope scope(isolate);
10583 ASSERT(args.length() == 2);
10584 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
10585 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10586 return *JSObject::PrepareElementsForSort(object, limit);
10587 }
10588
10589
10590 // Move contents of argument 0 (an array) to argument 1 (an array)
RUNTIME_FUNCTION(MaybeObject *,Runtime_MoveArrayContents)10591 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
10592 SealHandleScope shs(isolate);
10593 ASSERT(args.length() == 2);
10594 CONVERT_ARG_CHECKED(JSArray, from, 0);
10595 CONVERT_ARG_CHECKED(JSArray, to, 1);
10596 from->ValidateElements();
10597 to->ValidateElements();
10598 FixedArrayBase* new_elements = from->elements();
10599 ElementsKind from_kind = from->GetElementsKind();
10600 MaybeObject* maybe_new_map;
10601 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
10602 Object* new_map;
10603 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10604 to->set_map_and_elements(Map::cast(new_map), new_elements);
10605 to->set_length(from->length());
10606 Object* obj;
10607 { MaybeObject* maybe_obj = from->ResetElements();
10608 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10609 }
10610 from->set_length(Smi::FromInt(0));
10611 to->ValidateElements();
10612 return to;
10613 }
10614
10615
10616 // How many elements does this object/array have?
RUNTIME_FUNCTION(MaybeObject *,Runtime_EstimateNumberOfElements)10617 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
10618 SealHandleScope shs(isolate);
10619 ASSERT(args.length() == 1);
10620 CONVERT_ARG_CHECKED(JSObject, object, 0);
10621 HeapObject* elements = object->elements();
10622 if (elements->IsDictionary()) {
10623 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10624 return Smi::FromInt(result);
10625 } else if (object->IsJSArray()) {
10626 return JSArray::cast(object)->length();
10627 } else {
10628 return Smi::FromInt(FixedArray::cast(elements)->length());
10629 }
10630 }
10631
10632
10633 // Returns an array that tells you where in the [0, length) interval an array
10634 // might have elements. Can either return an array of keys (positive integers
10635 // or undefined) or a number representing the positive length of an interval
10636 // starting at index 0.
10637 // Intervals can span over some keys that are not in the object.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetArrayKeys)10638 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
10639 HandleScope scope(isolate);
10640 ASSERT(args.length() == 2);
10641 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
10642 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
10643 if (array->elements()->IsDictionary()) {
10644 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10645 for (Handle<Object> p = array;
10646 !p->IsNull();
10647 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10648 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10649 // Bail out if we find a proxy or interceptor, likely not worth
10650 // collecting keys in that case.
10651 return *isolate->factory()->NewNumberFromUint(length);
10652 }
10653 Handle<JSObject> current = Handle<JSObject>::cast(p);
10654 Handle<FixedArray> current_keys =
10655 isolate->factory()->NewFixedArray(
10656 current->NumberOfLocalElements(NONE));
10657 current->GetLocalElementKeys(*current_keys, NONE);
10658 keys = UnionOfKeys(keys, current_keys);
10659 }
10660 // Erase any keys >= length.
10661 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10662 // is changed to let this happen on the JS side.
10663 for (int i = 0; i < keys->length(); i++) {
10664 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
10665 }
10666 return *isolate->factory()->NewJSArrayWithElements(keys);
10667 } else {
10668 ASSERT(array->HasFastSmiOrObjectElements() ||
10669 array->HasFastDoubleElements());
10670 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10671 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
10672 }
10673 }
10674
10675
RUNTIME_FUNCTION(MaybeObject *,Runtime_LookupAccessor)10676 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
10677 HandleScope scope(isolate);
10678 ASSERT(args.length() == 3);
10679 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10680 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10681 CONVERT_SMI_ARG_CHECKED(flag, 2);
10682 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10683 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
10684 Handle<Object> result =
10685 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component);
10686 RETURN_IF_EMPTY_HANDLE(isolate, result);
10687 return *result;
10688 }
10689
10690
10691 #ifdef ENABLE_DEBUGGER_SUPPORT
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugBreak)10692 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
10693 SealHandleScope shs(isolate);
10694 ASSERT(args.length() == 0);
10695 return Execution::DebugBreakHelper(isolate);
10696 }
10697
10698
10699 // Helper functions for wrapping and unwrapping stack frame ids.
WrapFrameId(StackFrame::Id id)10700 static Smi* WrapFrameId(StackFrame::Id id) {
10701 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
10702 return Smi::FromInt(id >> 2);
10703 }
10704
10705
UnwrapFrameId(int wrapped)10706 static StackFrame::Id UnwrapFrameId(int wrapped) {
10707 return static_cast<StackFrame::Id>(wrapped << 2);
10708 }
10709
10710
10711 // Adds a JavaScript function as a debug event listener.
10712 // args[0]: debug event listener function to set or null or undefined for
10713 // clearing the event listener function
10714 // args[1]: object supplied during callback
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetDebugEventListener)10715 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
10716 SealHandleScope shs(isolate);
10717 ASSERT(args.length() == 2);
10718 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10719 args[0]->IsUndefined() ||
10720 args[0]->IsNull());
10721 Handle<Object> callback = args.at<Object>(0);
10722 Handle<Object> data = args.at<Object>(1);
10723 isolate->debugger()->SetEventListener(callback, data);
10724
10725 return isolate->heap()->undefined_value();
10726 }
10727
10728
RUNTIME_FUNCTION(MaybeObject *,Runtime_Break)10729 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
10730 SealHandleScope shs(isolate);
10731 ASSERT(args.length() == 0);
10732 isolate->stack_guard()->DebugBreak();
10733 return isolate->heap()->undefined_value();
10734 }
10735
10736
DebugLookupResultValue(Heap * heap,Object * receiver,Name * name,LookupResult * result,bool * caught_exception)10737 static MaybeObject* DebugLookupResultValue(Heap* heap,
10738 Object* receiver,
10739 Name* name,
10740 LookupResult* result,
10741 bool* caught_exception) {
10742 Object* value;
10743 switch (result->type()) {
10744 case NORMAL:
10745 value = result->holder()->GetNormalizedProperty(result);
10746 if (value->IsTheHole()) {
10747 return heap->undefined_value();
10748 }
10749 return value;
10750 case FIELD: {
10751 Object* value;
10752 MaybeObject* maybe_value =
10753 JSObject::cast(result->holder())->FastPropertyAt(
10754 result->representation(),
10755 result->GetFieldIndex().field_index());
10756 if (!maybe_value->To(&value)) return maybe_value;
10757 if (value->IsTheHole()) {
10758 return heap->undefined_value();
10759 }
10760 return value;
10761 }
10762 case CONSTANT:
10763 return result->GetConstant();
10764 case CALLBACKS: {
10765 Object* structure = result->GetCallbackObject();
10766 if (structure->IsForeign() || structure->IsAccessorInfo()) {
10767 Isolate* isolate = heap->isolate();
10768 HandleScope scope(isolate);
10769 Handle<Object> value = JSObject::GetPropertyWithCallback(
10770 handle(result->holder(), isolate),
10771 handle(receiver, isolate),
10772 handle(structure, isolate),
10773 handle(name, isolate));
10774 if (value.is_null()) {
10775 MaybeObject* exception = heap->isolate()->pending_exception();
10776 heap->isolate()->clear_pending_exception();
10777 if (caught_exception != NULL) *caught_exception = true;
10778 return exception;
10779 }
10780 return *value;
10781 } else {
10782 return heap->undefined_value();
10783 }
10784 }
10785 case INTERCEPTOR:
10786 case TRANSITION:
10787 return heap->undefined_value();
10788 case HANDLER:
10789 case NONEXISTENT:
10790 UNREACHABLE();
10791 return heap->undefined_value();
10792 }
10793 UNREACHABLE(); // keep the compiler happy
10794 return heap->undefined_value();
10795 }
10796
10797
10798 // Get debugger related details for an object property.
10799 // args[0]: object holding property
10800 // args[1]: name of the property
10801 //
10802 // The array returned contains the following information:
10803 // 0: Property value
10804 // 1: Property details
10805 // 2: Property value is exception
10806 // 3: Getter function if defined
10807 // 4: Setter function if defined
10808 // Items 2-4 are only filled if the property has either a getter or a setter
10809 // defined through __defineGetter__ and/or __defineSetter__.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugGetPropertyDetails)10810 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
10811 HandleScope scope(isolate);
10812
10813 ASSERT(args.length() == 2);
10814
10815 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10816 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10817
10818 // Make sure to set the current context to the context before the debugger was
10819 // entered (if the debugger is entered). The reason for switching context here
10820 // is that for some property lookups (accessors and interceptors) callbacks
10821 // into the embedding application can occour, and the embedding application
10822 // could have the assumption that its own native context is the current
10823 // context and not some internal debugger context.
10824 SaveContext save(isolate);
10825 if (isolate->debug()->InDebugger()) {
10826 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
10827 }
10828
10829 // Skip the global proxy as it has no properties and always delegates to the
10830 // real global object.
10831 if (obj->IsJSGlobalProxy()) {
10832 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10833 }
10834
10835
10836 // Check if the name is trivially convertible to an index and get the element
10837 // if so.
10838 uint32_t index;
10839 if (name->AsArrayIndex(&index)) {
10840 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
10841 Object* element_or_char;
10842 { MaybeObject* maybe_element_or_char =
10843 Runtime::GetElementOrCharAt(isolate, obj, index);
10844 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10845 return maybe_element_or_char;
10846 }
10847 }
10848 details->set(0, element_or_char);
10849 details->set(
10850 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
10851 return *isolate->factory()->NewJSArrayWithElements(details);
10852 }
10853
10854 // Find the number of objects making up this.
10855 int length = LocalPrototypeChainLength(*obj);
10856
10857 // Try local lookup on each of the objects.
10858 Handle<JSObject> jsproto = obj;
10859 for (int i = 0; i < length; i++) {
10860 LookupResult result(isolate);
10861 jsproto->LocalLookup(*name, &result);
10862 if (result.IsFound()) {
10863 // LookupResult is not GC safe as it holds raw object pointers.
10864 // GC can happen later in this code so put the required fields into
10865 // local variables using handles when required for later use.
10866 Handle<Object> result_callback_obj;
10867 if (result.IsPropertyCallbacks()) {
10868 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10869 isolate);
10870 }
10871 Smi* property_details = result.GetPropertyDetails().AsSmi();
10872 // DebugLookupResultValue can cause GC so details from LookupResult needs
10873 // to be copied to handles before this.
10874 bool caught_exception = false;
10875 Object* raw_value;
10876 { MaybeObject* maybe_raw_value =
10877 DebugLookupResultValue(isolate->heap(), *obj, *name,
10878 &result, &caught_exception);
10879 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10880 }
10881 Handle<Object> value(raw_value, isolate);
10882
10883 // If the callback object is a fixed array then it contains JavaScript
10884 // getter and/or setter.
10885 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
10886 result_callback_obj->IsAccessorPair();
10887 Handle<FixedArray> details =
10888 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
10889 details->set(0, *value);
10890 details->set(1, property_details);
10891 if (hasJavaScriptAccessors) {
10892 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
10893 details->set(2, isolate->heap()->ToBoolean(caught_exception));
10894 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10895 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
10896 }
10897
10898 return *isolate->factory()->NewJSArrayWithElements(details);
10899 }
10900 if (i < length - 1) {
10901 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10902 }
10903 }
10904
10905 return isolate->heap()->undefined_value();
10906 }
10907
10908
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugGetProperty)10909 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
10910 HandleScope scope(isolate);
10911
10912 ASSERT(args.length() == 2);
10913
10914 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10915 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10916
10917 LookupResult result(isolate);
10918 obj->Lookup(*name, &result);
10919 if (result.IsFound()) {
10920 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
10921 }
10922 return isolate->heap()->undefined_value();
10923 }
10924
10925
10926 // Return the property type calculated from the property details.
10927 // args[0]: smi with property details.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPropertyTypeFromDetails)10928 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
10929 SealHandleScope shs(isolate);
10930 ASSERT(args.length() == 1);
10931 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10932 return Smi::FromInt(static_cast<int>(details.type()));
10933 }
10934
10935
10936 // Return the property attribute calculated from the property details.
10937 // args[0]: smi with property details.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPropertyAttributesFromDetails)10938 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
10939 SealHandleScope shs(isolate);
10940 ASSERT(args.length() == 1);
10941 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10942 return Smi::FromInt(static_cast<int>(details.attributes()));
10943 }
10944
10945
10946 // Return the property insertion index calculated from the property details.
10947 // args[0]: smi with property details.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPropertyIndexFromDetails)10948 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
10949 SealHandleScope shs(isolate);
10950 ASSERT(args.length() == 1);
10951 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10952 // TODO(verwaest): Depends on the type of details.
10953 return Smi::FromInt(details.dictionary_index());
10954 }
10955
10956
10957 // Return property value from named interceptor.
10958 // args[0]: object
10959 // args[1]: property name
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugNamedInterceptorPropertyValue)10960 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
10961 HandleScope scope(isolate);
10962 ASSERT(args.length() == 2);
10963 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10964 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10965 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10966
10967 PropertyAttributes attributes;
10968 Handle<Object> result =
10969 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes);
10970 RETURN_IF_EMPTY_HANDLE(isolate, result);
10971 return *result;
10972 }
10973
10974
10975 // Return element value from indexed interceptor.
10976 // args[0]: object
10977 // args[1]: index
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugIndexedInterceptorElementValue)10978 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
10979 HandleScope scope(isolate);
10980 ASSERT(args.length() == 2);
10981 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10982 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10983 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10984
10985 return obj->GetElementWithInterceptor(*obj, index);
10986 }
10987
10988
RUNTIME_FUNCTION(MaybeObject *,Runtime_CheckExecutionState)10989 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
10990 SealHandleScope shs(isolate);
10991 ASSERT(args.length() >= 1);
10992 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
10993 // Check that the break id is valid.
10994 if (isolate->debug()->break_id() == 0 ||
10995 break_id != isolate->debug()->break_id()) {
10996 return isolate->Throw(
10997 isolate->heap()->illegal_execution_state_string());
10998 }
10999
11000 return isolate->heap()->true_value();
11001 }
11002
11003
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFrameCount)11004 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
11005 HandleScope scope(isolate);
11006 ASSERT(args.length() == 1);
11007
11008 // Check arguments.
11009 Object* result;
11010 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11011 RUNTIME_ARGUMENTS(isolate, args));
11012 if (!maybe_result->ToObject(&result)) return maybe_result;
11013 }
11014
11015 // Count all frames which are relevant to debugging stack trace.
11016 int n = 0;
11017 StackFrame::Id id = isolate->debug()->break_frame_id();
11018 if (id == StackFrame::NO_ID) {
11019 // If there is no JavaScript stack frame count is 0.
11020 return Smi::FromInt(0);
11021 }
11022
11023 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
11024 n += it.frame()->GetInlineCount();
11025 }
11026 return Smi::FromInt(n);
11027 }
11028
11029
11030 class FrameInspector {
11031 public:
FrameInspector(JavaScriptFrame * frame,int inlined_jsframe_index,Isolate * isolate)11032 FrameInspector(JavaScriptFrame* frame,
11033 int inlined_jsframe_index,
11034 Isolate* isolate)
11035 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
11036 // Calculate the deoptimized frame.
11037 if (frame->is_optimized()) {
11038 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
11039 frame, inlined_jsframe_index, isolate);
11040 }
11041 has_adapted_arguments_ = frame_->has_adapted_arguments();
11042 is_bottommost_ = inlined_jsframe_index == 0;
11043 is_optimized_ = frame_->is_optimized();
11044 }
11045
~FrameInspector()11046 ~FrameInspector() {
11047 // Get rid of the calculated deoptimized frame if any.
11048 if (deoptimized_frame_ != NULL) {
11049 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
11050 isolate_);
11051 }
11052 }
11053
GetParametersCount()11054 int GetParametersCount() {
11055 return is_optimized_
11056 ? deoptimized_frame_->parameters_count()
11057 : frame_->ComputeParametersCount();
11058 }
expression_count()11059 int expression_count() { return deoptimized_frame_->expression_count(); }
GetFunction()11060 Object* GetFunction() {
11061 return is_optimized_
11062 ? deoptimized_frame_->GetFunction()
11063 : frame_->function();
11064 }
GetParameter(int index)11065 Object* GetParameter(int index) {
11066 return is_optimized_
11067 ? deoptimized_frame_->GetParameter(index)
11068 : frame_->GetParameter(index);
11069 }
GetExpression(int index)11070 Object* GetExpression(int index) {
11071 return is_optimized_
11072 ? deoptimized_frame_->GetExpression(index)
11073 : frame_->GetExpression(index);
11074 }
GetSourcePosition()11075 int GetSourcePosition() {
11076 return is_optimized_
11077 ? deoptimized_frame_->GetSourcePosition()
11078 : frame_->LookupCode()->SourcePosition(frame_->pc());
11079 }
IsConstructor()11080 bool IsConstructor() {
11081 return is_optimized_ && !is_bottommost_
11082 ? deoptimized_frame_->HasConstructStub()
11083 : frame_->IsConstructor();
11084 }
11085
11086 // To inspect all the provided arguments the frame might need to be
11087 // replaced with the arguments frame.
SetArgumentsFrame(JavaScriptFrame * frame)11088 void SetArgumentsFrame(JavaScriptFrame* frame) {
11089 ASSERT(has_adapted_arguments_);
11090 frame_ = frame;
11091 is_optimized_ = frame_->is_optimized();
11092 ASSERT(!is_optimized_);
11093 }
11094
11095 private:
11096 JavaScriptFrame* frame_;
11097 DeoptimizedFrameInfo* deoptimized_frame_;
11098 Isolate* isolate_;
11099 bool is_optimized_;
11100 bool is_bottommost_;
11101 bool has_adapted_arguments_;
11102
11103 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11104 };
11105
11106
11107 static const int kFrameDetailsFrameIdIndex = 0;
11108 static const int kFrameDetailsReceiverIndex = 1;
11109 static const int kFrameDetailsFunctionIndex = 2;
11110 static const int kFrameDetailsArgumentCountIndex = 3;
11111 static const int kFrameDetailsLocalCountIndex = 4;
11112 static const int kFrameDetailsSourcePositionIndex = 5;
11113 static const int kFrameDetailsConstructCallIndex = 6;
11114 static const int kFrameDetailsAtReturnIndex = 7;
11115 static const int kFrameDetailsFlagsIndex = 8;
11116 static const int kFrameDetailsFirstDynamicIndex = 9;
11117
11118
FindSavedContextForFrame(Isolate * isolate,JavaScriptFrame * frame)11119 static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11120 JavaScriptFrame* frame) {
11121 SaveContext* save = isolate->save_context();
11122 while (save != NULL && !save->IsBelowFrame(frame)) {
11123 save = save->prev();
11124 }
11125 ASSERT(save != NULL);
11126 return save;
11127 }
11128
11129
11130 // Return an array with frame details
11131 // args[0]: number: break id
11132 // args[1]: number: frame index
11133 //
11134 // The array returned contains the following information:
11135 // 0: Frame id
11136 // 1: Receiver
11137 // 2: Function
11138 // 3: Argument count
11139 // 4: Local count
11140 // 5: Source position
11141 // 6: Constructor call
11142 // 7: Is at return
11143 // 8: Flags
11144 // Arguments name, value
11145 // Locals name, value
11146 // Return value if any
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFrameDetails)11147 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
11148 HandleScope scope(isolate);
11149 ASSERT(args.length() == 2);
11150
11151 // Check arguments.
11152 Object* check;
11153 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11154 RUNTIME_ARGUMENTS(isolate, args));
11155 if (!maybe_check->ToObject(&check)) return maybe_check;
11156 }
11157 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11158 Heap* heap = isolate->heap();
11159
11160 // Find the relevant frame with the requested index.
11161 StackFrame::Id id = isolate->debug()->break_frame_id();
11162 if (id == StackFrame::NO_ID) {
11163 // If there are no JavaScript stack frames return undefined.
11164 return heap->undefined_value();
11165 }
11166
11167 int count = 0;
11168 JavaScriptFrameIterator it(isolate, id);
11169 for (; !it.done(); it.Advance()) {
11170 if (index < count + it.frame()->GetInlineCount()) break;
11171 count += it.frame()->GetInlineCount();
11172 }
11173 if (it.done()) return heap->undefined_value();
11174
11175 bool is_optimized = it.frame()->is_optimized();
11176
11177 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11178 if (is_optimized) {
11179 inlined_jsframe_index =
11180 it.frame()->GetInlineCount() - (index - count) - 1;
11181 }
11182 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
11183
11184 // Traverse the saved contexts chain to find the active context for the
11185 // selected frame.
11186 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
11187
11188 // Get the frame id.
11189 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
11190
11191 // Find source position in unoptimized code.
11192 int position = frame_inspector.GetSourcePosition();
11193
11194 // Check for constructor frame.
11195 bool constructor = frame_inspector.IsConstructor();
11196
11197 // Get scope info and read from it for local variable information.
11198 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11199 Handle<SharedFunctionInfo> shared(function->shared());
11200 Handle<ScopeInfo> scope_info(shared->scope_info());
11201 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
11202
11203 // Get the locals names and values into a temporary array.
11204 //
11205 // TODO(1240907): Hide compiler-introduced stack variables
11206 // (e.g. .result)? For users of the debugger, they will probably be
11207 // confusing.
11208 Handle<FixedArray> locals =
11209 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
11210
11211 // Fill in the values of the locals.
11212 int i = 0;
11213 for (; i < scope_info->StackLocalCount(); ++i) {
11214 // Use the value from the stack.
11215 locals->set(i * 2, scope_info->LocalName(i));
11216 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
11217 }
11218 if (i < scope_info->LocalCount()) {
11219 // Get the context containing declarations.
11220 Handle<Context> context(
11221 Context::cast(it.frame()->context())->declaration_context());
11222 for (; i < scope_info->LocalCount(); ++i) {
11223 Handle<String> name(scope_info->LocalName(i));
11224 VariableMode mode;
11225 InitializationFlag init_flag;
11226 locals->set(i * 2, *name);
11227 locals->set(i * 2 + 1, context->get(
11228 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
11229 }
11230 }
11231
11232 // Check whether this frame is positioned at return. If not top
11233 // frame or if the frame is optimized it cannot be at a return.
11234 bool at_return = false;
11235 if (!is_optimized && index == 0) {
11236 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
11237 }
11238
11239 // If positioned just before return find the value to be returned and add it
11240 // to the frame information.
11241 Handle<Object> return_value = isolate->factory()->undefined_value();
11242 if (at_return) {
11243 StackFrameIterator it2(isolate);
11244 Address internal_frame_sp = NULL;
11245 while (!it2.done()) {
11246 if (it2.frame()->is_internal()) {
11247 internal_frame_sp = it2.frame()->sp();
11248 } else {
11249 if (it2.frame()->is_java_script()) {
11250 if (it2.frame()->id() == it.frame()->id()) {
11251 // The internal frame just before the JavaScript frame contains the
11252 // value to return on top. A debug break at return will create an
11253 // internal frame to store the return value (eax/rax/r0) before
11254 // entering the debug break exit frame.
11255 if (internal_frame_sp != NULL) {
11256 return_value =
11257 Handle<Object>(Memory::Object_at(internal_frame_sp),
11258 isolate);
11259 break;
11260 }
11261 }
11262 }
11263
11264 // Indicate that the previous frame was not an internal frame.
11265 internal_frame_sp = NULL;
11266 }
11267 it2.Advance();
11268 }
11269 }
11270
11271 // Now advance to the arguments adapter frame (if any). It contains all
11272 // the provided parameters whereas the function frame always have the number
11273 // of arguments matching the functions parameters. The rest of the
11274 // information (except for what is collected above) is the same.
11275 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
11276 it.AdvanceToArgumentsFrame();
11277 frame_inspector.SetArgumentsFrame(it.frame());
11278 }
11279
11280 // Find the number of arguments to fill. At least fill the number of
11281 // parameters for the function and fill more if more parameters are provided.
11282 int argument_count = scope_info->ParameterCount();
11283 if (argument_count < frame_inspector.GetParametersCount()) {
11284 argument_count = frame_inspector.GetParametersCount();
11285 }
11286
11287 // Calculate the size of the result.
11288 int details_size = kFrameDetailsFirstDynamicIndex +
11289 2 * (argument_count + scope_info->LocalCount()) +
11290 (at_return ? 1 : 0);
11291 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
11292
11293 // Add the frame id.
11294 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11295
11296 // Add the function (same as in function frame).
11297 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
11298
11299 // Add the arguments count.
11300 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11301
11302 // Add the locals count
11303 details->set(kFrameDetailsLocalCountIndex,
11304 Smi::FromInt(scope_info->LocalCount()));
11305
11306 // Add the source position.
11307 if (position != RelocInfo::kNoPosition) {
11308 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11309 } else {
11310 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
11311 }
11312
11313 // Add the constructor information.
11314 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
11315
11316 // Add the at return information.
11317 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
11318
11319 // Add flags to indicate information on whether this frame is
11320 // bit 0: invoked in the debugger context.
11321 // bit 1: optimized frame.
11322 // bit 2: inlined in optimized frame
11323 int flags = 0;
11324 if (*save->context() == *isolate->debug()->debug_context()) {
11325 flags |= 1 << 0;
11326 }
11327 if (is_optimized) {
11328 flags |= 1 << 1;
11329 flags |= inlined_jsframe_index << 2;
11330 }
11331 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
11332
11333 // Fill the dynamic part.
11334 int details_index = kFrameDetailsFirstDynamicIndex;
11335
11336 // Add arguments name and value.
11337 for (int i = 0; i < argument_count; i++) {
11338 // Name of the argument.
11339 if (i < scope_info->ParameterCount()) {
11340 details->set(details_index++, scope_info->ParameterName(i));
11341 } else {
11342 details->set(details_index++, heap->undefined_value());
11343 }
11344
11345 // Parameter value.
11346 if (i < frame_inspector.GetParametersCount()) {
11347 // Get the value from the stack.
11348 details->set(details_index++, frame_inspector.GetParameter(i));
11349 } else {
11350 details->set(details_index++, heap->undefined_value());
11351 }
11352 }
11353
11354 // Add locals name and value from the temporary copy from the function frame.
11355 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
11356 details->set(details_index++, locals->get(i));
11357 }
11358
11359 // Add the value being returned.
11360 if (at_return) {
11361 details->set(details_index++, *return_value);
11362 }
11363
11364 // Add the receiver (same as in function frame).
11365 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11366 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
11367 Handle<Object> receiver(it.frame()->receiver(), isolate);
11368 if (!receiver->IsJSObject() &&
11369 shared->is_classic_mode() &&
11370 !function->IsBuiltin()) {
11371 // If the receiver is not a JSObject and the function is not a
11372 // builtin or strict-mode we have hit an optimization where a
11373 // value object is not converted into a wrapped JS objects. To
11374 // hide this optimization from the debugger, we wrap the receiver
11375 // by creating correct wrapper object based on the calling frame's
11376 // native context.
11377 it.Advance();
11378 Handle<Context> calling_frames_native_context(
11379 Context::cast(Context::cast(it.frame()->context())->native_context()));
11380 ASSERT(!receiver->IsUndefined() && !receiver->IsNull());
11381 receiver =
11382 isolate->factory()->ToObject(receiver, calling_frames_native_context);
11383 }
11384 details->set(kFrameDetailsReceiverIndex, *receiver);
11385
11386 ASSERT_EQ(details_size, details_index);
11387 return *isolate->factory()->NewJSArrayWithElements(details);
11388 }
11389
11390
11391 // Create a plain JSObject which materializes the local scope for the specified
11392 // frame.
MaterializeStackLocalsWithFrameInspector(Isolate * isolate,Handle<JSObject> target,Handle<JSFunction> function,FrameInspector * frame_inspector)11393 static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
11394 Isolate* isolate,
11395 Handle<JSObject> target,
11396 Handle<JSFunction> function,
11397 FrameInspector* frame_inspector) {
11398 Handle<SharedFunctionInfo> shared(function->shared());
11399 Handle<ScopeInfo> scope_info(shared->scope_info());
11400
11401 // First fill all parameters.
11402 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11403 Handle<Object> value(i < frame_inspector->GetParametersCount()
11404 ? frame_inspector->GetParameter(i)
11405 : isolate->heap()->undefined_value(),
11406 isolate);
11407 ASSERT(!value->IsTheHole());
11408
11409 RETURN_IF_EMPTY_HANDLE_VALUE(
11410 isolate,
11411 Runtime::SetObjectProperty(isolate,
11412 target,
11413 Handle<String>(scope_info->ParameterName(i)),
11414 value,
11415 NONE,
11416 kNonStrictMode),
11417 Handle<JSObject>());
11418 }
11419
11420 // Second fill all stack locals.
11421 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11422 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11423 if (value->IsTheHole()) continue;
11424
11425 RETURN_IF_EMPTY_HANDLE_VALUE(
11426 isolate,
11427 Runtime::SetObjectProperty(
11428 isolate,
11429 target,
11430 Handle<String>(scope_info->StackLocalName(i)),
11431 value,
11432 NONE,
11433 kNonStrictMode),
11434 Handle<JSObject>());
11435 }
11436
11437 return target;
11438 }
11439
11440
UpdateStackLocalsFromMaterializedObject(Isolate * isolate,Handle<JSObject> target,Handle<JSFunction> function,JavaScriptFrame * frame,int inlined_jsframe_index)11441 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11442 Handle<JSObject> target,
11443 Handle<JSFunction> function,
11444 JavaScriptFrame* frame,
11445 int inlined_jsframe_index) {
11446 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11447 // Optimized frames are not supported.
11448 // TODO(yangguo): make sure all code deoptimized when debugger is active
11449 // and assert that this cannot happen.
11450 return;
11451 }
11452
11453 Handle<SharedFunctionInfo> shared(function->shared());
11454 Handle<ScopeInfo> scope_info(shared->scope_info());
11455
11456 // Parameters.
11457 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11458 ASSERT(!frame->GetParameter(i)->IsTheHole());
11459 HandleScope scope(isolate);
11460 Handle<Object> value = GetProperty(
11461 isolate, target, Handle<String>(scope_info->ParameterName(i)));
11462 frame->SetParameterValue(i, *value);
11463 }
11464
11465 // Stack locals.
11466 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11467 if (frame->GetExpression(i)->IsTheHole()) continue;
11468 HandleScope scope(isolate);
11469 Handle<Object> value = GetProperty(
11470 isolate, target, Handle<String>(scope_info->StackLocalName(i)));
11471 frame->SetExpression(i, *value);
11472 }
11473 }
11474
11475
MaterializeLocalContext(Isolate * isolate,Handle<JSObject> target,Handle<JSFunction> function,JavaScriptFrame * frame)11476 static Handle<JSObject> MaterializeLocalContext(Isolate* isolate,
11477 Handle<JSObject> target,
11478 Handle<JSFunction> function,
11479 JavaScriptFrame* frame) {
11480 HandleScope scope(isolate);
11481 Handle<SharedFunctionInfo> shared(function->shared());
11482 Handle<ScopeInfo> scope_info(shared->scope_info());
11483
11484 if (!scope_info->HasContext()) return target;
11485
11486 // Third fill all context locals.
11487 Handle<Context> frame_context(Context::cast(frame->context()));
11488 Handle<Context> function_context(frame_context->declaration_context());
11489 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11490 scope_info, function_context, target)) {
11491 return Handle<JSObject>();
11492 }
11493
11494 // Finally copy any properties from the function context extension.
11495 // These will be variables introduced by eval.
11496 if (function_context->closure() == *function) {
11497 if (function_context->has_extension() &&
11498 !function_context->IsNativeContext()) {
11499 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11500 bool threw = false;
11501 Handle<FixedArray> keys =
11502 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11503 if (threw) return Handle<JSObject>();
11504
11505 for (int i = 0; i < keys->length(); i++) {
11506 // Names of variables introduced by eval are strings.
11507 ASSERT(keys->get(i)->IsString());
11508 Handle<String> key(String::cast(keys->get(i)));
11509 RETURN_IF_EMPTY_HANDLE_VALUE(
11510 isolate,
11511 Runtime::SetObjectProperty(isolate,
11512 target,
11513 key,
11514 GetProperty(isolate, ext, key),
11515 NONE,
11516 kNonStrictMode),
11517 Handle<JSObject>());
11518 }
11519 }
11520 }
11521
11522 return target;
11523 }
11524
11525
MaterializeLocalScope(Isolate * isolate,JavaScriptFrame * frame,int inlined_jsframe_index)11526 static Handle<JSObject> MaterializeLocalScope(
11527 Isolate* isolate,
11528 JavaScriptFrame* frame,
11529 int inlined_jsframe_index) {
11530 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11531 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11532
11533 Handle<JSObject> local_scope =
11534 isolate->factory()->NewJSObject(isolate->object_function());
11535 local_scope = MaterializeStackLocalsWithFrameInspector(
11536 isolate, local_scope, function, &frame_inspector);
11537 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
11538
11539 return MaterializeLocalContext(isolate, local_scope, function, frame);
11540 }
11541
11542
11543 // Set the context local variable value.
SetContextLocalValue(Isolate * isolate,Handle<ScopeInfo> scope_info,Handle<Context> context,Handle<String> variable_name,Handle<Object> new_value)11544 static bool SetContextLocalValue(Isolate* isolate,
11545 Handle<ScopeInfo> scope_info,
11546 Handle<Context> context,
11547 Handle<String> variable_name,
11548 Handle<Object> new_value) {
11549 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11550 Handle<String> next_name(scope_info->ContextLocalName(i));
11551 if (variable_name->Equals(*next_name)) {
11552 VariableMode mode;
11553 InitializationFlag init_flag;
11554 int context_index =
11555 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
11556 context->set(context_index, *new_value);
11557 return true;
11558 }
11559 }
11560
11561 return false;
11562 }
11563
11564
SetLocalVariableValue(Isolate * isolate,JavaScriptFrame * frame,int inlined_jsframe_index,Handle<String> variable_name,Handle<Object> new_value)11565 static bool SetLocalVariableValue(Isolate* isolate,
11566 JavaScriptFrame* frame,
11567 int inlined_jsframe_index,
11568 Handle<String> variable_name,
11569 Handle<Object> new_value) {
11570 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11571 // Optimized frames are not supported.
11572 return false;
11573 }
11574
11575 Handle<JSFunction> function(frame->function());
11576 Handle<SharedFunctionInfo> shared(function->shared());
11577 Handle<ScopeInfo> scope_info(shared->scope_info());
11578
11579 bool default_result = false;
11580
11581 // Parameters.
11582 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11583 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
11584 frame->SetParameterValue(i, *new_value);
11585 // Argument might be shadowed in heap context, don't stop here.
11586 default_result = true;
11587 }
11588 }
11589
11590 // Stack locals.
11591 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11592 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
11593 frame->SetExpression(i, *new_value);
11594 return true;
11595 }
11596 }
11597
11598 if (scope_info->HasContext()) {
11599 // Context locals.
11600 Handle<Context> frame_context(Context::cast(frame->context()));
11601 Handle<Context> function_context(frame_context->declaration_context());
11602 if (SetContextLocalValue(
11603 isolate, scope_info, function_context, variable_name, new_value)) {
11604 return true;
11605 }
11606
11607 // Function context extension. These are variables introduced by eval.
11608 if (function_context->closure() == *function) {
11609 if (function_context->has_extension() &&
11610 !function_context->IsNativeContext()) {
11611 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11612
11613 if (JSReceiver::HasProperty(ext, variable_name)) {
11614 // We don't expect this to do anything except replacing
11615 // property value.
11616 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11617 NONE,
11618 kNonStrictMode);
11619 return true;
11620 }
11621 }
11622 }
11623 }
11624
11625 return default_result;
11626 }
11627
11628
11629 // Create a plain JSObject which materializes the closure content for the
11630 // context.
MaterializeClosure(Isolate * isolate,Handle<Context> context)11631 static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11632 Handle<Context> context) {
11633 ASSERT(context->IsFunctionContext());
11634
11635 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11636 Handle<ScopeInfo> scope_info(shared->scope_info());
11637
11638 // Allocate and initialize a JSObject with all the content of this function
11639 // closure.
11640 Handle<JSObject> closure_scope =
11641 isolate->factory()->NewJSObject(isolate->object_function());
11642
11643 // Fill all context locals to the context extension.
11644 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11645 scope_info, context, closure_scope)) {
11646 return Handle<JSObject>();
11647 }
11648
11649 // Finally copy any properties from the function context extension. This will
11650 // be variables introduced by eval.
11651 if (context->has_extension()) {
11652 Handle<JSObject> ext(JSObject::cast(context->extension()));
11653 bool threw = false;
11654 Handle<FixedArray> keys =
11655 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11656 if (threw) return Handle<JSObject>();
11657
11658 for (int i = 0; i < keys->length(); i++) {
11659 // Names of variables introduced by eval are strings.
11660 ASSERT(keys->get(i)->IsString());
11661 Handle<String> key(String::cast(keys->get(i)));
11662 RETURN_IF_EMPTY_HANDLE_VALUE(
11663 isolate,
11664 Runtime::SetObjectProperty(isolate, closure_scope, key,
11665 GetProperty(isolate, ext, key),
11666 NONE,
11667 kNonStrictMode),
11668 Handle<JSObject>());
11669 }
11670 }
11671
11672 return closure_scope;
11673 }
11674
11675
11676 // This method copies structure of MaterializeClosure method above.
SetClosureVariableValue(Isolate * isolate,Handle<Context> context,Handle<String> variable_name,Handle<Object> new_value)11677 static bool SetClosureVariableValue(Isolate* isolate,
11678 Handle<Context> context,
11679 Handle<String> variable_name,
11680 Handle<Object> new_value) {
11681 ASSERT(context->IsFunctionContext());
11682
11683 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11684 Handle<ScopeInfo> scope_info(shared->scope_info());
11685
11686 // Context locals to the context extension.
11687 if (SetContextLocalValue(
11688 isolate, scope_info, context, variable_name, new_value)) {
11689 return true;
11690 }
11691
11692 // Properties from the function context extension. This will
11693 // be variables introduced by eval.
11694 if (context->has_extension()) {
11695 Handle<JSObject> ext(JSObject::cast(context->extension()));
11696 if (JSReceiver::HasProperty(ext, variable_name)) {
11697 // We don't expect this to do anything except replacing property value.
11698 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11699 NONE,
11700 kNonStrictMode);
11701 return true;
11702 }
11703 }
11704
11705 return false;
11706 }
11707
11708
11709 // Create a plain JSObject which materializes the scope for the specified
11710 // catch context.
MaterializeCatchScope(Isolate * isolate,Handle<Context> context)11711 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11712 Handle<Context> context) {
11713 ASSERT(context->IsCatchContext());
11714 Handle<String> name(String::cast(context->extension()));
11715 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11716 isolate);
11717 Handle<JSObject> catch_scope =
11718 isolate->factory()->NewJSObject(isolate->object_function());
11719 RETURN_IF_EMPTY_HANDLE_VALUE(
11720 isolate,
11721 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
11722 NONE,
11723 kNonStrictMode),
11724 Handle<JSObject>());
11725 return catch_scope;
11726 }
11727
11728
SetCatchVariableValue(Isolate * isolate,Handle<Context> context,Handle<String> variable_name,Handle<Object> new_value)11729 static bool SetCatchVariableValue(Isolate* isolate,
11730 Handle<Context> context,
11731 Handle<String> variable_name,
11732 Handle<Object> new_value) {
11733 ASSERT(context->IsCatchContext());
11734 Handle<String> name(String::cast(context->extension()));
11735 if (!name->Equals(*variable_name)) {
11736 return false;
11737 }
11738 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11739 return true;
11740 }
11741
11742
11743 // Create a plain JSObject which materializes the block scope for the specified
11744 // block context.
MaterializeBlockScope(Isolate * isolate,Handle<Context> context)11745 static Handle<JSObject> MaterializeBlockScope(
11746 Isolate* isolate,
11747 Handle<Context> context) {
11748 ASSERT(context->IsBlockContext());
11749 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11750
11751 // Allocate and initialize a JSObject with all the arguments, stack locals
11752 // heap locals and extension properties of the debugged function.
11753 Handle<JSObject> block_scope =
11754 isolate->factory()->NewJSObject(isolate->object_function());
11755
11756 // Fill all context locals.
11757 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11758 scope_info, context, block_scope)) {
11759 return Handle<JSObject>();
11760 }
11761
11762 return block_scope;
11763 }
11764
11765
11766 // Create a plain JSObject which materializes the module scope for the specified
11767 // module context.
MaterializeModuleScope(Isolate * isolate,Handle<Context> context)11768 static Handle<JSObject> MaterializeModuleScope(
11769 Isolate* isolate,
11770 Handle<Context> context) {
11771 ASSERT(context->IsModuleContext());
11772 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11773
11774 // Allocate and initialize a JSObject with all the members of the debugged
11775 // module.
11776 Handle<JSObject> module_scope =
11777 isolate->factory()->NewJSObject(isolate->object_function());
11778
11779 // Fill all context locals.
11780 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11781 scope_info, context, module_scope)) {
11782 return Handle<JSObject>();
11783 }
11784
11785 return module_scope;
11786 }
11787
11788
11789 // Iterate over the actual scopes visible from a stack frame or from a closure.
11790 // The iteration proceeds from the innermost visible nested scope outwards.
11791 // All scopes are backed by an actual context except the local scope,
11792 // which is inserted "artificially" in the context chain.
11793 class ScopeIterator {
11794 public:
11795 enum ScopeType {
11796 ScopeTypeGlobal = 0,
11797 ScopeTypeLocal,
11798 ScopeTypeWith,
11799 ScopeTypeClosure,
11800 ScopeTypeCatch,
11801 ScopeTypeBlock,
11802 ScopeTypeModule
11803 };
11804
ScopeIterator(Isolate * isolate,JavaScriptFrame * frame,int inlined_jsframe_index)11805 ScopeIterator(Isolate* isolate,
11806 JavaScriptFrame* frame,
11807 int inlined_jsframe_index)
11808 : isolate_(isolate),
11809 frame_(frame),
11810 inlined_jsframe_index_(inlined_jsframe_index),
11811 function_(frame->function()),
11812 context_(Context::cast(frame->context())),
11813 nested_scope_chain_(4),
11814 failed_(false) {
11815
11816 // Catch the case when the debugger stops in an internal function.
11817 Handle<SharedFunctionInfo> shared_info(function_->shared());
11818 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11819 if (shared_info->script() == isolate->heap()->undefined_value()) {
11820 while (context_->closure() == *function_) {
11821 context_ = Handle<Context>(context_->previous(), isolate_);
11822 }
11823 return;
11824 }
11825
11826 // Get the debug info (create it if it does not exist).
11827 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
11828 // Return if ensuring debug info failed.
11829 return;
11830 }
11831 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11832
11833 // Find the break point where execution has stopped.
11834 BreakLocationIterator break_location_iterator(debug_info,
11835 ALL_BREAK_LOCATIONS);
11836 // pc points to the instruction after the current one, possibly a break
11837 // location as well. So the "- 1" to exclude it from the search.
11838 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
11839 if (break_location_iterator.IsExit()) {
11840 // We are within the return sequence. At the momemt it is not possible to
11841 // get a source position which is consistent with the current scope chain.
11842 // Thus all nested with, catch and block contexts are skipped and we only
11843 // provide the function scope.
11844 if (scope_info->HasContext()) {
11845 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11846 } else {
11847 while (context_->closure() == *function_) {
11848 context_ = Handle<Context>(context_->previous(), isolate_);
11849 }
11850 }
11851 if (scope_info->scope_type() != EVAL_SCOPE) {
11852 nested_scope_chain_.Add(scope_info);
11853 }
11854 } else {
11855 // Reparse the code and analyze the scopes.
11856 Handle<Script> script(Script::cast(shared_info->script()));
11857 Scope* scope = NULL;
11858
11859 // Check whether we are in global, eval or function code.
11860 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11861 if (scope_info->scope_type() != FUNCTION_SCOPE) {
11862 // Global or eval code.
11863 CompilationInfoWithZone info(script);
11864 if (scope_info->scope_type() == GLOBAL_SCOPE) {
11865 info.MarkAsGlobal();
11866 } else {
11867 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
11868 info.MarkAsEval();
11869 info.SetContext(Handle<Context>(function_->context()));
11870 }
11871 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
11872 scope = info.function()->scope();
11873 }
11874 RetrieveScopeChain(scope, shared_info);
11875 } else {
11876 // Function code
11877 CompilationInfoWithZone info(shared_info);
11878 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
11879 scope = info.function()->scope();
11880 }
11881 RetrieveScopeChain(scope, shared_info);
11882 }
11883 }
11884 }
11885
ScopeIterator(Isolate * isolate,Handle<JSFunction> function)11886 ScopeIterator(Isolate* isolate,
11887 Handle<JSFunction> function)
11888 : isolate_(isolate),
11889 frame_(NULL),
11890 inlined_jsframe_index_(0),
11891 function_(function),
11892 context_(function->context()),
11893 failed_(false) {
11894 if (function->IsBuiltin()) {
11895 context_ = Handle<Context>();
11896 }
11897 }
11898
11899 // More scopes?
Done()11900 bool Done() {
11901 ASSERT(!failed_);
11902 return context_.is_null();
11903 }
11904
Failed()11905 bool Failed() { return failed_; }
11906
11907 // Move to the next scope.
Next()11908 void Next() {
11909 ASSERT(!failed_);
11910 ScopeType scope_type = Type();
11911 if (scope_type == ScopeTypeGlobal) {
11912 // The global scope is always the last in the chain.
11913 ASSERT(context_->IsNativeContext());
11914 context_ = Handle<Context>();
11915 return;
11916 }
11917 if (nested_scope_chain_.is_empty()) {
11918 context_ = Handle<Context>(context_->previous(), isolate_);
11919 } else {
11920 if (nested_scope_chain_.last()->HasContext()) {
11921 ASSERT(context_->previous() != NULL);
11922 context_ = Handle<Context>(context_->previous(), isolate_);
11923 }
11924 nested_scope_chain_.RemoveLast();
11925 }
11926 }
11927
11928 // Return the type of the current scope.
Type()11929 ScopeType Type() {
11930 ASSERT(!failed_);
11931 if (!nested_scope_chain_.is_empty()) {
11932 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11933 switch (scope_info->scope_type()) {
11934 case FUNCTION_SCOPE:
11935 ASSERT(context_->IsFunctionContext() ||
11936 !scope_info->HasContext());
11937 return ScopeTypeLocal;
11938 case MODULE_SCOPE:
11939 ASSERT(context_->IsModuleContext());
11940 return ScopeTypeModule;
11941 case GLOBAL_SCOPE:
11942 ASSERT(context_->IsNativeContext());
11943 return ScopeTypeGlobal;
11944 case WITH_SCOPE:
11945 ASSERT(context_->IsWithContext());
11946 return ScopeTypeWith;
11947 case CATCH_SCOPE:
11948 ASSERT(context_->IsCatchContext());
11949 return ScopeTypeCatch;
11950 case BLOCK_SCOPE:
11951 ASSERT(!scope_info->HasContext() ||
11952 context_->IsBlockContext());
11953 return ScopeTypeBlock;
11954 case EVAL_SCOPE:
11955 UNREACHABLE();
11956 }
11957 }
11958 if (context_->IsNativeContext()) {
11959 ASSERT(context_->global_object()->IsGlobalObject());
11960 return ScopeTypeGlobal;
11961 }
11962 if (context_->IsFunctionContext()) {
11963 return ScopeTypeClosure;
11964 }
11965 if (context_->IsCatchContext()) {
11966 return ScopeTypeCatch;
11967 }
11968 if (context_->IsBlockContext()) {
11969 return ScopeTypeBlock;
11970 }
11971 if (context_->IsModuleContext()) {
11972 return ScopeTypeModule;
11973 }
11974 ASSERT(context_->IsWithContext());
11975 return ScopeTypeWith;
11976 }
11977
11978 // Return the JavaScript object with the content of the current scope.
ScopeObject()11979 Handle<JSObject> ScopeObject() {
11980 ASSERT(!failed_);
11981 switch (Type()) {
11982 case ScopeIterator::ScopeTypeGlobal:
11983 return Handle<JSObject>(CurrentContext()->global_object());
11984 case ScopeIterator::ScopeTypeLocal:
11985 // Materialize the content of the local scope into a JSObject.
11986 ASSERT(nested_scope_chain_.length() == 1);
11987 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
11988 case ScopeIterator::ScopeTypeWith:
11989 // Return the with object.
11990 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11991 case ScopeIterator::ScopeTypeCatch:
11992 return MaterializeCatchScope(isolate_, CurrentContext());
11993 case ScopeIterator::ScopeTypeClosure:
11994 // Materialize the content of the closure scope into a JSObject.
11995 return MaterializeClosure(isolate_, CurrentContext());
11996 case ScopeIterator::ScopeTypeBlock:
11997 return MaterializeBlockScope(isolate_, CurrentContext());
11998 case ScopeIterator::ScopeTypeModule:
11999 return MaterializeModuleScope(isolate_, CurrentContext());
12000 }
12001 UNREACHABLE();
12002 return Handle<JSObject>();
12003 }
12004
SetVariableValue(Handle<String> variable_name,Handle<Object> new_value)12005 bool SetVariableValue(Handle<String> variable_name,
12006 Handle<Object> new_value) {
12007 ASSERT(!failed_);
12008 switch (Type()) {
12009 case ScopeIterator::ScopeTypeGlobal:
12010 break;
12011 case ScopeIterator::ScopeTypeLocal:
12012 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
12013 variable_name, new_value);
12014 case ScopeIterator::ScopeTypeWith:
12015 break;
12016 case ScopeIterator::ScopeTypeCatch:
12017 return SetCatchVariableValue(isolate_, CurrentContext(),
12018 variable_name, new_value);
12019 case ScopeIterator::ScopeTypeClosure:
12020 return SetClosureVariableValue(isolate_, CurrentContext(),
12021 variable_name, new_value);
12022 case ScopeIterator::ScopeTypeBlock:
12023 // TODO(2399): should we implement it?
12024 break;
12025 case ScopeIterator::ScopeTypeModule:
12026 // TODO(2399): should we implement it?
12027 break;
12028 }
12029 return false;
12030 }
12031
CurrentScopeInfo()12032 Handle<ScopeInfo> CurrentScopeInfo() {
12033 ASSERT(!failed_);
12034 if (!nested_scope_chain_.is_empty()) {
12035 return nested_scope_chain_.last();
12036 } else if (context_->IsBlockContext()) {
12037 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
12038 } else if (context_->IsFunctionContext()) {
12039 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
12040 }
12041 return Handle<ScopeInfo>::null();
12042 }
12043
12044 // Return the context for this scope. For the local context there might not
12045 // be an actual context.
CurrentContext()12046 Handle<Context> CurrentContext() {
12047 ASSERT(!failed_);
12048 if (Type() == ScopeTypeGlobal ||
12049 nested_scope_chain_.is_empty()) {
12050 return context_;
12051 } else if (nested_scope_chain_.last()->HasContext()) {
12052 return context_;
12053 } else {
12054 return Handle<Context>();
12055 }
12056 }
12057
12058 #ifdef DEBUG
12059 // Debug print of the content of the current scope.
DebugPrint()12060 void DebugPrint() {
12061 ASSERT(!failed_);
12062 switch (Type()) {
12063 case ScopeIterator::ScopeTypeGlobal:
12064 PrintF("Global:\n");
12065 CurrentContext()->Print();
12066 break;
12067
12068 case ScopeIterator::ScopeTypeLocal: {
12069 PrintF("Local:\n");
12070 function_->shared()->scope_info()->Print();
12071 if (!CurrentContext().is_null()) {
12072 CurrentContext()->Print();
12073 if (CurrentContext()->has_extension()) {
12074 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12075 if (extension->IsJSContextExtensionObject()) {
12076 extension->Print();
12077 }
12078 }
12079 }
12080 break;
12081 }
12082
12083 case ScopeIterator::ScopeTypeWith:
12084 PrintF("With:\n");
12085 CurrentContext()->extension()->Print();
12086 break;
12087
12088 case ScopeIterator::ScopeTypeCatch:
12089 PrintF("Catch:\n");
12090 CurrentContext()->extension()->Print();
12091 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
12092 break;
12093
12094 case ScopeIterator::ScopeTypeClosure:
12095 PrintF("Closure:\n");
12096 CurrentContext()->Print();
12097 if (CurrentContext()->has_extension()) {
12098 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12099 if (extension->IsJSContextExtensionObject()) {
12100 extension->Print();
12101 }
12102 }
12103 break;
12104
12105 default:
12106 UNREACHABLE();
12107 }
12108 PrintF("\n");
12109 }
12110 #endif
12111
12112 private:
12113 Isolate* isolate_;
12114 JavaScriptFrame* frame_;
12115 int inlined_jsframe_index_;
12116 Handle<JSFunction> function_;
12117 Handle<Context> context_;
12118 List<Handle<ScopeInfo> > nested_scope_chain_;
12119 bool failed_;
12120
RetrieveScopeChain(Scope * scope,Handle<SharedFunctionInfo> shared_info)12121 void RetrieveScopeChain(Scope* scope,
12122 Handle<SharedFunctionInfo> shared_info) {
12123 if (scope != NULL) {
12124 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12125 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12126 } else {
12127 // A failed reparse indicates that the preparser has diverged from the
12128 // parser or that the preparse data given to the initial parse has been
12129 // faulty. We fail in debug mode but in release mode we only provide the
12130 // information we get from the context chain but nothing about
12131 // completely stack allocated scopes or stack allocated locals.
12132 // Or it could be due to stack overflow.
12133 ASSERT(isolate_->has_pending_exception());
12134 failed_ = true;
12135 }
12136 }
12137
12138 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12139 };
12140
12141
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetScopeCount)12142 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
12143 HandleScope scope(isolate);
12144 ASSERT(args.length() == 2);
12145
12146 // Check arguments.
12147 Object* check;
12148 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12149 RUNTIME_ARGUMENTS(isolate, args));
12150 if (!maybe_check->ToObject(&check)) return maybe_check;
12151 }
12152 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12153
12154 // Get the frame where the debugging is performed.
12155 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12156 JavaScriptFrameIterator it(isolate, id);
12157 JavaScriptFrame* frame = it.frame();
12158
12159 // Count the visible scopes.
12160 int n = 0;
12161 for (ScopeIterator it(isolate, frame, 0);
12162 !it.Done();
12163 it.Next()) {
12164 n++;
12165 }
12166
12167 return Smi::FromInt(n);
12168 }
12169
12170
12171 // Returns the list of step-in positions (text offset) in a function of the
12172 // stack frame in a range from the current debug break position to the end
12173 // of the corresponding statement.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetStepInPositions)12174 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) {
12175 HandleScope scope(isolate);
12176 ASSERT(args.length() == 2);
12177
12178 // Check arguments.
12179 Object* check;
12180 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12181 RUNTIME_ARGUMENTS(isolate, args));
12182 if (!maybe_check->ToObject(&check)) return maybe_check;
12183 }
12184 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12185
12186 // Get the frame where the debugging is performed.
12187 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12188 JavaScriptFrameIterator frame_it(isolate, id);
12189 RUNTIME_ASSERT(!frame_it.done());
12190
12191 JavaScriptFrame* frame = frame_it.frame();
12192
12193 Handle<JSFunction> fun =
12194 Handle<JSFunction>(frame->function());
12195 Handle<SharedFunctionInfo> shared =
12196 Handle<SharedFunctionInfo>(fun->shared());
12197
12198 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12199 return isolate->heap()->undefined_value();
12200 }
12201
12202 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12203
12204 int len = 0;
12205 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12206 // Find the break point where execution has stopped.
12207 BreakLocationIterator break_location_iterator(debug_info,
12208 ALL_BREAK_LOCATIONS);
12209
12210 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
12211 int current_statement_pos = break_location_iterator.statement_position();
12212
12213 while (!break_location_iterator.Done()) {
12214 bool accept;
12215 if (break_location_iterator.pc() > frame->pc()) {
12216 accept = true;
12217 } else {
12218 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12219 // The break point is near our pc. Could be a step-in possibility,
12220 // that is currently taken by active debugger call.
12221 if (break_frame_id == StackFrame::NO_ID) {
12222 // We are not stepping.
12223 accept = false;
12224 } else {
12225 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12226 // If our frame is a top frame and we are stepping, we can do step-in
12227 // at this place.
12228 accept = additional_frame_it.frame()->id() == id;
12229 }
12230 }
12231 if (accept) {
12232 if (break_location_iterator.IsStepInLocation(isolate)) {
12233 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12234 JSObject::SetElement(array, len,
12235 Handle<Object>(position_value, isolate),
12236 NONE, kNonStrictMode);
12237 len++;
12238 }
12239 }
12240 // Advance iterator.
12241 break_location_iterator.Next();
12242 if (current_statement_pos !=
12243 break_location_iterator.statement_position()) {
12244 break;
12245 }
12246 }
12247 return *array;
12248 }
12249
12250
12251 static const int kScopeDetailsTypeIndex = 0;
12252 static const int kScopeDetailsObjectIndex = 1;
12253 static const int kScopeDetailsSize = 2;
12254
12255
MaterializeScopeDetails(Isolate * isolate,ScopeIterator * it)12256 static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
12257 ScopeIterator* it) {
12258 // Calculate the size of the result.
12259 int details_size = kScopeDetailsSize;
12260 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12261
12262 // Fill in scope details.
12263 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12264 Handle<JSObject> scope_object = it->ScopeObject();
12265 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
12266 details->set(kScopeDetailsObjectIndex, *scope_object);
12267
12268 return *isolate->factory()->NewJSArrayWithElements(details);
12269 }
12270
12271
12272 // Return an array with scope details
12273 // args[0]: number: break id
12274 // args[1]: number: frame index
12275 // args[2]: number: inlined frame index
12276 // args[3]: number: scope index
12277 //
12278 // The array returned contains the following information:
12279 // 0: Scope type
12280 // 1: Scope object
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetScopeDetails)12281 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
12282 HandleScope scope(isolate);
12283 ASSERT(args.length() == 4);
12284
12285 // Check arguments.
12286 Object* check;
12287 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12288 RUNTIME_ARGUMENTS(isolate, args));
12289 if (!maybe_check->ToObject(&check)) return maybe_check;
12290 }
12291 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12292 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12293 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12294
12295 // Get the frame where the debugging is performed.
12296 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12297 JavaScriptFrameIterator frame_it(isolate, id);
12298 JavaScriptFrame* frame = frame_it.frame();
12299
12300 // Find the requested scope.
12301 int n = 0;
12302 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12303 for (; !it.Done() && n < index; it.Next()) {
12304 n++;
12305 }
12306 if (it.Done()) {
12307 return isolate->heap()->undefined_value();
12308 }
12309 return MaterializeScopeDetails(isolate, &it);
12310 }
12311
12312
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFunctionScopeCount)12313 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
12314 HandleScope scope(isolate);
12315 ASSERT(args.length() == 1);
12316
12317 // Check arguments.
12318 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12319
12320 // Count the visible scopes.
12321 int n = 0;
12322 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12323 n++;
12324 }
12325
12326 return Smi::FromInt(n);
12327 }
12328
12329
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFunctionScopeDetails)12330 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
12331 HandleScope scope(isolate);
12332 ASSERT(args.length() == 2);
12333
12334 // Check arguments.
12335 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12336 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12337
12338 // Find the requested scope.
12339 int n = 0;
12340 ScopeIterator it(isolate, fun);
12341 for (; !it.Done() && n < index; it.Next()) {
12342 n++;
12343 }
12344 if (it.Done()) {
12345 return isolate->heap()->undefined_value();
12346 }
12347
12348 return MaterializeScopeDetails(isolate, &it);
12349 }
12350
12351
SetScopeVariableValue(ScopeIterator * it,int index,Handle<String> variable_name,Handle<Object> new_value)12352 static bool SetScopeVariableValue(ScopeIterator* it, int index,
12353 Handle<String> variable_name,
12354 Handle<Object> new_value) {
12355 for (int n = 0; !it->Done() && n < index; it->Next()) {
12356 n++;
12357 }
12358 if (it->Done()) {
12359 return false;
12360 }
12361 return it->SetVariableValue(variable_name, new_value);
12362 }
12363
12364
12365 // Change variable value in closure or local scope
12366 // args[0]: number or JsFunction: break id or function
12367 // args[1]: number: frame index (when arg[0] is break id)
12368 // args[2]: number: inlined frame index (when arg[0] is break id)
12369 // args[3]: number: scope index
12370 // args[4]: string: variable name
12371 // args[5]: object: new value
12372 //
12373 // Return true if success and false otherwise
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetScopeVariableValue)12374 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
12375 HandleScope scope(isolate);
12376 ASSERT(args.length() == 6);
12377
12378 // Check arguments.
12379 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12380 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12381 Handle<Object> new_value = args.at<Object>(5);
12382
12383 bool res;
12384 if (args[0]->IsNumber()) {
12385 Object* check;
12386 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12387 RUNTIME_ARGUMENTS(isolate, args));
12388 if (!maybe_check->ToObject(&check)) return maybe_check;
12389 }
12390 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12391 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12392
12393 // Get the frame where the debugging is performed.
12394 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12395 JavaScriptFrameIterator frame_it(isolate, id);
12396 JavaScriptFrame* frame = frame_it.frame();
12397
12398 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12399 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12400 } else {
12401 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12402 ScopeIterator it(isolate, fun);
12403 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12404 }
12405
12406 return isolate->heap()->ToBoolean(res);
12407 }
12408
12409
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugPrintScopes)12410 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
12411 HandleScope scope(isolate);
12412 ASSERT(args.length() == 0);
12413
12414 #ifdef DEBUG
12415 // Print the scopes for the top frame.
12416 StackFrameLocator locator(isolate);
12417 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
12418 for (ScopeIterator it(isolate, frame, 0);
12419 !it.Done();
12420 it.Next()) {
12421 it.DebugPrint();
12422 }
12423 #endif
12424 return isolate->heap()->undefined_value();
12425 }
12426
12427
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetThreadCount)12428 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
12429 HandleScope scope(isolate);
12430 ASSERT(args.length() == 1);
12431
12432 // Check arguments.
12433 Object* result;
12434 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12435 RUNTIME_ARGUMENTS(isolate, args));
12436 if (!maybe_result->ToObject(&result)) return maybe_result;
12437 }
12438
12439 // Count all archived V8 threads.
12440 int n = 0;
12441 for (ThreadState* thread =
12442 isolate->thread_manager()->FirstThreadStateInUse();
12443 thread != NULL;
12444 thread = thread->Next()) {
12445 n++;
12446 }
12447
12448 // Total number of threads is current thread and archived threads.
12449 return Smi::FromInt(n + 1);
12450 }
12451
12452
12453 static const int kThreadDetailsCurrentThreadIndex = 0;
12454 static const int kThreadDetailsThreadIdIndex = 1;
12455 static const int kThreadDetailsSize = 2;
12456
12457 // Return an array with thread details
12458 // args[0]: number: break id
12459 // args[1]: number: thread index
12460 //
12461 // The array returned contains the following information:
12462 // 0: Is current thread?
12463 // 1: Thread id
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetThreadDetails)12464 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
12465 HandleScope scope(isolate);
12466 ASSERT(args.length() == 2);
12467
12468 // Check arguments.
12469 Object* check;
12470 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12471 RUNTIME_ARGUMENTS(isolate, args));
12472 if (!maybe_check->ToObject(&check)) return maybe_check;
12473 }
12474 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12475
12476 // Allocate array for result.
12477 Handle<FixedArray> details =
12478 isolate->factory()->NewFixedArray(kThreadDetailsSize);
12479
12480 // Thread index 0 is current thread.
12481 if (index == 0) {
12482 // Fill the details.
12483 details->set(kThreadDetailsCurrentThreadIndex,
12484 isolate->heap()->true_value());
12485 details->set(kThreadDetailsThreadIdIndex,
12486 Smi::FromInt(ThreadId::Current().ToInteger()));
12487 } else {
12488 // Find the thread with the requested index.
12489 int n = 1;
12490 ThreadState* thread =
12491 isolate->thread_manager()->FirstThreadStateInUse();
12492 while (index != n && thread != NULL) {
12493 thread = thread->Next();
12494 n++;
12495 }
12496 if (thread == NULL) {
12497 return isolate->heap()->undefined_value();
12498 }
12499
12500 // Fill the details.
12501 details->set(kThreadDetailsCurrentThreadIndex,
12502 isolate->heap()->false_value());
12503 details->set(kThreadDetailsThreadIdIndex,
12504 Smi::FromInt(thread->id().ToInteger()));
12505 }
12506
12507 // Convert to JS array and return.
12508 return *isolate->factory()->NewJSArrayWithElements(details);
12509 }
12510
12511
12512 // Sets the disable break state
12513 // args[0]: disable break state
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetDisableBreak)12514 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
12515 HandleScope scope(isolate);
12516 ASSERT(args.length() == 1);
12517 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
12518 isolate->debug()->set_disable_break(disable_break);
12519 return isolate->heap()->undefined_value();
12520 }
12521
12522
IsPositionAlignmentCodeCorrect(int alignment)12523 static bool IsPositionAlignmentCodeCorrect(int alignment) {
12524 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12525 }
12526
12527
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetBreakLocations)12528 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
12529 HandleScope scope(isolate);
12530 ASSERT(args.length() == 2);
12531
12532 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12533 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12534
12535 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12536 return isolate->ThrowIllegalOperation();
12537 }
12538 BreakPositionAlignment alignment =
12539 static_cast<BreakPositionAlignment>(statement_aligned_code);
12540
12541 Handle<SharedFunctionInfo> shared(fun->shared());
12542 // Find the number of break points
12543 Handle<Object> break_locations =
12544 Debug::GetSourceBreakLocations(shared, alignment);
12545 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
12546 // Return array as JS array
12547 return *isolate->factory()->NewJSArrayWithElements(
12548 Handle<FixedArray>::cast(break_locations));
12549 }
12550
12551
12552 // Set a break point in a function.
12553 // args[0]: function
12554 // args[1]: number: break source position (within the function source)
12555 // args[2]: number: break point object
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetFunctionBreakPoint)12556 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
12557 HandleScope scope(isolate);
12558 ASSERT(args.length() == 3);
12559 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12560 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12561 RUNTIME_ASSERT(source_position >= 0);
12562 Handle<Object> break_point_object_arg = args.at<Object>(2);
12563
12564 // Set break point.
12565 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12566 &source_position);
12567
12568 return Smi::FromInt(source_position);
12569 }
12570
12571
12572 // Changes the state of a break point in a script and returns source position
12573 // where break point was set. NOTE: Regarding performance see the NOTE for
12574 // GetScriptFromScriptData.
12575 // args[0]: script to set break point in
12576 // args[1]: number: break source position (within the script source)
12577 // args[2]: number, breakpoint position alignment
12578 // args[3]: number: break point object
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetScriptBreakPoint)12579 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
12580 HandleScope scope(isolate);
12581 ASSERT(args.length() == 4);
12582 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
12583 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12584 RUNTIME_ASSERT(source_position >= 0);
12585 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12586 Handle<Object> break_point_object_arg = args.at<Object>(3);
12587
12588 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12589 return isolate->ThrowIllegalOperation();
12590 }
12591 BreakPositionAlignment alignment =
12592 static_cast<BreakPositionAlignment>(statement_aligned_code);
12593
12594 // Get the script from the script wrapper.
12595 RUNTIME_ASSERT(wrapper->value()->IsScript());
12596 Handle<Script> script(Script::cast(wrapper->value()));
12597
12598 // Set break point.
12599 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
12600 &source_position,
12601 alignment)) {
12602 return isolate->heap()->undefined_value();
12603 }
12604
12605 return Smi::FromInt(source_position);
12606 }
12607
12608
12609 // Clear a break point
12610 // args[0]: number: break point object
RUNTIME_FUNCTION(MaybeObject *,Runtime_ClearBreakPoint)12611 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
12612 HandleScope scope(isolate);
12613 ASSERT(args.length() == 1);
12614 Handle<Object> break_point_object_arg = args.at<Object>(0);
12615
12616 // Clear break point.
12617 isolate->debug()->ClearBreakPoint(break_point_object_arg);
12618
12619 return isolate->heap()->undefined_value();
12620 }
12621
12622
12623 // Change the state of break on exceptions.
12624 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12625 // args[1]: Boolean indicating on/off.
RUNTIME_FUNCTION(MaybeObject *,Runtime_ChangeBreakOnException)12626 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
12627 HandleScope scope(isolate);
12628 ASSERT(args.length() == 2);
12629 RUNTIME_ASSERT(args[0]->IsNumber());
12630 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
12631
12632 // If the number doesn't match an enum value, the ChangeBreakOnException
12633 // function will default to affecting caught exceptions.
12634 ExceptionBreakType type =
12635 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
12636 // Update break point state.
12637 isolate->debug()->ChangeBreakOnException(type, enable);
12638 return isolate->heap()->undefined_value();
12639 }
12640
12641
12642 // Returns the state of break on exceptions
12643 // args[0]: boolean indicating uncaught exceptions
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsBreakOnException)12644 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
12645 HandleScope scope(isolate);
12646 ASSERT(args.length() == 1);
12647 RUNTIME_ASSERT(args[0]->IsNumber());
12648
12649 ExceptionBreakType type =
12650 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
12651 bool result = isolate->debug()->IsBreakOnException(type);
12652 return Smi::FromInt(result);
12653 }
12654
12655
12656 // Prepare for stepping
12657 // args[0]: break id for checking execution state
12658 // args[1]: step action from the enumeration StepAction
12659 // args[2]: number of times to perform the step, for step out it is the number
12660 // of frames to step down.
RUNTIME_FUNCTION(MaybeObject *,Runtime_PrepareStep)12661 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
12662 HandleScope scope(isolate);
12663 ASSERT(args.length() == 4);
12664 // Check arguments.
12665 Object* check;
12666 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12667 RUNTIME_ARGUMENTS(isolate, args));
12668 if (!maybe_check->ToObject(&check)) return maybe_check;
12669 }
12670 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
12671 return isolate->Throw(isolate->heap()->illegal_argument_string());
12672 }
12673
12674 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12675
12676 StackFrame::Id frame_id;
12677 if (wrapped_frame_id == 0) {
12678 frame_id = StackFrame::NO_ID;
12679 } else {
12680 frame_id = UnwrapFrameId(wrapped_frame_id);
12681 }
12682
12683 // Get the step action and check validity.
12684 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12685 if (step_action != StepIn &&
12686 step_action != StepNext &&
12687 step_action != StepOut &&
12688 step_action != StepInMin &&
12689 step_action != StepMin) {
12690 return isolate->Throw(isolate->heap()->illegal_argument_string());
12691 }
12692
12693 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12694 step_action != StepMin && step_action != StepOut) {
12695 return isolate->ThrowIllegalOperation();
12696 }
12697
12698 // Get the number of steps.
12699 int step_count = NumberToInt32(args[2]);
12700 if (step_count < 1) {
12701 return isolate->Throw(isolate->heap()->illegal_argument_string());
12702 }
12703
12704 // Clear all current stepping setup.
12705 isolate->debug()->ClearStepping();
12706
12707 // Prepare step.
12708 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
12709 step_count,
12710 frame_id);
12711 return isolate->heap()->undefined_value();
12712 }
12713
12714
12715 // Clear all stepping set by PrepareStep.
RUNTIME_FUNCTION(MaybeObject *,Runtime_ClearStepping)12716 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
12717 HandleScope scope(isolate);
12718 ASSERT(args.length() == 0);
12719 isolate->debug()->ClearStepping();
12720 return isolate->heap()->undefined_value();
12721 }
12722
12723
12724 // Helper function to find or create the arguments object for
12725 // Runtime_DebugEvaluate.
MaterializeArgumentsObject(Isolate * isolate,Handle<JSObject> target,Handle<JSFunction> function)12726 static Handle<JSObject> MaterializeArgumentsObject(
12727 Isolate* isolate,
12728 Handle<JSObject> target,
12729 Handle<JSFunction> function) {
12730 // Do not materialize the arguments object for eval or top-level code.
12731 // Skip if "arguments" is already taken.
12732 if (!function->shared()->is_function() ||
12733 JSReceiver::HasLocalProperty(target,
12734 isolate->factory()->arguments_string())) {
12735 return target;
12736 }
12737
12738 // FunctionGetArguments can't throw an exception.
12739 Handle<JSObject> arguments = Handle<JSObject>::cast(
12740 Accessors::FunctionGetArguments(function));
12741 Runtime::SetObjectProperty(isolate, target,
12742 isolate->factory()->arguments_string(),
12743 arguments,
12744 ::NONE,
12745 kNonStrictMode);
12746 return target;
12747 }
12748
12749
12750 // Compile and evaluate source for the given context.
DebugEvaluate(Isolate * isolate,Handle<Context> context,Handle<Object> context_extension,Handle<Object> receiver,Handle<String> source)12751 static MaybeObject* DebugEvaluate(Isolate* isolate,
12752 Handle<Context> context,
12753 Handle<Object> context_extension,
12754 Handle<Object> receiver,
12755 Handle<String> source) {
12756 if (context_extension->IsJSObject()) {
12757 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
12758 Handle<JSFunction> closure(context->closure(), isolate);
12759 context = isolate->factory()->NewWithContext(closure, context, extension);
12760 }
12761
12762 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
12763 source,
12764 context,
12765 context->IsNativeContext(),
12766 CLASSIC_MODE,
12767 NO_PARSE_RESTRICTION,
12768 RelocInfo::kNoPosition);
12769 RETURN_IF_EMPTY_HANDLE(isolate, shared);
12770
12771 Handle<JSFunction> eval_fun =
12772 isolate->factory()->NewFunctionFromSharedFunctionInfo(
12773 shared, context, NOT_TENURED);
12774 bool pending_exception;
12775 Handle<Object> result = Execution::Call(
12776 isolate, eval_fun, receiver, 0, NULL, &pending_exception);
12777
12778 if (pending_exception) return Failure::Exception();
12779
12780 // Skip the global proxy as it has no properties and always delegates to the
12781 // real global object.
12782 if (result->IsJSGlobalProxy()) {
12783 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
12784 }
12785
12786 // Clear the oneshot breakpoints so that the debugger does not step further.
12787 isolate->debug()->ClearStepping();
12788 return *result;
12789 }
12790
12791
12792 // Evaluate a piece of JavaScript in the context of a stack frame for
12793 // debugging. Things that need special attention are:
12794 // - Parameters and stack-allocated locals need to be materialized. Altered
12795 // values need to be written back to the stack afterwards.
12796 // - The arguments object needs to materialized.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugEvaluate)12797 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
12798 HandleScope scope(isolate);
12799
12800 // Check the execution state and decode arguments frame and source to be
12801 // evaluated.
12802 ASSERT(args.length() == 6);
12803 Object* check_result;
12804 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12805 RUNTIME_ARGUMENTS(isolate, args));
12806 if (!maybe_result->ToObject(&check_result)) return maybe_result;
12807 }
12808 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12809 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12810 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12811 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
12812 Handle<Object> context_extension(args[5], isolate);
12813
12814 // Handle the processing of break.
12815 DisableBreak disable_break_save(isolate, disable_break);
12816
12817 // Get the frame where the debugging is performed.
12818 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12819 JavaScriptFrameIterator it(isolate, id);
12820 JavaScriptFrame* frame = it.frame();
12821 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12822 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
12823
12824 // Traverse the saved contexts chain to find the active context for the
12825 // selected frame.
12826 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12827
12828 SaveContext savex(isolate);
12829 isolate->set_context(*(save->context()));
12830
12831 // Evaluate on the context of the frame.
12832 Handle<Context> context(Context::cast(frame->context()));
12833 ASSERT(!context.is_null());
12834
12835 // Materialize stack locals and the arguments object.
12836 Handle<JSObject> materialized =
12837 isolate->factory()->NewJSObject(isolate->object_function());
12838
12839 materialized = MaterializeStackLocalsWithFrameInspector(
12840 isolate, materialized, function, &frame_inspector);
12841 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
12842
12843 materialized = MaterializeArgumentsObject(isolate, materialized, function);
12844 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
12845
12846 // Add the materialized object in a with-scope to shadow the stack locals.
12847 context = isolate->factory()->NewWithContext(function, context, materialized);
12848
12849 Handle<Object> receiver(frame->receiver(), isolate);
12850 Object* evaluate_result_object;
12851 { MaybeObject* maybe_result =
12852 DebugEvaluate(isolate, context, context_extension, receiver, source);
12853 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
12854 }
12855
12856 Handle<Object> result(evaluate_result_object, isolate);
12857
12858 // Write back potential changes to materialized stack locals to the stack.
12859 UpdateStackLocalsFromMaterializedObject(
12860 isolate, materialized, function, frame, inlined_jsframe_index);
12861
12862 return *result;
12863 }
12864
12865
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugEvaluateGlobal)12866 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
12867 HandleScope scope(isolate);
12868
12869 // Check the execution state and decode arguments frame and source to be
12870 // evaluated.
12871 ASSERT(args.length() == 4);
12872 Object* check_result;
12873 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12874 RUNTIME_ARGUMENTS(isolate, args));
12875 if (!maybe_result->ToObject(&check_result)) return maybe_result;
12876 }
12877 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12878 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
12879 Handle<Object> context_extension(args[3], isolate);
12880
12881 // Handle the processing of break.
12882 DisableBreak disable_break_save(isolate, disable_break);
12883
12884 // Enter the top context from before the debugger was invoked.
12885 SaveContext save(isolate);
12886 SaveContext* top = &save;
12887 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
12888 top = top->prev();
12889 }
12890 if (top != NULL) {
12891 isolate->set_context(*top->context());
12892 }
12893
12894 // Get the native context now set to the top context from before the
12895 // debugger was invoked.
12896 Handle<Context> context = isolate->native_context();
12897 Handle<Object> receiver = isolate->global_object();
12898 return DebugEvaluate(isolate, context, context_extension, receiver, source);
12899 }
12900
12901
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugGetLoadedScripts)12902 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
12903 HandleScope scope(isolate);
12904 ASSERT(args.length() == 0);
12905
12906 // Fill the script objects.
12907 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
12908
12909 // Convert the script objects to proper JS objects.
12910 for (int i = 0; i < instances->length(); i++) {
12911 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12912 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12913 // because using
12914 // instances->set(i, *GetScriptWrapper(script))
12915 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12916 // already have dereferenced the instances handle.
12917 Handle<JSValue> wrapper = GetScriptWrapper(script);
12918 instances->set(i, *wrapper);
12919 }
12920
12921 // Return result as a JS array.
12922 Handle<JSObject> result =
12923 isolate->factory()->NewJSObject(isolate->array_function());
12924 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
12925 return *result;
12926 }
12927
12928
12929 // Helper function used by Runtime_DebugReferencedBy below.
DebugReferencedBy(HeapIterator * iterator,JSObject * target,Object * instance_filter,int max_references,FixedArray * instances,int instances_size,JSFunction * arguments_function)12930 static int DebugReferencedBy(HeapIterator* iterator,
12931 JSObject* target,
12932 Object* instance_filter, int max_references,
12933 FixedArray* instances, int instances_size,
12934 JSFunction* arguments_function) {
12935 Isolate* isolate = target->GetIsolate();
12936 SealHandleScope shs(isolate);
12937 DisallowHeapAllocation no_allocation;
12938
12939 // Iterate the heap.
12940 int count = 0;
12941 JSObject* last = NULL;
12942 HeapObject* heap_obj = NULL;
12943 while (((heap_obj = iterator->next()) != NULL) &&
12944 (max_references == 0 || count < max_references)) {
12945 // Only look at all JSObjects.
12946 if (heap_obj->IsJSObject()) {
12947 // Skip context extension objects and argument arrays as these are
12948 // checked in the context of functions using them.
12949 JSObject* obj = JSObject::cast(heap_obj);
12950 if (obj->IsJSContextExtensionObject() ||
12951 obj->map()->constructor() == arguments_function) {
12952 continue;
12953 }
12954
12955 // Check if the JS object has a reference to the object looked for.
12956 if (obj->ReferencesObject(target)) {
12957 // Check instance filter if supplied. This is normally used to avoid
12958 // references from mirror objects (see Runtime_IsInPrototypeChain).
12959 if (!instance_filter->IsUndefined()) {
12960 Object* V = obj;
12961 while (true) {
12962 Object* prototype = V->GetPrototype(isolate);
12963 if (prototype->IsNull()) {
12964 break;
12965 }
12966 if (instance_filter == prototype) {
12967 obj = NULL; // Don't add this object.
12968 break;
12969 }
12970 V = prototype;
12971 }
12972 }
12973
12974 if (obj != NULL) {
12975 // Valid reference found add to instance array if supplied an update
12976 // count.
12977 if (instances != NULL && count < instances_size) {
12978 instances->set(count, obj);
12979 }
12980 last = obj;
12981 count++;
12982 }
12983 }
12984 }
12985 }
12986
12987 // Check for circular reference only. This can happen when the object is only
12988 // referenced from mirrors and has a circular reference in which case the
12989 // object is not really alive and would have been garbage collected if not
12990 // referenced from the mirror.
12991 if (count == 1 && last == target) {
12992 count = 0;
12993 }
12994
12995 // Return the number of referencing objects found.
12996 return count;
12997 }
12998
12999
13000 // Scan the heap for objects with direct references to an object
13001 // args[0]: the object to find references to
13002 // args[1]: constructor function for instances to exclude (Mirror)
13003 // args[2]: the the maximum number of objects to return
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugReferencedBy)13004 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
13005 SealHandleScope shs(isolate);
13006 ASSERT(args.length() == 3);
13007
13008 // First perform a full GC in order to avoid references from dead objects.
13009 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
13010 "%DebugReferencedBy");
13011 // The heap iterator reserves the right to do a GC to make the heap iterable.
13012 // Due to the GC above we know it won't need to do that, but it seems cleaner
13013 // to get the heap iterator constructed before we start having unprotected
13014 // Object* locals that are not protected by handles.
13015
13016 // Check parameters.
13017 CONVERT_ARG_CHECKED(JSObject, target, 0);
13018 Object* instance_filter = args[1];
13019 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
13020 instance_filter->IsJSObject());
13021 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
13022 RUNTIME_ASSERT(max_references >= 0);
13023
13024
13025 // Get the constructor function for context extension and arguments array.
13026 JSObject* arguments_boilerplate =
13027 isolate->context()->native_context()->arguments_boilerplate();
13028 JSFunction* arguments_function =
13029 JSFunction::cast(arguments_boilerplate->map()->constructor());
13030
13031 // Get the number of referencing objects.
13032 int count;
13033 Heap* heap = isolate->heap();
13034 HeapIterator heap_iterator(heap);
13035 count = DebugReferencedBy(&heap_iterator,
13036 target, instance_filter, max_references,
13037 NULL, 0, arguments_function);
13038
13039 // Allocate an array to hold the result.
13040 Object* object;
13041 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
13042 if (!maybe_object->ToObject(&object)) return maybe_object;
13043 }
13044 FixedArray* instances = FixedArray::cast(object);
13045
13046 // Fill the referencing objects.
13047 // AllocateFixedArray above does not make the heap non-iterable.
13048 ASSERT(heap->IsHeapIterable());
13049 HeapIterator heap_iterator2(heap);
13050 count = DebugReferencedBy(&heap_iterator2,
13051 target, instance_filter, max_references,
13052 instances, count, arguments_function);
13053
13054 // Return result as JS array.
13055 Object* result;
13056 MaybeObject* maybe_result = heap->AllocateJSObject(
13057 isolate->context()->native_context()->array_function());
13058 if (!maybe_result->ToObject(&result)) return maybe_result;
13059 return JSArray::cast(result)->SetContent(instances);
13060 }
13061
13062
13063 // Helper function used by Runtime_DebugConstructedBy below.
DebugConstructedBy(HeapIterator * iterator,JSFunction * constructor,int max_references,FixedArray * instances,int instances_size)13064 static int DebugConstructedBy(HeapIterator* iterator,
13065 JSFunction* constructor,
13066 int max_references,
13067 FixedArray* instances,
13068 int instances_size) {
13069 DisallowHeapAllocation no_allocation;
13070
13071 // Iterate the heap.
13072 int count = 0;
13073 HeapObject* heap_obj = NULL;
13074 while (((heap_obj = iterator->next()) != NULL) &&
13075 (max_references == 0 || count < max_references)) {
13076 // Only look at all JSObjects.
13077 if (heap_obj->IsJSObject()) {
13078 JSObject* obj = JSObject::cast(heap_obj);
13079 if (obj->map()->constructor() == constructor) {
13080 // Valid reference found add to instance array if supplied an update
13081 // count.
13082 if (instances != NULL && count < instances_size) {
13083 instances->set(count, obj);
13084 }
13085 count++;
13086 }
13087 }
13088 }
13089
13090 // Return the number of referencing objects found.
13091 return count;
13092 }
13093
13094
13095 // Scan the heap for objects constructed by a specific function.
13096 // args[0]: the constructor to find instances of
13097 // args[1]: the the maximum number of objects to return
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugConstructedBy)13098 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
13099 SealHandleScope shs(isolate);
13100 ASSERT(args.length() == 2);
13101
13102 // First perform a full GC in order to avoid dead objects.
13103 Heap* heap = isolate->heap();
13104 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
13105
13106 // Check parameters.
13107 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
13108 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13109 RUNTIME_ASSERT(max_references >= 0);
13110
13111 // Get the number of referencing objects.
13112 int count;
13113 HeapIterator heap_iterator(heap);
13114 count = DebugConstructedBy(&heap_iterator,
13115 constructor,
13116 max_references,
13117 NULL,
13118 0);
13119
13120 // Allocate an array to hold the result.
13121 Object* object;
13122 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
13123 if (!maybe_object->ToObject(&object)) return maybe_object;
13124 }
13125 FixedArray* instances = FixedArray::cast(object);
13126
13127 ASSERT(isolate->heap()->IsHeapIterable());
13128 // Fill the referencing objects.
13129 HeapIterator heap_iterator2(heap);
13130 count = DebugConstructedBy(&heap_iterator2,
13131 constructor,
13132 max_references,
13133 instances,
13134 count);
13135
13136 // Return result as JS array.
13137 Object* result;
13138 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
13139 isolate->context()->native_context()->array_function());
13140 if (!maybe_result->ToObject(&result)) return maybe_result;
13141 }
13142 return JSArray::cast(result)->SetContent(instances);
13143 }
13144
13145
13146 // Find the effective prototype object as returned by __proto__.
13147 // args[0]: the object to find the prototype for.
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugGetPrototype)13148 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
13149 SealHandleScope shs(isolate);
13150 ASSERT(args.length() == 1);
13151 CONVERT_ARG_CHECKED(JSObject, obj, 0);
13152 return GetPrototypeSkipHiddenPrototypes(isolate, obj);
13153 }
13154
13155
13156 // Patches script source (should be called upon BeforeCompile event).
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugSetScriptSource)13157 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
13158 HandleScope scope(isolate);
13159 ASSERT(args.length() == 2);
13160
13161 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
13162 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13163
13164 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13165 Handle<Script> script(Script::cast(script_wrapper->value()));
13166
13167 int compilation_state = script->compilation_state();
13168 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13169 script->set_source(*source);
13170
13171 return isolate->heap()->undefined_value();
13172 }
13173
13174
RUNTIME_FUNCTION(MaybeObject *,Runtime_SystemBreak)13175 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
13176 SealHandleScope shs(isolate);
13177 ASSERT(args.length() == 0);
13178 OS::DebugBreak();
13179 return isolate->heap()->undefined_value();
13180 }
13181
13182
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugDisassembleFunction)13183 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
13184 HandleScope scope(isolate);
13185 #ifdef DEBUG
13186 ASSERT(args.length() == 1);
13187 // Get the function and make sure it is compiled.
13188 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13189 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
13190 return Failure::Exception();
13191 }
13192 func->code()->PrintLn();
13193 #endif // DEBUG
13194 return isolate->heap()->undefined_value();
13195 }
13196
13197
RUNTIME_FUNCTION(MaybeObject *,Runtime_DebugDisassembleConstructor)13198 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
13199 HandleScope scope(isolate);
13200 #ifdef DEBUG
13201 ASSERT(args.length() == 1);
13202 // Get the function and make sure it is compiled.
13203 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13204 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
13205 return Failure::Exception();
13206 }
13207 func->shared()->construct_stub()->PrintLn();
13208 #endif // DEBUG
13209 return isolate->heap()->undefined_value();
13210 }
13211
13212
RUNTIME_FUNCTION(MaybeObject *,Runtime_FunctionGetInferredName)13213 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
13214 SealHandleScope shs(isolate);
13215 ASSERT(args.length() == 1);
13216
13217 CONVERT_ARG_CHECKED(JSFunction, f, 0);
13218 return f->shared()->inferred_name();
13219 }
13220
13221
FindSharedFunctionInfosForScript(HeapIterator * iterator,Script * script,FixedArray * buffer)13222 static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13223 Script* script,
13224 FixedArray* buffer) {
13225 DisallowHeapAllocation no_allocation;
13226 int counter = 0;
13227 int buffer_size = buffer->length();
13228 for (HeapObject* obj = iterator->next();
13229 obj != NULL;
13230 obj = iterator->next()) {
13231 ASSERT(obj != NULL);
13232 if (!obj->IsSharedFunctionInfo()) {
13233 continue;
13234 }
13235 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13236 if (shared->script() != script) {
13237 continue;
13238 }
13239 if (counter < buffer_size) {
13240 buffer->set(counter, shared);
13241 }
13242 counter++;
13243 }
13244 return counter;
13245 }
13246
13247
13248 // For a script finds all SharedFunctionInfo's in the heap that points
13249 // to this script. Returns JSArray of SharedFunctionInfo wrapped
13250 // in OpaqueReferences.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditFindSharedFunctionInfosForScript)13251 RUNTIME_FUNCTION(MaybeObject*,
13252 Runtime_LiveEditFindSharedFunctionInfosForScript) {
13253 HandleScope scope(isolate);
13254 CHECK(isolate->debugger()->live_edit_enabled());
13255 ASSERT(args.length() == 1);
13256 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
13257
13258 RUNTIME_ASSERT(script_value->value()->IsScript());
13259 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13260
13261 const int kBufferSize = 32;
13262
13263 Handle<FixedArray> array;
13264 array = isolate->factory()->NewFixedArray(kBufferSize);
13265 int number;
13266 Heap* heap = isolate->heap();
13267 {
13268 heap->EnsureHeapIsIterable();
13269 DisallowHeapAllocation no_allocation;
13270 HeapIterator heap_iterator(heap);
13271 Script* scr = *script;
13272 FixedArray* arr = *array;
13273 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13274 }
13275 if (number > kBufferSize) {
13276 array = isolate->factory()->NewFixedArray(number);
13277 heap->EnsureHeapIsIterable();
13278 DisallowHeapAllocation no_allocation;
13279 HeapIterator heap_iterator(heap);
13280 Script* scr = *script;
13281 FixedArray* arr = *array;
13282 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13283 }
13284
13285 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
13286 result->set_length(Smi::FromInt(number));
13287
13288 LiveEdit::WrapSharedFunctionInfos(result);
13289
13290 return *result;
13291 }
13292
13293
13294 // For a script calculates compilation information about all its functions.
13295 // The script source is explicitly specified by the second argument.
13296 // The source of the actual script is not used, however it is important that
13297 // all generated code keeps references to this particular instance of script.
13298 // Returns a JSArray of compilation infos. The array is ordered so that
13299 // each function with all its descendant is always stored in a continues range
13300 // with the function itself going first. The root function is a script function.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditGatherCompileInfo)13301 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
13302 HandleScope scope(isolate);
13303 CHECK(isolate->debugger()->live_edit_enabled());
13304 ASSERT(args.length() == 2);
13305 CONVERT_ARG_CHECKED(JSValue, script, 0);
13306 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13307
13308 RUNTIME_ASSERT(script->value()->IsScript());
13309 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13310
13311 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
13312
13313 if (isolate->has_pending_exception()) {
13314 return Failure::Exception();
13315 }
13316
13317 return result;
13318 }
13319
13320
13321 // Changes the source of the script to a new_source.
13322 // If old_script_name is provided (i.e. is a String), also creates a copy of
13323 // the script with its original source and sends notification to debugger.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditReplaceScript)13324 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
13325 HandleScope scope(isolate);
13326 CHECK(isolate->debugger()->live_edit_enabled());
13327 ASSERT(args.length() == 3);
13328 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13329 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
13330 Handle<Object> old_script_name(args[2], isolate);
13331
13332 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13333 Handle<Script> original_script(Script::cast(original_script_value->value()));
13334
13335 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
13336 new_source,
13337 old_script_name);
13338
13339 if (old_script->IsScript()) {
13340 Handle<Script> script_handle(Script::cast(old_script));
13341 return *(GetScriptWrapper(script_handle));
13342 } else {
13343 return isolate->heap()->null_value();
13344 }
13345 }
13346
13347
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditFunctionSourceUpdated)13348 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
13349 HandleScope scope(isolate);
13350 CHECK(isolate->debugger()->live_edit_enabled());
13351 ASSERT(args.length() == 1);
13352 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
13353 return LiveEdit::FunctionSourceUpdated(shared_info);
13354 }
13355
13356
13357 // Replaces code of SharedFunctionInfo with a new one.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditReplaceFunctionCode)13358 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
13359 HandleScope scope(isolate);
13360 CHECK(isolate->debugger()->live_edit_enabled());
13361 ASSERT(args.length() == 2);
13362 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13363 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
13364
13365 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
13366 }
13367
13368
13369 // Connects SharedFunctionInfo to another script.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditFunctionSetScript)13370 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
13371 HandleScope scope(isolate);
13372 CHECK(isolate->debugger()->live_edit_enabled());
13373 ASSERT(args.length() == 2);
13374 Handle<Object> function_object(args[0], isolate);
13375 Handle<Object> script_object(args[1], isolate);
13376
13377 if (function_object->IsJSValue()) {
13378 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13379 if (script_object->IsJSValue()) {
13380 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13381 Script* script = Script::cast(JSValue::cast(*script_object)->value());
13382 script_object = Handle<Object>(script, isolate);
13383 }
13384
13385 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13386 } else {
13387 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13388 // and we check it in this function.
13389 }
13390
13391 return isolate->heap()->undefined_value();
13392 }
13393
13394
13395 // In a code of a parent function replaces original function as embedded object
13396 // with a substitution one.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditReplaceRefToNestedFunction)13397 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
13398 HandleScope scope(isolate);
13399 CHECK(isolate->debugger()->live_edit_enabled());
13400 ASSERT(args.length() == 3);
13401
13402 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13403 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13404 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
13405
13406 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
13407 subst_wrapper);
13408
13409 return isolate->heap()->undefined_value();
13410 }
13411
13412
13413 // Updates positions of a shared function info (first parameter) according
13414 // to script source change. Text change is described in second parameter as
13415 // array of groups of 3 numbers:
13416 // (change_begin, change_end, change_end_new_position).
13417 // Each group describes a change in text; groups are sorted by change_begin.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditPatchFunctionPositions)13418 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
13419 HandleScope scope(isolate);
13420 CHECK(isolate->debugger()->live_edit_enabled());
13421 ASSERT(args.length() == 2);
13422 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13423 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
13424
13425 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
13426 }
13427
13428
13429 // For array of SharedFunctionInfo's (each wrapped in JSValue)
13430 // checks that none of them have activations on stacks (of any thread).
13431 // Returns array of the same length with corresponding results of
13432 // LiveEdit::FunctionPatchabilityStatus type.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditCheckAndDropActivations)13433 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
13434 HandleScope scope(isolate);
13435 CHECK(isolate->debugger()->live_edit_enabled());
13436 ASSERT(args.length() == 2);
13437 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13438 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
13439
13440 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
13441 }
13442
13443
13444 // Compares 2 strings line-by-line, then token-wise and returns diff in form
13445 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13446 // of diff chunks.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditCompareStrings)13447 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
13448 HandleScope scope(isolate);
13449 CHECK(isolate->debugger()->live_edit_enabled());
13450 ASSERT(args.length() == 2);
13451 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13452 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
13453
13454 return *LiveEdit::CompareStrings(s1, s2);
13455 }
13456
13457
13458 // Restarts a call frame and completely drops all frames above.
13459 // Returns true if successful. Otherwise returns undefined or an error message.
RUNTIME_FUNCTION(MaybeObject *,Runtime_LiveEditRestartFrame)13460 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
13461 HandleScope scope(isolate);
13462 CHECK(isolate->debugger()->live_edit_enabled());
13463 ASSERT(args.length() == 2);
13464
13465 // Check arguments.
13466 Object* check;
13467 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
13468 RUNTIME_ARGUMENTS(isolate, args));
13469 if (!maybe_check->ToObject(&check)) return maybe_check;
13470 }
13471 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13472 Heap* heap = isolate->heap();
13473
13474 // Find the relevant frame with the requested index.
13475 StackFrame::Id id = isolate->debug()->break_frame_id();
13476 if (id == StackFrame::NO_ID) {
13477 // If there are no JavaScript stack frames return undefined.
13478 return heap->undefined_value();
13479 }
13480
13481 int count = 0;
13482 JavaScriptFrameIterator it(isolate, id);
13483 for (; !it.done(); it.Advance()) {
13484 if (index < count + it.frame()->GetInlineCount()) break;
13485 count += it.frame()->GetInlineCount();
13486 }
13487 if (it.done()) return heap->undefined_value();
13488
13489 const char* error_message = LiveEdit::RestartFrame(it.frame());
13490 if (error_message) {
13491 return *(isolate->factory()->InternalizeUtf8String(error_message));
13492 }
13493 return heap->true_value();
13494 }
13495
13496
13497 // A testing entry. Returns statement position which is the closest to
13498 // source_position.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFunctionCodePositionFromSource)13499 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
13500 HandleScope scope(isolate);
13501 CHECK(isolate->debugger()->live_edit_enabled());
13502 ASSERT(args.length() == 2);
13503 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13504 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13505
13506 Handle<Code> code(function->code(), isolate);
13507
13508 if (code->kind() != Code::FUNCTION &&
13509 code->kind() != Code::OPTIMIZED_FUNCTION) {
13510 return isolate->heap()->undefined_value();
13511 }
13512
13513 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
13514 int closest_pc = 0;
13515 int distance = kMaxInt;
13516 while (!it.done()) {
13517 int statement_position = static_cast<int>(it.rinfo()->data());
13518 // Check if this break point is closer that what was previously found.
13519 if (source_position <= statement_position &&
13520 statement_position - source_position < distance) {
13521 closest_pc =
13522 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
13523 distance = statement_position - source_position;
13524 // Check whether we can't get any closer.
13525 if (distance == 0) break;
13526 }
13527 it.next();
13528 }
13529
13530 return Smi::FromInt(closest_pc);
13531 }
13532
13533
13534 // Calls specified function with or without entering the debugger.
13535 // This is used in unit tests to run code as if debugger is entered or simply
13536 // to have a stack with C++ frame in the middle.
RUNTIME_FUNCTION(MaybeObject *,Runtime_ExecuteInDebugContext)13537 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
13538 HandleScope scope(isolate);
13539 ASSERT(args.length() == 2);
13540 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13541 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
13542
13543 Handle<Object> result;
13544 bool pending_exception;
13545 {
13546 if (without_debugger) {
13547 result = Execution::Call(isolate,
13548 function,
13549 isolate->global_object(),
13550 0,
13551 NULL,
13552 &pending_exception);
13553 } else {
13554 EnterDebugger enter_debugger(isolate);
13555 result = Execution::Call(isolate,
13556 function,
13557 isolate->global_object(),
13558 0,
13559 NULL,
13560 &pending_exception);
13561 }
13562 }
13563 if (!pending_exception) {
13564 return *result;
13565 } else {
13566 return Failure::Exception();
13567 }
13568 }
13569
13570
13571 // Sets a v8 flag.
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetFlags)13572 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
13573 SealHandleScope shs(isolate);
13574 CONVERT_ARG_CHECKED(String, arg, 0);
13575 SmartArrayPointer<char> flags =
13576 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
13577 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
13578 return isolate->heap()->undefined_value();
13579 }
13580
13581
13582 // Performs a GC.
13583 // Presently, it only does a full GC.
RUNTIME_FUNCTION(MaybeObject *,Runtime_CollectGarbage)13584 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
13585 SealHandleScope shs(isolate);
13586 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
13587 return isolate->heap()->undefined_value();
13588 }
13589
13590
13591 // Gets the current heap usage.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetHeapUsage)13592 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
13593 SealHandleScope shs(isolate);
13594 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
13595 if (!Smi::IsValid(usage)) {
13596 return *isolate->factory()->NewNumberFromInt(usage);
13597 }
13598 return Smi::FromInt(usage);
13599 }
13600
13601 #endif // ENABLE_DEBUGGER_SUPPORT
13602
13603
13604 #ifdef V8_I18N_SUPPORT
RUNTIME_FUNCTION(MaybeObject *,Runtime_CanonicalizeLanguageTag)13605 RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) {
13606 HandleScope scope(isolate);
13607
13608 ASSERT(args.length() == 1);
13609 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13610
13611 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13612
13613 // Return value which denotes invalid language tag.
13614 const char* const kInvalidTag = "invalid-tag";
13615
13616 UErrorCode error = U_ZERO_ERROR;
13617 char icu_result[ULOC_FULLNAME_CAPACITY];
13618 int icu_length = 0;
13619
13620 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13621 &icu_length, &error);
13622 if (U_FAILURE(error) || icu_length == 0) {
13623 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13624 }
13625
13626 char result[ULOC_FULLNAME_CAPACITY];
13627
13628 // Force strict BCP47 rules.
13629 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13630
13631 if (U_FAILURE(error)) {
13632 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13633 }
13634
13635 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13636 }
13637
13638
RUNTIME_FUNCTION(MaybeObject *,Runtime_AvailableLocalesOf)13639 RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) {
13640 HandleScope scope(isolate);
13641
13642 ASSERT(args.length() == 1);
13643 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13644
13645 const icu::Locale* available_locales = NULL;
13646 int32_t count = 0;
13647
13648 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13649 available_locales = icu::Collator::getAvailableLocales(count);
13650 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13651 available_locales = icu::NumberFormat::getAvailableLocales(count);
13652 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13653 available_locales = icu::DateFormat::getAvailableLocales(count);
13654 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13655 available_locales = icu::BreakIterator::getAvailableLocales(count);
13656 }
13657
13658 UErrorCode error = U_ZERO_ERROR;
13659 char result[ULOC_FULLNAME_CAPACITY];
13660 Handle<JSObject> locales =
13661 isolate->factory()->NewJSObject(isolate->object_function());
13662
13663 for (int32_t i = 0; i < count; ++i) {
13664 const char* icu_name = available_locales[i].getName();
13665
13666 error = U_ZERO_ERROR;
13667 // No need to force strict BCP47 rules.
13668 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13669 if (U_FAILURE(error)) {
13670 // This shouldn't happen, but lets not break the user.
13671 continue;
13672 }
13673
13674 RETURN_IF_EMPTY_HANDLE(isolate,
13675 JSObject::SetLocalPropertyIgnoreAttributes(
13676 locales,
13677 isolate->factory()->NewStringFromAscii(CStrVector(result)),
13678 isolate->factory()->NewNumber(i),
13679 NONE));
13680 }
13681
13682 return *locales;
13683 }
13684
13685
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetDefaultICULocale)13686 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) {
13687 SealHandleScope shs(isolate);
13688
13689 ASSERT(args.length() == 0);
13690
13691 icu::Locale default_locale;
13692
13693 // Set the locale
13694 char result[ULOC_FULLNAME_CAPACITY];
13695 UErrorCode status = U_ZERO_ERROR;
13696 uloc_toLanguageTag(
13697 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13698 if (U_SUCCESS(status)) {
13699 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13700 }
13701
13702 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und"));
13703 }
13704
13705
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetLanguageTagVariants)13706 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
13707 HandleScope scope(isolate);
13708
13709 ASSERT(args.length() == 1);
13710
13711 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13712
13713 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13714 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length);
13715 Handle<Name> maximized =
13716 isolate->factory()->NewStringFromAscii(CStrVector("maximized"));
13717 Handle<Name> base =
13718 isolate->factory()->NewStringFromAscii(CStrVector("base"));
13719 for (unsigned int i = 0; i < length; ++i) {
13720 MaybeObject* maybe_string = input->GetElement(isolate, i);
13721 Object* locale_id;
13722 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) {
13723 return isolate->Throw(isolate->heap()->illegal_argument_string());
13724 }
13725
13726 v8::String::Utf8Value utf8_locale_id(
13727 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id))));
13728
13729 UErrorCode error = U_ZERO_ERROR;
13730
13731 // Convert from BCP47 to ICU format.
13732 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13733 char icu_locale[ULOC_FULLNAME_CAPACITY];
13734 int icu_locale_length = 0;
13735 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13736 &icu_locale_length, &error);
13737 if (U_FAILURE(error) || icu_locale_length == 0) {
13738 return isolate->Throw(isolate->heap()->illegal_argument_string());
13739 }
13740
13741 // Maximize the locale.
13742 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13743 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13744 uloc_addLikelySubtags(
13745 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13746
13747 // Remove extensions from maximized locale.
13748 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13749 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13750 uloc_getBaseName(
13751 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13752
13753 // Get original name without extensions.
13754 // de_DE@collation=phonebook -> de_DE
13755 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13756 uloc_getBaseName(
13757 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13758
13759 // Convert from ICU locale format to BCP47 format.
13760 // de_Latn_DE -> de-Latn-DE
13761 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13762 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13763 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13764
13765 // de_DE -> de-DE
13766 char base_locale[ULOC_FULLNAME_CAPACITY];
13767 uloc_toLanguageTag(
13768 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13769
13770 if (U_FAILURE(error)) {
13771 return isolate->Throw(isolate->heap()->illegal_argument_string());
13772 }
13773
13774 Handle<JSObject> result =
13775 isolate->factory()->NewJSObject(isolate->object_function());
13776 RETURN_IF_EMPTY_HANDLE(isolate,
13777 JSObject::SetLocalPropertyIgnoreAttributes(
13778 result,
13779 maximized,
13780 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)),
13781 NONE));
13782 RETURN_IF_EMPTY_HANDLE(isolate,
13783 JSObject::SetLocalPropertyIgnoreAttributes(
13784 result,
13785 base,
13786 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)),
13787 NONE));
13788 output->set(i, *result);
13789 }
13790
13791 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output);
13792 result->set_length(Smi::FromInt(length));
13793 return *result;
13794 }
13795
13796
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateDateTimeFormat)13797 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
13798 HandleScope scope(isolate);
13799
13800 ASSERT(args.length() == 3);
13801
13802 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13803 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13804 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13805
13806 Handle<ObjectTemplateInfo> date_format_template =
13807 I18N::GetTemplate(isolate);
13808
13809 // Create an empty object wrapper.
13810 bool has_pending_exception = false;
13811 Handle<JSObject> local_object = Execution::InstantiateObject(
13812 date_format_template, &has_pending_exception);
13813 if (has_pending_exception) {
13814 ASSERT(isolate->has_pending_exception());
13815 return Failure::Exception();
13816 }
13817
13818 // Set date time formatter as internal field of the resulting JS object.
13819 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
13820 isolate, locale, options, resolved);
13821
13822 if (!date_format) return isolate->ThrowIllegalOperation();
13823
13824 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
13825
13826 RETURN_IF_EMPTY_HANDLE(isolate,
13827 JSObject::SetLocalPropertyIgnoreAttributes(
13828 local_object,
13829 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
13830 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13831 NONE));
13832
13833 // Make object handle weak so we can delete the data format once GC kicks in.
13834 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
13835 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
13836 NULL,
13837 DateFormat::DeleteDateFormat);
13838 return *local_object;
13839 }
13840
13841
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalDateFormat)13842 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
13843 HandleScope scope(isolate);
13844
13845 ASSERT(args.length() == 2);
13846
13847 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13848 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
13849
13850 bool has_pending_exception = false;
13851 Handle<Object> value =
13852 Execution::ToNumber(isolate, date, &has_pending_exception);
13853 if (has_pending_exception) {
13854 ASSERT(isolate->has_pending_exception());
13855 return Failure::Exception();
13856 }
13857
13858 icu::SimpleDateFormat* date_format =
13859 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13860 if (!date_format) return isolate->ThrowIllegalOperation();
13861
13862 icu::UnicodeString result;
13863 date_format->format(value->Number(), result);
13864
13865 return *isolate->factory()->NewStringFromTwoByte(
13866 Vector<const uint16_t>(
13867 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13868 result.length()));
13869 }
13870
13871
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalDateParse)13872 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
13873 HandleScope scope(isolate);
13874
13875 ASSERT(args.length() == 2);
13876
13877 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13878 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
13879
13880 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
13881 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
13882 icu::SimpleDateFormat* date_format =
13883 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13884 if (!date_format) return isolate->ThrowIllegalOperation();
13885
13886 UErrorCode status = U_ZERO_ERROR;
13887 UDate date = date_format->parse(u_date, status);
13888 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13889
13890 bool has_pending_exception = false;
13891 Handle<JSDate> result = Handle<JSDate>::cast(
13892 Execution::NewDate(
13893 isolate, static_cast<double>(date), &has_pending_exception));
13894 if (has_pending_exception) {
13895 ASSERT(isolate->has_pending_exception());
13896 return Failure::Exception();
13897 }
13898 return *result;
13899 }
13900
13901
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateNumberFormat)13902 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
13903 HandleScope scope(isolate);
13904
13905 ASSERT(args.length() == 3);
13906
13907 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13908 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13909 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13910
13911 Handle<ObjectTemplateInfo> number_format_template =
13912 I18N::GetTemplate(isolate);
13913
13914 // Create an empty object wrapper.
13915 bool has_pending_exception = false;
13916 Handle<JSObject> local_object = Execution::InstantiateObject(
13917 number_format_template, &has_pending_exception);
13918 if (has_pending_exception) {
13919 ASSERT(isolate->has_pending_exception());
13920 return Failure::Exception();
13921 }
13922
13923 // Set number formatter as internal field of the resulting JS object.
13924 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
13925 isolate, locale, options, resolved);
13926
13927 if (!number_format) return isolate->ThrowIllegalOperation();
13928
13929 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
13930
13931 RETURN_IF_EMPTY_HANDLE(isolate,
13932 JSObject::SetLocalPropertyIgnoreAttributes(
13933 local_object,
13934 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
13935 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13936 NONE));
13937
13938 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
13939 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
13940 NULL,
13941 NumberFormat::DeleteNumberFormat);
13942 return *local_object;
13943 }
13944
13945
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalNumberFormat)13946 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
13947 HandleScope scope(isolate);
13948
13949 ASSERT(args.length() == 2);
13950
13951 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13952 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
13953
13954 bool has_pending_exception = false;
13955 Handle<Object> value = Execution::ToNumber(
13956 isolate, number, &has_pending_exception);
13957 if (has_pending_exception) {
13958 ASSERT(isolate->has_pending_exception());
13959 return Failure::Exception();
13960 }
13961
13962 icu::DecimalFormat* number_format =
13963 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13964 if (!number_format) return isolate->ThrowIllegalOperation();
13965
13966 icu::UnicodeString result;
13967 number_format->format(value->Number(), result);
13968
13969 return *isolate->factory()->NewStringFromTwoByte(
13970 Vector<const uint16_t>(
13971 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13972 result.length()));
13973 }
13974
13975
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalNumberParse)13976 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
13977 HandleScope scope(isolate);
13978
13979 ASSERT(args.length() == 2);
13980
13981 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13982 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
13983
13984 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
13985 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
13986 icu::DecimalFormat* number_format =
13987 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13988 if (!number_format) return isolate->ThrowIllegalOperation();
13989
13990 UErrorCode status = U_ZERO_ERROR;
13991 icu::Formattable result;
13992 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
13993 // to be part of Chrome.
13994 // TODO(cira): Include currency parsing code using parseCurrency call.
13995 // We need to check if the formatter parses all currencies or only the
13996 // one it was constructed with (it will impact the API - how to return ISO
13997 // code and the value).
13998 number_format->parse(u_number, result, status);
13999 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
14000
14001 switch (result.getType()) {
14002 case icu::Formattable::kDouble:
14003 return *isolate->factory()->NewNumber(result.getDouble());
14004 case icu::Formattable::kLong:
14005 return *isolate->factory()->NewNumberFromInt(result.getLong());
14006 case icu::Formattable::kInt64:
14007 return *isolate->factory()->NewNumber(
14008 static_cast<double>(result.getInt64()));
14009 default:
14010 return isolate->heap()->undefined_value();
14011 }
14012 }
14013
14014
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateCollator)14015 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) {
14016 HandleScope scope(isolate);
14017
14018 ASSERT(args.length() == 3);
14019
14020 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14021 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14022 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14023
14024 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
14025
14026 // Create an empty object wrapper.
14027 bool has_pending_exception = false;
14028 Handle<JSObject> local_object = Execution::InstantiateObject(
14029 collator_template, &has_pending_exception);
14030 if (has_pending_exception) {
14031 ASSERT(isolate->has_pending_exception());
14032 return Failure::Exception();
14033 }
14034
14035 // Set collator as internal field of the resulting JS object.
14036 icu::Collator* collator = Collator::InitializeCollator(
14037 isolate, locale, options, resolved);
14038
14039 if (!collator) return isolate->ThrowIllegalOperation();
14040
14041 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
14042
14043 RETURN_IF_EMPTY_HANDLE(isolate,
14044 JSObject::SetLocalPropertyIgnoreAttributes(
14045 local_object,
14046 isolate->factory()->NewStringFromAscii(CStrVector("collator")),
14047 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14048 NONE));
14049
14050 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14051 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
14052 NULL,
14053 Collator::DeleteCollator);
14054 return *local_object;
14055 }
14056
14057
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalCompare)14058 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) {
14059 HandleScope scope(isolate);
14060
14061 ASSERT(args.length() == 3);
14062
14063 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14064 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14065 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14066
14067 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14068 if (!collator) return isolate->ThrowIllegalOperation();
14069
14070 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14071 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14072 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14073 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14074 UErrorCode status = U_ZERO_ERROR;
14075 UCollationResult result = collator->compare(u_string1,
14076 string_value1.length(),
14077 u_string2,
14078 string_value2.length(),
14079 status);
14080 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14081
14082 return *isolate->factory()->NewNumberFromInt(result);
14083 }
14084
14085
RUNTIME_FUNCTION(MaybeObject *,Runtime_CreateBreakIterator)14086 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) {
14087 HandleScope scope(isolate);
14088
14089 ASSERT(args.length() == 3);
14090
14091 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14092 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14093 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14094
14095 Handle<ObjectTemplateInfo> break_iterator_template =
14096 I18N::GetTemplate2(isolate);
14097
14098 // Create an empty object wrapper.
14099 bool has_pending_exception = false;
14100 Handle<JSObject> local_object = Execution::InstantiateObject(
14101 break_iterator_template, &has_pending_exception);
14102 if (has_pending_exception) {
14103 ASSERT(isolate->has_pending_exception());
14104 return Failure::Exception();
14105 }
14106
14107 // Set break iterator as internal field of the resulting JS object.
14108 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14109 isolate, locale, options, resolved);
14110
14111 if (!break_iterator) return isolate->ThrowIllegalOperation();
14112
14113 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14114 // Make sure that the pointer to adopted text is NULL.
14115 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14116
14117 RETURN_IF_EMPTY_HANDLE(isolate,
14118 JSObject::SetLocalPropertyIgnoreAttributes(
14119 local_object,
14120 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")),
14121 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14122 NONE));
14123
14124 // Make object handle weak so we can delete the break iterator once GC kicks
14125 // in.
14126 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14127 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
14128 NULL,
14129 BreakIterator::DeleteBreakIterator);
14130 return *local_object;
14131 }
14132
14133
RUNTIME_FUNCTION(MaybeObject *,Runtime_BreakIteratorAdoptText)14134 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) {
14135 HandleScope scope(isolate);
14136
14137 ASSERT(args.length() == 2);
14138
14139 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14140 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14141
14142 icu::BreakIterator* break_iterator =
14143 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14144 if (!break_iterator) return isolate->ThrowIllegalOperation();
14145
14146 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14147 break_iterator_holder->GetInternalField(1));
14148 delete u_text;
14149
14150 v8::String::Value text_value(v8::Utils::ToLocal(text));
14151 u_text = new icu::UnicodeString(
14152 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14153 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14154
14155 break_iterator->setText(*u_text);
14156
14157 return isolate->heap()->undefined_value();
14158 }
14159
14160
RUNTIME_FUNCTION(MaybeObject *,Runtime_BreakIteratorFirst)14161 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) {
14162 HandleScope scope(isolate);
14163
14164 ASSERT(args.length() == 1);
14165
14166 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14167
14168 icu::BreakIterator* break_iterator =
14169 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14170 if (!break_iterator) return isolate->ThrowIllegalOperation();
14171
14172 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14173 }
14174
14175
RUNTIME_FUNCTION(MaybeObject *,Runtime_BreakIteratorNext)14176 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) {
14177 HandleScope scope(isolate);
14178
14179 ASSERT(args.length() == 1);
14180
14181 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14182
14183 icu::BreakIterator* break_iterator =
14184 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14185 if (!break_iterator) return isolate->ThrowIllegalOperation();
14186
14187 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14188 }
14189
14190
RUNTIME_FUNCTION(MaybeObject *,Runtime_BreakIteratorCurrent)14191 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) {
14192 HandleScope scope(isolate);
14193
14194 ASSERT(args.length() == 1);
14195
14196 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14197
14198 icu::BreakIterator* break_iterator =
14199 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14200 if (!break_iterator) return isolate->ThrowIllegalOperation();
14201
14202 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14203 }
14204
14205
RUNTIME_FUNCTION(MaybeObject *,Runtime_BreakIteratorBreakType)14206 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) {
14207 HandleScope scope(isolate);
14208
14209 ASSERT(args.length() == 1);
14210
14211 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14212
14213 icu::BreakIterator* break_iterator =
14214 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14215 if (!break_iterator) return isolate->ThrowIllegalOperation();
14216
14217 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14218 icu::RuleBasedBreakIterator* rule_based_iterator =
14219 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14220 int32_t status = rule_based_iterator->getRuleStatus();
14221 // Keep return values in sync with JavaScript BreakType enum.
14222 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14223 return *isolate->factory()->NewStringFromAscii(CStrVector("none"));
14224 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14225 return *isolate->factory()->NewStringFromAscii(CStrVector("number"));
14226 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14227 return *isolate->factory()->NewStringFromAscii(CStrVector("letter"));
14228 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14229 return *isolate->factory()->NewStringFromAscii(CStrVector("kana"));
14230 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14231 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo"));
14232 } else {
14233 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown"));
14234 }
14235 }
14236 #endif // V8_I18N_SUPPORT
14237
14238
14239 // Finds the script object from the script data. NOTE: This operation uses
14240 // heap traversal to find the function generated for the source position
14241 // for the requested break point. For lazily compiled functions several heap
14242 // traversals might be required rendering this operation as a rather slow
14243 // operation. However for setting break points which is normally done through
14244 // some kind of user interaction the performance is not crucial.
Runtime_GetScriptFromScriptName(Handle<String> script_name)14245 static Handle<Object> Runtime_GetScriptFromScriptName(
14246 Handle<String> script_name) {
14247 // Scan the heap for Script objects to find the script with the requested
14248 // script data.
14249 Handle<Script> script;
14250 Factory* factory = script_name->GetIsolate()->factory();
14251 Heap* heap = script_name->GetHeap();
14252 heap->EnsureHeapIsIterable();
14253 DisallowHeapAllocation no_allocation_during_heap_iteration;
14254 HeapIterator iterator(heap);
14255 HeapObject* obj = NULL;
14256 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
14257 // If a script is found check if it has the script data requested.
14258 if (obj->IsScript()) {
14259 if (Script::cast(obj)->name()->IsString()) {
14260 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14261 script = Handle<Script>(Script::cast(obj));
14262 }
14263 }
14264 }
14265 }
14266
14267 // If no script with the requested script data is found return undefined.
14268 if (script.is_null()) return factory->undefined_value();
14269
14270 // Return the script found.
14271 return GetScriptWrapper(script);
14272 }
14273
14274
14275 // Get the script object from script data. NOTE: Regarding performance
14276 // see the NOTE for GetScriptFromScriptData.
14277 // args[0]: script data for the script to find the source for
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetScript)14278 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
14279 HandleScope scope(isolate);
14280
14281 ASSERT(args.length() == 1);
14282
14283 CONVERT_ARG_CHECKED(String, script_name, 0);
14284
14285 // Find the requested script.
14286 Handle<Object> result =
14287 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14288 return *result;
14289 }
14290
14291
14292 // Collect the raw data for a stack trace. Returns an array of 4
14293 // element segments each containing a receiver, function, code and
14294 // native code offset.
RUNTIME_FUNCTION(MaybeObject *,Runtime_CollectStackTrace)14295 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
14296 HandleScope scope(isolate);
14297 ASSERT_EQ(args.length(), 3);
14298 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14299 Handle<Object> caller = args.at<Object>(1);
14300 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
14301
14302 // Optionally capture a more detailed stack trace for the message.
14303 isolate->CaptureAndSetDetailedStackTrace(error_object);
14304 // Capture a simple stack trace for the stack property.
14305 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14306 }
14307
14308
14309 // Retrieve the stack trace. This is the raw stack trace that yet has to
14310 // be formatted. Since we only need this once, clear it afterwards.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetAndClearOverflowedStackTrace)14311 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) {
14312 HandleScope scope(isolate);
14313 ASSERT_EQ(args.length(), 1);
14314 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14315 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14316 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate);
14317 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14318 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
14319 JSObject::DeleteHiddenProperty(error_object, key);
14320 return *result;
14321 }
14322
14323
14324 // Returns V8 version as a string.
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetV8Version)14325 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
14326 SealHandleScope shs(isolate);
14327 ASSERT_EQ(args.length(), 0);
14328
14329 const char* version_string = v8::V8::GetVersion();
14330
14331 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
14332 NOT_TENURED);
14333 }
14334
14335
RUNTIME_FUNCTION(MaybeObject *,Runtime_Abort)14336 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
14337 SealHandleScope shs(isolate);
14338 ASSERT(args.length() == 2);
14339 OS::PrintError("abort: %s\n",
14340 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
14341 isolate->PrintStack(stderr);
14342 OS::Abort();
14343 UNREACHABLE();
14344 return NULL;
14345 }
14346
14347
RUNTIME_FUNCTION(MaybeObject *,Runtime_AbortJS)14348 RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) {
14349 HandleScope scope(isolate);
14350 ASSERT(args.length() == 1);
14351 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
14352 OS::PrintError("abort: %s\n", *message->ToCString());
14353 isolate->PrintStack(stderr);
14354 OS::Abort();
14355 UNREACHABLE();
14356 return NULL;
14357 }
14358
14359
RUNTIME_FUNCTION(MaybeObject *,Runtime_FlattenString)14360 RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
14361 HandleScope scope(isolate);
14362 ASSERT(args.length() == 1);
14363 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14364 FlattenString(str);
14365 return isolate->heap()->undefined_value();
14366 }
14367
14368
RUNTIME_FUNCTION(MaybeObject *,Runtime_NotifyContextDisposed)14369 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) {
14370 HandleScope scope(isolate);
14371 ASSERT(args.length() == 0);
14372 isolate->heap()->NotifyContextDisposed();
14373 return isolate->heap()->undefined_value();
14374 }
14375
14376
RUNTIME_FUNCTION(MaybeObject *,Runtime_MigrateInstance)14377 RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) {
14378 HandleScope scope(isolate);
14379 ASSERT(args.length() == 1);
14380 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14381 if (!object->IsJSObject()) return Smi::FromInt(0);
14382 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14383 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14384 JSObject::MigrateInstance(js_object);
14385 return *object;
14386 }
14387
14388
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetFromCache)14389 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
14390 SealHandleScope shs(isolate);
14391 // This is only called from codegen, so checks might be more lax.
14392 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
14393 Object* key = args[1];
14394
14395 int finger_index = cache->finger_index();
14396 Object* o = cache->get(finger_index);
14397 if (o == key) {
14398 // The fastest case: hit the same place again.
14399 return cache->get(finger_index + 1);
14400 }
14401
14402 for (int i = finger_index - 2;
14403 i >= JSFunctionResultCache::kEntriesIndex;
14404 i -= 2) {
14405 o = cache->get(i);
14406 if (o == key) {
14407 cache->set_finger_index(i);
14408 return cache->get(i + 1);
14409 }
14410 }
14411
14412 int size = cache->size();
14413 ASSERT(size <= cache->length());
14414
14415 for (int i = size - 2; i > finger_index; i -= 2) {
14416 o = cache->get(i);
14417 if (o == key) {
14418 cache->set_finger_index(i);
14419 return cache->get(i + 1);
14420 }
14421 }
14422
14423 // There is no value in the cache. Invoke the function and cache result.
14424 HandleScope scope(isolate);
14425
14426 Handle<JSFunctionResultCache> cache_handle(cache);
14427 Handle<Object> key_handle(key, isolate);
14428 Handle<Object> value;
14429 {
14430 Handle<JSFunction> factory(JSFunction::cast(
14431 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14432 // TODO(antonm): consider passing a receiver when constructing a cache.
14433 Handle<Object> receiver(isolate->native_context()->global_object(),
14434 isolate);
14435 // This handle is nor shared, nor used later, so it's safe.
14436 Handle<Object> argv[] = { key_handle };
14437 bool pending_exception;
14438 value = Execution::Call(isolate,
14439 factory,
14440 receiver,
14441 ARRAY_SIZE(argv),
14442 argv,
14443 &pending_exception);
14444 if (pending_exception) return Failure::Exception();
14445 }
14446
14447 #ifdef VERIFY_HEAP
14448 if (FLAG_verify_heap) {
14449 cache_handle->JSFunctionResultCacheVerify();
14450 }
14451 #endif
14452
14453 // Function invocation may have cleared the cache. Reread all the data.
14454 finger_index = cache_handle->finger_index();
14455 size = cache_handle->size();
14456
14457 // If we have spare room, put new data into it, otherwise evict post finger
14458 // entry which is likely to be the least recently used.
14459 int index = -1;
14460 if (size < cache_handle->length()) {
14461 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14462 index = size;
14463 } else {
14464 index = finger_index + JSFunctionResultCache::kEntrySize;
14465 if (index == cache_handle->length()) {
14466 index = JSFunctionResultCache::kEntriesIndex;
14467 }
14468 }
14469
14470 ASSERT(index % 2 == 0);
14471 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14472 ASSERT(index < cache_handle->length());
14473
14474 cache_handle->set(index, *key_handle);
14475 cache_handle->set(index + 1, *value);
14476 cache_handle->set_finger_index(index);
14477
14478 #ifdef VERIFY_HEAP
14479 if (FLAG_verify_heap) {
14480 cache_handle->JSFunctionResultCacheVerify();
14481 }
14482 #endif
14483
14484 return *value;
14485 }
14486
14487
RUNTIME_FUNCTION(MaybeObject *,Runtime_MessageGetStartPosition)14488 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
14489 SealHandleScope shs(isolate);
14490 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14491 return Smi::FromInt(message->start_position());
14492 }
14493
14494
RUNTIME_FUNCTION(MaybeObject *,Runtime_MessageGetScript)14495 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
14496 SealHandleScope shs(isolate);
14497 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14498 return message->script();
14499 }
14500
14501
14502 #ifdef DEBUG
14503 // ListNatives is ONLY used by the fuzz-natives.js in debug mode
14504 // Exclude the code in release mode.
RUNTIME_FUNCTION(MaybeObject *,Runtime_ListNatives)14505 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
14506 HandleScope scope(isolate);
14507 ASSERT(args.length() == 0);
14508 #define COUNT_ENTRY(Name, argc, ressize) + 1
14509 int entry_count = 0
14510 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14511 INLINE_FUNCTION_LIST(COUNT_ENTRY)
14512 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
14513 #undef COUNT_ENTRY
14514 Factory* factory = isolate->factory();
14515 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
14516 int index = 0;
14517 bool inline_runtime_functions = false;
14518 #define ADD_ENTRY(Name, argc, ressize) \
14519 { \
14520 HandleScope inner(isolate); \
14521 Handle<String> name; \
14522 /* Inline runtime functions have an underscore in front of the name. */ \
14523 if (inline_runtime_functions) { \
14524 name = factory->NewStringFromAscii( \
14525 Vector<const char>("_" #Name, StrLength("_" #Name))); \
14526 } else { \
14527 name = factory->NewStringFromAscii( \
14528 Vector<const char>(#Name, StrLength(#Name))); \
14529 } \
14530 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
14531 pair_elements->set(0, *name); \
14532 pair_elements->set(1, Smi::FromInt(argc)); \
14533 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
14534 elements->set(index++, *pair); \
14535 }
14536 inline_runtime_functions = false;
14537 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
14538 inline_runtime_functions = true;
14539 INLINE_FUNCTION_LIST(ADD_ENTRY)
14540 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
14541 #undef ADD_ENTRY
14542 ASSERT_EQ(index, entry_count);
14543 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
14544 return *result;
14545 }
14546 #endif
14547
14548
RUNTIME_FUNCTION(MaybeObject *,Runtime_Log)14549 RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
14550 SealHandleScope shs(isolate);
14551 ASSERT(args.length() == 2);
14552 CONVERT_ARG_CHECKED(String, format, 0);
14553 CONVERT_ARG_CHECKED(JSArray, elms, 1);
14554 DisallowHeapAllocation no_gc;
14555 String::FlatContent format_content = format->GetFlatContent();
14556 RUNTIME_ASSERT(format_content.IsAscii());
14557 Vector<const uint8_t> chars = format_content.ToOneByteVector();
14558 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
14559 return isolate->heap()->undefined_value();
14560 }
14561
14562
RUNTIME_FUNCTION(MaybeObject *,Runtime_IS_VAR)14563 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
14564 UNREACHABLE(); // implemented as macro in the parser
14565 return NULL;
14566 }
14567
14568
14569 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14570 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
14571 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14572 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14573 }
14574
14575 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)14576 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14577 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
14578 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
14579 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
14580 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
14581 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements)
14582 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
14583 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14584 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
14585 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
14586 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
14587 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
14588 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
14589 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
14590 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
14591 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
14592 // Properties test sitting with elements tests - not fooling anyone.
14593 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
14594
14595 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14596
14597
14598 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
14599 SealHandleScope shs(isolate);
14600 ASSERT(args.length() == 2);
14601 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14602 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
14603 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14604 }
14605
14606
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsAccessCheckNeeded)14607 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) {
14608 SealHandleScope shs(isolate);
14609 ASSERT(args.length() == 1);
14610 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
14611 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded());
14612 }
14613
14614
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsObserved)14615 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
14616 SealHandleScope shs(isolate);
14617 ASSERT(args.length() == 1);
14618
14619 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14620 JSReceiver* obj = JSReceiver::cast(args[0]);
14621 if (obj->IsJSGlobalProxy()) {
14622 Object* proto = obj->GetPrototype();
14623 if (proto->IsNull()) return isolate->heap()->false_value();
14624 ASSERT(proto->IsJSGlobalObject());
14625 obj = JSReceiver::cast(proto);
14626 }
14627 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14628 }
14629
14630
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetIsObserved)14631 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
14632 HandleScope scope(isolate);
14633 ASSERT(args.length() == 1);
14634 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
14635 if (obj->IsJSGlobalProxy()) {
14636 Object* proto = obj->GetPrototype();
14637 if (proto->IsNull()) return isolate->heap()->undefined_value();
14638 ASSERT(proto->IsJSGlobalObject());
14639 obj = handle(JSReceiver::cast(proto));
14640 }
14641 if (obj->IsJSProxy())
14642 return isolate->heap()->undefined_value();
14643
14644 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
14645 Handle<JSObject>::cast(obj)->HasFastElements()));
14646 ASSERT(obj->IsJSObject());
14647 JSObject::SetObserved(Handle<JSObject>::cast(obj));
14648 return isolate->heap()->undefined_value();
14649 }
14650
14651
RUNTIME_FUNCTION(MaybeObject *,Runtime_SetMicrotaskPending)14652 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) {
14653 SealHandleScope shs(isolate);
14654 ASSERT(args.length() == 1);
14655 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
14656 bool old_state = isolate->microtask_pending();
14657 isolate->set_microtask_pending(new_state);
14658 return isolate->heap()->ToBoolean(old_state);
14659 }
14660
14661
RUNTIME_FUNCTION(MaybeObject *,Runtime_GetObservationState)14662 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
14663 SealHandleScope shs(isolate);
14664 ASSERT(args.length() == 0);
14665 return isolate->heap()->observation_state();
14666 }
14667
14668
RUNTIME_FUNCTION(MaybeObject *,Runtime_ObservationWeakMapCreate)14669 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
14670 HandleScope scope(isolate);
14671 ASSERT(args.length() == 0);
14672 // TODO(adamk): Currently this runtime function is only called three times per
14673 // isolate. If it's called more often, the map should be moved into the
14674 // strong root list.
14675 Handle<Map> map =
14676 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
14677 Handle<JSWeakMap> weakmap =
14678 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
14679 return WeakCollectionInitialize(isolate, weakmap);
14680 }
14681
14682
RUNTIME_FUNCTION(MaybeObject *,Runtime_UnwrapGlobalProxy)14683 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
14684 SealHandleScope shs(isolate);
14685 ASSERT(args.length() == 1);
14686 Object* object = args[0];
14687 if (object->IsJSGlobalProxy()) {
14688 object = object->GetPrototype(isolate);
14689 if (object->IsNull()) return isolate->heap()->undefined_value();
14690 }
14691 return object;
14692 }
14693
14694
RUNTIME_FUNCTION(MaybeObject *,Runtime_IsAccessAllowedForObserver)14695 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) {
14696 HandleScope scope(isolate);
14697 ASSERT(args.length() == 3);
14698 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
14699 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
14700 ASSERT(object->IsAccessCheckNeeded());
14701 Handle<Object> key = args.at<Object>(2);
14702 SaveContext save(isolate);
14703 isolate->set_context(observer->context());
14704 if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
14705 v8::ACCESS_KEYS)) {
14706 return isolate->heap()->false_value();
14707 }
14708 bool access_allowed = false;
14709 uint32_t index = 0;
14710 if (key->ToArrayIndex(&index) ||
14711 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) {
14712 access_allowed =
14713 isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) &&
14714 isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS);
14715 } else {
14716 access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) &&
14717 isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS);
14718 }
14719 return isolate->heap()->ToBoolean(access_allowed);
14720 }
14721
14722
ArrayConstructorCommon(Isolate * isolate,Handle<JSFunction> constructor,Handle<AllocationSite> site,Arguments * caller_args)14723 static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
14724 Handle<JSFunction> constructor,
14725 Handle<AllocationSite> site,
14726 Arguments* caller_args) {
14727 bool holey = false;
14728 bool can_use_type_feedback = true;
14729 if (caller_args->length() == 1) {
14730 Object* argument_one = (*caller_args)[0];
14731 if (argument_one->IsSmi()) {
14732 int value = Smi::cast(argument_one)->value();
14733 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
14734 // the array is a dictionary in this case.
14735 can_use_type_feedback = false;
14736 } else if (value != 0) {
14737 holey = true;
14738 }
14739 } else {
14740 // Non-smi length argument produces a dictionary
14741 can_use_type_feedback = false;
14742 }
14743 }
14744
14745 JSArray* array;
14746 MaybeObject* maybe_array;
14747 if (!site.is_null() && can_use_type_feedback) {
14748 ElementsKind to_kind = site->GetElementsKind();
14749 if (holey && !IsFastHoleyElementsKind(to_kind)) {
14750 to_kind = GetHoleyElementsKind(to_kind);
14751 // Update the allocation site info to reflect the advice alteration.
14752 site->SetElementsKind(to_kind);
14753 }
14754
14755 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
14756 *constructor, site);
14757 if (!maybe_array->To(&array)) return maybe_array;
14758 } else {
14759 maybe_array = isolate->heap()->AllocateJSObject(*constructor);
14760 if (!maybe_array->To(&array)) return maybe_array;
14761 // We might need to transition to holey
14762 ElementsKind kind = constructor->initial_map()->elements_kind();
14763 if (holey && !IsFastHoleyElementsKind(kind)) {
14764 kind = GetHoleyElementsKind(kind);
14765 maybe_array = array->TransitionElementsKind(kind);
14766 if (maybe_array->IsFailure()) return maybe_array;
14767 }
14768 }
14769
14770 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
14771 DONT_INITIALIZE_ARRAY_ELEMENTS);
14772 if (maybe_array->IsFailure()) return maybe_array;
14773 ElementsKind old_kind = array->GetElementsKind();
14774 maybe_array = ArrayConstructInitializeElements(array, caller_args);
14775 if (maybe_array->IsFailure()) return maybe_array;
14776 if (!site.is_null() &&
14777 (old_kind != array->GetElementsKind() ||
14778 !can_use_type_feedback)) {
14779 // The arguments passed in caused a transition. This kind of complexity
14780 // can't be dealt with in the inlined hydrogen array constructor case.
14781 // We must mark the allocationsite as un-inlinable.
14782 site->SetDoNotInlineCall();
14783 }
14784 return array;
14785 }
14786
14787
RUNTIME_FUNCTION(MaybeObject *,Runtime_ArrayConstructor)14788 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
14789 HandleScope scope(isolate);
14790 // If we get 2 arguments then they are the stub parameters (constructor, type
14791 // info). If we get 4, then the first one is a pointer to the arguments
14792 // passed by the caller, and the last one is the length of the arguments
14793 // passed to the caller (redundant, but useful to check on the deoptimizer
14794 // with an assert).
14795 Arguments empty_args(0, NULL);
14796 bool no_caller_args = args.length() == 2;
14797 ASSERT(no_caller_args || args.length() == 4);
14798 int parameters_start = no_caller_args ? 0 : 1;
14799 Arguments* caller_args = no_caller_args
14800 ? &empty_args
14801 : reinterpret_cast<Arguments*>(args[0]);
14802 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14803 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
14804 #ifdef DEBUG
14805 if (!no_caller_args) {
14806 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
14807 ASSERT(arg_count == caller_args->length());
14808 }
14809 #endif
14810
14811 Handle<AllocationSite> site;
14812 if (!type_info.is_null() &&
14813 *type_info != isolate->heap()->undefined_value() &&
14814 Cell::cast(*type_info)->value()->IsAllocationSite()) {
14815 site = Handle<AllocationSite>(
14816 AllocationSite::cast(Cell::cast(*type_info)->value()), isolate);
14817 ASSERT(!site->SitePointsToLiteral());
14818 }
14819
14820 return ArrayConstructorCommon(isolate,
14821 constructor,
14822 site,
14823 caller_args);
14824 }
14825
14826
RUNTIME_FUNCTION(MaybeObject *,Runtime_InternalArrayConstructor)14827 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) {
14828 HandleScope scope(isolate);
14829 Arguments empty_args(0, NULL);
14830 bool no_caller_args = args.length() == 1;
14831 ASSERT(no_caller_args || args.length() == 3);
14832 int parameters_start = no_caller_args ? 0 : 1;
14833 Arguments* caller_args = no_caller_args
14834 ? &empty_args
14835 : reinterpret_cast<Arguments*>(args[0]);
14836 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14837 #ifdef DEBUG
14838 if (!no_caller_args) {
14839 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
14840 ASSERT(arg_count == caller_args->length());
14841 }
14842 #endif
14843 return ArrayConstructorCommon(isolate,
14844 constructor,
14845 Handle<AllocationSite>::null(),
14846 caller_args);
14847 }
14848
14849
RUNTIME_FUNCTION(MaybeObject *,Runtime_MaxSmi)14850 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) {
14851 return Smi::FromInt(Smi::kMaxValue);
14852 }
14853
14854
14855 // ----------------------------------------------------------------------------
14856 // Implementation of Runtime
14857
14858 #define F(name, number_of_args, result_size) \
14859 { Runtime::k##name, Runtime::RUNTIME, #name, \
14860 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
14861
14862
14863 #define I(name, number_of_args, result_size) \
14864 { Runtime::kInline##name, Runtime::INLINE, \
14865 "_" #name, NULL, number_of_args, result_size },
14866
14867 static const Runtime::Function kIntrinsicFunctions[] = {
14868 RUNTIME_FUNCTION_LIST(F)
14869 INLINE_FUNCTION_LIST(I)
14870 INLINE_RUNTIME_FUNCTION_LIST(I)
14871 };
14872
14873
InitializeIntrinsicFunctionNames(Heap * heap,Object * dictionary)14874 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
14875 Object* dictionary) {
14876 ASSERT(dictionary != NULL);
14877 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
14878 for (int i = 0; i < kNumFunctions; ++i) {
14879 Object* name_string;
14880 { MaybeObject* maybe_name_string =
14881 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
14882 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
14883 }
14884 NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
14885 { MaybeObject* maybe_dictionary = name_dictionary->Add(
14886 String::cast(name_string),
14887 Smi::FromInt(i),
14888 PropertyDetails(NONE, NORMAL, Representation::None()));
14889 if (!maybe_dictionary->ToObject(&dictionary)) {
14890 // Non-recoverable failure. Calling code must restart heap
14891 // initialization.
14892 return maybe_dictionary;
14893 }
14894 }
14895 }
14896 return dictionary;
14897 }
14898
14899
FunctionForName(Handle<String> name)14900 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
14901 Heap* heap = name->GetHeap();
14902 int entry = heap->intrinsic_function_names()->FindEntry(*name);
14903 if (entry != kNotFound) {
14904 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
14905 int function_index = Smi::cast(smi_index)->value();
14906 return &(kIntrinsicFunctions[function_index]);
14907 }
14908 return NULL;
14909 }
14910
14911
FunctionForId(Runtime::FunctionId id)14912 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
14913 return &(kIntrinsicFunctions[static_cast<int>(id)]);
14914 }
14915
14916
PerformGC(Object * result,Isolate * isolate)14917 void Runtime::PerformGC(Object* result, Isolate* isolate) {
14918 Failure* failure = Failure::cast(result);
14919 if (failure->IsRetryAfterGC()) {
14920 if (isolate->heap()->new_space()->AddFreshPage()) {
14921 return;
14922 }
14923
14924 // Try to do a garbage collection; ignore it if it fails. The C
14925 // entry stub will throw an out-of-memory exception in that case.
14926 isolate->heap()->CollectGarbage(failure->allocation_space(),
14927 "Runtime::PerformGC");
14928 } else {
14929 // Handle last resort GC and make sure to allow future allocations
14930 // to grow the heap without causing GCs (if possible).
14931 isolate->counters()->gc_last_resort_from_js()->Increment();
14932 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
14933 "Runtime::PerformGC");
14934 }
14935 }
14936
14937
14938 } } // namespace v8::internal
14939