1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdlib.h>
6#include <limits>
7
8#include "src/v8.h"
9
10#include "src/accessors.h"
11#include "src/allocation-site-scopes.h"
12#include "src/api.h"
13#include "src/arguments.h"
14#include "src/bailout-reason.h"
15#include "src/base/cpu.h"
16#include "src/base/platform/platform.h"
17#include "src/bootstrapper.h"
18#include "src/codegen.h"
19#include "src/compilation-cache.h"
20#include "src/compiler.h"
21#include "src/conversions.h"
22#include "src/cpu-profiler.h"
23#include "src/date.h"
24#include "src/dateparser-inl.h"
25#include "src/debug.h"
26#include "src/deoptimizer.h"
27#include "src/execution.h"
28#include "src/full-codegen.h"
29#include "src/global-handles.h"
30#include "src/isolate-inl.h"
31#include "src/json-parser.h"
32#include "src/json-stringifier.h"
33#include "src/jsregexp-inl.h"
34#include "src/jsregexp.h"
35#include "src/liveedit.h"
36#include "src/misc-intrinsics.h"
37#include "src/parser.h"
38#include "src/prototype.h"
39#include "src/runtime.h"
40#include "src/runtime-profiler.h"
41#include "src/scopeinfo.h"
42#include "src/smart-pointers.h"
43#include "src/string-search.h"
44#include "src/uri.h"
45#include "src/utils.h"
46#include "src/v8threads.h"
47#include "src/vm-state-inl.h"
48#include "third_party/fdlibm/fdlibm.h"
49
50#ifdef V8_I18N_SUPPORT
51#include "src/i18n.h"
52#include "unicode/brkiter.h"
53#include "unicode/calendar.h"
54#include "unicode/coll.h"
55#include "unicode/curramt.h"
56#include "unicode/datefmt.h"
57#include "unicode/dcfmtsym.h"
58#include "unicode/decimfmt.h"
59#include "unicode/dtfmtsym.h"
60#include "unicode/dtptngen.h"
61#include "unicode/locid.h"
62#include "unicode/numfmt.h"
63#include "unicode/numsys.h"
64#include "unicode/rbbi.h"
65#include "unicode/smpdtfmt.h"
66#include "unicode/timezone.h"
67#include "unicode/uchar.h"
68#include "unicode/ucol.h"
69#include "unicode/ucurr.h"
70#include "unicode/uloc.h"
71#include "unicode/unum.h"
72#include "unicode/uversion.h"
73#endif
74
75#ifndef _STLP_VENDOR_CSTD
76// STLPort doesn't import fpclassify and isless into the std namespace.
77using std::fpclassify;
78using std::isless;
79#endif
80
81namespace v8 {
82namespace internal {
83
84
85#define RUNTIME_ASSERT(value) \
86  if (!(value)) return isolate->ThrowIllegalOperation();
87
88#define RUNTIME_ASSERT_HANDLIFIED(value, T)                          \
89  if (!(value)) {                                                    \
90    isolate->ThrowIllegalOperation();                                \
91    return MaybeHandle<T>();                                         \
92  }
93
94// Cast the given object to a value of the specified type and store
95// it in a variable with the given name.  If the object is not of the
96// expected type call IllegalOperation and return.
97#define CONVERT_ARG_CHECKED(Type, name, index)                       \
98  RUNTIME_ASSERT(args[index]->Is##Type());                           \
99  Type* name = Type::cast(args[index]);
100
101#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index)                \
102  RUNTIME_ASSERT(args[index]->Is##Type());                           \
103  Handle<Type> name = args.at<Type>(index);
104
105#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index)               \
106  RUNTIME_ASSERT(args[index]->IsNumber());                           \
107  Handle<Object> name = args.at<Object>(index);
108
109// Cast the given object to a boolean and store it in a variable with
110// the given name.  If the object is not a boolean call IllegalOperation
111// and return.
112#define CONVERT_BOOLEAN_ARG_CHECKED(name, index)                     \
113  RUNTIME_ASSERT(args[index]->IsBoolean());                          \
114  bool name = args[index]->IsTrue();
115
116// Cast the given argument to a Smi and store its value in an int variable
117// with the given name.  If the argument is not a Smi call IllegalOperation
118// and return.
119#define CONVERT_SMI_ARG_CHECKED(name, index)                         \
120  RUNTIME_ASSERT(args[index]->IsSmi());                              \
121  int name = args.smi_at(index);
122
123// Cast the given argument to a double and store it in a variable with
124// the given name.  If the argument is not a number (as opposed to
125// the number not-a-number) call IllegalOperation and return.
126#define CONVERT_DOUBLE_ARG_CHECKED(name, index)                      \
127  RUNTIME_ASSERT(args[index]->IsNumber());                           \
128  double name = args.number_at(index);
129
130// Call the specified converter on the object *comand store the result in
131// a variable of the specified type with the given name.  If the
132// object is not a Number call IllegalOperation and return.
133#define CONVERT_NUMBER_CHECKED(type, name, Type, obj)                \
134  RUNTIME_ASSERT(obj->IsNumber());                                   \
135  type name = NumberTo##Type(obj);
136
137
138// Cast the given argument to PropertyDetails and store its value in a
139// variable with the given name.  If the argument is not a Smi call
140// IllegalOperation and return.
141#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index)                \
142  RUNTIME_ASSERT(args[index]->IsSmi());                              \
143  PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
144
145
146// Assert that the given argument has a valid value for a StrictMode
147// and store it in a StrictMode variable with the given name.
148#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index)                 \
149  RUNTIME_ASSERT(args[index]->IsSmi());                              \
150  RUNTIME_ASSERT(args.smi_at(index) == STRICT ||                     \
151                 args.smi_at(index) == SLOPPY);                      \
152  StrictMode name = static_cast<StrictMode>(args.smi_at(index));
153
154
155// Assert that the given argument is a number within the Int32 range
156// and convert it to int32_t.  If the argument is not an Int32 call
157// IllegalOperation and return.
158#define CONVERT_INT32_ARG_CHECKED(name, index)                       \
159  RUNTIME_ASSERT(args[index]->IsNumber());                           \
160  int32_t name = 0;                                                  \
161  RUNTIME_ASSERT(args[index]->ToInt32(&name));
162
163
164static Handle<Map> ComputeObjectLiteralMap(
165    Handle<Context> context,
166    Handle<FixedArray> constant_properties,
167    bool* is_result_from_cache) {
168  Isolate* isolate = context->GetIsolate();
169  int properties_length = constant_properties->length();
170  int number_of_properties = properties_length / 2;
171  // Check that there are only internal strings and array indices among keys.
172  int number_of_string_keys = 0;
173  for (int p = 0; p != properties_length; p += 2) {
174    Object* key = constant_properties->get(p);
175    uint32_t element_index = 0;
176    if (key->IsInternalizedString()) {
177      number_of_string_keys++;
178    } else if (key->ToArrayIndex(&element_index)) {
179      // An index key does not require space in the property backing store.
180      number_of_properties--;
181    } else {
182      // Bail out as a non-internalized-string non-index key makes caching
183      // impossible.
184      // DCHECK to make sure that the if condition after the loop is false.
185      DCHECK(number_of_string_keys != number_of_properties);
186      break;
187    }
188  }
189  // If we only have internalized strings and array indices among keys then we
190  // can use the map cache in the native context.
191  const int kMaxKeys = 10;
192  if ((number_of_string_keys == number_of_properties) &&
193      (number_of_string_keys < kMaxKeys)) {
194    // Create the fixed array with the key.
195    Handle<FixedArray> keys =
196        isolate->factory()->NewFixedArray(number_of_string_keys);
197    if (number_of_string_keys > 0) {
198      int index = 0;
199      for (int p = 0; p < properties_length; p += 2) {
200        Object* key = constant_properties->get(p);
201        if (key->IsInternalizedString()) {
202          keys->set(index++, key);
203        }
204      }
205      DCHECK(index == number_of_string_keys);
206    }
207    *is_result_from_cache = true;
208    return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
209  }
210  *is_result_from_cache = false;
211  return Map::Create(isolate, number_of_properties);
212}
213
214
215MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
216    Isolate* isolate,
217    Handle<FixedArray> literals,
218    Handle<FixedArray> constant_properties);
219
220
221MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
222    Isolate* isolate,
223    Handle<FixedArray> literals,
224    Handle<FixedArray> constant_properties,
225    bool should_have_fast_elements,
226    bool has_function_literal) {
227  // Get the native context from the literals array.  This is the
228  // context in which the function was created and we use the object
229  // function from this context to create the object literal.  We do
230  // not use the object function from the current native context
231  // because this might be the object function from another context
232  // which we should not have access to.
233  Handle<Context> context =
234      Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
235
236  // In case we have function literals, we want the object to be in
237  // slow properties mode for now. We don't go in the map cache because
238  // maps with constant functions can't be shared if the functions are
239  // not the same (which is the common case).
240  bool is_result_from_cache = false;
241  Handle<Map> map = has_function_literal
242      ? Handle<Map>(context->object_function()->initial_map())
243      : ComputeObjectLiteralMap(context,
244                                constant_properties,
245                                &is_result_from_cache);
246
247  PretenureFlag pretenure_flag =
248      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
249
250  Handle<JSObject> boilerplate =
251      isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
252
253  // Normalize the elements of the boilerplate to save space if needed.
254  if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
255
256  // Add the constant properties to the boilerplate.
257  int length = constant_properties->length();
258  bool should_transform =
259      !is_result_from_cache && boilerplate->HasFastProperties();
260  bool should_normalize = should_transform || has_function_literal;
261  if (should_normalize) {
262    // TODO(verwaest): We might not want to ever normalize here.
263    JSObject::NormalizeProperties(
264        boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
265  }
266  // TODO(verwaest): Support tracking representations in the boilerplate.
267  for (int index = 0; index < length; index +=2) {
268    Handle<Object> key(constant_properties->get(index+0), isolate);
269    Handle<Object> value(constant_properties->get(index+1), isolate);
270    if (value->IsFixedArray()) {
271      // The value contains the constant_properties of a
272      // simple object or array literal.
273      Handle<FixedArray> array = Handle<FixedArray>::cast(value);
274      ASSIGN_RETURN_ON_EXCEPTION(
275          isolate, value,
276          CreateLiteralBoilerplate(isolate, literals, array),
277          Object);
278    }
279    MaybeHandle<Object> maybe_result;
280    uint32_t element_index = 0;
281    if (key->IsInternalizedString()) {
282      if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
283        // Array index as string (uint32).
284        if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
285        maybe_result =
286            JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
287      } else {
288        Handle<String> name(String::cast(*key));
289        DCHECK(!name->AsArrayIndex(&element_index));
290        maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(
291            boilerplate, name, value, NONE);
292      }
293    } else if (key->ToArrayIndex(&element_index)) {
294      // Array index (uint32).
295      if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
296      maybe_result =
297          JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
298    } else {
299      // Non-uint32 number.
300      DCHECK(key->IsNumber());
301      double num = key->Number();
302      char arr[100];
303      Vector<char> buffer(arr, arraysize(arr));
304      const char* str = DoubleToCString(num, buffer);
305      Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str);
306      maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name,
307                                                              value, NONE);
308    }
309    // If setting the property on the boilerplate throws an
310    // exception, the exception is converted to an empty handle in
311    // the handle based operations.  In that case, we need to
312    // convert back to an exception.
313    RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
314  }
315
316  // Transform to fast properties if necessary. For object literals with
317  // containing function literals we defer this operation until after all
318  // computed properties have been assigned so that we can generate
319  // constant function properties.
320  if (should_transform && !has_function_literal) {
321    JSObject::MigrateSlowToFast(
322        boilerplate, boilerplate->map()->unused_property_fields());
323  }
324
325  return boilerplate;
326}
327
328
329MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
330    Handle<Object> object,
331    ElementsKind to_kind,
332    Isolate* isolate) {
333  HandleScope scope(isolate);
334  if (!object->IsJSObject()) {
335    isolate->ThrowIllegalOperation();
336    return MaybeHandle<Object>();
337  }
338  ElementsKind from_kind =
339      Handle<JSObject>::cast(object)->map()->elements_kind();
340  if (Map::IsValidElementsTransition(from_kind, to_kind)) {
341    JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
342    return object;
343  }
344  isolate->ThrowIllegalOperation();
345  return MaybeHandle<Object>();
346}
347
348
349MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
350    Isolate* isolate,
351    Handle<FixedArray> literals,
352    Handle<FixedArray> elements) {
353  // Create the JSArray.
354  Handle<JSFunction> constructor(
355      JSFunction::NativeContextFromLiterals(*literals)->array_function());
356
357  PretenureFlag pretenure_flag =
358      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
359
360  Handle<JSArray> object = Handle<JSArray>::cast(
361      isolate->factory()->NewJSObject(constructor, pretenure_flag));
362
363  ElementsKind constant_elements_kind =
364      static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
365  Handle<FixedArrayBase> constant_elements_values(
366      FixedArrayBase::cast(elements->get(1)));
367
368  { DisallowHeapAllocation no_gc;
369    DCHECK(IsFastElementsKind(constant_elements_kind));
370    Context* native_context = isolate->context()->native_context();
371    Object* maps_array = native_context->js_array_maps();
372    DCHECK(!maps_array->IsUndefined());
373    Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind);
374    object->set_map(Map::cast(map));
375  }
376
377  Handle<FixedArrayBase> copied_elements_values;
378  if (IsFastDoubleElementsKind(constant_elements_kind)) {
379    copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
380        Handle<FixedDoubleArray>::cast(constant_elements_values));
381  } else {
382    DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind));
383    const bool is_cow =
384        (constant_elements_values->map() ==
385         isolate->heap()->fixed_cow_array_map());
386    if (is_cow) {
387      copied_elements_values = constant_elements_values;
388#if DEBUG
389      Handle<FixedArray> fixed_array_values =
390          Handle<FixedArray>::cast(copied_elements_values);
391      for (int i = 0; i < fixed_array_values->length(); i++) {
392        DCHECK(!fixed_array_values->get(i)->IsFixedArray());
393      }
394#endif
395    } else {
396      Handle<FixedArray> fixed_array_values =
397          Handle<FixedArray>::cast(constant_elements_values);
398      Handle<FixedArray> fixed_array_values_copy =
399          isolate->factory()->CopyFixedArray(fixed_array_values);
400      copied_elements_values = fixed_array_values_copy;
401      for (int i = 0; i < fixed_array_values->length(); i++) {
402        if (fixed_array_values->get(i)->IsFixedArray()) {
403          // The value contains the constant_properties of a
404          // simple object or array literal.
405          Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
406          Handle<Object> result;
407          ASSIGN_RETURN_ON_EXCEPTION(
408              isolate, result,
409              CreateLiteralBoilerplate(isolate, literals, fa),
410              Object);
411          fixed_array_values_copy->set(i, *result);
412        }
413      }
414    }
415  }
416  object->set_elements(*copied_elements_values);
417  object->set_length(Smi::FromInt(copied_elements_values->length()));
418
419  JSObject::ValidateElements(object);
420  return object;
421}
422
423
424MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
425    Isolate* isolate,
426    Handle<FixedArray> literals,
427    Handle<FixedArray> array) {
428  Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
429  const bool kHasNoFunctionLiteral = false;
430  switch (CompileTimeValue::GetLiteralType(array)) {
431    case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
432      return CreateObjectLiteralBoilerplate(isolate,
433                                            literals,
434                                            elements,
435                                            true,
436                                            kHasNoFunctionLiteral);
437    case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
438      return CreateObjectLiteralBoilerplate(isolate,
439                                            literals,
440                                            elements,
441                                            false,
442                                            kHasNoFunctionLiteral);
443    case CompileTimeValue::ARRAY_LITERAL:
444      return Runtime::CreateArrayLiteralBoilerplate(
445          isolate, literals, elements);
446    default:
447      UNREACHABLE();
448      return MaybeHandle<Object>();
449  }
450}
451
452
453RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
454  HandleScope scope(isolate);
455  DCHECK(args.length() == 4);
456  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
457  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
458  CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
459  CONVERT_SMI_ARG_CHECKED(flags, 3);
460  bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
461  bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
462
463  RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
464
465  // Check if boilerplate exists. If not, create it first.
466  Handle<Object> literal_site(literals->get(literals_index), isolate);
467  Handle<AllocationSite> site;
468  Handle<JSObject> boilerplate;
469  if (*literal_site == isolate->heap()->undefined_value()) {
470    Handle<Object> raw_boilerplate;
471    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
472        isolate, raw_boilerplate,
473        CreateObjectLiteralBoilerplate(
474            isolate,
475            literals,
476            constant_properties,
477            should_have_fast_elements,
478            has_function_literal));
479    boilerplate = Handle<JSObject>::cast(raw_boilerplate);
480
481    AllocationSiteCreationContext creation_context(isolate);
482    site = creation_context.EnterNewScope();
483    RETURN_FAILURE_ON_EXCEPTION(
484        isolate,
485        JSObject::DeepWalk(boilerplate, &creation_context));
486    creation_context.ExitScope(site, boilerplate);
487
488    // Update the functions literal and return the boilerplate.
489    literals->set(literals_index, *site);
490  } else {
491    site = Handle<AllocationSite>::cast(literal_site);
492    boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
493                                   isolate);
494  }
495
496  AllocationSiteUsageContext usage_context(isolate, site, true);
497  usage_context.EnterNewScope();
498  MaybeHandle<Object> maybe_copy = JSObject::DeepCopy(
499      boilerplate, &usage_context);
500  usage_context.ExitScope(site, boilerplate);
501  Handle<Object> copy;
502  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy);
503  return *copy;
504}
505
506
507MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
508    Isolate* isolate,
509    Handle<FixedArray> literals,
510    int literals_index,
511    Handle<FixedArray> elements) {
512  // Check if boilerplate exists. If not, create it first.
513  Handle<Object> literal_site(literals->get(literals_index), isolate);
514  Handle<AllocationSite> site;
515  if (*literal_site == isolate->heap()->undefined_value()) {
516    DCHECK(*elements != isolate->heap()->empty_fixed_array());
517    Handle<Object> boilerplate;
518    ASSIGN_RETURN_ON_EXCEPTION(
519        isolate, boilerplate,
520        Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements),
521        AllocationSite);
522
523    AllocationSiteCreationContext creation_context(isolate);
524    site = creation_context.EnterNewScope();
525    if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
526                           &creation_context).is_null()) {
527      return Handle<AllocationSite>::null();
528    }
529    creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
530
531    literals->set(literals_index, *site);
532  } else {
533    site = Handle<AllocationSite>::cast(literal_site);
534  }
535
536  return site;
537}
538
539
540static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate,
541                                           Handle<FixedArray> literals,
542                                           int literals_index,
543                                           Handle<FixedArray> elements,
544                                           int flags) {
545  RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 &&
546                            literals_index < literals->length(), JSObject);
547  Handle<AllocationSite> site;
548  ASSIGN_RETURN_ON_EXCEPTION(
549      isolate, site,
550      GetLiteralAllocationSite(isolate, literals, literals_index, elements),
551      JSObject);
552
553  bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
554  Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
555  AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
556  usage_context.EnterNewScope();
557  JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
558                                      ? JSObject::kNoHints
559                                      : JSObject::kObjectIsShallow;
560  MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
561                                                  hints);
562  usage_context.ExitScope(site, boilerplate);
563  return copy;
564}
565
566
567RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
568  HandleScope scope(isolate);
569  DCHECK(args.length() == 4);
570  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
571  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
572  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
573  CONVERT_SMI_ARG_CHECKED(flags, 3);
574
575  Handle<JSObject> result;
576  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
577      CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
578                             flags));
579  return *result;
580}
581
582
583RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) {
584  HandleScope scope(isolate);
585  DCHECK(args.length() == 3);
586  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
587  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
588  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
589
590  Handle<JSObject> result;
591  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
592     CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
593                            ArrayLiteral::kShallowElements));
594  return *result;
595}
596
597
598RUNTIME_FUNCTION(Runtime_CreateSymbol) {
599  HandleScope scope(isolate);
600  DCHECK(args.length() == 1);
601  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
602  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
603  Handle<Symbol> symbol = isolate->factory()->NewSymbol();
604  if (name->IsString()) symbol->set_name(*name);
605  return *symbol;
606}
607
608
609RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) {
610  HandleScope scope(isolate);
611  DCHECK(args.length() == 1);
612  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
613  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
614  Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol();
615  if (name->IsString()) symbol->set_name(*name);
616  return *symbol;
617}
618
619
620RUNTIME_FUNCTION(Runtime_CreatePrivateOwnSymbol) {
621  HandleScope scope(isolate);
622  DCHECK(args.length() == 1);
623  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
624  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
625  Handle<Symbol> symbol = isolate->factory()->NewPrivateOwnSymbol();
626  if (name->IsString()) symbol->set_name(*name);
627  return *symbol;
628}
629
630
631RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateOwnSymbol) {
632  HandleScope scope(isolate);
633  DCHECK(args.length() == 1);
634  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
635  Handle<JSObject> registry = isolate->GetSymbolRegistry();
636  Handle<String> part = isolate->factory()->private_intern_string();
637  Handle<Object> privates;
638  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
639      isolate, privates, Object::GetPropertyOrElement(registry, part));
640  Handle<Object> symbol;
641  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
642      isolate, symbol, Object::GetPropertyOrElement(privates, name));
643  if (!symbol->IsSymbol()) {
644    DCHECK(symbol->IsUndefined());
645    symbol = isolate->factory()->NewPrivateSymbol();
646    Handle<Symbol>::cast(symbol)->set_name(*name);
647    Handle<Symbol>::cast(symbol)->set_is_own(true);
648    JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol,
649                          STRICT).Assert();
650  }
651  return *symbol;
652}
653
654
655RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
656  HandleScope scope(isolate);
657  DCHECK(args.length() == 1);
658  CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
659  return *Object::ToObject(isolate, symbol).ToHandleChecked();
660}
661
662
663RUNTIME_FUNCTION(Runtime_SymbolDescription) {
664  SealHandleScope shs(isolate);
665  DCHECK(args.length() == 1);
666  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
667  return symbol->name();
668}
669
670
671RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
672  HandleScope scope(isolate);
673  DCHECK(args.length() == 0);
674  return *isolate->GetSymbolRegistry();
675}
676
677
678RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) {
679  SealHandleScope shs(isolate);
680  DCHECK(args.length() == 1);
681  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
682  return isolate->heap()->ToBoolean(symbol->is_private());
683}
684
685
686RUNTIME_FUNCTION(Runtime_CreateJSProxy) {
687  HandleScope scope(isolate);
688  DCHECK(args.length() == 2);
689  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
690  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
691  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
692  return *isolate->factory()->NewJSProxy(handler, prototype);
693}
694
695
696RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
697  HandleScope scope(isolate);
698  DCHECK(args.length() == 4);
699  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
700  CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1);
701  RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
702  CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2);
703  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3);
704  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
705  return *isolate->factory()->NewJSFunctionProxy(
706      handler, call_trap, construct_trap, prototype);
707}
708
709
710RUNTIME_FUNCTION(Runtime_IsJSProxy) {
711  SealHandleScope shs(isolate);
712  DCHECK(args.length() == 1);
713  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
714  return isolate->heap()->ToBoolean(obj->IsJSProxy());
715}
716
717
718RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) {
719  SealHandleScope shs(isolate);
720  DCHECK(args.length() == 1);
721  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
722  return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
723}
724
725
726RUNTIME_FUNCTION(Runtime_GetHandler) {
727  SealHandleScope shs(isolate);
728  DCHECK(args.length() == 1);
729  CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
730  return proxy->handler();
731}
732
733
734RUNTIME_FUNCTION(Runtime_GetCallTrap) {
735  SealHandleScope shs(isolate);
736  DCHECK(args.length() == 1);
737  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
738  return proxy->call_trap();
739}
740
741
742RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
743  SealHandleScope shs(isolate);
744  DCHECK(args.length() == 1);
745  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
746  return proxy->construct_trap();
747}
748
749
750RUNTIME_FUNCTION(Runtime_Fix) {
751  HandleScope scope(isolate);
752  DCHECK(args.length() == 1);
753  CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
754  JSProxy::Fix(proxy);
755  return isolate->heap()->undefined_value();
756}
757
758
759void Runtime::FreeArrayBuffer(Isolate* isolate,
760                              JSArrayBuffer* phantom_array_buffer) {
761  if (phantom_array_buffer->should_be_freed()) {
762    DCHECK(phantom_array_buffer->is_external());
763    free(phantom_array_buffer->backing_store());
764  }
765  if (phantom_array_buffer->is_external()) return;
766
767  size_t allocated_length = NumberToSize(
768      isolate, phantom_array_buffer->byte_length());
769
770  reinterpret_cast<v8::Isolate*>(isolate)
771      ->AdjustAmountOfExternalAllocatedMemory(
772          -static_cast<int64_t>(allocated_length));
773  CHECK(V8::ArrayBufferAllocator() != NULL);
774  V8::ArrayBufferAllocator()->Free(
775      phantom_array_buffer->backing_store(),
776      allocated_length);
777}
778
779
780void Runtime::SetupArrayBuffer(Isolate* isolate,
781                               Handle<JSArrayBuffer> array_buffer,
782                               bool is_external,
783                               void* data,
784                               size_t allocated_length) {
785  DCHECK(array_buffer->GetInternalFieldCount() ==
786      v8::ArrayBuffer::kInternalFieldCount);
787  for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
788    array_buffer->SetInternalField(i, Smi::FromInt(0));
789  }
790  array_buffer->set_backing_store(data);
791  array_buffer->set_flag(Smi::FromInt(0));
792  array_buffer->set_is_external(is_external);
793
794  Handle<Object> byte_length =
795      isolate->factory()->NewNumberFromSize(allocated_length);
796  CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
797  array_buffer->set_byte_length(*byte_length);
798
799  array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
800  isolate->heap()->set_array_buffers_list(*array_buffer);
801  array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
802}
803
804
805bool Runtime::SetupArrayBufferAllocatingData(
806    Isolate* isolate,
807    Handle<JSArrayBuffer> array_buffer,
808    size_t allocated_length,
809    bool initialize) {
810  void* data;
811  CHECK(V8::ArrayBufferAllocator() != NULL);
812  if (allocated_length != 0) {
813    if (initialize) {
814      data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
815    } else {
816      data =
817          V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
818    }
819    if (data == NULL) return false;
820  } else {
821    data = NULL;
822  }
823
824  SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
825
826  reinterpret_cast<v8::Isolate*>(isolate)
827      ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
828
829  return true;
830}
831
832
833void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
834  Isolate* isolate = array_buffer->GetIsolate();
835  for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
836       !view_obj->IsUndefined();) {
837    Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
838    if (view->IsJSTypedArray()) {
839      JSTypedArray::cast(*view)->Neuter();
840    } else if (view->IsJSDataView()) {
841      JSDataView::cast(*view)->Neuter();
842    } else {
843      UNREACHABLE();
844    }
845    view_obj = handle(view->weak_next(), isolate);
846  }
847  array_buffer->Neuter();
848}
849
850
851RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
852  HandleScope scope(isolate);
853  DCHECK(args.length() == 2);
854  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
855  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
856  if (!holder->byte_length()->IsUndefined()) {
857    // ArrayBuffer is already initialized; probably a fuzz test.
858    return *holder;
859  }
860  size_t allocated_length = 0;
861  if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
862    THROW_NEW_ERROR_RETURN_FAILURE(
863        isolate, NewRangeError("invalid_array_buffer_length",
864                               HandleVector<Object>(NULL, 0)));
865  }
866  if (!Runtime::SetupArrayBufferAllocatingData(isolate,
867                                               holder, allocated_length)) {
868    THROW_NEW_ERROR_RETURN_FAILURE(
869        isolate, NewRangeError("invalid_array_buffer_length",
870                               HandleVector<Object>(NULL, 0)));
871  }
872  return *holder;
873}
874
875
876RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
877  SealHandleScope shs(isolate);
878  DCHECK(args.length() == 1);
879  CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
880  return holder->byte_length();
881}
882
883
884RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
885  HandleScope scope(isolate);
886  DCHECK(args.length() == 3);
887  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
888  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
889  CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
890  RUNTIME_ASSERT(!source.is_identical_to(target));
891  size_t start = 0;
892  RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
893  size_t target_length = NumberToSize(isolate, target->byte_length());
894
895  if (target_length == 0) return isolate->heap()->undefined_value();
896
897  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
898  RUNTIME_ASSERT(start <= source_byte_length);
899  RUNTIME_ASSERT(source_byte_length - start >= target_length);
900  uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
901  uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
902  CopyBytes(target_data, source_data + start, target_length);
903  return isolate->heap()->undefined_value();
904}
905
906
907RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
908  HandleScope scope(isolate);
909  DCHECK(args.length() == 1);
910  CONVERT_ARG_CHECKED(Object, object, 0);
911  return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
912}
913
914
915RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
916  HandleScope scope(isolate);
917  DCHECK(args.length() == 1);
918  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
919  if (array_buffer->backing_store() == NULL) {
920    CHECK(Smi::FromInt(0) == array_buffer->byte_length());
921    return isolate->heap()->undefined_value();
922  }
923  DCHECK(!array_buffer->is_external());
924  void* backing_store = array_buffer->backing_store();
925  size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
926  array_buffer->set_is_external(true);
927  Runtime::NeuterArrayBuffer(array_buffer);
928  V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
929  return isolate->heap()->undefined_value();
930}
931
932
933void Runtime::ArrayIdToTypeAndSize(
934    int arrayId,
935    ExternalArrayType* array_type,
936    ElementsKind* external_elements_kind,
937    ElementsKind* fixed_elements_kind,
938    size_t* element_size) {
939  switch (arrayId) {
940#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)                           \
941    case ARRAY_ID_##TYPE:                                                      \
942      *array_type = kExternal##Type##Array;                                    \
943      *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS;                    \
944      *fixed_elements_kind = TYPE##_ELEMENTS;                                  \
945      *element_size = size;                                                    \
946      break;
947
948    TYPED_ARRAYS(ARRAY_ID_CASE)
949#undef ARRAY_ID_CASE
950
951    default:
952      UNREACHABLE();
953  }
954}
955
956
957RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
958  HandleScope scope(isolate);
959  DCHECK(args.length() == 5);
960  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
961  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
962  CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
963  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
964  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
965
966  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
967                 arrayId <= Runtime::ARRAY_ID_LAST);
968
969  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
970  size_t element_size = 1;  // Bogus initialization.
971  ElementsKind external_elements_kind =
972      EXTERNAL_INT8_ELEMENTS;  // Bogus initialization.
973  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
974  Runtime::ArrayIdToTypeAndSize(arrayId,
975      &array_type,
976      &external_elements_kind,
977      &fixed_elements_kind,
978      &element_size);
979  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
980
981  size_t byte_offset = 0;
982  size_t byte_length = 0;
983  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
984  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
985
986  if (maybe_buffer->IsJSArrayBuffer()) {
987    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
988    size_t array_buffer_byte_length =
989        NumberToSize(isolate, buffer->byte_length());
990    RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
991    RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
992  } else {
993    RUNTIME_ASSERT(maybe_buffer->IsNull());
994  }
995
996  RUNTIME_ASSERT(byte_length % element_size == 0);
997  size_t length = byte_length / element_size;
998
999  if (length > static_cast<unsigned>(Smi::kMaxValue)) {
1000    THROW_NEW_ERROR_RETURN_FAILURE(
1001        isolate, NewRangeError("invalid_typed_array_length",
1002                               HandleVector<Object>(NULL, 0)));
1003  }
1004
1005  // All checks are done, now we can modify objects.
1006
1007  DCHECK(holder->GetInternalFieldCount() ==
1008      v8::ArrayBufferView::kInternalFieldCount);
1009  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1010    holder->SetInternalField(i, Smi::FromInt(0));
1011  }
1012  Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
1013  holder->set_length(*length_obj);
1014  holder->set_byte_offset(*byte_offset_object);
1015  holder->set_byte_length(*byte_length_object);
1016
1017  if (!maybe_buffer->IsNull()) {
1018    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
1019    holder->set_buffer(*buffer);
1020    holder->set_weak_next(buffer->weak_first_view());
1021    buffer->set_weak_first_view(*holder);
1022
1023    Handle<ExternalArray> elements =
1024        isolate->factory()->NewExternalArray(
1025            static_cast<int>(length), array_type,
1026            static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
1027    Handle<Map> map =
1028        JSObject::GetElementsTransitionMap(holder, external_elements_kind);
1029    JSObject::SetMapAndElements(holder, map, elements);
1030    DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
1031  } else {
1032    holder->set_buffer(Smi::FromInt(0));
1033    holder->set_weak_next(isolate->heap()->undefined_value());
1034    Handle<FixedTypedArrayBase> elements =
1035        isolate->factory()->NewFixedTypedArray(
1036            static_cast<int>(length), array_type);
1037    holder->set_elements(*elements);
1038  }
1039  return isolate->heap()->undefined_value();
1040}
1041
1042
1043// Initializes a typed array from an array-like object.
1044// If an array-like object happens to be a typed array of the same type,
1045// initializes backing store using memove.
1046//
1047// Returns true if backing store was initialized or false otherwise.
1048RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
1049  HandleScope scope(isolate);
1050  DCHECK(args.length() == 4);
1051  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
1052  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
1053  CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
1054  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
1055
1056  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
1057                 arrayId <= Runtime::ARRAY_ID_LAST);
1058
1059  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
1060  size_t element_size = 1;  // Bogus initialization.
1061  ElementsKind external_elements_kind =
1062      EXTERNAL_INT8_ELEMENTS;  // Bogus intialization.
1063  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
1064  Runtime::ArrayIdToTypeAndSize(arrayId,
1065      &array_type,
1066      &external_elements_kind,
1067      &fixed_elements_kind,
1068      &element_size);
1069
1070  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
1071
1072  Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
1073  if (source->IsJSTypedArray() &&
1074      JSTypedArray::cast(*source)->type() == array_type) {
1075    length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
1076  }
1077  size_t length = 0;
1078  RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
1079
1080  if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
1081      (length > (kMaxInt / element_size))) {
1082    THROW_NEW_ERROR_RETURN_FAILURE(
1083        isolate, NewRangeError("invalid_typed_array_length",
1084                               HandleVector<Object>(NULL, 0)));
1085  }
1086  size_t byte_length = length * element_size;
1087
1088  DCHECK(holder->GetInternalFieldCount() ==
1089      v8::ArrayBufferView::kInternalFieldCount);
1090  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1091    holder->SetInternalField(i, Smi::FromInt(0));
1092  }
1093
1094  // NOTE: not initializing backing store.
1095  // We assume that the caller of this function will initialize holder
1096  // with the loop
1097  //      for(i = 0; i < length; i++) { holder[i] = source[i]; }
1098  // We assume that the caller of this function is always a typed array
1099  // constructor.
1100  // If source is a typed array, this loop will always run to completion,
1101  // so we are sure that the backing store will be initialized.
1102  // Otherwise, the indexing operation might throw, so the loop will not
1103  // run to completion and the typed array might remain partly initialized.
1104  // However we further assume that the caller of this function is a typed array
1105  // constructor, and the exception will propagate out of the constructor,
1106  // therefore uninitialized memory will not be accessible by a user program.
1107  //
1108  // TODO(dslomov): revise this once we support subclassing.
1109
1110  if (!Runtime::SetupArrayBufferAllocatingData(
1111        isolate, buffer, byte_length, false)) {
1112    THROW_NEW_ERROR_RETURN_FAILURE(
1113        isolate, NewRangeError("invalid_array_buffer_length",
1114                               HandleVector<Object>(NULL, 0)));
1115  }
1116
1117  holder->set_buffer(*buffer);
1118  holder->set_byte_offset(Smi::FromInt(0));
1119  Handle<Object> byte_length_obj(
1120      isolate->factory()->NewNumberFromSize(byte_length));
1121  holder->set_byte_length(*byte_length_obj);
1122  holder->set_length(*length_obj);
1123  holder->set_weak_next(buffer->weak_first_view());
1124  buffer->set_weak_first_view(*holder);
1125
1126  Handle<ExternalArray> elements =
1127      isolate->factory()->NewExternalArray(
1128          static_cast<int>(length), array_type,
1129          static_cast<uint8_t*>(buffer->backing_store()));
1130  Handle<Map> map = JSObject::GetElementsTransitionMap(
1131      holder, external_elements_kind);
1132  JSObject::SetMapAndElements(holder, map, elements);
1133
1134  if (source->IsJSTypedArray()) {
1135    Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1136
1137    if (typed_array->type() == holder->type()) {
1138      uint8_t* backing_store =
1139        static_cast<uint8_t*>(
1140          typed_array->GetBuffer()->backing_store());
1141      size_t source_byte_offset =
1142          NumberToSize(isolate, typed_array->byte_offset());
1143      memcpy(
1144          buffer->backing_store(),
1145          backing_store + source_byte_offset,
1146          byte_length);
1147      return isolate->heap()->true_value();
1148    }
1149  }
1150
1151  return isolate->heap()->false_value();
1152}
1153
1154
1155#define BUFFER_VIEW_GETTER(Type, getter, accessor) \
1156  RUNTIME_FUNCTION(Runtime_##Type##Get##getter) {                    \
1157    HandleScope scope(isolate);                                               \
1158    DCHECK(args.length() == 1);                                               \
1159    CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0);                          \
1160    return holder->accessor();                                                \
1161  }
1162
1163BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
1164BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
1165BUFFER_VIEW_GETTER(TypedArray, Length, length)
1166BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
1167
1168#undef BUFFER_VIEW_GETTER
1169
1170RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
1171  HandleScope scope(isolate);
1172  DCHECK(args.length() == 1);
1173  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
1174  return *holder->GetBuffer();
1175}
1176
1177
1178// Return codes for Runtime_TypedArraySetFastCases.
1179// Should be synchronized with typedarray.js natives.
1180enum TypedArraySetResultCodes {
1181  // Set from typed array of the same type.
1182  // This is processed by TypedArraySetFastCases
1183  TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1184  // Set from typed array of the different type, overlapping in memory.
1185  TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1186  // Set from typed array of the different type, non-overlapping.
1187  TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1188  // Set from non-typed array.
1189  TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1190};
1191
1192
1193RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
1194  HandleScope scope(isolate);
1195  DCHECK(args.length() == 3);
1196  if (!args[0]->IsJSTypedArray()) {
1197    THROW_NEW_ERROR_RETURN_FAILURE(
1198        isolate,
1199        NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
1200  }
1201
1202  if (!args[1]->IsJSTypedArray())
1203    return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
1204
1205  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
1206  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
1207  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
1208
1209  Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1210  Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1211  size_t offset = 0;
1212  RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
1213  size_t target_length = NumberToSize(isolate, target->length());
1214  size_t source_length = NumberToSize(isolate, source->length());
1215  size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1216  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1217  if (offset > target_length || offset + source_length > target_length ||
1218      offset + source_length < offset) {  // overflow
1219    THROW_NEW_ERROR_RETURN_FAILURE(
1220        isolate, NewRangeError("typed_array_set_source_too_large",
1221                               HandleVector<Object>(NULL, 0)));
1222  }
1223
1224  size_t target_offset = NumberToSize(isolate, target->byte_offset());
1225  size_t source_offset = NumberToSize(isolate, source->byte_offset());
1226  uint8_t* target_base =
1227      static_cast<uint8_t*>(
1228        target->GetBuffer()->backing_store()) + target_offset;
1229  uint8_t* source_base =
1230      static_cast<uint8_t*>(
1231        source->GetBuffer()->backing_store()) + source_offset;
1232
1233  // Typed arrays of the same type: use memmove.
1234  if (target->type() == source->type()) {
1235    memmove(target_base + offset * target->element_size(),
1236        source_base, source_byte_length);
1237    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
1238  }
1239
1240  // Typed arrays of different types over the same backing store
1241  if ((source_base <= target_base &&
1242        source_base + source_byte_length > target_base) ||
1243      (target_base <= source_base &&
1244        target_base + target_byte_length > source_base)) {
1245    // We do not support overlapping ArrayBuffers
1246    DCHECK(
1247      target->GetBuffer()->backing_store() ==
1248      source->GetBuffer()->backing_store());
1249    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
1250  } else {  // Non-overlapping typed arrays
1251    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
1252  }
1253}
1254
1255
1256RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
1257  DCHECK(args.length() == 0);
1258  DCHECK_OBJECT_SIZE(
1259      FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset);
1260  return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
1261}
1262
1263
1264RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
1265  HandleScope scope(isolate);
1266  DCHECK(args.length() == 4);
1267  CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1268  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1269  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
1270  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
1271
1272  DCHECK(holder->GetInternalFieldCount() ==
1273      v8::ArrayBufferView::kInternalFieldCount);
1274  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1275    holder->SetInternalField(i, Smi::FromInt(0));
1276  }
1277  size_t buffer_length = 0;
1278  size_t offset = 0;
1279  size_t length = 0;
1280  RUNTIME_ASSERT(
1281      TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
1282  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
1283  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
1284
1285  // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
1286  // Entire range [offset, offset + length] must be in bounds.
1287  RUNTIME_ASSERT(offset <= buffer_length);
1288  RUNTIME_ASSERT(offset + length <= buffer_length);
1289  // No overflow.
1290  RUNTIME_ASSERT(offset + length >= offset);
1291
1292  holder->set_buffer(*buffer);
1293  holder->set_byte_offset(*byte_offset);
1294  holder->set_byte_length(*byte_length);
1295
1296  holder->set_weak_next(buffer->weak_first_view());
1297  buffer->set_weak_first_view(*holder);
1298
1299  return isolate->heap()->undefined_value();
1300}
1301
1302
1303inline static bool NeedToFlipBytes(bool is_little_endian) {
1304#ifdef V8_TARGET_LITTLE_ENDIAN
1305  return !is_little_endian;
1306#else
1307  return is_little_endian;
1308#endif
1309}
1310
1311
1312template<int n>
1313inline void CopyBytes(uint8_t* target, uint8_t* source) {
1314  for (int i = 0; i < n; i++) {
1315    *(target++) = *(source++);
1316  }
1317}
1318
1319
1320template<int n>
1321inline void FlipBytes(uint8_t* target, uint8_t* source) {
1322  source = source + (n-1);
1323  for (int i = 0; i < n; i++) {
1324    *(target++) = *(source--);
1325  }
1326}
1327
1328
1329template<typename T>
1330inline static bool DataViewGetValue(
1331    Isolate* isolate,
1332    Handle<JSDataView> data_view,
1333    Handle<Object> byte_offset_obj,
1334    bool is_little_endian,
1335    T* result) {
1336  size_t byte_offset = 0;
1337  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1338    return false;
1339  }
1340  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1341
1342  size_t data_view_byte_offset =
1343      NumberToSize(isolate, data_view->byte_offset());
1344  size_t data_view_byte_length =
1345      NumberToSize(isolate, data_view->byte_length());
1346  if (byte_offset + sizeof(T) > data_view_byte_length ||
1347      byte_offset + sizeof(T) < byte_offset)  {  // overflow
1348    return false;
1349  }
1350
1351  union Value {
1352    T data;
1353    uint8_t bytes[sizeof(T)];
1354  };
1355
1356  Value value;
1357  size_t buffer_offset = data_view_byte_offset + byte_offset;
1358  DCHECK(
1359      NumberToSize(isolate, buffer->byte_length())
1360      >= buffer_offset + sizeof(T));
1361  uint8_t* source =
1362        static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1363  if (NeedToFlipBytes(is_little_endian)) {
1364    FlipBytes<sizeof(T)>(value.bytes, source);
1365  } else {
1366    CopyBytes<sizeof(T)>(value.bytes, source);
1367  }
1368  *result = value.data;
1369  return true;
1370}
1371
1372
1373template<typename T>
1374static bool DataViewSetValue(
1375    Isolate* isolate,
1376    Handle<JSDataView> data_view,
1377    Handle<Object> byte_offset_obj,
1378    bool is_little_endian,
1379    T data) {
1380  size_t byte_offset = 0;
1381  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1382    return false;
1383  }
1384  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1385
1386  size_t data_view_byte_offset =
1387      NumberToSize(isolate, data_view->byte_offset());
1388  size_t data_view_byte_length =
1389      NumberToSize(isolate, data_view->byte_length());
1390  if (byte_offset + sizeof(T) > data_view_byte_length ||
1391      byte_offset + sizeof(T) < byte_offset)  {  // overflow
1392    return false;
1393  }
1394
1395  union Value {
1396    T data;
1397    uint8_t bytes[sizeof(T)];
1398  };
1399
1400  Value value;
1401  value.data = data;
1402  size_t buffer_offset = data_view_byte_offset + byte_offset;
1403  DCHECK(
1404      NumberToSize(isolate, buffer->byte_length())
1405      >= buffer_offset + sizeof(T));
1406  uint8_t* target =
1407        static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1408  if (NeedToFlipBytes(is_little_endian)) {
1409    FlipBytes<sizeof(T)>(target, value.bytes);
1410  } else {
1411    CopyBytes<sizeof(T)>(target, value.bytes);
1412  }
1413  return true;
1414}
1415
1416
1417#define DATA_VIEW_GETTER(TypeName, Type, Converter)                   \
1418  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                   \
1419    HandleScope scope(isolate);                                       \
1420    DCHECK(args.length() == 3);                                       \
1421    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                \
1422    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                     \
1423    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                 \
1424    Type result;                                                      \
1425    if (DataViewGetValue(isolate, holder, offset, is_little_endian,   \
1426                         &result)) {                                  \
1427      return *isolate->factory()->Converter(result);                  \
1428    } else {                                                          \
1429      THROW_NEW_ERROR_RETURN_FAILURE(                                 \
1430          isolate, NewRangeError("invalid_data_view_accessor_offset", \
1431                                 HandleVector<Object>(NULL, 0)));     \
1432    }                                                                 \
1433  }
1434
1435DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
1436DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
1437DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
1438DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
1439DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
1440DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
1441DATA_VIEW_GETTER(Float32, float, NewNumber)
1442DATA_VIEW_GETTER(Float64, double, NewNumber)
1443
1444#undef DATA_VIEW_GETTER
1445
1446
1447template <typename T>
1448static T DataViewConvertValue(double value);
1449
1450
1451template <>
1452int8_t DataViewConvertValue<int8_t>(double value) {
1453  return static_cast<int8_t>(DoubleToInt32(value));
1454}
1455
1456
1457template <>
1458int16_t DataViewConvertValue<int16_t>(double value) {
1459  return static_cast<int16_t>(DoubleToInt32(value));
1460}
1461
1462
1463template <>
1464int32_t DataViewConvertValue<int32_t>(double value) {
1465  return DoubleToInt32(value);
1466}
1467
1468
1469template <>
1470uint8_t DataViewConvertValue<uint8_t>(double value) {
1471  return static_cast<uint8_t>(DoubleToUint32(value));
1472}
1473
1474
1475template <>
1476uint16_t DataViewConvertValue<uint16_t>(double value) {
1477  return static_cast<uint16_t>(DoubleToUint32(value));
1478}
1479
1480
1481template <>
1482uint32_t DataViewConvertValue<uint32_t>(double value) {
1483  return DoubleToUint32(value);
1484}
1485
1486
1487template <>
1488float DataViewConvertValue<float>(double value) {
1489  return static_cast<float>(value);
1490}
1491
1492
1493template <>
1494double DataViewConvertValue<double>(double value) {
1495  return value;
1496}
1497
1498
1499#define DATA_VIEW_SETTER(TypeName, Type)                                  \
1500  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                       \
1501    HandleScope scope(isolate);                                           \
1502    DCHECK(args.length() == 4);                                           \
1503    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                    \
1504    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                         \
1505    CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                          \
1506    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                     \
1507    Type v = DataViewConvertValue<Type>(value->Number());                 \
1508    if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
1509      return isolate->heap()->undefined_value();                          \
1510    } else {                                                              \
1511      THROW_NEW_ERROR_RETURN_FAILURE(                                     \
1512          isolate, NewRangeError("invalid_data_view_accessor_offset",     \
1513                                 HandleVector<Object>(NULL, 0)));         \
1514    }                                                                     \
1515  }
1516
1517DATA_VIEW_SETTER(Uint8, uint8_t)
1518DATA_VIEW_SETTER(Int8, int8_t)
1519DATA_VIEW_SETTER(Uint16, uint16_t)
1520DATA_VIEW_SETTER(Int16, int16_t)
1521DATA_VIEW_SETTER(Uint32, uint32_t)
1522DATA_VIEW_SETTER(Int32, int32_t)
1523DATA_VIEW_SETTER(Float32, float)
1524DATA_VIEW_SETTER(Float64, double)
1525
1526#undef DATA_VIEW_SETTER
1527
1528
1529RUNTIME_FUNCTION(Runtime_SetInitialize) {
1530  HandleScope scope(isolate);
1531  DCHECK(args.length() == 1);
1532  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1533  Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
1534  holder->set_table(*table);
1535  return *holder;
1536}
1537
1538
1539RUNTIME_FUNCTION(Runtime_SetAdd) {
1540  HandleScope scope(isolate);
1541  DCHECK(args.length() == 2);
1542  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1543  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1544  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1545  table = OrderedHashSet::Add(table, key);
1546  holder->set_table(*table);
1547  return *holder;
1548}
1549
1550
1551RUNTIME_FUNCTION(Runtime_SetHas) {
1552  HandleScope scope(isolate);
1553  DCHECK(args.length() == 2);
1554  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1555  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1556  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1557  return isolate->heap()->ToBoolean(table->Contains(key));
1558}
1559
1560
1561RUNTIME_FUNCTION(Runtime_SetDelete) {
1562  HandleScope scope(isolate);
1563  DCHECK(args.length() == 2);
1564  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1565  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1566  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1567  bool was_present = false;
1568  table = OrderedHashSet::Remove(table, key, &was_present);
1569  holder->set_table(*table);
1570  return isolate->heap()->ToBoolean(was_present);
1571}
1572
1573
1574RUNTIME_FUNCTION(Runtime_SetClear) {
1575  HandleScope scope(isolate);
1576  DCHECK(args.length() == 1);
1577  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1578  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1579  table = OrderedHashSet::Clear(table);
1580  holder->set_table(*table);
1581  return isolate->heap()->undefined_value();
1582}
1583
1584
1585RUNTIME_FUNCTION(Runtime_SetGetSize) {
1586  HandleScope scope(isolate);
1587  DCHECK(args.length() == 1);
1588  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1589  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1590  return Smi::FromInt(table->NumberOfElements());
1591}
1592
1593
1594RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
1595  HandleScope scope(isolate);
1596  DCHECK(args.length() == 3);
1597  CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
1598  CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
1599  CONVERT_SMI_ARG_CHECKED(kind, 2)
1600  RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
1601                 kind == JSSetIterator::kKindEntries);
1602  Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
1603  holder->set_table(*table);
1604  holder->set_index(Smi::FromInt(0));
1605  holder->set_kind(Smi::FromInt(kind));
1606  return isolate->heap()->undefined_value();
1607}
1608
1609
1610RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
1611  SealHandleScope shs(isolate);
1612  DCHECK(args.length() == 2);
1613  CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
1614  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
1615  return holder->Next(value_array);
1616}
1617
1618
1619RUNTIME_FUNCTION(Runtime_MapInitialize) {
1620  HandleScope scope(isolate);
1621  DCHECK(args.length() == 1);
1622  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1623  Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
1624  holder->set_table(*table);
1625  return *holder;
1626}
1627
1628
1629RUNTIME_FUNCTION(Runtime_MapGet) {
1630  HandleScope scope(isolate);
1631  DCHECK(args.length() == 2);
1632  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1633  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1634  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1635  Handle<Object> lookup(table->Lookup(key), isolate);
1636  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1637}
1638
1639
1640RUNTIME_FUNCTION(Runtime_MapHas) {
1641  HandleScope scope(isolate);
1642  DCHECK(args.length() == 2);
1643  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1644  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1645  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1646  Handle<Object> lookup(table->Lookup(key), isolate);
1647  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1648}
1649
1650
1651RUNTIME_FUNCTION(Runtime_MapDelete) {
1652  HandleScope scope(isolate);
1653  DCHECK(args.length() == 2);
1654  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1655  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1656  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1657  bool was_present = false;
1658  Handle<OrderedHashMap> new_table =
1659      OrderedHashMap::Remove(table, key, &was_present);
1660  holder->set_table(*new_table);
1661  return isolate->heap()->ToBoolean(was_present);
1662}
1663
1664
1665RUNTIME_FUNCTION(Runtime_MapClear) {
1666  HandleScope scope(isolate);
1667  DCHECK(args.length() == 1);
1668  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1669  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1670  table = OrderedHashMap::Clear(table);
1671  holder->set_table(*table);
1672  return isolate->heap()->undefined_value();
1673}
1674
1675
1676RUNTIME_FUNCTION(Runtime_MapSet) {
1677  HandleScope scope(isolate);
1678  DCHECK(args.length() == 3);
1679  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1680  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1681  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1682  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1683  Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value);
1684  holder->set_table(*new_table);
1685  return *holder;
1686}
1687
1688
1689RUNTIME_FUNCTION(Runtime_MapGetSize) {
1690  HandleScope scope(isolate);
1691  DCHECK(args.length() == 1);
1692  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1693  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1694  return Smi::FromInt(table->NumberOfElements());
1695}
1696
1697
1698RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
1699  HandleScope scope(isolate);
1700  DCHECK(args.length() == 3);
1701  CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
1702  CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
1703  CONVERT_SMI_ARG_CHECKED(kind, 2)
1704  RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys
1705      || kind == JSMapIterator::kKindValues
1706      || kind == JSMapIterator::kKindEntries);
1707  Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
1708  holder->set_table(*table);
1709  holder->set_index(Smi::FromInt(0));
1710  holder->set_kind(Smi::FromInt(kind));
1711  return isolate->heap()->undefined_value();
1712}
1713
1714
1715RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
1716  HandleScope scope(isolate);
1717  DCHECK(args.length() == 1);
1718  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
1719  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1720  Handle<FixedArray> entries =
1721      isolate->factory()->NewFixedArray(table->NumberOfElements() * 2);
1722  {
1723    DisallowHeapAllocation no_gc;
1724    int number_of_non_hole_elements = 0;
1725    for (int i = 0; i < table->Capacity(); i++) {
1726      Handle<Object> key(table->KeyAt(i), isolate);
1727      if (table->IsKey(*key)) {
1728        entries->set(number_of_non_hole_elements++, *key);
1729        Object* value = table->Lookup(key);
1730        entries->set(number_of_non_hole_elements++, value);
1731      }
1732    }
1733    DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements);
1734  }
1735  return *isolate->factory()->NewJSArrayWithElements(entries);
1736}
1737
1738
1739RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
1740  SealHandleScope shs(isolate);
1741  DCHECK(args.length() == 2);
1742  CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
1743  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
1744  return holder->Next(value_array);
1745}
1746
1747
1748static Handle<JSWeakCollection> WeakCollectionInitialize(
1749    Isolate* isolate,
1750    Handle<JSWeakCollection> weak_collection) {
1751  DCHECK(weak_collection->map()->inobject_properties() == 0);
1752  Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
1753  weak_collection->set_table(*table);
1754  return weak_collection;
1755}
1756
1757
1758RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
1759  HandleScope scope(isolate);
1760  DCHECK(args.length() == 1);
1761  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1762  return *WeakCollectionInitialize(isolate, weak_collection);
1763}
1764
1765
1766RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
1767  HandleScope scope(isolate);
1768  DCHECK(args.length() == 2);
1769  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1770  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1771  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
1772  Handle<ObjectHashTable> table(
1773      ObjectHashTable::cast(weak_collection->table()));
1774  RUNTIME_ASSERT(table->IsKey(*key));
1775  Handle<Object> lookup(table->Lookup(key), isolate);
1776  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1777}
1778
1779
1780RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
1781  HandleScope scope(isolate);
1782  DCHECK(args.length() == 2);
1783  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1784  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1785  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
1786  Handle<ObjectHashTable> table(
1787      ObjectHashTable::cast(weak_collection->table()));
1788  RUNTIME_ASSERT(table->IsKey(*key));
1789  Handle<Object> lookup(table->Lookup(key), isolate);
1790  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1791}
1792
1793
1794RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
1795  HandleScope scope(isolate);
1796  DCHECK(args.length() == 2);
1797  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1798  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1799  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
1800  Handle<ObjectHashTable> table(ObjectHashTable::cast(
1801      weak_collection->table()));
1802  RUNTIME_ASSERT(table->IsKey(*key));
1803  bool was_present = false;
1804  Handle<ObjectHashTable> new_table =
1805      ObjectHashTable::Remove(table, key, &was_present);
1806  weak_collection->set_table(*new_table);
1807  return isolate->heap()->ToBoolean(was_present);
1808}
1809
1810
1811RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
1812  HandleScope scope(isolate);
1813  DCHECK(args.length() == 3);
1814  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1815  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1816  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
1817  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1818  Handle<ObjectHashTable> table(
1819      ObjectHashTable::cast(weak_collection->table()));
1820  RUNTIME_ASSERT(table->IsKey(*key));
1821  Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1822  weak_collection->set_table(*new_table);
1823  return *weak_collection;
1824}
1825
1826
1827RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
1828  HandleScope scope(isolate);
1829  DCHECK(args.length() == 1);
1830  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
1831  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1832  Handle<FixedArray> values =
1833      isolate->factory()->NewFixedArray(table->NumberOfElements());
1834  {
1835    DisallowHeapAllocation no_gc;
1836    int number_of_non_hole_elements = 0;
1837    for (int i = 0; i < table->Capacity(); i++) {
1838      Handle<Object> key(table->KeyAt(i), isolate);
1839      if (table->IsKey(*key)) {
1840        values->set(number_of_non_hole_elements++, *key);
1841      }
1842    }
1843    DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements);
1844  }
1845  return *isolate->factory()->NewJSArrayWithElements(values);
1846}
1847
1848
1849RUNTIME_FUNCTION(Runtime_GetPrototype) {
1850  HandleScope scope(isolate);
1851  DCHECK(args.length() == 1);
1852  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
1853  // We don't expect access checks to be needed on JSProxy objects.
1854  DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
1855  PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
1856  do {
1857    if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() &&
1858        !isolate->MayNamedAccess(
1859            Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
1860            isolate->factory()->proto_string(), v8::ACCESS_GET)) {
1861      isolate->ReportFailedAccessCheck(
1862          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
1863          v8::ACCESS_GET);
1864      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1865      return isolate->heap()->undefined_value();
1866    }
1867    iter.AdvanceIgnoringProxies();
1868    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
1869      return *PrototypeIterator::GetCurrent(iter);
1870    }
1871  } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
1872  return *PrototypeIterator::GetCurrent(iter);
1873}
1874
1875
1876static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
1877    Isolate* isolate, Handle<Object> receiver) {
1878  PrototypeIterator iter(isolate, receiver);
1879  while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
1880    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
1881      return PrototypeIterator::GetCurrent(iter);
1882    }
1883    iter.Advance();
1884  }
1885  return PrototypeIterator::GetCurrent(iter);
1886}
1887
1888
1889RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
1890  HandleScope scope(isolate);
1891  DCHECK(args.length() == 2);
1892  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1893  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
1894  DCHECK(!obj->IsAccessCheckNeeded());
1895  DCHECK(!obj->map()->is_observed());
1896  Handle<Object> result;
1897  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1898      isolate, result, JSObject::SetPrototype(obj, prototype, false));
1899  return *result;
1900}
1901
1902
1903RUNTIME_FUNCTION(Runtime_SetPrototype) {
1904  HandleScope scope(isolate);
1905  DCHECK(args.length() == 2);
1906  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1907  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
1908  if (obj->IsAccessCheckNeeded() &&
1909      !isolate->MayNamedAccess(
1910          obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) {
1911    isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
1912    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1913    return isolate->heap()->undefined_value();
1914  }
1915  if (obj->map()->is_observed()) {
1916    Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
1917    Handle<Object> result;
1918    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1919        isolate, result,
1920        JSObject::SetPrototype(obj, prototype, true));
1921
1922    Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
1923    if (!new_value->SameValue(*old_value)) {
1924      JSObject::EnqueueChangeRecord(obj, "setPrototype",
1925                                    isolate->factory()->proto_string(),
1926                                    old_value);
1927    }
1928    return *result;
1929  }
1930  Handle<Object> result;
1931  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1932      isolate, result,
1933      JSObject::SetPrototype(obj, prototype, true));
1934  return *result;
1935}
1936
1937
1938RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
1939  HandleScope shs(isolate);
1940  DCHECK(args.length() == 2);
1941  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1942  CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
1943  CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
1944  PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
1945  while (true) {
1946    iter.AdvanceIgnoringProxies();
1947    if (iter.IsAtEnd()) return isolate->heap()->false_value();
1948    if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
1949  }
1950}
1951
1952
1953// Enumerator used as indices into the array returned from GetOwnProperty
1954enum PropertyDescriptorIndices {
1955  IS_ACCESSOR_INDEX,
1956  VALUE_INDEX,
1957  GETTER_INDEX,
1958  SETTER_INDEX,
1959  WRITABLE_INDEX,
1960  ENUMERABLE_INDEX,
1961  CONFIGURABLE_INDEX,
1962  DESCRIPTOR_SIZE
1963};
1964
1965
1966MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
1967                                                          Handle<JSObject> obj,
1968                                                          Handle<Name> name) {
1969  Heap* heap = isolate->heap();
1970  Factory* factory = isolate->factory();
1971
1972  PropertyAttributes attrs;
1973  uint32_t index = 0;
1974  Handle<Object> value;
1975  MaybeHandle<AccessorPair> maybe_accessors;
1976  // TODO(verwaest): Unify once indexed properties can be handled by the
1977  // LookupIterator.
1978  if (name->AsArrayIndex(&index)) {
1979    // Get attributes.
1980    Maybe<PropertyAttributes> maybe =
1981        JSReceiver::GetOwnElementAttribute(obj, index);
1982    if (!maybe.has_value) return MaybeHandle<Object>();
1983    attrs = maybe.value;
1984    if (attrs == ABSENT) return factory->undefined_value();
1985
1986    // Get AccessorPair if present.
1987    maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index);
1988
1989    // Get value if not an AccessorPair.
1990    if (maybe_accessors.is_null()) {
1991      ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
1992          Runtime::GetElementOrCharAt(isolate, obj, index), Object);
1993    }
1994  } else {
1995    // Get attributes.
1996    LookupIterator it(obj, name, LookupIterator::HIDDEN);
1997    Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
1998    if (!maybe.has_value) return MaybeHandle<Object>();
1999    attrs = maybe.value;
2000    if (attrs == ABSENT) return factory->undefined_value();
2001
2002    // Get AccessorPair if present.
2003    if (it.state() == LookupIterator::ACCESSOR &&
2004        it.GetAccessors()->IsAccessorPair()) {
2005      maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
2006    }
2007
2008    // Get value if not an AccessorPair.
2009    if (maybe_accessors.is_null()) {
2010      ASSIGN_RETURN_ON_EXCEPTION(
2011          isolate, value, Object::GetProperty(&it), Object);
2012    }
2013  }
2014  DCHECK(!isolate->has_pending_exception());
2015  Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE);
2016  elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
2017  elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
2018  elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null()));
2019
2020  Handle<AccessorPair> accessors;
2021  if (maybe_accessors.ToHandle(&accessors)) {
2022    Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
2023    Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
2024    elms->set(GETTER_INDEX, *getter);
2025    elms->set(SETTER_INDEX, *setter);
2026  } else {
2027    elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
2028    elms->set(VALUE_INDEX, *value);
2029  }
2030
2031  return factory->NewJSArrayWithElements(elms);
2032}
2033
2034
2035// Returns an array with the property description:
2036//  if args[1] is not a property on args[0]
2037//          returns undefined
2038//  if args[1] is a data property on args[0]
2039//         [false, value, Writeable, Enumerable, Configurable]
2040//  if args[1] is an accessor on args[0]
2041//         [true, GetFunction, SetFunction, Enumerable, Configurable]
2042RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
2043  HandleScope scope(isolate);
2044  DCHECK(args.length() == 2);
2045  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2046  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2047  Handle<Object> result;
2048  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2049      isolate, result, GetOwnProperty(isolate, obj, name));
2050  return *result;
2051}
2052
2053
2054RUNTIME_FUNCTION(Runtime_PreventExtensions) {
2055  HandleScope scope(isolate);
2056  DCHECK(args.length() == 1);
2057  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2058  Handle<Object> result;
2059  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2060      isolate, result, JSObject::PreventExtensions(obj));
2061  return *result;
2062}
2063
2064
2065RUNTIME_FUNCTION(Runtime_ToMethod) {
2066  HandleScope scope(isolate);
2067  DCHECK(args.length() == 2);
2068  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2069  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
2070  Handle<JSFunction> clone = JSFunction::CloneClosure(fun);
2071  Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
2072  JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol,
2073                                           home_object, DONT_ENUM).Assert();
2074  return *clone;
2075}
2076
2077
2078RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
2079  DCHECK(args.length() == 0);
2080  return isolate->heap()->home_object_symbol();
2081}
2082
2083
2084RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
2085  HandleScope scope(isolate);
2086  DCHECK(args.length() == 3);
2087  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0);
2088  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
2089  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
2090
2091  if (home_object->IsAccessCheckNeeded() &&
2092      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) {
2093    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
2094    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2095  }
2096
2097  PrototypeIterator iter(isolate, home_object);
2098  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
2099  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
2100
2101  LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
2102  Handle<Object> result;
2103  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2104  return *result;
2105}
2106
2107
2108RUNTIME_FUNCTION(Runtime_IsExtensible) {
2109  SealHandleScope shs(isolate);
2110  DCHECK(args.length() == 1);
2111  CONVERT_ARG_CHECKED(JSObject, obj, 0);
2112  if (obj->IsJSGlobalProxy()) {
2113    PrototypeIterator iter(isolate, obj);
2114    if (iter.IsAtEnd()) return isolate->heap()->false_value();
2115    DCHECK(iter.GetCurrent()->IsJSGlobalObject());
2116    obj = JSObject::cast(iter.GetCurrent());
2117  }
2118  return isolate->heap()->ToBoolean(obj->map()->is_extensible());
2119}
2120
2121
2122RUNTIME_FUNCTION(Runtime_RegExpCompile) {
2123  HandleScope scope(isolate);
2124  DCHECK(args.length() == 3);
2125  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
2126  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
2127  CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
2128  Handle<Object> result;
2129  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2130      isolate, result, RegExpImpl::Compile(re, pattern, flags));
2131  return *result;
2132}
2133
2134
2135RUNTIME_FUNCTION(Runtime_CreateApiFunction) {
2136  HandleScope scope(isolate);
2137  DCHECK(args.length() == 2);
2138  CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
2139  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
2140  return *isolate->factory()->CreateApiFunction(data, prototype);
2141}
2142
2143
2144RUNTIME_FUNCTION(Runtime_IsTemplate) {
2145  SealHandleScope shs(isolate);
2146  DCHECK(args.length() == 1);
2147  CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0);
2148  bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
2149  return isolate->heap()->ToBoolean(result);
2150}
2151
2152
2153RUNTIME_FUNCTION(Runtime_GetTemplateField) {
2154  SealHandleScope shs(isolate);
2155  DCHECK(args.length() == 2);
2156  CONVERT_ARG_CHECKED(HeapObject, templ, 0);
2157  CONVERT_SMI_ARG_CHECKED(index, 1);
2158  int offset = index * kPointerSize + HeapObject::kHeaderSize;
2159  InstanceType type = templ->map()->instance_type();
2160  RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
2161                 type == OBJECT_TEMPLATE_INFO_TYPE);
2162  RUNTIME_ASSERT(offset > 0);
2163  if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
2164    RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
2165  } else {
2166    RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
2167  }
2168  return *HeapObject::RawField(templ, offset);
2169}
2170
2171
2172RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
2173  HandleScope scope(isolate);
2174  DCHECK(args.length() == 1);
2175  CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
2176  Handle<Map> old_map(object->map());
2177  bool needs_access_checks = old_map->is_access_check_needed();
2178  if (needs_access_checks) {
2179    // Copy map so it won't interfere constructor's initial map.
2180    Handle<Map> new_map = Map::Copy(old_map);
2181    new_map->set_is_access_check_needed(false);
2182    JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
2183  }
2184  return isolate->heap()->ToBoolean(needs_access_checks);
2185}
2186
2187
2188RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
2189  HandleScope scope(isolate);
2190  DCHECK(args.length() == 1);
2191  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2192  Handle<Map> old_map(object->map());
2193  RUNTIME_ASSERT(!old_map->is_access_check_needed());
2194  // Copy map so it won't interfere constructor's initial map.
2195  Handle<Map> new_map = Map::Copy(old_map);
2196  new_map->set_is_access_check_needed(true);
2197  JSObject::MigrateToMap(object, new_map);
2198  return isolate->heap()->undefined_value();
2199}
2200
2201
2202static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
2203  HandleScope scope(isolate);
2204  Handle<Object> args[1] = { name };
2205  THROW_NEW_ERROR_RETURN_FAILURE(
2206      isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
2207}
2208
2209
2210// May throw a RedeclarationError.
2211static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
2212                              Handle<String> name, Handle<Object> value,
2213                              PropertyAttributes attr, bool is_var,
2214                              bool is_const, bool is_function) {
2215  // Do the lookup own properties only, see ES5 erratum.
2216  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
2217  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
2218  if (!maybe.has_value) return isolate->heap()->exception();
2219
2220  if (it.IsFound()) {
2221    PropertyAttributes old_attributes = maybe.value;
2222    // The name was declared before; check for conflicting re-declarations.
2223    if (is_const) return ThrowRedeclarationError(isolate, name);
2224
2225    // Skip var re-declarations.
2226    if (is_var) return isolate->heap()->undefined_value();
2227
2228    DCHECK(is_function);
2229    if ((old_attributes & DONT_DELETE) != 0) {
2230      // Only allow reconfiguring globals to functions in user code (no
2231      // natives, which are marked as read-only).
2232      DCHECK((attr & READ_ONLY) == 0);
2233
2234      // Check whether we can reconfigure the existing property into a
2235      // function.
2236      PropertyDetails old_details = it.property_details();
2237      // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
2238      // which are actually data properties, not accessor properties.
2239      if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
2240          old_details.type() == CALLBACKS) {
2241        return ThrowRedeclarationError(isolate, name);
2242      }
2243      // If the existing property is not configurable, keep its attributes. Do
2244      attr = old_attributes;
2245    }
2246  }
2247
2248  // Define or redefine own property.
2249  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
2250                                           global, name, value, attr));
2251
2252  return isolate->heap()->undefined_value();
2253}
2254
2255
2256RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
2257  HandleScope scope(isolate);
2258  DCHECK(args.length() == 3);
2259  Handle<GlobalObject> global(isolate->global_object());
2260
2261  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
2262  CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
2263  CONVERT_SMI_ARG_CHECKED(flags, 2);
2264
2265  // Traverse the name/value pairs and set the properties.
2266  int length = pairs->length();
2267  for (int i = 0; i < length; i += 2) {
2268    HandleScope scope(isolate);
2269    Handle<String> name(String::cast(pairs->get(i)));
2270    Handle<Object> initial_value(pairs->get(i + 1), isolate);
2271
2272    // We have to declare a global const property. To capture we only
2273    // assign to it when evaluating the assignment for "const x =
2274    // <expr>" the initial value is the hole.
2275    bool is_var = initial_value->IsUndefined();
2276    bool is_const = initial_value->IsTheHole();
2277    bool is_function = initial_value->IsSharedFunctionInfo();
2278    DCHECK(is_var + is_const + is_function == 1);
2279
2280    Handle<Object> value;
2281    if (is_function) {
2282      // Copy the function and update its context. Use it as value.
2283      Handle<SharedFunctionInfo> shared =
2284          Handle<SharedFunctionInfo>::cast(initial_value);
2285      Handle<JSFunction> function =
2286          isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
2287                                                                TENURED);
2288      value = function;
2289    } else {
2290      value = isolate->factory()->undefined_value();
2291    }
2292
2293    // Compute the property attributes. According to ECMA-262,
2294    // the property must be non-configurable except in eval.
2295    bool is_native = DeclareGlobalsNativeFlag::decode(flags);
2296    bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
2297    int attr = NONE;
2298    if (is_const) attr |= READ_ONLY;
2299    if (is_function && is_native) attr |= READ_ONLY;
2300    if (!is_const && !is_eval) attr |= DONT_DELETE;
2301
2302    Object* result = DeclareGlobals(isolate, global, name, value,
2303                                    static_cast<PropertyAttributes>(attr),
2304                                    is_var, is_const, is_function);
2305    if (isolate->has_pending_exception()) return result;
2306  }
2307
2308  return isolate->heap()->undefined_value();
2309}
2310
2311
2312RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
2313  HandleScope scope(isolate);
2314  // args[0] == name
2315  // args[1] == language_mode
2316  // args[2] == value (optional)
2317
2318  // Determine if we need to assign to the variable if it already
2319  // exists (based on the number of arguments).
2320  RUNTIME_ASSERT(args.length() == 3);
2321
2322  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2323  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
2324  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2325
2326  Handle<GlobalObject> global(isolate->context()->global_object());
2327  Handle<Object> result;
2328  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2329      isolate, result, Object::SetProperty(global, name, value, strict_mode));
2330  return *result;
2331}
2332
2333
2334RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
2335  HandleScope handle_scope(isolate);
2336  // All constants are declared with an initial value. The name
2337  // of the constant is the first argument and the initial value
2338  // is the second.
2339  RUNTIME_ASSERT(args.length() == 2);
2340  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2341  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
2342
2343  Handle<GlobalObject> global = isolate->global_object();
2344
2345  // Lookup the property as own on the global object.
2346  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
2347  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
2348  DCHECK(maybe.has_value);
2349  PropertyAttributes old_attributes = maybe.value;
2350
2351  PropertyAttributes attr =
2352      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2353  // Set the value if the property is either missing, or the property attributes
2354  // allow setting the value without invoking an accessor.
2355  if (it.IsFound()) {
2356    // Ignore if we can't reconfigure the value.
2357    if ((old_attributes & DONT_DELETE) != 0) {
2358      if ((old_attributes & READ_ONLY) != 0 ||
2359          it.state() == LookupIterator::ACCESSOR) {
2360        return *value;
2361      }
2362      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
2363    }
2364  }
2365
2366  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
2367                                           global, name, value, attr));
2368
2369  return *value;
2370}
2371
2372
2373RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
2374  HandleScope scope(isolate);
2375  DCHECK(args.length() == 4);
2376
2377  // Declarations are always made in a function, native, or global context. In
2378  // the case of eval code, the context passed is the context of the caller,
2379  // which may be some nested context and not the declaration context.
2380  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
2381  Handle<Context> context(context_arg->declaration_context());
2382  CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
2383  CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
2384  PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
2385  RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
2386  CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
2387
2388  // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
2389  bool is_var = *initial_value == NULL;
2390  bool is_const = initial_value->IsTheHole();
2391  bool is_function = initial_value->IsJSFunction();
2392  DCHECK(is_var + is_const + is_function == 1);
2393
2394  int index;
2395  PropertyAttributes attributes;
2396  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
2397  BindingFlags binding_flags;
2398  Handle<Object> holder =
2399      context->Lookup(name, flags, &index, &attributes, &binding_flags);
2400
2401  Handle<JSObject> object;
2402  Handle<Object> value =
2403      is_function ? initial_value
2404                  : Handle<Object>::cast(isolate->factory()->undefined_value());
2405
2406  // TODO(verwaest): This case should probably not be covered by this function,
2407  // but by DeclareGlobals instead.
2408  if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
2409      (context_arg->has_extension() &&
2410       context_arg->extension()->IsJSGlobalObject())) {
2411    return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
2412                          value, attr, is_var, is_const, is_function);
2413  }
2414
2415  if (attributes != ABSENT) {
2416    // The name was declared before; check for conflicting re-declarations.
2417    if (is_const || (attributes & READ_ONLY) != 0) {
2418      return ThrowRedeclarationError(isolate, name);
2419    }
2420
2421    // Skip var re-declarations.
2422    if (is_var) return isolate->heap()->undefined_value();
2423
2424    DCHECK(is_function);
2425    if (index >= 0) {
2426      DCHECK(holder.is_identical_to(context));
2427      context->set(index, *initial_value);
2428      return isolate->heap()->undefined_value();
2429    }
2430
2431    object = Handle<JSObject>::cast(holder);
2432
2433  } else if (context->has_extension()) {
2434    object = handle(JSObject::cast(context->extension()));
2435    DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
2436  } else {
2437    DCHECK(context->IsFunctionContext());
2438    object =
2439        isolate->factory()->NewJSObject(isolate->context_extension_function());
2440    context->set_extension(*object);
2441  }
2442
2443  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
2444                                           object, name, value, attr));
2445
2446  return isolate->heap()->undefined_value();
2447}
2448
2449
2450RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
2451  HandleScope scope(isolate);
2452  DCHECK(args.length() == 3);
2453
2454  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
2455  DCHECK(!value->IsTheHole());
2456  // Initializations are always done in a function or native context.
2457  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
2458  Handle<Context> context(context_arg->declaration_context());
2459  CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
2460
2461  int index;
2462  PropertyAttributes attributes;
2463  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
2464  BindingFlags binding_flags;
2465  Handle<Object> holder =
2466      context->Lookup(name, flags, &index, &attributes, &binding_flags);
2467
2468  if (index >= 0) {
2469    DCHECK(holder->IsContext());
2470    // Property was found in a context.  Perform the assignment if the constant
2471    // was uninitialized.
2472    Handle<Context> context = Handle<Context>::cast(holder);
2473    DCHECK((attributes & READ_ONLY) != 0);
2474    if (context->get(index)->IsTheHole()) context->set(index, *value);
2475    return *value;
2476  }
2477
2478  PropertyAttributes attr =
2479      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2480
2481  // Strict mode handling not needed (legacy const is disallowed in strict
2482  // mode).
2483
2484  // The declared const was configurable, and may have been deleted in the
2485  // meanwhile. If so, re-introduce the variable in the context extension.
2486  DCHECK(context_arg->has_extension());
2487  if (attributes == ABSENT) {
2488    holder = handle(context_arg->extension(), isolate);
2489  } else {
2490    // For JSContextExtensionObjects, the initializer can be run multiple times
2491    // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
2492    // first assignment should go through. For JSGlobalObjects, additionally any
2493    // code can run in between that modifies the declared property.
2494    DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
2495
2496    LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
2497    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
2498    if (!maybe.has_value) return isolate->heap()->exception();
2499    PropertyAttributes old_attributes = maybe.value;
2500
2501    // Ignore if we can't reconfigure the value.
2502    if ((old_attributes & DONT_DELETE) != 0) {
2503      if ((old_attributes & READ_ONLY) != 0 ||
2504          it.state() == LookupIterator::ACCESSOR) {
2505        return *value;
2506      }
2507      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
2508    }
2509  }
2510
2511  RETURN_FAILURE_ON_EXCEPTION(
2512      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
2513                   Handle<JSObject>::cast(holder), name, value, attr));
2514
2515  return *value;
2516}
2517
2518
2519RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
2520  HandleScope scope(isolate);
2521  DCHECK(args.length() == 2);
2522  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2523  CONVERT_SMI_ARG_CHECKED(properties, 1);
2524  // Conservative upper limit to prevent fuzz tests from going OOM.
2525  RUNTIME_ASSERT(properties <= 100000);
2526  if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
2527    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
2528  }
2529  return *object;
2530}
2531
2532
2533RUNTIME_FUNCTION(Runtime_RegExpExecRT) {
2534  HandleScope scope(isolate);
2535  DCHECK(args.length() == 4);
2536  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2537  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
2538  CONVERT_INT32_ARG_CHECKED(index, 2);
2539  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
2540  // Due to the way the JS calls are constructed this must be less than the
2541  // length of a string, i.e. it is always a Smi.  We check anyway for security.
2542  RUNTIME_ASSERT(index >= 0);
2543  RUNTIME_ASSERT(index <= subject->length());
2544  isolate->counters()->regexp_entry_runtime()->Increment();
2545  Handle<Object> result;
2546  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2547      isolate, result,
2548      RegExpImpl::Exec(regexp, subject, index, last_match_info));
2549  return *result;
2550}
2551
2552
2553RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
2554  HandleScope handle_scope(isolate);
2555  DCHECK(args.length() == 3);
2556  CONVERT_SMI_ARG_CHECKED(size, 0);
2557  RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength);
2558  CONVERT_ARG_HANDLE_CHECKED(Object, index, 1);
2559  CONVERT_ARG_HANDLE_CHECKED(Object, input, 2);
2560  Handle<FixedArray> elements =  isolate->factory()->NewFixedArray(size);
2561  Handle<Map> regexp_map(isolate->native_context()->regexp_result_map());
2562  Handle<JSObject> object =
2563      isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false);
2564  Handle<JSArray> array = Handle<JSArray>::cast(object);
2565  array->set_elements(*elements);
2566  array->set_length(Smi::FromInt(size));
2567  // Write in-object properties after the length of the array.
2568  array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index);
2569  array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input);
2570  return *array;
2571}
2572
2573
2574RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) {
2575  HandleScope scope(isolate);
2576  DCHECK(args.length() == 6);
2577  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2578  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2579  // If source is the empty string we set it to "(?:)" instead as
2580  // suggested by ECMA-262, 5th, section 15.10.4.1.
2581  if (source->length() == 0) source = isolate->factory()->query_colon_string();
2582
2583  CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2584  if (!global->IsTrue()) global = isolate->factory()->false_value();
2585
2586  CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2587  if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
2588
2589  CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2590  if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
2591
2592  CONVERT_ARG_HANDLE_CHECKED(Object, sticky, 5);
2593  if (!sticky->IsTrue()) sticky = isolate->factory()->false_value();
2594
2595  Map* map = regexp->map();
2596  Object* constructor = map->constructor();
2597  if (!FLAG_harmony_regexps &&
2598      constructor->IsJSFunction() &&
2599      JSFunction::cast(constructor)->initial_map() == map) {
2600    // If we still have the original map, set in-object properties directly.
2601    regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
2602    // Both true and false are immovable immortal objects so no need for write
2603    // barrier.
2604    regexp->InObjectPropertyAtPut(
2605        JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
2606    regexp->InObjectPropertyAtPut(
2607        JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
2608    regexp->InObjectPropertyAtPut(
2609        JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
2610    regexp->InObjectPropertyAtPut(
2611        JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
2612    return *regexp;
2613  }
2614
2615  // Map has changed, so use generic, but slower, method.  We also end here if
2616  // the --harmony-regexp flag is set, because the initial map does not have
2617  // space for the 'sticky' flag, since it is from the snapshot, but must work
2618  // both with and without --harmony-regexp.  When sticky comes out from under
2619  // the flag, we will be able to use the fast initial map.
2620  PropertyAttributes final =
2621      static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2622  PropertyAttributes writable =
2623      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
2624  Handle<Object> zero(Smi::FromInt(0), isolate);
2625  Factory* factory = isolate->factory();
2626  JSObject::SetOwnPropertyIgnoreAttributes(
2627      regexp, factory->source_string(), source, final).Check();
2628  JSObject::SetOwnPropertyIgnoreAttributes(
2629      regexp, factory->global_string(), global, final).Check();
2630  JSObject::SetOwnPropertyIgnoreAttributes(
2631      regexp, factory->ignore_case_string(), ignoreCase, final).Check();
2632  JSObject::SetOwnPropertyIgnoreAttributes(
2633      regexp, factory->multiline_string(), multiline, final).Check();
2634  if (FLAG_harmony_regexps) {
2635    JSObject::SetOwnPropertyIgnoreAttributes(
2636        regexp, factory->sticky_string(), sticky, final).Check();
2637  }
2638  JSObject::SetOwnPropertyIgnoreAttributes(
2639      regexp, factory->last_index_string(), zero, writable).Check();
2640  return *regexp;
2641}
2642
2643
2644RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
2645  HandleScope scope(isolate);
2646  DCHECK(args.length() == 1);
2647  CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
2648  Object* length = prototype->length();
2649  RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
2650  RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
2651  // This is necessary to enable fast checks for absence of elements
2652  // on Array.prototype and below.
2653  prototype->set_elements(isolate->heap()->empty_fixed_array());
2654  return Smi::FromInt(0);
2655}
2656
2657
2658static void InstallBuiltin(Isolate* isolate,
2659                           Handle<JSObject> holder,
2660                           const char* name,
2661                           Builtins::Name builtin_name) {
2662  Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
2663  Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2664  Handle<JSFunction> optimized =
2665      isolate->factory()->NewFunctionWithoutPrototype(key, code);
2666  optimized->shared()->DontAdaptArguments();
2667  JSObject::AddProperty(holder, key, optimized, NONE);
2668}
2669
2670
2671RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
2672  HandleScope scope(isolate);
2673  DCHECK(args.length() == 0);
2674  Handle<JSObject> holder =
2675      isolate->factory()->NewJSObject(isolate->object_function());
2676
2677  InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2678  InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2679  InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2680  InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2681  InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2682  InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2683  InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
2684
2685  return *holder;
2686}
2687
2688
2689RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
2690  SealHandleScope shs(isolate);
2691  DCHECK(args.length() == 1);
2692  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2693  if (!callable->IsJSFunction()) {
2694    HandleScope scope(isolate);
2695    Handle<Object> delegate;
2696    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2697        isolate, delegate,
2698        Execution::TryGetFunctionDelegate(
2699            isolate, Handle<JSReceiver>(callable)));
2700    callable = JSFunction::cast(*delegate);
2701  }
2702  JSFunction* function = JSFunction::cast(callable);
2703  SharedFunctionInfo* shared = function->shared();
2704  return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
2705}
2706
2707
2708RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) {
2709  SealHandleScope shs(isolate);
2710  DCHECK(args.length() == 1);
2711  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2712
2713  if (!callable->IsJSFunction()) {
2714    HandleScope scope(isolate);
2715    Handle<Object> delegate;
2716    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2717        isolate, delegate,
2718        Execution::TryGetFunctionDelegate(
2719            isolate, Handle<JSReceiver>(callable)));
2720    callable = JSFunction::cast(*delegate);
2721  }
2722  JSFunction* function = JSFunction::cast(callable);
2723
2724  SharedFunctionInfo* shared = function->shared();
2725  if (shared->native() || shared->strict_mode() == STRICT) {
2726    return isolate->heap()->undefined_value();
2727  }
2728  // Returns undefined for strict or native functions, or
2729  // the associated global receiver for "normal" functions.
2730
2731  return function->global_proxy();
2732}
2733
2734
2735RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) {
2736  HandleScope scope(isolate);
2737  DCHECK(args.length() == 4);
2738  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
2739  CONVERT_SMI_ARG_CHECKED(index, 1);
2740  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
2741  CONVERT_ARG_HANDLE_CHECKED(String, flags, 3);
2742
2743  // Get the RegExp function from the context in the literals array.
2744  // This is the RegExp function from the context in which the
2745  // function was created.  We do not use the RegExp function from the
2746  // current native context because this might be the RegExp function
2747  // from another context which we should not have access to.
2748  Handle<JSFunction> constructor =
2749      Handle<JSFunction>(
2750          JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
2751  // Compute the regular expression literal.
2752  Handle<Object> regexp;
2753  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2754      isolate, regexp,
2755      RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags));
2756  literals->set(index, *regexp);
2757  return *regexp;
2758}
2759
2760
2761RUNTIME_FUNCTION(Runtime_FunctionGetName) {
2762  SealHandleScope shs(isolate);
2763  DCHECK(args.length() == 1);
2764
2765  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2766  return f->shared()->name();
2767}
2768
2769
2770RUNTIME_FUNCTION(Runtime_FunctionSetName) {
2771  SealHandleScope shs(isolate);
2772  DCHECK(args.length() == 2);
2773
2774  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2775  CONVERT_ARG_CHECKED(String, name, 1);
2776  f->shared()->set_name(name);
2777  return isolate->heap()->undefined_value();
2778}
2779
2780
2781RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) {
2782  SealHandleScope shs(isolate);
2783  DCHECK(args.length() == 1);
2784  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2785  return isolate->heap()->ToBoolean(
2786      f->shared()->name_should_print_as_anonymous());
2787}
2788
2789
2790RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2791  SealHandleScope shs(isolate);
2792  DCHECK(args.length() == 1);
2793  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2794  f->shared()->set_name_should_print_as_anonymous(true);
2795  return isolate->heap()->undefined_value();
2796}
2797
2798
2799RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
2800  SealHandleScope shs(isolate);
2801  DCHECK(args.length() == 1);
2802  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2803  return isolate->heap()->ToBoolean(f->shared()->is_generator());
2804}
2805
2806
2807RUNTIME_FUNCTION(Runtime_FunctionIsArrow) {
2808  SealHandleScope shs(isolate);
2809  DCHECK(args.length() == 1);
2810  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2811  return isolate->heap()->ToBoolean(f->shared()->is_arrow());
2812}
2813
2814
2815RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) {
2816  SealHandleScope shs(isolate);
2817  DCHECK(args.length() == 1);
2818  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2819  return isolate->heap()->ToBoolean(f->shared()->is_concise_method());
2820}
2821
2822
2823RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
2824  SealHandleScope shs(isolate);
2825  DCHECK(args.length() == 1);
2826
2827  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2828  RUNTIME_ASSERT(f->RemovePrototype());
2829
2830  return isolate->heap()->undefined_value();
2831}
2832
2833
2834RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
2835  HandleScope scope(isolate);
2836  DCHECK(args.length() == 1);
2837
2838  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2839  Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2840  if (!script->IsScript()) return isolate->heap()->undefined_value();
2841
2842  return *Script::GetWrapper(Handle<Script>::cast(script));
2843}
2844
2845
2846RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
2847  HandleScope scope(isolate);
2848  DCHECK(args.length() == 1);
2849
2850  CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2851  Handle<SharedFunctionInfo> shared(f->shared());
2852  return *shared->GetSourceCode();
2853}
2854
2855
2856RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
2857  SealHandleScope shs(isolate);
2858  DCHECK(args.length() == 1);
2859
2860  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2861  int pos = fun->shared()->start_position();
2862  return Smi::FromInt(pos);
2863}
2864
2865
2866RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
2867  SealHandleScope shs(isolate);
2868  DCHECK(args.length() == 2);
2869
2870  CONVERT_ARG_CHECKED(Code, code, 0);
2871  CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2872
2873  RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2874
2875  Address pc = code->address() + offset;
2876  return Smi::FromInt(code->SourcePosition(pc));
2877}
2878
2879
2880RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) {
2881  SealHandleScope shs(isolate);
2882  DCHECK(args.length() == 2);
2883
2884  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2885  CONVERT_ARG_CHECKED(String, name, 1);
2886  fun->SetInstanceClassName(name);
2887  return isolate->heap()->undefined_value();
2888}
2889
2890
2891RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
2892  SealHandleScope shs(isolate);
2893  DCHECK(args.length() == 2);
2894
2895  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2896  CONVERT_SMI_ARG_CHECKED(length, 1);
2897  RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 ||
2898                 (length & 0xC0000000) == 0x0);
2899  fun->shared()->set_length(length);
2900  return isolate->heap()->undefined_value();
2901}
2902
2903
2904RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
2905  HandleScope scope(isolate);
2906  DCHECK(args.length() == 2);
2907
2908  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2909  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
2910  RUNTIME_ASSERT(fun->should_have_prototype());
2911  Accessors::FunctionSetPrototype(fun, value);
2912  return args[0];  // return TOS
2913}
2914
2915
2916RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
2917  SealHandleScope shs(isolate);
2918  DCHECK(args.length() == 1);
2919
2920  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2921  return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
2922}
2923
2924
2925RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) {
2926  SealHandleScope shs(isolate);
2927  DCHECK(args.length() == 1);
2928
2929  CONVERT_ARG_CHECKED(JSFunction, f, 0);
2930  return isolate->heap()->ToBoolean(f->IsBuiltin());
2931}
2932
2933
2934RUNTIME_FUNCTION(Runtime_SetCode) {
2935  HandleScope scope(isolate);
2936  DCHECK(args.length() == 2);
2937
2938  CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
2939  CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1);
2940
2941  Handle<SharedFunctionInfo> target_shared(target->shared());
2942  Handle<SharedFunctionInfo> source_shared(source->shared());
2943  RUNTIME_ASSERT(!source_shared->bound());
2944
2945  if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
2946    return isolate->heap()->exception();
2947  }
2948
2949  // Mark both, the source and the target, as un-flushable because the
2950  // shared unoptimized code makes them impossible to enqueue in a list.
2951  DCHECK(target_shared->code()->gc_metadata() == NULL);
2952  DCHECK(source_shared->code()->gc_metadata() == NULL);
2953  target_shared->set_dont_flush(true);
2954  source_shared->set_dont_flush(true);
2955
2956  // Set the code, scope info, formal parameter count, and the length
2957  // of the target shared function info.
2958  target_shared->ReplaceCode(source_shared->code());
2959  target_shared->set_scope_info(source_shared->scope_info());
2960  target_shared->set_length(source_shared->length());
2961  target_shared->set_feedback_vector(source_shared->feedback_vector());
2962  target_shared->set_formal_parameter_count(
2963      source_shared->formal_parameter_count());
2964  target_shared->set_script(source_shared->script());
2965  target_shared->set_start_position_and_type(
2966      source_shared->start_position_and_type());
2967  target_shared->set_end_position(source_shared->end_position());
2968  bool was_native = target_shared->native();
2969  target_shared->set_compiler_hints(source_shared->compiler_hints());
2970  target_shared->set_native(was_native);
2971  target_shared->set_profiler_ticks(source_shared->profiler_ticks());
2972
2973  // Set the code of the target function.
2974  target->ReplaceCode(source_shared->code());
2975  DCHECK(target->next_function_link()->IsUndefined());
2976
2977  // Make sure we get a fresh copy of the literal vector to avoid cross
2978  // context contamination.
2979  Handle<Context> context(source->context());
2980  int number_of_literals = source->NumberOfLiterals();
2981  Handle<FixedArray> literals =
2982      isolate->factory()->NewFixedArray(number_of_literals, TENURED);
2983  if (number_of_literals > 0) {
2984    literals->set(JSFunction::kLiteralNativeContextIndex,
2985                  context->native_context());
2986  }
2987  target->set_context(*context);
2988  target->set_literals(*literals);
2989
2990  if (isolate->logger()->is_logging_code_events() ||
2991      isolate->cpu_profiler()->is_profiling()) {
2992    isolate->logger()->LogExistingFunction(
2993        source_shared, Handle<Code>(source_shared->code()));
2994  }
2995
2996  return *target;
2997}
2998
2999
3000RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
3001  HandleScope scope(isolate);
3002  DCHECK(args.length() == 0);
3003
3004  JavaScriptFrameIterator it(isolate);
3005  JavaScriptFrame* frame = it.frame();
3006  Handle<JSFunction> function(frame->function());
3007  RUNTIME_ASSERT(function->shared()->is_generator());
3008
3009  Handle<JSGeneratorObject> generator;
3010  if (frame->IsConstructor()) {
3011    generator = handle(JSGeneratorObject::cast(frame->receiver()));
3012  } else {
3013    generator = isolate->factory()->NewJSGeneratorObject(function);
3014  }
3015  generator->set_function(*function);
3016  generator->set_context(Context::cast(frame->context()));
3017  generator->set_receiver(frame->receiver());
3018  generator->set_continuation(0);
3019  generator->set_operand_stack(isolate->heap()->empty_fixed_array());
3020  generator->set_stack_handler_index(-1);
3021
3022  return *generator;
3023}
3024
3025
3026RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
3027  HandleScope handle_scope(isolate);
3028  DCHECK(args.length() == 1);
3029  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
3030
3031  JavaScriptFrameIterator stack_iterator(isolate);
3032  JavaScriptFrame* frame = stack_iterator.frame();
3033  RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3034  DCHECK_EQ(frame->function(), generator_object->function());
3035
3036  // The caller should have saved the context and continuation already.
3037  DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
3038  DCHECK_LT(0, generator_object->continuation());
3039
3040  // We expect there to be at least two values on the operand stack: the return
3041  // value of the yield expression, and the argument to this runtime call.
3042  // Neither of those should be saved.
3043  int operands_count = frame->ComputeOperandsCount();
3044  DCHECK_GE(operands_count, 2);
3045  operands_count -= 2;
3046
3047  if (operands_count == 0) {
3048    // Although it's semantically harmless to call this function with an
3049    // operands_count of zero, it is also unnecessary.
3050    DCHECK_EQ(generator_object->operand_stack(),
3051              isolate->heap()->empty_fixed_array());
3052    DCHECK_EQ(generator_object->stack_handler_index(), -1);
3053    // If there are no operands on the stack, there shouldn't be a handler
3054    // active either.
3055    DCHECK(!frame->HasHandler());
3056  } else {
3057    int stack_handler_index = -1;
3058    Handle<FixedArray> operand_stack =
3059        isolate->factory()->NewFixedArray(operands_count);
3060    frame->SaveOperandStack(*operand_stack, &stack_handler_index);
3061    generator_object->set_operand_stack(*operand_stack);
3062    generator_object->set_stack_handler_index(stack_handler_index);
3063  }
3064
3065  return isolate->heap()->undefined_value();
3066}
3067
3068
3069// Note that this function is the slow path for resuming generators.  It is only
3070// called if the suspended activation had operands on the stack, stack handlers
3071// needing rewinding, or if the resume should throw an exception.  The fast path
3072// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
3073// inlined into GeneratorNext and GeneratorThrow.  EmitGeneratorResumeResume is
3074// called in any case, as it needs to reconstruct the stack frame and make space
3075// for arguments and operands.
3076RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
3077  SealHandleScope shs(isolate);
3078  DCHECK(args.length() == 3);
3079  CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3080  CONVERT_ARG_CHECKED(Object, value, 1);
3081  CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3082  JavaScriptFrameIterator stack_iterator(isolate);
3083  JavaScriptFrame* frame = stack_iterator.frame();
3084
3085  DCHECK_EQ(frame->function(), generator_object->function());
3086  DCHECK(frame->function()->is_compiled());
3087
3088  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
3089  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
3090
3091  Address pc = generator_object->function()->code()->instruction_start();
3092  int offset = generator_object->continuation();
3093  DCHECK(offset > 0);
3094  frame->set_pc(pc + offset);
3095  if (FLAG_enable_ool_constant_pool) {
3096    frame->set_constant_pool(
3097        generator_object->function()->code()->constant_pool());
3098  }
3099  generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3100
3101  FixedArray* operand_stack = generator_object->operand_stack();
3102  int operands_count = operand_stack->length();
3103  if (operands_count != 0) {
3104    frame->RestoreOperandStack(operand_stack,
3105                               generator_object->stack_handler_index());
3106    generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
3107    generator_object->set_stack_handler_index(-1);
3108  }
3109
3110  JSGeneratorObject::ResumeMode resume_mode =
3111      static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3112  switch (resume_mode) {
3113    case JSGeneratorObject::NEXT:
3114      return value;
3115    case JSGeneratorObject::THROW:
3116      return isolate->Throw(value);
3117  }
3118
3119  UNREACHABLE();
3120  return isolate->ThrowIllegalOperation();
3121}
3122
3123
3124RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) {
3125  HandleScope scope(isolate);
3126  DCHECK(args.length() == 1);
3127  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3128  int continuation = generator->continuation();
3129  const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
3130      "generator_finished" : "generator_running";
3131  Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3132  THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv));
3133}
3134
3135
3136RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
3137  HandleScope scope(isolate);
3138  DCHECK(args.length() == 1);
3139  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3140
3141  // %ObjectFreeze is a fast path and these cases are handled elsewhere.
3142  RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
3143                 !object->map()->is_observed() &&
3144                 !object->IsJSProxy());
3145
3146  Handle<Object> result;
3147  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
3148  return *result;
3149}
3150
3151
3152RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) {
3153  HandleScope handle_scope(isolate);
3154  DCHECK(args.length() == 2);
3155
3156  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3157  CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
3158
3159  // Flatten the string.  If someone wants to get a char at an index
3160  // in a cons string, it is likely that more indices will be
3161  // accessed.
3162  subject = String::Flatten(subject);
3163
3164  if (i >= static_cast<uint32_t>(subject->length())) {
3165    return isolate->heap()->nan_value();
3166  }
3167
3168  return Smi::FromInt(subject->Get(i));
3169}
3170
3171
3172RUNTIME_FUNCTION(Runtime_CharFromCode) {
3173  HandleScope handlescope(isolate);
3174  DCHECK(args.length() == 1);
3175  if (args[0]->IsNumber()) {
3176    CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]);
3177    code &= 0xffff;
3178    return *isolate->factory()->LookupSingleCharacterStringFromCode(code);
3179  }
3180  return isolate->heap()->empty_string();
3181}
3182
3183
3184class FixedArrayBuilder {
3185 public:
3186  explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3187      : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
3188        length_(0),
3189        has_non_smi_elements_(false) {
3190    // Require a non-zero initial size. Ensures that doubling the size to
3191    // extend the array will work.
3192    DCHECK(initial_capacity > 0);
3193  }
3194
3195  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3196      : array_(backing_store),
3197        length_(0),
3198        has_non_smi_elements_(false) {
3199    // Require a non-zero initial size. Ensures that doubling the size to
3200    // extend the array will work.
3201    DCHECK(backing_store->length() > 0);
3202  }
3203
3204  bool HasCapacity(int elements) {
3205    int length = array_->length();
3206    int required_length = length_ + elements;
3207    return (length >= required_length);
3208  }
3209
3210  void EnsureCapacity(int elements) {
3211    int length = array_->length();
3212    int required_length = length_ + elements;
3213    if (length < required_length) {
3214      int new_length = length;
3215      do {
3216        new_length *= 2;
3217      } while (new_length < required_length);
3218      Handle<FixedArray> extended_array =
3219          array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
3220      array_->CopyTo(0, *extended_array, 0, length_);
3221      array_ = extended_array;
3222    }
3223  }
3224
3225  void Add(Object* value) {
3226    DCHECK(!value->IsSmi());
3227    DCHECK(length_ < capacity());
3228    array_->set(length_, value);
3229    length_++;
3230    has_non_smi_elements_ = true;
3231  }
3232
3233  void Add(Smi* value) {
3234    DCHECK(value->IsSmi());
3235    DCHECK(length_ < capacity());
3236    array_->set(length_, value);
3237    length_++;
3238  }
3239
3240  Handle<FixedArray> array() {
3241    return array_;
3242  }
3243
3244  int length() {
3245    return length_;
3246  }
3247
3248  int capacity() {
3249    return array_->length();
3250  }
3251
3252  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
3253    JSArray::SetContent(target_array, array_);
3254    target_array->set_length(Smi::FromInt(length_));
3255    return target_array;
3256  }
3257
3258
3259 private:
3260  Handle<FixedArray> array_;
3261  int length_;
3262  bool has_non_smi_elements_;
3263};
3264
3265
3266// Forward declarations.
3267const int kStringBuilderConcatHelperLengthBits = 11;
3268const int kStringBuilderConcatHelperPositionBits = 19;
3269
3270template <typename schar>
3271static inline void StringBuilderConcatHelper(String*,
3272                                             schar*,
3273                                             FixedArray*,
3274                                             int);
3275
3276typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3277    StringBuilderSubstringLength;
3278typedef BitField<int,
3279                 kStringBuilderConcatHelperLengthBits,
3280                 kStringBuilderConcatHelperPositionBits>
3281    StringBuilderSubstringPosition;
3282
3283
3284class ReplacementStringBuilder {
3285 public:
3286  ReplacementStringBuilder(Heap* heap, Handle<String> subject,
3287                           int estimated_part_count)
3288      : heap_(heap),
3289        array_builder_(heap->isolate(), estimated_part_count),
3290        subject_(subject),
3291        character_count_(0),
3292        is_one_byte_(subject->IsOneByteRepresentation()) {
3293    // Require a non-zero initial size. Ensures that doubling the size to
3294    // extend the array will work.
3295    DCHECK(estimated_part_count > 0);
3296  }
3297
3298  static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3299                                     int from,
3300                                     int to) {
3301    DCHECK(from >= 0);
3302    int length = to - from;
3303    DCHECK(length > 0);
3304    if (StringBuilderSubstringLength::is_valid(length) &&
3305        StringBuilderSubstringPosition::is_valid(from)) {
3306      int encoded_slice = StringBuilderSubstringLength::encode(length) |
3307          StringBuilderSubstringPosition::encode(from);
3308      builder->Add(Smi::FromInt(encoded_slice));
3309    } else {
3310      // Otherwise encode as two smis.
3311      builder->Add(Smi::FromInt(-length));
3312      builder->Add(Smi::FromInt(from));
3313    }
3314  }
3315
3316
3317  void EnsureCapacity(int elements) {
3318    array_builder_.EnsureCapacity(elements);
3319  }
3320
3321
3322  void AddSubjectSlice(int from, int to) {
3323    AddSubjectSlice(&array_builder_, from, to);
3324    IncrementCharacterCount(to - from);
3325  }
3326
3327
3328  void AddString(Handle<String> string) {
3329    int length = string->length();
3330    DCHECK(length > 0);
3331    AddElement(*string);
3332    if (!string->IsOneByteRepresentation()) {
3333      is_one_byte_ = false;
3334    }
3335    IncrementCharacterCount(length);
3336  }
3337
3338
3339  MaybeHandle<String> ToString() {
3340    Isolate* isolate = heap_->isolate();
3341    if (array_builder_.length() == 0) {
3342      return isolate->factory()->empty_string();
3343    }
3344
3345    Handle<String> joined_string;
3346    if (is_one_byte_) {
3347      Handle<SeqOneByteString> seq;
3348      ASSIGN_RETURN_ON_EXCEPTION(
3349          isolate, seq,
3350          isolate->factory()->NewRawOneByteString(character_count_),
3351          String);
3352
3353      DisallowHeapAllocation no_gc;
3354      uint8_t* char_buffer = seq->GetChars();
3355      StringBuilderConcatHelper(*subject_,
3356                                char_buffer,
3357                                *array_builder_.array(),
3358                                array_builder_.length());
3359      joined_string = Handle<String>::cast(seq);
3360    } else {
3361      // Two-byte.
3362      Handle<SeqTwoByteString> seq;
3363      ASSIGN_RETURN_ON_EXCEPTION(
3364          isolate, seq,
3365          isolate->factory()->NewRawTwoByteString(character_count_),
3366          String);
3367
3368      DisallowHeapAllocation no_gc;
3369      uc16* char_buffer = seq->GetChars();
3370      StringBuilderConcatHelper(*subject_,
3371                                char_buffer,
3372                                *array_builder_.array(),
3373                                array_builder_.length());
3374      joined_string = Handle<String>::cast(seq);
3375    }
3376    return joined_string;
3377  }
3378
3379
3380  void IncrementCharacterCount(int by) {
3381    if (character_count_ > String::kMaxLength - by) {
3382      STATIC_ASSERT(String::kMaxLength < kMaxInt);
3383      character_count_ = kMaxInt;
3384    } else {
3385      character_count_ += by;
3386    }
3387  }
3388
3389 private:
3390  void AddElement(Object* element) {
3391    DCHECK(element->IsSmi() || element->IsString());
3392    DCHECK(array_builder_.capacity() > array_builder_.length());
3393    array_builder_.Add(element);
3394  }
3395
3396  Heap* heap_;
3397  FixedArrayBuilder array_builder_;
3398  Handle<String> subject_;
3399  int character_count_;
3400  bool is_one_byte_;
3401};
3402
3403
3404class CompiledReplacement {
3405 public:
3406  explicit CompiledReplacement(Zone* zone)
3407      : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
3408
3409  // Return whether the replacement is simple.
3410  bool Compile(Handle<String> replacement,
3411               int capture_count,
3412               int subject_length);
3413
3414  // Use Apply only if Compile returned false.
3415  void Apply(ReplacementStringBuilder* builder,
3416             int match_from,
3417             int match_to,
3418             int32_t* match);
3419
3420  // Number of distinct parts of the replacement pattern.
3421  int parts() {
3422    return parts_.length();
3423  }
3424
3425  Zone* zone() const { return zone_; }
3426
3427 private:
3428  enum PartType {
3429    SUBJECT_PREFIX = 1,
3430    SUBJECT_SUFFIX,
3431    SUBJECT_CAPTURE,
3432    REPLACEMENT_SUBSTRING,
3433    REPLACEMENT_STRING,
3434
3435    NUMBER_OF_PART_TYPES
3436  };
3437
3438  struct ReplacementPart {
3439    static inline ReplacementPart SubjectMatch() {
3440      return ReplacementPart(SUBJECT_CAPTURE, 0);
3441    }
3442    static inline ReplacementPart SubjectCapture(int capture_index) {
3443      return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3444    }
3445    static inline ReplacementPart SubjectPrefix() {
3446      return ReplacementPart(SUBJECT_PREFIX, 0);
3447    }
3448    static inline ReplacementPart SubjectSuffix(int subject_length) {
3449      return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3450    }
3451    static inline ReplacementPart ReplacementString() {
3452      return ReplacementPart(REPLACEMENT_STRING, 0);
3453    }
3454    static inline ReplacementPart ReplacementSubString(int from, int to) {
3455      DCHECK(from >= 0);
3456      DCHECK(to > from);
3457      return ReplacementPart(-from, to);
3458    }
3459
3460    // If tag <= 0 then it is the negation of a start index of a substring of
3461    // the replacement pattern, otherwise it's a value from PartType.
3462    ReplacementPart(int tag, int data)
3463        : tag(tag), data(data) {
3464      // Must be non-positive or a PartType value.
3465      DCHECK(tag < NUMBER_OF_PART_TYPES);
3466    }
3467    // Either a value of PartType or a non-positive number that is
3468    // the negation of an index into the replacement string.
3469    int tag;
3470    // The data value's interpretation depends on the value of tag:
3471    // tag == SUBJECT_PREFIX ||
3472    // tag == SUBJECT_SUFFIX:  data is unused.
3473    // tag == SUBJECT_CAPTURE: data is the number of the capture.
3474    // tag == REPLACEMENT_SUBSTRING ||
3475    // tag == REPLACEMENT_STRING:    data is index into array of substrings
3476    //                               of the replacement string.
3477    // tag <= 0: Temporary representation of the substring of the replacement
3478    //           string ranging over -tag .. data.
3479    //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3480    //           substring objects.
3481    int data;
3482  };
3483
3484  template<typename Char>
3485  bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3486                               Vector<Char> characters,
3487                               int capture_count,
3488                               int subject_length,
3489                               Zone* zone) {
3490    int length = characters.length();
3491    int last = 0;
3492    for (int i = 0; i < length; i++) {
3493      Char c = characters[i];
3494      if (c == '$') {
3495        int next_index = i + 1;
3496        if (next_index == length) {  // No next character!
3497          break;
3498        }
3499        Char c2 = characters[next_index];
3500        switch (c2) {
3501        case '$':
3502          if (i > last) {
3503            // There is a substring before. Include the first "$".
3504            parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3505                       zone);
3506            last = next_index + 1;  // Continue after the second "$".
3507          } else {
3508            // Let the next substring start with the second "$".
3509            last = next_index;
3510          }
3511          i = next_index;
3512          break;
3513        case '`':
3514          if (i > last) {
3515            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3516          }
3517          parts->Add(ReplacementPart::SubjectPrefix(), zone);
3518          i = next_index;
3519          last = i + 1;
3520          break;
3521        case '\'':
3522          if (i > last) {
3523            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3524          }
3525          parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
3526          i = next_index;
3527          last = i + 1;
3528          break;
3529        case '&':
3530          if (i > last) {
3531            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3532          }
3533          parts->Add(ReplacementPart::SubjectMatch(), zone);
3534          i = next_index;
3535          last = i + 1;
3536          break;
3537        case '0':
3538        case '1':
3539        case '2':
3540        case '3':
3541        case '4':
3542        case '5':
3543        case '6':
3544        case '7':
3545        case '8':
3546        case '9': {
3547          int capture_ref = c2 - '0';
3548          if (capture_ref > capture_count) {
3549            i = next_index;
3550            continue;
3551          }
3552          int second_digit_index = next_index + 1;
3553          if (second_digit_index < length) {
3554            // Peek ahead to see if we have two digits.
3555            Char c3 = characters[second_digit_index];
3556            if ('0' <= c3 && c3 <= '9') {  // Double digits.
3557              int double_digit_ref = capture_ref * 10 + c3 - '0';
3558              if (double_digit_ref <= capture_count) {
3559                next_index = second_digit_index;
3560                capture_ref = double_digit_ref;
3561              }
3562            }
3563          }
3564          if (capture_ref > 0) {
3565            if (i > last) {
3566              parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3567            }
3568            DCHECK(capture_ref <= capture_count);
3569            parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
3570            last = next_index + 1;
3571          }
3572          i = next_index;
3573          break;
3574        }
3575        default:
3576          i = next_index;
3577          break;
3578        }
3579      }
3580    }
3581    if (length > last) {
3582      if (last == 0) {
3583        // Replacement is simple.  Do not use Apply to do the replacement.
3584        return true;
3585      } else {
3586        parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
3587      }
3588    }
3589    return false;
3590  }
3591
3592  ZoneList<ReplacementPart> parts_;
3593  ZoneList<Handle<String> > replacement_substrings_;
3594  Zone* zone_;
3595};
3596
3597
3598bool CompiledReplacement::Compile(Handle<String> replacement,
3599                                  int capture_count,
3600                                  int subject_length) {
3601  {
3602    DisallowHeapAllocation no_gc;
3603    String::FlatContent content = replacement->GetFlatContent();
3604    DCHECK(content.IsFlat());
3605    bool simple = false;
3606    if (content.IsOneByte()) {
3607      simple = ParseReplacementPattern(&parts_,
3608                                       content.ToOneByteVector(),
3609                                       capture_count,
3610                                       subject_length,
3611                                       zone());
3612    } else {
3613      DCHECK(content.IsTwoByte());
3614      simple = ParseReplacementPattern(&parts_,
3615                                       content.ToUC16Vector(),
3616                                       capture_count,
3617                                       subject_length,
3618                                       zone());
3619    }
3620    if (simple) return true;
3621  }
3622
3623  Isolate* isolate = replacement->GetIsolate();
3624  // Find substrings of replacement string and create them as String objects.
3625  int substring_index = 0;
3626  for (int i = 0, n = parts_.length(); i < n; i++) {
3627    int tag = parts_[i].tag;
3628    if (tag <= 0) {  // A replacement string slice.
3629      int from = -tag;
3630      int to = parts_[i].data;
3631      replacement_substrings_.Add(
3632          isolate->factory()->NewSubString(replacement, from, to), zone());
3633      parts_[i].tag = REPLACEMENT_SUBSTRING;
3634      parts_[i].data = substring_index;
3635      substring_index++;
3636    } else if (tag == REPLACEMENT_STRING) {
3637      replacement_substrings_.Add(replacement, zone());
3638      parts_[i].data = substring_index;
3639      substring_index++;
3640    }
3641  }
3642  return false;
3643}
3644
3645
3646void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3647                                int match_from,
3648                                int match_to,
3649                                int32_t* match) {
3650  DCHECK_LT(0, parts_.length());
3651  for (int i = 0, n = parts_.length(); i < n; i++) {
3652    ReplacementPart part = parts_[i];
3653    switch (part.tag) {
3654      case SUBJECT_PREFIX:
3655        if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3656        break;
3657      case SUBJECT_SUFFIX: {
3658        int subject_length = part.data;
3659        if (match_to < subject_length) {
3660          builder->AddSubjectSlice(match_to, subject_length);
3661        }
3662        break;
3663      }
3664      case SUBJECT_CAPTURE: {
3665        int capture = part.data;
3666        int from = match[capture * 2];
3667        int to = match[capture * 2 + 1];
3668        if (from >= 0 && to > from) {
3669          builder->AddSubjectSlice(from, to);
3670        }
3671        break;
3672      }
3673      case REPLACEMENT_SUBSTRING:
3674      case REPLACEMENT_STRING:
3675        builder->AddString(replacement_substrings_[part.data]);
3676        break;
3677      default:
3678        UNREACHABLE();
3679    }
3680  }
3681}
3682
3683
3684void FindOneByteStringIndices(Vector<const uint8_t> subject, char pattern,
3685                              ZoneList<int>* indices, unsigned int limit,
3686                              Zone* zone) {
3687  DCHECK(limit > 0);
3688  // Collect indices of pattern in subject using memchr.
3689  // Stop after finding at most limit values.
3690  const uint8_t* subject_start = subject.start();
3691  const uint8_t* subject_end = subject_start + subject.length();
3692  const uint8_t* pos = subject_start;
3693  while (limit > 0) {
3694    pos = reinterpret_cast<const uint8_t*>(
3695        memchr(pos, pattern, subject_end - pos));
3696    if (pos == NULL) return;
3697    indices->Add(static_cast<int>(pos - subject_start), zone);
3698    pos++;
3699    limit--;
3700  }
3701}
3702
3703
3704void FindTwoByteStringIndices(const Vector<const uc16> subject,
3705                              uc16 pattern,
3706                              ZoneList<int>* indices,
3707                              unsigned int limit,
3708                              Zone* zone) {
3709  DCHECK(limit > 0);
3710  const uc16* subject_start = subject.start();
3711  const uc16* subject_end = subject_start + subject.length();
3712  for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3713    if (*pos == pattern) {
3714      indices->Add(static_cast<int>(pos - subject_start), zone);
3715      limit--;
3716    }
3717  }
3718}
3719
3720
3721template <typename SubjectChar, typename PatternChar>
3722void FindStringIndices(Isolate* isolate,
3723                       Vector<const SubjectChar> subject,
3724                       Vector<const PatternChar> pattern,
3725                       ZoneList<int>* indices,
3726                       unsigned int limit,
3727                       Zone* zone) {
3728  DCHECK(limit > 0);
3729  // Collect indices of pattern in subject.
3730  // Stop after finding at most limit values.
3731  int pattern_length = pattern.length();
3732  int index = 0;
3733  StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3734  while (limit > 0) {
3735    index = search.Search(subject, index);
3736    if (index < 0) return;
3737    indices->Add(index, zone);
3738    index += pattern_length;
3739    limit--;
3740  }
3741}
3742
3743
3744void FindStringIndicesDispatch(Isolate* isolate,
3745                               String* subject,
3746                               String* pattern,
3747                               ZoneList<int>* indices,
3748                               unsigned int limit,
3749                               Zone* zone) {
3750  {
3751    DisallowHeapAllocation no_gc;
3752    String::FlatContent subject_content = subject->GetFlatContent();
3753    String::FlatContent pattern_content = pattern->GetFlatContent();
3754    DCHECK(subject_content.IsFlat());
3755    DCHECK(pattern_content.IsFlat());
3756    if (subject_content.IsOneByte()) {
3757      Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
3758      if (pattern_content.IsOneByte()) {
3759        Vector<const uint8_t> pattern_vector =
3760            pattern_content.ToOneByteVector();
3761        if (pattern_vector.length() == 1) {
3762          FindOneByteStringIndices(subject_vector, pattern_vector[0], indices,
3763                                   limit, zone);
3764        } else {
3765          FindStringIndices(isolate,
3766                            subject_vector,
3767                            pattern_vector,
3768                            indices,
3769                            limit,
3770                            zone);
3771        }
3772      } else {
3773        FindStringIndices(isolate,
3774                          subject_vector,
3775                          pattern_content.ToUC16Vector(),
3776                          indices,
3777                          limit,
3778                          zone);
3779      }
3780    } else {
3781      Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3782      if (pattern_content.IsOneByte()) {
3783        Vector<const uint8_t> pattern_vector =
3784            pattern_content.ToOneByteVector();
3785        if (pattern_vector.length() == 1) {
3786          FindTwoByteStringIndices(subject_vector,
3787                                   pattern_vector[0],
3788                                   indices,
3789                                   limit,
3790                                   zone);
3791        } else {
3792          FindStringIndices(isolate,
3793                            subject_vector,
3794                            pattern_vector,
3795                            indices,
3796                            limit,
3797                            zone);
3798        }
3799      } else {
3800        Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3801        if (pattern_vector.length() == 1) {
3802          FindTwoByteStringIndices(subject_vector,
3803                                   pattern_vector[0],
3804                                   indices,
3805                                   limit,
3806                                   zone);
3807        } else {
3808          FindStringIndices(isolate,
3809                            subject_vector,
3810                            pattern_vector,
3811                            indices,
3812                            limit,
3813                            zone);
3814        }
3815      }
3816    }
3817  }
3818}
3819
3820
3821template<typename ResultSeqString>
3822MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString(
3823    Isolate* isolate,
3824    Handle<String> subject,
3825    Handle<JSRegExp> pattern_regexp,
3826    Handle<String> replacement,
3827    Handle<JSArray> last_match_info) {
3828  DCHECK(subject->IsFlat());
3829  DCHECK(replacement->IsFlat());
3830
3831  ZoneScope zone_scope(isolate->runtime_zone());
3832  ZoneList<int> indices(8, zone_scope.zone());
3833  DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
3834  String* pattern =
3835      String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
3836  int subject_len = subject->length();
3837  int pattern_len = pattern->length();
3838  int replacement_len = replacement->length();
3839
3840  FindStringIndicesDispatch(
3841      isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
3842
3843  int matches = indices.length();
3844  if (matches == 0) return *subject;
3845
3846  // Detect integer overflow.
3847  int64_t result_len_64 =
3848      (static_cast<int64_t>(replacement_len) -
3849       static_cast<int64_t>(pattern_len)) *
3850      static_cast<int64_t>(matches) +
3851      static_cast<int64_t>(subject_len);
3852  int result_len;
3853  if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
3854    STATIC_ASSERT(String::kMaxLength < kMaxInt);
3855    result_len = kMaxInt;  // Provoke exception.
3856  } else {
3857    result_len = static_cast<int>(result_len_64);
3858  }
3859
3860  int subject_pos = 0;
3861  int result_pos = 0;
3862
3863  MaybeHandle<SeqString> maybe_res;
3864  if (ResultSeqString::kHasOneByteEncoding) {
3865    maybe_res = isolate->factory()->NewRawOneByteString(result_len);
3866  } else {
3867    maybe_res = isolate->factory()->NewRawTwoByteString(result_len);
3868  }
3869  Handle<SeqString> untyped_res;
3870  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res);
3871  Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res);
3872
3873  for (int i = 0; i < matches; i++) {
3874    // Copy non-matched subject content.
3875    if (subject_pos < indices.at(i)) {
3876      String::WriteToFlat(*subject,
3877                          result->GetChars() + result_pos,
3878                          subject_pos,
3879                          indices.at(i));
3880      result_pos += indices.at(i) - subject_pos;
3881    }
3882
3883    // Replace match.
3884    if (replacement_len > 0) {
3885      String::WriteToFlat(*replacement,
3886                          result->GetChars() + result_pos,
3887                          0,
3888                          replacement_len);
3889      result_pos += replacement_len;
3890    }
3891
3892    subject_pos = indices.at(i) + pattern_len;
3893  }
3894  // Add remaining subject content at the end.
3895  if (subject_pos < subject_len) {
3896    String::WriteToFlat(*subject,
3897                        result->GetChars() + result_pos,
3898                        subject_pos,
3899                        subject_len);
3900  }
3901
3902  int32_t match_indices[] = { indices.at(matches - 1),
3903                              indices.at(matches - 1) + pattern_len };
3904  RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
3905
3906  return *result;
3907}
3908
3909
3910MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString(
3911    Isolate* isolate,
3912    Handle<String> subject,
3913    Handle<JSRegExp> regexp,
3914    Handle<String> replacement,
3915    Handle<JSArray> last_match_info) {
3916  DCHECK(subject->IsFlat());
3917  DCHECK(replacement->IsFlat());
3918
3919  int capture_count = regexp->CaptureCount();
3920  int subject_length = subject->length();
3921
3922  // CompiledReplacement uses zone allocation.
3923  ZoneScope zone_scope(isolate->runtime_zone());
3924  CompiledReplacement compiled_replacement(zone_scope.zone());
3925  bool simple_replace = compiled_replacement.Compile(replacement,
3926                                                     capture_count,
3927                                                     subject_length);
3928
3929  // Shortcut for simple non-regexp global replacements
3930  if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
3931    if (subject->HasOnlyOneByteChars() &&
3932        replacement->HasOnlyOneByteChars()) {
3933      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
3934          isolate, subject, regexp, replacement, last_match_info);
3935    } else {
3936      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
3937          isolate, subject, regexp, replacement, last_match_info);
3938    }
3939  }
3940
3941  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3942  if (global_cache.HasException()) return isolate->heap()->exception();
3943
3944  int32_t* current_match = global_cache.FetchNext();
3945  if (current_match == NULL) {
3946    if (global_cache.HasException()) return isolate->heap()->exception();
3947    return *subject;
3948  }
3949
3950  // Guessing the number of parts that the final result string is built
3951  // from. Global regexps can match any number of times, so we guess
3952  // conservatively.
3953  int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
3954  ReplacementStringBuilder builder(isolate->heap(),
3955                                   subject,
3956                                   expected_parts);
3957
3958  // Number of parts added by compiled replacement plus preceeding
3959  // string and possibly suffix after last match.  It is possible for
3960  // all components to use two elements when encoded as two smis.
3961  const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
3962
3963  int prev = 0;
3964
3965  do {
3966    builder.EnsureCapacity(parts_added_per_loop);
3967
3968    int start = current_match[0];
3969    int end = current_match[1];
3970
3971    if (prev < start) {
3972      builder.AddSubjectSlice(prev, start);
3973    }
3974
3975    if (simple_replace) {
3976      builder.AddString(replacement);
3977    } else {
3978      compiled_replacement.Apply(&builder,
3979                                 start,
3980                                 end,
3981                                 current_match);
3982    }
3983    prev = end;
3984
3985    current_match = global_cache.FetchNext();
3986  } while (current_match != NULL);
3987
3988  if (global_cache.HasException()) return isolate->heap()->exception();
3989
3990  if (prev < subject_length) {
3991    builder.EnsureCapacity(2);
3992    builder.AddSubjectSlice(prev, subject_length);
3993  }
3994
3995  RegExpImpl::SetLastMatchInfo(last_match_info,
3996                               subject,
3997                               capture_count,
3998                               global_cache.LastSuccessfulMatch());
3999
4000  Handle<String> result;
4001  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString());
4002  return *result;
4003}
4004
4005
4006template <typename ResultSeqString>
4007MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString(
4008    Isolate* isolate,
4009    Handle<String> subject,
4010    Handle<JSRegExp> regexp,
4011    Handle<JSArray> last_match_info) {
4012  DCHECK(subject->IsFlat());
4013
4014  // Shortcut for simple non-regexp global replacements
4015  if (regexp->TypeTag() == JSRegExp::ATOM) {
4016    Handle<String> empty_string = isolate->factory()->empty_string();
4017    if (subject->IsOneByteRepresentation()) {
4018      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4019          isolate, subject, regexp, empty_string, last_match_info);
4020    } else {
4021      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4022          isolate, subject, regexp, empty_string, last_match_info);
4023    }
4024  }
4025
4026  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4027  if (global_cache.HasException()) return isolate->heap()->exception();
4028
4029  int32_t* current_match = global_cache.FetchNext();
4030  if (current_match == NULL) {
4031    if (global_cache.HasException()) return isolate->heap()->exception();
4032    return *subject;
4033  }
4034
4035  int start = current_match[0];
4036  int end = current_match[1];
4037  int capture_count = regexp->CaptureCount();
4038  int subject_length = subject->length();
4039
4040  int new_length = subject_length - (end - start);
4041  if (new_length == 0) return isolate->heap()->empty_string();
4042
4043  Handle<ResultSeqString> answer;
4044  if (ResultSeqString::kHasOneByteEncoding) {
4045    answer = Handle<ResultSeqString>::cast(
4046        isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked());
4047  } else {
4048    answer = Handle<ResultSeqString>::cast(
4049        isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked());
4050  }
4051
4052  int prev = 0;
4053  int position = 0;
4054
4055  do {
4056    start = current_match[0];
4057    end = current_match[1];
4058    if (prev < start) {
4059      // Add substring subject[prev;start] to answer string.
4060      String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
4061      position += start - prev;
4062    }
4063    prev = end;
4064
4065    current_match = global_cache.FetchNext();
4066  } while (current_match != NULL);
4067
4068  if (global_cache.HasException()) return isolate->heap()->exception();
4069
4070  RegExpImpl::SetLastMatchInfo(last_match_info,
4071                               subject,
4072                               capture_count,
4073                               global_cache.LastSuccessfulMatch());
4074
4075  if (prev < subject_length) {
4076    // Add substring subject[prev;length] to answer string.
4077    String::WriteToFlat(
4078        *subject, answer->GetChars() + position, prev, subject_length);
4079    position += subject_length - prev;
4080  }
4081
4082  if (position == 0) return isolate->heap()->empty_string();
4083
4084  // Shorten string and fill
4085  int string_size = ResultSeqString::SizeFor(position);
4086  int allocated_string_size = ResultSeqString::SizeFor(new_length);
4087  int delta = allocated_string_size - string_size;
4088
4089  answer->set_length(position);
4090  if (delta == 0) return *answer;
4091
4092  Address end_of_string = answer->address() + string_size;
4093  Heap* heap = isolate->heap();
4094
4095  // The trimming is performed on a newly allocated object, which is on a
4096  // fresly allocated page or on an already swept page. Hence, the sweeper
4097  // thread can not get confused with the filler creation. No synchronization
4098  // needed.
4099  heap->CreateFillerObjectAt(end_of_string, delta);
4100  heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
4101  return *answer;
4102}
4103
4104
4105RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
4106  HandleScope scope(isolate);
4107  DCHECK(args.length() == 4);
4108
4109  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4110  CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4111  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4112  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
4113
4114  RUNTIME_ASSERT(regexp->GetFlags().is_global());
4115  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
4116
4117  subject = String::Flatten(subject);
4118
4119  if (replacement->length() == 0) {
4120    if (subject->HasOnlyOneByteChars()) {
4121      return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
4122          isolate, subject, regexp, last_match_info);
4123    } else {
4124      return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
4125          isolate, subject, regexp, last_match_info);
4126    }
4127  }
4128
4129  replacement = String::Flatten(replacement);
4130
4131  return StringReplaceGlobalRegExpWithString(
4132      isolate, subject, regexp, replacement, last_match_info);
4133}
4134
4135
4136// This may return an empty MaybeHandle if an exception is thrown or
4137// we abort due to reaching the recursion limit.
4138MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate,
4139                                                   Handle<String> subject,
4140                                                   Handle<String> search,
4141                                                   Handle<String> replace,
4142                                                   bool* found,
4143                                                   int recursion_limit) {
4144  StackLimitCheck stackLimitCheck(isolate);
4145  if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
4146    return MaybeHandle<String>();
4147  }
4148  recursion_limit--;
4149  if (subject->IsConsString()) {
4150    ConsString* cons = ConsString::cast(*subject);
4151    Handle<String> first = Handle<String>(cons->first());
4152    Handle<String> second = Handle<String>(cons->second());
4153    Handle<String> new_first;
4154    if (!StringReplaceOneCharWithString(
4155            isolate, first, search, replace, found, recursion_limit)
4156            .ToHandle(&new_first)) {
4157      return MaybeHandle<String>();
4158    }
4159    if (*found) return isolate->factory()->NewConsString(new_first, second);
4160
4161    Handle<String> new_second;
4162    if (!StringReplaceOneCharWithString(
4163            isolate, second, search, replace, found, recursion_limit)
4164            .ToHandle(&new_second)) {
4165      return MaybeHandle<String>();
4166    }
4167    if (*found) return isolate->factory()->NewConsString(first, new_second);
4168
4169    return subject;
4170  } else {
4171    int index = Runtime::StringMatch(isolate, subject, search, 0);
4172    if (index == -1) return subject;
4173    *found = true;
4174    Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4175    Handle<String> cons1;
4176    ASSIGN_RETURN_ON_EXCEPTION(
4177        isolate, cons1,
4178        isolate->factory()->NewConsString(first, replace),
4179        String);
4180    Handle<String> second =
4181        isolate->factory()->NewSubString(subject, index + 1, subject->length());
4182    return isolate->factory()->NewConsString(cons1, second);
4183  }
4184}
4185
4186
4187RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
4188  HandleScope scope(isolate);
4189  DCHECK(args.length() == 3);
4190  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4191  CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4192  CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
4193
4194  // If the cons string tree is too deep, we simply abort the recursion and
4195  // retry with a flattened subject string.
4196  const int kRecursionLimit = 0x1000;
4197  bool found = false;
4198  Handle<String> result;
4199  if (StringReplaceOneCharWithString(
4200          isolate, subject, search, replace, &found, kRecursionLimit)
4201          .ToHandle(&result)) {
4202    return *result;
4203  }
4204  if (isolate->has_pending_exception()) return isolate->heap()->exception();
4205
4206  subject = String::Flatten(subject);
4207  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
4208      isolate, result,
4209      StringReplaceOneCharWithString(
4210          isolate, subject, search, replace, &found, kRecursionLimit));
4211  return *result;
4212}
4213
4214
4215// Perform string match of pattern on subject, starting at start index.
4216// Caller must ensure that 0 <= start_index <= sub->length(),
4217// and should check that pat->length() + start_index <= sub->length().
4218int Runtime::StringMatch(Isolate* isolate,
4219                         Handle<String> sub,
4220                         Handle<String> pat,
4221                         int start_index) {
4222  DCHECK(0 <= start_index);
4223  DCHECK(start_index <= sub->length());
4224
4225  int pattern_length = pat->length();
4226  if (pattern_length == 0) return start_index;
4227
4228  int subject_length = sub->length();
4229  if (start_index + pattern_length > subject_length) return -1;
4230
4231  sub = String::Flatten(sub);
4232  pat = String::Flatten(pat);
4233
4234  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
4235  // Extract flattened substrings of cons strings before getting encoding.
4236  String::FlatContent seq_sub = sub->GetFlatContent();
4237  String::FlatContent seq_pat = pat->GetFlatContent();
4238
4239  // dispatch on type of strings
4240  if (seq_pat.IsOneByte()) {
4241    Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
4242    if (seq_sub.IsOneByte()) {
4243      return SearchString(isolate,
4244                          seq_sub.ToOneByteVector(),
4245                          pat_vector,
4246                          start_index);
4247    }
4248    return SearchString(isolate,
4249                        seq_sub.ToUC16Vector(),
4250                        pat_vector,
4251                        start_index);
4252  }
4253  Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4254  if (seq_sub.IsOneByte()) {
4255    return SearchString(isolate,
4256                        seq_sub.ToOneByteVector(),
4257                        pat_vector,
4258                        start_index);
4259  }
4260  return SearchString(isolate,
4261                      seq_sub.ToUC16Vector(),
4262                      pat_vector,
4263                      start_index);
4264}
4265
4266
4267RUNTIME_FUNCTION(Runtime_StringIndexOf) {
4268  HandleScope scope(isolate);
4269  DCHECK(args.length() == 3);
4270
4271  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4272  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4273  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
4274
4275  uint32_t start_index;
4276  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4277
4278  RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
4279  int position = Runtime::StringMatch(isolate, sub, pat, start_index);
4280  return Smi::FromInt(position);
4281}
4282
4283
4284template <typename schar, typename pchar>
4285static int StringMatchBackwards(Vector<const schar> subject,
4286                                Vector<const pchar> pattern,
4287                                int idx) {
4288  int pattern_length = pattern.length();
4289  DCHECK(pattern_length >= 1);
4290  DCHECK(idx + pattern_length <= subject.length());
4291
4292  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
4293    for (int i = 0; i < pattern_length; i++) {
4294      uc16 c = pattern[i];
4295      if (c > String::kMaxOneByteCharCode) {
4296        return -1;
4297      }
4298    }
4299  }
4300
4301  pchar pattern_first_char = pattern[0];
4302  for (int i = idx; i >= 0; i--) {
4303    if (subject[i] != pattern_first_char) continue;
4304    int j = 1;
4305    while (j < pattern_length) {
4306      if (pattern[j] != subject[i+j]) {
4307        break;
4308      }
4309      j++;
4310    }
4311    if (j == pattern_length) {
4312      return i;
4313    }
4314  }
4315  return -1;
4316}
4317
4318
4319RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
4320  HandleScope scope(isolate);
4321  DCHECK(args.length() == 3);
4322
4323  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4324  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4325  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
4326
4327  uint32_t start_index;
4328  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4329
4330  uint32_t pat_length = pat->length();
4331  uint32_t sub_length = sub->length();
4332
4333  if (start_index + pat_length > sub_length) {
4334    start_index = sub_length - pat_length;
4335  }
4336
4337  if (pat_length == 0) {
4338    return Smi::FromInt(start_index);
4339  }
4340
4341  sub = String::Flatten(sub);
4342  pat = String::Flatten(pat);
4343
4344  int position = -1;
4345  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
4346
4347  String::FlatContent sub_content = sub->GetFlatContent();
4348  String::FlatContent pat_content = pat->GetFlatContent();
4349
4350  if (pat_content.IsOneByte()) {
4351    Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
4352    if (sub_content.IsOneByte()) {
4353      position = StringMatchBackwards(sub_content.ToOneByteVector(),
4354                                      pat_vector,
4355                                      start_index);
4356    } else {
4357      position = StringMatchBackwards(sub_content.ToUC16Vector(),
4358                                      pat_vector,
4359                                      start_index);
4360    }
4361  } else {
4362    Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4363    if (sub_content.IsOneByte()) {
4364      position = StringMatchBackwards(sub_content.ToOneByteVector(),
4365                                      pat_vector,
4366                                      start_index);
4367    } else {
4368      position = StringMatchBackwards(sub_content.ToUC16Vector(),
4369                                      pat_vector,
4370                                      start_index);
4371    }
4372  }
4373
4374  return Smi::FromInt(position);
4375}
4376
4377
4378RUNTIME_FUNCTION(Runtime_StringLocaleCompare) {
4379  HandleScope handle_scope(isolate);
4380  DCHECK(args.length() == 2);
4381
4382  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
4383  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
4384
4385  if (str1.is_identical_to(str2)) return Smi::FromInt(0);  // Equal.
4386  int str1_length = str1->length();
4387  int str2_length = str2->length();
4388
4389  // Decide trivial cases without flattening.
4390  if (str1_length == 0) {
4391    if (str2_length == 0) return Smi::FromInt(0);  // Equal.
4392    return Smi::FromInt(-str2_length);
4393  } else {
4394    if (str2_length == 0) return Smi::FromInt(str1_length);
4395  }
4396
4397  int end = str1_length < str2_length ? str1_length : str2_length;
4398
4399  // No need to flatten if we are going to find the answer on the first
4400  // character.  At this point we know there is at least one character
4401  // in each string, due to the trivial case handling above.
4402  int d = str1->Get(0) - str2->Get(0);
4403  if (d != 0) return Smi::FromInt(d);
4404
4405  str1 = String::Flatten(str1);
4406  str2 = String::Flatten(str2);
4407
4408  DisallowHeapAllocation no_gc;
4409  String::FlatContent flat1 = str1->GetFlatContent();
4410  String::FlatContent flat2 = str2->GetFlatContent();
4411
4412  for (int i = 0; i < end; i++) {
4413    if (flat1.Get(i) != flat2.Get(i)) {
4414      return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
4415    }
4416  }
4417
4418  return Smi::FromInt(str1_length - str2_length);
4419}
4420
4421
4422RUNTIME_FUNCTION(Runtime_SubString) {
4423  HandleScope scope(isolate);
4424  DCHECK(args.length() == 3);
4425
4426  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
4427  int start, end;
4428  // We have a fast integer-only case here to avoid a conversion to double in
4429  // the common case where from and to are Smis.
4430  if (args[1]->IsSmi() && args[2]->IsSmi()) {
4431    CONVERT_SMI_ARG_CHECKED(from_number, 1);
4432    CONVERT_SMI_ARG_CHECKED(to_number, 2);
4433    start = from_number;
4434    end = to_number;
4435  } else {
4436    CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4437    CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
4438    start = FastD2IChecked(from_number);
4439    end = FastD2IChecked(to_number);
4440  }
4441  RUNTIME_ASSERT(end >= start);
4442  RUNTIME_ASSERT(start >= 0);
4443  RUNTIME_ASSERT(end <= string->length());
4444  isolate->counters()->sub_string_runtime()->Increment();
4445
4446  return *isolate->factory()->NewSubString(string, start, end);
4447}
4448
4449
4450RUNTIME_FUNCTION(Runtime_InternalizeString) {
4451  HandleScope handles(isolate);
4452  RUNTIME_ASSERT(args.length() == 1);
4453  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
4454  return *isolate->factory()->InternalizeString(string);
4455}
4456
4457
4458RUNTIME_FUNCTION(Runtime_StringMatch) {
4459  HandleScope handles(isolate);
4460  DCHECK(args.length() == 3);
4461
4462  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4463  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4464  CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
4465
4466  RUNTIME_ASSERT(regexp_info->HasFastObjectElements());
4467
4468  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4469  if (global_cache.HasException()) return isolate->heap()->exception();
4470
4471  int capture_count = regexp->CaptureCount();
4472
4473  ZoneScope zone_scope(isolate->runtime_zone());
4474  ZoneList<int> offsets(8, zone_scope.zone());
4475
4476  while (true) {
4477    int32_t* match = global_cache.FetchNext();
4478    if (match == NULL) break;
4479    offsets.Add(match[0], zone_scope.zone());  // start
4480    offsets.Add(match[1], zone_scope.zone());  // end
4481  }
4482
4483  if (global_cache.HasException()) return isolate->heap()->exception();
4484
4485  if (offsets.length() == 0) {
4486    // Not a single match.
4487    return isolate->heap()->null_value();
4488  }
4489
4490  RegExpImpl::SetLastMatchInfo(regexp_info,
4491                               subject,
4492                               capture_count,
4493                               global_cache.LastSuccessfulMatch());
4494
4495  int matches = offsets.length() / 2;
4496  Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
4497  Handle<String> substring =
4498      isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
4499  elements->set(0, *substring);
4500  for (int i = 1; i < matches; i++) {
4501    HandleScope temp_scope(isolate);
4502    int from = offsets.at(i * 2);
4503    int to = offsets.at(i * 2 + 1);
4504    Handle<String> substring =
4505        isolate->factory()->NewProperSubString(subject, from, to);
4506    elements->set(i, *substring);
4507  }
4508  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
4509  result->set_length(Smi::FromInt(matches));
4510  return *result;
4511}
4512
4513
4514// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4515// separate last match info.  See comment on that function.
4516template<bool has_capture>
4517static Object* SearchRegExpMultiple(
4518    Isolate* isolate,
4519    Handle<String> subject,
4520    Handle<JSRegExp> regexp,
4521    Handle<JSArray> last_match_array,
4522    Handle<JSArray> result_array) {
4523  DCHECK(subject->IsFlat());
4524  DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
4525
4526  int capture_count = regexp->CaptureCount();
4527  int subject_length = subject->length();
4528
4529  static const int kMinLengthToCache = 0x1000;
4530
4531  if (subject_length > kMinLengthToCache) {
4532    Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4533        isolate->heap(),
4534        *subject,
4535        regexp->data(),
4536        RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
4537    if (*cached_answer != Smi::FromInt(0)) {
4538      Handle<FixedArray> cached_fixed_array =
4539          Handle<FixedArray>(FixedArray::cast(*cached_answer));
4540      // The cache FixedArray is a COW-array and can therefore be reused.
4541      JSArray::SetContent(result_array, cached_fixed_array);
4542      // The actual length of the result array is stored in the last element of
4543      // the backing store (the backing FixedArray may have a larger capacity).
4544      Object* cached_fixed_array_last_element =
4545          cached_fixed_array->get(cached_fixed_array->length() - 1);
4546      Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4547      result_array->set_length(js_array_length);
4548      RegExpImpl::SetLastMatchInfo(
4549          last_match_array, subject, capture_count, NULL);
4550      return *result_array;
4551    }
4552  }
4553
4554  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4555  if (global_cache.HasException()) return isolate->heap()->exception();
4556
4557  // Ensured in Runtime_RegExpExecMultiple.
4558  DCHECK(result_array->HasFastObjectElements());
4559  Handle<FixedArray> result_elements(
4560      FixedArray::cast(result_array->elements()));
4561  if (result_elements->length() < 16) {
4562    result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4563  }
4564
4565  FixedArrayBuilder builder(result_elements);
4566
4567  // Position to search from.
4568  int match_start = -1;
4569  int match_end = 0;
4570  bool first = true;
4571
4572  // Two smis before and after the match, for very long strings.
4573  static const int kMaxBuilderEntriesPerRegExpMatch = 5;
4574
4575  while (true) {
4576    int32_t* current_match = global_cache.FetchNext();
4577    if (current_match == NULL) break;
4578    match_start = current_match[0];
4579    builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
4580    if (match_end < match_start) {
4581      ReplacementStringBuilder::AddSubjectSlice(&builder,
4582                                                match_end,
4583                                                match_start);
4584    }
4585    match_end = current_match[1];
4586    {
4587      // Avoid accumulating new handles inside loop.
4588      HandleScope temp_scope(isolate);
4589      Handle<String> match;
4590      if (!first) {
4591        match = isolate->factory()->NewProperSubString(subject,
4592                                                       match_start,
4593                                                       match_end);
4594      } else {
4595        match = isolate->factory()->NewSubString(subject,
4596                                                 match_start,
4597                                                 match_end);
4598        first = false;
4599      }
4600
4601      if (has_capture) {
4602        // Arguments array to replace function is match, captures, index and
4603        // subject, i.e., 3 + capture count in total.
4604        Handle<FixedArray> elements =
4605            isolate->factory()->NewFixedArray(3 + capture_count);
4606
4607        elements->set(0, *match);
4608        for (int i = 1; i <= capture_count; i++) {
4609          int start = current_match[i * 2];
4610          if (start >= 0) {
4611            int end = current_match[i * 2 + 1];
4612            DCHECK(start <= end);
4613            Handle<String> substring =
4614                isolate->factory()->NewSubString(subject, start, end);
4615            elements->set(i, *substring);
4616          } else {
4617            DCHECK(current_match[i * 2 + 1] < 0);
4618            elements->set(i, isolate->heap()->undefined_value());
4619          }
4620        }
4621        elements->set(capture_count + 1, Smi::FromInt(match_start));
4622        elements->set(capture_count + 2, *subject);
4623        builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
4624      } else {
4625        builder.Add(*match);
4626      }
4627    }
4628  }
4629
4630  if (global_cache.HasException()) return isolate->heap()->exception();
4631
4632  if (match_start >= 0) {
4633    // Finished matching, with at least one match.
4634    if (match_end < subject_length) {
4635      ReplacementStringBuilder::AddSubjectSlice(&builder,
4636                                                match_end,
4637                                                subject_length);
4638    }
4639
4640    RegExpImpl::SetLastMatchInfo(
4641        last_match_array, subject, capture_count, NULL);
4642
4643    if (subject_length > kMinLengthToCache) {
4644      // Store the length of the result array into the last element of the
4645      // backing FixedArray.
4646      builder.EnsureCapacity(1);
4647      Handle<FixedArray> fixed_array = builder.array();
4648      fixed_array->set(fixed_array->length() - 1,
4649                       Smi::FromInt(builder.length()));
4650      // Cache the result and turn the FixedArray into a COW array.
4651      RegExpResultsCache::Enter(isolate,
4652                                subject,
4653                                handle(regexp->data(), isolate),
4654                                fixed_array,
4655                                RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4656    }
4657    return *builder.ToJSArray(result_array);
4658  } else {
4659    return isolate->heap()->null_value();  // No matches at all.
4660  }
4661}
4662
4663
4664// This is only called for StringReplaceGlobalRegExpWithFunction.  This sets
4665// lastMatchInfoOverride to maintain the last match info, so we don't need to
4666// set any other last match array info.
4667RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
4668  HandleScope handles(isolate);
4669  DCHECK(args.length() == 4);
4670
4671  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
4672  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4673  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4674  CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
4675  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
4676  RUNTIME_ASSERT(result_array->HasFastObjectElements());
4677
4678  subject = String::Flatten(subject);
4679  RUNTIME_ASSERT(regexp->GetFlags().is_global());
4680
4681  if (regexp->CaptureCount() == 0) {
4682    return SearchRegExpMultiple<false>(
4683        isolate, subject, regexp, last_match_info, result_array);
4684  } else {
4685    return SearchRegExpMultiple<true>(
4686        isolate, subject, regexp, last_match_info, result_array);
4687  }
4688}
4689
4690
4691RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
4692  HandleScope scope(isolate);
4693  DCHECK(args.length() == 2);
4694  CONVERT_SMI_ARG_CHECKED(radix, 1);
4695  RUNTIME_ASSERT(2 <= radix && radix <= 36);
4696
4697  // Fast case where the result is a one character string.
4698  if (args[0]->IsSmi()) {
4699    int value = args.smi_at(0);
4700    if (value >= 0 && value < radix) {
4701      // Character array used for conversion.
4702      static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
4703      return *isolate->factory()->
4704          LookupSingleCharacterStringFromCode(kCharTable[value]);
4705    }
4706  }
4707
4708  // Slow case.
4709  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4710  if (std::isnan(value)) {
4711    return isolate->heap()->nan_string();
4712  }
4713  if (std::isinf(value)) {
4714    if (value < 0) {
4715      return isolate->heap()->minus_infinity_string();
4716    }
4717    return isolate->heap()->infinity_string();
4718  }
4719  char* str = DoubleToRadixCString(value, radix);
4720  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4721  DeleteArray(str);
4722  return *result;
4723}
4724
4725
4726RUNTIME_FUNCTION(Runtime_NumberToFixed) {
4727  HandleScope scope(isolate);
4728  DCHECK(args.length() == 2);
4729
4730  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4731  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4732  int f = FastD2IChecked(f_number);
4733  // See DoubleToFixedCString for these constants:
4734  RUNTIME_ASSERT(f >= 0 && f <= 20);
4735  RUNTIME_ASSERT(!Double(value).IsSpecial());
4736  char* str = DoubleToFixedCString(value, f);
4737  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4738  DeleteArray(str);
4739  return *result;
4740}
4741
4742
4743RUNTIME_FUNCTION(Runtime_NumberToExponential) {
4744  HandleScope scope(isolate);
4745  DCHECK(args.length() == 2);
4746
4747  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4748  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4749  int f = FastD2IChecked(f_number);
4750  RUNTIME_ASSERT(f >= -1 && f <= 20);
4751  RUNTIME_ASSERT(!Double(value).IsSpecial());
4752  char* str = DoubleToExponentialCString(value, f);
4753  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4754  DeleteArray(str);
4755  return *result;
4756}
4757
4758
4759RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
4760  HandleScope scope(isolate);
4761  DCHECK(args.length() == 2);
4762
4763  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4764  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4765  int f = FastD2IChecked(f_number);
4766  RUNTIME_ASSERT(f >= 1 && f <= 21);
4767  RUNTIME_ASSERT(!Double(value).IsSpecial());
4768  char* str = DoubleToPrecisionCString(value, f);
4769  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4770  DeleteArray(str);
4771  return *result;
4772}
4773
4774
4775RUNTIME_FUNCTION(Runtime_IsValidSmi) {
4776  SealHandleScope shs(isolate);
4777  DCHECK(args.length() == 1);
4778
4779  CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4780  return isolate->heap()->ToBoolean(Smi::IsValid(number));
4781}
4782
4783
4784// Returns a single character string where first character equals
4785// string->Get(index).
4786static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4787  if (index < static_cast<uint32_t>(string->length())) {
4788    Factory* factory = string->GetIsolate()->factory();
4789    return factory->LookupSingleCharacterStringFromCode(
4790        String::Flatten(string)->Get(index));
4791  }
4792  return Execution::CharAt(string, index);
4793}
4794
4795
4796MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
4797                                                Handle<Object> object,
4798                                                uint32_t index) {
4799  // Handle [] indexing on Strings
4800  if (object->IsString()) {
4801    Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4802    if (!result->IsUndefined()) return result;
4803  }
4804
4805  // Handle [] indexing on String objects
4806  if (object->IsStringObjectWithCharacterAt(index)) {
4807    Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4808    Handle<Object> result =
4809        GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4810    if (!result->IsUndefined()) return result;
4811  }
4812
4813  Handle<Object> result;
4814  if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
4815    PrototypeIterator iter(isolate, object);
4816    return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
4817                              index);
4818  } else {
4819    return Object::GetElement(isolate, object, index);
4820  }
4821}
4822
4823
4824MUST_USE_RESULT
4825static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
4826  if (key->IsName()) {
4827    return Handle<Name>::cast(key);
4828  } else {
4829    Handle<Object> converted;
4830    ASSIGN_RETURN_ON_EXCEPTION(
4831        isolate, converted, Execution::ToString(isolate, key), Name);
4832    return Handle<Name>::cast(converted);
4833  }
4834}
4835
4836
4837MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
4838                                               Handle<JSReceiver> object,
4839                                               Handle<Object> key) {
4840  Maybe<bool> maybe;
4841  // Check if the given key is an array index.
4842  uint32_t index;
4843  if (key->ToArrayIndex(&index)) {
4844    maybe = JSReceiver::HasElement(object, index);
4845  } else {
4846    // Convert the key to a name - possibly by calling back into JavaScript.
4847    Handle<Name> name;
4848    ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
4849
4850    maybe = JSReceiver::HasProperty(object, name);
4851  }
4852
4853  if (!maybe.has_value) return MaybeHandle<Object>();
4854  return isolate->factory()->ToBoolean(maybe.value);
4855}
4856
4857
4858MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
4859                                               Handle<Object> object,
4860                                               Handle<Object> key) {
4861  if (object->IsUndefined() || object->IsNull()) {
4862    Handle<Object> args[2] = { key, object };
4863    THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
4864                                          HandleVector(args, 2)),
4865                    Object);
4866  }
4867
4868  // Check if the given key is an array index.
4869  uint32_t index;
4870  if (key->ToArrayIndex(&index)) {
4871    return GetElementOrCharAt(isolate, object, index);
4872  }
4873
4874  // Convert the key to a name - possibly by calling back into JavaScript.
4875  Handle<Name> name;
4876  ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
4877
4878  // Check if the name is trivially convertible to an index and get
4879  // the element if so.
4880  if (name->AsArrayIndex(&index)) {
4881    return GetElementOrCharAt(isolate, object, index);
4882  } else {
4883    return Object::GetProperty(object, name);
4884  }
4885}
4886
4887
4888RUNTIME_FUNCTION(Runtime_GetProperty) {
4889  HandleScope scope(isolate);
4890  DCHECK(args.length() == 2);
4891
4892  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
4893  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
4894  Handle<Object> result;
4895  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
4896      isolate, result,
4897      Runtime::GetObjectProperty(isolate, object, key));
4898  return *result;
4899}
4900
4901
4902// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
4903RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
4904  HandleScope scope(isolate);
4905  DCHECK(args.length() == 2);
4906
4907  CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
4908  CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);