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.
10 #include "accessors.h"
11 #include "allocation-site-scopes.h"
13 #include "arguments.h"
14 #include "bootstrapper.h"
16 #include "compilation-cache.h"
18 #include "conversions.h"
20 #include "cpu-profiler.h"
21 #include "dateparser-inl.h"
23 #include "deoptimizer.h"
25 #include "execution.h"
26 #include "full-codegen.h"
27 #include "global-handles.h"
28 #include "isolate-inl.h"
30 #include "jsregexp-inl.h"
31 #include "json-parser.h"
32 #include "json-stringifier.h"
34 #include "misc-intrinsics.h"
37 #include "runtime-profiler.h"
39 #include "scopeinfo.h"
40 #include "smart-pointers.h"
41 #include "string-search.h"
42 #include "stub-cache.h"
44 #include "v8threads.h"
45 #include "vm-state-inl.h"
47 #ifdef V8_I18N_SUPPORT
49 #include "unicode/brkiter.h"
50 #include "unicode/calendar.h"
51 #include "unicode/coll.h"
52 #include "unicode/curramt.h"
53 #include "unicode/datefmt.h"
54 #include "unicode/dcfmtsym.h"
55 #include "unicode/decimfmt.h"
56 #include "unicode/dtfmtsym.h"
57 #include "unicode/dtptngen.h"
58 #include "unicode/locid.h"
59 #include "unicode/numfmt.h"
60 #include "unicode/numsys.h"
61 #include "unicode/rbbi.h"
62 #include "unicode/smpdtfmt.h"
63 #include "unicode/timezone.h"
64 #include "unicode/uchar.h"
65 #include "unicode/ucol.h"
66 #include "unicode/ucurr.h"
67 #include "unicode/uloc.h"
68 #include "unicode/unum.h"
69 #include "unicode/uversion.h"
72 #ifndef _STLP_VENDOR_CSTD
73 // STLPort doesn't import fpclassify and isless into the std namespace.
74 using std::fpclassify;
82 #define RUNTIME_ASSERT(value) \
83 if (!(value)) return isolate->ThrowIllegalOperation();
85 #define RUNTIME_ASSERT_HANDLIFIED(value, T) \
87 isolate->ThrowIllegalOperation(); \
88 return MaybeHandle<T>(); \
91 // Cast the given object to a value of the specified type and store
92 // it in a variable with the given name. If the object is not of the
93 // expected type call IllegalOperation and return.
94 #define CONVERT_ARG_CHECKED(Type, name, index) \
95 RUNTIME_ASSERT(args[index]->Is##Type()); \
96 Type* name = Type::cast(args[index]);
98 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
99 RUNTIME_ASSERT(args[index]->Is##Type()); \
100 Handle<Type> name = args.at<Type>(index);
102 #define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \
103 RUNTIME_ASSERT(args[index]->IsNumber()); \
104 Handle<Object> name = args.at<Object>(index);
106 // Cast the given object to a boolean and store it in a variable with
107 // the given name. If the object is not a boolean call IllegalOperation
109 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
110 RUNTIME_ASSERT(args[index]->IsBoolean()); \
111 bool name = args[index]->IsTrue();
113 // Cast the given argument to a Smi and store its value in an int variable
114 // with the given name. If the argument is not a Smi call IllegalOperation
116 #define CONVERT_SMI_ARG_CHECKED(name, index) \
117 RUNTIME_ASSERT(args[index]->IsSmi()); \
118 int name = args.smi_at(index);
120 // Cast the given argument to a double and store it in a variable with
121 // the given name. If the argument is not a number (as opposed to
122 // the number not-a-number) call IllegalOperation and return.
123 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
124 RUNTIME_ASSERT(args[index]->IsNumber()); \
125 double name = args.number_at(index);
127 // Call the specified converter on the object *comand store the result in
128 // a variable of the specified type with the given name. If the
129 // object is not a Number call IllegalOperation and return.
130 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
131 RUNTIME_ASSERT(obj->IsNumber()); \
132 type name = NumberTo##Type(obj);
135 // Cast the given argument to PropertyDetails and store its value in a
136 // variable with the given name. If the argument is not a Smi call
137 // IllegalOperation and return.
138 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
139 RUNTIME_ASSERT(args[index]->IsSmi()); \
140 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
143 // Assert that the given argument has a valid value for a StrictMode
144 // and store it in a StrictMode variable with the given name.
145 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
146 RUNTIME_ASSERT(args[index]->IsSmi()); \
147 RUNTIME_ASSERT(args.smi_at(index) == STRICT || \
148 args.smi_at(index) == SLOPPY); \
149 StrictMode name = static_cast<StrictMode>(args.smi_at(index));
152 static Handle<Map> ComputeObjectLiteralMap(
153 Handle<Context> context,
154 Handle<FixedArray> constant_properties,
155 bool* is_result_from_cache) {
156 Isolate* isolate = context->GetIsolate();
157 int properties_length = constant_properties->length();
158 int number_of_properties = properties_length / 2;
159 // Check that there are only internal strings and array indices among keys.
160 int number_of_string_keys = 0;
161 for (int p = 0; p != properties_length; p += 2) {
162 Object* key = constant_properties->get(p);
163 uint32_t element_index = 0;
164 if (key->IsInternalizedString()) {
165 number_of_string_keys++;
166 } else if (key->ToArrayIndex(&element_index)) {
167 // An index key does not require space in the property backing store.
168 number_of_properties--;
170 // Bail out as a non-internalized-string non-index key makes caching
172 // ASSERT to make sure that the if condition after the loop is false.
173 ASSERT(number_of_string_keys != number_of_properties);
177 // If we only have internalized strings and array indices among keys then we
178 // can use the map cache in the native context.
179 const int kMaxKeys = 10;
180 if ((number_of_string_keys == number_of_properties) &&
181 (number_of_string_keys < kMaxKeys)) {
182 // Create the fixed array with the key.
183 Handle<FixedArray> keys =
184 isolate->factory()->NewFixedArray(number_of_string_keys);
185 if (number_of_string_keys > 0) {
187 for (int p = 0; p < properties_length; p += 2) {
188 Object* key = constant_properties->get(p);
189 if (key->IsInternalizedString()) {
190 keys->set(index++, key);
193 ASSERT(index == number_of_string_keys);
195 *is_result_from_cache = true;
196 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
198 *is_result_from_cache = false;
199 return Map::Create(handle(context->object_function()), number_of_properties);
203 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
205 Handle<FixedArray> literals,
206 Handle<FixedArray> constant_properties);
209 MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
211 Handle<FixedArray> literals,
212 Handle<FixedArray> constant_properties,
213 bool should_have_fast_elements,
214 bool has_function_literal) {
215 // Get the native context from the literals array. This is the
216 // context in which the function was created and we use the object
217 // function from this context to create the object literal. We do
218 // not use the object function from the current native context
219 // because this might be the object function from another context
220 // which we should not have access to.
221 Handle<Context> context =
222 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
224 // In case we have function literals, we want the object to be in
225 // slow properties mode for now. We don't go in the map cache because
226 // maps with constant functions can't be shared if the functions are
227 // not the same (which is the common case).
228 bool is_result_from_cache = false;
229 Handle<Map> map = has_function_literal
230 ? Handle<Map>(context->object_function()->initial_map())
231 : ComputeObjectLiteralMap(context,
233 &is_result_from_cache);
235 PretenureFlag pretenure_flag =
236 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
238 Handle<JSObject> boilerplate =
239 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
241 // Normalize the elements of the boilerplate to save space if needed.
242 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
244 // Add the constant properties to the boilerplate.
245 int length = constant_properties->length();
246 bool should_transform =
247 !is_result_from_cache && boilerplate->HasFastProperties();
248 if (should_transform || has_function_literal) {
249 // Normalize the properties of object to avoid n^2 behavior
250 // when extending the object multiple properties. Indicate the number of
251 // properties to be added.
252 JSObject::NormalizeProperties(
253 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
256 // TODO(verwaest): Support tracking representations in the boilerplate.
257 for (int index = 0; index < length; index +=2) {
258 Handle<Object> key(constant_properties->get(index+0), isolate);
259 Handle<Object> value(constant_properties->get(index+1), isolate);
260 if (value->IsFixedArray()) {
261 // The value contains the constant_properties of a
262 // simple object or array literal.
263 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
264 ASSIGN_RETURN_ON_EXCEPTION(
266 CreateLiteralBoilerplate(isolate, literals, array),
269 MaybeHandle<Object> maybe_result;
270 uint32_t element_index = 0;
271 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT;
272 if (key->IsInternalizedString()) {
273 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
274 // Array index as string (uint32).
275 maybe_result = JSObject::SetOwnElement(
276 boilerplate, element_index, value, SLOPPY);
278 Handle<String> name(String::cast(*key));
279 ASSERT(!name->AsArrayIndex(&element_index));
280 maybe_result = JSObject::SetLocalPropertyIgnoreAttributes(
281 boilerplate, name, value, NONE,
282 Object::OPTIMAL_REPRESENTATION, mode);
284 } else if (key->ToArrayIndex(&element_index)) {
285 // Array index (uint32).
286 maybe_result = JSObject::SetOwnElement(
287 boilerplate, element_index, value, SLOPPY);
289 // Non-uint32 number.
290 ASSERT(key->IsNumber());
291 double num = key->Number();
293 Vector<char> buffer(arr, ARRAY_SIZE(arr));
294 const char* str = DoubleToCString(num, buffer);
295 Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str);
296 maybe_result = JSObject::SetLocalPropertyIgnoreAttributes(
297 boilerplate, name, value, NONE,
298 Object::OPTIMAL_REPRESENTATION, mode);
300 // If setting the property on the boilerplate throws an
301 // exception, the exception is converted to an empty handle in
302 // the handle based operations. In that case, we need to
303 // convert back to an exception.
304 RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
307 // Transform to fast properties if necessary. For object literals with
308 // containing function literals we defer this operation until after all
309 // computed properties have been assigned so that we can generate
310 // constant function properties.
311 if (should_transform && !has_function_literal) {
312 JSObject::TransformToFastProperties(
313 boilerplate, boilerplate->map()->unused_property_fields());
320 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
321 Handle<Object> object,
322 ElementsKind to_kind,
324 HandleScope scope(isolate);
325 if (!object->IsJSObject()) {
326 isolate->ThrowIllegalOperation();
327 return MaybeHandle<Object>();
329 ElementsKind from_kind =
330 Handle<JSObject>::cast(object)->map()->elements_kind();
331 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
332 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
335 isolate->ThrowIllegalOperation();
336 return MaybeHandle<Object>();
340 static const int kSmiLiteralMinimumLength = 1024;
343 MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
345 Handle<FixedArray> literals,
346 Handle<FixedArray> elements) {
347 // Create the JSArray.
348 Handle<JSFunction> constructor(
349 JSFunction::NativeContextFromLiterals(*literals)->array_function());
351 PretenureFlag pretenure_flag =
352 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
354 Handle<JSArray> object = Handle<JSArray>::cast(
355 isolate->factory()->NewJSObject(constructor, pretenure_flag));
357 ElementsKind constant_elements_kind =
358 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
359 Handle<FixedArrayBase> constant_elements_values(
360 FixedArrayBase::cast(elements->get(1)));
362 { DisallowHeapAllocation no_gc;
363 ASSERT(IsFastElementsKind(constant_elements_kind));
364 Context* native_context = isolate->context()->native_context();
365 Object* maps_array = native_context->js_array_maps();
366 ASSERT(!maps_array->IsUndefined());
367 Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind);
368 object->set_map(Map::cast(map));
371 Handle<FixedArrayBase> copied_elements_values;
372 if (IsFastDoubleElementsKind(constant_elements_kind)) {
373 ASSERT(FLAG_smi_only_arrays);
374 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
375 Handle<FixedDoubleArray>::cast(constant_elements_values));
377 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
379 (constant_elements_values->map() ==
380 isolate->heap()->fixed_cow_array_map());
382 copied_elements_values = constant_elements_values;
384 Handle<FixedArray> fixed_array_values =
385 Handle<FixedArray>::cast(copied_elements_values);
386 for (int i = 0; i < fixed_array_values->length(); i++) {
387 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
391 Handle<FixedArray> fixed_array_values =
392 Handle<FixedArray>::cast(constant_elements_values);
393 Handle<FixedArray> fixed_array_values_copy =
394 isolate->factory()->CopyFixedArray(fixed_array_values);
395 copied_elements_values = fixed_array_values_copy;
396 for (int i = 0; i < fixed_array_values->length(); i++) {
397 if (fixed_array_values->get(i)->IsFixedArray()) {
398 // The value contains the constant_properties of a
399 // simple object or array literal.
400 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
401 Handle<Object> result;
402 ASSIGN_RETURN_ON_EXCEPTION(
404 CreateLiteralBoilerplate(isolate, literals, fa),
406 fixed_array_values_copy->set(i, *result);
411 object->set_elements(*copied_elements_values);
412 object->set_length(Smi::FromInt(copied_elements_values->length()));
414 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
415 // on or the object is larger than the threshold.
416 if (!FLAG_smi_only_arrays &&
417 constant_elements_values->length() < kSmiLiteralMinimumLength) {
418 ElementsKind elements_kind = object->GetElementsKind();
419 if (!IsFastObjectElementsKind(elements_kind)) {
420 if (IsFastHoleyElementsKind(elements_kind)) {
421 TransitionElements(object, FAST_HOLEY_ELEMENTS, isolate).Check();
423 TransitionElements(object, FAST_ELEMENTS, isolate).Check();
428 JSObject::ValidateElements(object);
433 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
435 Handle<FixedArray> literals,
436 Handle<FixedArray> array) {
437 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
438 const bool kHasNoFunctionLiteral = false;
439 switch (CompileTimeValue::GetLiteralType(array)) {
440 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
441 return CreateObjectLiteralBoilerplate(isolate,
445 kHasNoFunctionLiteral);
446 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
447 return CreateObjectLiteralBoilerplate(isolate,
451 kHasNoFunctionLiteral);
452 case CompileTimeValue::ARRAY_LITERAL:
453 return Runtime::CreateArrayLiteralBoilerplate(
454 isolate, literals, elements);
457 return MaybeHandle<Object>();
462 RUNTIME_FUNCTION(RuntimeHidden_CreateObjectLiteral) {
463 HandleScope scope(isolate);
464 ASSERT(args.length() == 4);
465 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
466 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
467 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
468 CONVERT_SMI_ARG_CHECKED(flags, 3);
469 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
470 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
472 RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
474 // Check if boilerplate exists. If not, create it first.
475 Handle<Object> literal_site(literals->get(literals_index), isolate);
476 Handle<AllocationSite> site;
477 Handle<JSObject> boilerplate;
478 if (*literal_site == isolate->heap()->undefined_value()) {
479 Handle<Object> raw_boilerplate;
480 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
481 isolate, raw_boilerplate,
482 CreateObjectLiteralBoilerplate(
486 should_have_fast_elements,
487 has_function_literal));
488 boilerplate = Handle<JSObject>::cast(raw_boilerplate);
490 AllocationSiteCreationContext creation_context(isolate);
491 site = creation_context.EnterNewScope();
492 RETURN_FAILURE_ON_EXCEPTION(
494 JSObject::DeepWalk(boilerplate, &creation_context));
495 creation_context.ExitScope(site, boilerplate);
497 // Update the functions literal and return the boilerplate.
498 literals->set(literals_index, *site);
500 site = Handle<AllocationSite>::cast(literal_site);
501 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
505 AllocationSiteUsageContext usage_context(isolate, site, true);
506 usage_context.EnterNewScope();
507 MaybeHandle<Object> maybe_copy = JSObject::DeepCopy(
508 boilerplate, &usage_context);
509 usage_context.ExitScope(site, boilerplate);
511 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy);
516 MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
518 Handle<FixedArray> literals,
520 Handle<FixedArray> elements) {
521 // Check if boilerplate exists. If not, create it first.
522 Handle<Object> literal_site(literals->get(literals_index), isolate);
523 Handle<AllocationSite> site;
524 if (*literal_site == isolate->heap()->undefined_value()) {
525 ASSERT(*elements != isolate->heap()->empty_fixed_array());
526 Handle<Object> boilerplate;
527 ASSIGN_RETURN_ON_EXCEPTION(
528 isolate, boilerplate,
529 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements),
532 AllocationSiteCreationContext creation_context(isolate);
533 site = creation_context.EnterNewScope();
534 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
535 &creation_context).is_null()) {
536 return Handle<AllocationSite>::null();
538 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
540 literals->set(literals_index, *site);
542 site = Handle<AllocationSite>::cast(literal_site);
549 static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate,
550 Handle<FixedArray> literals,
552 Handle<FixedArray> elements,
554 RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 &&
555 literals_index < literals->length(), JSObject);
556 Handle<AllocationSite> site;
557 ASSIGN_RETURN_ON_EXCEPTION(
559 GetLiteralAllocationSite(isolate, literals, literals_index, elements),
562 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
563 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
564 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
565 usage_context.EnterNewScope();
566 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
568 : JSObject::kObjectIsShallowArray;
569 MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
571 usage_context.ExitScope(site, boilerplate);
576 RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteral) {
577 HandleScope scope(isolate);
578 ASSERT(args.length() == 4);
579 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
580 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
581 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
582 CONVERT_SMI_ARG_CHECKED(flags, 3);
584 Handle<JSObject> result;
585 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
586 CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
592 RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteralStubBailout) {
593 HandleScope scope(isolate);
594 ASSERT(args.length() == 3);
595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
599 Handle<JSObject> result;
600 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
601 CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
602 ArrayLiteral::kShallowElements));
607 RUNTIME_FUNCTION(Runtime_CreateSymbol) {
608 HandleScope scope(isolate);
609 ASSERT(args.length() == 1);
610 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
611 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
612 Handle<Symbol> symbol = isolate->factory()->NewSymbol();
613 if (name->IsString()) symbol->set_name(*name);
618 RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) {
619 HandleScope scope(isolate);
620 ASSERT(args.length() == 1);
621 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
622 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
623 Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol();
624 if (name->IsString()) symbol->set_name(*name);
629 RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateSymbol) {
630 HandleScope scope(isolate);
631 ASSERT(args.length() == 1);
632 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
633 Handle<JSObject> registry = isolate->GetSymbolRegistry();
634 Handle<String> part = isolate->factory()->private_intern_string();
635 Handle<Object> privates;
636 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
637 isolate, privates, Object::GetPropertyOrElement(registry, part));
638 Handle<Object> symbol;
639 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
640 isolate, symbol, Object::GetPropertyOrElement(privates, name));
641 if (!symbol->IsSymbol()) {
642 ASSERT(symbol->IsUndefined());
643 symbol = isolate->factory()->NewPrivateSymbol();
644 Handle<Symbol>::cast(symbol)->set_name(*name);
645 JSObject::SetProperty(Handle<JSObject>::cast(privates),
646 name, symbol, NONE, STRICT).Assert();
652 RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
653 HandleScope scope(isolate);
654 ASSERT(args.length() == 1);
655 CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
656 return *Object::ToObject(isolate, symbol).ToHandleChecked();
660 RUNTIME_FUNCTION(Runtime_SymbolDescription) {
661 SealHandleScope shs(isolate);
662 ASSERT(args.length() == 1);
663 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
664 return symbol->name();
668 RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
669 HandleScope scope(isolate);
670 ASSERT(args.length() == 0);
671 return *isolate->GetSymbolRegistry();
675 RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) {
676 SealHandleScope shs(isolate);
677 ASSERT(args.length() == 1);
678 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
679 return isolate->heap()->ToBoolean(symbol->is_private());
683 RUNTIME_FUNCTION(Runtime_CreateJSProxy) {
684 HandleScope scope(isolate);
685 ASSERT(args.length() == 2);
686 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
687 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
688 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
689 return *isolate->factory()->NewJSProxy(handler, prototype);
693 RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
694 HandleScope scope(isolate);
695 ASSERT(args.length() == 4);
696 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
697 CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1);
698 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
699 CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2);
700 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3);
701 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
702 return *isolate->factory()->NewJSFunctionProxy(
703 handler, call_trap, construct_trap, prototype);
707 RUNTIME_FUNCTION(Runtime_IsJSProxy) {
708 SealHandleScope shs(isolate);
709 ASSERT(args.length() == 1);
710 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
711 return isolate->heap()->ToBoolean(obj->IsJSProxy());
715 RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) {
716 SealHandleScope shs(isolate);
717 ASSERT(args.length() == 1);
718 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
719 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
723 RUNTIME_FUNCTION(Runtime_GetHandler) {
724 SealHandleScope shs(isolate);
725 ASSERT(args.length() == 1);
726 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
727 return proxy->handler();
731 RUNTIME_FUNCTION(Runtime_GetCallTrap) {
732 SealHandleScope shs(isolate);
733 ASSERT(args.length() == 1);
734 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
735 return proxy->call_trap();
739 RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
740 SealHandleScope shs(isolate);
741 ASSERT(args.length() == 1);
742 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
743 return proxy->construct_trap();
747 RUNTIME_FUNCTION(Runtime_Fix) {
748 HandleScope scope(isolate);
749 ASSERT(args.length() == 1);
750 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
752 return isolate->heap()->undefined_value();
756 void Runtime::FreeArrayBuffer(Isolate* isolate,
757 JSArrayBuffer* phantom_array_buffer) {
758 if (phantom_array_buffer->should_be_freed()) {
759 ASSERT(phantom_array_buffer->is_external());
760 free(phantom_array_buffer->backing_store());
762 if (phantom_array_buffer->is_external()) return;
764 size_t allocated_length = NumberToSize(
765 isolate, phantom_array_buffer->byte_length());
767 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
768 -static_cast<int64_t>(allocated_length));
769 CHECK(V8::ArrayBufferAllocator() != NULL);
770 V8::ArrayBufferAllocator()->Free(
771 phantom_array_buffer->backing_store(),
776 void Runtime::SetupArrayBuffer(Isolate* isolate,
777 Handle<JSArrayBuffer> array_buffer,
780 size_t allocated_length) {
781 ASSERT(array_buffer->GetInternalFieldCount() ==
782 v8::ArrayBuffer::kInternalFieldCount);
783 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
784 array_buffer->SetInternalField(i, Smi::FromInt(0));
786 array_buffer->set_backing_store(data);
787 array_buffer->set_flag(Smi::FromInt(0));
788 array_buffer->set_is_external(is_external);
790 Handle<Object> byte_length =
791 isolate->factory()->NewNumberFromSize(allocated_length);
792 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
793 array_buffer->set_byte_length(*byte_length);
795 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
796 isolate->heap()->set_array_buffers_list(*array_buffer);
797 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
801 bool Runtime::SetupArrayBufferAllocatingData(
803 Handle<JSArrayBuffer> array_buffer,
804 size_t allocated_length,
807 CHECK(V8::ArrayBufferAllocator() != NULL);
808 if (allocated_length != 0) {
810 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
813 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
815 if (data == NULL) return false;
820 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
822 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
828 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
829 Isolate* isolate = array_buffer->GetIsolate();
830 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
831 !view_obj->IsUndefined();) {
832 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
833 if (view->IsJSTypedArray()) {
834 JSTypedArray::cast(*view)->Neuter();
835 } else if (view->IsJSDataView()) {
836 JSDataView::cast(*view)->Neuter();
840 view_obj = handle(view->weak_next(), isolate);
842 array_buffer->Neuter();
846 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
847 HandleScope scope(isolate);
848 ASSERT(args.length() == 2);
849 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
850 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
851 if (!holder->byte_length()->IsUndefined()) {
852 // ArrayBuffer is already initialized; probably a fuzz test.
855 size_t allocated_length = 0;
856 if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
857 return isolate->Throw(
858 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
859 HandleVector<Object>(NULL, 0)));
861 if (!Runtime::SetupArrayBufferAllocatingData(isolate,
862 holder, allocated_length)) {
863 return isolate->Throw(
864 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
865 HandleVector<Object>(NULL, 0)));
871 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
872 SealHandleScope shs(isolate);
873 ASSERT(args.length() == 1);
874 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
875 return holder->byte_length();
879 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
880 HandleScope scope(isolate);
881 ASSERT(args.length() == 3);
882 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
883 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
884 CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
886 RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
887 size_t target_length = NumberToSize(isolate, target->byte_length());
889 if (target_length == 0) return isolate->heap()->undefined_value();
891 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
892 RUNTIME_ASSERT(start <= source_byte_length);
893 RUNTIME_ASSERT(source_byte_length - start >= target_length);
894 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
895 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
896 CopyBytes(target_data, source_data + start, target_length);
897 return isolate->heap()->undefined_value();
901 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
902 HandleScope scope(isolate);
903 ASSERT(args.length() == 1);
904 CONVERT_ARG_CHECKED(Object, object, 0);
905 return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
909 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
910 HandleScope scope(isolate);
911 ASSERT(args.length() == 1);
912 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
913 if (array_buffer->backing_store() == NULL) {
914 CHECK(Smi::FromInt(0) == array_buffer->byte_length());
915 return isolate->heap()->undefined_value();
917 ASSERT(!array_buffer->is_external());
918 void* backing_store = array_buffer->backing_store();
919 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
920 array_buffer->set_is_external(true);
921 Runtime::NeuterArrayBuffer(array_buffer);
922 V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
923 return isolate->heap()->undefined_value();
927 void Runtime::ArrayIdToTypeAndSize(
929 ExternalArrayType* array_type,
930 ElementsKind* external_elements_kind,
931 ElementsKind* fixed_elements_kind,
932 size_t* element_size) {
934 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
935 case ARRAY_ID_##TYPE: \
936 *array_type = kExternal##Type##Array; \
937 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
938 *fixed_elements_kind = TYPE##_ELEMENTS; \
939 *element_size = size; \
942 TYPED_ARRAYS(ARRAY_ID_CASE)
951 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
952 HandleScope scope(isolate);
953 ASSERT(args.length() == 5);
954 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
955 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
956 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
957 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
958 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
960 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
961 arrayId <= Runtime::ARRAY_ID_LAST);
962 RUNTIME_ASSERT(maybe_buffer->IsNull() || maybe_buffer->IsJSArrayBuffer());
964 ASSERT(holder->GetInternalFieldCount() ==
965 v8::ArrayBufferView::kInternalFieldCount);
966 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
967 holder->SetInternalField(i, Smi::FromInt(0));
970 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
971 size_t element_size = 1; // Bogus initialization.
972 ElementsKind external_elements_kind =
973 EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
974 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
975 Runtime::ArrayIdToTypeAndSize(arrayId,
977 &external_elements_kind,
978 &fixed_elements_kind,
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));
986 holder->set_byte_offset(*byte_offset_object);
987 holder->set_byte_length(*byte_length_object);
989 CHECK_EQ(0, static_cast<int>(byte_length % element_size));
990 size_t length = byte_length / element_size;
992 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
993 return isolate->Throw(
994 *isolate->factory()->NewRangeError("invalid_typed_array_length",
995 HandleVector<Object>(NULL, 0)));
998 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
999 holder->set_length(*length_obj);
1000 if (!maybe_buffer->IsNull()) {
1001 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(*maybe_buffer));
1003 size_t array_buffer_byte_length =
1004 NumberToSize(isolate, buffer->byte_length());
1005 RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
1006 RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
1008 holder->set_buffer(*buffer);
1009 holder->set_weak_next(buffer->weak_first_view());
1010 buffer->set_weak_first_view(*holder);
1012 Handle<ExternalArray> elements =
1013 isolate->factory()->NewExternalArray(
1014 static_cast<int>(length), array_type,
1015 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
1017 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
1018 JSObject::SetMapAndElements(holder, map, elements);
1019 ASSERT(IsExternalArrayElementsKind(holder->map()->elements_kind()));
1021 holder->set_buffer(Smi::FromInt(0));
1022 holder->set_weak_next(isolate->heap()->undefined_value());
1023 Handle<FixedTypedArrayBase> elements =
1024 isolate->factory()->NewFixedTypedArray(
1025 static_cast<int>(length), array_type);
1026 holder->set_elements(*elements);
1028 return isolate->heap()->undefined_value();
1032 // Initializes a typed array from an array-like object.
1033 // If an array-like object happens to be a typed array of the same type,
1034 // initializes backing store using memove.
1036 // Returns true if backing store was initialized or false otherwise.
1037 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
1038 HandleScope scope(isolate);
1039 ASSERT(args.length() == 4);
1040 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
1041 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
1042 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
1043 CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
1045 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
1046 arrayId <= Runtime::ARRAY_ID_LAST);
1048 ASSERT(holder->GetInternalFieldCount() ==
1049 v8::ArrayBufferView::kInternalFieldCount);
1050 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1051 holder->SetInternalField(i, Smi::FromInt(0));
1054 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
1055 size_t element_size = 1; // Bogus initialization.
1056 ElementsKind external_elements_kind =
1057 EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
1058 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
1059 Runtime::ArrayIdToTypeAndSize(arrayId,
1061 &external_elements_kind,
1062 &fixed_elements_kind,
1065 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
1066 if (source->IsJSTypedArray() &&
1067 JSTypedArray::cast(*source)->type() == array_type) {
1068 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
1071 RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
1073 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
1074 (length > (kMaxInt / element_size))) {
1075 return isolate->Throw(*isolate->factory()->
1076 NewRangeError("invalid_typed_array_length",
1077 HandleVector<Object>(NULL, 0)));
1079 size_t byte_length = length * element_size;
1081 // NOTE: not initializing backing store.
1082 // We assume that the caller of this function will initialize holder
1084 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
1085 // We assume that the caller of this function is always a typed array
1087 // If source is a typed array, this loop will always run to completion,
1088 // so we are sure that the backing store will be initialized.
1089 // Otherwise, the indexing operation might throw, so the loop will not
1090 // run to completion and the typed array might remain partly initialized.
1091 // However we further assume that the caller of this function is a typed array
1092 // constructor, and the exception will propagate out of the constructor,
1093 // therefore uninitialized memory will not be accessible by a user program.
1095 // TODO(dslomov): revise this once we support subclassing.
1097 if (!Runtime::SetupArrayBufferAllocatingData(
1098 isolate, buffer, byte_length, false)) {
1099 return isolate->Throw(*isolate->factory()->
1100 NewRangeError("invalid_array_buffer_length",
1101 HandleVector<Object>(NULL, 0)));
1104 holder->set_buffer(*buffer);
1105 holder->set_byte_offset(Smi::FromInt(0));
1106 Handle<Object> byte_length_obj(
1107 isolate->factory()->NewNumberFromSize(byte_length));
1108 holder->set_byte_length(*byte_length_obj);
1109 holder->set_length(*length_obj);
1110 holder->set_weak_next(buffer->weak_first_view());
1111 buffer->set_weak_first_view(*holder);
1113 Handle<ExternalArray> elements =
1114 isolate->factory()->NewExternalArray(
1115 static_cast<int>(length), array_type,
1116 static_cast<uint8_t*>(buffer->backing_store()));
1117 Handle<Map> map = JSObject::GetElementsTransitionMap(
1118 holder, external_elements_kind);
1119 JSObject::SetMapAndElements(holder, map, elements);
1121 if (source->IsJSTypedArray()) {
1122 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1124 if (typed_array->type() == holder->type()) {
1125 uint8_t* backing_store =
1126 static_cast<uint8_t*>(
1127 typed_array->GetBuffer()->backing_store());
1128 size_t source_byte_offset =
1129 NumberToSize(isolate, typed_array->byte_offset());
1131 buffer->backing_store(),
1132 backing_store + source_byte_offset,
1134 return isolate->heap()->true_value();
1138 return isolate->heap()->false_value();
1142 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
1143 RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
1144 HandleScope scope(isolate); \
1145 ASSERT(args.length() == 1); \
1146 CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
1147 return holder->accessor(); \
1150 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
1151 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
1152 BUFFER_VIEW_GETTER(TypedArray, Length, length)
1153 BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
1155 #undef BUFFER_VIEW_GETTER
1157 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
1158 HandleScope scope(isolate);
1159 ASSERT(args.length() == 1);
1160 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
1161 return *holder->GetBuffer();
1165 // Return codes for Runtime_TypedArraySetFastCases.
1166 // Should be synchronized with typedarray.js natives.
1167 enum TypedArraySetResultCodes {
1168 // Set from typed array of the same type.
1169 // This is processed by TypedArraySetFastCases
1170 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1171 // Set from typed array of the different type, overlapping in memory.
1172 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1173 // Set from typed array of the different type, non-overlapping.
1174 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1175 // Set from non-typed array.
1176 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1180 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
1181 HandleScope scope(isolate);
1182 ASSERT(args.length() == 3);
1183 if (!args[0]->IsJSTypedArray())
1184 return isolate->Throw(*isolate->factory()->NewTypeError(
1185 "not_typed_array", HandleVector<Object>(NULL, 0)));
1187 if (!args[1]->IsJSTypedArray())
1188 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
1190 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
1191 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
1192 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
1194 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1195 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1197 RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
1198 size_t target_length = NumberToSize(isolate, target->length());
1199 size_t source_length = NumberToSize(isolate, source->length());
1200 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1201 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1202 if (offset > target_length ||
1203 offset + source_length > target_length ||
1204 offset + source_length < offset) // overflow
1205 return isolate->Throw(*isolate->factory()->NewRangeError(
1206 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
1208 size_t target_offset = NumberToSize(isolate, target->byte_offset());
1209 size_t source_offset = NumberToSize(isolate, source->byte_offset());
1210 uint8_t* target_base =
1211 static_cast<uint8_t*>(
1212 target->GetBuffer()->backing_store()) + target_offset;
1213 uint8_t* source_base =
1214 static_cast<uint8_t*>(
1215 source->GetBuffer()->backing_store()) + source_offset;
1217 // Typed arrays of the same type: use memmove.
1218 if (target->type() == source->type()) {
1219 memmove(target_base + offset * target->element_size(),
1220 source_base, source_byte_length);
1221 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
1224 // Typed arrays of different types over the same backing store
1225 if ((source_base <= target_base &&
1226 source_base + source_byte_length > target_base) ||
1227 (target_base <= source_base &&
1228 target_base + target_byte_length > source_base)) {
1229 // We do not support overlapping ArrayBuffers
1231 target->GetBuffer()->backing_store() ==
1232 source->GetBuffer()->backing_store());
1233 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
1234 } else { // Non-overlapping typed arrays
1235 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
1240 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
1241 ASSERT(args.length() == 0);
1243 FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset);
1244 return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
1248 RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
1249 HandleScope scope(isolate);
1250 ASSERT(args.length() == 4);
1251 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1252 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1253 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
1254 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
1256 ASSERT(holder->GetInternalFieldCount() ==
1257 v8::ArrayBufferView::kInternalFieldCount);
1258 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1259 holder->SetInternalField(i, Smi::FromInt(0));
1261 size_t buffer_length = 0;
1265 TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
1266 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
1267 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
1269 // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
1270 // Entire range [offset, offset + length] must be in bounds.
1271 RUNTIME_ASSERT(offset <= buffer_length);
1272 RUNTIME_ASSERT(offset + length <= buffer_length);
1274 RUNTIME_ASSERT(offset + length >= offset);
1276 holder->set_buffer(*buffer);
1277 holder->set_byte_offset(*byte_offset);
1278 holder->set_byte_length(*byte_length);
1280 holder->set_weak_next(buffer->weak_first_view());
1281 buffer->set_weak_first_view(*holder);
1283 return isolate->heap()->undefined_value();
1287 inline static bool NeedToFlipBytes(bool is_little_endian) {
1288 #ifdef V8_TARGET_LITTLE_ENDIAN
1289 return !is_little_endian;
1291 return is_little_endian;
1297 inline void CopyBytes(uint8_t* target, uint8_t* source) {
1298 for (int i = 0; i < n; i++) {
1299 *(target++) = *(source++);
1305 inline void FlipBytes(uint8_t* target, uint8_t* source) {
1306 source = source + (n-1);
1307 for (int i = 0; i < n; i++) {
1308 *(target++) = *(source--);
1313 template<typename T>
1314 inline static bool DataViewGetValue(
1316 Handle<JSDataView> data_view,
1317 Handle<Object> byte_offset_obj,
1318 bool is_little_endian,
1320 size_t byte_offset = 0;
1321 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1324 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1326 size_t data_view_byte_offset =
1327 NumberToSize(isolate, data_view->byte_offset());
1328 size_t data_view_byte_length =
1329 NumberToSize(isolate, data_view->byte_length());
1330 if (byte_offset + sizeof(T) > data_view_byte_length ||
1331 byte_offset + sizeof(T) < byte_offset) { // overflow
1337 uint8_t bytes[sizeof(T)];
1341 size_t buffer_offset = data_view_byte_offset + byte_offset;
1343 NumberToSize(isolate, buffer->byte_length())
1344 >= buffer_offset + sizeof(T));
1346 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1347 if (NeedToFlipBytes(is_little_endian)) {
1348 FlipBytes<sizeof(T)>(value.bytes, source);
1350 CopyBytes<sizeof(T)>(value.bytes, source);
1352 *result = value.data;
1357 template<typename T>
1358 static bool DataViewSetValue(
1360 Handle<JSDataView> data_view,
1361 Handle<Object> byte_offset_obj,
1362 bool is_little_endian,
1364 size_t byte_offset = 0;
1365 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1368 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1370 size_t data_view_byte_offset =
1371 NumberToSize(isolate, data_view->byte_offset());
1372 size_t data_view_byte_length =
1373 NumberToSize(isolate, data_view->byte_length());
1374 if (byte_offset + sizeof(T) > data_view_byte_length ||
1375 byte_offset + sizeof(T) < byte_offset) { // overflow
1381 uint8_t bytes[sizeof(T)];
1386 size_t buffer_offset = data_view_byte_offset + byte_offset;
1388 NumberToSize(isolate, buffer->byte_length())
1389 >= buffer_offset + sizeof(T));
1391 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1392 if (NeedToFlipBytes(is_little_endian)) {
1393 FlipBytes<sizeof(T)>(target, value.bytes);
1395 CopyBytes<sizeof(T)>(target, value.bytes);
1401 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
1402 RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \
1403 HandleScope scope(isolate); \
1404 ASSERT(args.length() == 3); \
1405 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1406 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1407 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
1409 if (DataViewGetValue( \
1410 isolate, holder, offset, is_little_endian, &result)) { \
1411 return *isolate->factory()->Converter(result); \
1413 return isolate->Throw(*isolate->factory()->NewRangeError( \
1414 "invalid_data_view_accessor_offset", \
1415 HandleVector<Object>(NULL, 0))); \
1419 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
1420 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
1421 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
1422 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
1423 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
1424 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
1425 DATA_VIEW_GETTER(Float32, float, NewNumber)
1426 DATA_VIEW_GETTER(Float64, double, NewNumber)
1428 #undef DATA_VIEW_GETTER
1431 template <typename T>
1432 static T DataViewConvertValue(double value);
1436 int8_t DataViewConvertValue<int8_t>(double value) {
1437 return static_cast<int8_t>(DoubleToInt32(value));
1442 int16_t DataViewConvertValue<int16_t>(double value) {
1443 return static_cast<int16_t>(DoubleToInt32(value));
1448 int32_t DataViewConvertValue<int32_t>(double value) {
1449 return DoubleToInt32(value);
1454 uint8_t DataViewConvertValue<uint8_t>(double value) {
1455 return static_cast<uint8_t>(DoubleToUint32(value));
1460 uint16_t DataViewConvertValue<uint16_t>(double value) {
1461 return static_cast<uint16_t>(DoubleToUint32(value));
1466 uint32_t DataViewConvertValue<uint32_t>(double value) {
1467 return DoubleToUint32(value);
1472 float DataViewConvertValue<float>(double value) {
1473 return static_cast<float>(value);
1478 double DataViewConvertValue<double>(double value) {
1483 #define DATA_VIEW_SETTER(TypeName, Type) \
1484 RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \
1485 HandleScope scope(isolate); \
1486 ASSERT(args.length() == 4); \
1487 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1488 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1489 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
1490 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
1491 Type v = DataViewConvertValue<Type>(value->Number()); \
1492 if (DataViewSetValue( \
1493 isolate, holder, offset, is_little_endian, v)) { \
1494 return isolate->heap()->undefined_value(); \
1496 return isolate->Throw(*isolate->factory()->NewRangeError( \
1497 "invalid_data_view_accessor_offset", \
1498 HandleVector<Object>(NULL, 0))); \
1502 DATA_VIEW_SETTER(Uint8, uint8_t)
1503 DATA_VIEW_SETTER(Int8, int8_t)
1504 DATA_VIEW_SETTER(Uint16, uint16_t)
1505 DATA_VIEW_SETTER(Int16, int16_t)
1506 DATA_VIEW_SETTER(Uint32, uint32_t)
1507 DATA_VIEW_SETTER(Int32, int32_t)
1508 DATA_VIEW_SETTER(Float32, float)
1509 DATA_VIEW_SETTER(Float64, double)
1511 #undef DATA_VIEW_SETTER
1514 RUNTIME_FUNCTION(Runtime_SetInitialize) {
1515 HandleScope scope(isolate);
1516 ASSERT(args.length() == 1);
1517 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1518 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
1519 holder->set_table(*table);
1524 RUNTIME_FUNCTION(Runtime_SetAdd) {
1525 HandleScope scope(isolate);
1526 ASSERT(args.length() == 2);
1527 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1528 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1529 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1530 table = OrderedHashSet::Add(table, key);
1531 holder->set_table(*table);
1532 return isolate->heap()->undefined_value();
1536 RUNTIME_FUNCTION(Runtime_SetHas) {
1537 HandleScope scope(isolate);
1538 ASSERT(args.length() == 2);
1539 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1540 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1541 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1542 return isolate->heap()->ToBoolean(table->Contains(key));
1546 RUNTIME_FUNCTION(Runtime_SetDelete) {
1547 HandleScope scope(isolate);
1548 ASSERT(args.length() == 2);
1549 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1550 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1551 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1552 table = OrderedHashSet::Remove(table, key);
1553 holder->set_table(*table);
1554 return isolate->heap()->undefined_value();
1558 RUNTIME_FUNCTION(Runtime_SetClear) {
1559 HandleScope scope(isolate);
1560 ASSERT(args.length() == 1);
1561 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1562 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1563 table = OrderedHashSet::Clear(table);
1564 holder->set_table(*table);
1565 return isolate->heap()->undefined_value();
1569 RUNTIME_FUNCTION(Runtime_SetGetSize) {
1570 HandleScope scope(isolate);
1571 ASSERT(args.length() == 1);
1572 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1573 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1574 return Smi::FromInt(table->NumberOfElements());
1578 RUNTIME_FUNCTION(Runtime_SetCreateIterator) {
1579 HandleScope scope(isolate);
1580 ASSERT(args.length() == 2);
1581 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1582 CONVERT_SMI_ARG_CHECKED(kind, 1)
1583 RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
1584 kind == JSSetIterator::kKindEntries);
1585 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
1586 return *JSSetIterator::Create(table, kind);
1590 RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
1591 HandleScope scope(isolate);
1592 ASSERT(args.length() == 1);
1593 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
1594 return *JSSetIterator::Next(holder);
1598 RUNTIME_FUNCTION(Runtime_SetIteratorClose) {
1599 HandleScope scope(isolate);
1600 ASSERT(args.length() == 1);
1601 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
1603 return isolate->heap()->undefined_value();
1607 RUNTIME_FUNCTION(Runtime_MapInitialize) {
1608 HandleScope scope(isolate);
1609 ASSERT(args.length() == 1);
1610 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1611 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
1612 holder->set_table(*table);
1617 RUNTIME_FUNCTION(Runtime_MapGet) {
1618 HandleScope scope(isolate);
1619 ASSERT(args.length() == 2);
1620 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1621 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1622 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1623 Handle<Object> lookup(table->Lookup(key), isolate);
1624 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1628 RUNTIME_FUNCTION(Runtime_MapHas) {
1629 HandleScope scope(isolate);
1630 ASSERT(args.length() == 2);
1631 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1632 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1633 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1634 Handle<Object> lookup(table->Lookup(key), isolate);
1635 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1639 RUNTIME_FUNCTION(Runtime_MapDelete) {
1640 HandleScope scope(isolate);
1641 ASSERT(args.length() == 2);
1642 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1643 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1644 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1645 Handle<Object> lookup(table->Lookup(key), isolate);
1646 Handle<OrderedHashMap> new_table =
1647 OrderedHashMap::Put(table, key, isolate->factory()->the_hole_value());
1648 holder->set_table(*new_table);
1649 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1653 RUNTIME_FUNCTION(Runtime_MapClear) {
1654 HandleScope scope(isolate);
1655 ASSERT(args.length() == 1);
1656 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1657 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1658 table = OrderedHashMap::Clear(table);
1659 holder->set_table(*table);
1660 return isolate->heap()->undefined_value();
1664 RUNTIME_FUNCTION(Runtime_MapSet) {
1665 HandleScope scope(isolate);
1666 ASSERT(args.length() == 3);
1667 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1668 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1669 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1670 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1671 Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value);
1672 holder->set_table(*new_table);
1673 return isolate->heap()->undefined_value();
1677 RUNTIME_FUNCTION(Runtime_MapGetSize) {
1678 HandleScope scope(isolate);
1679 ASSERT(args.length() == 1);
1680 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1681 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1682 return Smi::FromInt(table->NumberOfElements());
1686 RUNTIME_FUNCTION(Runtime_MapCreateIterator) {
1687 HandleScope scope(isolate);
1688 ASSERT(args.length() == 2);
1689 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1690 CONVERT_SMI_ARG_CHECKED(kind, 1)
1691 RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys
1692 || kind == JSMapIterator::kKindValues
1693 || kind == JSMapIterator::kKindEntries);
1694 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
1695 return *JSMapIterator::Create(table, kind);
1699 RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
1700 HandleScope scope(isolate);
1701 ASSERT(args.length() == 1);
1702 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
1703 return *JSMapIterator::Next(holder);
1707 RUNTIME_FUNCTION(Runtime_MapIteratorClose) {
1708 HandleScope scope(isolate);
1709 ASSERT(args.length() == 1);
1710 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
1712 return isolate->heap()->undefined_value();
1716 static Handle<JSWeakCollection> WeakCollectionInitialize(
1718 Handle<JSWeakCollection> weak_collection) {
1719 ASSERT(weak_collection->map()->inobject_properties() == 0);
1720 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
1721 weak_collection->set_table(*table);
1722 weak_collection->set_next(Smi::FromInt(0));
1723 return weak_collection;
1727 RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
1728 HandleScope scope(isolate);
1729 ASSERT(args.length() == 1);
1730 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1731 return *WeakCollectionInitialize(isolate, weak_collection);
1735 RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
1736 HandleScope scope(isolate);
1737 ASSERT(args.length() == 2);
1738 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1739 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1740 Handle<ObjectHashTable> table(
1741 ObjectHashTable::cast(weak_collection->table()));
1742 Handle<Object> lookup(table->Lookup(key), isolate);
1743 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1747 RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
1748 HandleScope scope(isolate);
1749 ASSERT(args.length() == 2);
1750 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1751 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1752 Handle<ObjectHashTable> table(
1753 ObjectHashTable::cast(weak_collection->table()));
1754 Handle<Object> lookup(table->Lookup(key), isolate);
1755 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1759 RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
1760 HandleScope scope(isolate);
1761 ASSERT(args.length() == 2);
1762 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1763 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1764 Handle<ObjectHashTable> table(ObjectHashTable::cast(
1765 weak_collection->table()));
1766 Handle<Object> lookup(table->Lookup(key), isolate);
1767 Handle<ObjectHashTable> new_table =
1768 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
1769 weak_collection->set_table(*new_table);
1770 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1774 RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
1775 HandleScope scope(isolate);
1776 ASSERT(args.length() == 3);
1777 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1778 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1779 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1780 Handle<ObjectHashTable> table(
1781 ObjectHashTable::cast(weak_collection->table()));
1782 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1783 weak_collection->set_table(*new_table);
1784 return isolate->heap()->undefined_value();
1788 RUNTIME_FUNCTION(Runtime_ClassOf) {
1789 SealHandleScope shs(isolate);
1790 ASSERT(args.length() == 1);
1791 CONVERT_ARG_CHECKED(Object, obj, 0);
1792 if (!obj->IsJSObject()) return isolate->heap()->null_value();
1793 return JSObject::cast(obj)->class_name();
1797 RUNTIME_FUNCTION(Runtime_GetPrototype) {
1798 HandleScope scope(isolate);
1799 ASSERT(args.length() == 1);
1800 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
1801 // We don't expect access checks to be needed on JSProxy objects.
1802 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
1804 if (obj->IsAccessCheckNeeded() &&
1805 !isolate->MayNamedAccess(Handle<JSObject>::cast(obj),
1806 isolate->factory()->proto_string(),
1808 isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(obj),
1810 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1811 return isolate->heap()->undefined_value();
1813 obj = Object::GetPrototype(isolate, obj);
1814 } while (obj->IsJSObject() &&
1815 JSObject::cast(*obj)->map()->is_hidden_prototype());
1820 static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
1821 Isolate* isolate, Handle<Object> receiver) {
1822 Handle<Object> current = Object::GetPrototype(isolate, receiver);
1823 while (current->IsJSObject() &&
1824 JSObject::cast(*current)->map()->is_hidden_prototype()) {
1825 current = Object::GetPrototype(isolate, current);
1831 RUNTIME_FUNCTION(Runtime_SetPrototype) {
1832 HandleScope scope(isolate);
1833 ASSERT(args.length() == 2);
1834 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1835 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
1836 if (obj->IsAccessCheckNeeded() &&
1837 !isolate->MayNamedAccess(
1838 obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) {
1839 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
1840 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1841 return isolate->heap()->undefined_value();
1843 if (obj->map()->is_observed()) {
1844 Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
1845 Handle<Object> result;
1846 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1848 JSObject::SetPrototype(obj, prototype, true));
1850 Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
1851 if (!new_value->SameValue(*old_value)) {
1852 JSObject::EnqueueChangeRecord(obj, "setPrototype",
1853 isolate->factory()->proto_string(),
1858 Handle<Object> result;
1859 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1861 JSObject::SetPrototype(obj, prototype, true));
1866 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
1867 HandleScope shs(isolate);
1868 ASSERT(args.length() == 2);
1869 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1870 CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
1871 CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
1873 Handle<Object> prototype = Object::GetPrototype(isolate, V);
1874 if (prototype->IsNull()) return isolate->heap()->false_value();
1875 if (*O == *prototype) return isolate->heap()->true_value();
1881 static bool CheckAccessException(Object* callback,
1882 v8::AccessType access_type) {
1883 DisallowHeapAllocation no_gc;
1884 ASSERT(!callback->IsForeign());
1885 if (callback->IsAccessorInfo()) {
1886 AccessorInfo* info = AccessorInfo::cast(callback);
1888 (access_type == v8::ACCESS_HAS &&
1889 (info->all_can_read() || info->all_can_write())) ||
1890 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1891 (access_type == v8::ACCESS_SET && info->all_can_write());
1893 if (callback->IsAccessorPair()) {
1894 AccessorPair* info = AccessorPair::cast(callback);
1896 (access_type == v8::ACCESS_HAS &&
1897 (info->all_can_read() || info->all_can_write())) ||
1898 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1899 (access_type == v8::ACCESS_SET && info->all_can_write());
1906 static bool CheckGenericAccess(
1907 Handle<JSObject> receiver,
1908 Handle<JSObject> holder,
1910 v8::AccessType access_type,
1911 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) {
1912 Isolate* isolate = receiver->GetIsolate();
1913 for (Handle<JSObject> current = receiver;
1915 current = handle(JSObject::cast(current->GetPrototype()), isolate)) {
1916 if (current->IsAccessCheckNeeded() &&
1917 !(isolate->*mayAccess)(current, key, access_type)) {
1920 if (current.is_identical_to(holder)) break;
1926 enum AccessCheckResult {
1933 static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj,
1935 v8::AccessType access_type) {
1937 if (name->AsArrayIndex(&index)) {
1938 // TODO(1095): we should traverse hidden prototype hierachy as well.
1939 if (CheckGenericAccess(
1940 obj, obj, index, access_type, &Isolate::MayIndexedAccess)) {
1941 return ACCESS_ALLOWED;
1944 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1945 return ACCESS_FORBIDDEN;
1948 Isolate* isolate = obj->GetIsolate();
1949 LookupResult lookup(isolate);
1950 obj->LocalLookup(name, &lookup, true);
1952 if (!lookup.IsProperty()) return ACCESS_ABSENT;
1953 Handle<JSObject> holder(lookup.holder(), isolate);
1954 if (CheckGenericAccess<Handle<Object> >(
1955 obj, holder, name, access_type, &Isolate::MayNamedAccess)) {
1956 return ACCESS_ALLOWED;
1959 // Access check callback denied the access, but some properties
1960 // can have a special permissions which override callbacks descision
1961 // (currently see v8::AccessControl).
1962 // API callbacks can have per callback access exceptions.
1963 switch (lookup.type()) {
1965 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1966 return ACCESS_ALLOWED;
1970 // If the object has an interceptor, try real named properties.
1971 // Overwrite the result to fetch the correct property later.
1972 holder->LookupRealNamedProperty(name, &lookup);
1973 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1974 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1975 return ACCESS_ALLOWED;
1983 isolate->ReportFailedAccessCheck(obj, access_type);
1984 return ACCESS_FORBIDDEN;
1988 // Enumerator used as indices into the array returned from GetOwnProperty
1989 enum PropertyDescriptorIndices {
2001 MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
2002 Handle<JSObject> obj,
2003 Handle<Name> name) {
2004 Heap* heap = isolate->heap();
2005 Factory* factory = isolate->factory();
2006 // Due to some WebKit tests, we want to make sure that we do not log
2007 // more than one access failure here.
2008 AccessCheckResult access_check_result =
2009 CheckPropertyAccess(obj, name, v8::ACCESS_HAS);
2010 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2011 switch (access_check_result) {
2012 case ACCESS_FORBIDDEN: return factory->false_value();
2013 case ACCESS_ALLOWED: break;
2014 case ACCESS_ABSENT: return factory->undefined_value();
2017 PropertyAttributes attrs = JSReceiver::GetLocalPropertyAttribute(obj, name);
2018 if (attrs == ABSENT) {
2019 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2020 return factory->undefined_value();
2022 ASSERT(!isolate->has_scheduled_exception());
2023 Handle<AccessorPair> accessors;
2024 bool has_accessors =
2025 JSObject::GetLocalPropertyAccessorPair(obj, name).ToHandle(&accessors);
2026 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
2027 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
2028 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
2029 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(has_accessors));
2031 if (!has_accessors) {
2032 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
2033 // Runtime::GetObjectProperty does access check.
2034 Handle<Object> value;
2035 ASSIGN_RETURN_ON_EXCEPTION(
2036 isolate, value, Runtime::GetObjectProperty(isolate, obj, name),
2038 elms->set(VALUE_INDEX, *value);
2040 // Access checks are performed for both accessors separately.
2041 // When they fail, the respective field is not set in the descriptor.
2042 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
2043 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
2045 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) {
2046 ASSERT(!isolate->has_scheduled_exception());
2047 elms->set(GETTER_INDEX, *getter);
2049 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2052 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) {
2053 ASSERT(!isolate->has_scheduled_exception());
2054 elms->set(SETTER_INDEX, *setter);
2056 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2060 return isolate->factory()->NewJSArrayWithElements(elms);
2064 // Returns an array with the property description:
2065 // if args[1] is not a property on args[0]
2066 // returns undefined
2067 // if args[1] is a data property on args[0]
2068 // [false, value, Writeable, Enumerable, Configurable]
2069 // if args[1] is an accessor on args[0]
2070 // [true, GetFunction, SetFunction, Enumerable, Configurable]
2071 RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
2072 HandleScope scope(isolate);
2073 ASSERT(args.length() == 2);
2074 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2075 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2076 Handle<Object> result;
2077 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2078 isolate, result, GetOwnProperty(isolate, obj, name));
2083 RUNTIME_FUNCTION(Runtime_PreventExtensions) {
2084 HandleScope scope(isolate);
2085 ASSERT(args.length() == 1);
2086 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2087 Handle<Object> result;
2088 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2089 isolate, result, JSObject::PreventExtensions(obj));
2094 RUNTIME_FUNCTION(Runtime_IsExtensible) {
2095 SealHandleScope shs(isolate);
2096 ASSERT(args.length() == 1);
2097 CONVERT_ARG_CHECKED(JSObject, obj, 0);
2098 if (obj->IsJSGlobalProxy()) {
2099 Object* proto = obj->GetPrototype();
2100 if (proto->IsNull()) return isolate->heap()->false_value();
2101 ASSERT(proto->IsJSGlobalObject());
2102 obj = JSObject::cast(proto);
2104 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
2108 RUNTIME_FUNCTION(Runtime_RegExpCompile) {
2109 HandleScope scope(isolate);
2110 ASSERT(args.length() == 3);
2111 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
2112 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
2113 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
2114 Handle<Object> result;
2115 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2116 isolate, result, RegExpImpl::Compile(re, pattern, flags));
2121 RUNTIME_FUNCTION(Runtime_CreateApiFunction) {
2122 HandleScope scope(isolate);
2123 ASSERT(args.length() == 2);
2124 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
2125 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
2126 return *isolate->factory()->CreateApiFunction(data, prototype);
2130 RUNTIME_FUNCTION(Runtime_IsTemplate) {
2131 SealHandleScope shs(isolate);
2132 ASSERT(args.length() == 1);
2133 CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0);
2134 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
2135 return isolate->heap()->ToBoolean(result);
2139 RUNTIME_FUNCTION(Runtime_GetTemplateField) {
2140 SealHandleScope shs(isolate);
2141 ASSERT(args.length() == 2);
2142 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
2143 CONVERT_SMI_ARG_CHECKED(index, 1);
2144 int offset = index * kPointerSize + HeapObject::kHeaderSize;
2145 InstanceType type = templ->map()->instance_type();
2146 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
2147 type == OBJECT_TEMPLATE_INFO_TYPE);
2148 RUNTIME_ASSERT(offset > 0);
2149 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
2150 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
2152 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
2154 return *HeapObject::RawField(templ, offset);
2158 RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
2159 HandleScope scope(isolate);
2160 ASSERT(args.length() == 1);
2161 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
2162 Handle<Map> old_map(object->map());
2163 bool needs_access_checks = old_map->is_access_check_needed();
2164 if (needs_access_checks) {
2165 // Copy map so it won't interfere constructor's initial map.
2166 Handle<Map> new_map = Map::Copy(old_map);
2167 new_map->set_is_access_check_needed(false);
2168 if (object->IsJSObject()) {
2169 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
2171 object->set_map(*new_map);
2174 return isolate->heap()->ToBoolean(needs_access_checks);
2178 RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
2179 HandleScope scope(isolate);
2180 ASSERT(args.length() == 1);
2181 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
2182 Handle<Map> old_map(object->map());
2183 if (!old_map->is_access_check_needed()) {
2184 // Copy map so it won't interfere constructor's initial map.
2185 Handle<Map> new_map = Map::Copy(old_map);
2186 new_map->set_is_access_check_needed(true);
2187 if (object->IsJSObject()) {
2188 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
2190 object->set_map(*new_map);
2193 return isolate->heap()->undefined_value();
2197 // Transform getter or setter into something DefineAccessor can handle.
2198 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
2199 Handle<Object> component) {
2200 if (component->IsUndefined()) return isolate->factory()->null_value();
2201 Handle<FunctionTemplateInfo> info =
2202 Handle<FunctionTemplateInfo>::cast(component);
2203 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
2207 RUNTIME_FUNCTION(Runtime_SetAccessorProperty) {
2208 HandleScope scope(isolate);
2209 ASSERT(args.length() == 6);
2210 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2211 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2212 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
2213 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
2214 CONVERT_SMI_ARG_CHECKED(attribute, 4);
2215 CONVERT_SMI_ARG_CHECKED(access_control, 5);
2216 RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
2217 RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
2218 RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
2219 static_cast<PropertyAttributes>(attribute)));
2220 JSObject::DefineAccessor(object,
2222 InstantiateAccessorComponent(isolate, getter),
2223 InstantiateAccessorComponent(isolate, setter),
2224 static_cast<PropertyAttributes>(attribute),
2225 static_cast<v8::AccessControl>(access_control));
2226 return isolate->heap()->undefined_value();
2230 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
2231 HandleScope scope(isolate);
2232 Handle<Object> args[1] = { name };
2233 Handle<Object> error = isolate->factory()->NewTypeError(
2234 "var_redeclaration", HandleVector(args, 1));
2235 return isolate->Throw(*error);
2239 RUNTIME_FUNCTION(RuntimeHidden_DeclareGlobals) {
2240 HandleScope scope(isolate);
2241 ASSERT(args.length() == 3);
2242 Handle<GlobalObject> global = Handle<GlobalObject>(
2243 isolate->context()->global_object());
2245 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
2246 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
2247 CONVERT_SMI_ARG_CHECKED(flags, 2);
2249 // Traverse the name/value pairs and set the properties.
2250 int length = pairs->length();
2251 for (int i = 0; i < length; i += 2) {
2252 HandleScope scope(isolate);
2253 Handle<String> name(String::cast(pairs->get(i)));
2254 Handle<Object> value(pairs->get(i + 1), isolate);
2256 // We have to declare a global const property. To capture we only
2257 // assign to it when evaluating the assignment for "const x =
2258 // <expr>" the initial value is the hole.
2259 bool is_var = value->IsUndefined();
2260 bool is_const = value->IsTheHole();
2261 bool is_function = value->IsSharedFunctionInfo();
2262 ASSERT(is_var + is_const + is_function == 1);
2264 if (is_var || is_const) {
2265 // Lookup the property in the global object, and don't set the
2266 // value of the variable if the property is already there.
2267 // Do the lookup locally only, see ES5 erratum.
2268 LookupResult lookup(isolate);
2269 global->LocalLookup(name, &lookup, true);
2270 if (lookup.IsFound()) {
2271 // We found an existing property. Unless it was an interceptor
2272 // that claims the property is absent, skip this declaration.
2273 if (!lookup.IsInterceptor()) continue;
2274 if (JSReceiver::GetPropertyAttribute(global, name) != ABSENT) continue;
2275 // Fall-through and introduce the absent property by using
2278 } else if (is_function) {
2279 // Copy the function and update its context. Use it as value.
2280 Handle<SharedFunctionInfo> shared =
2281 Handle<SharedFunctionInfo>::cast(value);
2282 Handle<JSFunction> function =
2283 isolate->factory()->NewFunctionFromSharedFunctionInfo(
2284 shared, context, TENURED);
2288 LookupResult lookup(isolate);
2289 global->LocalLookup(name, &lookup, true);
2291 // Compute the property attributes. According to ECMA-262,
2292 // the property must be non-configurable except in eval.
2294 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
2296 attr |= DONT_DELETE;
2298 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
2299 if (is_const || (is_native && is_function)) {
2303 StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags);
2305 if (!lookup.IsFound() || is_function) {
2306 // If the local property exists, check that we can reconfigure it
2307 // as required for function declarations.
2308 if (lookup.IsFound() && lookup.IsDontDelete()) {
2309 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
2310 lookup.IsPropertyCallbacks()) {
2311 return ThrowRedeclarationError(isolate, name);
2313 // If the existing property is not configurable, keep its attributes.
2314 attr = lookup.GetAttributes();
2316 // Define or redefine own property.
2317 RETURN_FAILURE_ON_EXCEPTION(isolate,
2318 JSObject::SetLocalPropertyIgnoreAttributes(
2319 global, name, value, static_cast<PropertyAttributes>(attr)));
2321 // Do a [[Put]] on the existing (own) property.
2322 RETURN_FAILURE_ON_EXCEPTION(
2324 JSObject::SetProperty(
2325 global, name, value, static_cast<PropertyAttributes>(attr),
2330 ASSERT(!isolate->has_pending_exception());
2331 return isolate->heap()->undefined_value();
2335 RUNTIME_FUNCTION(RuntimeHidden_DeclareContextSlot) {
2336 HandleScope scope(isolate);
2337 ASSERT(args.length() == 4);
2339 // Declarations are always made in a function or native context. In the
2340 // case of eval code, the context passed is the context of the caller,
2341 // which may be some nested context and not the declaration context.
2342 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
2343 Handle<Context> context(context_arg->declaration_context());
2344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
2345 CONVERT_SMI_ARG_CHECKED(mode_arg, 2);
2346 PropertyAttributes mode = static_cast<PropertyAttributes>(mode_arg);
2347 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
2348 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
2351 PropertyAttributes attributes;
2352 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
2353 BindingFlags binding_flags;
2354 Handle<Object> holder =
2355 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2357 if (attributes != ABSENT) {
2358 // The name was declared before; check for conflicting re-declarations.
2359 // Note: this is actually inconsistent with what happens for globals (where
2360 // we silently ignore such declarations).
2361 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
2362 // Functions are not read-only.
2363 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
2364 return ThrowRedeclarationError(isolate, name);
2367 // Initialize it if necessary.
2368 if (*initial_value != NULL) {
2370 ASSERT(holder.is_identical_to(context));
2371 if (((attributes & READ_ONLY) == 0) ||
2372 context->get(index)->IsTheHole()) {
2373 context->set(index, *initial_value);
2376 // Slow case: The property is in the context extension object of a
2377 // function context or the global object of a native context.
2378 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2379 RETURN_FAILURE_ON_EXCEPTION(
2381 JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY));
2386 // The property is not in the function context. It needs to be
2387 // "declared" in the function context's extension context or as a
2388 // property of the the global object.
2389 Handle<JSObject> object;
2390 if (context->has_extension()) {
2391 object = Handle<JSObject>(JSObject::cast(context->extension()));
2393 // Context extension objects are allocated lazily.
2394 ASSERT(context->IsFunctionContext());
2395 object = isolate->factory()->NewJSObject(
2396 isolate->context_extension_function());
2397 context->set_extension(*object);
2399 ASSERT(*object != NULL);
2401 // Declare the property by setting it to the initial value if provided,
2402 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
2403 // constant declarations).
2404 ASSERT(!JSReceiver::HasLocalProperty(object, name));
2405 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
2406 if (*initial_value != NULL) value = initial_value;
2407 // Declaring a const context slot is a conflicting declaration if
2408 // there is a callback with that name in a prototype. It is
2409 // allowed to introduce const variables in
2410 // JSContextExtensionObjects. They are treated specially in
2411 // SetProperty and no setters are invoked for those since they are
2412 // not real JSObjects.
2413 if (initial_value->IsTheHole() &&
2414 !object->IsJSContextExtensionObject()) {
2415 LookupResult lookup(isolate);
2416 object->Lookup(name, &lookup);
2417 if (lookup.IsPropertyCallbacks()) {
2418 return ThrowRedeclarationError(isolate, name);
2421 if (object->IsJSGlobalObject()) {
2422 // Define own property on the global object.
2423 RETURN_FAILURE_ON_EXCEPTION(isolate,
2424 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
2426 RETURN_FAILURE_ON_EXCEPTION(isolate,
2427 JSReceiver::SetProperty(object, name, value, mode, SLOPPY));
2431 return isolate->heap()->undefined_value();
2435 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
2436 HandleScope scope(isolate);
2438 // args[1] == language_mode
2439 // args[2] == value (optional)
2441 // Determine if we need to assign to the variable if it already
2442 // exists (based on the number of arguments).
2443 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
2444 bool assign = args.length() == 3;
2446 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2447 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
2449 // According to ECMA-262, section 12.2, page 62, the property must
2450 // not be deletable.
2451 PropertyAttributes attributes = DONT_DELETE;
2453 // Lookup the property locally in the global object. If it isn't
2454 // there, there is a property with this name in the prototype chain.
2455 // We follow Safari and Firefox behavior and only set the property
2456 // locally if there is an explicit initialization value that we have
2457 // to assign to the property.
2458 // Note that objects can have hidden prototypes, so we need to traverse
2459 // the whole chain of hidden prototypes to do a 'local' lookup.
2460 LookupResult lookup(isolate);
2461 isolate->context()->global_object()->LocalLookup(name, &lookup, true);
2462 if (lookup.IsInterceptor()) {
2463 Handle<JSObject> holder(lookup.holder());
2464 PropertyAttributes intercepted =
2465 JSReceiver::GetPropertyAttribute(holder, name);
2466 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
2467 // Found an interceptor that's not read only.
2469 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2470 Handle<Object> result;
2471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2473 JSObject::SetPropertyForResult(
2474 holder, &lookup, name, value, attributes, strict_mode));
2477 return isolate->heap()->undefined_value();
2483 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2484 Handle<GlobalObject> global(isolate->context()->global_object());
2485 Handle<Object> result;
2486 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2488 JSReceiver::SetProperty(global, name, value, attributes, strict_mode));
2491 return isolate->heap()->undefined_value();
2495 RUNTIME_FUNCTION(RuntimeHidden_InitializeConstGlobal) {
2496 SealHandleScope shs(isolate);
2497 // All constants are declared with an initial value. The name
2498 // of the constant is the first argument and the initial value
2500 RUNTIME_ASSERT(args.length() == 2);
2501 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2502 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
2504 // Get the current global object from top.
2505 GlobalObject* global = isolate->context()->global_object();
2507 // According to ECMA-262, section 12.2, page 62, the property must
2508 // not be deletable. Since it's a const, it must be READ_ONLY too.
2509 PropertyAttributes attributes =
2510 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2512 // Lookup the property locally in the global object. If it isn't
2513 // there, we add the property and take special precautions to always
2514 // add it as a local property even in case of callbacks in the
2515 // prototype chain (this rules out using SetProperty).
2516 // We use SetLocalPropertyIgnoreAttributes instead
2517 LookupResult lookup(isolate);
2518 global->LocalLookup(name, &lookup);
2519 if (!lookup.IsFound()) {
2520 HandleScope handle_scope(isolate);
2521 Handle<GlobalObject> global(isolate->context()->global_object());
2522 RETURN_FAILURE_ON_EXCEPTION(
2524 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
2529 if (!lookup.IsReadOnly()) {
2530 // Restore global object from context (in case of GC) and continue
2531 // with setting the value.
2532 HandleScope handle_scope(isolate);
2533 Handle<GlobalObject> global(isolate->context()->global_object());
2535 // BUG 1213575: Handle the case where we have to set a read-only
2536 // property through an interceptor and only do it if it's
2537 // uninitialized, e.g. the hole. Nirk...
2538 // Passing sloppy mode because the property is writable.
2539 RETURN_FAILURE_ON_EXCEPTION(
2541 JSReceiver::SetProperty(global, name, value, attributes, SLOPPY));
2545 // Set the value, but only if we're assigning the initial value to a
2546 // constant. For now, we determine this by checking if the
2547 // current value is the hole.
2548 // Strict mode handling not needed (const is disallowed in strict mode).
2549 if (lookup.IsField()) {
2550 FixedArray* properties = global->properties();
2551 int index = lookup.GetFieldIndex().field_index();
2552 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
2553 properties->set(index, *value);
2555 } else if (lookup.IsNormal()) {
2556 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
2557 !lookup.IsReadOnly()) {
2558 HandleScope scope(isolate);
2559 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
2562 // Ignore re-initialization of constants that have already been
2563 // assigned a constant value.
2564 ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
2567 // Use the set value as the result of the operation.
2572 RUNTIME_FUNCTION(RuntimeHidden_InitializeConstContextSlot) {
2573 HandleScope scope(isolate);
2574 ASSERT(args.length() == 3);
2576 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
2577 ASSERT(!value->IsTheHole());
2578 // Initializations are always done in a function or native context.
2579 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
2580 Handle<Context> context(context_arg->declaration_context());
2581 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
2584 PropertyAttributes attributes;
2585 ContextLookupFlags flags = FOLLOW_CHAINS;
2586 BindingFlags binding_flags;
2587 Handle<Object> holder =
2588 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2591 ASSERT(holder->IsContext());
2592 // Property was found in a context. Perform the assignment if we
2593 // found some non-constant or an uninitialized constant.
2594 Handle<Context> context = Handle<Context>::cast(holder);
2595 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
2596 context->set(index, *value);
2601 // The property could not be found, we introduce it as a property of the
2603 if (attributes == ABSENT) {
2604 Handle<JSObject> global = Handle<JSObject>(
2605 isolate->context()->global_object());
2606 // Strict mode not needed (const disallowed in strict mode).
2607 RETURN_FAILURE_ON_EXCEPTION(
2609 JSReceiver::SetProperty(global, name, value, NONE, SLOPPY));
2613 // The property was present in some function's context extension object,
2614 // as a property on the subject of a with, or as a property of the global
2617 // In most situations, eval-introduced consts should still be present in
2618 // the context extension object. However, because declaration and
2619 // initialization are separate, the property might have been deleted
2620 // before we reach the initialization point.
2624 // function f() { eval("delete x; const x;"); }
2626 // In that case, the initialization behaves like a normal assignment.
2627 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2629 if (*object == context->extension()) {
2630 // This is the property that was introduced by the const declaration.
2631 // Set it if it hasn't been set before. NOTE: We cannot use
2632 // GetProperty() to get the current value as it 'unholes' the value.
2633 LookupResult lookup(isolate);
2634 object->LocalLookupRealNamedProperty(name, &lookup);
2635 ASSERT(lookup.IsFound()); // the property was declared
2636 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
2638 if (lookup.IsField()) {
2639 FixedArray* properties = object->properties();
2640 int index = lookup.GetFieldIndex().field_index();
2641 if (properties->get(index)->IsTheHole()) {
2642 properties->set(index, *value);
2644 } else if (lookup.IsNormal()) {
2645 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
2646 JSObject::SetNormalizedProperty(object, &lookup, value);
2649 // We should not reach here. Any real, named property should be
2650 // either a field or a dictionary slot.
2654 // The property was found on some other object. Set it if it is not a
2655 // read-only property.
2656 if ((attributes & READ_ONLY) == 0) {
2657 // Strict mode not needed (const disallowed in strict mode).
2658 RETURN_FAILURE_ON_EXCEPTION(
2660 JSReceiver::SetProperty(object, name, value, attributes, SLOPPY));
2668 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
2669 HandleScope scope(isolate);
2670 ASSERT(args.length() == 2);
2671 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2672 CONVERT_SMI_ARG_CHECKED(properties, 1);
2673 // Conservative upper limit to prevent fuzz tests from going OOM.
2674 RUNTIME_ASSERT(properties <= 100000);
2675 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
2676 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
2682 RUNTIME_FUNCTION(RuntimeHidden_RegExpExec) {
2683 HandleScope scope(isolate);
2684 ASSERT(args.length() == 4);
2685 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2686 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
2687 // Due to the way the JS calls are constructed this must be less than the
2688 // length of a string, i.e. it is always a Smi. We check anyway for security.
2689 CONVERT_SMI_ARG_CHECKED(index, 2);
2690 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
2691 RUNTIME_ASSERT(index >= 0);
2692 RUNTIME_ASSERT(index <= subject->length());
2693 isolate->counters()->regexp_entry_runtime()->Increment();
2694 Handle<Object> result;
2695 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2697 RegExpImpl::Exec(regexp, subject, index, last_match_info));
2702 RUNTIME_FUNCTION(RuntimeHidden_RegExpConstructResult) {
2703 HandleScope handle_scope(isolate);
2704 ASSERT(args.length() == 3);
2705 CONVERT_SMI_ARG_CHECKED(size, 0);
2706 RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength);
2707 CONVERT_ARG_HANDLE_CHECKED(Object, index, 1);
2708 CONVERT_ARG_HANDLE_CHECKED(Object, input, 2);
2709 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size);
2710 Handle<Map> regexp_map(isolate->native_context()->regexp_result_map());
2711 Handle<JSObject> object =
2712 isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false);
2713 Handle<JSArray> array = Handle<JSArray>::cast(object);
2714 array->set_elements(*elements);
2715 array->set_length(Smi::FromInt(size));
2716 // Write in-object properties after the length of the array.
2717 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index);
2718 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input);
2723 RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) {
2724 HandleScope scope(isolate);
2725 ASSERT(args.length() == 5);
2726 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2727 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2728 // If source is the empty string we set it to "(?:)" instead as
2729 // suggested by ECMA-262, 5th, section 15.10.4.1.
2730 if (source->length() == 0) source = isolate->factory()->query_colon_string();
2732 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2733 if (!global->IsTrue()) global = isolate->factory()->false_value();
2735 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2736 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
2738 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2739 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
2741 Map* map = regexp->map();
2742 Object* constructor = map->constructor();
2743 if (constructor->IsJSFunction() &&
2744 JSFunction::cast(constructor)->initial_map() == map) {
2745 // If we still have the original map, set in-object properties directly.
2746 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
2747 // Both true and false are immovable immortal objects so no need for write
2749 regexp->InObjectPropertyAtPut(
2750 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
2751 regexp->InObjectPropertyAtPut(
2752 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
2753 regexp->InObjectPropertyAtPut(
2754 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
2755 regexp->InObjectPropertyAtPut(
2756 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
2760 // Map has changed, so use generic, but slower, method.
2761 PropertyAttributes final =
2762 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2763 PropertyAttributes writable =
2764 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
2765 Handle<Object> zero(Smi::FromInt(0), isolate);
2766 Factory* factory = isolate->factory();
2767 JSObject::SetLocalPropertyIgnoreAttributes(
2768 regexp, factory->source_string(), source, final).Check();
2769 JSObject::SetLocalPropertyIgnoreAttributes(
2770 regexp, factory->global_string(), global, final).Check();
2771 JSObject::SetLocalPropertyIgnoreAttributes(
2772 regexp, factory->ignore_case_string(), ignoreCase, final).Check();
2773 JSObject::SetLocalPropertyIgnoreAttributes(
2774 regexp, factory->multiline_string(), multiline, final).Check();
2775 JSObject::SetLocalPropertyIgnoreAttributes(
2776 regexp, factory->last_index_string(), zero, writable).Check();
2781 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
2782 HandleScope scope(isolate);
2783 ASSERT(args.length() == 1);
2784 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
2785 Object* length = prototype->length();
2786 RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
2787 RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
2788 // This is necessary to enable fast checks for absence of elements
2789 // on Array.prototype and below.
2790 prototype->set_elements(isolate->heap()->empty_fixed_array());
2791 return Smi::FromInt(0);
2795 static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
2796 Handle<JSObject> holder,
2798 Builtins::Name builtin_name) {
2799 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
2800 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2801 Handle<JSFunction> optimized =
2802 isolate->factory()->NewFunction(MaybeHandle<Object>(),
2805 JSObject::kHeaderSize,
2808 optimized->shared()->DontAdaptArguments();
2809 JSReceiver::SetProperty(holder, key, optimized, NONE, STRICT).Assert();
2814 RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
2815 HandleScope scope(isolate);
2816 ASSERT(args.length() == 1);
2817 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
2819 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2820 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2821 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2822 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2823 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2824 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2825 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
2831 RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
2832 SealHandleScope shs(isolate);
2833 ASSERT(args.length() == 1);
2834 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2835 if (!callable->IsJSFunction()) {
2836 HandleScope scope(isolate);
2837 Handle<Object> delegate;
2838 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2840 Execution::TryGetFunctionDelegate(
2841 isolate, Handle<JSReceiver>(callable)));
2842 callable = JSFunction::cast(*delegate);
2844 JSFunction* function = JSFunction::cast(callable);
2845 SharedFunctionInfo* shared = function->shared();
2846 return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
2850 RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) {
2851 SealHandleScope shs(isolate);
2852 ASSERT(args.length() == 1);
2853 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2855 if (!callable->IsJSFunction()) {
2856 HandleScope scope(isolate);
2857 Handle<Object> delegate;
2858 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2860 Execution::TryGetFunctionDelegate(
2861 isolate, Handle<JSReceiver>(callable)));
2862 callable = JSFunction::cast(*delegate);
2864 JSFunction* function = JSFunction::cast(callable);
2866 SharedFunctionInfo* shared = function->shared();
2867 if (shared->native() || shared->strict_mode() == STRICT) {
2868 return isolate->heap()->undefined_value();
2870 // Returns undefined for strict or native functions, or
2871 // the associated global receiver for "normal" functions.
2873 Context* native_context =
2874 function->context()->global_object()->native_context();
2875 return native_context->global_object()->global_receiver();
2879 RUNTIME_FUNCTION(RuntimeHidden_MaterializeRegExpLiteral) {
2880 HandleScope scope(isolate);
2881 ASSERT(args.length() == 4);
2882 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
2883 CONVERT_SMI_ARG_CHECKED(index, 1);
2884 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
2885 CONVERT_ARG_HANDLE_CHECKED(String, flags, 3);
2887 // Get the RegExp function from the context in the literals array.
2888 // This is the RegExp function from the context in which the
2889 // function was created. We do not use the RegExp function from the
2890 // current native context because this might be the RegExp function
2891 // from another context which we should not have access to.
2892 Handle<JSFunction> constructor =
2894 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
2895 // Compute the regular expression literal.
2896 Handle<Object> regexp;
2897 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2899 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags));
2900 literals->set(index, *regexp);
2905 RUNTIME_FUNCTION(Runtime_FunctionGetName) {
2906 SealHandleScope shs(isolate);
2907 ASSERT(args.length() == 1);
2909 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2910 return f->shared()->name();
2914 RUNTIME_FUNCTION(Runtime_FunctionSetName) {
2915 SealHandleScope shs(isolate);
2916 ASSERT(args.length() == 2);
2918 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2919 CONVERT_ARG_CHECKED(String, name, 1);
2920 f->shared()->set_name(name);
2921 return isolate->heap()->undefined_value();
2925 RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) {
2926 SealHandleScope shs(isolate);
2927 ASSERT(args.length() == 1);
2928 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2929 return isolate->heap()->ToBoolean(
2930 f->shared()->name_should_print_as_anonymous());
2934 RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2935 SealHandleScope shs(isolate);
2936 ASSERT(args.length() == 1);
2937 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2938 f->shared()->set_name_should_print_as_anonymous(true);
2939 return isolate->heap()->undefined_value();
2943 RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
2944 SealHandleScope shs(isolate);
2945 ASSERT(args.length() == 1);
2946 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2947 return isolate->heap()->ToBoolean(f->shared()->is_generator());
2951 RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
2952 SealHandleScope shs(isolate);
2953 ASSERT(args.length() == 1);
2955 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2956 RUNTIME_ASSERT(f->RemovePrototype());
2958 return isolate->heap()->undefined_value();
2962 RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
2963 HandleScope scope(isolate);
2964 ASSERT(args.length() == 1);
2966 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2967 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2968 if (!script->IsScript()) return isolate->heap()->undefined_value();
2970 return *Script::GetWrapper(Handle<Script>::cast(script));
2974 RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
2975 HandleScope scope(isolate);
2976 ASSERT(args.length() == 1);
2978 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2979 Handle<SharedFunctionInfo> shared(f->shared());
2980 return *shared->GetSourceCode();
2984 RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
2985 SealHandleScope shs(isolate);
2986 ASSERT(args.length() == 1);
2988 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2989 int pos = fun->shared()->start_position();
2990 return Smi::FromInt(pos);
2994 RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
2995 SealHandleScope shs(isolate);
2996 ASSERT(args.length() == 2);
2998 CONVERT_ARG_CHECKED(Code, code, 0);
2999 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
3001 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
3003 Address pc = code->address() + offset;
3004 return Smi::FromInt(code->SourcePosition(pc));
3008 RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) {
3009 SealHandleScope shs(isolate);
3010 ASSERT(args.length() == 2);
3012 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
3013 CONVERT_ARG_CHECKED(String, name, 1);
3014 fun->SetInstanceClassName(name);
3015 return isolate->heap()->undefined_value();
3019 RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
3020 SealHandleScope shs(isolate);
3021 ASSERT(args.length() == 2);
3023 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
3024 CONVERT_SMI_ARG_CHECKED(length, 1);
3025 fun->shared()->set_length(length);
3026 return isolate->heap()->undefined_value();
3030 RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
3031 HandleScope scope(isolate);
3032 ASSERT(args.length() == 2);
3034 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
3035 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
3036 ASSERT(fun->should_have_prototype());
3037 Accessors::FunctionSetPrototype(fun, value);
3038 return args[0]; // return TOS
3042 RUNTIME_FUNCTION(Runtime_FunctionSetReadOnlyPrototype) {
3043 HandleScope shs(isolate);
3044 RUNTIME_ASSERT(args.length() == 1);
3045 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
3047 Handle<String> name = isolate->factory()->prototype_string();
3049 if (function->HasFastProperties()) {
3050 // Construct a new field descriptor with updated attributes.
3051 Handle<DescriptorArray> instance_desc =
3052 handle(function->map()->instance_descriptors());
3054 int index = instance_desc->SearchWithCache(*name, function->map());
3055 ASSERT(index != DescriptorArray::kNotFound);
3056 PropertyDetails details = instance_desc->GetDetails(index);
3058 CallbacksDescriptor new_desc(
3060 handle(instance_desc->GetValue(index), isolate),
3061 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY));
3063 // Create a new map featuring the new field descriptors array.
3064 Handle<Map> map = handle(function->map());
3065 Handle<Map> new_map = Map::CopyReplaceDescriptor(
3066 map, instance_desc, &new_desc, index, OMIT_TRANSITION);
3068 JSObject::MigrateToMap(function, new_map);
3069 } else { // Dictionary properties.
3070 // Directly manipulate the property details.
3071 DisallowHeapAllocation no_gc;
3072 int entry = function->property_dictionary()->FindEntry(name);
3073 ASSERT(entry != NameDictionary::kNotFound);
3074 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
3075 PropertyDetails new_details(
3076 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
3078 details.dictionary_index());
3079 function->property_dictionary()->DetailsAtPut(entry, new_details);
3085 RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
3086 SealHandleScope shs(isolate);
3087 ASSERT(args.length() == 1);
3089 CONVERT_ARG_CHECKED(JSFunction, f, 0);
3090 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
3094 RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) {
3095 SealHandleScope shs(isolate);
3096 ASSERT(args.length() == 1);
3098 CONVERT_ARG_CHECKED(JSFunction, f, 0);
3099 return isolate->heap()->ToBoolean(f->IsBuiltin());
3103 RUNTIME_FUNCTION(Runtime_SetCode) {
3104 HandleScope scope(isolate);
3105 ASSERT(args.length() == 2);
3107 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
3108 CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1);
3110 Handle<SharedFunctionInfo> target_shared(target->shared());
3111 Handle<SharedFunctionInfo> source_shared(source->shared());
3112 RUNTIME_ASSERT(!source_shared->bound());
3114 if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
3115 return isolate->heap()->exception();
3118 // Mark both, the source and the target, as un-flushable because the
3119 // shared unoptimized code makes them impossible to enqueue in a list.
3120 ASSERT(target_shared->code()->gc_metadata() == NULL);
3121 ASSERT(source_shared->code()->gc_metadata() == NULL);
3122 target_shared->set_dont_flush(true);
3123 source_shared->set_dont_flush(true);
3125 // Set the code, scope info, formal parameter count, and the length
3126 // of the target shared function info.
3127 target_shared->ReplaceCode(source_shared->code());
3128 target_shared->set_scope_info(source_shared->scope_info());
3129 target_shared->set_length(source_shared->length());
3130 target_shared->set_feedback_vector(source_shared->feedback_vector());
3131 target_shared->set_formal_parameter_count(
3132 source_shared->formal_parameter_count());
3133 target_shared->set_script(source_shared->script());
3134 target_shared->set_start_position_and_type(
3135 source_shared->start_position_and_type());
3136 target_shared->set_end_position(source_shared->end_position());
3137 bool was_native = target_shared->native();
3138 target_shared->set_compiler_hints(source_shared->compiler_hints());
3139 target_shared->set_native(was_native);
3140 target_shared->set_profiler_ticks(source_shared->profiler_ticks());
3142 // Set the code of the target function.
3143 target->ReplaceCode(source_shared->code());
3144 ASSERT(target->next_function_link()->IsUndefined());
3146 // Make sure we get a fresh copy of the literal vector to avoid cross
3147 // context contamination.
3148 Handle<Context> context(source->context());
3149 int number_of_literals = source->NumberOfLiterals();
3150 Handle<FixedArray> literals =
3151 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
3152 if (number_of_literals > 0) {
3153 literals->set(JSFunction::kLiteralNativeContextIndex,
3154 context->native_context());
3156 target->set_context(*context);
3157 target->set_literals(*literals);
3159 if (isolate->logger()->is_logging_code_events() ||
3160 isolate->cpu_profiler()->is_profiling()) {
3161 isolate->logger()->LogExistingFunction(
3162 source_shared, Handle<Code>(source_shared->code()));
3169 RUNTIME_FUNCTION(Runtime_SetExpectedNumberOfProperties) {
3170 HandleScope scope(isolate);
3171 ASSERT(args.length() == 2);
3172 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
3173 CONVERT_SMI_ARG_CHECKED(num, 1);
3174 RUNTIME_ASSERT(num >= 0);
3175 // If objects constructed from this function exist then changing
3176 // 'estimated_nof_properties' is dangerous since the previous value might
3177 // have been compiled into the fast construct stub. Moreover, the inobject
3178 // slack tracking logic might have adjusted the previous value, so even
3179 // passing the same value is risky.
3180 if (!func->shared()->live_objects_may_exist()) {
3181 func->shared()->set_expected_nof_properties(num);
3182 if (func->has_initial_map()) {
3183 Handle<Map> new_initial_map = Map::Copy(handle(func->initial_map()));
3184 new_initial_map->set_unused_property_fields(num);
3185 func->set_initial_map(*new_initial_map);
3188 return isolate->heap()->undefined_value();
3192 RUNTIME_FUNCTION(RuntimeHidden_CreateJSGeneratorObject) {
3193 HandleScope scope(isolate);
3194 ASSERT(args.length() == 0);
3196 JavaScriptFrameIterator it(isolate);
3197 JavaScriptFrame* frame = it.frame();
3198 Handle<JSFunction> function(frame->function());
3199 RUNTIME_ASSERT(function->shared()->is_generator());
3201 Handle<JSGeneratorObject> generator;
3202 if (frame->IsConstructor()) {
3203 generator = handle(JSGeneratorObject::cast(frame->receiver()));
3205 generator = isolate->factory()->NewJSGeneratorObject(function);
3207 generator->set_function(*function);
3208 generator->set_context(Context::cast(frame->context()));
3209 generator->set_receiver(frame->receiver());
3210 generator->set_continuation(0);
3211 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
3212 generator->set_stack_handler_index(-1);
3218 RUNTIME_FUNCTION(RuntimeHidden_SuspendJSGeneratorObject) {
3219 HandleScope handle_scope(isolate);
3220 ASSERT(args.length() == 1);
3221 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
3223 JavaScriptFrameIterator stack_iterator(isolate);
3224 JavaScriptFrame* frame = stack_iterator.frame();
3225 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3226 ASSERT_EQ(frame->function(), generator_object->function());
3228 // The caller should have saved the context and continuation already.
3229 ASSERT_EQ(generator_object->context(), Context::cast(frame->context()));
3230 ASSERT_LT(0, generator_object->continuation());
3232 // We expect there to be at least two values on the operand stack: the return
3233 // value of the yield expression, and the argument to this runtime call.
3234 // Neither of those should be saved.
3235 int operands_count = frame->ComputeOperandsCount();
3236 ASSERT_GE(operands_count, 2);
3237 operands_count -= 2;
3239 if (operands_count == 0) {
3240 // Although it's semantically harmless to call this function with an
3241 // operands_count of zero, it is also unnecessary.
3242 ASSERT_EQ(generator_object->operand_stack(),
3243 isolate->heap()->empty_fixed_array());
3244 ASSERT_EQ(generator_object->stack_handler_index(), -1);
3245 // If there are no operands on the stack, there shouldn't be a handler
3247 ASSERT(!frame->HasHandler());
3249 int stack_handler_index = -1;
3250 Handle<FixedArray> operand_stack =
3251 isolate->factory()->NewFixedArray(operands_count);
3252 frame->SaveOperandStack(*operand_stack, &stack_handler_index);
3253 generator_object->set_operand_stack(*operand_stack);
3254 generator_object->set_stack_handler_index(stack_handler_index);
3257 return isolate->heap()->undefined_value();
3261 // Note that this function is the slow path for resuming generators. It is only
3262 // called if the suspended activation had operands on the stack, stack handlers
3263 // needing rewinding, or if the resume should throw an exception. The fast path
3264 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
3265 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
3266 // called in any case, as it needs to reconstruct the stack frame and make space
3267 // for arguments and operands.
3268 RUNTIME_FUNCTION(RuntimeHidden_ResumeJSGeneratorObject) {
3269 SealHandleScope shs(isolate);
3270 ASSERT(args.length() == 3);
3271 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3272 CONVERT_ARG_CHECKED(Object, value, 1);
3273 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3274 JavaScriptFrameIterator stack_iterator(isolate);
3275 JavaScriptFrame* frame = stack_iterator.frame();
3277 ASSERT_EQ(frame->function(), generator_object->function());
3278 ASSERT(frame->function()->is_compiled());
3280 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
3281 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
3283 Address pc = generator_object->function()->code()->instruction_start();
3284 int offset = generator_object->continuation();
3286 frame->set_pc(pc + offset);
3287 if (FLAG_enable_ool_constant_pool) {
3288 frame->set_constant_pool(
3289 generator_object->function()->code()->constant_pool());
3291 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3293 FixedArray* operand_stack = generator_object->operand_stack();
3294 int operands_count = operand_stack->length();
3295 if (operands_count != 0) {
3296 frame->RestoreOperandStack(operand_stack,
3297 generator_object->stack_handler_index());
3298 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
3299 generator_object->set_stack_handler_index(-1);
3302 JSGeneratorObject::ResumeMode resume_mode =
3303 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3304 switch (resume_mode) {
3305 case JSGeneratorObject::NEXT:
3307 case JSGeneratorObject::THROW:
3308 return isolate->Throw(value);
3312 return isolate->ThrowIllegalOperation();
3316 RUNTIME_FUNCTION(RuntimeHidden_ThrowGeneratorStateError) {
3317 HandleScope scope(isolate);
3318 ASSERT(args.length() == 1);
3319 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3320 int continuation = generator->continuation();
3321 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
3322 "generator_finished" : "generator_running";
3323 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3324 Handle<Object> error = isolate->factory()->NewError(message, argv);
3325 return isolate->Throw(*error);
3329 RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
3330 HandleScope scope(isolate);
3331 ASSERT(args.length() == 1);
3332 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3333 Handle<Object> result;
3334 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
3339 RUNTIME_FUNCTION(RuntimeHidden_StringCharCodeAt) {
3340 HandleScope handle_scope(isolate);
3341 ASSERT(args.length() == 2);
3343 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3344 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
3346 // Flatten the string. If someone wants to get a char at an index
3347 // in a cons string, it is likely that more indices will be
3349 subject = String::Flatten(subject);
3351 if (i >= static_cast<uint32_t>(subject->length())) {
3352 return isolate->heap()->nan_value();
3355 return Smi::FromInt(subject->Get(i));
3359 RUNTIME_FUNCTION(Runtime_CharFromCode) {
3360 HandleScope handlescope(isolate);
3361 ASSERT(args.length() == 1);
3362 if (args[0]->IsNumber()) {
3363 CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]);
3365 return *isolate->factory()->LookupSingleCharacterStringFromCode(code);
3367 return isolate->heap()->empty_string();
3371 class FixedArrayBuilder {
3373 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3374 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
3376 has_non_smi_elements_(false) {
3377 // Require a non-zero initial size. Ensures that doubling the size to
3378 // extend the array will work.
3379 ASSERT(initial_capacity > 0);
3382 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3383 : array_(backing_store),
3385 has_non_smi_elements_(false) {
3386 // Require a non-zero initial size. Ensures that doubling the size to
3387 // extend the array will work.
3388 ASSERT(backing_store->length() > 0);
3391 bool HasCapacity(int elements) {
3392 int length = array_->length();
3393 int required_length = length_ + elements;
3394 return (length >= required_length);
3397 void EnsureCapacity(int elements) {
3398 int length = array_->length();
3399 int required_length = length_ + elements;
3400 if (length < required_length) {
3401 int new_length = length;
3404 } while (new_length < required_length);
3405 Handle<FixedArray> extended_array =
3406 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
3407 array_->CopyTo(0, *extended_array, 0, length_);
3408 array_ = extended_array;
3412 void Add(Object* value) {
3413 ASSERT(!value->IsSmi());
3414 ASSERT(length_ < capacity());
3415 array_->set(length_, value);
3417 has_non_smi_elements_ = true;
3420 void Add(Smi* value) {
3421 ASSERT(value->IsSmi());
3422 ASSERT(length_ < capacity());
3423 array_->set(length_, value);
3427 Handle<FixedArray> array() {
3436 return array_->length();
3439 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
3440 JSArray::SetContent(target_array, array_);
3441 target_array->set_length(Smi::FromInt(length_));
3442 return target_array;
3447 Handle<FixedArray> array_;
3449 bool has_non_smi_elements_;
3453 // Forward declarations.
3454 const int kStringBuilderConcatHelperLengthBits = 11;
3455 const int kStringBuilderConcatHelperPositionBits = 19;
3457 template <typename schar>
3458 static inline void StringBuilderConcatHelper(String*,
3463 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3464 StringBuilderSubstringLength;
3465 typedef BitField<int,
3466 kStringBuilderConcatHelperLengthBits,
3467 kStringBuilderConcatHelperPositionBits>
3468 StringBuilderSubstringPosition;
3471 class ReplacementStringBuilder {
3473 ReplacementStringBuilder(Heap* heap,
3474 Handle<String> subject,
3475 int estimated_part_count)
3477 array_builder_(heap->isolate(), estimated_part_count),
3479 character_count_(0),
3480 is_ascii_(subject->IsOneByteRepresentation()) {
3481 // Require a non-zero initial size. Ensures that doubling the size to
3482 // extend the array will work.
3483 ASSERT(estimated_part_count > 0);
3486 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3490 int length = to - from;
3492 if (StringBuilderSubstringLength::is_valid(length) &&
3493 StringBuilderSubstringPosition::is_valid(from)) {
3494 int encoded_slice = StringBuilderSubstringLength::encode(length) |
3495 StringBuilderSubstringPosition::encode(from);
3496 builder->Add(Smi::FromInt(encoded_slice));
3498 // Otherwise encode as two smis.
3499 builder->Add(Smi::FromInt(-length));
3500 builder->Add(Smi::FromInt(from));
3505 void EnsureCapacity(int elements) {
3506 array_builder_.EnsureCapacity(elements);
3510 void AddSubjectSlice(int from, int to) {
3511 AddSubjectSlice(&array_builder_, from, to);
3512 IncrementCharacterCount(to - from);
3516 void AddString(Handle<String> string) {
3517 int length = string->length();
3519 AddElement(*string);
3520 if (!string->IsOneByteRepresentation()) {
3523 IncrementCharacterCount(length);
3527 MaybeHandle<String> ToString() {
3528 Isolate* isolate = heap_->isolate();
3529 if (array_builder_.length() == 0) {
3530 return isolate->factory()->empty_string();
3533 Handle<String> joined_string;
3535 Handle<SeqOneByteString> seq;
3536 ASSIGN_RETURN_ON_EXCEPTION(
3538 isolate->factory()->NewRawOneByteString(character_count_),
3541 DisallowHeapAllocation no_gc;
3542 uint8_t* char_buffer = seq->GetChars();
3543 StringBuilderConcatHelper(*subject_,
3545 *array_builder_.array(),
3546 array_builder_.length());
3547 joined_string = Handle<String>::cast(seq);
3550 Handle<SeqTwoByteString> seq;
3551 ASSIGN_RETURN_ON_EXCEPTION(
3553 isolate->factory()->NewRawTwoByteString(character_count_),
3556 DisallowHeapAllocation no_gc;
3557 uc16* char_buffer = seq->GetChars();
3558 StringBuilderConcatHelper(*subject_,
3560 *array_builder_.array(),
3561 array_builder_.length());
3562 joined_string = Handle<String>::cast(seq);
3564 return joined_string;
3568 void IncrementCharacterCount(int by) {
3569 if (character_count_ > String::kMaxLength - by) {
3570 STATIC_ASSERT(String::kMaxLength < kMaxInt);
3571 character_count_ = kMaxInt;
3573 character_count_ += by;
3578 void AddElement(Object* element) {
3579 ASSERT(element->IsSmi() || element->IsString());
3580 ASSERT(array_builder_.capacity() > array_builder_.length());
3581 array_builder_.Add(element);
3585 FixedArrayBuilder array_builder_;
3586 Handle<String> subject_;
3587 int character_count_;
3592 class CompiledReplacement {
3594 explicit CompiledReplacement(Zone* zone)
3595 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
3597 // Return whether the replacement is simple.
3598 bool Compile(Handle<String> replacement,
3600 int subject_length);
3602 // Use Apply only if Compile returned false.
3603 void Apply(ReplacementStringBuilder* builder,
3608 // Number of distinct parts of the replacement pattern.
3610 return parts_.length();
3613 Zone* zone() const { return zone_; }
3620 REPLACEMENT_SUBSTRING,
3623 NUMBER_OF_PART_TYPES
3626 struct ReplacementPart {
3627 static inline ReplacementPart SubjectMatch() {
3628 return ReplacementPart(SUBJECT_CAPTURE, 0);
3630 static inline ReplacementPart SubjectCapture(int capture_index) {
3631 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3633 static inline ReplacementPart SubjectPrefix() {
3634 return ReplacementPart(SUBJECT_PREFIX, 0);
3636 static inline ReplacementPart SubjectSuffix(int subject_length) {
3637 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3639 static inline ReplacementPart ReplacementString() {
3640 return ReplacementPart(REPLACEMENT_STRING, 0);
3642 static inline ReplacementPart ReplacementSubString(int from, int to) {
3645 return ReplacementPart(-from, to);
3648 // If tag <= 0 then it is the negation of a start index of a substring of
3649 // the replacement pattern, otherwise it's a value from PartType.
3650 ReplacementPart(int tag, int data)
3651 : tag(tag), data(data) {
3652 // Must be non-positive or a PartType value.
3653 ASSERT(tag < NUMBER_OF_PART_TYPES);
3655 // Either a value of PartType or a non-positive number that is
3656 // the negation of an index into the replacement string.
3658 // The data value's interpretation depends on the value of tag:
3659 // tag == SUBJECT_PREFIX ||
3660 // tag == SUBJECT_SUFFIX: data is unused.
3661 // tag == SUBJECT_CAPTURE: data is the number of the capture.
3662 // tag == REPLACEMENT_SUBSTRING ||
3663 // tag == REPLACEMENT_STRING: data is index into array of substrings
3664 // of the replacement string.
3665 // tag <= 0: Temporary representation of the substring of the replacement
3666 // string ranging over -tag .. data.
3667 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3668 // substring objects.
3672 template<typename Char>
3673 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3674 Vector<Char> characters,
3678 int length = characters.length();
3680 for (int i = 0; i < length; i++) {
3681 Char c = characters[i];
3683 int next_index = i + 1;
3684 if (next_index == length) { // No next character!
3687 Char c2 = characters[next_index];
3691 // There is a substring before. Include the first "$".
3692 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3694 last = next_index + 1; // Continue after the second "$".
3696 // Let the next substring start with the second "$".
3703 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3705 parts->Add(ReplacementPart::SubjectPrefix(), zone);
3711 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3713 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
3719 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3721 parts->Add(ReplacementPart::SubjectMatch(), zone);
3735 int capture_ref = c2 - '0';
3736 if (capture_ref > capture_count) {
3740 int second_digit_index = next_index + 1;
3741 if (second_digit_index < length) {
3742 // Peek ahead to see if we have two digits.
3743 Char c3 = characters[second_digit_index];
3744 if ('0' <= c3 && c3 <= '9') { // Double digits.
3745 int double_digit_ref = capture_ref * 10 + c3 - '0';
3746 if (double_digit_ref <= capture_count) {
3747 next_index = second_digit_index;
3748 capture_ref = double_digit_ref;
3752 if (capture_ref > 0) {
3754 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3756 ASSERT(capture_ref <= capture_count);
3757 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
3758 last = next_index + 1;
3769 if (length > last) {
3771 // Replacement is simple. Do not use Apply to do the replacement.
3774 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
3780 ZoneList<ReplacementPart> parts_;
3781 ZoneList<Handle<String> > replacement_substrings_;
3786 bool CompiledReplacement::Compile(Handle<String> replacement,
3788 int subject_length) {
3790 DisallowHeapAllocation no_gc;
3791 String::FlatContent content = replacement->GetFlatContent();
3792 ASSERT(content.IsFlat());
3793 bool simple = false;
3794 if (content.IsAscii()) {
3795 simple = ParseReplacementPattern(&parts_,
3796 content.ToOneByteVector(),
3801 ASSERT(content.IsTwoByte());
3802 simple = ParseReplacementPattern(&parts_,
3803 content.ToUC16Vector(),
3808 if (simple) return true;
3811 Isolate* isolate = replacement->GetIsolate();
3812 // Find substrings of replacement string and create them as String objects.
3813 int substring_index = 0;
3814 for (int i = 0, n = parts_.length(); i < n; i++) {
3815 int tag = parts_[i].tag;
3816 if (tag <= 0) { // A replacement string slice.
3818 int to = parts_[i].data;
3819 replacement_substrings_.Add(
3820 isolate->factory()->NewSubString(replacement, from, to), zone());
3821 parts_[i].tag = REPLACEMENT_SUBSTRING;
3822 parts_[i].data = substring_index;
3824 } else if (tag == REPLACEMENT_STRING) {
3825 replacement_substrings_.Add(replacement, zone());
3826 parts_[i].data = substring_index;
3834 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3838 ASSERT_LT(0, parts_.length());
3839 for (int i = 0, n = parts_.length(); i < n; i++) {
3840 ReplacementPart part = parts_[i];
3842 case SUBJECT_PREFIX:
3843 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3845 case SUBJECT_SUFFIX: {
3846 int subject_length = part.data;
3847 if (match_to < subject_length) {
3848 builder->AddSubjectSlice(match_to, subject_length);
3852 case SUBJECT_CAPTURE: {
3853 int capture = part.data;
3854 int from = match[capture * 2];
3855 int to = match[capture * 2 + 1];
3856 if (from >= 0 && to > from) {
3857 builder->AddSubjectSlice(from, to);
3861 case REPLACEMENT_SUBSTRING:
3862 case REPLACEMENT_STRING:
3863 builder->AddString(replacement_substrings_[part.data]);
3872 void FindAsciiStringIndices(Vector<const uint8_t> subject,
3874 ZoneList<int>* indices,
3878 // Collect indices of pattern in subject using memchr.
3879 // Stop after finding at most limit values.
3880 const uint8_t* subject_start = subject.start();
3881 const uint8_t* subject_end = subject_start + subject.length();
3882 const uint8_t* pos = subject_start;
3884 pos = reinterpret_cast<const uint8_t*>(
3885 memchr(pos, pattern, subject_end - pos));
3886 if (pos == NULL) return;
3887 indices->Add(static_cast<int>(pos - subject_start), zone);
3894 void FindTwoByteStringIndices(const Vector<const uc16> subject,
3896 ZoneList<int>* indices,
3900 const uc16* subject_start = subject.start();
3901 const uc16* subject_end = subject_start + subject.length();
3902 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3903 if (*pos == pattern) {
3904 indices->Add(static_cast<int>(pos - subject_start), zone);
3911 template <typename SubjectChar, typename PatternChar>
3912 void FindStringIndices(Isolate* isolate,
3913 Vector<const SubjectChar> subject,
3914 Vector<const PatternChar> pattern,
3915 ZoneList<int>* indices,
3919 // Collect indices of pattern in subject.
3920 // Stop after finding at most limit values.
3921 int pattern_length = pattern.length();
3923 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3925 index = search.Search(subject, index);
3926 if (index < 0) return;
3927 indices->Add(index, zone);
3928 index += pattern_length;
3934 void FindStringIndicesDispatch(Isolate* isolate,
3937 ZoneList<int>* indices,
3941 DisallowHeapAllocation no_gc;
3942 String::FlatContent subject_content = subject->GetFlatContent();
3943 String::FlatContent pattern_content = pattern->GetFlatContent();
3944 ASSERT(subject_content.IsFlat());
3945 ASSERT(pattern_content.IsFlat());
3946 if (subject_content.IsAscii()) {
3947 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
3948 if (pattern_content.IsAscii()) {
3949 Vector<const uint8_t> pattern_vector =
3950 pattern_content.ToOneByteVector();
3951 if (pattern_vector.length() == 1) {
3952 FindAsciiStringIndices(subject_vector,
3958 FindStringIndices(isolate,
3966 FindStringIndices(isolate,
3968 pattern_content.ToUC16Vector(),
3974 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3975 if (pattern_content.IsAscii()) {
3976 Vector<const uint8_t> pattern_vector =
3977 pattern_content.ToOneByteVector();
3978 if (pattern_vector.length() == 1) {
3979 FindTwoByteStringIndices(subject_vector,
3985 FindStringIndices(isolate,
3993 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3994 if (pattern_vector.length() == 1) {
3995 FindTwoByteStringIndices(subject_vector,
4001 FindStringIndices(isolate,
4014 template<typename ResultSeqString>
4015 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString(
4017 Handle<String> subject,
4018 Handle<JSRegExp> pattern_regexp,
4019 Handle<String> replacement,
4020 Handle<JSArray> last_match_info) {
4021 ASSERT(subject->IsFlat());
4022 ASSERT(replacement->IsFlat());
4024 ZoneScope zone_scope(isolate->runtime_zone());
4025 ZoneList<int> indices(8, zone_scope.zone());
4026 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
4028 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
4029 int subject_len = subject->length();
4030 int pattern_len = pattern->length();
4031 int replacement_len = replacement->length();
4033 FindStringIndicesDispatch(
4034 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
4036 int matches = indices.length();
4037 if (matches == 0) return *subject;
4039 // Detect integer overflow.
4040 int64_t result_len_64 =
4041 (static_cast<int64_t>(replacement_len) -
4042 static_cast<int64_t>(pattern_len)) *
4043 static_cast<int64_t>(matches) +
4044 static_cast<int64_t>(subject_len);
4046 if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
4047 STATIC_ASSERT(String::kMaxLength < kMaxInt);
4048 result_len = kMaxInt; // Provoke exception.
4050 result_len = static_cast<int>(result_len_64);
4053 int subject_pos = 0;
4056 MaybeHandle<SeqString> maybe_res;
4057 if (ResultSeqString::kHasAsciiEncoding) {
4058 maybe_res = isolate->factory()->NewRawOneByteString(result_len);
4060 maybe_res = isolate->factory()->NewRawTwoByteString(result_len);
4062 Handle<SeqString> untyped_res;
4063 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res);
4064 Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res);
4066 for (int i = 0; i < matches; i++) {
4067 // Copy non-matched subject content.
4068 if (subject_pos < indices.at(i)) {
4069 String::WriteToFlat(*subject,
4070 result->GetChars() + result_pos,
4073 result_pos += indices.at(i) - subject_pos;
4077 if (replacement_len > 0) {
4078 String::WriteToFlat(*replacement,
4079 result->GetChars() + result_pos,
4082 result_pos += replacement_len;
4085 subject_pos = indices.at(i) + pattern_len;
4087 // Add remaining subject content at the end.
4088 if (subject_pos < subject_len) {
4089 String::WriteToFlat(*subject,
4090 result->GetChars() + result_pos,
4095 int32_t match_indices[] = { indices.at(matches - 1),
4096 indices.at(matches - 1) + pattern_len };
4097 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
4103 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString(
4105 Handle<String> subject,
4106 Handle<JSRegExp> regexp,
4107 Handle<String> replacement,
4108 Handle<JSArray> last_match_info) {
4109 ASSERT(subject->IsFlat());
4110 ASSERT(replacement->IsFlat());
4112 int capture_count = regexp->CaptureCount();
4113 int subject_length = subject->length();
4115 // CompiledReplacement uses zone allocation.
4116 ZoneScope zone_scope(isolate->runtime_zone());
4117 CompiledReplacement compiled_replacement(zone_scope.zone());
4118 bool simple_replace = compiled_replacement.Compile(replacement,
4122 // Shortcut for simple non-regexp global replacements
4123 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
4124 if (subject->HasOnlyOneByteChars() &&
4125 replacement->HasOnlyOneByteChars()) {
4126 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4127 isolate, subject, regexp, replacement, last_match_info);
4129 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4130 isolate, subject, regexp, replacement, last_match_info);
4134 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4135 if (global_cache.HasException()) return isolate->heap()->exception();
4137 int32_t* current_match = global_cache.FetchNext();
4138 if (current_match == NULL) {
4139 if (global_cache.HasException()) return isolate->heap()->exception();
4143 // Guessing the number of parts that the final result string is built
4144 // from. Global regexps can match any number of times, so we guess
4146 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
4147 ReplacementStringBuilder builder(isolate->heap(),
4151 // Number of parts added by compiled replacement plus preceeding
4152 // string and possibly suffix after last match. It is possible for
4153 // all components to use two elements when encoded as two smis.
4154 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
4159 builder.EnsureCapacity(parts_added_per_loop);
4161 int start = current_match[0];
4162 int end = current_match[1];
4165 builder.AddSubjectSlice(prev, start);
4168 if (simple_replace) {
4169 builder.AddString(replacement);
4171 compiled_replacement.Apply(&builder,
4178 current_match = global_cache.FetchNext();
4179 } while (current_match != NULL);
4181 if (global_cache.HasException()) return isolate->heap()->exception();
4183 if (prev < subject_length) {
4184 builder.EnsureCapacity(2);
4185 builder.AddSubjectSlice(prev, subject_length);
4188 RegExpImpl::SetLastMatchInfo(last_match_info,
4191 global_cache.LastSuccessfulMatch());
4193 Handle<String> result;
4194 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString());
4199 template <typename ResultSeqString>
4200 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString(
4202 Handle<String> subject,
4203 Handle<JSRegExp> regexp,
4204 Handle<JSArray> last_match_info) {
4205 ASSERT(subject->IsFlat());
4207 // Shortcut for simple non-regexp global replacements
4208 if (regexp->TypeTag() == JSRegExp::ATOM) {
4209 Handle<String> empty_string = isolate->factory()->empty_string();
4210 if (subject->IsOneByteRepresentation()) {
4211 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4212 isolate, subject, regexp, empty_string, last_match_info);
4214 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4215 isolate, subject, regexp, empty_string, last_match_info);
4219 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4220 if (global_cache.HasException()) return isolate->heap()->exception();
4222 int32_t* current_match = global_cache.FetchNext();
4223 if (current_match == NULL) {
4224 if (global_cache.HasException()) return isolate->heap()->exception();
4228 int start = current_match[0];
4229 int end = current_match[1];
4230 int capture_count = regexp->CaptureCount();
4231 int subject_length = subject->length();
4233 int new_length = subject_length - (end - start);
4234 if (new_length == 0) return isolate->heap()->empty_string();
4236 Handle<ResultSeqString> answer;
4237 if (ResultSeqString::kHasAsciiEncoding) {
4238 answer = Handle<ResultSeqString>::cast(
4239 isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked());
4241 answer = Handle<ResultSeqString>::cast(
4242 isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked());
4249 start = current_match[0];
4250 end = current_match[1];
4252 // Add substring subject[prev;start] to answer string.
4253 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
4254 position += start - prev;
4258 current_match = global_cache.FetchNext();
4259 } while (current_match != NULL);
4261 if (global_cache.HasException()) return isolate->heap()->exception();
4263 RegExpImpl::SetLastMatchInfo(last_match_info,
4266 global_cache.LastSuccessfulMatch());
4268 if (prev < subject_length) {
4269 // Add substring subject[prev;length] to answer string.
4270 String::WriteToFlat(
4271 *subject, answer->GetChars() + position, prev, subject_length);
4272 position += subject_length - prev;
4275 if (position == 0) return isolate->heap()->empty_string();
4277 // Shorten string and fill
4278 int string_size = ResultSeqString::SizeFor(position);
4279 int allocated_string_size = ResultSeqString::SizeFor(new_length);
4280 int delta = allocated_string_size - string_size;
4282 answer->set_length(position);
4283 if (delta == 0) return *answer;
4285 Address end_of_string = answer->address() + string_size;
4286 Heap* heap = isolate->heap();
4288 // The trimming is performed on a newly allocated object, which is on a
4289 // fresly allocated page or on an already swept page. Hence, the sweeper
4290 // thread can not get confused with the filler creation. No synchronization
4292 heap->CreateFillerObjectAt(end_of_string, delta);
4293 heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
4298 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
4299 HandleScope scope(isolate);
4300 ASSERT(args.length() == 4);
4302 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4303 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4304 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4305 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
4307 RUNTIME_ASSERT(regexp->GetFlags().is_global());
4309 subject = String::Flatten(subject);
4311 if (replacement->length() == 0) {
4312 if (subject->HasOnlyOneByteChars()) {
4313 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
4314 isolate, subject, regexp, last_match_info);
4316 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
4317 isolate, subject, regexp, last_match_info);
4321 replacement = String::Flatten(replacement);
4323 return StringReplaceGlobalRegExpWithString(
4324 isolate, subject, regexp, replacement, last_match_info);
4328 // This may return an empty MaybeHandle if an exception is thrown or
4329 // we abort due to reaching the recursion limit.
4330 MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate,
4331 Handle<String> subject,
4332 Handle<String> search,
4333 Handle<String> replace,
4335 int recursion_limit) {
4336 if (recursion_limit == 0) return MaybeHandle<String>();
4338 if (subject->IsConsString()) {
4339 ConsString* cons = ConsString::cast(*subject);
4340 Handle<String> first = Handle<String>(cons->first());
4341 Handle<String> second = Handle<String>(cons->second());
4342 Handle<String> new_first;
4343 if (!StringReplaceOneCharWithString(
4344 isolate, first, search, replace, found, recursion_limit)
4345 .ToHandle(&new_first)) {
4346 return MaybeHandle<String>();
4348 if (*found) return isolate->factory()->NewConsString(new_first, second);
4350 Handle<String> new_second;
4351 if (!StringReplaceOneCharWithString(
4352 isolate, second, search, replace, found, recursion_limit)
4353 .ToHandle(&new_second)) {
4354 return MaybeHandle<String>();
4356 if (*found) return isolate->factory()->NewConsString(first, new_second);
4360 int index = Runtime::StringMatch(isolate, subject, search, 0);
4361 if (index == -1) return subject;
4363 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4364 Handle<String> cons1;
4365 ASSIGN_RETURN_ON_EXCEPTION(
4367 isolate->factory()->NewConsString(first, replace),
4369 Handle<String> second =
4370 isolate->factory()->NewSubString(subject, index + 1, subject->length());
4371 return isolate->factory()->NewConsString(cons1, second);
4376 RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
4377 HandleScope scope(isolate);
4378 ASSERT(args.length() == 3);
4379 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4380 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4381 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
4383 // If the cons string tree is too deep, we simply abort the recursion and
4384 // retry with a flattened subject string.
4385 const int kRecursionLimit = 0x1000;
4387 Handle<String> result;
4388 if (StringReplaceOneCharWithString(
4389 isolate, subject, search, replace, &found, kRecursionLimit)
4390 .ToHandle(&result)) {
4393 if (isolate->has_pending_exception()) return isolate->heap()->exception();
4395 subject = String::Flatten(subject);
4396 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
4398 StringReplaceOneCharWithString(
4399 isolate, subject, search, replace, &found, kRecursionLimit));
4404 // Perform string match of pattern on subject, starting at start index.
4405 // Caller must ensure that 0 <= start_index <= sub->length(),
4406 // and should check that pat->length() + start_index <= sub->length().
4407 int Runtime::StringMatch(Isolate* isolate,
4411 ASSERT(0 <= start_index);
4412 ASSERT(start_index <= sub->length());
4414 int pattern_length = pat->length();
4415 if (pattern_length == 0) return start_index;
4417 int subject_length = sub->length();
4418 if (start_index + pattern_length > subject_length) return -1;
4420 sub = String::Flatten(sub);
4421 pat = String::Flatten(pat);
4423 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4424 // Extract flattened substrings of cons strings before determining asciiness.
4425 String::FlatContent seq_sub = sub->GetFlatContent();
4426 String::FlatContent seq_pat = pat->GetFlatContent();
4428 // dispatch on type of strings
4429 if (seq_pat.IsAscii()) {
4430 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
4431 if (seq_sub.IsAscii()) {
4432 return SearchString(isolate,
4433 seq_sub.ToOneByteVector(),
4437 return SearchString(isolate,
4438 seq_sub.ToUC16Vector(),
4442 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4443 if (seq_sub.IsAscii()) {
4444 return SearchString(isolate,
4445 seq_sub.ToOneByteVector(),
4449 return SearchString(isolate,
4450 seq_sub.ToUC16Vector(),
4456 RUNTIME_FUNCTION(Runtime_StringIndexOf) {
4457 HandleScope scope(isolate);
4458 ASSERT(args.length() == 3);
4460 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4461 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4462 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
4464 uint32_t start_index;
4465 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4467 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
4468 int position = Runtime::StringMatch(isolate, sub, pat, start_index);
4469 return Smi::FromInt(position);
4473 template <typename schar, typename pchar>
4474 static int StringMatchBackwards(Vector<const schar> subject,
4475 Vector<const pchar> pattern,
4477 int pattern_length = pattern.length();
4478 ASSERT(pattern_length >= 1);
4479 ASSERT(idx + pattern_length <= subject.length());
4481 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
4482 for (int i = 0; i < pattern_length; i++) {
4483 uc16 c = pattern[i];
4484 if (c > String::kMaxOneByteCharCode) {
4490 pchar pattern_first_char = pattern[0];
4491 for (int i = idx; i >= 0; i--) {
4492 if (subject[i] != pattern_first_char) continue;
4494 while (j < pattern_length) {
4495 if (pattern[j] != subject[i+j]) {
4500 if (j == pattern_length) {
4508 RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
4509 HandleScope scope(isolate);
4510 ASSERT(args.length() == 3);
4512 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4513 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4514 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
4516 uint32_t start_index;
4517 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4519 uint32_t pat_length = pat->length();
4520 uint32_t sub_length = sub->length();
4522 if (start_index + pat_length > sub_length) {
4523 start_index = sub_length - pat_length;
4526 if (pat_length == 0) {
4527 return Smi::FromInt(start_index);
4530 sub = String::Flatten(sub);
4531 pat = String::Flatten(pat);
4534 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4536 String::FlatContent sub_content = sub->GetFlatContent();
4537 String::FlatContent pat_content = pat->GetFlatContent();
4539 if (pat_content.IsAscii()) {
4540 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
4541 if (sub_content.IsAscii()) {
4542 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4546 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4551 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4552 if (sub_content.IsAscii()) {
4553 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4557 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4563 return Smi::FromInt(position);
4567 RUNTIME_FUNCTION(Runtime_StringLocaleCompare) {
4568 HandleScope handle_scope(isolate);
4569 ASSERT(args.length() == 2);
4571 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
4572 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
4574 if (str1.is_identical_to(str2)) return Smi::FromInt(0); // Equal.
4575 int str1_length = str1->length();
4576 int str2_length = str2->length();
4578 // Decide trivial cases without flattening.
4579 if (str1_length == 0) {
4580 if (str2_length == 0) return Smi::FromInt(0); // Equal.
4581 return Smi::FromInt(-str2_length);
4583 if (str2_length == 0) return Smi::FromInt(str1_length);
4586 int end = str1_length < str2_length ? str1_length : str2_length;
4588 // No need to flatten if we are going to find the answer on the first
4589 // character. At this point we know there is at least one character
4590 // in each string, due to the trivial case handling above.
4591 int d = str1->Get(0) - str2->Get(0);
4592 if (d != 0) return Smi::FromInt(d);
4594 str1 = String::Flatten(str1);
4595 str2 = String::Flatten(str2);
4597 DisallowHeapAllocation no_gc;
4598 String::FlatContent flat1 = str1->GetFlatContent();
4599 String::FlatContent flat2 = str2->GetFlatContent();
4601 for (int i = 0; i < end; i++) {
4602 if (flat1.Get(i) != flat2.Get(i)) {
4603 return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
4607 return Smi::FromInt(str1_length - str2_length);
4611 RUNTIME_FUNCTION(RuntimeHidden_SubString) {
4612 HandleScope scope(isolate);
4613 ASSERT(args.length() == 3);
4615 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
4617 // We have a fast integer-only case here to avoid a conversion to double in
4618 // the common case where from and to are Smis.
4619 if (args[1]->IsSmi() && args[2]->IsSmi()) {
4620 CONVERT_SMI_ARG_CHECKED(from_number, 1);
4621 CONVERT_SMI_ARG_CHECKED(to_number, 2);
4622 start = from_number;
4625 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4626 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
4627 start = FastD2IChecked(from_number);
4628 end = FastD2IChecked(to_number);
4630 RUNTIME_ASSERT(end >= start);
4631 RUNTIME_ASSERT(start >= 0);
4632 RUNTIME_ASSERT(end <= string->length());
4633 isolate->counters()->sub_string_runtime()->Increment();
4635 return *isolate->factory()->NewSubString(string, start, end);
4639 RUNTIME_FUNCTION(Runtime_StringMatch) {
4640 HandleScope handles(isolate);
4641 ASSERT(args.length() == 3);
4643 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4644 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4645 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
4647 RUNTIME_ASSERT(regexp_info->HasFastObjectElements());
4649 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4650 if (global_cache.HasException()) return isolate->heap()->exception();
4652 int capture_count = regexp->CaptureCount();
4654 ZoneScope zone_scope(isolate->runtime_zone());
4655 ZoneList<int> offsets(8, zone_scope.zone());
4658 int32_t* match = global_cache.FetchNext();
4659 if (match == NULL) break;
4660 offsets.Add(match[0], zone_scope.zone()); // start
4661 offsets.Add(match[1], zone_scope.zone()); // end
4664 if (global_cache.HasException()) return isolate->heap()->exception();
4666 if (offsets.length() == 0) {
4667 // Not a single match.
4668 return isolate->heap()->null_value();
4671 RegExpImpl::SetLastMatchInfo(regexp_info,
4674 global_cache.LastSuccessfulMatch());
4676 int matches = offsets.length() / 2;
4677 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
4678 Handle<String> substring =
4679 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
4680 elements->set(0, *substring);
4681 for (int i = 1; i < matches; i++) {
4682 HandleScope temp_scope(isolate);
4683 int from = offsets.at(i * 2);
4684 int to = offsets.at(i * 2 + 1);
4685 Handle<String> substring =
4686 isolate->factory()->NewProperSubString(subject, from, to);
4687 elements->set(i, *substring);
4689 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
4690 result->set_length(Smi::FromInt(matches));
4695 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4696 // separate last match info. See comment on that function.
4697 template<bool has_capture>
4698 static Object* SearchRegExpMultiple(
4700 Handle<String> subject,
4701 Handle<JSRegExp> regexp,
4702 Handle<JSArray> last_match_array,
4703 Handle<JSArray> result_array) {
4704 ASSERT(subject->IsFlat());
4705 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
4707 int capture_count = regexp->CaptureCount();
4708 int subject_length = subject->length();
4710 static const int kMinLengthToCache = 0x1000;
4712 if (subject_length > kMinLengthToCache) {
4713 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4717 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
4718 if (*cached_answer != Smi::FromInt(0)) {
4719 Handle<FixedArray> cached_fixed_array =
4720 Handle<FixedArray>(FixedArray::cast(*cached_answer));
4721 // The cache FixedArray is a COW-array and can therefore be reused.
4722 JSArray::SetContent(result_array, cached_fixed_array);
4723 // The actual length of the result array is stored in the last element of
4724 // the backing store (the backing FixedArray may have a larger capacity).
4725 Object* cached_fixed_array_last_element =
4726 cached_fixed_array->get(cached_fixed_array->length() - 1);
4727 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4728 result_array->set_length(js_array_length);
4729 RegExpImpl::SetLastMatchInfo(
4730 last_match_array, subject, capture_count, NULL);
4731 return *result_array;
4735 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4736 if (global_cache.HasException()) return isolate->heap()->exception();
4738 Handle<FixedArray> result_elements;
4739 if (result_array->HasFastObjectElements()) {
4741 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4743 if (result_elements.is_null() || result_elements->length() < 16) {
4744 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4747 FixedArrayBuilder builder(result_elements);
4749 // Position to search from.
4750 int match_start = -1;
4754 // Two smis before and after the match, for very long strings.
4755 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
4758 int32_t* current_match = global_cache.FetchNext();
4759 if (current_match == NULL) break;
4760 match_start = current_match[0];
4761 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
4762 if (match_end < match_start) {
4763 ReplacementStringBuilder::AddSubjectSlice(&builder,
4767 match_end = current_match[1];
4769 // Avoid accumulating new handles inside loop.
4770 HandleScope temp_scope(isolate);
4771 Handle<String> match;
4773 match = isolate->factory()->NewProperSubString(subject,
4777 match = isolate->factory()->NewSubString(subject,
4784 // Arguments array to replace function is match, captures, index and
4785 // subject, i.e., 3 + capture count in total.
4786 Handle<FixedArray> elements =
4787 isolate->factory()->NewFixedArray(3 + capture_count);
4789 elements->set(0, *match);
4790 for (int i = 1; i <= capture_count; i++) {
4791 int start = current_match[i * 2];
4793 int end = current_match[i * 2 + 1];
4794 ASSERT(start <= end);
4795 Handle<String> substring =
4796 isolate->factory()->NewSubString(subject, start, end);
4797 elements->set(i, *substring);
4799 ASSERT(current_match[i * 2 + 1] < 0);
4800 elements->set(i, isolate->heap()->undefined_value());
4803 elements->set(capture_count + 1, Smi::FromInt(match_start));
4804 elements->set(capture_count + 2, *subject);
4805 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
4807 builder.Add(*match);
4812 if (global_cache.HasException()) return isolate->heap()->exception();
4814 if (match_start >= 0) {
4815 // Finished matching, with at least one match.
4816 if (match_end < subject_length) {
4817 ReplacementStringBuilder::AddSubjectSlice(&builder,
4822 RegExpImpl::SetLastMatchInfo(
4823 last_match_array, subject, capture_count, NULL);
4825 if (subject_length > kMinLengthToCache) {
4826 // Store the length of the result array into the last element of the
4827 // backing FixedArray.
4828 builder.EnsureCapacity(1);
4829 Handle<FixedArray> fixed_array = builder.array();
4830 fixed_array->set(fixed_array->length() - 1,
4831 Smi::FromInt(builder.length()));
4832 // Cache the result and turn the FixedArray into a COW array.
4833 RegExpResultsCache::Enter(isolate,
4835 handle(regexp->data(), isolate),
4837 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4839 return *builder.ToJSArray(result_array);
4841 return isolate->heap()->null_value(); // No matches at all.
4846 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4847 // lastMatchInfoOverride to maintain the last match info, so we don't need to
4848 // set any other last match array info.
4849 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
4850 HandleScope handles(isolate);
4851 ASSERT(args.length() == 4);
4853 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
4854 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4855 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4856 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
4858 subject = String::Flatten(subject);
4859 ASSERT(regexp->GetFlags().is_global());
4861 if (regexp->CaptureCount() == 0) {
4862 return SearchRegExpMultiple<false>(
4863 isolate, subject, regexp, last_match_info, result_array);
4865 return SearchRegExpMultiple<true>(
4866 isolate, subject, regexp, last_match_info, result_array);
4871 RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
4872 HandleScope scope(isolate);
4873 ASSERT(args.length() == 2);
4874 CONVERT_SMI_ARG_CHECKED(radix, 1);
4875 RUNTIME_ASSERT(2 <= radix && radix <= 36);
4877 // Fast case where the result is a one character string.
4878 if (args[0]->IsSmi()) {
4879 int value = args.smi_at(0);
4880 if (value >= 0 && value < radix) {
4881 // Character array used for conversion.
4882 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
4883 return *isolate->factory()->
4884 LookupSingleCharacterStringFromCode(kCharTable[value]);
4889 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4890 if (std::isnan(value)) {
4891 return isolate->heap()->nan_string();
4893 if (std::isinf(value)) {
4895 return isolate->heap()->minus_infinity_string();
4897 return isolate->heap()->infinity_string();
4899 char* str = DoubleToRadixCString(value, radix);
4900 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4906 RUNTIME_FUNCTION(Runtime_NumberToFixed) {
4907 HandleScope scope(isolate);
4908 ASSERT(args.length() == 2);
4910 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4911 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4912 int f = FastD2IChecked(f_number);
4913 // See DoubleToFixedCString for these constants:
4914 RUNTIME_ASSERT(f >= 0 && f <= 20);
4915 char* str = DoubleToFixedCString(value, f);
4916 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4922 RUNTIME_FUNCTION(Runtime_NumberToExponential) {
4923 HandleScope scope(isolate);
4924 ASSERT(args.length() == 2);
4926 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4927 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4928 int f = FastD2IChecked(f_number);
4929 RUNTIME_ASSERT(f >= -1 && f <= 20);
4930 char* str = DoubleToExponentialCString(value, f);
4931 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4937 RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
4938 HandleScope scope(isolate);
4939 ASSERT(args.length() == 2);
4941 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4942 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4943 int f = FastD2IChecked(f_number);
4944 RUNTIME_ASSERT(f >= 1 && f <= 21);
4945 char* str = DoubleToPrecisionCString(value, f);
4946 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
4952 RUNTIME_FUNCTION(Runtime_IsValidSmi) {
4953 SealHandleScope shs(isolate);
4954 ASSERT(args.length() == 1);
4956 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4957 return isolate->heap()->ToBoolean(Smi::IsValid(number));
4961 // Returns a single character string where first character equals
4962 // string->Get(index).
4963 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4964 if (index < static_cast<uint32_t>(string->length())) {
4965 Factory* factory = string->GetIsolate()->factory();
4966 return factory->LookupSingleCharacterStringFromCode(
4967 String::Flatten(string)->Get(index));
4969 return Execution::CharAt(string, index);
4973 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
4974 Handle<Object> object,
4976 // Handle [] indexing on Strings
4977 if (object->IsString()) {
4978 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4979 if (!result->IsUndefined()) return result;
4982 // Handle [] indexing on String objects
4983 if (object->IsStringObjectWithCharacterAt(index)) {
4984 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4985 Handle<Object> result =
4986 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4987 if (!result->IsUndefined()) return result;
4990 Handle<Object> result;
4991 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
4992 Handle<Object> proto(object->GetPrototype(isolate), isolate);
4993 return Object::GetElement(isolate, proto, index);
4995 return Object::GetElement(isolate, object, index);
5001 static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
5002 if (key->IsName()) {
5003 return Handle<Name>::cast(key);
5005 Handle<Object> converted;
5006 ASSIGN_RETURN_ON_EXCEPTION(
5007 isolate, converted, Execution::ToString(isolate, key), Name);
5008 return Handle<Name>::cast(converted);
5013 MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
5014 Handle<JSReceiver> object,
5015 Handle<Object> key) {
5016 // Check if the given key is an array index.
5018 if (key->ToArrayIndex(&index)) {
5019 return isolate->factory()->ToBoolean(JSReceiver::HasElement(object, index));
5022 // Convert the key to a name - possibly by calling back into JavaScript.
5024 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
5026 return isolate->factory()->ToBoolean(JSReceiver::HasProperty(object, name));
5030 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
5031 Handle<Object> object,
5032 Handle<Object> key) {
5033 if (object->IsUndefined() || object->IsNull()) {
5034 Handle<Object> args[2] = { key, object };
5035 return isolate->Throw<Object>(
5036 isolate->factory()->NewTypeError("non_object_property_load",
5037 HandleVector(args, 2)));
5040 // Check if the given key is an array index.
5042 if (key->ToArrayIndex(&index)) {
5043 return GetElementOrCharAt(isolate, object, index);
5046 // Convert the key to a name - possibly by calling back into JavaScript.
5048 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
5050 // Check if the name is trivially convertible to an index and get
5051 // the element if so.
5052 if (name->AsArrayIndex(&index)) {
5053 return GetElementOrCharAt(isolate, object, index);
5055 return Object::GetProperty(object, name);
5060 RUNTIME_FUNCTION(Runtime_GetProperty) {
5061 HandleScope scope(isolate);
5062 ASSERT(args.length() == 2);
5064 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5065 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
5066 Handle<Object> result;
5067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5069 Runtime::GetObjectProperty(isolate, object, key));
5074 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
5075 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
5076 HandleScope scope(isolate);
5077 ASSERT(args.length() == 2);
5079 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
5080 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
5082 // Fast cases for getting named properties of the receiver JSObject
5085 // The global proxy objects has to be excluded since LocalLookup on
5086 // the global proxy object can return a valid result even though the
5087 // global proxy object never has properties. This is the case
5088 // because the global proxy object forwards everything to its hidden
5089 // prototype including local lookups.
5091 // Additionally, we need to make sure that we do not cache results
5092 // for objects that require access checks.
5093 if (receiver_obj->IsJSObject()) {
5094 if (!receiver_obj->IsJSGlobalProxy() &&
5095 !receiver_obj->IsAccessCheckNeeded() &&
5096 key_obj->IsName()) {
5097 DisallowHeapAllocation no_allocation;
5098 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
5099 Handle<Name> key = Handle<Name>::cast(key_obj);
5100 if (receiver->HasFastProperties()) {
5101 // Attempt to use lookup cache.
5102 Handle<Map> receiver_map(receiver->map(), isolate);
5103 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
5104 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
5106 // Doubles are not cached, so raw read the value.
5107 Object* value = receiver->RawFastPropertyAt(offset);
5108 return value->IsTheHole()
5109 ? isolate->heap()->undefined_value()
5112 // Lookup cache miss. Perform lookup and update the cache if
5114 LookupResult result(isolate);
5115 receiver->LocalLookup(key, &result);
5116 if (result.IsField()) {
5117 int offset = result.GetFieldIndex().field_index();
5118 // Do not track double fields in the keyed lookup cache. Reading
5119 // double values requires boxing.
5120 if (!result.representation().IsDouble()) {
5121 keyed_lookup_cache->Update(receiver_map, key, offset);
5123 AllowHeapAllocation allow_allocation;
5124 return *JSObject::FastPropertyAt(
5125 receiver, result.representation(), offset);
5128 // Attempt dictionary lookup.
5129 NameDictionary* dictionary = receiver->property_dictionary();
5130 int entry = dictionary->FindEntry(key);
5131 if ((entry != NameDictionary::kNotFound) &&
5132 (dictionary->DetailsAt(entry).type() == NORMAL)) {
5133 Object* value = dictionary->ValueAt(entry);
5134 if (!receiver->IsGlobalObject()) return value;
5135 value = PropertyCell::cast(value)->value();
5136 if (!value->IsTheHole()) return value;
5137 // If value is the hole do the general lookup.
5140 } else if (FLAG_smi_only_arrays && key_obj->IsSmi()) {
5141 // JSObject without a name key. If the key is a Smi, check for a
5142 // definite out-of-bounds access to elements, which is a strong indicator
5143 // that subsequent accesses will also call the runtime. Proactively
5144 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
5145 // doubles for those future calls in the case that the elements would
5146 // become FAST_DOUBLE_ELEMENTS.
5147 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
5148 ElementsKind elements_kind = js_object->GetElementsKind();
5149 if (IsFastDoubleElementsKind(elements_kind)) {
5150 Handle<Smi> key = Handle<Smi>::cast(key_obj);
5151 if (key->value() >= js_object->elements()->length()) {
5152 if (IsFastHoleyElementsKind(elements_kind)) {
5153 elements_kind = FAST_HOLEY_ELEMENTS;
5155 elements_kind = FAST_ELEMENTS;
5157 RETURN_FAILURE_ON_EXCEPTION(
5158 isolate, TransitionElements(js_object, elements_kind, isolate));
5161 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
5162 !IsFastElementsKind(elements_kind));
5165 } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
5166 // Fast case for string indexing using [] with a smi index.
5167 Handle<String> str = Handle<String>::cast(receiver_obj);
5168 int index = args.smi_at(1);
5169 if (index >= 0 && index < str->length()) {
5170 return *GetCharAt(str, index);
5174 // Fall back to GetObjectProperty.
5175 Handle<Object> result;
5176 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5178 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
5183 static bool IsValidAccessor(Handle<Object> obj) {
5184 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
5188 // Implements part of 8.12.9 DefineOwnProperty.
5189 // There are 3 cases that lead here:
5190 // Step 4b - define a new accessor property.
5191 // Steps 9c & 12 - replace an existing data property with an accessor property.
5192 // Step 12 - update an existing accessor property with an accessor or generic
5194 RUNTIME_FUNCTION(Runtime_DefineOrRedefineAccessorProperty) {
5195 HandleScope scope(isolate);
5196 ASSERT(args.length() == 5);
5197 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5198 RUNTIME_ASSERT(!obj->IsNull());
5199 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5200 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
5201 RUNTIME_ASSERT(IsValidAccessor(getter));
5202 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
5203 RUNTIME_ASSERT(IsValidAccessor(setter));
5204 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
5205 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5206 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5208 bool fast = obj->HasFastProperties();
5209 // DefineAccessor checks access rights.
5210 JSObject::DefineAccessor(obj, name, getter, setter, attr);
5211 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5212 if (fast) JSObject::TransformToFastProperties(obj, 0);
5213 return isolate->heap()->undefined_value();
5217 // Implements part of 8.12.9 DefineOwnProperty.
5218 // There are 3 cases that lead here:
5219 // Step 4a - define a new data property.
5220 // Steps 9b & 12 - replace an existing accessor property with a data property.
5221 // Step 12 - update an existing data property with a data or generic
5223 RUNTIME_FUNCTION(Runtime_DefineOrRedefineDataProperty) {
5224 HandleScope scope(isolate);
5225 ASSERT(args.length() == 4);
5226 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
5227 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5228 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
5229 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
5230 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5231 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5233 // Check access rights if needed.
5234 if (js_object->IsAccessCheckNeeded() &&
5235 !isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
5236 return isolate->heap()->undefined_value();
5239 LookupResult lookup(isolate);
5240 js_object->LocalLookupRealNamedProperty(name, &lookup);
5242 // Special case for callback properties.
5243 if (lookup.IsPropertyCallbacks()) {
5244 Handle<Object> callback(lookup.GetCallbackObject(), isolate);
5245 // Avoid redefining callback as data property, just use the stored
5246 // setter to update the value instead.
5247 // TODO(mstarzinger): So far this only works if property attributes don't
5248 // change, this should be fixed once we cleanup the underlying code.
5249 ASSERT(!callback->IsForeign());
5250 if (callback->IsAccessorInfo() &&
5251 lookup.GetAttributes() == attr) {
5252 Handle<Object> result_object;
5253 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5254 isolate, result_object,
5255 JSObject::SetPropertyWithCallback(js_object,
5259 handle(lookup.holder()),
5261 return *result_object;
5265 // Take special care when attributes are different and there is already
5266 // a property. For simplicity we normalize the property which enables us
5267 // to not worry about changing the instance_descriptor and creating a new
5268 // map. The current version of SetObjectProperty does not handle attributes
5269 // correctly in the case where a property is a field and is reset with
5271 if (lookup.IsFound() &&
5272 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) {
5273 // New attributes - normalize to avoid writing to instance descriptor
5274 if (js_object->IsJSGlobalProxy()) {
5275 // Since the result is a property, the prototype will exist so
5276 // we don't have to check for null.
5277 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
5279 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
5280 // Use IgnoreAttributes version since a readonly property may be
5281 // overridden and SetProperty does not allow this.
5282 Handle<Object> result;
5283 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5285 JSObject::SetLocalPropertyIgnoreAttributes(
5286 js_object, name, obj_value, attr));
5290 Handle<Object> result;
5291 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5293 Runtime::ForceSetObjectProperty(
5294 js_object, name, obj_value, attr,
5295 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED));
5300 // Return property without being observable by accessors or interceptors.
5301 RUNTIME_FUNCTION(Runtime_GetDataProperty) {
5302 HandleScope scope(isolate);
5303 ASSERT(args.length() == 2);
5304 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5305 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5306 return *JSObject::GetDataProperty(object, key);
5310 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
5311 Handle<Object> object,
5313 Handle<Object> value,
5314 PropertyAttributes attr,
5315 StrictMode strict_mode) {
5316 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
5318 if (object->IsUndefined() || object->IsNull()) {
5319 Handle<Object> args[2] = { key, object };
5320 Handle<Object> error =
5321 isolate->factory()->NewTypeError("non_object_property_store",
5322 HandleVector(args, 2));
5323 return isolate->Throw<Object>(error);
5326 if (object->IsJSProxy()) {
5327 Handle<Object> name_object;
5328 if (key->IsSymbol()) {
5331 ASSIGN_RETURN_ON_EXCEPTION(
5332 isolate, name_object, Execution::ToString(isolate, key), Object);
5334 Handle<Name> name = Handle<Name>::cast(name_object);
5335 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
5340 // If the object isn't a JavaScript object, we ignore the store.
5341 if (!object->IsJSObject()) return value;
5343 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
5345 // Check if the given key is an array index.
5347 if (key->ToArrayIndex(&index)) {
5348 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5349 // of a string using [] notation. We need to support this too in
5351 // In the case of a String object we just need to redirect the assignment to
5352 // the underlying string if the index is in range. Since the underlying
5353 // string does nothing with the assignment then we can ignore such
5355 if (js_object->IsStringObjectWithCharacterAt(index)) {
5359 JSObject::ValidateElements(js_object);
5360 if (js_object->HasExternalArrayElements() ||
5361 js_object->HasFixedTypedArrayElements()) {
5362 // TODO(ningxin): Throw an error if setting a Float32x4Array element
5363 // while the value is not Float32x4Object.
5364 if (!value->IsNumber() && !value->IsFloat32x4() &&
5365 !value->IsFloat64x2() && !value->IsInt32x4() &&
5366 !value->IsUndefined()) {
5367 ASSIGN_RETURN_ON_EXCEPTION(
5368 isolate, value, Execution::ToNumber(isolate, value), Object);
5372 MaybeHandle<Object> result = JSObject::SetElement(
5373 js_object, index, value, attr, strict_mode, true, set_mode);
5374 JSObject::ValidateElements(js_object);
5376 return result.is_null() ? result : value;
5379 if (key->IsName()) {
5380 Handle<Name> name = Handle<Name>::cast(key);
5381 if (name->AsArrayIndex(&index)) {
5382 if (js_object->HasExternalArrayElements()) {
5383 // TODO(ningxin): Throw an error if setting a Float32x4Array element
5384 // while the value is not Float32x4Object.
5385 if (!value->IsNumber() && !value->IsFloat32x4() &&
5386 !value->IsFloat64x2() && !value->IsInt32x4() &&
5387 !value->IsUndefined()) {
5388 ASSIGN_RETURN_ON_EXCEPTION(
5389 isolate, value, Execution::ToNumber(isolate, value), Object);
5392 return JSObject::SetElement(js_object, index, value, attr,
5393 strict_mode, true, set_mode);
5395 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
5396 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5400 // Call-back into JavaScript to convert the key to a string.
5401 Handle<Object> converted;
5402 ASSIGN_RETURN_ON_EXCEPTION(
5403 isolate, converted, Execution::ToString(isolate, key), Object);
5404 Handle<String> name = Handle<String>::cast(converted);
5406 if (name->AsArrayIndex(&index)) {
5407 return JSObject::SetElement(js_object, index, value, attr,
5408 strict_mode, true, set_mode);
5410 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5415 MaybeHandle<Object> Runtime::ForceSetObjectProperty(
5416 Handle<JSObject> js_object,
5418 Handle<Object> value,
5419 PropertyAttributes attr,
5420 JSReceiver::StoreFromKeyed store_from_keyed) {
5421 Isolate* isolate = js_object->GetIsolate();
5422 // Check if the given key is an array index.
5424 if (key->ToArrayIndex(&index)) {
5425 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5426 // of a string using [] notation. We need to support this too in
5428 // In the case of a String object we just need to redirect the assignment to
5429 // the underlying string if the index is in range. Since the underlying
5430 // string does nothing with the assignment then we can ignore such
5432 if (js_object->IsStringObjectWithCharacterAt(index)) {
5436 return JSObject::SetElement(js_object, index, value, attr,
5437 SLOPPY, false, DEFINE_PROPERTY);
5440 if (key->IsName()) {
5441 Handle<Name> name = Handle<Name>::cast(key);
5442 if (name->AsArrayIndex(&index)) {
5443 return JSObject::SetElement(js_object, index, value, attr,
5444 SLOPPY, false, DEFINE_PROPERTY);
5446 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
5447 return JSObject::SetLocalPropertyIgnoreAttributes(
5448 js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION,
5449 ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
5454 // Call-back into JavaScript to convert the key to a string.
5455 Handle<Object> converted;
5456 ASSIGN_RETURN_ON_EXCEPTION(
5457 isolate, converted, Execution::ToString(isolate, key), Object);
5458 Handle<String> name = Handle<String>::cast(converted);
5460 if (name->AsArrayIndex(&index)) {
5461 return JSObject::SetElement(js_object, index, value, attr,
5462 SLOPPY, false, DEFINE_PROPERTY);
5464 return JSObject::SetLocalPropertyIgnoreAttributes(
5465 js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION,
5466 ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
5472 MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
5473 Handle<JSReceiver> receiver,
5475 JSReceiver::DeleteMode mode) {
5476 // Check if the given key is an array index.
5478 if (key->ToArrayIndex(&index)) {
5479 // In Firefox/SpiderMonkey, Safari and Opera you can access the
5480 // characters of a string using [] notation. In the case of a
5481 // String object we just need to redirect the deletion to the
5482 // underlying string if the index is in range. Since the
5483 // underlying string does nothing with the deletion, we can ignore
5485 if (receiver->IsStringObjectWithCharacterAt(index)) {
5486 return isolate->factory()->true_value();
5489 return JSReceiver::DeleteElement(receiver, index, mode);
5493 if (key->IsName()) {
5494 name = Handle<Name>::cast(key);
5496 // Call-back into JavaScript to convert the key to a string.
5497 Handle<Object> converted;
5498 ASSIGN_RETURN_ON_EXCEPTION(
5499 isolate, converted, Execution::ToString(isolate, key), Object);
5500 name = Handle<String>::cast(converted);
5503 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
5504 return JSReceiver::DeleteProperty(receiver, name, mode);
5508 RUNTIME_FUNCTION(Runtime_SetHiddenProperty) {
5509 HandleScope scope(isolate);
5510 RUNTIME_ASSERT(args.length() == 3);
5512 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5513 CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
5514 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5515 return *JSObject::SetHiddenProperty(object, key, value);
5519 RUNTIME_FUNCTION(Runtime_SetProperty) {
5520 HandleScope scope(isolate);
5521 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
5523 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5524 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
5525 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5526 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
5528 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5529 // Compute attributes.
5530 PropertyAttributes attributes =
5531 static_cast<PropertyAttributes>(unchecked_attributes);
5533 StrictMode strict_mode = SLOPPY;
5534 if (args.length() == 5) {
5535 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 4);
5536 strict_mode = strict_mode_arg;
5539 Handle<Object> result;
5540 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5542 Runtime::SetObjectProperty(
5543 isolate, object, key, value, attributes, strict_mode));
5548 RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
5549 HandleScope scope(isolate);
5550 RUNTIME_ASSERT(args.length() == 2);
5551 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
5552 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
5553 JSObject::TransitionElementsKind(array, map->elements_kind());
5558 // Set the native flag on the function.
5559 // This is used to decide if we should transform null and undefined
5560 // into the global object when doing call and apply.
5561 RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
5562 SealHandleScope shs(isolate);
5563 RUNTIME_ASSERT(args.length() == 1);
5565 CONVERT_ARG_CHECKED(Object, object, 0);
5567 if (object->IsJSFunction()) {
5568 JSFunction* func = JSFunction::cast(object);
5569 func->shared()->set_native(true);
5571 return isolate->heap()->undefined_value();
5575 RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
5576 SealHandleScope shs(isolate);
5577 RUNTIME_ASSERT(args.length() == 1);
5578 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5580 if (object->IsJSFunction()) {
5581 JSFunction* func = JSFunction::cast(*object);
5582 func->shared()->set_inline_builtin(true);
5584 return isolate->heap()->undefined_value();
5588 RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) {
5589 HandleScope scope(isolate);
5590 RUNTIME_ASSERT(args.length() == 5);
5591 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5592 CONVERT_SMI_ARG_CHECKED(store_index, 1);
5593 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5594 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
5595 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
5597 Object* raw_literal_cell = literals->get(literal_index);
5598 JSArray* boilerplate = NULL;
5599 if (raw_literal_cell->IsAllocationSite()) {
5600 AllocationSite* site = AllocationSite::cast(raw_literal_cell);
5601 boilerplate = JSArray::cast(site->transition_info());
5603 boilerplate = JSArray::cast(raw_literal_cell);
5605 Handle<JSArray> boilerplate_object(boilerplate);
5606 ElementsKind elements_kind = object->GetElementsKind();
5607 ASSERT(IsFastElementsKind(elements_kind));
5608 // Smis should never trigger transitions.
5609 ASSERT(!value->IsSmi());
5611 if (value->IsNumber()) {
5612 ASSERT(IsFastSmiElementsKind(elements_kind));
5613 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5614 ? FAST_HOLEY_DOUBLE_ELEMENTS
5615 : FAST_DOUBLE_ELEMENTS;
5616 if (IsMoreGeneralElementsKindTransition(
5617 boilerplate_object->GetElementsKind(),
5618 transitioned_kind)) {
5619 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5621 JSObject::TransitionElementsKind(object, transitioned_kind);
5622 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
5623 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
5624 HeapNumber* number = HeapNumber::cast(*value);
5625 double_array->set(store_index, number->Number());
5627 ASSERT(IsFastSmiElementsKind(elements_kind) ||
5628 IsFastDoubleElementsKind(elements_kind));
5629 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5630 ? FAST_HOLEY_ELEMENTS
5632 JSObject::TransitionElementsKind(object, transitioned_kind);
5633 if (IsMoreGeneralElementsKindTransition(
5634 boilerplate_object->GetElementsKind(),
5635 transitioned_kind)) {
5636 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5638 FixedArray* object_array = FixedArray::cast(object->elements());
5639 object_array->set(store_index, *value);
5645 // Check whether debugger and is about to step into the callback that is passed
5646 // to a built-in function such as Array.forEach.
5647 RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
5648 ASSERT(args.length() == 1);
5649 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
5650 return isolate->heap()->false_value();
5652 CONVERT_ARG_CHECKED(Object, callback, 0);
5653 // We do not step into the callback if it's a builtin or not even a function.
5654 return isolate->heap()->ToBoolean(
5655 callback->IsJSFunction() && !JSFunction::cast(callback)->IsBuiltin());
5659 // Set one shot breakpoints for the callback function that is passed to a
5660 // built-in function such as Array.forEach to enable stepping into the callback.
5661 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
5662 ASSERT(args.length() == 1);
5663 Debug* debug = isolate->debug();
5664 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
5665 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
5666 HandleScope scope(isolate);
5667 // When leaving the callback, step out has been activated, but not performed
5668 // if we do not leave the builtin. To be able to step into the callback
5669 // again, we need to clear the step out at this point.
5670 debug->ClearStepOut();
5671 debug->FloodWithOneShot(callback);
5672 return isolate->heap()->undefined_value();
5676 // The argument is a closure that is kept until the epilogue is called.
5677 // On exception, the closure is called, which returns the promise if the
5678 // exception is considered uncaught, or undefined otherwise.
5679 RUNTIME_FUNCTION(Runtime_DebugPromiseHandlePrologue) {
5680 ASSERT(args.length() == 1);
5681 HandleScope scope(isolate);
5682 CONVERT_ARG_HANDLE_CHECKED(JSFunction, promise_getter, 0);
5683 isolate->debug()->PromiseHandlePrologue(promise_getter);
5684 return isolate->heap()->undefined_value();
5688 RUNTIME_FUNCTION(Runtime_DebugPromiseHandleEpilogue) {
5689 ASSERT(args.length() == 0);
5690 SealHandleScope shs(isolate);
5691 isolate->debug()->PromiseHandleEpilogue();
5692 return isolate->heap()->undefined_value();
5696 // Set a local property, even if it is READ_ONLY. If the property does not
5697 // exist, it will be added with attributes NONE.
5698 RUNTIME_FUNCTION(Runtime_IgnoreAttributesAndSetProperty) {
5699 HandleScope scope(isolate);
5700 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
5701 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5702 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5703 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5704 // Compute attributes.
5705 PropertyAttributes attributes = NONE;
5706 if (args.length() == 4) {
5707 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
5708 // Only attribute bits should be set.
5710 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5711 attributes = static_cast<PropertyAttributes>(unchecked_value);
5713 Handle<Object> result;
5714 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5716 JSObject::SetLocalPropertyIgnoreAttributes(
5717 object, name, value, attributes));
5722 RUNTIME_FUNCTION(Runtime_DeleteProperty) {
5723 HandleScope scope(isolate);
5724 ASSERT(args.length() == 3);
5725 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5726 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5727 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
5728 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
5729 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
5730 Handle<Object> result;
5731 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5733 JSReceiver::DeleteProperty(object, key, delete_mode));
5738 static Object* HasLocalPropertyImplementation(Isolate* isolate,
5739 Handle<JSObject> object,
5741 if (JSReceiver::HasLocalProperty(object, key)) {
5742 return isolate->heap()->true_value();
5744 // Handle hidden prototypes. If there's a hidden prototype above this thing
5745 // then we have to check it for properties, because they are supposed to
5746 // look like they are on this object.
5747 Handle<Object> proto(object->GetPrototype(), isolate);
5748 if (proto->IsJSObject() &&
5749 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
5750 return HasLocalPropertyImplementation(isolate,
5751 Handle<JSObject>::cast(proto),
5754 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5755 return isolate->heap()->false_value();
5759 RUNTIME_FUNCTION(Runtime_HasLocalProperty) {
5760 HandleScope scope(isolate);
5761 ASSERT(args.length() == 2);
5762 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
5763 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5766 const bool key_is_array_index = key->AsArrayIndex(&index);
5768 // Only JS objects can have properties.
5769 if (object->IsJSObject()) {
5770 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
5771 // Fast case: either the key is a real named property or it is not
5772 // an array index and there are no interceptors or hidden
5774 if (JSObject::HasRealNamedProperty(js_obj, key)) {
5775 ASSERT(!isolate->has_scheduled_exception());
5776 return isolate->heap()->true_value();
5778 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5780 Map* map = js_obj->map();
5781 if (!key_is_array_index &&
5782 !map->has_named_interceptor() &&
5783 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
5784 return isolate->heap()->false_value();
5787 return HasLocalPropertyImplementation(isolate,
5788 Handle<JSObject>(js_obj),
5790 } else if (object->IsString() && key_is_array_index) {
5791 // Well, there is one exception: Handle [] on strings.
5792 Handle<String> string = Handle<String>::cast(object);
5793 if (index < static_cast<uint32_t>(string->length())) {
5794 return isolate->heap()->true_value();
5797 return isolate->heap()->false_value();
5801 RUNTIME_FUNCTION(Runtime_HasProperty) {
5802 HandleScope scope(isolate);
5803 ASSERT(args.length() == 2);
5804 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5805 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5807 bool result = JSReceiver::HasProperty(receiver, key);
5808 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5809 if (isolate->has_pending_exception()) return isolate->heap()->exception();
5810 return isolate->heap()->ToBoolean(result);
5814 RUNTIME_FUNCTION(Runtime_HasElement) {
5815 HandleScope scope(isolate);
5816 ASSERT(args.length() == 2);
5817 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5818 CONVERT_SMI_ARG_CHECKED(index, 1);
5820 bool result = JSReceiver::HasElement(receiver, index);
5821 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5822 return isolate->heap()->ToBoolean(result);
5826 RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
5827 HandleScope scope(isolate);
5828 ASSERT(args.length() == 2);
5830 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5831 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5833 PropertyAttributes att = JSReceiver::GetLocalPropertyAttribute(object, key);
5834 if (att == ABSENT || (att & DONT_ENUM) != 0) {
5835 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5836 return isolate->heap()->false_value();
5838 ASSERT(!isolate->has_scheduled_exception());
5839 return isolate->heap()->true_value();
5843 RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
5844 HandleScope scope(isolate);
5845 ASSERT(args.length() == 1);
5846 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5847 Handle<JSArray> result;
5849 isolate->counters()->for_in()->Increment();
5850 Handle<FixedArray> elements;
5851 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5853 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
5854 return *isolate->factory()->NewJSArrayWithElements(elements);
5858 // Returns either a FixedArray as Runtime_GetPropertyNames,
5859 // or, if the given object has an enum cache that contains
5860 // all enumerable properties of the object and its prototypes
5861 // have none, the map of the object. This is used to speed up
5862 // the check for deletions during a for-in.
5863 RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
5864 SealHandleScope shs(isolate);
5865 ASSERT(args.length() == 1);
5867 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
5869 if (raw_object->IsSimpleEnum()) return raw_object->map();
5871 HandleScope scope(isolate);
5872 Handle<JSReceiver> object(raw_object);
5873 Handle<FixedArray> content;
5874 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
5876 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
5878 // Test again, since cache may have been built by preceding call.
5879 if (object->IsSimpleEnum()) return object->map();
5885 // Find the length of the prototype chain that is to to handled as one. If a
5886 // prototype object is hidden it is to be viewed as part of the the object it
5887 // is prototype for.
5888 static int LocalPrototypeChainLength(JSObject* obj) {
5890 Object* proto = obj->GetPrototype();
5891 while (proto->IsJSObject() &&
5892 JSObject::cast(proto)->map()->is_hidden_prototype()) {
5894 proto = JSObject::cast(proto)->GetPrototype();
5900 // Return the names of the local named properties.
5902 // args[1]: PropertyAttributes as int
5903 RUNTIME_FUNCTION(Runtime_GetLocalPropertyNames) {
5904 HandleScope scope(isolate);
5905 ASSERT(args.length() == 2);
5906 if (!args[0]->IsJSObject()) {
5907 return isolate->heap()->undefined_value();
5909 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5910 CONVERT_SMI_ARG_CHECKED(filter_value, 1);
5911 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
5913 // Skip the global proxy as it has no properties and always delegates to the
5914 // real global object.
5915 if (obj->IsJSGlobalProxy()) {
5916 // Only collect names if access is permitted.
5917 if (obj->IsAccessCheckNeeded() &&
5918 !isolate->MayNamedAccess(
5919 obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5920 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
5921 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5922 return *isolate->factory()->NewJSArray(0);
5924 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5927 // Find the number of objects making up this.
5928 int length = LocalPrototypeChainLength(*obj);
5930 // Find the number of local properties for each of the objects.
5931 ScopedVector<int> local_property_count(length);
5932 int total_property_count = 0;
5933 Handle<JSObject> jsproto = obj;
5934 for (int i = 0; i < length; i++) {
5935 // Only collect names if access is permitted.
5936 if (jsproto->IsAccessCheckNeeded() &&
5937 !isolate->MayNamedAccess(
5938 jsproto, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5939 isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
5940 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
5941 return *isolate->factory()->NewJSArray(0);
5944 n = jsproto->NumberOfLocalProperties(filter);
5945 local_property_count[i] = n;
5946 total_property_count += n;
5947 if (i < length - 1) {
5948 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5952 // Allocate an array with storage for all the property names.
5953 Handle<FixedArray> names =
5954 isolate->factory()->NewFixedArray(total_property_count);
5956 // Get the property names.
5958 int next_copy_index = 0;
5959 int hidden_strings = 0;
5960 for (int i = 0; i < length; i++) {
5961 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
5963 // Names from hidden prototypes may already have been added
5964 // for inherited function template instances. Count the duplicates
5965 // and stub them out; the final copy pass at the end ignores holes.
5966 for (int j = next_copy_index;
5967 j < next_copy_index + local_property_count[i];
5969 Object* name_from_hidden_proto = names->get(j);
5970 for (int k = 0; k < next_copy_index; k++) {
5971 if (names->get(k) != isolate->heap()->hidden_string()) {
5972 Object* name = names->get(k);
5973 if (name_from_hidden_proto == name) {
5974 names->set(j, isolate->heap()->hidden_string());
5982 next_copy_index += local_property_count[i];
5984 // Hidden properties only show up if the filter does not skip strings.
5985 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
5988 if (i < length - 1) {
5989 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5993 // Filter out name of hidden properties object and
5994 // hidden prototype duplicates.
5995 if (hidden_strings > 0) {
5996 Handle<FixedArray> old_names = names;
5997 names = isolate->factory()->NewFixedArray(
5998 names->length() - hidden_strings);
6000 for (int i = 0; i < total_property_count; i++) {
6001 Object* name = old_names->get(i);
6002 if (name == isolate->heap()->hidden_string()) {
6006 names->set(dest_pos++, name);
6008 ASSERT_EQ(0, hidden_strings);
6011 return *isolate->factory()->NewJSArrayWithElements(names);
6015 // Return the names of the local indexed properties.
6017 RUNTIME_FUNCTION(Runtime_GetLocalElementNames) {
6018 HandleScope scope(isolate);
6019 ASSERT(args.length() == 1);
6020 if (!args[0]->IsJSObject()) {
6021 return isolate->heap()->undefined_value();
6023 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6025 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
6026 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
6027 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
6028 return *isolate->factory()->NewJSArrayWithElements(names);
6032 // Return information on whether an object has a named or indexed interceptor.
6034 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
6035 HandleScope scope(isolate);
6036 ASSERT(args.length() == 1);
6037 if (!args[0]->IsJSObject()) {
6038 return Smi::FromInt(0);
6040 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6043 if (obj->HasNamedInterceptor()) result |= 2;
6044 if (obj->HasIndexedInterceptor()) result |= 1;
6046 return Smi::FromInt(result);
6050 // Return property names from named interceptor.
6052 RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
6053 HandleScope scope(isolate);
6054 ASSERT(args.length() == 1);
6055 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6057 if (obj->HasNamedInterceptor()) {
6058 Handle<JSObject> result;
6059 if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
6063 return isolate->heap()->undefined_value();
6067 // Return element names from indexed interceptor.
6069 RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
6070 HandleScope scope(isolate);
6071 ASSERT(args.length() == 1);
6072 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6074 if (obj->HasIndexedInterceptor()) {
6075 Handle<JSObject> result;
6076 if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
6080 return isolate->heap()->undefined_value();
6084 RUNTIME_FUNCTION(Runtime_LocalKeys) {
6085 HandleScope scope(isolate);
6086 ASSERT(args.length() == 1);
6087 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
6088 Handle<JSObject> object(raw_object);
6090 if (object->IsJSGlobalProxy()) {
6091 // Do access checks before going to the global object.
6092 if (object->IsAccessCheckNeeded() &&
6093 !isolate->MayNamedAccess(
6094 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
6095 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
6096 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
6097 return *isolate->factory()->NewJSArray(0);
6100 Handle<Object> proto(object->GetPrototype(), isolate);
6101 // If proxy is detached we simply return an empty array.
6102 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
6103 object = Handle<JSObject>::cast(proto);
6106 Handle<FixedArray> contents;
6107 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6109 JSReceiver::GetKeys(object, JSReceiver::LOCAL_ONLY));
6111 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
6112 // property array and since the result is mutable we have to create
6113 // a fresh clone on each invocation.
6114 int length = contents->length();
6115 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
6116 for (int i = 0; i < length; i++) {
6117 Object* entry = contents->get(i);
6118 if (entry->IsString()) {
6119 copy->set(i, entry);
6121 ASSERT(entry->IsNumber());
6122 HandleScope scope(isolate);
6123 Handle<Object> entry_handle(entry, isolate);
6124 Handle<Object> entry_str =
6125 isolate->factory()->NumberToString(entry_handle);
6126 copy->set(i, *entry_str);
6129 return *isolate->factory()->NewJSArrayWithElements(copy);
6133 RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
6134 SealHandleScope shs(isolate);
6135 ASSERT(args.length() == 1);
6136 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
6138 // Compute the frame holding the arguments.
6139 JavaScriptFrameIterator it(isolate);
6140 it.AdvanceToArgumentsFrame();
6141 JavaScriptFrame* frame = it.frame();
6143 // Get the actual number of provided arguments.
6144 const uint32_t n = frame->ComputeParametersCount();
6146 // Try to convert the key to an index. If successful and within
6147 // index return the the argument from the frame.
6149 if (raw_key->ToArrayIndex(&index) && index < n) {
6150 return frame->GetParameter(index);
6153 HandleScope scope(isolate);
6154 if (raw_key->IsSymbol()) {
6155 // Lookup in the initial Object.prototype object.
6156 Handle<Object> result;
6157 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6159 Object::GetProperty(isolate->initial_object_prototype(),
6160 Handle<Symbol>::cast(raw_key)));
6164 // Convert the key to a string.
6165 Handle<Object> converted;
6166 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6167 isolate, converted, Execution::ToString(isolate, raw_key));
6168 Handle<String> key = Handle<String>::cast(converted);
6170 // Try to convert the string key into an array index.
6171 if (key->AsArrayIndex(&index)) {
6173 return frame->GetParameter(index);
6175 Handle<Object> initial_prototype(isolate->initial_object_prototype());
6176 Handle<Object> result;
6177 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6179 Object::GetElement(isolate, initial_prototype, index));
6184 // Handle special arguments properties.
6185 if (String::Equals(isolate->factory()->length_string(), key)) {
6186 return Smi::FromInt(n);
6188 if (String::Equals(isolate->factory()->callee_string(), key)) {
6189 JSFunction* function = frame->function();
6190 if (function->shared()->strict_mode() == STRICT) {
6191 return isolate->Throw(*isolate->factory()->NewTypeError(
6192 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
6197 // Lookup in the initial Object.prototype object.
6198 Handle<Object> result;
6199 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6201 Object::GetProperty(isolate->initial_object_prototype(), key));
6206 RUNTIME_FUNCTION(Runtime_ToFastProperties) {
6207 HandleScope scope(isolate);
6208 ASSERT(args.length() == 1);
6209 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6210 if (object->IsJSObject() && !object->IsGlobalObject()) {
6211 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
6217 RUNTIME_FUNCTION(Runtime_ToBool) {
6218 SealHandleScope shs(isolate);
6219 ASSERT(args.length() == 1);
6220 CONVERT_ARG_CHECKED(Object, object, 0);
6222 return isolate->heap()->ToBoolean(object->BooleanValue());
6226 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
6227 // Possible optimizations: put the type string into the oddballs.
6228 RUNTIME_FUNCTION(Runtime_Typeof) {
6229 SealHandleScope shs(isolate);
6230 ASSERT(args.length() == 1);
6231 CONVERT_ARG_CHECKED(Object, obj, 0);
6232 if (obj->IsNumber()) return isolate->heap()->number_string();
6233 if (obj->IsFloat32x4()) return isolate->heap()->float32x4_string();
6234 if (obj->IsFloat64x2()) return isolate->heap()->float64x2_string();
6235 if (obj->IsInt32x4()) return isolate->heap()->int32x4_string();
6236 HeapObject* heap_obj = HeapObject::cast(obj);
6238 // typeof an undetectable object is 'undefined'
6239 if (heap_obj->map()->is_undetectable()) {
6240 return isolate->heap()->undefined_string();
6243 InstanceType instance_type = heap_obj->map()->instance_type();
6244 if (instance_type < FIRST_NONSTRING_TYPE) {
6245 return isolate->heap()->string_string();
6248 switch (instance_type) {
6250 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
6251 return isolate->heap()->boolean_string();
6253 if (heap_obj->IsNull()) {
6254 return FLAG_harmony_typeof
6255 ? isolate->heap()->null_string()
6256 : isolate->heap()->object_string();
6258 ASSERT(heap_obj->IsUndefined());
6259 return isolate->heap()->undefined_string();
6261 return isolate->heap()->symbol_string();
6262 case JS_FUNCTION_TYPE:
6263 case JS_FUNCTION_PROXY_TYPE:
6264 return isolate->heap()->function_string();
6266 // For any kind of object not handled above, the spec rule for
6267 // host objects gives that it is okay to return "object"
6268 return isolate->heap()->object_string();
6273 static bool AreDigits(const uint8_t*s, int from, int to) {
6274 for (int i = from; i < to; i++) {
6275 if (s[i] < '0' || s[i] > '9') return false;
6282 static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
6283 ASSERT(to - from < 10); // Overflow is not possible.
6285 int d = s[from] - '0';
6287 for (int i = from + 1; i < to; i++) {
6288 d = 10 * d + (s[i] - '0');
6295 RUNTIME_FUNCTION(Runtime_StringToNumber) {
6296 HandleScope handle_scope(isolate);
6297 ASSERT(args.length() == 1);
6298 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6299 subject = String::Flatten(subject);
6301 // Fast case: short integer or some sorts of junk values.
6302 if (subject->IsSeqOneByteString()) {
6303 int len = subject->length();
6304 if (len == 0) return Smi::FromInt(0);
6306 DisallowHeapAllocation no_gc;
6307 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
6308 bool minus = (data[0] == '-');
6309 int start_pos = (minus ? 1 : 0);
6311 if (start_pos == len) {
6312 return isolate->heap()->nan_value();
6313 } else if (data[start_pos] > '9') {
6314 // Fast check for a junk value. A valid string may start from a
6315 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
6316 // or the 'I' character ('Infinity'). All of that have codes not greater
6317 // than '9' except 'I' and .
6318 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
6319 return isolate->heap()->nan_value();
6321 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6322 // The maximal/minimal smi has 10 digits. If the string has less digits
6323 // we know it will fit into the smi-data type.
6324 int d = ParseDecimalInteger(data, start_pos, len);
6326 if (d == 0) return isolate->heap()->minus_zero_value();
6328 } else if (!subject->HasHashCode() &&
6329 len <= String::kMaxArrayIndexSize &&
6330 (len == 1 || data[0] != '0')) {
6331 // String hash is not calculated yet but all the data are present.
6332 // Update the hash field to speed up sequential convertions.
6333 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
6335 subject->Hash(); // Force hash calculation.
6336 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6337 static_cast<int>(hash));
6339 subject->set_hash_field(hash);
6341 return Smi::FromInt(d);
6346 int flags = ALLOW_HEX;
6347 if (FLAG_harmony_numeric_literals) {
6348 // The current spec draft has not updated "ToNumber Applied to the String
6349 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6350 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6353 return *isolate->factory()->NewNumber(StringToDouble(
6354 isolate->unicode_cache(), *subject, flags));
6358 RUNTIME_FUNCTION(Runtime_NewString) {
6359 HandleScope scope(isolate);
6360 ASSERT(args.length() == 2);
6361 CONVERT_SMI_ARG_CHECKED(length, 0);
6362 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6363 if (length == 0) return isolate->heap()->empty_string();
6364 Handle<String> result;
6366 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6367 isolate, result, isolate->factory()->NewRawOneByteString(length));
6369 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6370 isolate, result, isolate->factory()->NewRawTwoByteString(length));
6376 RUNTIME_FUNCTION(Runtime_TruncateString) {
6377 HandleScope scope(isolate);
6378 ASSERT(args.length() == 2);
6379 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
6380 CONVERT_SMI_ARG_CHECKED(new_length, 1);
6381 RUNTIME_ASSERT(new_length >= 0);
6382 return *SeqString::Truncate(string, new_length);
6386 RUNTIME_FUNCTION(Runtime_URIEscape) {
6387 HandleScope scope(isolate);
6388 ASSERT(args.length() == 1);
6389 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6390 Handle<String> string = String::Flatten(source);
6391 ASSERT(string->IsFlat());
6392 Handle<String> result;
6393 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6395 string->IsOneByteRepresentationUnderneath()
6396 ? URIEscape::Escape<uint8_t>(isolate, source)
6397 : URIEscape::Escape<uc16>(isolate, source));
6402 RUNTIME_FUNCTION(Runtime_URIUnescape) {
6403 HandleScope scope(isolate);
6404 ASSERT(args.length() == 1);
6405 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6406 Handle<String> string = String::Flatten(source);
6407 ASSERT(string->IsFlat());
6408 Handle<String> result;
6409 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6411 string->IsOneByteRepresentationUnderneath()
6412 ? URIUnescape::Unescape<uint8_t>(isolate, source)
6413 : URIUnescape::Unescape<uc16>(isolate, source));
6418 RUNTIME_FUNCTION(Runtime_QuoteJSONString) {
6419 HandleScope scope(isolate);
6420 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
6421 ASSERT(args.length() == 1);
6422 Handle<Object> result;
6423 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6424 isolate, result, BasicJsonStringifier::StringifyString(isolate, string));
6429 RUNTIME_FUNCTION(Runtime_BasicJSONStringify) {
6430 HandleScope scope(isolate);
6431 ASSERT(args.length() == 1);
6432 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6433 BasicJsonStringifier stringifier(isolate);
6434 Handle<Object> result;
6435 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6436 isolate, result, stringifier.Stringify(object));
6441 RUNTIME_FUNCTION(Runtime_StringParseInt) {
6442 HandleScope handle_scope(isolate);
6443 ASSERT(args.length() == 2);
6444 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6445 CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
6446 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
6448 subject = String::Flatten(subject);
6451 { DisallowHeapAllocation no_gc;
6452 String::FlatContent flat = subject->GetFlatContent();
6454 // ECMA-262 section 15.1.2.3, empty string is NaN
6455 if (flat.IsAscii()) {
6456 value = StringToInt(
6457 isolate->unicode_cache(), flat.ToOneByteVector(), radix);
6459 value = StringToInt(
6460 isolate->unicode_cache(), flat.ToUC16Vector(), radix);
6464 return *isolate->factory()->NewNumber(value);
6468 RUNTIME_FUNCTION(Runtime_StringParseFloat) {
6469 HandleScope shs(isolate);
6470 ASSERT(args.length() == 1);
6471 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6473 subject = String::Flatten(subject);
6474 double value = StringToDouble(
6475 isolate->unicode_cache(), *subject, ALLOW_TRAILING_JUNK, OS::nan_value());
6477 return *isolate->factory()->NewNumber(value);
6481 static inline bool ToUpperOverflows(uc32 character) {
6482 // y with umlauts and the micro sign are the only characters that stop
6483 // fitting into one-byte when converting to uppercase.
6484 static const uc32 yuml_code = 0xff;
6485 static const uc32 micro_code = 0xb5;
6486 return (character == yuml_code || character == micro_code);
6490 template <class Converter>
6491 MUST_USE_RESULT static Object* ConvertCaseHelper(
6496 unibrow::Mapping<Converter, 128>* mapping) {
6497 DisallowHeapAllocation no_gc;
6498 // We try this twice, once with the assumption that the result is no longer
6499 // than the input and, if that assumption breaks, again with the exact
6500 // length. This may not be pretty, but it is nicer than what was here before
6501 // and I hereby claim my vaffel-is.
6503 // NOTE: This assumes that the upper/lower case of an ASCII
6504 // character is also ASCII. This is currently the case, but it
6505 // might break in the future if we implement more context and locale
6506 // dependent upper/lower conversions.
6507 bool has_changed_character = false;
6509 // Convert all characters to upper case, assuming that they will fit
6511 Access<ConsStringIteratorOp> op(
6512 isolate->runtime_state()->string_iterator());
6513 StringCharacterStream stream(string, op.value());
6514 unibrow::uchar chars[Converter::kMaxWidth];
6515 // We can assume that the string is not empty
6516 uc32 current = stream.GetNext();
6517 bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
6518 for (int i = 0; i < result_length;) {
6519 bool has_next = stream.HasMore();
6520 uc32 next = has_next ? stream.GetNext() : 0;
6521 int char_length = mapping->get(current, next, chars);
6522 if (char_length == 0) {
6523 // The case conversion of this character is the character itself.
6524 result->Set(i, current);
6526 } else if (char_length == 1 &&
6527 (ignore_overflow || !ToUpperOverflows(current))) {
6528 // Common case: converting the letter resulted in one character.
6529 ASSERT(static_cast<uc32>(chars[0]) != current);
6530 result->Set(i, chars[0]);
6531 has_changed_character = true;
6533 } else if (result_length == string->length()) {
6534 bool overflows = ToUpperOverflows(current);
6535 // We've assumed that the result would be as long as the
6536 // input but here is a character that converts to several
6537 // characters. No matter, we calculate the exact length
6538 // of the result and try the whole thing again.
6540 // Note that this leaves room for optimization. We could just
6541 // memcpy what we already have to the result string. Also,
6542 // the result string is the last object allocated we could
6543 // "realloc" it and probably, in the vast majority of cases,
6544 // extend the existing string to be able to hold the full
6546 int next_length = 0;
6548 next_length = mapping->get(next, 0, chars);
6549 if (next_length == 0) next_length = 1;
6551 int current_length = i + char_length + next_length;
6552 while (stream.HasMore()) {
6553 current = stream.GetNext();
6554 overflows |= ToUpperOverflows(current);
6555 // NOTE: we use 0 as the next character here because, while
6556 // the next character may affect what a character converts to,
6557 // it does not in any case affect the length of what it convert
6559 int char_length = mapping->get(current, 0, chars);
6560 if (char_length == 0) char_length = 1;
6561 current_length += char_length;
6562 if (current_length > String::kMaxLength) {
6563 AllowHeapAllocation allocate_error_and_return;
6564 return isolate->ThrowInvalidStringLength();
6567 // Try again with the real length. Return signed if we need
6568 // to allocate a two-byte string for to uppercase.
6569 return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
6570 : Smi::FromInt(current_length);
6572 for (int j = 0; j < char_length; j++) {
6573 result->Set(i, chars[j]);
6576 has_changed_character = true;
6580 if (has_changed_character) {
6583 // If we didn't actually change anything in doing the conversion
6584 // we simple return the result and let the converted string
6585 // become garbage; there is no reason to keep two identical strings
6594 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6595 static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
6597 // Given a word and two range boundaries returns a word with high bit
6598 // set in every byte iff the corresponding input byte was strictly in
6599 // the range (m, n). All the other bits in the result are cleared.
6600 // This function is only useful when it can be inlined and the
6601 // boundaries are statically known.
6602 // Requires: all bytes in the input word and the boundaries must be
6603 // ASCII (less than 0x7F).
6604 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6605 // Use strict inequalities since in edge cases the function could be
6606 // further simplified.
6607 ASSERT(0 < m && m < n);
6608 // Has high bit set in every w byte less than n.
6609 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6610 // Has high bit set in every w byte greater than m.
6611 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6612 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6617 static bool CheckFastAsciiConvert(char* dst,
6622 bool expected_changed = false;
6623 for (int i = 0; i < length; i++) {
6624 if (dst[i] == src[i]) continue;
6625 expected_changed = true;
6627 ASSERT('A' <= src[i] && src[i] <= 'Z');
6628 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6630 ASSERT('a' <= src[i] && src[i] <= 'z');
6631 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6634 return (expected_changed == changed);
6639 template<class Converter>
6640 static bool FastAsciiConvert(char* dst,
6643 bool* changed_out) {
6645 char* saved_dst = dst;
6646 const char* saved_src = src;
6648 DisallowHeapAllocation no_gc;
6649 // We rely on the distance between upper and lower case letters
6650 // being a known power of 2.
6651 ASSERT('a' - 'A' == (1 << 5));
6652 // Boundaries for the range of input characters than require conversion.
6653 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
6654 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
6655 bool changed = false;
6656 uintptr_t or_acc = 0;
6657 const char* const limit = src + length;
6658 #ifdef V8_HOST_CAN_READ_UNALIGNED
6659 // Process the prefix of the input that requires no conversion one
6660 // (machine) word at a time.
6661 while (src <= limit - sizeof(uintptr_t)) {
6662 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
6664 if (AsciiRangeMask(w, lo, hi) != 0) {
6668 *reinterpret_cast<uintptr_t*>(dst) = w;
6669 src += sizeof(uintptr_t);
6670 dst += sizeof(uintptr_t);
6672 // Process the remainder of the input performing conversion when
6673 // required one word at a time.
6674 while (src <= limit - sizeof(uintptr_t)) {
6675 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
6677 uintptr_t m = AsciiRangeMask(w, lo, hi);
6678 // The mask has high (7th) bit set in every byte that needs
6679 // conversion and we know that the distance between cases is
6681 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6682 src += sizeof(uintptr_t);
6683 dst += sizeof(uintptr_t);
6686 // Process the last few bytes of the input (or the whole input if
6687 // unaligned access is not supported).
6688 while (src < limit) {
6691 if (lo < c && c < hi) {
6699 if ((or_acc & kAsciiMask) != 0) {
6703 ASSERT(CheckFastAsciiConvert(
6704 saved_dst, saved_src, length, changed, Converter::kIsToLower));
6706 *changed_out = changed;
6713 template <class Converter>
6714 MUST_USE_RESULT static Object* ConvertCase(
6717 unibrow::Mapping<Converter, 128>* mapping) {
6718 s = String::Flatten(s);
6719 int length = s->length();
6720 // Assume that the string is not empty; we need this assumption later
6721 if (length == 0) return *s;
6723 // Simpler handling of ASCII strings.
6725 // NOTE: This assumes that the upper/lower case of an ASCII
6726 // character is also ASCII. This is currently the case, but it
6727 // might break in the future if we implement more context and locale
6728 // dependent upper/lower conversions.
6729 if (s->IsOneByteRepresentationUnderneath()) {
6730 // Same length as input.
6731 Handle<SeqOneByteString> result =
6732 isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
6733 DisallowHeapAllocation no_gc;
6734 String::FlatContent flat_content = s->GetFlatContent();
6735 ASSERT(flat_content.IsFlat());
6736 bool has_changed_character = false;
6737 bool is_ascii = FastAsciiConvert<Converter>(
6738 reinterpret_cast<char*>(result->GetChars()),
6739 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
6741 &has_changed_character);
6742 // If not ASCII, we discard the result and take the 2 byte path.
6743 if (is_ascii) return has_changed_character ? *result : *s;
6746 Handle<SeqString> result; // Same length as input.
6747 if (s->IsOneByteRepresentation()) {
6748 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
6750 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
6753 Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
6754 if (answer->IsException() || answer->IsString()) return answer;
6756 ASSERT(answer->IsSmi());
6757 length = Smi::cast(answer)->value();
6758 if (s->IsOneByteRepresentation() && length > 0) {
6759 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6760 isolate, result, isolate->factory()->NewRawOneByteString(length));
6762 if (length < 0) length = -length;
6763 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
6764 isolate, result, isolate->factory()->NewRawTwoByteString(length));
6766 return ConvertCaseHelper(isolate, *s, *result, length, mapping);
6770 RUNTIME_FUNCTION(Runtime_StringToLowerCase) {
6771 HandleScope scope(isolate);
6772 ASSERT(args.length() == 1);
6773 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6775 s, isolate, isolate->runtime_state()->to_lower_mapping());
6779 RUNTIME_FUNCTION(Runtime_StringToUpperCase) {
6780 HandleScope scope(isolate);
6781 ASSERT(args.length() == 1);
6782 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6784 s, isolate, isolate->runtime_state()->to_upper_mapping());
6788 RUNTIME_FUNCTION(Runtime_StringTrim) {
6789 HandleScope scope(isolate);
6790 ASSERT(args.length() == 3);
6792 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
6793 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6794 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
6796 string = String::Flatten(string);
6797 int length = string->length();
6800 UnicodeCache* unicode_cache = isolate->unicode_cache();
6802 while (left < length &&
6803 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
6810 while (right > left &&
6811 unicode_cache->IsWhiteSpaceOrLineTerminator(
6812 string->Get(right - 1))) {
6817 return *isolate->factory()->NewSubString(string, left, right);
6821 RUNTIME_FUNCTION(Runtime_StringSplit) {
6822 HandleScope handle_scope(isolate);
6823 ASSERT(args.length() == 3);
6824 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6825 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
6826 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6827 RUNTIME_ASSERT(limit > 0);
6829 int subject_length = subject->length();
6830 int pattern_length = pattern->length();
6831 RUNTIME_ASSERT(pattern_length > 0);
6833 if (limit == 0xffffffffu) {
6834 Handle<Object> cached_answer(
6835 RegExpResultsCache::Lookup(isolate->heap(),
6838 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6840 if (*cached_answer != Smi::FromInt(0)) {
6841 // The cache FixedArray is a COW-array and can therefore be reused.
6842 Handle<JSArray> result =
6843 isolate->factory()->NewJSArrayWithElements(
6844 Handle<FixedArray>::cast(cached_answer));
6849 // The limit can be very large (0xffffffffu), but since the pattern
6850 // isn't empty, we can never create more parts than ~half the length
6853 subject = String::Flatten(subject);
6854 pattern = String::Flatten(pattern);
6856 static const int kMaxInitialListCapacity = 16;
6858 ZoneScope zone_scope(isolate->runtime_zone());
6860 // Find (up to limit) indices of separator and end-of-string in subject
6861 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6862 ZoneList<int> indices(initial_capacity, zone_scope.zone());
6864 FindStringIndicesDispatch(isolate, *subject, *pattern,
6865 &indices, limit, zone_scope.zone());
6867 if (static_cast<uint32_t>(indices.length()) < limit) {
6868 indices.Add(subject_length, zone_scope.zone());
6871 // The list indices now contains the end of each part to create.
6873 // Create JSArray of substrings separated by separator.
6874 int part_count = indices.length();
6876 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
6877 JSObject::EnsureCanContainHeapObjectElements(result);
6878 result->set_length(Smi::FromInt(part_count));
6880 ASSERT(result->HasFastObjectElements());
6882 if (part_count == 1 && indices.at(0) == subject_length) {
6883 FixedArray::cast(result->elements())->set(0, *subject);
6887 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6889 for (int i = 0; i < part_count; i++) {
6890 HandleScope local_loop_handle(isolate);
6891 int part_end = indices.at(i);
6892 Handle<String> substring =
6893 isolate->factory()->NewProperSubString(subject, part_start, part_end);
6894 elements->set(i, *substring);
6895 part_start = part_end + pattern_length;
6898 if (limit == 0xffffffffu) {
6899 if (result->HasFastObjectElements()) {
6900 RegExpResultsCache::Enter(isolate,
6904 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
6912 // Copies ASCII characters to the given fixed array looking up
6913 // one-char strings in the cache. Gives up on the first char that is
6914 // not in the cache and fills the remainder with smi zeros. Returns
6915 // the length of the successfully copied prefix.
6916 static int CopyCachedAsciiCharsToArray(Heap* heap,
6917 const uint8_t* chars,
6918 FixedArray* elements,
6920 DisallowHeapAllocation no_gc;
6921 FixedArray* ascii_cache = heap->single_character_string_cache();
6922 Object* undefined = heap->undefined_value();
6924 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
6925 for (i = 0; i < length; ++i) {
6926 Object* value = ascii_cache->get(chars[i]);
6927 if (value == undefined) break;
6928 elements->set(i, value, mode);
6931 ASSERT(Smi::FromInt(0) == 0);
6932 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6935 for (int j = 0; j < length; ++j) {
6936 Object* element = elements->get(j);
6937 ASSERT(element == Smi::FromInt(0) ||
6938 (element->IsString() && String::cast(element)->LooksValid()));
6945 // Converts a String to JSArray.
6946 // For example, "foo" => ["f", "o", "o"].
6947 RUNTIME_FUNCTION(Runtime_StringToArray) {
6948 HandleScope scope(isolate);
6949 ASSERT(args.length() == 2);
6950 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6951 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
6953 s = String::Flatten(s);
6954 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
6956 Handle<FixedArray> elements;
6958 if (s->IsFlat() && s->IsOneByteRepresentation()) {
6959 // Try using cached chars where possible.
6960 elements = isolate->factory()->NewUninitializedFixedArray(length);
6962 DisallowHeapAllocation no_gc;
6963 String::FlatContent content = s->GetFlatContent();
6964 if (content.IsAscii()) {
6965 Vector<const uint8_t> chars = content.ToOneByteVector();
6966 // Note, this will initialize all elements (not only the prefix)
6967 // to prevent GC from seeing partially initialized array.
6968 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6973 MemsetPointer(elements->data_start(),
6974 isolate->heap()->undefined_value(),
6978 elements = isolate->factory()->NewFixedArray(length);
6980 for (int i = position; i < length; ++i) {
6981 Handle<Object> str =
6982 isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
6983 elements->set(i, *str);
6987 for (int i = 0; i < length; ++i) {
6988 ASSERT(String::cast(elements->get(i))->length() == 1);
6992 return *isolate->factory()->NewJSArrayWithElements(elements);
6996 RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
6997 HandleScope scope(isolate);
6998 ASSERT(args.length() == 1);
6999 CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
7000 return *Object::ToObject(isolate, value).ToHandleChecked();
7004 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
7005 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
7006 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
7007 return char_length == 0;
7011 RUNTIME_FUNCTION(RuntimeHidden_NumberToString) {
7012 HandleScope scope(isolate);
7013 ASSERT(args.length() == 1);
7014 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
7016 return *isolate->factory()->NumberToString(number);
7020 RUNTIME_FUNCTION(RuntimeHidden_NumberToStringSkipCache) {
7021 HandleScope scope(isolate);
7022 ASSERT(args.length() == 1);
7023 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
7025 return *isolate->factory()->NumberToString(number, false);
7029 RUNTIME_FUNCTION(Runtime_NumberToInteger) {
7030 HandleScope scope(isolate);
7031 ASSERT(args.length() == 1);
7033 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
7034 return *isolate->factory()->NewNumber(DoubleToInteger(number));
7038 RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
7039 HandleScope scope(isolate);
7040 ASSERT(args.length() == 1);
7042 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
7043 double double_value = DoubleToInteger(number);
7044 // Map both -0 and +0 to +0.
7045 if (double_value == 0) double_value = 0;
7047 return *isolate->factory()->NewNumber(double_value);
7051 RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
7052 HandleScope scope(isolate);
7053 ASSERT(args.length() == 1);
7055 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
7056 return *isolate->factory()->NewNumberFromUint(number);
7060 RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
7061 HandleScope scope(isolate);
7062 ASSERT(args.length() == 1);
7064 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
7065 return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
7069 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
7071 RUNTIME_FUNCTION(RuntimeHidden_NumberToSmi) {
7072 SealHandleScope shs(isolate);
7073 ASSERT(args.length() == 1);
7074 CONVERT_ARG_CHECKED(Object, obj, 0);
7078 if (obj->IsHeapNumber()) {
7079 double value = HeapNumber::cast(obj)->value();
7080 int int_value = FastD2I(value);
7081 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
7082 return Smi::FromInt(int_value);
7085 return isolate->heap()->nan_value();
7089 RUNTIME_FUNCTION(RuntimeHidden_AllocateHeapNumber) {
7090 HandleScope scope(isolate);
7091 ASSERT(args.length() == 0);
7092 return *isolate->factory()->NewHeapNumber(0);
7096 RUNTIME_FUNCTION(Runtime_AllocateFloat32x4) {
7097 HandleScope scope(isolate);
7098 ASSERT(args.length() == 0);
7100 float32x4_value_t zero = {{0, 0, 0, 0}};
7101 return *isolate->factory()->NewFloat32x4(zero);
7105 RUNTIME_FUNCTION(Runtime_AllocateFloat64x2) {
7106 HandleScope scope(isolate);
7107 ASSERT(args.length() == 0);
7109 float64x2_value_t zero = {{0, 0}};
7110 return *isolate->factory()->NewFloat64x2(zero);
7114 RUNTIME_FUNCTION(Runtime_AllocateInt32x4) {
7115 HandleScope scope(isolate);
7116 ASSERT(args.length() == 0);
7118 int32x4_value_t zero = {{0, 0, 0, 0}};
7119 return *isolate->factory()->NewInt32x4(zero);
7123 RUNTIME_FUNCTION(Runtime_NumberAdd) {
7124 HandleScope scope(isolate);
7125 ASSERT(args.length() == 2);
7127 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7128 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7129 return *isolate->factory()->NewNumber(x + y);
7133 RUNTIME_FUNCTION(Runtime_NumberSub) {
7134 HandleScope scope(isolate);
7135 ASSERT(args.length() == 2);
7137 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7138 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7139 return *isolate->factory()->NewNumber(x - y);
7143 RUNTIME_FUNCTION(Runtime_NumberMul) {
7144 HandleScope scope(isolate);
7145 ASSERT(args.length() == 2);
7147 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7148 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7149 return *isolate->factory()->NewNumber(x * y);
7153 RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
7154 HandleScope scope(isolate);
7155 ASSERT(args.length() == 1);
7157 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7158 return *isolate->factory()->NewNumber(-x);
7162 RUNTIME_FUNCTION(Runtime_NumberDiv) {
7163 HandleScope scope(isolate);
7164 ASSERT(args.length() == 2);
7166 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7167 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7168 return *isolate->factory()->NewNumber(x / y);
7172 RUNTIME_FUNCTION(Runtime_NumberMod) {
7173 HandleScope scope(isolate);
7174 ASSERT(args.length() == 2);
7176 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7177 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7178 return *isolate->factory()->NewNumber(modulo(x, y));
7182 RUNTIME_FUNCTION(Runtime_NumberImul) {
7183 HandleScope scope(isolate);
7184 ASSERT(args.length() == 2);
7186 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7187 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7188 return *isolate->factory()->NewNumberFromInt(x * y);
7192 RUNTIME_FUNCTION(RuntimeHidden_StringAdd) {
7193 HandleScope scope(isolate);
7194 ASSERT(args.length() == 2);
7195 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
7196 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
7197 isolate->counters()->string_add_runtime()->Increment();
7198 Handle<String> result;
7199 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
7200 isolate, result, isolate->factory()->NewConsString(str1, str2));
7205 template <typename sinkchar>
7206 static inline void StringBuilderConcatHelper(String* special,
7208 FixedArray* fixed_array,
7210 DisallowHeapAllocation no_gc;
7212 for (int i = 0; i < array_length; i++) {
7213 Object* element = fixed_array->get(i);
7214 if (element->IsSmi()) {
7215 // Smi encoding of position and length.
7216 int encoded_slice = Smi::cast(element)->value();
7219 if (encoded_slice > 0) {
7220 // Position and length encoded in one smi.
7221 pos = StringBuilderSubstringPosition::decode(encoded_slice);
7222 len = StringBuilderSubstringLength::decode(encoded_slice);
7224 // Position and length encoded in two smis.
7225 Object* obj = fixed_array->get(++i);
7226 ASSERT(obj->IsSmi());
7227 pos = Smi::cast(obj)->value();
7228 len = -encoded_slice;
7230 String::WriteToFlat(special,
7236 String* string = String::cast(element);
7237 int element_length = string->length();
7238 String::WriteToFlat(string, sink + position, 0, element_length);
7239 position += element_length;
7245 // Returns the result length of the concatenation.
7246 // On illegal argument, -1 is returned.
7247 static inline int StringBuilderConcatLength(int special_length,
7248 FixedArray* fixed_array,
7251 DisallowHeapAllocation no_gc;
7253 for (int i = 0; i < array_length; i++) {
7255 Object* elt = fixed_array->get(i);
7257 // Smi encoding of position and length.
7258 int smi_value = Smi::cast(elt)->value();
7261 if (smi_value > 0) {
7262 // Position and length encoded in one smi.
7263 pos = StringBuilderSubstringPosition::decode(smi_value);
7264 len = StringBuilderSubstringLength::decode(smi_value);
7266 // Position and length encoded in two smis.
7268 // Get the position and check that it is a positive smi.
7270 if (i >= array_length) return -1;
7271 Object* next_smi = fixed_array->get(i);
7272 if (!next_smi->IsSmi()) return -1;
7273 pos = Smi::cast(next_smi)->value();
7274 if (pos < 0) return -1;
7278 if (pos > special_length || len > special_length - pos) return -1;
7280 } else if (elt->IsString()) {
7281 String* element = String::cast(elt);
7282 int element_length = element->length();
7283 increment = element_length;
7284 if (*one_byte && !element->HasOnlyOneByteChars()) {
7290 if (increment > String::kMaxLength - position) {
7291 return kMaxInt; // Provoke throw on allocation.
7293 position += increment;
7299 RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
7300 HandleScope scope(isolate);
7301 ASSERT(args.length() == 3);
7302 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
7303 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
7304 CONVERT_SMI_ARG_CHECKED(array_length, 1);
7305 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
7307 size_t actual_array_length = 0;
7309 TryNumberToSize(isolate, array->length(), &actual_array_length));
7310 RUNTIME_ASSERT(array_length >= 0);
7311 RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length);
7313 // This assumption is used by the slice encoding in one or two smis.
7314 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7316 RUNTIME_ASSERT(array->HasFastElements());
7317 JSObject::EnsureCanContainHeapObjectElements(array);
7319 int special_length = special->length();
7320 if (!array->HasFastObjectElements()) {
7321 return isolate->Throw(isolate->heap()->illegal_argument_string());
7325 bool one_byte = special->HasOnlyOneByteChars();
7327 { DisallowHeapAllocation no_gc;
7328 FixedArray* fixed_array = FixedArray::cast(array->elements());
7329 if (fixed_array->length() < array_length) {
7330 array_length = fixed_array->length();
7333 if (array_length == 0) {
7334 return isolate->heap()->empty_string();
7335 } else if (array_length == 1) {
7336 Object* first = fixed_array->get(0);
7337 if (first->IsString()) return first;
7339 length = StringBuilderConcatLength(
7340 special_length, fixed_array, array_length, &one_byte);
7344 return isolate->Throw(isolate->heap()->illegal_argument_string());
7348 Handle<SeqOneByteString> answer;
7349 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
7351 isolate->factory()->NewRawOneByteString(length));
7352 StringBuilderConcatHelper(*special,
7354 FixedArray::cast(array->elements()),
7358 Handle<SeqTwoByteString> answer;
7359 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
7361 isolate->factory()->NewRawTwoByteString(length));
7362 StringBuilderConcatHelper(*special,
7364 FixedArray::cast(array->elements()),
7371 RUNTIME_FUNCTION(Runtime_StringBuilderJoin) {
7372 HandleScope scope(isolate);
7373 ASSERT(args.length() == 3);
7374 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
7375 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
7376 CONVERT_SMI_ARG_CHECKED(array_length, 1);
7377 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
7378 RUNTIME_ASSERT(array->HasFastObjectElements());
7380 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
7381 if (fixed_array->length() < array_length) {
7382 array_length = fixed_array->length();
7385 if (array_length == 0) {
7386 return isolate->heap()->empty_string();
7387 } else if (array_length == 1) {
7388 Object* first = fixed_array->get(0);
7389 RUNTIME_ASSERT(first->IsString());
7393 int separator_length = separator->length();
7394 RUNTIME_ASSERT(separator_length > 0);
7395 int max_nof_separators =
7396 (String::kMaxLength + separator_length - 1) / separator_length;
7397 if (max_nof_separators < (array_length - 1)) {
7398 return isolate->ThrowInvalidStringLength();
7400 int length = (array_length - 1) * separator_length;
7401 for (int i = 0; i < array_length; i++) {
7402 Object* element_obj = fixed_array->get(i);
7403 RUNTIME_ASSERT(element_obj->IsString());
7404 String* element = String::cast(element_obj);
7405 int increment = element->length();
7406 if (increment > String::kMaxLength - length) {
7407 STATIC_ASSERT(String::kMaxLength < kMaxInt);
7408 length = kMaxInt; // Provoke exception;
7411 length += increment;
7414 Handle<SeqTwoByteString> answer;
7415 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
7417 isolate->factory()->NewRawTwoByteString(length));
7419 DisallowHeapAllocation no_gc;
7421 uc16* sink = answer->GetChars();
7423 uc16* end = sink + length;
7426 String* first = String::cast(fixed_array->get(0));
7427 String* seperator_raw = *separator;
7428 int first_length = first->length();
7429 String::WriteToFlat(first, sink, 0, first_length);
7430 sink += first_length;
7432 for (int i = 1; i < array_length; i++) {
7433 ASSERT(sink + separator_length <= end);
7434 String::WriteToFlat(seperator_raw, sink, 0, separator_length);
7435 sink += separator_length;
7437 String* element = String::cast(fixed_array->get(i));
7438 int element_length = element->length();
7439 ASSERT(sink + element_length <= end);
7440 String::WriteToFlat(element, sink, 0, element_length);
7441 sink += element_length;
7443 ASSERT(sink == end);
7445 // Use %_FastAsciiArrayJoin instead.
7446 ASSERT(!answer->IsOneByteRepresentation());
7450 template <typename Char>
7451 static void JoinSparseArrayWithSeparator(FixedArray* elements,
7452 int elements_length,
7453 uint32_t array_length,
7455 Vector<Char> buffer) {
7456 DisallowHeapAllocation no_gc;
7457 int previous_separator_position = 0;
7458 int separator_length = separator->length();
7460 for (int i = 0; i < elements_length; i += 2) {
7461 int position = NumberToInt32(elements->get(i));
7462 String* string = String::cast(elements->get(i + 1));
7463 int string_length = string->length();
7464 if (string->length() > 0) {
7465 while (previous_separator_position < position) {
7466 String::WriteToFlat<Char>(separator, &buffer[cursor],
7467 0, separator_length);
7468 cursor += separator_length;
7469 previous_separator_position++;
7471 String::WriteToFlat<Char>(string, &buffer[cursor],
7473 cursor += string->length();
7476 if (separator_length > 0) {
7477 // Array length must be representable as a signed 32-bit number,
7478 // otherwise the total string length would have been too large.
7479 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7480 int last_array_index = static_cast<int>(array_length - 1);
7481 while (previous_separator_position < last_array_index) {
7482 String::WriteToFlat<Char>(separator, &buffer[cursor],
7483 0, separator_length);
7484 cursor += separator_length;
7485 previous_separator_position++;
7488 ASSERT(cursor <= buffer.length());
7492 RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) {
7493 HandleScope scope(isolate);
7494 ASSERT(args.length() == 3);
7495 CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0);
7496 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
7497 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
7498 // elements_array is fast-mode JSarray of alternating positions
7499 // (increasing order) and strings.
7500 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
7501 // array_length is length of original array (used to add separators);
7502 // separator is string to put between elements. Assumed to be non-empty.
7503 RUNTIME_ASSERT(array_length > 0);
7505 // Find total length of join result.
7506 int string_length = 0;
7507 bool is_ascii = separator->IsOneByteRepresentation();
7508 bool overflow = false;
7509 CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length());
7510 RUNTIME_ASSERT(elements_length <= elements_array->elements()->length());
7511 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7512 FixedArray* elements = FixedArray::cast(elements_array->elements());
7513 for (int i = 0; i < elements_length; i += 2) {
7514 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7515 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7518 { DisallowHeapAllocation no_gc;
7519 for (int i = 0; i < elements_length; i += 2) {
7520 String* string = String::cast(elements->get(i + 1));
7521 int length = string->length();
7522 if (is_ascii && !string->IsOneByteRepresentation()) {
7525 if (length > String::kMaxLength ||
7526 String::kMaxLength - length < string_length) {
7530 string_length += length;
7534 int separator_length = separator->length();
7535 if (!overflow && separator_length > 0) {
7536 if (array_length <= 0x7fffffffu) {
7537 int separator_count = static_cast<int>(array_length) - 1;
7538 int remaining_length = String::kMaxLength - string_length;
7539 if ((remaining_length / separator_length) >= separator_count) {
7540 string_length += separator_length * (array_length - 1);
7542 // Not room for the separators within the maximal string length.
7546 // Nonempty separator and at least 2^31-1 separators necessary
7547 // means that the string is too large to create.
7548 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7553 // Throw an exception if the resulting string is too large. See
7554 // https://code.google.com/p/chromium/issues/detail?id=336820
7556 return isolate->ThrowInvalidStringLength();
7560 Handle<SeqOneByteString> result = isolate->factory()->NewRawOneByteString(
7561 string_length).ToHandleChecked();
7562 JoinSparseArrayWithSeparator<uint8_t>(
7563 FixedArray::cast(elements_array->elements()),
7567 Vector<uint8_t>(result->GetChars(), string_length));
7570 Handle<SeqTwoByteString> result = isolate->factory()->NewRawTwoByteString(
7571 string_length).ToHandleChecked();
7572 JoinSparseArrayWithSeparator<uc16>(
7573 FixedArray::cast(elements_array->elements()),
7577 Vector<uc16>(result->GetChars(), string_length));
7583 RUNTIME_FUNCTION(Runtime_NumberOr) {
7584 HandleScope scope(isolate);
7585 ASSERT(args.length() == 2);
7587 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7588 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7589 return *isolate->factory()->NewNumberFromInt(x | y);
7593 RUNTIME_FUNCTION(Runtime_NumberAnd) {
7594 HandleScope scope(isolate);
7595 ASSERT(args.length() == 2);
7597 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7598 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7599 return *isolate->factory()->NewNumberFromInt(x & y);
7603 RUNTIME_FUNCTION(Runtime_NumberXor) {
7604 HandleScope scope(isolate);
7605 ASSERT(args.length() == 2);
7607 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7608 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7609 return *isolate->factory()->NewNumberFromInt(x ^ y);
7613 RUNTIME_FUNCTION(Runtime_NumberShl) {
7614 HandleScope scope(isolate);
7615 ASSERT(args.length() == 2);
7617 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7618 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7619 return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
7623 RUNTIME_FUNCTION(Runtime_NumberShr) {
7624 HandleScope scope(isolate);
7625 ASSERT(args.length() == 2);
7627 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7628 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7629 return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
7633 RUNTIME_FUNCTION(Runtime_NumberSar) {
7634 HandleScope scope(isolate);
7635 ASSERT(args.length() == 2);
7637 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7638 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7639 return *isolate->factory()->NewNumberFromInt(
7640 ArithmeticShiftRight(x, y & 0x1f));
7644 RUNTIME_FUNCTION(Runtime_NumberEquals) {
7645 SealHandleScope shs(isolate);
7646 ASSERT(args.length() == 2);
7648 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7649 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7650 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7651 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
7652 if (x == y) return Smi::FromInt(EQUAL);
7654 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7655 result = Smi::FromInt(EQUAL);
7657 result = Smi::FromInt(NOT_EQUAL);
7663 RUNTIME_FUNCTION(Runtime_StringEquals) {
7664 HandleScope handle_scope(isolate);
7665 ASSERT(args.length() == 2);
7667 CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
7668 CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
7670 bool not_equal = !String::Equals(x, y);
7671 // This is slightly convoluted because the value that signifies
7672 // equality is 0 and inequality is 1 so we have to negate the result
7673 // from String::Equals.
7674 ASSERT(not_equal == 0 || not_equal == 1);
7675 STATIC_CHECK(EQUAL == 0);
7676 STATIC_CHECK(NOT_EQUAL == 1);
7677 return Smi::FromInt(not_equal);
7681 RUNTIME_FUNCTION(Runtime_NumberCompare) {
7682 SealHandleScope shs(isolate);
7683 ASSERT(args.length() == 3);
7685 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7686 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7687 CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
7688 if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
7689 if (x == y) return Smi::FromInt(EQUAL);
7690 if (isless(x, y)) return Smi::FromInt(LESS);
7691 return Smi::FromInt(GREATER);
7695 // Compare two Smis as if they were converted to strings and then
7696 // compared lexicographically.
7697 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
7698 SealHandleScope shs(isolate);
7699 ASSERT(args.length() == 2);
7700 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7701 CONVERT_SMI_ARG_CHECKED(y_value, 1);
7703 // If the integers are equal so are the string representations.
7704 if (x_value == y_value) return Smi::FromInt(EQUAL);
7706 // If one of the integers is zero the normal integer order is the
7707 // same as the lexicographic order of the string representations.
7708 if (x_value == 0 || y_value == 0)
7709 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
7711 // If only one of the integers is negative the negative number is
7712 // smallest because the char code of '-' is less than the char code
7713 // of any digit. Otherwise, we make both values positive.
7715 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7716 // architectures using 32-bit Smis.
7717 uint32_t x_scaled = x_value;
7718 uint32_t y_scaled = y_value;
7719 if (x_value < 0 || y_value < 0) {
7720 if (y_value >= 0) return Smi::FromInt(LESS);
7721 if (x_value >= 0) return Smi::FromInt(GREATER);
7722 x_scaled = -x_value;
7723 y_scaled = -y_value;
7726 static const uint32_t kPowersOf10[] = {
7727 1, 10, 100, 1000, 10*1000, 100*1000,
7728 1000*1000, 10*1000*1000, 100*1000*1000,
7732 // If the integers have the same number of decimal digits they can be
7733 // compared directly as the numeric order is the same as the
7734 // lexicographic order. If one integer has fewer digits, it is scaled
7735 // by some power of 10 to have the same number of digits as the longer
7736 // integer. If the scaled integers are equal it means the shorter
7737 // integer comes first in the lexicographic order.
7739 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7740 int x_log2 = IntegerLog2(x_scaled);
7741 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7742 x_log10 -= x_scaled < kPowersOf10[x_log10];
7744 int y_log2 = IntegerLog2(y_scaled);
7745 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7746 y_log10 -= y_scaled < kPowersOf10[y_log10];
7750 if (x_log10 < y_log10) {
7751 // X has fewer digits. We would like to simply scale up X but that
7752 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7753 // be scaled up to 9_000_000_000. So we scale up by the next
7754 // smallest power and scale down Y to drop one digit. It is OK to
7755 // drop one digit from the longer integer since the final digit is
7756 // past the length of the shorter integer.
7757 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7760 } else if (y_log10 < x_log10) {
7761 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7766 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7767 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7768 return Smi::FromInt(tie);
7772 RUNTIME_FUNCTION(RuntimeHidden_StringCompare) {
7773 HandleScope handle_scope(isolate);
7774 ASSERT(args.length() == 2);
7776 CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
7777 CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
7779 isolate->counters()->string_compare_runtime()->Increment();
7781 // A few fast case tests before we flatten.
7782 if (x.is_identical_to(y)) return Smi::FromInt(EQUAL);
7783 if (y->length() == 0) {
7784 if (x->length() == 0) return Smi::FromInt(EQUAL);
7785 return Smi::FromInt(GREATER);
7786 } else if (x->length() == 0) {
7787 return Smi::FromInt(LESS);
7790 int d = x->Get(0) - y->Get(0);
7791 if (d < 0) return Smi::FromInt(LESS);
7792 else if (d > 0) return Smi::FromInt(GREATER);
7795 x = String::Flatten(x);
7796 y = String::Flatten(y);
7798 DisallowHeapAllocation no_gc;
7799 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7800 int prefix_length = x->length();
7801 if (y->length() < prefix_length) {
7802 prefix_length = y->length();
7803 equal_prefix_result = Smi::FromInt(GREATER);
7804 } else if (y->length() > prefix_length) {
7805 equal_prefix_result = Smi::FromInt(LESS);
7808 String::FlatContent x_content = x->GetFlatContent();
7809 String::FlatContent y_content = y->GetFlatContent();
7810 if (x_content.IsAscii()) {
7811 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
7812 if (y_content.IsAscii()) {
7813 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7814 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7816 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7817 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7820 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7821 if (y_content.IsAscii()) {
7822 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7823 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7825 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7826 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7831 result = equal_prefix_result;
7833 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7839 #define RUNTIME_UNARY_MATH(Name, name) \
7840 RUNTIME_FUNCTION(Runtime_Math##Name) { \
7841 HandleScope scope(isolate); \
7842 ASSERT(args.length() == 1); \
7843 isolate->counters()->math_##name()->Increment(); \
7844 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \
7845 return *isolate->factory()->NewHeapNumber(std::name(x)); \
7848 RUNTIME_UNARY_MATH(Acos, acos)
7849 RUNTIME_UNARY_MATH(Asin, asin)
7850 RUNTIME_UNARY_MATH(Atan, atan)
7851 RUNTIME_UNARY_MATH(Log, log)
7852 #undef RUNTIME_UNARY_MATH
7855 RUNTIME_FUNCTION(Runtime_DoubleHi) {
7856 HandleScope scope(isolate);
7857 ASSERT(args.length() == 1);
7858 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7859 uint64_t integer = double_to_uint64(x);
7860 integer = (integer >> 32) & 0xFFFFFFFFu;
7861 return *isolate->factory()->NewNumber(static_cast<int32_t>(integer));
7865 RUNTIME_FUNCTION(Runtime_DoubleLo) {
7866 HandleScope scope(isolate);
7867 ASSERT(args.length() == 1);
7868 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7869 return *isolate->factory()->NewNumber(
7870 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
7874 RUNTIME_FUNCTION(Runtime_ConstructDouble) {
7875 HandleScope scope(isolate);
7876 ASSERT(args.length() == 2);
7877 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
7878 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
7879 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
7880 return *isolate->factory()->NewNumber(uint64_to_double(result));
7884 static const double kPiDividedBy4 = 0.78539816339744830962;
7887 RUNTIME_FUNCTION(Runtime_MathAtan2) {
7888 HandleScope scope(isolate);
7889 ASSERT(args.length() == 2);
7890 isolate->counters()->math_atan2()->Increment();
7892 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7893 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7895 if (std::isinf(x) && std::isinf(y)) {
7896 // Make sure that the result in case of two infinite arguments
7897 // is a multiple of Pi / 4. The sign of the result is determined
7898 // by the first argument (x) and the sign of the second argument
7899 // determines the multiplier: one or three.
7900 int multiplier = (x < 0) ? -1 : 1;
7901 if (y < 0) multiplier *= 3;
7902 result = multiplier * kPiDividedBy4;
7904 result = std::atan2(x, y);
7906 return *isolate->factory()->NewNumber(result);
7910 RUNTIME_FUNCTION(Runtime_MathExp) {
7911 HandleScope scope(isolate);
7912 ASSERT(args.length() == 1);
7913 isolate->counters()->math_exp()->Increment();
7915 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7916 lazily_initialize_fast_exp();
7917 return *isolate->factory()->NewNumber(fast_exp(x));
7921 RUNTIME_FUNCTION(Runtime_MathFloor) {
7922 HandleScope scope(isolate);
7923 ASSERT(args.length() == 1);
7924 isolate->counters()->math_floor()->Increment();
7926 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7927 return *isolate->factory()->NewNumber(std::floor(x));
7931 // Slow version of Math.pow. We check for fast paths for special cases.
7932 // Used if SSE2/VFP3 is not available.
7933 RUNTIME_FUNCTION(RuntimeHidden_MathPowSlow) {
7934 HandleScope scope(isolate);
7935 ASSERT(args.length() == 2);
7936 isolate->counters()->math_pow()->Increment();
7938 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7940 // If the second argument is a smi, it is much faster to call the
7941 // custom powi() function than the generic pow().
7942 if (args[1]->IsSmi()) {
7943 int y = args.smi_at(1);
7944 return *isolate->factory()->NewNumber(power_double_int(x, y));
7947 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7948 double result = power_helper(x, y);
7949 if (std::isnan(result)) return isolate->heap()->nan_value();
7950 return *isolate->factory()->NewNumber(result);
7954 // Fast version of Math.pow if we know that y is not an integer and y is not
7955 // -0.5 or 0.5. Used as slow case from full codegen.
7956 RUNTIME_FUNCTION(RuntimeHidden_MathPow) {
7957 HandleScope scope(isolate);
7958 ASSERT(args.length() == 2);
7959 isolate->counters()->math_pow()->Increment();
7961 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7962 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7964 return Smi::FromInt(1);
7966 double result = power_double_double(x, y);
7967 if (std::isnan(result)) return isolate->heap()->nan_value();
7968 return *isolate->factory()->NewNumber(result);
7973 RUNTIME_FUNCTION(Runtime_RoundNumber) {
7974 HandleScope scope(isolate);
7975 ASSERT(args.length() == 1);
7976 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
7977 isolate->counters()->math_round()->Increment();
7979 if (!input->IsHeapNumber()) {
7980 ASSERT(input->IsSmi());
7984 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
7986 double value = number->value();
7987 int exponent = number->get_exponent();
7988 int sign = number->get_sign();
7990 if (exponent < -1) {
7991 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7992 if (sign) return isolate->heap()->minus_zero_value();
7993 return Smi::FromInt(0);
7996 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7997 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7998 // argument holds for 32-bit smis).
7999 if (!sign && exponent < kSmiValueSize - 2) {
8000 return Smi::FromInt(static_cast<int>(value + 0.5));
8003 // If the magnitude is big enough, there's no place for fraction part. If we
8004 // try to add 0.5 to this number, 1.0 will be added instead.
8005 if (exponent >= 52) {
8009 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
8011 // Do not call NumberFromDouble() to avoid extra checks.
8012 return *isolate->factory()->NewNumber(std::floor(value + 0.5));
8016 RUNTIME_FUNCTION(Runtime_MathSqrt) {
8017 HandleScope scope(isolate);
8018 ASSERT(args.length() == 1);
8019 isolate->counters()->math_sqrt()->Increment();
8021 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
8022 return *isolate->factory()->NewNumber(fast_sqrt(x));
8026 RUNTIME_FUNCTION(Runtime_MathFround) {
8027 HandleScope scope(isolate);
8028 ASSERT(args.length() == 1);
8030 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
8031 float xf = static_cast<float>(x);
8032 return *isolate->factory()->NewNumber(xf);
8036 RUNTIME_FUNCTION(Runtime_DateMakeDay) {
8037 SealHandleScope shs(isolate);
8038 ASSERT(args.length() == 2);
8040 CONVERT_SMI_ARG_CHECKED(year, 0);
8041 CONVERT_SMI_ARG_CHECKED(month, 1);
8043 int days = isolate->date_cache()->DaysFromYearMonth(year, month);
8044 RUNTIME_ASSERT(Smi::IsValid(days));
8045 return Smi::FromInt(days);
8049 RUNTIME_FUNCTION(Runtime_DateSetValue) {
8050 HandleScope scope(isolate);
8051 ASSERT(args.length() == 3);
8053 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
8054 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
8055 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
8057 DateCache* date_cache = isolate->date_cache();
8059 Handle<Object> value;;
8060 bool is_value_nan = false;
8061 if (std::isnan(time)) {
8062 value = isolate->factory()->nan_value();
8063 is_value_nan = true;
8064 } else if (!is_utc &&
8065 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
8066 time > DateCache::kMaxTimeBeforeUTCInMs)) {
8067 value = isolate->factory()->nan_value();
8068 is_value_nan = true;
8070 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
8071 if (time < -DateCache::kMaxTimeInMs ||
8072 time > DateCache::kMaxTimeInMs) {
8073 value = isolate->factory()->nan_value();
8074 is_value_nan = true;
8076 value = isolate->factory()->NewNumber(DoubleToInteger(time));
8079 date->SetValue(*value, is_value_nan);
8084 RUNTIME_FUNCTION(RuntimeHidden_NewArgumentsFast) {
8085 HandleScope scope(isolate);
8086 ASSERT(args.length() == 3);
8088 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
8089 Object** parameters = reinterpret_cast<Object**>(args[1]);
8090 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
8092 Handle<JSObject> result =
8093 isolate->factory()->NewArgumentsObject(callee, argument_count);
8094 // Allocate the elements if needed.
8095 int parameter_count = callee->shared()->formal_parameter_count();
8096 if (argument_count > 0) {
8097 if (parameter_count > 0) {
8098 int mapped_count = Min(argument_count, parameter_count);
8099 Handle<FixedArray> parameter_map =
8100 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
8101 parameter_map->set_map(
8102 isolate->heap()->sloppy_arguments_elements_map());
8104 Handle<Map> map = Map::Copy(handle(result->map()));
8105 map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
8107 result->set_map(*map);
8108 result->set_elements(*parameter_map);
8110 // Store the context and the arguments array at the beginning of the
8112 Handle<Context> context(isolate->context());
8113 Handle<FixedArray> arguments =
8114 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8115 parameter_map->set(0, *context);
8116 parameter_map->set(1, *arguments);
8118 // Loop over the actual parameters backwards.
8119 int index = argument_count - 1;
8120 while (index >= mapped_count) {
8121 // These go directly in the arguments array and have no
8122 // corresponding slot in the parameter map.
8123 arguments->set(index, *(parameters - index - 1));
8127 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
8128 while (index >= 0) {
8129 // Detect duplicate names to the right in the parameter list.
8130 Handle<String> name(scope_info->ParameterName(index));
8131 int context_local_count = scope_info->ContextLocalCount();
8132 bool duplicate = false;
8133 for (int j = index + 1; j < parameter_count; ++j) {
8134 if (scope_info->ParameterName(j) == *name) {
8141 // This goes directly in the arguments array with a hole in the
8143 arguments->set(index, *(parameters - index - 1));
8144 parameter_map->set_the_hole(index + 2);
8146 // The context index goes in the parameter map with a hole in the
8148 int context_index = -1;
8149 for (int j = 0; j < context_local_count; ++j) {
8150 if (scope_info->ContextLocalName(j) == *name) {
8155 ASSERT(context_index >= 0);
8156 arguments->set_the_hole(index);
8157 parameter_map->set(index + 2, Smi::FromInt(
8158 Context::MIN_CONTEXT_SLOTS + context_index));
8164 // If there is no aliasing, the arguments object elements are not
8165 // special in any way.
8166 Handle<FixedArray> elements =
8167 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8168 result->set_elements(*elements);
8169 for (int i = 0; i < argument_count; ++i) {
8170 elements->set(i, *(parameters - i - 1));
8178 RUNTIME_FUNCTION(RuntimeHidden_NewStrictArgumentsFast) {
8179 HandleScope scope(isolate);
8180 ASSERT(args.length() == 3);
8181 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
8182 Object** parameters = reinterpret_cast<Object**>(args[1]);
8183 CONVERT_SMI_ARG_CHECKED(length, 2);
8185 Handle<JSObject> result =
8186 isolate->factory()->NewArgumentsObject(callee, length);
8189 Handle<FixedArray> array =
8190 isolate->factory()->NewUninitializedFixedArray(length);
8191 DisallowHeapAllocation no_gc;
8192 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
8193 for (int i = 0; i < length; i++) {
8194 array->set(i, *--parameters, mode);
8196 result->set_elements(*array);
8202 RUNTIME_FUNCTION(RuntimeHidden_NewClosureFromStubFailure) {
8203 HandleScope scope(isolate);
8204 ASSERT(args.length() == 1);
8205 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8206 Handle<Context> context(isolate->context());
8207 PretenureFlag pretenure_flag = NOT_TENURED;
8208 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
8209 shared, context, pretenure_flag);
8213 RUNTIME_FUNCTION(RuntimeHidden_NewClosure) {
8214 HandleScope scope(isolate);
8215 ASSERT(args.length() == 3);
8216 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8217 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8218 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
8220 // The caller ensures that we pretenure closures that are assigned
8221 // directly to properties.
8222 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
8223 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
8224 shared, context, pretenure_flag);
8228 // Find the arguments of the JavaScript function invocation that called
8229 // into C++ code. Collect these in a newly allocated array of handles (possibly
8230 // prefixed by a number of empty handles).
8231 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8235 // Find frame containing arguments passed to the caller.
8236 JavaScriptFrameIterator it(isolate);
8237 JavaScriptFrame* frame = it.frame();
8238 List<JSFunction*> functions(2);
8239 frame->GetFunctions(&functions);
8240 if (functions.length() > 1) {
8241 int inlined_jsframe_index = functions.length() - 1;
8242 JSFunction* inlined_function = functions[inlined_jsframe_index];
8243 SlotRefValueBuilder slot_refs(
8245 inlined_jsframe_index,
8246 inlined_function->shared()->formal_parameter_count());
8248 int args_count = slot_refs.args_length();
8250 *total_argc = prefix_argc + args_count;
8251 SmartArrayPointer<Handle<Object> > param_data(
8252 NewArray<Handle<Object> >(*total_argc));
8253 slot_refs.Prepare(isolate);
8254 for (int i = 0; i < args_count; i++) {
8255 Handle<Object> val = slot_refs.GetNext(isolate, 0);
8256 param_data[prefix_argc + i] = val;
8258 slot_refs.Finish(isolate);
8262 it.AdvanceToArgumentsFrame();
8264 int args_count = frame->ComputeParametersCount();
8266 *total_argc = prefix_argc + args_count;
8267 SmartArrayPointer<Handle<Object> > param_data(
8268 NewArray<Handle<Object> >(*total_argc));
8269 for (int i = 0; i < args_count; i++) {
8270 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
8271 param_data[prefix_argc + i] = val;
8278 RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
8279 HandleScope scope(isolate);
8280 ASSERT(args.length() == 4);
8281 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
8282 RUNTIME_ASSERT(args[3]->IsNumber());
8283 Handle<Object> bindee = args.at<Object>(1);
8285 // TODO(lrn): Create bound function in C++ code from premade shared info.
8286 bound_function->shared()->set_bound(true);
8287 // Get all arguments of calling function (Function.prototype.bind).
8289 SmartArrayPointer<Handle<Object> > arguments =
8290 GetCallerArguments(isolate, 0, &argc);
8291 // Don't count the this-arg.
8293 RUNTIME_ASSERT(*arguments[0] == args[2]);
8296 RUNTIME_ASSERT(args[2]->IsUndefined());
8298 // Initialize array of bindings (function, this, and any existing arguments
8299 // if the function was already bound).
8300 Handle<FixedArray> new_bindings;
8302 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8303 Handle<FixedArray> old_bindings(
8304 JSFunction::cast(*bindee)->function_bindings());
8305 RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex);
8307 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8308 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8311 for (int n = old_bindings->length(); i < n; i++) {
8312 new_bindings->set(i, old_bindings->get(i));
8315 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8316 new_bindings = isolate->factory()->NewFixedArray(array_size);
8317 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8318 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8321 // Copy arguments, skipping the first which is "this_arg".
8322 for (int j = 0; j < argc; j++, i++) {
8323 new_bindings->set(i, *arguments[j + 1]);
8325 new_bindings->set_map_no_write_barrier(
8326 isolate->heap()->fixed_cow_array_map());
8327 bound_function->set_function_bindings(*new_bindings);
8330 Handle<String> length_string = isolate->factory()->length_string();
8331 Handle<Object> new_length(args.at<Object>(3));
8332 PropertyAttributes attr =
8333 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8334 Runtime::ForceSetObjectProperty(
8335 bound_function, length_string, new_length, attr).Assert();
8336 return *bound_function;
8340 RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
8341 HandleScope handles(isolate);
8342 ASSERT(args.length() == 1);
8343 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
8344 if (callable->IsJSFunction()) {
8345 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8346 if (function->shared()->bound()) {
8347 Handle<FixedArray> bindings(function->function_bindings());
8348 RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8349 return *isolate->factory()->NewJSArrayWithElements(bindings);
8352 return isolate->heap()->undefined_value();
8356 RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
8357 HandleScope scope(isolate);
8358 ASSERT(args.length() == 1);
8359 // First argument is a function to use as a constructor.
8360 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8361 RUNTIME_ASSERT(function->shared()->bound());
8363 // The argument is a bound function. Extract its bound arguments
8365 Handle<FixedArray> bound_args =
8366 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8367 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8368 Handle<Object> bound_function(
8369 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8371 ASSERT(!bound_function->IsJSFunction() ||
8372 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
8375 SmartArrayPointer<Handle<Object> > param_data =
8376 GetCallerArguments(isolate, bound_argc, &total_argc);
8377 for (int i = 0; i < bound_argc; i++) {
8378 param_data[i] = Handle<Object>(bound_args->get(
8379 JSFunction::kBoundArgumentsStartIndex + i), isolate);
8382 if (!bound_function->IsJSFunction()) {
8383 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
8384 isolate, bound_function,
8385 Execution::TryGetConstructorDelegate(isolate, bound_function));
8387 ASSERT(bound_function->IsJSFunction());
8389 Handle<Object> result;
8390 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
8392 Execution::New(Handle<JSFunction>::cast(bound_function),
8393 total_argc, param_data.get()));
8398 static Object* Runtime_NewObjectHelper(Isolate* isolate,
8399 Handle<Object> constructor,
8400 Handle<AllocationSite> site) {
8401 // If the constructor isn't a proper function we throw a type error.
8402 if (!constructor->IsJSFunction()) {
8403 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8404 Handle<Object> type_error =
8405 isolate->factory()->NewTypeError("not_constructor", arguments);
8406 return isolate->Throw(*type_error);
8409 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
8411 // If function should not have prototype, construction is not allowed. In this
8412 // case generated code bailouts here, since function has no initial_map.
8413 if (!function->should_have_prototype() && !function->shared()->bound()) {
8414 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8415 Handle<Object> type_error =
8416 isolate->factory()->NewTypeError("not_constructor", arguments);
8417 return isolate->Throw(*type_error);
8420 Debug* debug = isolate->debug();
8421 // Handle stepping into constructors if step into is active.
8422 if (debug->StepInActive()) {
8423 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
8426 if (function->has_initial_map()) {
8427 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
8428 // The 'Function' function ignores the receiver object when
8429 // called using 'new' and creates a new JSFunction object that
8430 // is returned. The receiver object is only used for error
8431 // reporting if an error occurs when constructing the new
8432 // JSFunction. Factory::NewJSObject() should not be used to
8433 // allocate JSFunctions since it does not properly initialize
8434 // the shared part of the function. Since the receiver is
8435 // ignored anyway, we use the global object as the receiver
8436 // instead of a new JSFunction object. This way, errors are
8437 // reported the same way whether or not 'Function' is called
8439 return isolate->context()->global_object();
8443 // The function should be compiled for the optimization hints to be
8445 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
8447 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
8448 if (!function->has_initial_map() &&
8449 shared->IsInobjectSlackTrackingInProgress()) {
8450 // The tracking is already in progress for another function. We can only
8451 // track one initial_map at a time, so we force the completion before the
8452 // function is called as a constructor for the first time.
8453 shared->CompleteInobjectSlackTracking();
8456 Handle<JSObject> result;
8457 if (site.is_null()) {
8458 result = isolate->factory()->NewJSObject(function);
8460 result = isolate->factory()->NewJSObjectWithMemento(function, site);
8463 isolate->counters()->constructed_objects()->Increment();
8464 isolate->counters()->constructed_objects_runtime()->Increment();
8470 RUNTIME_FUNCTION(RuntimeHidden_NewObject) {
8471 HandleScope scope(isolate);
8472 ASSERT(args.length() == 1);
8473 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
8474 return Runtime_NewObjectHelper(isolate,
8476 Handle<AllocationSite>::null());
8480 RUNTIME_FUNCTION(RuntimeHidden_NewObjectWithAllocationSite) {
8481 HandleScope scope(isolate);
8482 ASSERT(args.length() == 2);
8483 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
8484 CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
8485 Handle<AllocationSite> site;
8486 if (feedback->IsAllocationSite()) {
8487 // The feedback can be an AllocationSite or undefined.
8488 site = Handle<AllocationSite>::cast(feedback);
8490 return Runtime_NewObjectHelper(isolate, constructor, site);
8494 RUNTIME_FUNCTION(RuntimeHidden_FinalizeInstanceSize) {
8495 HandleScope scope(isolate);
8496 ASSERT(args.length() == 1);
8498 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8499 function->shared()->CompleteInobjectSlackTracking();
8501 return isolate->heap()->undefined_value();
8505 RUNTIME_FUNCTION(RuntimeHidden_CompileUnoptimized) {
8506 HandleScope scope(isolate);
8507 ASSERT(args.length() == 1);
8508 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8510 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
8511 PrintF("[unoptimized: ");
8512 function->PrintName();
8517 // Compile the target function.
8518 ASSERT(function->shared()->allows_lazy_compilation());
8521 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
8522 Compiler::GetUnoptimizedCode(function));
8523 function->ReplaceCode(*code);
8525 // All done. Return the compiled code.
8526 ASSERT(function->is_compiled());
8527 ASSERT(function->code()->kind() == Code::FUNCTION ||
8529 function->code()->kind() == Code::OPTIMIZED_FUNCTION));
8534 RUNTIME_FUNCTION(RuntimeHidden_CompileOptimized) {
8535 HandleScope scope(isolate);
8536 ASSERT(args.length() == 2);
8537 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8538 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
8540 Handle<Code> unoptimized(function->shared()->code());
8541 if (!function->shared()->is_compiled()) {
8542 // If the function is not compiled, do not optimize.
8543 // This can happen if the debugger is activated and
8544 // the function is returned to the not compiled state.
8545 // TODO(yangguo): reconsider this.
8546 function->ReplaceCode(function->shared()->code());
8547 } else if (!isolate->use_crankshaft() ||
8548 function->shared()->optimization_disabled() ||
8549 isolate->DebuggerHasBreakPoints()) {
8550 // If the function is not optimizable or debugger is active continue
8551 // using the code from the full compiler.
8552 if (FLAG_trace_opt) {
8553 PrintF("[failed to optimize ");
8554 function->PrintName();
8555 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8556 function->shared()->optimization_disabled() ? "F" : "T",
8557 isolate->DebuggerHasBreakPoints() ? "T" : "F");
8559 function->ReplaceCode(*unoptimized);
8561 Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT
8562 : Compiler::NOT_CONCURRENT;
8564 if (Compiler::GetOptimizedCode(
8565 function, unoptimized, mode).ToHandle(&code)) {
8566 function->ReplaceCode(*code);
8568 function->ReplaceCode(*unoptimized);
8572 ASSERT(function->code()->kind() == Code::FUNCTION ||
8573 function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
8574 function->IsInOptimizationQueue());
8575 return function->code();
8579 class ActivationsFinder : public ThreadVisitor {
8582 bool has_code_activations_;
8584 explicit ActivationsFinder(Code* code)
8586 has_code_activations_(false) { }
8588 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8589 JavaScriptFrameIterator it(isolate, top);
8593 void VisitFrames(JavaScriptFrameIterator* it) {
8594 for (; !it->done(); it->Advance()) {
8595 JavaScriptFrame* frame = it->frame();
8596 if (code_->contains(frame->pc())) has_code_activations_ = true;
8602 RUNTIME_FUNCTION(RuntimeHidden_NotifyStubFailure) {
8603 HandleScope scope(isolate);
8604 ASSERT(args.length() == 0);
8605 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8606 ASSERT(AllowHeapAllocation::IsAllowed());
8608 return isolate->heap()->undefined_value();
8612 RUNTIME_FUNCTION(RuntimeHidden_NotifyDeoptimized) {
8613 HandleScope scope(isolate);
8614 ASSERT(args.length() == 1);
8615 CONVERT_SMI_ARG_CHECKED(type_arg, 0);
8616 Deoptimizer::BailoutType type =
8617 static_cast<Deoptimizer::BailoutType>(type_arg);
8618 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8619 ASSERT(AllowHeapAllocation::IsAllowed());
8621 Handle<JSFunction> function = deoptimizer->function();
8622 Handle<Code> optimized_code = deoptimizer->compiled_code();
8624 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8625 ASSERT(type == deoptimizer->bailout_type());
8627 // Make sure to materialize objects before causing any allocation.
8628 JavaScriptFrameIterator it(isolate);
8629 deoptimizer->MaterializeHeapObjects(&it);
8632 JavaScriptFrame* frame = it.frame();
8633 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8634 ASSERT(frame->function() == *function);
8636 // Avoid doing too much work when running with --always-opt and keep
8637 // the optimized code around.
8638 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
8639 return isolate->heap()->undefined_value();
8642 // Search for other activations of the same function and code.
8643 ActivationsFinder activations_finder(*optimized_code);
8644 activations_finder.VisitFrames(&it);
8645 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8647 if (!activations_finder.has_code_activations_) {
8648 if (function->code() == *optimized_code) {
8649 if (FLAG_trace_deopt) {
8650 PrintF("[removing optimized code for: ");
8651 function->PrintName();
8654 function->ReplaceCode(function->shared()->code());
8655 // Evict optimized code for this function from the cache so that it
8656 // doesn't get used for new closures.
8657 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8658 "notify deoptimized");
8661 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8662 // unconditionally if the code is not already marked for deoptimization.
8663 // If there is an index by shared function info, all the better.
8664 Deoptimizer::DeoptimizeFunction(*function);
8667 return isolate->heap()->undefined_value();
8671 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
8672 HandleScope scope(isolate);
8673 ASSERT(args.length() == 1);
8674 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8675 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
8677 Deoptimizer::DeoptimizeFunction(*function);
8679 return isolate->heap()->undefined_value();
8683 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
8684 HandleScope scope(isolate);
8685 ASSERT(args.length() == 1);
8686 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8687 function->shared()->ClearTypeFeedbackInfo();
8688 Code* unoptimized = function->shared()->code();
8689 if (unoptimized->kind() == Code::FUNCTION) {
8690 unoptimized->ClearInlineCaches();
8692 return isolate->heap()->undefined_value();
8696 RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
8697 SealHandleScope shs(isolate);
8698 ASSERT(args.length() == 0);
8699 #if defined(USE_SIMULATOR)
8700 return isolate->heap()->true_value();
8702 return isolate->heap()->false_value();
8707 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
8708 SealHandleScope shs(isolate);
8709 ASSERT(args.length() == 0);
8710 return isolate->heap()->ToBoolean(
8711 isolate->concurrent_recompilation_enabled());
8715 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
8716 HandleScope scope(isolate);
8717 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8718 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8720 if (!function->IsOptimizable() &&
8721 !function->IsMarkedForConcurrentOptimization() &&
8722 !function->IsInOptimizationQueue()) {
8723 return isolate->heap()->undefined_value();
8726 function->MarkForOptimization();
8728 Code* unoptimized = function->shared()->code();
8729 if (args.length() == 2 &&
8730 unoptimized->kind() == Code::FUNCTION) {
8731 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8732 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
8733 // Start patching from the currently patched loop nesting level.
8734 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
8735 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
8736 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
8737 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8738 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8740 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) &&
8741 isolate->concurrent_recompilation_enabled()) {
8742 function->MarkForConcurrentOptimization();
8746 return isolate->heap()->undefined_value();
8750 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
8751 HandleScope scope(isolate);
8752 ASSERT(args.length() == 1);
8753 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8754 function->shared()->set_optimization_disabled(true);
8755 return isolate->heap()->undefined_value();
8759 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
8760 HandleScope scope(isolate);
8761 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8762 if (!isolate->use_crankshaft()) {
8763 return Smi::FromInt(4); // 4 == "never".
8765 bool sync_with_compiler_thread = true;
8766 if (args.length() == 2) {
8767 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8768 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8769 sync_with_compiler_thread = false;
8772 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8773 if (isolate->concurrent_recompilation_enabled() &&
8774 sync_with_compiler_thread) {
8775 while (function->IsInOptimizationQueue()) {
8776 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8780 if (FLAG_always_opt) {
8781 // We may have always opt, but that is more best-effort than a real
8782 // promise, so we still say "no" if it is not optimized.
8783 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8784 : Smi::FromInt(2); // 2 == "no".
8786 if (FLAG_deopt_every_n_times) {
8787 return Smi::FromInt(6); // 6 == "maybe deopted".
8789 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8790 : Smi::FromInt(2); // 2 == "no".
8794 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
8795 ASSERT(args.length() == 0);
8796 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8797 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
8798 isolate->optimizing_compiler_thread()->Unblock();
8799 return isolate->heap()->undefined_value();
8803 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
8804 HandleScope scope(isolate);
8805 ASSERT(args.length() == 1);
8806 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8807 return Smi::FromInt(function->shared()->opt_count());
8811 static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8812 Handle<JSFunction> function,
8813 Handle<Code> current_code) {
8814 // Keep track of whether we've succeeded in optimizing.
8815 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
8816 // If we are trying to do OSR when there are already optimized
8817 // activations of the function, it means (a) the function is directly or
8818 // indirectly recursive and (b) an optimized invocation has been
8819 // deoptimized so that we are currently in an unoptimized activation.
8820 // Check for optimized activations of this function.
8821 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8822 JavaScriptFrame* frame = it.frame();
8823 if (frame->is_optimized() && frame->function() == *function) return false;
8830 RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
8831 HandleScope scope(isolate);
8832 ASSERT(args.length() == 1);
8833 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8834 Handle<Code> caller_code(function->shared()->code());
8836 // We're not prepared to handle a function with arguments object.
8837 ASSERT(!function->shared()->uses_arguments());
8839 // Passing the PC in the javascript frame from the caller directly is
8840 // not GC safe, so we walk the stack to get it.
8841 JavaScriptFrameIterator it(isolate);
8842 JavaScriptFrame* frame = it.frame();
8843 if (!caller_code->contains(frame->pc())) {
8844 // Code on the stack may not be the code object referenced by the shared
8845 // function info. It may have been replaced to include deoptimization data.
8846 caller_code = Handle<Code>(frame->LookupCode());
8849 uint32_t pc_offset = static_cast<uint32_t>(
8850 frame->pc() - caller_code->instruction_start());
8853 ASSERT_EQ(frame->function(), *function);
8854 ASSERT_EQ(frame->LookupCode(), *caller_code);
8855 ASSERT(caller_code->contains(frame->pc()));
8859 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
8860 ASSERT(!ast_id.IsNone());
8862 Compiler::ConcurrencyMode mode = isolate->concurrent_osr_enabled()
8863 ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
8864 Handle<Code> result = Handle<Code>::null();
8866 OptimizedCompileJob* job = NULL;
8867 if (mode == Compiler::CONCURRENT) {
8868 // Gate the OSR entry with a stack check.
8869 BackEdgeTable::AddStackCheck(caller_code, pc_offset);
8870 // Poll already queued compilation jobs.
8871 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
8872 if (thread->IsQueuedForOSR(function, ast_id)) {
8873 if (FLAG_trace_osr) {
8874 PrintF("[OSR - Still waiting for queued: ");
8875 function->PrintName();
8876 PrintF(" at AST id %d]\n", ast_id.ToInt());
8881 job = thread->FindReadyOSRCandidate(function, ast_id);
8885 if (FLAG_trace_osr) {
8886 PrintF("[OSR - Found ready: ");
8887 function->PrintName();
8888 PrintF(" at AST id %d]\n", ast_id.ToInt());
8890 result = Compiler::GetConcurrentlyOptimizedCode(job);
8891 } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
8892 if (FLAG_trace_osr) {
8893 PrintF("[OSR - Compiling: ");
8894 function->PrintName();
8895 PrintF(" at AST id %d]\n", ast_id.ToInt());
8897 MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode(
8898 function, caller_code, mode, ast_id);
8899 if (maybe_result.ToHandle(&result) &&
8900 result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
8901 // Optimization is queued. Return to check later.
8906 // Revert the patched back edge table, regardless of whether OSR succeeds.
8907 BackEdgeTable::Revert(isolate, *caller_code);
8909 // Check whether we ended up with usable optimized code.
8910 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8911 DeoptimizationInputData* data =
8912 DeoptimizationInputData::cast(result->deoptimization_data());
8914 if (data->OsrPcOffset()->value() >= 0) {
8915 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8916 if (FLAG_trace_osr) {
8917 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
8918 ast_id.ToInt(), data->OsrPcOffset()->value());
8920 // TODO(titzer): this is a massive hack to make the deopt counts
8921 // match. Fix heuristics for reenabling optimizations!
8922 function->shared()->increment_deopt_count();
8924 // TODO(titzer): Do not install code into the function.
8925 function->ReplaceCode(*result);
8931 if (FLAG_trace_osr) {
8932 PrintF("[OSR - Failed: ");
8933 function->PrintName();
8934 PrintF(" at AST id %d]\n", ast_id.ToInt());
8937 if (!function->IsOptimized()) {
8938 function->ReplaceCode(function->shared()->code());
8944 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
8945 SealHandleScope shs(isolate);
8946 ASSERT(args.length() == 2 || args.length() == 3);
8948 CONVERT_SMI_ARG_CHECKED(interval, 0);
8949 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8950 isolate->heap()->set_allocation_timeout(timeout);
8951 FLAG_gc_interval = interval;
8952 if (args.length() == 3) {
8953 // Enable/disable inline allocation if requested.
8954 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
8955 if (inline_allocation) {
8956 isolate->heap()->EnableInlineAllocation();
8958 isolate->heap()->DisableInlineAllocation();
8962 return isolate->heap()->undefined_value();
8966 RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
8967 SealHandleScope shs(isolate);
8968 ASSERT(args.length() == 0);
8969 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8970 return isolate->heap()->undefined_value();
8974 RUNTIME_FUNCTION(Runtime_GetRootNaN) {
8975 SealHandleScope shs(isolate);
8976 ASSERT(args.length() == 0);
8977 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8978 return isolate->heap()->nan_value();
8982 RUNTIME_FUNCTION(Runtime_Call) {
8983 HandleScope scope(isolate);
8984 ASSERT(args.length() >= 2);
8985 int argc = args.length() - 2;
8986 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8987 Object* receiver = args[0];
8989 // If there are too many arguments, allocate argv via malloc.
8990 const int argv_small_size = 10;
8991 Handle<Object> argv_small_buffer[argv_small_size];
8992 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8993 Handle<Object>* argv = argv_small_buffer;
8994 if (argc > argv_small_size) {
8995 argv = new Handle<Object>[argc];
8996 if (argv == NULL) return isolate->StackOverflow();
8997 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
9000 for (int i = 0; i < argc; ++i) {
9001 argv[i] = Handle<Object>(args[1 + i], isolate);
9004 Handle<JSReceiver> hfun(fun);
9005 Handle<Object> hreceiver(receiver, isolate);
9006 Handle<Object> result;
9007 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9009 Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
9014 RUNTIME_FUNCTION(Runtime_Apply) {
9015 HandleScope scope(isolate);
9016 ASSERT(args.length() == 5);
9017 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
9018 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
9019 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
9020 CONVERT_SMI_ARG_CHECKED(offset, 3);
9021 CONVERT_SMI_ARG_CHECKED(argc, 4);
9022 RUNTIME_ASSERT(offset >= 0);
9023 // Loose upper bound to allow fuzzing. We'll most likely run out of
9024 // stack space before hitting this limit.
9025 static int kMaxArgc = 1000000;
9026 RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
9028 // If there are too many arguments, allocate argv via malloc.
9029 const int argv_small_size = 10;
9030 Handle<Object> argv_small_buffer[argv_small_size];
9031 SmartArrayPointer<Handle<Object> > argv_large_buffer;
9032 Handle<Object>* argv = argv_small_buffer;
9033 if (argc > argv_small_size) {
9034 argv = new Handle<Object>[argc];
9035 if (argv == NULL) return isolate->StackOverflow();
9036 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
9039 for (int i = 0; i < argc; ++i) {
9040 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9042 Object::GetElement(isolate, arguments, offset + i));
9045 Handle<Object> result;
9046 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9048 Execution::Call(isolate, fun, receiver, argc, argv, true));
9053 RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
9054 HandleScope scope(isolate);
9055 ASSERT(args.length() == 1);
9056 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
9057 RUNTIME_ASSERT(!object->IsJSFunction());
9058 return *Execution::GetFunctionDelegate(isolate, object);
9062 RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
9063 HandleScope scope(isolate);
9064 ASSERT(args.length() == 1);
9065 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
9066 RUNTIME_ASSERT(!object->IsJSFunction());
9067 return *Execution::GetConstructorDelegate(isolate, object);
9071 RUNTIME_FUNCTION(RuntimeHidden_NewGlobalContext) {
9072 HandleScope scope(isolate);
9073 ASSERT(args.length() == 2);
9075 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9076 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9077 Handle<Context> result =
9078 isolate->factory()->NewGlobalContext(function, scope_info);
9080 ASSERT(function->context() == isolate->context());
9081 ASSERT(function->context()->global_object() == result->global_object());
9082 result->global_object()->set_global_context(*result);
9087 RUNTIME_FUNCTION(RuntimeHidden_NewFunctionContext) {
9088 HandleScope scope(isolate);
9089 ASSERT(args.length() == 1);
9091 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9092 int length = function->shared()->scope_info()->ContextLength();
9093 return *isolate->factory()->NewFunctionContext(length, function);
9097 RUNTIME_FUNCTION(RuntimeHidden_PushWithContext) {
9098 HandleScope scope(isolate);
9099 ASSERT(args.length() == 2);
9100 Handle<JSReceiver> extension_object;
9101 if (args[0]->IsJSReceiver()) {
9102 extension_object = args.at<JSReceiver>(0);
9104 // Try to convert the object to a proper JavaScript object.
9105 MaybeHandle<JSReceiver> maybe_object =
9106 Object::ToObject(isolate, args.at<Object>(0));
9107 if (!maybe_object.ToHandle(&extension_object)) {
9108 Handle<Object> handle = args.at<Object>(0);
9109 Handle<Object> result =
9110 isolate->factory()->NewTypeError("with_expression",
9111 HandleVector(&handle, 1));
9112 return isolate->Throw(*result);
9116 Handle<JSFunction> function;
9117 if (args[1]->IsSmi()) {
9118 // A smi sentinel indicates a context nested inside global code rather
9119 // than some function. There is a canonical empty function that can be
9120 // gotten from the native context.
9121 function = handle(isolate->context()->native_context()->closure());
9123 function = args.at<JSFunction>(1);
9126 Handle<Context> current(isolate->context());
9127 Handle<Context> context = isolate->factory()->NewWithContext(
9128 function, current, extension_object);
9129 isolate->set_context(*context);
9134 RUNTIME_FUNCTION(RuntimeHidden_PushCatchContext) {
9135 HandleScope scope(isolate);
9136 ASSERT(args.length() == 3);
9137 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
9138 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
9139 Handle<JSFunction> function;
9140 if (args[2]->IsSmi()) {
9141 // A smi sentinel indicates a context nested inside global code rather
9142 // than some function. There is a canonical empty function that can be
9143 // gotten from the native context.
9144 function = handle(isolate->context()->native_context()->closure());
9146 function = args.at<JSFunction>(2);
9148 Handle<Context> current(isolate->context());
9149 Handle<Context> context = isolate->factory()->NewCatchContext(
9150 function, current, name, thrown_object);
9151 isolate->set_context(*context);
9156 RUNTIME_FUNCTION(RuntimeHidden_PushBlockContext) {
9157 HandleScope scope(isolate);
9158 ASSERT(args.length() == 2);
9159 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
9160 Handle<JSFunction> function;
9161 if (args[1]->IsSmi()) {
9162 // A smi sentinel indicates a context nested inside global code rather
9163 // than some function. There is a canonical empty function that can be
9164 // gotten from the native context.
9165 function = handle(isolate->context()->native_context()->closure());
9167 function = args.at<JSFunction>(1);
9169 Handle<Context> current(isolate->context());
9170 Handle<Context> context = isolate->factory()->NewBlockContext(
9171 function, current, scope_info);
9172 isolate->set_context(*context);
9177 RUNTIME_FUNCTION(Runtime_IsJSModule) {
9178 SealHandleScope shs(isolate);
9179 ASSERT(args.length() == 1);
9180 CONVERT_ARG_CHECKED(Object, obj, 0);
9181 return isolate->heap()->ToBoolean(obj->IsJSModule());
9185 RUNTIME_FUNCTION(RuntimeHidden_PushModuleContext) {
9186 SealHandleScope shs(isolate);
9187 ASSERT(args.length() == 2);
9188 CONVERT_SMI_ARG_CHECKED(index, 0);
9190 if (!args[1]->IsScopeInfo()) {
9191 // Module already initialized. Find hosting context and retrieve context.
9192 Context* host = Context::cast(isolate->context())->global_context();
9193 Context* context = Context::cast(host->get(index));
9194 ASSERT(context->previous() == isolate->context());
9195 isolate->set_context(context);
9199 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9201 // Allocate module context.
9202 HandleScope scope(isolate);
9203 Factory* factory = isolate->factory();
9204 Handle<Context> context = factory->NewModuleContext(scope_info);
9205 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
9206 context->set_module(*module);
9207 Context* previous = isolate->context();
9208 context->set_previous(previous);
9209 context->set_closure(previous->closure());
9210 context->set_global_object(previous->global_object());
9211 isolate->set_context(*context);
9213 // Find hosting scope and initialize internal variable holding module there.
9214 previous->global_context()->set(index, *context);
9220 RUNTIME_FUNCTION(RuntimeHidden_DeclareModules) {
9221 HandleScope scope(isolate);
9222 ASSERT(args.length() == 1);
9223 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9224 Context* host_context = isolate->context();
9226 for (int i = 0; i < descriptions->length(); ++i) {
9227 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9228 int host_index = description->host_index();
9229 Handle<Context> context(Context::cast(host_context->get(host_index)));
9230 Handle<JSModule> module(context->module());
9232 for (int j = 0; j < description->length(); ++j) {
9233 Handle<String> name(description->name(j));
9234 VariableMode mode = description->mode(j);
9235 int index = description->index(j);
9240 case CONST_LEGACY: {
9241 PropertyAttributes attr =
9242 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9243 Handle<AccessorInfo> info =
9244 Accessors::MakeModuleExport(name, index, attr);
9245 Handle<Object> result =
9246 JSObject::SetAccessor(module, info).ToHandleChecked();
9247 ASSERT(!result->IsUndefined());
9252 Object* referenced_context = Context::cast(host_context)->get(index);
9253 Handle<JSModule> value(Context::cast(referenced_context)->module());
9254 JSReceiver::SetProperty(module, name, value, FROZEN, STRICT).Assert();
9260 case DYNAMIC_GLOBAL:
9266 JSObject::PreventExtensions(module).Assert();
9269 ASSERT(!isolate->has_pending_exception());
9270 return isolate->heap()->undefined_value();
9274 RUNTIME_FUNCTION(RuntimeHidden_DeleteContextSlot) {
9275 HandleScope scope(isolate);
9276 ASSERT(args.length() == 2);
9278 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9279 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
9282 PropertyAttributes attributes;
9283 ContextLookupFlags flags = FOLLOW_CHAINS;
9284 BindingFlags binding_flags;
9285 Handle<Object> holder = context->Lookup(name,
9291 // If the slot was not found the result is true.
9292 if (holder.is_null()) {
9293 return isolate->heap()->true_value();
9296 // If the slot was found in a context, it should be DONT_DELETE.
9297 if (holder->IsContext()) {
9298 return isolate->heap()->false_value();
9301 // The slot was found in a JSObject, either a context extension object,
9302 // the global object, or the subject of a with. Try to delete it
9303 // (respecting DONT_DELETE).
9304 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9305 Handle<Object> result;
9306 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9308 JSReceiver::DeleteProperty(object, name));
9313 // A mechanism to return a pair of Object pointers in registers (if possible).
9314 // How this is achieved is calling convention-dependent.
9315 // All currently supported x86 compiles uses calling conventions that are cdecl
9316 // variants where a 64-bit value is returned in two 32-bit registers
9317 // (edx:eax on ia32, r1:r0 on ARM).
9318 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9319 // In Win64 calling convention, a struct of two pointers is returned in memory,
9320 // allocated by the caller, and passed as a pointer in a hidden first parameter.
9321 #ifdef V8_HOST_ARCH_64_BIT
9328 static inline ObjectPair MakePair(Object* x, Object* y) {
9329 ObjectPair result = {x, y};
9330 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9331 // In Win64 they are assigned to a hidden first argument.
9335 typedef uint64_t ObjectPair;
9336 static inline ObjectPair MakePair(Object* x, Object* y) {
9337 #if defined(V8_TARGET_LITTLE_ENDIAN)
9338 return reinterpret_cast<uint32_t>(x) |
9339 (reinterpret_cast<ObjectPair>(y) << 32);
9340 #elif defined(V8_TARGET_BIG_ENDIAN)
9341 return reinterpret_cast<uint32_t>(y) |
9342 (reinterpret_cast<ObjectPair>(x) << 32);
9344 #error Unknown endianness
9350 static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9352 ASSERT(!holder->IsGlobalObject());
9353 Context* top = isolate->context();
9354 // Get the context extension function.
9355 JSFunction* context_extension_function =
9356 top->native_context()->context_extension_function();
9357 // If the holder isn't a context extension object, we just return it
9358 // as the receiver. This allows arguments objects to be used as
9359 // receivers, but only if they are put in the context scope chain
9360 // explicitly via a with-statement.
9361 Object* constructor = holder->map()->constructor();
9362 if (constructor != context_extension_function) return holder;
9363 // Fall back to using the global object as the implicit receiver if
9364 // the property turns out to be a local variable allocated in a
9365 // context extension object - introduced via eval.
9366 return isolate->heap()->undefined_value();
9370 static ObjectPair LoadContextSlotHelper(Arguments args,
9373 HandleScope scope(isolate);
9374 ASSERT_EQ(2, args.length());
9376 if (!args[0]->IsContext() || !args[1]->IsString()) {
9377 return MakePair(isolate->ThrowIllegalOperation(), NULL);
9379 Handle<Context> context = args.at<Context>(0);
9380 Handle<String> name = args.at<String>(1);
9383 PropertyAttributes attributes;
9384 ContextLookupFlags flags = FOLLOW_CHAINS;
9385 BindingFlags binding_flags;
9386 Handle<Object> holder = context->Lookup(name,
9391 if (isolate->has_pending_exception()) {
9392 return MakePair(isolate->heap()->exception(), NULL);
9395 // If the index is non-negative, the slot has been found in a context.
9397 ASSERT(holder->IsContext());
9398 // If the "property" we were looking for is a local variable, the
9399 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
9400 Handle<Object> receiver = isolate->factory()->undefined_value();
9401 Object* value = Context::cast(*holder)->get(index);
9402 // Check for uninitialized bindings.
9403 switch (binding_flags) {
9404 case MUTABLE_CHECK_INITIALIZED:
9405 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9406 if (value->IsTheHole()) {
9407 Handle<Object> reference_error =
9408 isolate->factory()->NewReferenceError("not_defined",
9409 HandleVector(&name, 1));
9410 return MakePair(isolate->Throw(*reference_error), NULL);
9413 case MUTABLE_IS_INITIALIZED:
9414 case IMMUTABLE_IS_INITIALIZED:
9415 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9416 ASSERT(!value->IsTheHole());
9417 return MakePair(value, *receiver);
9418 case IMMUTABLE_CHECK_INITIALIZED:
9419 if (value->IsTheHole()) {
9420 ASSERT((attributes & READ_ONLY) != 0);
9421 value = isolate->heap()->undefined_value();
9423 return MakePair(value, *receiver);
9424 case MISSING_BINDING:
9426 return MakePair(NULL, NULL);
9430 // Otherwise, if the slot was found the holder is a context extension
9431 // object, subject of a with, or a global object. We read the named
9432 // property from it.
9433 if (!holder.is_null()) {
9434 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
9435 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
9436 // GetProperty below can cause GC.
9437 Handle<Object> receiver_handle(
9438 object->IsGlobalObject()
9439 ? Object::cast(isolate->heap()->undefined_value())
9440 : object->IsJSProxy() ? static_cast<Object*>(*object)
9441 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
9444 // No need to unhole the value here. This is taken care of by the
9445 // GetProperty function.
9446 Handle<Object> value;
9447 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9449 Object::GetProperty(object, name),
9450 MakePair(isolate->heap()->exception(), NULL));
9451 return MakePair(*value, *receiver_handle);
9455 // The property doesn't exist - throw exception.
9456 Handle<Object> reference_error =
9457 isolate->factory()->NewReferenceError("not_defined",
9458 HandleVector(&name, 1));
9459 return MakePair(isolate->Throw(*reference_error), NULL);
9461 // The property doesn't exist - return undefined.
9462 return MakePair(isolate->heap()->undefined_value(),
9463 isolate->heap()->undefined_value());
9468 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlot) {
9469 return LoadContextSlotHelper(args, isolate, true);
9473 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlotNoReferenceError) {
9474 return LoadContextSlotHelper(args, isolate, false);
9478 RUNTIME_FUNCTION(RuntimeHidden_StoreContextSlot) {
9479 HandleScope scope(isolate);
9480 ASSERT(args.length() == 4);
9482 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
9483 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9484 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
9485 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
9488 PropertyAttributes attributes;
9489 ContextLookupFlags flags = FOLLOW_CHAINS;
9490 BindingFlags binding_flags;
9491 Handle<Object> holder = context->Lookup(name,
9496 if (isolate->has_pending_exception()) return isolate->heap()->exception();
9499 // The property was found in a context slot.
9500 Handle<Context> context = Handle<Context>::cast(holder);
9501 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9502 context->get(index)->IsTheHole()) {
9503 Handle<Object> error =
9504 isolate->factory()->NewReferenceError("not_defined",
9505 HandleVector(&name, 1));
9506 return isolate->Throw(*error);
9508 // Ignore if read_only variable.
9509 if ((attributes & READ_ONLY) == 0) {
9510 // Context is a fixed array and set cannot fail.
9511 context->set(index, *value);
9512 } else if (strict_mode == STRICT) {
9513 // Setting read only property in strict mode.
9514 Handle<Object> error =
9515 isolate->factory()->NewTypeError("strict_cannot_assign",
9516 HandleVector(&name, 1));
9517 return isolate->Throw(*error);
9522 // Slow case: The property is not in a context slot. It is either in a
9523 // context extension object, a property of the subject of a with, or a
9524 // property of the global object.
9525 Handle<JSReceiver> object;
9527 if (!holder.is_null()) {
9528 // The property exists on the holder.
9529 object = Handle<JSReceiver>::cast(holder);
9531 // The property was not found.
9532 ASSERT(attributes == ABSENT);
9534 if (strict_mode == STRICT) {
9535 // Throw in strict mode (assignment to undefined variable).
9536 Handle<Object> error =
9537 isolate->factory()->NewReferenceError(
9538 "not_defined", HandleVector(&name, 1));
9539 return isolate->Throw(*error);
9541 // In sloppy mode, the property is added to the global object.
9543 object = Handle<JSReceiver>(isolate->context()->global_object());
9546 // Set the property if it's not read only or doesn't yet exist.
9547 if ((attributes & READ_ONLY) == 0 ||
9548 (JSReceiver::GetLocalPropertyAttribute(object, name) == ABSENT)) {
9549 RETURN_FAILURE_ON_EXCEPTION(
9551 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
9552 } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) {
9553 // Setting read only property in strict mode.
9554 Handle<Object> error =
9555 isolate->factory()->NewTypeError(
9556 "strict_cannot_assign", HandleVector(&name, 1));
9557 return isolate->Throw(*error);
9563 RUNTIME_FUNCTION(RuntimeHidden_Throw) {
9564 HandleScope scope(isolate);
9565 ASSERT(args.length() == 1);
9567 return isolate->Throw(args[0]);
9571 RUNTIME_FUNCTION(RuntimeHidden_ReThrow) {
9572 HandleScope scope(isolate);
9573 ASSERT(args.length() == 1);
9575 return isolate->ReThrow(args[0]);
9579 RUNTIME_FUNCTION(RuntimeHidden_PromoteScheduledException) {
9580 SealHandleScope shs(isolate);
9581 ASSERT(args.length() == 0);
9582 return isolate->PromoteScheduledException();
9586 RUNTIME_FUNCTION(RuntimeHidden_ThrowReferenceError) {
9587 HandleScope scope(isolate);
9588 ASSERT(args.length() == 1);
9589 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
9590 Handle<Object> reference_error =
9591 isolate->factory()->NewReferenceError("not_defined",
9592 HandleVector(&name, 1));
9593 return isolate->Throw(*reference_error);
9597 RUNTIME_FUNCTION(RuntimeHidden_ThrowNotDateError) {
9598 HandleScope scope(isolate);
9599 ASSERT(args.length() == 0);
9600 return isolate->Throw(*isolate->factory()->NewTypeError(
9601 "not_date_object", HandleVector<Object>(NULL, 0)));
9605 RUNTIME_FUNCTION(RuntimeHidden_ThrowMessage) {
9606 HandleScope scope(isolate);
9607 ASSERT(args.length() == 1);
9608 CONVERT_SMI_ARG_CHECKED(message_id, 0);
9609 const char* message = GetBailoutReason(
9610 static_cast<BailoutReason>(message_id));
9611 Handle<String> message_handle =
9612 isolate->factory()->NewStringFromAsciiChecked(message);
9613 return isolate->Throw(*message_handle);
9617 RUNTIME_FUNCTION(RuntimeHidden_StackGuard) {
9618 SealHandleScope shs(isolate);
9619 ASSERT(args.length() == 0);
9621 // First check if this is a real stack overflow.
9622 if (isolate->stack_guard()->IsStackOverflow()) {
9623 return isolate->StackOverflow();
9626 return Execution::HandleStackGuardInterrupt(isolate);
9630 RUNTIME_FUNCTION(RuntimeHidden_TryInstallOptimizedCode) {
9631 HandleScope scope(isolate);
9632 ASSERT(args.length() == 1);
9633 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9635 // First check if this is a real stack overflow.
9636 if (isolate->stack_guard()->IsStackOverflow()) {
9637 SealHandleScope shs(isolate);
9638 return isolate->StackOverflow();
9641 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9642 return (function->IsOptimized()) ? function->code()
9643 : function->shared()->code();
9647 RUNTIME_FUNCTION(RuntimeHidden_Interrupt) {
9648 SealHandleScope shs(isolate);
9649 ASSERT(args.length() == 0);
9650 return Execution::HandleStackGuardInterrupt(isolate);
9654 static int StackSize(Isolate* isolate) {
9656 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
9661 static void PrintTransition(Isolate* isolate, Object* result) {
9663 { const int nmax = 80;
9664 int n = StackSize(isolate);
9666 PrintF("%4d:%*s", n, n, "");
9668 PrintF("%4d:%*s", n, nmax, "...");
9671 if (result == NULL) {
9672 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
9677 result->ShortPrint();
9683 RUNTIME_FUNCTION(Runtime_TraceEnter) {
9684 SealHandleScope shs(isolate);
9685 ASSERT(args.length() == 0);
9686 PrintTransition(isolate, NULL);
9687 return isolate->heap()->undefined_value();
9691 RUNTIME_FUNCTION(Runtime_TraceExit) {
9692 SealHandleScope shs(isolate);
9693 ASSERT(args.length() == 1);
9694 CONVERT_ARG_CHECKED(Object, obj, 0);
9695 PrintTransition(isolate, obj);
9696 return obj; // return TOS
9700 RUNTIME_FUNCTION(Runtime_DebugPrint) {
9701 SealHandleScope shs(isolate);
9702 ASSERT(args.length() == 1);
9705 if (args[0]->IsString()) {
9706 // If we have a string, assume it's a code "marker"
9707 // and print some interesting cpu debugging info.
9708 JavaScriptFrameIterator it(isolate);
9709 JavaScriptFrame* frame = it.frame();
9710 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9711 frame->fp(), frame->sp(), frame->caller_sp());
9713 PrintF("DebugPrint: ");
9716 if (args[0]->IsHeapObject()) {
9718 HeapObject::cast(args[0])->map()->Print();
9721 // ShortPrint is available in release mode. Print is not.
9722 args[0]->ShortPrint();
9727 return args[0]; // return TOS
9731 RUNTIME_FUNCTION(Runtime_DebugTrace) {
9732 SealHandleScope shs(isolate);
9733 ASSERT(args.length() == 0);
9734 isolate->PrintStack(stdout);
9735 return isolate->heap()->undefined_value();
9739 RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
9740 HandleScope scope(isolate);
9741 ASSERT(args.length() == 0);
9743 // According to ECMA-262, section 15.9.1, page 117, the precision of
9744 // the number in a Date object representing a particular instant in
9745 // time is milliseconds. Therefore, we floor the result of getting
9747 double millis = std::floor(OS::TimeCurrentMillis());
9748 return *isolate->factory()->NewNumber(millis);
9752 RUNTIME_FUNCTION(Runtime_DateParseString) {
9753 HandleScope scope(isolate);
9754 ASSERT(args.length() == 2);
9755 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
9756 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
9758 RUNTIME_ASSERT(output->HasFastElements());
9759 JSObject::EnsureCanContainHeapObjectElements(output);
9760 RUNTIME_ASSERT(output->HasFastObjectElements());
9761 Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
9762 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9764 str = String::Flatten(str);
9765 DisallowHeapAllocation no_gc;
9768 String::FlatContent str_content = str->GetFlatContent();
9769 if (str_content.IsAscii()) {
9770 result = DateParser::Parse(str_content.ToOneByteVector(),
9772 isolate->unicode_cache());
9774 ASSERT(str_content.IsTwoByte());
9775 result = DateParser::Parse(str_content.ToUC16Vector(),
9777 isolate->unicode_cache());
9783 return isolate->heap()->null_value();
9788 RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
9789 HandleScope scope(isolate);
9790 ASSERT(args.length() == 1);
9792 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9794 isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
9795 Handle<String> result = isolate->factory()->NewStringFromUtf8(
9796 CStrVector(zone)).ToHandleChecked();
9801 RUNTIME_FUNCTION(Runtime_DateToUTC) {
9802 HandleScope scope(isolate);
9803 ASSERT(args.length() == 1);
9805 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9806 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9808 return *isolate->factory()->NewNumber(static_cast<double>(time));
9812 RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
9813 HandleScope hs(isolate);
9814 ASSERT(args.length() == 0);
9815 if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
9816 Handle<FixedArray> date_cache_version =
9817 isolate->factory()->NewFixedArray(1, TENURED);
9818 date_cache_version->set(0, Smi::FromInt(0));
9819 isolate->eternal_handles()->CreateSingleton(
9820 isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
9822 Handle<FixedArray> date_cache_version =
9823 Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
9824 EternalHandles::DATE_CACHE_VERSION));
9825 // Return result as a JS array.
9826 Handle<JSObject> result =
9827 isolate->factory()->NewJSObject(isolate->array_function());
9828 JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
9833 RUNTIME_FUNCTION(Runtime_GlobalReceiver) {
9834 SealHandleScope shs(isolate);
9835 ASSERT(args.length() == 1);
9836 CONVERT_ARG_CHECKED(Object, global, 0);
9837 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
9838 return JSGlobalObject::cast(global)->global_receiver();
9842 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) {
9843 SealHandleScope shs(isolate);
9844 ASSERT(args.length() == 1);
9845 CONVERT_ARG_CHECKED(Object, global, 0);
9846 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
9847 return isolate->heap()->ToBoolean(
9848 !JSGlobalObject::cast(global)->IsDetached());
9852 RUNTIME_FUNCTION(Runtime_ParseJson) {
9853 HandleScope scope(isolate);
9854 ASSERT(args.length() == 1);
9855 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9857 source = String::Flatten(source);
9858 // Optimized fast case where we only have ASCII characters.
9859 Handle<Object> result;
9860 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9862 source->IsSeqOneByteString() ? JsonParser<true>::Parse(source)
9863 : JsonParser<false>::Parse(source));
9868 bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9869 Handle<Context> context) {
9870 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9871 // Check with callback if set.
9872 AllowCodeGenerationFromStringsCallback callback =
9873 isolate->allow_code_gen_callback();
9874 if (callback == NULL) {
9875 // No callback set and code generation disallowed.
9878 // Callback set. Let it decide if code generation is allowed.
9879 VMState<EXTERNAL> state(isolate);
9880 return callback(v8::Utils::ToLocal(context));
9885 RUNTIME_FUNCTION(Runtime_CompileString) {
9886 HandleScope scope(isolate);
9887 ASSERT(args.length() == 2);
9888 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9889 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
9891 // Extract native context.
9892 Handle<Context> context(isolate->context()->native_context());
9894 // Check if native context allows code generation from
9895 // strings. Throw an exception if it doesn't.
9896 if (context->allow_code_gen_from_strings()->IsFalse() &&
9897 !CodeGenerationFromStringsAllowed(isolate, context)) {
9898 Handle<Object> error_message =
9899 context->ErrorMessageForCodeGenerationFromStrings();
9900 return isolate->Throw(*isolate->factory()->NewEvalError(
9901 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9904 // Compile source string in the native context.
9905 ParseRestriction restriction = function_literal_only
9906 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
9907 Handle<JSFunction> fun;
9908 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
9910 Compiler::GetFunctionFromEval(
9911 source, context, SLOPPY, restriction, RelocInfo::kNoPosition));
9916 static ObjectPair CompileGlobalEval(Isolate* isolate,
9917 Handle<String> source,
9918 Handle<Object> receiver,
9919 StrictMode strict_mode,
9920 int scope_position) {
9921 Handle<Context> context = Handle<Context>(isolate->context());
9922 Handle<Context> native_context = Handle<Context>(context->native_context());
9924 // Check if native context allows code generation from
9925 // strings. Throw an exception if it doesn't.
9926 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9927 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
9928 Handle<Object> error_message =
9929 native_context->ErrorMessageForCodeGenerationFromStrings();
9930 isolate->Throw(*isolate->factory()->NewEvalError(
9931 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9932 return MakePair(isolate->heap()->exception(), NULL);
9935 // Deal with a normal eval call with a string argument. Compile it
9936 // and return the compiled function bound in the local context.
9937 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
9938 Handle<JSFunction> compiled;
9939 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
9941 Compiler::GetFunctionFromEval(
9942 source, context, strict_mode, restriction, scope_position),
9943 MakePair(isolate->heap()->exception(), NULL));
9944 return MakePair(*compiled, *receiver);
9948 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_ResolvePossiblyDirectEval) {
9949 HandleScope scope(isolate);
9950 ASSERT(args.length() == 5);
9952 Handle<Object> callee = args.at<Object>(0);
9954 // If "eval" didn't refer to the original GlobalEval, it's not a
9955 // direct call to eval.
9956 // (And even if it is, but the first argument isn't a string, just let
9957 // execution default to an indirect call to eval, which will also return
9958 // the first argument without doing anything).
9959 if (*callee != isolate->native_context()->global_eval_fun() ||
9960 !args[1]->IsString()) {
9961 return MakePair(*callee, isolate->heap()->undefined_value());
9964 ASSERT(args[3]->IsSmi());
9965 ASSERT(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT);
9966 StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3));
9967 ASSERT(args[4]->IsSmi());
9968 return CompileGlobalEval(isolate,
9976 RUNTIME_FUNCTION(RuntimeHidden_AllocateInNewSpace) {
9977 HandleScope scope(isolate);
9978 ASSERT(args.length() == 1);
9979 CONVERT_SMI_ARG_CHECKED(size, 0);
9980 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9981 RUNTIME_ASSERT(size > 0);
9982 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
9983 return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE);
9987 RUNTIME_FUNCTION(RuntimeHidden_AllocateInTargetSpace) {
9988 HandleScope scope(isolate);
9989 ASSERT(args.length() == 2);
9990 CONVERT_SMI_ARG_CHECKED(size, 0);
9991 CONVERT_SMI_ARG_CHECKED(flags, 1);
9992 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9993 RUNTIME_ASSERT(size > 0);
9994 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
9995 bool double_align = AllocateDoubleAlignFlag::decode(flags);
9996 AllocationSpace space = AllocateTargetSpace::decode(flags);
9997 return *isolate->factory()->NewFillerObject(size, double_align, space);
10001 // Push an object unto an array of objects if it is not already in the
10002 // array. Returns true if the element was pushed on the stack and
10003 // false otherwise.
10004 RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
10005 HandleScope scope(isolate);
10006 ASSERT(args.length() == 2);
10007 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
10008 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
10009 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
10010 int length = Smi::cast(array->length())->value();
10011 FixedArray* elements = FixedArray::cast(array->elements());
10012 for (int i = 0; i < length; i++) {
10013 if (elements->get(i) == *element) return isolate->heap()->false_value();
10016 // Strict not needed. Used for cycle detection in Array join implementation.
10017 RETURN_FAILURE_ON_EXCEPTION(
10019 JSObject::SetFastElement(array, length, element, SLOPPY, true));
10020 return isolate->heap()->true_value();
10025 * A simple visitor visits every element of Array's.
10026 * The backend storage can be a fixed array for fast elements case,
10027 * or a dictionary for sparse array. Since Dictionary is a subtype
10028 * of FixedArray, the class can be used by both fast and slow cases.
10029 * The second parameter of the constructor, fast_elements, specifies
10030 * whether the storage is a FixedArray or Dictionary.
10032 * An index limit is used to deal with the situation that a result array
10033 * length overflows 32-bit non-negative integer.
10035 class ArrayConcatVisitor {
10037 ArrayConcatVisitor(Isolate* isolate,
10038 Handle<FixedArray> storage,
10039 bool fast_elements) :
10041 storage_(Handle<FixedArray>::cast(
10042 isolate->global_handles()->Create(*storage))),
10044 fast_elements_(fast_elements),
10045 exceeds_array_limit_(false) { }
10047 ~ArrayConcatVisitor() {
10051 void visit(uint32_t i, Handle<Object> elm) {
10052 if (i > JSObject::kMaxElementCount - index_offset_) {
10053 exceeds_array_limit_ = true;
10056 uint32_t index = index_offset_ + i;
10058 if (fast_elements_) {
10059 if (index < static_cast<uint32_t>(storage_->length())) {
10060 storage_->set(index, *elm);
10063 // Our initial estimate of length was foiled, possibly by
10064 // getters on the arrays increasing the length of later arrays
10065 // during iteration.
10066 // This shouldn't happen in anything but pathological cases.
10067 SetDictionaryMode(index);
10068 // Fall-through to dictionary mode.
10070 ASSERT(!fast_elements_);
10071 Handle<SeededNumberDictionary> dict(
10072 SeededNumberDictionary::cast(*storage_));
10073 Handle<SeededNumberDictionary> result =
10074 SeededNumberDictionary::AtNumberPut(dict, index, elm);
10075 if (!result.is_identical_to(dict)) {
10076 // Dictionary needed to grow.
10078 set_storage(*result);
10082 void increase_index_offset(uint32_t delta) {
10083 if (JSObject::kMaxElementCount - index_offset_ < delta) {
10084 index_offset_ = JSObject::kMaxElementCount;
10086 index_offset_ += delta;
10090 bool exceeds_array_limit() {
10091 return exceeds_array_limit_;
10094 Handle<JSArray> ToArray() {
10095 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
10096 Handle<Object> length =
10097 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
10098 Handle<Map> map = JSObject::GetElementsTransitionMap(
10100 fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
10101 array->set_map(*map);
10102 array->set_length(*length);
10103 array->set_elements(*storage_);
10108 // Convert storage to dictionary mode.
10109 void SetDictionaryMode(uint32_t index) {
10110 ASSERT(fast_elements_);
10111 Handle<FixedArray> current_storage(*storage_);
10112 Handle<SeededNumberDictionary> slow_storage(
10113 SeededNumberDictionary::New(isolate_, current_storage->length()));
10114 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
10115 for (uint32_t i = 0; i < current_length; i++) {
10116 HandleScope loop_scope(isolate_);
10117 Handle<Object> element(current_storage->get(i), isolate_);
10118 if (!element->IsTheHole()) {
10119 Handle<SeededNumberDictionary> new_storage =
10120 SeededNumberDictionary::AtNumberPut(slow_storage, i, element);
10121 if (!new_storage.is_identical_to(slow_storage)) {
10122 slow_storage = loop_scope.CloseAndEscape(new_storage);
10127 set_storage(*slow_storage);
10128 fast_elements_ = false;
10131 inline void clear_storage() {
10132 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
10135 inline void set_storage(FixedArray* storage) {
10136 storage_ = Handle<FixedArray>::cast(
10137 isolate_->global_handles()->Create(storage));
10141 Handle<FixedArray> storage_; // Always a global handle.
10142 // Index after last seen index. Always less than or equal to
10143 // JSObject::kMaxElementCount.
10144 uint32_t index_offset_;
10145 bool fast_elements_ : 1;
10146 bool exceeds_array_limit_ : 1;
10150 static uint32_t EstimateElementCount(Handle<JSArray> array) {
10151 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10152 int element_count = 0;
10153 switch (array->GetElementsKind()) {
10154 case FAST_SMI_ELEMENTS:
10155 case FAST_HOLEY_SMI_ELEMENTS:
10156 case FAST_ELEMENTS:
10157 case FAST_HOLEY_ELEMENTS: {
10158 // Fast elements can't have lengths that are not representable by
10159 // a 32-bit signed integer.
10160 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
10161 int fast_length = static_cast<int>(length);
10162 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
10163 for (int i = 0; i < fast_length; i++) {
10164 if (!elements->get(i)->IsTheHole()) element_count++;
10168 case FAST_DOUBLE_ELEMENTS:
10169 case FAST_HOLEY_DOUBLE_ELEMENTS: {
10170 // Fast elements can't have lengths that are not representable by
10171 // a 32-bit signed integer.
10172 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
10173 int fast_length = static_cast<int>(length);
10174 if (array->elements()->IsFixedArray()) {
10175 ASSERT(FixedArray::cast(array->elements())->length() == 0);
10178 Handle<FixedDoubleArray> elements(
10179 FixedDoubleArray::cast(array->elements()));
10180 for (int i = 0; i < fast_length; i++) {
10181 if (!elements->is_the_hole(i)) element_count++;
10185 case DICTIONARY_ELEMENTS: {
10186 Handle<SeededNumberDictionary> dictionary(
10187 SeededNumberDictionary::cast(array->elements()));
10188 int capacity = dictionary->Capacity();
10189 for (int i = 0; i < capacity; i++) {
10190 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
10191 if (dictionary->IsKey(*key)) {
10197 case SLOPPY_ARGUMENTS_ELEMENTS:
10198 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
10199 case EXTERNAL_##TYPE##_ELEMENTS: \
10200 case TYPE##_ELEMENTS: \
10202 TYPED_ARRAYS(TYPED_ARRAY_CASE)
10203 #undef TYPED_ARRAY_CASE
10204 // External arrays are always dense.
10207 // As an estimate, we assume that the prototype doesn't contain any
10208 // inherited elements.
10209 return element_count;
10214 template<class ExternalArrayClass, class ElementType>
10215 static void IterateExternalArrayElements(Isolate* isolate,
10216 Handle<JSObject> receiver,
10217 bool elements_are_ints,
10218 bool elements_are_guaranteed_smis,
10219 ArrayConcatVisitor* visitor) {
10220 Handle<ExternalArrayClass> array(
10221 ExternalArrayClass::cast(receiver->elements()));
10222 uint32_t len = static_cast<uint32_t>(array->length());
10224 ASSERT(visitor != NULL);
10225 if (elements_are_ints) {
10226 if (elements_are_guaranteed_smis) {
10227 for (uint32_t j = 0; j < len; j++) {
10228 HandleScope loop_scope(isolate);
10229 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10231 visitor->visit(j, e);
10234 for (uint32_t j = 0; j < len; j++) {
10235 HandleScope loop_scope(isolate);
10236 int64_t val = static_cast<int64_t>(array->get_scalar(j));
10237 if (Smi::IsValid(static_cast<intptr_t>(val))) {
10238 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
10239 visitor->visit(j, e);
10242 isolate->factory()->NewNumber(static_cast<ElementType>(val));
10243 visitor->visit(j, e);
10248 for (uint32_t j = 0; j < len; j++) {
10249 HandleScope loop_scope(isolate);
10250 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
10251 visitor->visit(j, e);
10257 static void IterateExternalFloat32x4ArrayElements(Isolate* isolate,
10258 Handle<JSObject> receiver,
10259 ArrayConcatVisitor* visitor) {
10260 Handle<ExternalFloat32x4Array> array(
10261 ExternalFloat32x4Array::cast(receiver->elements()));
10262 uint32_t len = static_cast<uint32_t>(array->length());
10264 ASSERT(visitor != NULL);
10265 for (uint32_t j = 0; j < len; j++) {
10266 HandleScope loop_scope(isolate);
10267 Handle<Object> e = isolate->factory()->NewFloat32x4(array->get_scalar(j));
10268 visitor->visit(j, e);
10273 static void IterateExternalFloat64x2ArrayElements(Isolate* isolate,
10274 Handle<JSObject> receiver,
10275 ArrayConcatVisitor* visitor) {
10276 Handle<ExternalFloat64x2Array> array(
10277 ExternalFloat64x2Array::cast(receiver->elements()));
10278 uint32_t len = static_cast<uint32_t>(array->length());
10280 ASSERT(visitor != NULL);
10281 for (uint32_t j = 0; j < len; j++) {
10282 HandleScope loop_scope(isolate);
10283 Handle<Object> e = isolate->factory()->NewFloat64x2(array->get_scalar(j));
10284 visitor->visit(j, e);
10289 static void IterateExternalInt32x4ArrayElements(Isolate* isolate,
10290 Handle<JSObject> receiver,
10291 ArrayConcatVisitor* visitor) {
10292 Handle<ExternalInt32x4Array> array(
10293 ExternalInt32x4Array::cast(receiver->elements()));
10294 uint32_t len = static_cast<uint32_t>(array->length());
10296 ASSERT(visitor != NULL);
10297 for (uint32_t j = 0; j < len; j++) {
10298 HandleScope loop_scope(isolate);
10299 Handle<Object> e = isolate->factory()->NewInt32x4(array->get_scalar(j));
10300 visitor->visit(j, e);
10305 // Used for sorting indices in a List<uint32_t>.
10306 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10309 return (a == b) ? 0 : (a < b) ? -1 : 1;
10313 static void CollectElementIndices(Handle<JSObject> object,
10315 List<uint32_t>* indices) {
10316 Isolate* isolate = object->GetIsolate();
10317 ElementsKind kind = object->GetElementsKind();
10319 case FAST_SMI_ELEMENTS:
10320 case FAST_ELEMENTS:
10321 case FAST_HOLEY_SMI_ELEMENTS:
10322 case FAST_HOLEY_ELEMENTS: {
10323 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10324 uint32_t length = static_cast<uint32_t>(elements->length());
10325 if (range < length) length = range;
10326 for (uint32_t i = 0; i < length; i++) {
10327 if (!elements->get(i)->IsTheHole()) {
10333 case FAST_HOLEY_DOUBLE_ELEMENTS:
10334 case FAST_DOUBLE_ELEMENTS: {
10335 // TODO(1810): Decide if it's worthwhile to implement this.
10339 case DICTIONARY_ELEMENTS: {
10340 Handle<SeededNumberDictionary> dict(
10341 SeededNumberDictionary::cast(object->elements()));
10342 uint32_t capacity = dict->Capacity();
10343 for (uint32_t j = 0; j < capacity; j++) {
10344 HandleScope loop_scope(isolate);
10345 Handle<Object> k(dict->KeyAt(j), isolate);
10346 if (dict->IsKey(*k)) {
10347 ASSERT(k->IsNumber());
10348 uint32_t index = static_cast<uint32_t>(k->Number());
10349 if (index < range) {
10350 indices->Add(index);
10357 int dense_elements_length;
10359 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
10360 case EXTERNAL_##TYPE##_ELEMENTS: { \
10361 dense_elements_length = \
10362 External##Type##Array::cast(object->elements())->length(); \
10366 TYPED_ARRAYS(TYPED_ARRAY_CASE)
10367 #undef TYPED_ARRAY_CASE
10371 dense_elements_length = 0;
10374 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10375 if (range <= length) {
10377 // We will add all indices, so we might as well clear it first
10378 // and avoid duplicates.
10381 for (uint32_t i = 0; i < length; i++) {
10384 if (length == range) return; // All indices accounted for already.
10389 Handle<Object> prototype(object->GetPrototype(), isolate);
10390 if (prototype->IsJSObject()) {
10391 // The prototype will usually have no inherited element indices,
10392 // but we have to check.
10393 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10399 * A helper function that visits elements of a JSArray in numerical
10402 * The visitor argument called for each existing element in the array
10403 * with the element index and the element's value.
10404 * Afterwards it increments the base-index of the visitor by the array
10406 * Returns false if any access threw an exception, otherwise true.
10408 static bool IterateElements(Isolate* isolate,
10409 Handle<JSArray> receiver,
10410 ArrayConcatVisitor* visitor) {
10411 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10412 switch (receiver->GetElementsKind()) {
10413 case FAST_SMI_ELEMENTS:
10414 case FAST_ELEMENTS:
10415 case FAST_HOLEY_SMI_ELEMENTS:
10416 case FAST_HOLEY_ELEMENTS: {
10417 // Run through the elements FixedArray and use HasElement and GetElement
10418 // to check the prototype for missing elements.
10419 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10420 int fast_length = static_cast<int>(length);
10421 ASSERT(fast_length <= elements->length());
10422 for (int j = 0; j < fast_length; j++) {
10423 HandleScope loop_scope(isolate);
10424 Handle<Object> element_value(elements->get(j), isolate);
10425 if (!element_value->IsTheHole()) {
10426 visitor->visit(j, element_value);
10427 } else if (JSReceiver::HasElement(receiver, j)) {
10428 // Call GetElement on receiver, not its prototype, or getters won't
10429 // have the correct receiver.
10430 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
10431 isolate, element_value,
10432 Object::GetElement(isolate, receiver, j),
10434 visitor->visit(j, element_value);
10439 case FAST_HOLEY_DOUBLE_ELEMENTS:
10440 case FAST_DOUBLE_ELEMENTS: {
10441 // Empty array is FixedArray but not FixedDoubleArray.
10442 if (length == 0) break;
10443 // Run through the elements FixedArray and use HasElement and GetElement
10444 // to check the prototype for missing elements.
10445 Handle<FixedDoubleArray> elements(
10446 FixedDoubleArray::cast(receiver->elements()));
10447 int fast_length = static_cast<int>(length);
10448 ASSERT(fast_length <= elements->length());
10449 for (int j = 0; j < fast_length; j++) {
10450 HandleScope loop_scope(isolate);
10451 if (!elements->is_the_hole(j)) {
10452 double double_value = elements->get_scalar(j);
10453 Handle<Object> element_value =
10454 isolate->factory()->NewNumber(double_value);
10455 visitor->visit(j, element_value);
10456 } else if (JSReceiver::HasElement(receiver, j)) {
10457 // Call GetElement on receiver, not its prototype, or getters won't
10458 // have the correct receiver.
10459 Handle<Object> element_value;
10460 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
10461 isolate, element_value,
10462 Object::GetElement(isolate, receiver, j),
10464 visitor->visit(j, element_value);
10469 case DICTIONARY_ELEMENTS: {
10470 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
10471 List<uint32_t> indices(dict->Capacity() / 2);
10472 // Collect all indices in the object and the prototypes less
10473 // than length. This might introduce duplicates in the indices list.
10474 CollectElementIndices(receiver, length, &indices);
10475 indices.Sort(&compareUInt32);
10477 int n = indices.length();
10479 HandleScope loop_scope(isolate);
10480 uint32_t index = indices[j];
10481 Handle<Object> element;
10482 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
10484 Object::GetElement(isolate, receiver, index),
10486 visitor->visit(index, element);
10487 // Skip to next different index (i.e., omit duplicates).
10490 } while (j < n && indices[j] == index);
10494 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
10495 Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast(
10496 receiver->elements()));
10497 for (uint32_t j = 0; j < length; j++) {
10498 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
10499 visitor->visit(j, e);
10503 case EXTERNAL_INT8_ELEMENTS: {
10504 IterateExternalArrayElements<ExternalInt8Array, int8_t>(
10505 isolate, receiver, true, true, visitor);
10508 case EXTERNAL_UINT8_ELEMENTS: {
10509 IterateExternalArrayElements<ExternalUint8Array, uint8_t>(
10510 isolate, receiver, true, true, visitor);
10513 case EXTERNAL_INT16_ELEMENTS: {
10514 IterateExternalArrayElements<ExternalInt16Array, int16_t>(
10515 isolate, receiver, true, true, visitor);
10518 case EXTERNAL_UINT16_ELEMENTS: {
10519 IterateExternalArrayElements<ExternalUint16Array, uint16_t>(
10520 isolate, receiver, true, true, visitor);
10523 case EXTERNAL_INT32_ELEMENTS: {
10524 IterateExternalArrayElements<ExternalInt32Array, int32_t>(
10525 isolate, receiver, true, false, visitor);
10528 case EXTERNAL_UINT32_ELEMENTS: {
10529 IterateExternalArrayElements<ExternalUint32Array, uint32_t>(
10530 isolate, receiver, true, false, visitor);
10533 case EXTERNAL_FLOAT32_ELEMENTS: {
10534 IterateExternalArrayElements<ExternalFloat32Array, float>(
10535 isolate, receiver, false, false, visitor);
10538 case EXTERNAL_FLOAT32x4_ELEMENTS: {
10539 IterateExternalFloat32x4ArrayElements(isolate, receiver, visitor);
10542 case EXTERNAL_FLOAT64x2_ELEMENTS: {
10543 IterateExternalFloat64x2ArrayElements(isolate, receiver, visitor);
10546 case EXTERNAL_INT32x4_ELEMENTS: {
10547 IterateExternalInt32x4ArrayElements(isolate, receiver, visitor);
10550 case EXTERNAL_FLOAT64_ELEMENTS: {
10551 IterateExternalArrayElements<ExternalFloat64Array, double>(
10552 isolate, receiver, false, false, visitor);
10559 visitor->increase_index_offset(length);
10565 * Array::concat implementation.
10566 * See ECMAScript 262, 15.4.4.4.
10567 * TODO(581): Fix non-compliance for very large concatenations and update to
10568 * following the ECMAScript 5 specification.
10570 RUNTIME_FUNCTION(Runtime_ArrayConcat) {
10571 HandleScope handle_scope(isolate);
10572 ASSERT(args.length() == 1);
10574 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
10575 int argument_count = static_cast<int>(arguments->length()->Number());
10576 RUNTIME_ASSERT(arguments->HasFastObjectElements());
10577 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
10579 // Pass 1: estimate the length and number of elements of the result.
10580 // The actual length can be larger if any of the arguments have getters
10581 // that mutate other arguments (but will otherwise be precise).
10582 // The number of elements is precise if there are no inherited elements.
10584 ElementsKind kind = FAST_SMI_ELEMENTS;
10586 uint32_t estimate_result_length = 0;
10587 uint32_t estimate_nof_elements = 0;
10588 for (int i = 0; i < argument_count; i++) {
10589 HandleScope loop_scope(isolate);
10590 Handle<Object> obj(elements->get(i), isolate);
10591 uint32_t length_estimate;
10592 uint32_t element_estimate;
10593 if (obj->IsJSArray()) {
10594 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10595 length_estimate = static_cast<uint32_t>(array->length()->Number());
10596 if (length_estimate != 0) {
10597 ElementsKind array_kind =
10598 GetPackedElementsKind(array->map()->elements_kind());
10599 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10603 element_estimate = EstimateElementCount(array);
10605 if (obj->IsHeapObject()) {
10606 if (obj->IsNumber()) {
10607 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10608 kind = FAST_DOUBLE_ELEMENTS;
10610 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10611 kind = FAST_ELEMENTS;
10614 length_estimate = 1;
10615 element_estimate = 1;
10617 // Avoid overflows by capping at kMaxElementCount.
10618 if (JSObject::kMaxElementCount - estimate_result_length <
10620 estimate_result_length = JSObject::kMaxElementCount;
10622 estimate_result_length += length_estimate;
10624 if (JSObject::kMaxElementCount - estimate_nof_elements <
10625 element_estimate) {
10626 estimate_nof_elements = JSObject::kMaxElementCount;
10628 estimate_nof_elements += element_estimate;
10632 // If estimated number of elements is more than half of length, a
10633 // fixed array (fast case) is more time and space-efficient than a
10635 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
10637 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
10638 Handle<FixedArrayBase> storage =
10639 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10641 if (estimate_result_length > 0) {
10642 Handle<FixedDoubleArray> double_storage =
10643 Handle<FixedDoubleArray>::cast(storage);
10644 bool failure = false;
10645 for (int i = 0; i < argument_count; i++) {
10646 Handle<Object> obj(elements->get(i), isolate);
10647 if (obj->IsSmi()) {
10648 double_storage->set(j, Smi::cast(*obj)->value());
10650 } else if (obj->IsNumber()) {
10651 double_storage->set(j, obj->Number());
10654 JSArray* array = JSArray::cast(*obj);
10655 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10656 switch (array->map()->elements_kind()) {
10657 case FAST_HOLEY_DOUBLE_ELEMENTS:
10658 case FAST_DOUBLE_ELEMENTS: {
10659 // Empty array is FixedArray but not FixedDoubleArray.
10660 if (length == 0) break;
10661 FixedDoubleArray* elements =
10662 FixedDoubleArray::cast(array->elements());
10663 for (uint32_t i = 0; i < length; i++) {
10664 if (elements->is_the_hole(i)) {
10668 double double_value = elements->get_scalar(i);
10669 double_storage->set(j, double_value);
10674 case FAST_HOLEY_SMI_ELEMENTS:
10675 case FAST_SMI_ELEMENTS: {
10676 FixedArray* elements(
10677 FixedArray::cast(array->elements()));
10678 for (uint32_t i = 0; i < length; i++) {
10679 Object* element = elements->get(i);
10680 if (element->IsTheHole()) {
10684 int32_t int_value = Smi::cast(element)->value();
10685 double_storage->set(j, int_value);
10690 case FAST_HOLEY_ELEMENTS:
10691 ASSERT_EQ(0, length);
10697 if (failure) break;
10700 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10701 Smi* length = Smi::FromInt(j);
10703 map = JSObject::GetElementsTransitionMap(array, kind);
10704 array->set_map(*map);
10705 array->set_length(length);
10706 array->set_elements(*storage);
10710 Handle<FixedArray> storage;
10712 // The backing storage array must have non-existing elements to preserve
10713 // holes across concat operations.
10714 storage = isolate->factory()->NewFixedArrayWithHoles(
10715 estimate_result_length);
10717 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10718 uint32_t at_least_space_for = estimate_nof_elements +
10719 (estimate_nof_elements >> 2);
10720 storage = Handle<FixedArray>::cast(
10721 SeededNumberDictionary::New(isolate, at_least_space_for));
10724 ArrayConcatVisitor visitor(isolate, storage, fast_case);
10726 for (int i = 0; i < argument_count; i++) {
10727 Handle<Object> obj(elements->get(i), isolate);
10728 if (obj->IsJSArray()) {
10729 Handle<JSArray> array = Handle<JSArray>::cast(obj);
10730 if (!IterateElements(isolate, array, &visitor)) {
10731 return isolate->heap()->exception();
10734 visitor.visit(0, obj);
10735 visitor.increase_index_offset(1);
10739 if (visitor.exceeds_array_limit()) {
10740 return isolate->Throw(
10741 *isolate->factory()->NewRangeError("invalid_array_length",
10742 HandleVector<Object>(NULL, 0)));
10744 return *visitor.ToArray();
10748 // This will not allocate (flatten the string), but it may run
10749 // very slowly for very deeply nested ConsStrings. For debugging use only.
10750 RUNTIME_FUNCTION(Runtime_GlobalPrint) {
10751 SealHandleScope shs(isolate);
10752 ASSERT(args.length() == 1);
10754 CONVERT_ARG_CHECKED(String, string, 0);
10755 ConsStringIteratorOp op;
10756 StringCharacterStream stream(string, &op);
10757 while (stream.HasMore()) {
10758 uint16_t character = stream.GetNext();
10759 PrintF("%c", character);
10765 // Moves all own elements of an object, that are below a limit, to positions
10766 // starting at zero. All undefined values are placed after non-undefined values,
10767 // and are followed by non-existing element. Does not change the length
10769 // Returns the number of non-undefined elements collected.
10770 // Returns -1 if hole removal is not supported by this method.
10771 RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
10772 HandleScope scope(isolate);
10773 ASSERT(args.length() == 2);
10774 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
10775 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10776 return *JSObject::PrepareElementsForSort(object, limit);
10780 // Move contents of argument 0 (an array) to argument 1 (an array)
10781 RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
10782 HandleScope scope(isolate);
10783 ASSERT(args.length() == 2);
10784 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
10785 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
10786 JSObject::ValidateElements(from);
10787 JSObject::ValidateElements(to);
10789 Handle<FixedArrayBase> new_elements(from->elements());
10790 ElementsKind from_kind = from->GetElementsKind();
10791 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
10792 JSObject::SetMapAndElements(to, new_map, new_elements);
10793 to->set_length(from->length());
10795 JSObject::ResetElements(from);
10796 from->set_length(Smi::FromInt(0));
10798 JSObject::ValidateElements(to);
10803 // How many elements does this object/array have?
10804 RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
10805 SealHandleScope shs(isolate);
10806 ASSERT(args.length() == 1);
10807 CONVERT_ARG_CHECKED(JSObject, object, 0);
10808 HeapObject* elements = object->elements();
10809 if (elements->IsDictionary()) {
10810 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10811 return Smi::FromInt(result);
10812 } else if (object->IsJSArray()) {
10813 return JSArray::cast(object)->length();
10815 return Smi::FromInt(FixedArray::cast(elements)->length());
10820 // Returns an array that tells you where in the [0, length) interval an array
10821 // might have elements. Can either return an array of keys (positive integers
10822 // or undefined) or a number representing the positive length of an interval
10823 // starting at index 0.
10824 // Intervals can span over some keys that are not in the object.
10825 RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
10826 HandleScope scope(isolate);
10827 ASSERT(args.length() == 2);
10828 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
10829 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
10830 if (array->elements()->IsDictionary()) {
10831 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10832 for (Handle<Object> p = array;
10834 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10835 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10836 // Bail out if we find a proxy or interceptor, likely not worth
10837 // collecting keys in that case.
10838 return *isolate->factory()->NewNumberFromUint(length);
10840 Handle<JSObject> current = Handle<JSObject>::cast(p);
10841 Handle<FixedArray> current_keys =
10842 isolate->factory()->NewFixedArray(
10843 current->NumberOfLocalElements(NONE));
10844 current->GetLocalElementKeys(*current_keys, NONE);
10845 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
10846 isolate, keys, FixedArray::UnionOfKeys(keys, current_keys));
10848 // Erase any keys >= length.
10849 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10850 // is changed to let this happen on the JS side.
10851 for (int i = 0; i < keys->length(); i++) {
10852 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
10854 return *isolate->factory()->NewJSArrayWithElements(keys);
10856 ASSERT(array->HasFastSmiOrObjectElements() ||
10857 array->HasFastDoubleElements());
10858 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10859 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
10864 RUNTIME_FUNCTION(Runtime_LookupAccessor) {
10865 HandleScope scope(isolate);
10866 ASSERT(args.length() == 3);
10867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10868 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10869 CONVERT_SMI_ARG_CHECKED(flag, 2);
10870 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10871 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
10872 Handle<Object> result;
10873 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
10875 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component));
10880 RUNTIME_FUNCTION(Runtime_DebugBreak) {
10881 SealHandleScope shs(isolate);
10882 ASSERT(args.length() == 0);
10883 return Execution::DebugBreakHelper(isolate);
10887 // Helper functions for wrapping and unwrapping stack frame ids.
10888 static Smi* WrapFrameId(StackFrame::Id id) {
10889 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
10890 return Smi::FromInt(id >> 2);
10894 static StackFrame::Id UnwrapFrameId(int wrapped) {
10895 return static_cast<StackFrame::Id>(wrapped << 2);
10899 // Adds a JavaScript function as a debug event listener.
10900 // args[0]: debug event listener function to set or null or undefined for
10901 // clearing the event listener function
10902 // args[1]: object supplied during callback
10903 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
10904 SealHandleScope shs(isolate);
10905 ASSERT(args.length() == 2);
10906 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10907 args[0]->IsUndefined() ||
10908 args[0]->IsNull());
10909 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
10910 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
10911 isolate->debugger()->SetEventListener(callback, data);
10913 return isolate->heap()->undefined_value();
10917 RUNTIME_FUNCTION(Runtime_Break) {
10918 SealHandleScope shs(isolate);
10919 ASSERT(args.length() == 0);
10920 isolate->stack_guard()->DebugBreak();
10921 return isolate->heap()->undefined_value();
10925 static Handle<Object> DebugLookupResultValue(Isolate* isolate,
10926 Handle<Object> receiver,
10928 LookupResult* result,
10929 bool* has_caught = NULL) {
10930 Handle<Object> value = isolate->factory()->undefined_value();
10931 if (!result->IsFound()) return value;
10932 switch (result->type()) {
10934 value = JSObject::GetNormalizedProperty(
10935 handle(result->holder(), isolate), result);
10938 value = JSObject::FastPropertyAt(handle(result->holder(), isolate),
10939 result->representation(),
10940 result->GetFieldIndex().field_index());
10943 return handle(result->GetConstant(), isolate);
10945 Handle<Object> structure(result->GetCallbackObject(), isolate);
10946 ASSERT(!structure->IsForeign());
10947 if (structure->IsAccessorInfo()) {
10948 MaybeHandle<Object> obj = JSObject::GetPropertyWithCallback(
10949 handle(result->holder(), isolate), receiver, structure, name);
10950 if (!obj.ToHandle(&value)) {
10951 value = handle(isolate->pending_exception(), isolate);
10952 isolate->clear_pending_exception();
10953 if (has_caught != NULL) *has_caught = true;
10966 ASSERT(!value->IsTheHole() || result->IsReadOnly());
10967 return value->IsTheHole()
10968 ? Handle<Object>::cast(isolate->factory()->undefined_value()) : value;
10972 // Get debugger related details for an object property.
10973 // args[0]: object holding property
10974 // args[1]: name of the property
10976 // The array returned contains the following information:
10977 // 0: Property value
10978 // 1: Property details
10979 // 2: Property value is exception
10980 // 3: Getter function if defined
10981 // 4: Setter function if defined
10982 // Items 2-4 are only filled if the property has either a getter or a setter
10983 // defined through __defineGetter__ and/or __defineSetter__.
10984 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
10985 HandleScope scope(isolate);
10987 ASSERT(args.length() == 2);
10989 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10990 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10992 // Make sure to set the current context to the context before the debugger was
10993 // entered (if the debugger is entered). The reason for switching context here
10994 // is that for some property lookups (accessors and interceptors) callbacks
10995 // into the embedding application can occour, and the embedding application
10996 // could have the assumption that its own native context is the current
10997 // context and not some internal debugger context.
10998 SaveContext save(isolate);
10999 if (isolate->debug()->InDebugger()) {
11000 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
11003 // Skip the global proxy as it has no properties and always delegates to the
11004 // real global object.
11005 if (obj->IsJSGlobalProxy()) {
11006 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
11010 // Check if the name is trivially convertible to an index and get the element
11013 if (name->AsArrayIndex(&index)) {
11014 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
11015 Handle<Object> element_or_char;
11016 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
11017 isolate, element_or_char,
11018 Runtime::GetElementOrCharAt(isolate, obj, index));
11019 details->set(0, *element_or_char);
11021 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
11022 return *isolate->factory()->NewJSArrayWithElements(details);
11025 // Find the number of objects making up this.
11026 int length = LocalPrototypeChainLength(*obj);
11028 // Try local lookup on each of the objects.
11029 Handle<JSObject> jsproto = obj;
11030 for (int i = 0; i < length; i++) {
11031 LookupResult result(isolate);
11032 jsproto->LocalLookup(name, &result);
11033 if (result.IsFound()) {
11034 // LookupResult is not GC safe as it holds raw object pointers.
11035 // GC can happen later in this code so put the required fields into
11036 // local variables using handles when required for later use.
11037 Handle<Object> result_callback_obj;
11038 if (result.IsPropertyCallbacks()) {
11039 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
11044 bool has_caught = false;
11045 Handle<Object> value = DebugLookupResultValue(
11046 isolate, obj, name, &result, &has_caught);
11048 // If the callback object is a fixed array then it contains JavaScript
11049 // getter and/or setter.
11050 bool has_js_accessors = result.IsPropertyCallbacks() &&
11051 result_callback_obj->IsAccessorPair();
11052 Handle<FixedArray> details =
11053 isolate->factory()->NewFixedArray(has_js_accessors ? 5 : 2);
11054 details->set(0, *value);
11055 details->set(1, result.GetPropertyDetails().AsSmi());
11056 if (has_js_accessors) {
11057 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
11058 details->set(2, isolate->heap()->ToBoolean(has_caught));
11059 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
11060 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
11063 return *isolate->factory()->NewJSArrayWithElements(details);
11065 if (i < length - 1) {
11066 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
11070 return isolate->heap()->undefined_value();
11074 RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
11075 HandleScope scope(isolate);
11077 ASSERT(args.length() == 2);
11079 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11080 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
11082 LookupResult result(isolate);
11083 obj->Lookup(name, &result);
11084 return *DebugLookupResultValue(isolate, obj, name, &result);
11088 // Return the property type calculated from the property details.
11089 // args[0]: smi with property details.
11090 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
11091 SealHandleScope shs(isolate);
11092 ASSERT(args.length() == 1);
11093 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11094 return Smi::FromInt(static_cast<int>(details.type()));
11098 // Return the property attribute calculated from the property details.
11099 // args[0]: smi with property details.
11100 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
11101 SealHandleScope shs(isolate);
11102 ASSERT(args.length() == 1);
11103 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11104 return Smi::FromInt(static_cast<int>(details.attributes()));
11108 // Return the property insertion index calculated from the property details.
11109 // args[0]: smi with property details.
11110 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
11111 SealHandleScope shs(isolate);
11112 ASSERT(args.length() == 1);
11113 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11114 // TODO(verwaest): Depends on the type of details.
11115 return Smi::FromInt(details.dictionary_index());
11119 // Return property value from named interceptor.
11121 // args[1]: property name
11122 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
11123 HandleScope scope(isolate);
11124 ASSERT(args.length() == 2);
11125 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11126 RUNTIME_ASSERT(obj->HasNamedInterceptor());
11127 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
11129 PropertyAttributes attributes;
11130 Handle<Object> result;
11131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
11133 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes));
11138 // Return element value from indexed interceptor.
11141 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
11142 HandleScope scope(isolate);
11143 ASSERT(args.length() == 2);
11144 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11145 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
11146 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
11147 Handle<Object> result;
11148 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
11149 isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index));
11154 static bool CheckExecutionState(Isolate* isolate, int break_id) {
11155 return (isolate->debug()->break_id() != 0 &&
11156 break_id == isolate->debug()->break_id());
11160 RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
11161 SealHandleScope shs(isolate);
11162 ASSERT(args.length() == 1);
11163 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
11164 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
11165 return isolate->heap()->true_value();
11169 RUNTIME_FUNCTION(Runtime_GetFrameCount) {
11170 HandleScope scope(isolate);
11171 ASSERT(args.length() == 1);
11172 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
11173 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
11175 // Count all frames which are relevant to debugging stack trace.
11177 StackFrame::Id id = isolate->debug()->break_frame_id();
11178 if (id == StackFrame::NO_ID) {
11179 // If there is no JavaScript stack frame count is 0.
11180 return Smi::FromInt(0);
11183 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
11184 n += it.frame()->GetInlineCount();
11186 return Smi::FromInt(n);
11190 class FrameInspector {
11192 FrameInspector(JavaScriptFrame* frame,
11193 int inlined_jsframe_index,
11195 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
11196 // Calculate the deoptimized frame.
11197 if (frame->is_optimized()) {
11198 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
11199 frame, inlined_jsframe_index, isolate);
11201 has_adapted_arguments_ = frame_->has_adapted_arguments();
11202 is_bottommost_ = inlined_jsframe_index == 0;
11203 is_optimized_ = frame_->is_optimized();
11206 ~FrameInspector() {
11207 // Get rid of the calculated deoptimized frame if any.
11208 if (deoptimized_frame_ != NULL) {
11209 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
11214 int GetParametersCount() {
11215 return is_optimized_
11216 ? deoptimized_frame_->parameters_count()
11217 : frame_->ComputeParametersCount();
11219 int expression_count() { return deoptimized_frame_->expression_count(); }
11220 Object* GetFunction() {
11221 return is_optimized_
11222 ? deoptimized_frame_->GetFunction()
11223 : frame_->function();
11225 Object* GetParameter(int index) {
11226 return is_optimized_
11227 ? deoptimized_frame_->GetParameter(index)
11228 : frame_->GetParameter(index);
11230 Object* GetExpression(int index) {
11231 return is_optimized_
11232 ? deoptimized_frame_->GetExpression(index)
11233 : frame_->GetExpression(index);
11235 int GetSourcePosition() {
11236 return is_optimized_
11237 ? deoptimized_frame_->GetSourcePosition()
11238 : frame_->LookupCode()->SourcePosition(frame_->pc());
11240 bool IsConstructor() {
11241 return is_optimized_ && !is_bottommost_
11242 ? deoptimized_frame_->HasConstructStub()
11243 : frame_->IsConstructor();
11246 // To inspect all the provided arguments the frame might need to be
11247 // replaced with the arguments frame.
11248 void SetArgumentsFrame(JavaScriptFrame* frame) {
11249 ASSERT(has_adapted_arguments_);
11251 is_optimized_ = frame_->is_optimized();
11252 ASSERT(!is_optimized_);
11256 JavaScriptFrame* frame_;
11257 DeoptimizedFrameInfo* deoptimized_frame_;
11259 bool is_optimized_;
11260 bool is_bottommost_;
11261 bool has_adapted_arguments_;
11263 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11267 static const int kFrameDetailsFrameIdIndex = 0;
11268 static const int kFrameDetailsReceiverIndex = 1;
11269 static const int kFrameDetailsFunctionIndex = 2;
11270 static const int kFrameDetailsArgumentCountIndex = 3;
11271 static const int kFrameDetailsLocalCountIndex = 4;
11272 static const int kFrameDetailsSourcePositionIndex = 5;
11273 static const int kFrameDetailsConstructCallIndex = 6;
11274 static const int kFrameDetailsAtReturnIndex = 7;
11275 static const int kFrameDetailsFlagsIndex = 8;
11276 static const int kFrameDetailsFirstDynamicIndex = 9;
11279 static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11280 JavaScriptFrame* frame) {
11281 SaveContext* save = isolate->save_context();
11282 while (save != NULL && !save->IsBelowFrame(frame)) {
11283 save = save->prev();
11285 ASSERT(save != NULL);
11290 // Return an array with frame details
11291 // args[0]: number: break id
11292 // args[1]: number: frame index
11294 // The array returned contains the following information:
11298 // 3: Argument count
11300 // 5: Source position
11301 // 6: Constructor call
11304 // Arguments name, value
11305 // Locals name, value
11306 // Return value if any
11307 RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
11308 HandleScope scope(isolate);
11309 ASSERT(args.length() == 2);
11310 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
11311 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
11313 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11314 Heap* heap = isolate->heap();
11316 // Find the relevant frame with the requested index.
11317 StackFrame::Id id = isolate->debug()->break_frame_id();
11318 if (id == StackFrame::NO_ID) {
11319 // If there are no JavaScript stack frames return undefined.
11320 return heap->undefined_value();
11324 JavaScriptFrameIterator it(isolate, id);
11325 for (; !it.done(); it.Advance()) {
11326 if (index < count + it.frame()->GetInlineCount()) break;
11327 count += it.frame()->GetInlineCount();
11329 if (it.done()) return heap->undefined_value();
11331 bool is_optimized = it.frame()->is_optimized();
11333 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11334 if (is_optimized) {
11335 inlined_jsframe_index =
11336 it.frame()->GetInlineCount() - (index - count) - 1;
11338 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
11340 // Traverse the saved contexts chain to find the active context for the
11342 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
11344 // Get the frame id.
11345 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
11347 // Find source position in unoptimized code.
11348 int position = frame_inspector.GetSourcePosition();
11350 // Check for constructor frame.
11351 bool constructor = frame_inspector.IsConstructor();
11353 // Get scope info and read from it for local variable information.
11354 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11355 Handle<SharedFunctionInfo> shared(function->shared());
11356 Handle<ScopeInfo> scope_info(shared->scope_info());
11357 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
11359 // Get the locals names and values into a temporary array.
11360 int local_count = scope_info->LocalCount();
11361 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
11362 // Hide compiler-introduced temporary variables, whether on the stack or on
11364 if (scope_info->LocalIsSynthetic(slot))
11368 Handle<FixedArray> locals =
11369 isolate->factory()->NewFixedArray(local_count * 2);
11371 // Fill in the values of the locals.
11374 for (; i < scope_info->StackLocalCount(); ++i) {
11375 // Use the value from the stack.
11376 if (scope_info->LocalIsSynthetic(i))
11378 locals->set(local * 2, scope_info->LocalName(i));
11379 locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
11382 if (local < local_count) {
11383 // Get the context containing declarations.
11384 Handle<Context> context(
11385 Context::cast(it.frame()->context())->declaration_context());
11386 for (; i < scope_info->LocalCount(); ++i) {
11387 if (scope_info->LocalIsSynthetic(i))
11389 Handle<String> name(scope_info->LocalName(i));
11391 InitializationFlag init_flag;
11392 locals->set(local * 2, *name);
11393 int context_slot_index =
11394 ScopeInfo::ContextSlotIndex(scope_info, name, &mode, &init_flag);
11395 Object* value = context->get(context_slot_index);
11396 locals->set(local * 2 + 1, value);
11401 // Check whether this frame is positioned at return. If not top
11402 // frame or if the frame is optimized it cannot be at a return.
11403 bool at_return = false;
11404 if (!is_optimized && index == 0) {
11405 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
11408 // If positioned just before return find the value to be returned and add it
11409 // to the frame information.
11410 Handle<Object> return_value = isolate->factory()->undefined_value();
11412 StackFrameIterator it2(isolate);
11413 Address internal_frame_sp = NULL;
11414 while (!it2.done()) {
11415 if (it2.frame()->is_internal()) {
11416 internal_frame_sp = it2.frame()->sp();
11418 if (it2.frame()->is_java_script()) {
11419 if (it2.frame()->id() == it.frame()->id()) {
11420 // The internal frame just before the JavaScript frame contains the
11421 // value to return on top. A debug break at return will create an
11422 // internal frame to store the return value (eax/rax/r0) before
11423 // entering the debug break exit frame.
11424 if (internal_frame_sp != NULL) {
11426 Handle<Object>(Memory::Object_at(internal_frame_sp),
11433 // Indicate that the previous frame was not an internal frame.
11434 internal_frame_sp = NULL;
11440 // Now advance to the arguments adapter frame (if any). It contains all
11441 // the provided parameters whereas the function frame always have the number
11442 // of arguments matching the functions parameters. The rest of the
11443 // information (except for what is collected above) is the same.
11444 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
11445 it.AdvanceToArgumentsFrame();
11446 frame_inspector.SetArgumentsFrame(it.frame());
11449 // Find the number of arguments to fill. At least fill the number of
11450 // parameters for the function and fill more if more parameters are provided.
11451 int argument_count = scope_info->ParameterCount();
11452 if (argument_count < frame_inspector.GetParametersCount()) {
11453 argument_count = frame_inspector.GetParametersCount();
11456 // Calculate the size of the result.
11457 int details_size = kFrameDetailsFirstDynamicIndex +
11458 2 * (argument_count + local_count) +
11459 (at_return ? 1 : 0);
11460 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
11462 // Add the frame id.
11463 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11465 // Add the function (same as in function frame).
11466 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
11468 // Add the arguments count.
11469 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11471 // Add the locals count
11472 details->set(kFrameDetailsLocalCountIndex,
11473 Smi::FromInt(local_count));
11475 // Add the source position.
11476 if (position != RelocInfo::kNoPosition) {
11477 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11479 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
11482 // Add the constructor information.
11483 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
11485 // Add the at return information.
11486 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
11488 // Add flags to indicate information on whether this frame is
11489 // bit 0: invoked in the debugger context.
11490 // bit 1: optimized frame.
11491 // bit 2: inlined in optimized frame
11493 if (*save->context() == *isolate->debug()->debug_context()) {
11496 if (is_optimized) {
11498 flags |= inlined_jsframe_index << 2;
11500 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
11502 // Fill the dynamic part.
11503 int details_index = kFrameDetailsFirstDynamicIndex;
11505 // Add arguments name and value.
11506 for (int i = 0; i < argument_count; i++) {
11507 // Name of the argument.
11508 if (i < scope_info->ParameterCount()) {
11509 details->set(details_index++, scope_info->ParameterName(i));
11511 details->set(details_index++, heap->undefined_value());
11514 // Parameter value.
11515 if (i < frame_inspector.GetParametersCount()) {
11516 // Get the value from the stack.
11517 details->set(details_index++, frame_inspector.GetParameter(i));
11519 details->set(details_index++, heap->undefined_value());
11523 // Add locals name and value from the temporary copy from the function frame.
11524 for (int i = 0; i < local_count * 2; i++) {
11525 details->set(details_index++, locals->get(i));
11528 // Add the value being returned.
11530 details->set(details_index++, *return_value);
11533 // Add the receiver (same as in function frame).
11534 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11535 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
11536 Handle<Object> receiver(it.frame()->receiver(), isolate);
11537 if (!receiver->IsJSObject() &&
11538 shared->strict_mode() == SLOPPY &&
11539 !function->IsBuiltin()) {
11540 // If the receiver is not a JSObject and the function is not a
11541 // builtin or strict-mode we have hit an optimization where a
11542 // value object is not converted into a wrapped JS objects. To
11543 // hide this optimization from the debugger, we wrap the receiver
11544 // by creating correct wrapper object based on the calling frame's
11547 if (receiver->IsUndefined()) {
11548 Context* context = function->context();
11549 receiver = handle(context->global_object()->global_receiver());
11551 ASSERT(!receiver->IsNull());
11552 Context* context = Context::cast(it.frame()->context());
11553 Handle<Context> native_context(Context::cast(context->native_context()));
11554 receiver = Object::ToObject(
11555 isolate, receiver, native_context).ToHandleChecked();
11558 details->set(kFrameDetailsReceiverIndex, *receiver);
11560 ASSERT_EQ(details_size, details_index);
11561 return *isolate->factory()->NewJSArrayWithElements(details);
11565 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
11566 Handle<String> parameter_name) {
11568 InitializationFlag flag;
11569 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &flag) != -1;
11573 // Create a plain JSObject which materializes the local scope for the specified
11576 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
11578 Handle<JSObject> target,
11579 Handle<JSFunction> function,
11580 FrameInspector* frame_inspector) {
11581 Handle<SharedFunctionInfo> shared(function->shared());
11582 Handle<ScopeInfo> scope_info(shared->scope_info());
11584 // First fill all parameters.
11585 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11586 // Do not materialize the parameter if it is shadowed by a context local.
11587 Handle<String> name(scope_info->ParameterName(i));
11588 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
11590 HandleScope scope(isolate);
11591 Handle<Object> value(i < frame_inspector->GetParametersCount()
11592 ? frame_inspector->GetParameter(i)
11593 : isolate->heap()->undefined_value(),
11595 ASSERT(!value->IsTheHole());
11597 RETURN_ON_EXCEPTION(
11599 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY),
11603 // Second fill all stack locals.
11604 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11605 if (scope_info->LocalIsSynthetic(i)) continue;
11606 Handle<String> name(scope_info->StackLocalName(i));
11607 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11608 if (value->IsTheHole()) continue;
11610 RETURN_ON_EXCEPTION(
11612 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY),
11620 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11621 Handle<JSObject> target,
11622 Handle<JSFunction> function,
11623 JavaScriptFrame* frame,
11624 int inlined_jsframe_index) {
11625 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11626 // Optimized frames are not supported.
11627 // TODO(yangguo): make sure all code deoptimized when debugger is active
11628 // and assert that this cannot happen.
11632 Handle<SharedFunctionInfo> shared(function->shared());
11633 Handle<ScopeInfo> scope_info(shared->scope_info());
11636 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11637 // Shadowed parameters were not materialized.
11638 Handle<String> name(scope_info->ParameterName(i));
11639 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
11641 ASSERT(!frame->GetParameter(i)->IsTheHole());
11642 HandleScope scope(isolate);
11643 Handle<Object> value =
11644 Object::GetPropertyOrElement(target, name).ToHandleChecked();
11645 frame->SetParameterValue(i, *value);
11649 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11650 if (scope_info->LocalIsSynthetic(i)) continue;
11651 if (frame->GetExpression(i)->IsTheHole()) continue;
11652 HandleScope scope(isolate);
11653 Handle<Object> value = Object::GetPropertyOrElement(
11655 handle(scope_info->StackLocalName(i), isolate)).ToHandleChecked();
11656 frame->SetExpression(i, *value);
11661 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
11663 Handle<JSObject> target,
11664 Handle<JSFunction> function,
11665 JavaScriptFrame* frame) {
11666 HandleScope scope(isolate);
11667 Handle<SharedFunctionInfo> shared(function->shared());
11668 Handle<ScopeInfo> scope_info(shared->scope_info());
11670 if (!scope_info->HasContext()) return target;
11672 // Third fill all context locals.
11673 Handle<Context> frame_context(Context::cast(frame->context()));
11674 Handle<Context> function_context(frame_context->declaration_context());
11675 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11676 scope_info, function_context, target)) {
11677 return MaybeHandle<JSObject>();
11680 // Finally copy any properties from the function context extension.
11681 // These will be variables introduced by eval.
11682 if (function_context->closure() == *function) {
11683 if (function_context->has_extension() &&
11684 !function_context->IsNativeContext()) {
11685 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11686 Handle<FixedArray> keys;
11687 ASSIGN_RETURN_ON_EXCEPTION(
11689 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
11692 for (int i = 0; i < keys->length(); i++) {
11693 // Names of variables introduced by eval are strings.
11694 ASSERT(keys->get(i)->IsString());
11695 Handle<String> key(String::cast(keys->get(i)));
11696 Handle<Object> value;
11697 ASSIGN_RETURN_ON_EXCEPTION(
11698 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
11699 RETURN_ON_EXCEPTION(
11701 Runtime::SetObjectProperty(
11702 isolate, target, key, value, NONE, SLOPPY),
11712 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
11714 JavaScriptFrame* frame,
11715 int inlined_jsframe_index) {
11716 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11717 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11719 Handle<JSObject> local_scope =
11720 isolate->factory()->NewJSObject(isolate->object_function());
11721 ASSIGN_RETURN_ON_EXCEPTION(
11722 isolate, local_scope,
11723 MaterializeStackLocalsWithFrameInspector(
11724 isolate, local_scope, function, &frame_inspector),
11727 return MaterializeLocalContext(isolate, local_scope, function, frame);
11731 // Set the context local variable value.
11732 static bool SetContextLocalValue(Isolate* isolate,
11733 Handle<ScopeInfo> scope_info,
11734 Handle<Context> context,
11735 Handle<String> variable_name,
11736 Handle<Object> new_value) {
11737 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11738 Handle<String> next_name(scope_info->ContextLocalName(i));
11739 if (String::Equals(variable_name, next_name)) {
11741 InitializationFlag init_flag;
11742 int context_index =
11743 ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &init_flag);
11744 context->set(context_index, *new_value);
11753 static bool SetLocalVariableValue(Isolate* isolate,
11754 JavaScriptFrame* frame,
11755 int inlined_jsframe_index,
11756 Handle<String> variable_name,
11757 Handle<Object> new_value) {
11758 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11759 // Optimized frames are not supported.
11763 Handle<JSFunction> function(frame->function());
11764 Handle<SharedFunctionInfo> shared(function->shared());
11765 Handle<ScopeInfo> scope_info(shared->scope_info());
11767 bool default_result = false;
11770 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11771 HandleScope scope(isolate);
11772 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
11773 frame->SetParameterValue(i, *new_value);
11774 // Argument might be shadowed in heap context, don't stop here.
11775 default_result = true;
11780 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11781 HandleScope scope(isolate);
11782 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
11783 frame->SetExpression(i, *new_value);
11788 if (scope_info->HasContext()) {
11790 Handle<Context> frame_context(Context::cast(frame->context()));
11791 Handle<Context> function_context(frame_context->declaration_context());
11792 if (SetContextLocalValue(
11793 isolate, scope_info, function_context, variable_name, new_value)) {
11797 // Function context extension. These are variables introduced by eval.
11798 if (function_context->closure() == *function) {
11799 if (function_context->has_extension() &&
11800 !function_context->IsNativeContext()) {
11801 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11803 if (JSReceiver::HasProperty(ext, variable_name)) {
11804 // We don't expect this to do anything except replacing
11806 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11807 NONE, SLOPPY).Assert();
11814 return default_result;
11818 // Create a plain JSObject which materializes the closure content for the
11820 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
11822 Handle<Context> context) {
11823 ASSERT(context->IsFunctionContext());
11825 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11826 Handle<ScopeInfo> scope_info(shared->scope_info());
11828 // Allocate and initialize a JSObject with all the content of this function
11830 Handle<JSObject> closure_scope =
11831 isolate->factory()->NewJSObject(isolate->object_function());
11833 // Fill all context locals to the context extension.
11834 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11835 scope_info, context, closure_scope)) {
11836 return MaybeHandle<JSObject>();
11839 // Finally copy any properties from the function context extension. This will
11840 // be variables introduced by eval.
11841 if (context->has_extension()) {
11842 Handle<JSObject> ext(JSObject::cast(context->extension()));
11843 Handle<FixedArray> keys;
11844 ASSIGN_RETURN_ON_EXCEPTION(
11846 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), JSObject);
11848 for (int i = 0; i < keys->length(); i++) {
11849 HandleScope scope(isolate);
11850 // Names of variables introduced by eval are strings.
11851 ASSERT(keys->get(i)->IsString());
11852 Handle<String> key(String::cast(keys->get(i)));
11853 Handle<Object> value;
11854 ASSIGN_RETURN_ON_EXCEPTION(
11855 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
11856 RETURN_ON_EXCEPTION(
11858 Runtime::SetObjectProperty(
11859 isolate, closure_scope, key, value, NONE, SLOPPY),
11864 return closure_scope;
11868 // This method copies structure of MaterializeClosure method above.
11869 static bool SetClosureVariableValue(Isolate* isolate,
11870 Handle<Context> context,
11871 Handle<String> variable_name,
11872 Handle<Object> new_value) {
11873 ASSERT(context->IsFunctionContext());
11875 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11876 Handle<ScopeInfo> scope_info(shared->scope_info());
11878 // Context locals to the context extension.
11879 if (SetContextLocalValue(
11880 isolate, scope_info, context, variable_name, new_value)) {
11884 // Properties from the function context extension. This will
11885 // be variables introduced by eval.
11886 if (context->has_extension()) {
11887 Handle<JSObject> ext(JSObject::cast(context->extension()));
11888 if (JSReceiver::HasProperty(ext, variable_name)) {
11889 // We don't expect this to do anything except replacing property value.
11890 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11891 NONE, SLOPPY).Assert();
11900 // Create a plain JSObject which materializes the scope for the specified
11902 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
11904 Handle<Context> context) {
11905 ASSERT(context->IsCatchContext());
11906 Handle<String> name(String::cast(context->extension()));
11907 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11909 Handle<JSObject> catch_scope =
11910 isolate->factory()->NewJSObject(isolate->object_function());
11911 RETURN_ON_EXCEPTION(
11913 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
11916 return catch_scope;
11920 static bool SetCatchVariableValue(Isolate* isolate,
11921 Handle<Context> context,
11922 Handle<String> variable_name,
11923 Handle<Object> new_value) {
11924 ASSERT(context->IsCatchContext());
11925 Handle<String> name(String::cast(context->extension()));
11926 if (!String::Equals(name, variable_name)) {
11929 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11934 // Create a plain JSObject which materializes the block scope for the specified
11936 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
11938 Handle<Context> context) {
11939 ASSERT(context->IsBlockContext());
11940 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11942 // Allocate and initialize a JSObject with all the arguments, stack locals
11943 // heap locals and extension properties of the debugged function.
11944 Handle<JSObject> block_scope =
11945 isolate->factory()->NewJSObject(isolate->object_function());
11947 // Fill all context locals.
11948 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11949 scope_info, context, block_scope)) {
11950 return MaybeHandle<JSObject>();
11953 return block_scope;
11957 // Create a plain JSObject which materializes the module scope for the specified
11959 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
11961 Handle<Context> context) {
11962 ASSERT(context->IsModuleContext());
11963 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11965 // Allocate and initialize a JSObject with all the members of the debugged
11967 Handle<JSObject> module_scope =
11968 isolate->factory()->NewJSObject(isolate->object_function());
11970 // Fill all context locals.
11971 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11972 scope_info, context, module_scope)) {
11973 return MaybeHandle<JSObject>();
11976 return module_scope;
11980 // Iterate over the actual scopes visible from a stack frame or from a closure.
11981 // The iteration proceeds from the innermost visible nested scope outwards.
11982 // All scopes are backed by an actual context except the local scope,
11983 // which is inserted "artificially" in the context chain.
11984 class ScopeIterator {
11987 ScopeTypeGlobal = 0,
11996 ScopeIterator(Isolate* isolate,
11997 JavaScriptFrame* frame,
11998 int inlined_jsframe_index,
11999 bool ignore_nested_scopes = false)
12000 : isolate_(isolate),
12002 inlined_jsframe_index_(inlined_jsframe_index),
12003 function_(frame->function()),
12004 context_(Context::cast(frame->context())),
12005 nested_scope_chain_(4),
12008 // Catch the case when the debugger stops in an internal function.
12009 Handle<SharedFunctionInfo> shared_info(function_->shared());
12010 Handle<ScopeInfo> scope_info(shared_info->scope_info());
12011 if (shared_info->script() == isolate->heap()->undefined_value()) {
12012 while (context_->closure() == *function_) {
12013 context_ = Handle<Context>(context_->previous(), isolate_);
12018 // Get the debug info (create it if it does not exist).
12019 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
12020 // Return if ensuring debug info failed.
12024 // Currently it takes too much time to find nested scopes due to script
12025 // parsing. Sometimes we want to run the ScopeIterator as fast as possible
12026 // (for example, while collecting async call stacks on every
12027 // addEventListener call), even if we drop some nested scopes.
12028 // Later we may optimize getting the nested scopes (cache the result?)
12029 // and include nested scopes into the "fast" iteration case as well.
12030 if (!ignore_nested_scopes) {
12031 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
12033 // Find the break point where execution has stopped.
12034 BreakLocationIterator break_location_iterator(debug_info,
12035 ALL_BREAK_LOCATIONS);
12036 // pc points to the instruction after the current one, possibly a break
12037 // location as well. So the "- 1" to exclude it from the search.
12038 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
12040 // Within the return sequence at the moment it is not possible to
12041 // get a source position which is consistent with the current scope chain.
12042 // Thus all nested with, catch and block contexts are skipped and we only
12043 // provide the function scope.
12044 ignore_nested_scopes = break_location_iterator.IsExit();
12047 if (ignore_nested_scopes) {
12048 if (scope_info->HasContext()) {
12049 context_ = Handle<Context>(context_->declaration_context(), isolate_);
12051 while (context_->closure() == *function_) {
12052 context_ = Handle<Context>(context_->previous(), isolate_);
12055 if (scope_info->scope_type() == FUNCTION_SCOPE) {
12056 nested_scope_chain_.Add(scope_info);
12059 // Reparse the code and analyze the scopes.
12060 Handle<Script> script(Script::cast(shared_info->script()));
12061 Scope* scope = NULL;
12063 // Check whether we are in global, eval or function code.
12064 Handle<ScopeInfo> scope_info(shared_info->scope_info());
12065 if (scope_info->scope_type() != FUNCTION_SCOPE) {
12066 // Global or eval code.
12067 CompilationInfoWithZone info(script);
12068 if (scope_info->scope_type() == GLOBAL_SCOPE) {
12069 info.MarkAsGlobal();
12071 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
12073 info.SetContext(Handle<Context>(function_->context()));
12075 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
12076 scope = info.function()->scope();
12078 RetrieveScopeChain(scope, shared_info);
12081 CompilationInfoWithZone info(shared_info);
12082 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
12083 scope = info.function()->scope();
12085 RetrieveScopeChain(scope, shared_info);
12090 ScopeIterator(Isolate* isolate,
12091 Handle<JSFunction> function)
12092 : isolate_(isolate),
12094 inlined_jsframe_index_(0),
12095 function_(function),
12096 context_(function->context()),
12098 if (function->IsBuiltin()) {
12099 context_ = Handle<Context>();
12106 return context_.is_null();
12109 bool Failed() { return failed_; }
12111 // Move to the next scope.
12114 ScopeType scope_type = Type();
12115 if (scope_type == ScopeTypeGlobal) {
12116 // The global scope is always the last in the chain.
12117 ASSERT(context_->IsNativeContext());
12118 context_ = Handle<Context>();
12121 if (nested_scope_chain_.is_empty()) {
12122 context_ = Handle<Context>(context_->previous(), isolate_);
12124 if (nested_scope_chain_.last()->HasContext()) {
12125 ASSERT(context_->previous() != NULL);
12126 context_ = Handle<Context>(context_->previous(), isolate_);
12128 nested_scope_chain_.RemoveLast();
12132 // Return the type of the current scope.
12135 if (!nested_scope_chain_.is_empty()) {
12136 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
12137 switch (scope_info->scope_type()) {
12138 case FUNCTION_SCOPE:
12139 ASSERT(context_->IsFunctionContext() ||
12140 !scope_info->HasContext());
12141 return ScopeTypeLocal;
12143 ASSERT(context_->IsModuleContext());
12144 return ScopeTypeModule;
12146 ASSERT(context_->IsNativeContext());
12147 return ScopeTypeGlobal;
12149 ASSERT(context_->IsWithContext());
12150 return ScopeTypeWith;
12152 ASSERT(context_->IsCatchContext());
12153 return ScopeTypeCatch;
12155 ASSERT(!scope_info->HasContext() ||
12156 context_->IsBlockContext());
12157 return ScopeTypeBlock;
12162 if (context_->IsNativeContext()) {
12163 ASSERT(context_->global_object()->IsGlobalObject());
12164 return ScopeTypeGlobal;
12166 if (context_->IsFunctionContext()) {
12167 return ScopeTypeClosure;
12169 if (context_->IsCatchContext()) {
12170 return ScopeTypeCatch;
12172 if (context_->IsBlockContext()) {
12173 return ScopeTypeBlock;
12175 if (context_->IsModuleContext()) {
12176 return ScopeTypeModule;
12178 ASSERT(context_->IsWithContext());
12179 return ScopeTypeWith;
12182 // Return the JavaScript object with the content of the current scope.
12183 MaybeHandle<JSObject> ScopeObject() {
12186 case ScopeIterator::ScopeTypeGlobal:
12187 return Handle<JSObject>(CurrentContext()->global_object());
12188 case ScopeIterator::ScopeTypeLocal:
12189 // Materialize the content of the local scope into a JSObject.
12190 ASSERT(nested_scope_chain_.length() == 1);
12191 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
12192 case ScopeIterator::ScopeTypeWith:
12193 // Return the with object.
12194 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
12195 case ScopeIterator::ScopeTypeCatch:
12196 return MaterializeCatchScope(isolate_, CurrentContext());
12197 case ScopeIterator::ScopeTypeClosure:
12198 // Materialize the content of the closure scope into a JSObject.
12199 return MaterializeClosure(isolate_, CurrentContext());
12200 case ScopeIterator::ScopeTypeBlock:
12201 return MaterializeBlockScope(isolate_, CurrentContext());
12202 case ScopeIterator::ScopeTypeModule:
12203 return MaterializeModuleScope(isolate_, CurrentContext());
12206 return Handle<JSObject>();
12209 bool SetVariableValue(Handle<String> variable_name,
12210 Handle<Object> new_value) {
12213 case ScopeIterator::ScopeTypeGlobal:
12215 case ScopeIterator::ScopeTypeLocal:
12216 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
12217 variable_name, new_value);
12218 case ScopeIterator::ScopeTypeWith:
12220 case ScopeIterator::ScopeTypeCatch:
12221 return SetCatchVariableValue(isolate_, CurrentContext(),
12222 variable_name, new_value);
12223 case ScopeIterator::ScopeTypeClosure:
12224 return SetClosureVariableValue(isolate_, CurrentContext(),
12225 variable_name, new_value);
12226 case ScopeIterator::ScopeTypeBlock:
12227 // TODO(2399): should we implement it?
12229 case ScopeIterator::ScopeTypeModule:
12230 // TODO(2399): should we implement it?
12236 Handle<ScopeInfo> CurrentScopeInfo() {
12238 if (!nested_scope_chain_.is_empty()) {
12239 return nested_scope_chain_.last();
12240 } else if (context_->IsBlockContext()) {
12241 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
12242 } else if (context_->IsFunctionContext()) {
12243 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
12245 return Handle<ScopeInfo>::null();
12248 // Return the context for this scope. For the local context there might not
12249 // be an actual context.
12250 Handle<Context> CurrentContext() {
12252 if (Type() == ScopeTypeGlobal ||
12253 nested_scope_chain_.is_empty()) {
12255 } else if (nested_scope_chain_.last()->HasContext()) {
12258 return Handle<Context>();
12263 // Debug print of the content of the current scope.
12264 void DebugPrint() {
12267 case ScopeIterator::ScopeTypeGlobal:
12268 PrintF("Global:\n");
12269 CurrentContext()->Print();
12272 case ScopeIterator::ScopeTypeLocal: {
12273 PrintF("Local:\n");
12274 function_->shared()->scope_info()->Print();
12275 if (!CurrentContext().is_null()) {
12276 CurrentContext()->Print();
12277 if (CurrentContext()->has_extension()) {
12278 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12279 if (extension->IsJSContextExtensionObject()) {
12280 extension->Print();
12287 case ScopeIterator::ScopeTypeWith:
12289 CurrentContext()->extension()->Print();
12292 case ScopeIterator::ScopeTypeCatch:
12293 PrintF("Catch:\n");
12294 CurrentContext()->extension()->Print();
12295 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
12298 case ScopeIterator::ScopeTypeClosure:
12299 PrintF("Closure:\n");
12300 CurrentContext()->Print();
12301 if (CurrentContext()->has_extension()) {
12302 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12303 if (extension->IsJSContextExtensionObject()) {
12304 extension->Print();
12318 JavaScriptFrame* frame_;
12319 int inlined_jsframe_index_;
12320 Handle<JSFunction> function_;
12321 Handle<Context> context_;
12322 List<Handle<ScopeInfo> > nested_scope_chain_;
12325 void RetrieveScopeChain(Scope* scope,
12326 Handle<SharedFunctionInfo> shared_info) {
12327 if (scope != NULL) {
12328 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12329 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12331 // A failed reparse indicates that the preparser has diverged from the
12332 // parser or that the preparse data given to the initial parse has been
12333 // faulty. We fail in debug mode but in release mode we only provide the
12334 // information we get from the context chain but nothing about
12335 // completely stack allocated scopes or stack allocated locals.
12336 // Or it could be due to stack overflow.
12337 ASSERT(isolate_->has_pending_exception());
12342 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12346 RUNTIME_FUNCTION(Runtime_GetScopeCount) {
12347 HandleScope scope(isolate);
12348 ASSERT(args.length() == 2);
12349 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12350 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12352 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12354 // Get the frame where the debugging is performed.
12355 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12356 JavaScriptFrameIterator it(isolate, id);
12357 JavaScriptFrame* frame = it.frame();
12359 // Count the visible scopes.
12361 for (ScopeIterator it(isolate, frame, 0);
12367 return Smi::FromInt(n);
12371 // Returns the list of step-in positions (text offset) in a function of the
12372 // stack frame in a range from the current debug break position to the end
12373 // of the corresponding statement.
12374 RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
12375 HandleScope scope(isolate);
12376 ASSERT(args.length() == 2);
12377 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12378 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12380 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12382 // Get the frame where the debugging is performed.
12383 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12384 JavaScriptFrameIterator frame_it(isolate, id);
12385 RUNTIME_ASSERT(!frame_it.done());
12387 JavaScriptFrame* frame = frame_it.frame();
12389 Handle<JSFunction> fun =
12390 Handle<JSFunction>(frame->function());
12391 Handle<SharedFunctionInfo> shared =
12392 Handle<SharedFunctionInfo>(fun->shared());
12394 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12395 return isolate->heap()->undefined_value();
12398 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12401 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12402 // Find the break point where execution has stopped.
12403 BreakLocationIterator break_location_iterator(debug_info,
12404 ALL_BREAK_LOCATIONS);
12406 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
12407 int current_statement_pos = break_location_iterator.statement_position();
12409 while (!break_location_iterator.Done()) {
12411 if (break_location_iterator.pc() > frame->pc()) {
12414 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12415 // The break point is near our pc. Could be a step-in possibility,
12416 // that is currently taken by active debugger call.
12417 if (break_frame_id == StackFrame::NO_ID) {
12418 // We are not stepping.
12421 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12422 // If our frame is a top frame and we are stepping, we can do step-in
12424 accept = additional_frame_it.frame()->id() == id;
12428 if (break_location_iterator.IsStepInLocation(isolate)) {
12429 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12430 RETURN_FAILURE_ON_EXCEPTION(
12432 JSObject::SetElement(array, len,
12433 Handle<Object>(position_value, isolate),
12438 // Advance iterator.
12439 break_location_iterator.Next();
12440 if (current_statement_pos !=
12441 break_location_iterator.statement_position()) {
12449 static const int kScopeDetailsTypeIndex = 0;
12450 static const int kScopeDetailsObjectIndex = 1;
12451 static const int kScopeDetailsSize = 2;
12454 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
12456 ScopeIterator* it) {
12457 // Calculate the size of the result.
12458 int details_size = kScopeDetailsSize;
12459 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12461 // Fill in scope details.
12462 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12463 Handle<JSObject> scope_object;
12464 ASSIGN_RETURN_ON_EXCEPTION(
12465 isolate, scope_object, it->ScopeObject(), JSObject);
12466 details->set(kScopeDetailsObjectIndex, *scope_object);
12468 return isolate->factory()->NewJSArrayWithElements(details);
12472 // Return an array with scope details
12473 // args[0]: number: break id
12474 // args[1]: number: frame index
12475 // args[2]: number: inlined frame index
12476 // args[3]: number: scope index
12478 // The array returned contains the following information:
12481 RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
12482 HandleScope scope(isolate);
12483 ASSERT(args.length() == 4);
12484 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12485 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12487 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12488 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12489 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12491 // Get the frame where the debugging is performed.
12492 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12493 JavaScriptFrameIterator frame_it(isolate, id);
12494 JavaScriptFrame* frame = frame_it.frame();
12496 // Find the requested scope.
12498 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12499 for (; !it.Done() && n < index; it.Next()) {
12503 return isolate->heap()->undefined_value();
12505 Handle<JSObject> details;
12506 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
12507 isolate, details, MaterializeScopeDetails(isolate, &it));
12512 // Return an array of scope details
12513 // args[0]: number: break id
12514 // args[1]: number: frame index
12515 // args[2]: number: inlined frame index
12516 // args[3]: boolean: ignore nested scopes
12518 // The array returned contains arrays with the following information:
12521 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
12522 HandleScope scope(isolate);
12523 ASSERT(args.length() == 3 || args.length() == 4);
12524 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12525 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12527 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12528 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12530 bool ignore_nested_scopes = false;
12531 if (args.length() == 4) {
12532 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
12533 ignore_nested_scopes = flag;
12536 // Get the frame where the debugging is performed.
12537 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12538 JavaScriptFrameIterator frame_it(isolate, id);
12539 JavaScriptFrame* frame = frame_it.frame();
12541 List<Handle<JSObject> > result(4);
12542 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
12543 for (; !it.Done(); it.Next()) {
12544 Handle<JSObject> details;
12545 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
12546 isolate, details, MaterializeScopeDetails(isolate, &it));
12547 result.Add(details);
12550 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
12551 for (int i = 0; i < result.length(); ++i) {
12552 array->set(i, *result[i]);
12554 return *isolate->factory()->NewJSArrayWithElements(array);
12558 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
12559 HandleScope scope(isolate);
12560 ASSERT(args.length() == 1);
12562 // Check arguments.
12563 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12565 // Count the visible scopes.
12567 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12571 return Smi::FromInt(n);
12575 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
12576 HandleScope scope(isolate);
12577 ASSERT(args.length() == 2);
12579 // Check arguments.
12580 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12581 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12583 // Find the requested scope.
12585 ScopeIterator it(isolate, fun);
12586 for (; !it.Done() && n < index; it.Next()) {
12590 return isolate->heap()->undefined_value();
12593 Handle<JSObject> details;
12594 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
12595 isolate, details, MaterializeScopeDetails(isolate, &it));
12600 static bool SetScopeVariableValue(ScopeIterator* it, int index,
12601 Handle<String> variable_name,
12602 Handle<Object> new_value) {
12603 for (int n = 0; !it->Done() && n < index; it->Next()) {
12609 return it->SetVariableValue(variable_name, new_value);
12613 // Change variable value in closure or local scope
12614 // args[0]: number or JsFunction: break id or function
12615 // args[1]: number: frame index (when arg[0] is break id)
12616 // args[2]: number: inlined frame index (when arg[0] is break id)
12617 // args[3]: number: scope index
12618 // args[4]: string: variable name
12619 // args[5]: object: new value
12621 // Return true if success and false otherwise
12622 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
12623 HandleScope scope(isolate);
12624 ASSERT(args.length() == 6);
12626 // Check arguments.
12627 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12628 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12629 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
12632 if (args[0]->IsNumber()) {
12633 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12634 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12636 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12637 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12639 // Get the frame where the debugging is performed.
12640 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12641 JavaScriptFrameIterator frame_it(isolate, id);
12642 JavaScriptFrame* frame = frame_it.frame();
12644 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12645 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12647 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12648 ScopeIterator it(isolate, fun);
12649 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12652 return isolate->heap()->ToBoolean(res);
12656 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
12657 HandleScope scope(isolate);
12658 ASSERT(args.length() == 0);
12661 // Print the scopes for the top frame.
12662 StackFrameLocator locator(isolate);
12663 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
12664 for (ScopeIterator it(isolate, frame, 0);
12670 return isolate->heap()->undefined_value();
12674 RUNTIME_FUNCTION(Runtime_GetThreadCount) {
12675 HandleScope scope(isolate);
12676 ASSERT(args.length() == 1);
12677 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12678 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12680 // Count all archived V8 threads.
12682 for (ThreadState* thread =
12683 isolate->thread_manager()->FirstThreadStateInUse();
12685 thread = thread->Next()) {
12689 // Total number of threads is current thread and archived threads.
12690 return Smi::FromInt(n + 1);
12694 static const int kThreadDetailsCurrentThreadIndex = 0;
12695 static const int kThreadDetailsThreadIdIndex = 1;
12696 static const int kThreadDetailsSize = 2;
12698 // Return an array with thread details
12699 // args[0]: number: break id
12700 // args[1]: number: thread index
12702 // The array returned contains the following information:
12703 // 0: Is current thread?
12705 RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
12706 HandleScope scope(isolate);
12707 ASSERT(args.length() == 2);
12708 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12709 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12711 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12713 // Allocate array for result.
12714 Handle<FixedArray> details =
12715 isolate->factory()->NewFixedArray(kThreadDetailsSize);
12717 // Thread index 0 is current thread.
12719 // Fill the details.
12720 details->set(kThreadDetailsCurrentThreadIndex,
12721 isolate->heap()->true_value());
12722 details->set(kThreadDetailsThreadIdIndex,
12723 Smi::FromInt(ThreadId::Current().ToInteger()));
12725 // Find the thread with the requested index.
12727 ThreadState* thread =
12728 isolate->thread_manager()->FirstThreadStateInUse();
12729 while (index != n && thread != NULL) {
12730 thread = thread->Next();
12733 if (thread == NULL) {
12734 return isolate->heap()->undefined_value();
12737 // Fill the details.
12738 details->set(kThreadDetailsCurrentThreadIndex,
12739 isolate->heap()->false_value());
12740 details->set(kThreadDetailsThreadIdIndex,
12741 Smi::FromInt(thread->id().ToInteger()));
12744 // Convert to JS array and return.
12745 return *isolate->factory()->NewJSArrayWithElements(details);
12749 // Sets the disable break state
12750 // args[0]: disable break state
12751 RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
12752 HandleScope scope(isolate);
12753 ASSERT(args.length() == 1);
12754 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
12755 isolate->debug()->set_disable_break(disable_break);
12756 return isolate->heap()->undefined_value();
12760 static bool IsPositionAlignmentCodeCorrect(int alignment) {
12761 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12765 RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
12766 HandleScope scope(isolate);
12767 ASSERT(args.length() == 2);
12769 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12770 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12772 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12773 return isolate->ThrowIllegalOperation();
12775 BreakPositionAlignment alignment =
12776 static_cast<BreakPositionAlignment>(statement_aligned_code);
12778 Handle<SharedFunctionInfo> shared(fun->shared());
12779 // Find the number of break points
12780 Handle<Object> break_locations =
12781 Debug::GetSourceBreakLocations(shared, alignment);
12782 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
12783 // Return array as JS array
12784 return *isolate->factory()->NewJSArrayWithElements(
12785 Handle<FixedArray>::cast(break_locations));
12789 // Set a break point in a function.
12790 // args[0]: function
12791 // args[1]: number: break source position (within the function source)
12792 // args[2]: number: break point object
12793 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
12794 HandleScope scope(isolate);
12795 ASSERT(args.length() == 3);
12796 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12797 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12798 RUNTIME_ASSERT(source_position >= 0);
12799 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
12801 // Set break point.
12802 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12805 return Smi::FromInt(source_position);
12809 // Changes the state of a break point in a script and returns source position
12810 // where break point was set. NOTE: Regarding performance see the NOTE for
12811 // GetScriptFromScriptData.
12812 // args[0]: script to set break point in
12813 // args[1]: number: break source position (within the script source)
12814 // args[2]: number, breakpoint position alignment
12815 // args[3]: number: break point object
12816 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
12817 HandleScope scope(isolate);
12818 ASSERT(args.length() == 4);
12819 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
12820 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12821 RUNTIME_ASSERT(source_position >= 0);
12822 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12823 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
12825 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12826 return isolate->ThrowIllegalOperation();
12828 BreakPositionAlignment alignment =
12829 static_cast<BreakPositionAlignment>(statement_aligned_code);
12831 // Get the script from the script wrapper.
12832 RUNTIME_ASSERT(wrapper->value()->IsScript());
12833 Handle<Script> script(Script::cast(wrapper->value()));
12835 // Set break point.
12836 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
12839 return isolate->heap()->undefined_value();
12842 return Smi::FromInt(source_position);
12846 // Clear a break point
12847 // args[0]: number: break point object
12848 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
12849 HandleScope scope(isolate);
12850 ASSERT(args.length() == 1);
12851 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
12853 // Clear break point.
12854 isolate->debug()->ClearBreakPoint(break_point_object_arg);
12856 return isolate->heap()->undefined_value();
12860 // Change the state of break on exceptions.
12861 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12862 // args[1]: Boolean indicating on/off.
12863 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
12864 HandleScope scope(isolate);
12865 ASSERT(args.length() == 2);
12866 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
12867 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
12869 // If the number doesn't match an enum value, the ChangeBreakOnException
12870 // function will default to affecting caught exceptions.
12871 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
12872 // Update break point state.
12873 isolate->debug()->ChangeBreakOnException(type, enable);
12874 return isolate->heap()->undefined_value();
12878 // Returns the state of break on exceptions
12879 // args[0]: boolean indicating uncaught exceptions
12880 RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
12881 HandleScope scope(isolate);
12882 ASSERT(args.length() == 1);
12883 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
12885 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
12886 bool result = isolate->debug()->IsBreakOnException(type);
12887 return Smi::FromInt(result);
12891 // Prepare for stepping
12892 // args[0]: break id for checking execution state
12893 // args[1]: step action from the enumeration StepAction
12894 // args[2]: number of times to perform the step, for step out it is the number
12895 // of frames to step down.
12896 RUNTIME_FUNCTION(Runtime_PrepareStep) {
12897 HandleScope scope(isolate);
12898 ASSERT(args.length() == 4);
12899 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
12900 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
12902 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
12903 return isolate->Throw(isolate->heap()->illegal_argument_string());
12906 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12908 StackFrame::Id frame_id;
12909 if (wrapped_frame_id == 0) {
12910 frame_id = StackFrame::NO_ID;
12912 frame_id = UnwrapFrameId(wrapped_frame_id);
12915 // Get the step action and check validity.
12916 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12917 if (step_action != StepIn &&
12918 step_action != StepNext &&
12919 step_action != StepOut &&
12920 step_action != StepInMin &&
12921 step_action != StepMin) {
12922 return isolate->Throw(isolate->heap()->illegal_argument_string());
12925 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12926 step_action != StepMin && step_action != StepOut) {
12927 return isolate->ThrowIllegalOperation();
12930 // Get the number of steps.
12931 int step_count = NumberToInt32(args[2]);
12932 if (step_count < 1) {
12933 return isolate->Throw(isolate->heap()->illegal_argument_string());
12936 // Clear all current stepping setup.
12937 isolate->debug()->ClearStepping();
12940 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
12943 return isolate->heap()->undefined_value();
12947 // Clear all stepping set by PrepareStep.
12948 RUNTIME_FUNCTION(Runtime_ClearStepping) {
12949 HandleScope scope(isolate);
12950 ASSERT(args.length() == 0);
12951 isolate->debug()->ClearStepping();
12952 return isolate->heap()->undefined_value();
12956 // Helper function to find or create the arguments object for
12957 // Runtime_DebugEvaluate.
12958 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
12960 Handle<JSObject> target,
12961 Handle<JSFunction> function) {
12962 // Do not materialize the arguments object for eval or top-level code.
12963 // Skip if "arguments" is already taken.
12964 if (!function->shared()->is_function() ||
12965 JSReceiver::HasLocalProperty(target,
12966 isolate->factory()->arguments_string())) {
12970 // FunctionGetArguments can't throw an exception.
12971 Handle<JSObject> arguments = Handle<JSObject>::cast(
12972 Accessors::FunctionGetArguments(function));
12973 Handle<String> arguments_str = isolate->factory()->arguments_string();
12974 RETURN_ON_EXCEPTION(
12976 Runtime::SetObjectProperty(
12977 isolate, target, arguments_str, arguments, ::NONE, SLOPPY),
12983 // Compile and evaluate source for the given context.
12984 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
12985 Handle<Context> context,
12986 Handle<Object> context_extension,
12987 Handle<Object> receiver,
12988 Handle<String> source) {
12989 if (context_extension->IsJSObject()) {
12990 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
12991 Handle<JSFunction> closure(context->closure(), isolate);
12992 context = isolate->factory()->NewWithContext(closure, context, extension);
12995 Handle<JSFunction> eval_fun;
12996 ASSIGN_RETURN_ON_EXCEPTION(
12998 Compiler::GetFunctionFromEval(source,
13001 NO_PARSE_RESTRICTION,
13002 RelocInfo::kNoPosition),
13005 Handle<Object> result;
13006 ASSIGN_RETURN_ON_EXCEPTION(
13008 Execution::Call(isolate, eval_fun, receiver, 0, NULL),
13011 // Skip the global proxy as it has no properties and always delegates to the
13012 // real global object.
13013 if (result->IsJSGlobalProxy()) {
13014 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
13017 // Clear the oneshot breakpoints so that the debugger does not step further.
13018 isolate->debug()->ClearStepping();
13023 // Evaluate a piece of JavaScript in the context of a stack frame for
13024 // debugging. Things that need special attention are:
13025 // - Parameters and stack-allocated locals need to be materialized. Altered
13026 // values need to be written back to the stack afterwards.
13027 // - The arguments object needs to materialized.
13028 RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
13029 HandleScope scope(isolate);
13031 // Check the execution state and decode arguments frame and source to be
13033 ASSERT(args.length() == 6);
13034 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
13035 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
13037 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
13038 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
13039 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
13040 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
13041 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
13043 // Handle the processing of break.
13044 DisableBreak disable_break_save(isolate, disable_break);
13046 // Get the frame where the debugging is performed.
13047 StackFrame::Id id = UnwrapFrameId(wrapped_id);
13048 JavaScriptFrameIterator it(isolate, id);
13049 JavaScriptFrame* frame = it.frame();
13050 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
13051 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
13053 // Traverse the saved contexts chain to find the active context for the
13055 SaveContext* save = FindSavedContextForFrame(isolate, frame);
13057 SaveContext savex(isolate);
13058 isolate->set_context(*(save->context()));
13060 // Evaluate on the context of the frame.
13061 Handle<Context> context(Context::cast(frame->context()));
13062 ASSERT(!context.is_null());
13064 // Materialize stack locals and the arguments object.
13065 Handle<JSObject> materialized =
13066 isolate->factory()->NewJSObject(isolate->object_function());
13068 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13069 isolate, materialized,
13070 MaterializeStackLocalsWithFrameInspector(
13071 isolate, materialized, function, &frame_inspector));
13073 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13074 isolate, materialized,
13075 MaterializeArgumentsObject(isolate, materialized, function));
13077 // Add the materialized object in a with-scope to shadow the stack locals.
13078 context = isolate->factory()->NewWithContext(function, context, materialized);
13080 Handle<Object> receiver(frame->receiver(), isolate);
13081 Handle<Object> result;
13082 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13084 DebugEvaluate(isolate, context, context_extension, receiver, source));
13086 // Write back potential changes to materialized stack locals to the stack.
13087 UpdateStackLocalsFromMaterializedObject(
13088 isolate, materialized, function, frame, inlined_jsframe_index);
13094 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
13095 HandleScope scope(isolate);
13097 // Check the execution state and decode arguments frame and source to be
13099 ASSERT(args.length() == 4);
13100 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
13101 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
13103 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13104 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
13105 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
13107 // Handle the processing of break.
13108 DisableBreak disable_break_save(isolate, disable_break);
13110 // Enter the top context from before the debugger was invoked.
13111 SaveContext save(isolate);
13112 SaveContext* top = &save;
13113 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
13117 isolate->set_context(*top->context());
13120 // Get the native context now set to the top context from before the
13121 // debugger was invoked.
13122 Handle<Context> context = isolate->native_context();
13123 Handle<Object> receiver = isolate->global_object();
13124 Handle<Object> result;
13125 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13127 DebugEvaluate(isolate, context, context_extension, receiver, source));
13132 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
13133 HandleScope scope(isolate);
13134 ASSERT(args.length() == 0);
13136 // Fill the script objects.
13137 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
13139 // Convert the script objects to proper JS objects.
13140 for (int i = 0; i < instances->length(); i++) {
13141 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
13142 // Get the script wrapper in a local handle before calling GetScriptWrapper,
13144 // instances->set(i, *GetScriptWrapper(script))
13145 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
13146 // already have dereferenced the instances handle.
13147 Handle<JSObject> wrapper = Script::GetWrapper(script);
13148 instances->set(i, *wrapper);
13151 // Return result as a JS array.
13152 Handle<JSObject> result =
13153 isolate->factory()->NewJSObject(isolate->array_function());
13154 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13159 // Helper function used by Runtime_DebugReferencedBy below.
13160 static int DebugReferencedBy(HeapIterator* iterator,
13162 Object* instance_filter, int max_references,
13163 FixedArray* instances, int instances_size,
13164 JSFunction* arguments_function) {
13165 Isolate* isolate = target->GetIsolate();
13166 SealHandleScope shs(isolate);
13167 DisallowHeapAllocation no_allocation;
13169 // Iterate the heap.
13171 JSObject* last = NULL;
13172 HeapObject* heap_obj = NULL;
13173 while (((heap_obj = iterator->next()) != NULL) &&
13174 (max_references == 0 || count < max_references)) {
13175 // Only look at all JSObjects.
13176 if (heap_obj->IsJSObject()) {
13177 // Skip context extension objects and argument arrays as these are
13178 // checked in the context of functions using them.
13179 JSObject* obj = JSObject::cast(heap_obj);
13180 if (obj->IsJSContextExtensionObject() ||
13181 obj->map()->constructor() == arguments_function) {
13185 // Check if the JS object has a reference to the object looked for.
13186 if (obj->ReferencesObject(target)) {
13187 // Check instance filter if supplied. This is normally used to avoid
13188 // references from mirror objects (see Runtime_IsInPrototypeChain).
13189 if (!instance_filter->IsUndefined()) {
13192 Object* prototype = V->GetPrototype(isolate);
13193 if (prototype->IsNull()) {
13196 if (instance_filter == prototype) {
13197 obj = NULL; // Don't add this object.
13205 // Valid reference found add to instance array if supplied an update
13207 if (instances != NULL && count < instances_size) {
13208 instances->set(count, obj);
13217 // Check for circular reference only. This can happen when the object is only
13218 // referenced from mirrors and has a circular reference in which case the
13219 // object is not really alive and would have been garbage collected if not
13220 // referenced from the mirror.
13221 if (count == 1 && last == target) {
13225 // Return the number of referencing objects found.
13230 // Scan the heap for objects with direct references to an object
13231 // args[0]: the object to find references to
13232 // args[1]: constructor function for instances to exclude (Mirror)
13233 // args[2]: the the maximum number of objects to return
13234 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
13235 HandleScope scope(isolate);
13236 ASSERT(args.length() == 3);
13238 // First perform a full GC in order to avoid references from dead objects.
13239 Heap* heap = isolate->heap();
13240 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugReferencedBy");
13241 // The heap iterator reserves the right to do a GC to make the heap iterable.
13242 // Due to the GC above we know it won't need to do that, but it seems cleaner
13243 // to get the heap iterator constructed before we start having unprotected
13244 // Object* locals that are not protected by handles.
13246 // Check parameters.
13247 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
13248 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
13249 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
13250 instance_filter->IsJSObject());
13251 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
13252 RUNTIME_ASSERT(max_references >= 0);
13255 // Get the constructor function for context extension and arguments array.
13256 Handle<JSObject> arguments_boilerplate(
13257 isolate->context()->native_context()->sloppy_arguments_boilerplate());
13258 Handle<JSFunction> arguments_function(
13259 JSFunction::cast(arguments_boilerplate->map()->constructor()));
13261 // Get the number of referencing objects.
13263 HeapIterator heap_iterator(heap);
13264 count = DebugReferencedBy(&heap_iterator,
13265 *target, *instance_filter, max_references,
13266 NULL, 0, *arguments_function);
13268 // Allocate an array to hold the result.
13269 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
13271 // Fill the referencing objects.
13272 // AllocateFixedArray above does not make the heap non-iterable.
13273 ASSERT(heap->IsHeapIterable());
13274 HeapIterator heap_iterator2(heap);
13275 count = DebugReferencedBy(&heap_iterator2,
13276 *target, *instance_filter, max_references,
13277 *instances, count, *arguments_function);
13279 // Return result as JS array.
13280 Handle<JSFunction> constructor(
13281 isolate->context()->native_context()->array_function());
13283 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
13284 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13289 // Helper function used by Runtime_DebugConstructedBy below.
13290 static int DebugConstructedBy(HeapIterator* iterator,
13291 JSFunction* constructor,
13292 int max_references,
13293 FixedArray* instances,
13294 int instances_size) {
13295 DisallowHeapAllocation no_allocation;
13297 // Iterate the heap.
13299 HeapObject* heap_obj = NULL;
13300 while (((heap_obj = iterator->next()) != NULL) &&
13301 (max_references == 0 || count < max_references)) {
13302 // Only look at all JSObjects.
13303 if (heap_obj->IsJSObject()) {
13304 JSObject* obj = JSObject::cast(heap_obj);
13305 if (obj->map()->constructor() == constructor) {
13306 // Valid reference found add to instance array if supplied an update
13308 if (instances != NULL && count < instances_size) {
13309 instances->set(count, obj);
13316 // Return the number of referencing objects found.
13321 // Scan the heap for objects constructed by a specific function.
13322 // args[0]: the constructor to find instances of
13323 // args[1]: the the maximum number of objects to return
13324 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
13325 HandleScope scope(isolate);
13326 ASSERT(args.length() == 2);
13328 // First perform a full GC in order to avoid dead objects.
13329 Heap* heap = isolate->heap();
13330 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
13332 // Check parameters.
13333 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
13334 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13335 RUNTIME_ASSERT(max_references >= 0);
13337 // Get the number of referencing objects.
13339 HeapIterator heap_iterator(heap);
13340 count = DebugConstructedBy(&heap_iterator,
13346 // Allocate an array to hold the result.
13347 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
13349 ASSERT(heap->IsHeapIterable());
13350 // Fill the referencing objects.
13351 HeapIterator heap_iterator2(heap);
13352 count = DebugConstructedBy(&heap_iterator2,
13358 // Return result as JS array.
13359 Handle<JSFunction> array_function(
13360 isolate->context()->native_context()->array_function());
13361 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
13362 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13367 // Find the effective prototype object as returned by __proto__.
13368 // args[0]: the object to find the prototype for.
13369 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
13370 HandleScope shs(isolate);
13371 ASSERT(args.length() == 1);
13372 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
13373 return *GetPrototypeSkipHiddenPrototypes(isolate, obj);
13377 // Patches script source (should be called upon BeforeCompile event).
13378 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
13379 HandleScope scope(isolate);
13380 ASSERT(args.length() == 2);
13382 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
13383 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13385 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13386 Handle<Script> script(Script::cast(script_wrapper->value()));
13388 int compilation_state = script->compilation_state();
13389 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13390 script->set_source(*source);
13392 return isolate->heap()->undefined_value();
13396 RUNTIME_FUNCTION(Runtime_SystemBreak) {
13397 SealHandleScope shs(isolate);
13398 ASSERT(args.length() == 0);
13400 return isolate->heap()->undefined_value();
13404 RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
13405 HandleScope scope(isolate);
13407 ASSERT(args.length() == 1);
13408 // Get the function and make sure it is compiled.
13409 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13410 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
13411 return isolate->heap()->exception();
13413 func->code()->PrintLn();
13415 return isolate->heap()->undefined_value();
13419 RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
13420 HandleScope scope(isolate);
13422 ASSERT(args.length() == 1);
13423 // Get the function and make sure it is compiled.
13424 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13425 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
13426 return isolate->heap()->exception();
13428 func->shared()->construct_stub()->PrintLn();
13430 return isolate->heap()->undefined_value();
13434 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
13435 SealHandleScope shs(isolate);
13436 ASSERT(args.length() == 1);
13438 CONVERT_ARG_CHECKED(JSFunction, f, 0);
13439 return f->shared()->inferred_name();
13443 static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13445 FixedArray* buffer) {
13446 DisallowHeapAllocation no_allocation;
13448 int buffer_size = buffer->length();
13449 for (HeapObject* obj = iterator->next();
13451 obj = iterator->next()) {
13452 ASSERT(obj != NULL);
13453 if (!obj->IsSharedFunctionInfo()) {
13456 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13457 if (shared->script() != script) {
13460 if (counter < buffer_size) {
13461 buffer->set(counter, shared);
13469 // For a script finds all SharedFunctionInfo's in the heap that points
13470 // to this script. Returns JSArray of SharedFunctionInfo wrapped
13471 // in OpaqueReferences.
13472 RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
13473 HandleScope scope(isolate);
13474 CHECK(isolate->debugger()->live_edit_enabled());
13475 ASSERT(args.length() == 1);
13476 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
13478 RUNTIME_ASSERT(script_value->value()->IsScript());
13479 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13481 const int kBufferSize = 32;
13483 Handle<FixedArray> array;
13484 array = isolate->factory()->NewFixedArray(kBufferSize);
13486 Heap* heap = isolate->heap();
13488 heap->EnsureHeapIsIterable();
13489 DisallowHeapAllocation no_allocation;
13490 HeapIterator heap_iterator(heap);
13491 Script* scr = *script;
13492 FixedArray* arr = *array;
13493 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13495 if (number > kBufferSize) {
13496 array = isolate->factory()->NewFixedArray(number);
13497 heap->EnsureHeapIsIterable();
13498 DisallowHeapAllocation no_allocation;
13499 HeapIterator heap_iterator(heap);
13500 Script* scr = *script;
13501 FixedArray* arr = *array;
13502 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13505 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
13506 result->set_length(Smi::FromInt(number));
13508 LiveEdit::WrapSharedFunctionInfos(result);
13514 // For a script calculates compilation information about all its functions.
13515 // The script source is explicitly specified by the second argument.
13516 // The source of the actual script is not used, however it is important that
13517 // all generated code keeps references to this particular instance of script.
13518 // Returns a JSArray of compilation infos. The array is ordered so that
13519 // each function with all its descendant is always stored in a continues range
13520 // with the function itself going first. The root function is a script function.
13521 RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
13522 HandleScope scope(isolate);
13523 CHECK(isolate->debugger()->live_edit_enabled());
13524 ASSERT(args.length() == 2);
13525 CONVERT_ARG_CHECKED(JSValue, script, 0);
13526 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13528 RUNTIME_ASSERT(script->value()->IsScript());
13529 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13531 Handle<JSArray> result;
13532 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13533 isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
13538 // Changes the source of the script to a new_source.
13539 // If old_script_name is provided (i.e. is a String), also creates a copy of
13540 // the script with its original source and sends notification to debugger.
13541 RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
13542 HandleScope scope(isolate);
13543 CHECK(isolate->debugger()->live_edit_enabled());
13544 ASSERT(args.length() == 3);
13545 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13546 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
13547 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
13549 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13550 Handle<Script> original_script(Script::cast(original_script_value->value()));
13552 Handle<Object> old_script = LiveEdit::ChangeScriptSource(
13553 original_script, new_source, old_script_name);
13555 if (old_script->IsScript()) {
13556 Handle<Script> script_handle = Handle<Script>::cast(old_script);
13557 return *Script::GetWrapper(script_handle);
13559 return isolate->heap()->null_value();
13564 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
13565 HandleScope scope(isolate);
13566 CHECK(isolate->debugger()->live_edit_enabled());
13567 ASSERT(args.length() == 1);
13568 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
13569 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
13571 LiveEdit::FunctionSourceUpdated(shared_info);
13572 return isolate->heap()->undefined_value();
13576 // Replaces code of SharedFunctionInfo with a new one.
13577 RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
13578 HandleScope scope(isolate);
13579 CHECK(isolate->debugger()->live_edit_enabled());
13580 ASSERT(args.length() == 2);
13581 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13582 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
13583 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
13585 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
13586 return isolate->heap()->undefined_value();
13590 // Connects SharedFunctionInfo to another script.
13591 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
13592 HandleScope scope(isolate);
13593 CHECK(isolate->debugger()->live_edit_enabled());
13594 ASSERT(args.length() == 2);
13595 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
13596 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
13598 if (function_object->IsJSValue()) {
13599 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13600 if (script_object->IsJSValue()) {
13601 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13602 Script* script = Script::cast(JSValue::cast(*script_object)->value());
13603 script_object = Handle<Object>(script, isolate);
13606 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13608 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13609 // and we check it in this function.
13612 return isolate->heap()->undefined_value();
13616 // In a code of a parent function replaces original function as embedded object
13617 // with a substitution one.
13618 RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
13619 HandleScope scope(isolate);
13620 CHECK(isolate->debugger()->live_edit_enabled());
13621 ASSERT(args.length() == 3);
13623 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13624 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13625 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
13626 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
13627 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
13628 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
13630 LiveEdit::ReplaceRefToNestedFunction(
13631 parent_wrapper, orig_wrapper, subst_wrapper);
13632 return isolate->heap()->undefined_value();
13636 // Updates positions of a shared function info (first parameter) according
13637 // to script source change. Text change is described in second parameter as
13638 // array of groups of 3 numbers:
13639 // (change_begin, change_end, change_end_new_position).
13640 // Each group describes a change in text; groups are sorted by change_begin.
13641 RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
13642 HandleScope scope(isolate);
13643 CHECK(isolate->debugger()->live_edit_enabled());
13644 ASSERT(args.length() == 2);
13645 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13646 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
13647 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
13649 LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
13650 return isolate->heap()->undefined_value();
13654 // For array of SharedFunctionInfo's (each wrapped in JSValue)
13655 // checks that none of them have activations on stacks (of any thread).
13656 // Returns array of the same length with corresponding results of
13657 // LiveEdit::FunctionPatchabilityStatus type.
13658 RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
13659 HandleScope scope(isolate);
13660 CHECK(isolate->debugger()->live_edit_enabled());
13661 ASSERT(args.length() == 2);
13662 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13663 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
13664 RUNTIME_ASSERT(shared_array->length()->IsSmi());
13665 int array_length = Smi::cast(shared_array->length())->value();
13666 for (int i = 0; i < array_length; i++) {
13667 Handle<Object> element =
13668 Object::GetElement(isolate, shared_array, i).ToHandleChecked();
13670 element->IsJSValue() &&
13671 Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
13674 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
13678 // Compares 2 strings line-by-line, then token-wise and returns diff in form
13679 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13681 RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
13682 HandleScope scope(isolate);
13683 CHECK(isolate->debugger()->live_edit_enabled());
13684 ASSERT(args.length() == 2);
13685 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13686 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
13688 return *LiveEdit::CompareStrings(s1, s2);
13692 // Restarts a call frame and completely drops all frames above.
13693 // Returns true if successful. Otherwise returns undefined or an error message.
13694 RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
13695 HandleScope scope(isolate);
13696 CHECK(isolate->debugger()->live_edit_enabled());
13697 ASSERT(args.length() == 2);
13698 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
13699 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
13701 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13702 Heap* heap = isolate->heap();
13704 // Find the relevant frame with the requested index.
13705 StackFrame::Id id = isolate->debug()->break_frame_id();
13706 if (id == StackFrame::NO_ID) {
13707 // If there are no JavaScript stack frames return undefined.
13708 return heap->undefined_value();
13712 JavaScriptFrameIterator it(isolate, id);
13713 for (; !it.done(); it.Advance()) {
13714 if (index < count + it.frame()->GetInlineCount()) break;
13715 count += it.frame()->GetInlineCount();
13717 if (it.done()) return heap->undefined_value();
13719 const char* error_message = LiveEdit::RestartFrame(it.frame());
13720 if (error_message) {
13721 return *(isolate->factory()->InternalizeUtf8String(error_message));
13723 return heap->true_value();
13727 // A testing entry. Returns statement position which is the closest to
13728 // source_position.
13729 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
13730 HandleScope scope(isolate);
13731 CHECK(isolate->debugger()->live_edit_enabled());
13732 ASSERT(args.length() == 2);
13733 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13734 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13736 Handle<Code> code(function->code(), isolate);
13738 if (code->kind() != Code::FUNCTION &&
13739 code->kind() != Code::OPTIMIZED_FUNCTION) {
13740 return isolate->heap()->undefined_value();
13743 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
13744 int closest_pc = 0;
13745 int distance = kMaxInt;
13746 while (!it.done()) {
13747 int statement_position = static_cast<int>(it.rinfo()->data());
13748 // Check if this break point is closer that what was previously found.
13749 if (source_position <= statement_position &&
13750 statement_position - source_position < distance) {
13752 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
13753 distance = statement_position - source_position;
13754 // Check whether we can't get any closer.
13755 if (distance == 0) break;
13760 return Smi::FromInt(closest_pc);
13764 // Calls specified function with or without entering the debugger.
13765 // This is used in unit tests to run code as if debugger is entered or simply
13766 // to have a stack with C++ frame in the middle.
13767 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
13768 HandleScope scope(isolate);
13769 ASSERT(args.length() == 2);
13770 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13771 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
13773 MaybeHandle<Object> maybe_result;
13774 if (without_debugger) {
13775 maybe_result = Execution::Call(isolate,
13777 isolate->global_object(),
13781 EnterDebugger enter_debugger(isolate);
13782 maybe_result = Execution::Call(isolate,
13784 isolate->global_object(),
13788 Handle<Object> result;
13789 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
13795 RUNTIME_FUNCTION(Runtime_SetFlags) {
13796 SealHandleScope shs(isolate);
13797 ASSERT(args.length() == 1);
13798 CONVERT_ARG_CHECKED(String, arg, 0);
13799 SmartArrayPointer<char> flags =
13800 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
13801 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
13802 return isolate->heap()->undefined_value();
13807 // Presently, it only does a full GC.
13808 RUNTIME_FUNCTION(Runtime_CollectGarbage) {
13809 SealHandleScope shs(isolate);
13810 ASSERT(args.length() == 1);
13811 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
13812 return isolate->heap()->undefined_value();
13816 // Gets the current heap usage.
13817 RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
13818 SealHandleScope shs(isolate);
13819 ASSERT(args.length() == 0);
13820 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
13821 if (!Smi::IsValid(usage)) {
13822 return *isolate->factory()->NewNumberFromInt(usage);
13824 return Smi::FromInt(usage);
13828 #ifdef V8_I18N_SUPPORT
13829 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
13830 HandleScope scope(isolate);
13831 Factory* factory = isolate->factory();
13833 ASSERT(args.length() == 1);
13834 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13836 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13838 // Return value which denotes invalid language tag.
13839 const char* const kInvalidTag = "invalid-tag";
13841 UErrorCode error = U_ZERO_ERROR;
13842 char icu_result[ULOC_FULLNAME_CAPACITY];
13843 int icu_length = 0;
13845 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13846 &icu_length, &error);
13847 if (U_FAILURE(error) || icu_length == 0) {
13848 return *factory->NewStringFromAsciiChecked(kInvalidTag);
13851 char result[ULOC_FULLNAME_CAPACITY];
13853 // Force strict BCP47 rules.
13854 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13856 if (U_FAILURE(error)) {
13857 return *factory->NewStringFromAsciiChecked(kInvalidTag);
13860 return *factory->NewStringFromAsciiChecked(result);
13864 RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
13865 HandleScope scope(isolate);
13866 Factory* factory = isolate->factory();
13868 ASSERT(args.length() == 1);
13869 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13871 const icu::Locale* available_locales = NULL;
13874 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13875 available_locales = icu::Collator::getAvailableLocales(count);
13876 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13877 available_locales = icu::NumberFormat::getAvailableLocales(count);
13878 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13879 available_locales = icu::DateFormat::getAvailableLocales(count);
13880 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13881 available_locales = icu::BreakIterator::getAvailableLocales(count);
13884 UErrorCode error = U_ZERO_ERROR;
13885 char result[ULOC_FULLNAME_CAPACITY];
13886 Handle<JSObject> locales =
13887 factory->NewJSObject(isolate->object_function());
13889 for (int32_t i = 0; i < count; ++i) {
13890 const char* icu_name = available_locales[i].getName();
13892 error = U_ZERO_ERROR;
13893 // No need to force strict BCP47 rules.
13894 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13895 if (U_FAILURE(error)) {
13896 // This shouldn't happen, but lets not break the user.
13900 RETURN_FAILURE_ON_EXCEPTION(isolate,
13901 JSObject::SetLocalPropertyIgnoreAttributes(
13903 factory->NewStringFromAsciiChecked(result),
13904 factory->NewNumber(i),
13912 RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
13913 HandleScope scope(isolate);
13914 Factory* factory = isolate->factory();
13916 ASSERT(args.length() == 0);
13918 icu::Locale default_locale;
13921 char result[ULOC_FULLNAME_CAPACITY];
13922 UErrorCode status = U_ZERO_ERROR;
13923 uloc_toLanguageTag(
13924 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13925 if (U_SUCCESS(status)) {
13926 return *factory->NewStringFromAsciiChecked(result);
13929 return *factory->NewStringFromStaticAscii("und");
13933 RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
13934 HandleScope scope(isolate);
13935 Factory* factory = isolate->factory();
13937 ASSERT(args.length() == 1);
13939 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13941 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13942 // Set some limit to prevent fuzz tests from going OOM.
13943 // Can be bumped when callers' requirements change.
13944 RUNTIME_ASSERT(length < 100);
13945 Handle<FixedArray> output = factory->NewFixedArray(length);
13946 Handle<Name> maximized = factory->NewStringFromStaticAscii("maximized");
13947 Handle<Name> base = factory->NewStringFromStaticAscii("base");
13948 for (unsigned int i = 0; i < length; ++i) {
13949 Handle<Object> locale_id;
13950 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
13951 isolate, locale_id, Object::GetElement(isolate, input, i));
13952 if (!locale_id->IsString()) {
13953 return isolate->Throw(*factory->illegal_argument_string());
13956 v8::String::Utf8Value utf8_locale_id(
13957 v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
13959 UErrorCode error = U_ZERO_ERROR;
13961 // Convert from BCP47 to ICU format.
13962 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13963 char icu_locale[ULOC_FULLNAME_CAPACITY];
13964 int icu_locale_length = 0;
13965 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13966 &icu_locale_length, &error);
13967 if (U_FAILURE(error) || icu_locale_length == 0) {
13968 return isolate->Throw(*factory->illegal_argument_string());
13971 // Maximize the locale.
13972 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13973 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13974 uloc_addLikelySubtags(
13975 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13977 // Remove extensions from maximized locale.
13978 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13979 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13981 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13983 // Get original name without extensions.
13984 // de_DE@collation=phonebook -> de_DE
13985 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13987 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13989 // Convert from ICU locale format to BCP47 format.
13990 // de_Latn_DE -> de-Latn-DE
13991 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13992 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13993 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13996 char base_locale[ULOC_FULLNAME_CAPACITY];
13997 uloc_toLanguageTag(
13998 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
14000 if (U_FAILURE(error)) {
14001 return isolate->Throw(*factory->illegal_argument_string());
14004 Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
14005 RETURN_FAILURE_ON_EXCEPTION(isolate,
14006 JSObject::SetLocalPropertyIgnoreAttributes(
14009 factory->NewStringFromAsciiChecked(base_max_locale),
14011 RETURN_FAILURE_ON_EXCEPTION(isolate,
14012 JSObject::SetLocalPropertyIgnoreAttributes(
14015 factory->NewStringFromAsciiChecked(base_locale),
14017 output->set(i, *result);
14020 Handle<JSArray> result = factory->NewJSArrayWithElements(output);
14021 result->set_length(Smi::FromInt(length));
14026 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
14027 HandleScope scope(isolate);
14029 ASSERT(args.length() == 1);
14031 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
14033 if (!input->IsJSObject()) return isolate->heap()->false_value();
14034 Handle<JSObject> obj = Handle<JSObject>::cast(input);
14036 Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
14037 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate);
14038 return isolate->heap()->ToBoolean(!tag->IsTheHole());
14042 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
14043 HandleScope scope(isolate);
14045 ASSERT(args.length() == 2);
14047 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
14048 CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
14050 if (!input->IsJSObject()) return isolate->heap()->false_value();
14051 Handle<JSObject> obj = Handle<JSObject>::cast(input);
14053 Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
14054 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate);
14055 return isolate->heap()->ToBoolean(
14056 tag->IsString() && String::cast(*tag)->Equals(*expected_type));
14060 RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
14061 HandleScope scope(isolate);
14063 ASSERT(args.length() == 3);
14065 CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
14066 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
14067 CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
14069 Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
14070 JSObject::SetHiddenProperty(input, marker, type);
14072 marker = isolate->factory()->intl_impl_object_string();
14073 JSObject::SetHiddenProperty(input, marker, impl);
14075 return isolate->heap()->undefined_value();
14079 RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
14080 HandleScope scope(isolate);
14082 ASSERT(args.length() == 1);
14084 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
14086 if (!input->IsJSObject()) {
14087 Vector< Handle<Object> > arguments = HandleVector(&input, 1);
14088 Handle<Object> type_error =
14089 isolate->factory()->NewTypeError("not_intl_object", arguments);
14090 return isolate->Throw(*type_error);
14093 Handle<JSObject> obj = Handle<JSObject>::cast(input);
14095 Handle<String> marker = isolate->factory()->intl_impl_object_string();
14096 Handle<Object> impl(obj->GetHiddenProperty(marker), isolate);
14097 if (impl->IsTheHole()) {
14098 Vector< Handle<Object> > arguments = HandleVector(&obj, 1);
14099 Handle<Object> type_error =
14100 isolate->factory()->NewTypeError("not_intl_object", arguments);
14101 return isolate->Throw(*type_error);
14107 RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
14108 HandleScope scope(isolate);
14110 ASSERT(args.length() == 3);
14112 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14113 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14114 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14116 Handle<ObjectTemplateInfo> date_format_template =
14117 I18N::GetTemplate(isolate);
14119 // Create an empty object wrapper.
14120 Handle<JSObject> local_object;
14121 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14122 isolate, local_object,
14123 Execution::InstantiateObject(date_format_template));
14125 // Set date time formatter as internal field of the resulting JS object.
14126 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
14127 isolate, locale, options, resolved);
14129 if (!date_format) return isolate->ThrowIllegalOperation();
14131 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
14133 RETURN_FAILURE_ON_EXCEPTION(isolate,
14134 JSObject::SetLocalPropertyIgnoreAttributes(
14136 isolate->factory()->NewStringFromStaticAscii("dateFormat"),
14137 isolate->factory()->NewStringFromStaticAscii("valid"),
14140 // Make object handle weak so we can delete the data format once GC kicks in.
14141 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14142 GlobalHandles::MakeWeak(wrapper.location(),
14143 reinterpret_cast<void*>(wrapper.location()),
14144 DateFormat::DeleteDateFormat);
14145 return *local_object;
14149 RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
14150 HandleScope scope(isolate);
14152 ASSERT(args.length() == 2);
14154 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
14155 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
14157 Handle<Object> value;
14158 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14159 isolate, value, Execution::ToNumber(isolate, date));
14161 icu::SimpleDateFormat* date_format =
14162 DateFormat::UnpackDateFormat(isolate, date_format_holder);
14163 if (!date_format) return isolate->ThrowIllegalOperation();
14165 icu::UnicodeString result;
14166 date_format->format(value->Number(), result);
14168 Handle<String> result_str;
14169 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14170 isolate, result_str,
14171 isolate->factory()->NewStringFromTwoByte(
14172 Vector<const uint16_t>(
14173 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14174 result.length())));
14175 return *result_str;
14179 RUNTIME_FUNCTION(Runtime_InternalDateParse) {
14180 HandleScope scope(isolate);
14182 ASSERT(args.length() == 2);
14184 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
14185 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
14187 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
14188 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
14189 icu::SimpleDateFormat* date_format =
14190 DateFormat::UnpackDateFormat(isolate, date_format_holder);
14191 if (!date_format) return isolate->ThrowIllegalOperation();
14193 UErrorCode status = U_ZERO_ERROR;
14194 UDate date = date_format->parse(u_date, status);
14195 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
14197 Handle<Object> result;
14198 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14200 Execution::NewDate(isolate, static_cast<double>(date)));
14201 ASSERT(result->IsJSDate());
14206 RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
14207 HandleScope scope(isolate);
14209 ASSERT(args.length() == 3);
14211 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14212 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14213 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14215 Handle<ObjectTemplateInfo> number_format_template =
14216 I18N::GetTemplate(isolate);
14218 // Create an empty object wrapper.
14219 Handle<JSObject> local_object;
14220 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14221 isolate, local_object,
14222 Execution::InstantiateObject(number_format_template));
14224 // Set number formatter as internal field of the resulting JS object.
14225 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
14226 isolate, locale, options, resolved);
14228 if (!number_format) return isolate->ThrowIllegalOperation();
14230 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
14232 RETURN_FAILURE_ON_EXCEPTION(isolate,
14233 JSObject::SetLocalPropertyIgnoreAttributes(
14235 isolate->factory()->NewStringFromStaticAscii("numberFormat"),
14236 isolate->factory()->NewStringFromStaticAscii("valid"),
14239 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14240 GlobalHandles::MakeWeak(wrapper.location(),
14241 reinterpret_cast<void*>(wrapper.location()),
14242 NumberFormat::DeleteNumberFormat);
14243 return *local_object;
14247 RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
14248 HandleScope scope(isolate);
14250 ASSERT(args.length() == 2);
14252 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
14253 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
14255 Handle<Object> value;
14256 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14257 isolate, value, Execution::ToNumber(isolate, number));
14259 icu::DecimalFormat* number_format =
14260 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
14261 if (!number_format) return isolate->ThrowIllegalOperation();
14263 icu::UnicodeString result;
14264 number_format->format(value->Number(), result);
14266 Handle<String> result_str;
14267 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14268 isolate, result_str,
14269 isolate->factory()->NewStringFromTwoByte(
14270 Vector<const uint16_t>(
14271 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14272 result.length())));
14273 return *result_str;
14277 RUNTIME_FUNCTION(Runtime_InternalNumberParse) {
14278 HandleScope scope(isolate);
14280 ASSERT(args.length() == 2);
14282 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
14283 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
14285 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
14286 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
14287 icu::DecimalFormat* number_format =
14288 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
14289 if (!number_format) return isolate->ThrowIllegalOperation();
14291 UErrorCode status = U_ZERO_ERROR;
14292 icu::Formattable result;
14293 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
14294 // to be part of Chrome.
14295 // TODO(cira): Include currency parsing code using parseCurrency call.
14296 // We need to check if the formatter parses all currencies or only the
14297 // one it was constructed with (it will impact the API - how to return ISO
14298 // code and the value).
14299 number_format->parse(u_number, result, status);
14300 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
14302 switch (result.getType()) {
14303 case icu::Formattable::kDouble:
14304 return *isolate->factory()->NewNumber(result.getDouble());
14305 case icu::Formattable::kLong:
14306 return *isolate->factory()->NewNumberFromInt(result.getLong());
14307 case icu::Formattable::kInt64:
14308 return *isolate->factory()->NewNumber(
14309 static_cast<double>(result.getInt64()));
14311 return isolate->heap()->undefined_value();
14316 RUNTIME_FUNCTION(Runtime_CreateCollator) {
14317 HandleScope scope(isolate);
14319 ASSERT(args.length() == 3);
14321 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14322 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14323 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14325 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
14327 // Create an empty object wrapper.
14328 Handle<JSObject> local_object;
14329 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14330 isolate, local_object, Execution::InstantiateObject(collator_template));
14332 // Set collator as internal field of the resulting JS object.
14333 icu::Collator* collator = Collator::InitializeCollator(
14334 isolate, locale, options, resolved);
14336 if (!collator) return isolate->ThrowIllegalOperation();
14338 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
14340 RETURN_FAILURE_ON_EXCEPTION(isolate,
14341 JSObject::SetLocalPropertyIgnoreAttributes(
14343 isolate->factory()->NewStringFromStaticAscii("collator"),
14344 isolate->factory()->NewStringFromStaticAscii("valid"),
14347 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14348 GlobalHandles::MakeWeak(wrapper.location(),
14349 reinterpret_cast<void*>(wrapper.location()),
14350 Collator::DeleteCollator);
14351 return *local_object;
14355 RUNTIME_FUNCTION(Runtime_InternalCompare) {
14356 HandleScope scope(isolate);
14358 ASSERT(args.length() == 3);
14360 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14361 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14362 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14364 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14365 if (!collator) return isolate->ThrowIllegalOperation();
14367 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14368 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14369 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14370 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14371 UErrorCode status = U_ZERO_ERROR;
14372 UCollationResult result = collator->compare(u_string1,
14373 string_value1.length(),
14375 string_value2.length(),
14377 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14379 return *isolate->factory()->NewNumberFromInt(result);
14383 RUNTIME_FUNCTION(Runtime_StringNormalize) {
14384 HandleScope scope(isolate);
14385 static const UNormalizationMode normalizationForms[] =
14386 { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD };
14388 ASSERT(args.length() == 2);
14390 CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0);
14391 CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
14392 RUNTIME_ASSERT(form_id >= 0 &&
14393 static_cast<size_t>(form_id) < ARRAY_SIZE(normalizationForms));
14395 v8::String::Value string_value(v8::Utils::ToLocal(stringValue));
14396 const UChar* u_value = reinterpret_cast<const UChar*>(*string_value);
14398 // TODO(mnita): check Normalizer2 (not available in ICU 46)
14399 UErrorCode status = U_ZERO_ERROR;
14400 icu::UnicodeString result;
14401 icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0,
14403 if (U_FAILURE(status)) {
14404 return isolate->heap()->undefined_value();
14407 Handle<String> result_str;
14408 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14409 isolate, result_str,
14410 isolate->factory()->NewStringFromTwoByte(
14411 Vector<const uint16_t>(
14412 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14413 result.length())));
14414 return *result_str;
14418 RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
14419 HandleScope scope(isolate);
14421 ASSERT(args.length() == 3);
14423 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14424 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14425 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14427 Handle<ObjectTemplateInfo> break_iterator_template =
14428 I18N::GetTemplate2(isolate);
14430 // Create an empty object wrapper.
14431 Handle<JSObject> local_object;
14432 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14433 isolate, local_object,
14434 Execution::InstantiateObject(break_iterator_template));
14436 // Set break iterator as internal field of the resulting JS object.
14437 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14438 isolate, locale, options, resolved);
14440 if (!break_iterator) return isolate->ThrowIllegalOperation();
14442 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14443 // Make sure that the pointer to adopted text is NULL.
14444 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14446 RETURN_FAILURE_ON_EXCEPTION(isolate,
14447 JSObject::SetLocalPropertyIgnoreAttributes(
14449 isolate->factory()->NewStringFromStaticAscii("breakIterator"),
14450 isolate->factory()->NewStringFromStaticAscii("valid"),
14453 // Make object handle weak so we can delete the break iterator once GC kicks
14455 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14456 GlobalHandles::MakeWeak(wrapper.location(),
14457 reinterpret_cast<void*>(wrapper.location()),
14458 BreakIterator::DeleteBreakIterator);
14459 return *local_object;
14463 RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
14464 HandleScope scope(isolate);
14466 ASSERT(args.length() == 2);
14468 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14469 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14471 icu::BreakIterator* break_iterator =
14472 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14473 if (!break_iterator) return isolate->ThrowIllegalOperation();
14475 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14476 break_iterator_holder->GetInternalField(1));
14479 v8::String::Value text_value(v8::Utils::ToLocal(text));
14480 u_text = new icu::UnicodeString(
14481 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14482 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14484 break_iterator->setText(*u_text);
14486 return isolate->heap()->undefined_value();
14490 RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
14491 HandleScope scope(isolate);
14493 ASSERT(args.length() == 1);
14495 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14497 icu::BreakIterator* break_iterator =
14498 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14499 if (!break_iterator) return isolate->ThrowIllegalOperation();
14501 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14505 RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
14506 HandleScope scope(isolate);
14508 ASSERT(args.length() == 1);
14510 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14512 icu::BreakIterator* break_iterator =
14513 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14514 if (!break_iterator) return isolate->ThrowIllegalOperation();
14516 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14520 RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
14521 HandleScope scope(isolate);
14523 ASSERT(args.length() == 1);
14525 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14527 icu::BreakIterator* break_iterator =
14528 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14529 if (!break_iterator) return isolate->ThrowIllegalOperation();
14531 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14535 RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
14536 HandleScope scope(isolate);
14538 ASSERT(args.length() == 1);
14540 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14542 icu::BreakIterator* break_iterator =
14543 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14544 if (!break_iterator) return isolate->ThrowIllegalOperation();
14546 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14547 icu::RuleBasedBreakIterator* rule_based_iterator =
14548 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14549 int32_t status = rule_based_iterator->getRuleStatus();
14550 // Keep return values in sync with JavaScript BreakType enum.
14551 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14552 return *isolate->factory()->NewStringFromStaticAscii("none");
14553 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14554 return *isolate->factory()->NewStringFromStaticAscii("number");
14555 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14556 return *isolate->factory()->NewStringFromStaticAscii("letter");
14557 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14558 return *isolate->factory()->NewStringFromStaticAscii("kana");
14559 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14560 return *isolate->factory()->NewStringFromStaticAscii("ideo");
14562 return *isolate->factory()->NewStringFromStaticAscii("unknown");
14565 #endif // V8_I18N_SUPPORT
14568 // Finds the script object from the script data. NOTE: This operation uses
14569 // heap traversal to find the function generated for the source position
14570 // for the requested break point. For lazily compiled functions several heap
14571 // traversals might be required rendering this operation as a rather slow
14572 // operation. However for setting break points which is normally done through
14573 // some kind of user interaction the performance is not crucial.
14574 static Handle<Object> Runtime_GetScriptFromScriptName(
14575 Handle<String> script_name) {
14576 // Scan the heap for Script objects to find the script with the requested
14578 Handle<Script> script;
14579 Factory* factory = script_name->GetIsolate()->factory();
14580 Heap* heap = script_name->GetHeap();
14581 heap->EnsureHeapIsIterable();
14582 DisallowHeapAllocation no_allocation_during_heap_iteration;
14583 HeapIterator iterator(heap);
14584 HeapObject* obj = NULL;
14585 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
14586 // If a script is found check if it has the script data requested.
14587 if (obj->IsScript()) {
14588 if (Script::cast(obj)->name()->IsString()) {
14589 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14590 script = Handle<Script>(Script::cast(obj));
14596 // If no script with the requested script data is found return undefined.
14597 if (script.is_null()) return factory->undefined_value();
14599 // Return the script found.
14600 return Script::GetWrapper(script);
14604 // Get the script object from script data. NOTE: Regarding performance
14605 // see the NOTE for GetScriptFromScriptData.
14606 // args[0]: script data for the script to find the source for
14607 RUNTIME_FUNCTION(Runtime_GetScript) {
14608 HandleScope scope(isolate);
14610 ASSERT(args.length() == 1);
14612 CONVERT_ARG_CHECKED(String, script_name, 0);
14614 // Find the requested script.
14615 Handle<Object> result =
14616 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14621 // Collect the raw data for a stack trace. Returns an array of 4
14622 // element segments each containing a receiver, function, code and
14623 // native code offset.
14624 RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
14625 HandleScope scope(isolate);
14626 ASSERT(args.length() == 3);
14627 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14628 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
14629 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
14631 // Optionally capture a more detailed stack trace for the message.
14632 isolate->CaptureAndSetDetailedStackTrace(error_object);
14633 // Capture a simple stack trace for the stack property.
14634 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14638 // Retrieve the stack trace. This is the raw stack trace that yet has to
14639 // be formatted. Since we only need this once, clear it afterwards.
14640 RUNTIME_FUNCTION(Runtime_GetAndClearOverflowedStackTrace) {
14641 HandleScope scope(isolate);
14642 ASSERT(args.length() == 1);
14643 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14644 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14645 Handle<Object> result(error_object->GetHiddenProperty(key), isolate);
14646 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14647 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
14648 JSObject::DeleteHiddenProperty(error_object, key);
14653 // Returns V8 version as a string.
14654 RUNTIME_FUNCTION(Runtime_GetV8Version) {
14655 HandleScope scope(isolate);
14656 ASSERT(args.length() == 0);
14658 const char* version_string = v8::V8::GetVersion();
14660 return *isolate->factory()->NewStringFromAsciiChecked(version_string);
14664 RUNTIME_FUNCTION(Runtime_Abort) {
14665 SealHandleScope shs(isolate);
14666 ASSERT(args.length() == 1);
14667 CONVERT_SMI_ARG_CHECKED(message_id, 0);
14668 const char* message = GetBailoutReason(
14669 static_cast<BailoutReason>(message_id));
14670 OS::PrintError("abort: %s\n", message);
14671 isolate->PrintStack(stderr);
14678 RUNTIME_FUNCTION(Runtime_AbortJS) {
14679 HandleScope scope(isolate);
14680 ASSERT(args.length() == 1);
14681 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
14682 OS::PrintError("abort: %s\n", message->ToCString().get());
14683 isolate->PrintStack(stderr);
14690 RUNTIME_FUNCTION(Runtime_FlattenString) {
14691 HandleScope scope(isolate);
14692 ASSERT(args.length() == 1);
14693 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14694 return *String::Flatten(str);
14698 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
14699 HandleScope scope(isolate);
14700 ASSERT(args.length() == 0);
14701 isolate->heap()->NotifyContextDisposed();
14702 return isolate->heap()->undefined_value();
14706 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
14707 HandleScope scope(isolate);
14708 ASSERT(args.length() == 2);
14709 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
14710 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
14711 int idx = index->value() >> 1;
14712 int inobject_properties = object->map()->inobject_properties();
14714 idx = -idx + inobject_properties - 1;
14716 int max_idx = object->properties()->length() + inobject_properties;
14717 RUNTIME_ASSERT(idx < max_idx);
14718 Handle<Object> raw_value(object->RawFastPropertyAt(idx), isolate);
14719 RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized());
14720 return *Object::NewStorageFor(isolate, raw_value, Representation::Double());
14724 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
14725 HandleScope scope(isolate);
14726 ASSERT(args.length() == 1);
14727 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14728 if (!object->IsJSObject()) return Smi::FromInt(0);
14729 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14730 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14731 // This call must not cause lazy deopts, because it's called from deferred
14732 // code where we can't handle lazy deopts for lack of a suitable bailout
14733 // ID. So we just try migration and signal failure if necessary,
14734 // which will also trigger a deopt.
14735 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
14740 RUNTIME_FUNCTION(RuntimeHidden_GetFromCache) {
14741 SealHandleScope shs(isolate);
14742 // This is only called from codegen, so checks might be more lax.
14743 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
14744 CONVERT_ARG_CHECKED(Object, key, 1);
14747 DisallowHeapAllocation no_alloc;
14749 int finger_index = cache->finger_index();
14750 Object* o = cache->get(finger_index);
14752 // The fastest case: hit the same place again.
14753 return cache->get(finger_index + 1);
14756 for (int i = finger_index - 2;
14757 i >= JSFunctionResultCache::kEntriesIndex;
14761 cache->set_finger_index(i);
14762 return cache->get(i + 1);
14766 int size = cache->size();
14767 ASSERT(size <= cache->length());
14769 for (int i = size - 2; i > finger_index; i -= 2) {
14772 cache->set_finger_index(i);
14773 return cache->get(i + 1);
14778 // There is no value in the cache. Invoke the function and cache result.
14779 HandleScope scope(isolate);
14781 Handle<JSFunctionResultCache> cache_handle(cache);
14782 Handle<Object> key_handle(key, isolate);
14783 Handle<Object> value;
14785 Handle<JSFunction> factory(JSFunction::cast(
14786 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14787 // TODO(antonm): consider passing a receiver when constructing a cache.
14788 Handle<Object> receiver(isolate->native_context()->global_object(),
14790 // This handle is nor shared, nor used later, so it's safe.
14791 Handle<Object> argv[] = { key_handle };
14792 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14794 Execution::Call(isolate, factory, receiver, ARRAY_SIZE(argv), argv));
14798 if (FLAG_verify_heap) {
14799 cache_handle->JSFunctionResultCacheVerify();
14803 // Function invocation may have cleared the cache. Reread all the data.
14804 int finger_index = cache_handle->finger_index();
14805 int size = cache_handle->size();
14807 // If we have spare room, put new data into it, otherwise evict post finger
14808 // entry which is likely to be the least recently used.
14810 if (size < cache_handle->length()) {
14811 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14814 index = finger_index + JSFunctionResultCache::kEntrySize;
14815 if (index == cache_handle->length()) {
14816 index = JSFunctionResultCache::kEntriesIndex;
14820 ASSERT(index % 2 == 0);
14821 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14822 ASSERT(index < cache_handle->length());
14824 cache_handle->set(index, *key_handle);
14825 cache_handle->set(index + 1, *value);
14826 cache_handle->set_finger_index(index);
14829 if (FLAG_verify_heap) {
14830 cache_handle->JSFunctionResultCacheVerify();
14838 RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
14839 SealHandleScope shs(isolate);
14840 ASSERT(args.length() == 1);
14841 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14842 return Smi::FromInt(message->start_position());
14846 RUNTIME_FUNCTION(Runtime_MessageGetScript) {
14847 SealHandleScope shs(isolate);
14848 ASSERT(args.length() == 1);
14849 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14850 return message->script();
14855 // ListNatives is ONLY used by the fuzz-natives.js in debug mode
14856 // Exclude the code in release mode.
14857 RUNTIME_FUNCTION(Runtime_ListNatives) {
14858 HandleScope scope(isolate);
14859 ASSERT(args.length() == 0);
14860 #define COUNT_ENTRY(Name, argc, ressize) + 1
14861 int entry_count = 0
14862 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14863 RUNTIME_HIDDEN_FUNCTION_LIST(COUNT_ENTRY)
14864 INLINE_FUNCTION_LIST(COUNT_ENTRY);
14866 Factory* factory = isolate->factory();
14867 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
14869 bool inline_runtime_functions = false;
14870 #define ADD_ENTRY(Name, argc, ressize) \
14872 HandleScope inner(isolate); \
14873 Handle<String> name; \
14874 /* Inline runtime functions have an underscore in front of the name. */ \
14875 if (inline_runtime_functions) { \
14876 name = factory->NewStringFromStaticAscii("_" #Name); \
14878 name = factory->NewStringFromStaticAscii(#Name); \
14880 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
14881 pair_elements->set(0, *name); \
14882 pair_elements->set(1, Smi::FromInt(argc)); \
14883 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
14884 elements->set(index++, *pair); \
14886 inline_runtime_functions = false;
14887 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
14888 // Calling hidden runtime functions should just throw.
14889 RUNTIME_HIDDEN_FUNCTION_LIST(ADD_ENTRY)
14890 inline_runtime_functions = true;
14891 INLINE_FUNCTION_LIST(ADD_ENTRY)
14893 ASSERT_EQ(index, entry_count);
14894 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
14900 RUNTIME_FUNCTION(RuntimeHidden_Log) {
14901 HandleScope handle_scope(isolate);
14902 ASSERT(args.length() == 2);
14903 CONVERT_ARG_HANDLE_CHECKED(String, format, 0);
14904 CONVERT_ARG_HANDLE_CHECKED(JSArray, elms, 1);
14906 SmartArrayPointer<char> format_chars = format->ToCString();
14907 isolate->logger()->LogRuntime(
14908 Vector<const char>(format_chars.get(), format->length()), elms);
14909 return isolate->heap()->undefined_value();
14913 RUNTIME_FUNCTION(Runtime_IS_VAR) {
14914 UNREACHABLE(); // implemented as macro in the parser
14919 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14920 RUNTIME_FUNCTION(Runtime_Has##Name) { \
14921 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14922 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14925 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
14926 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14927 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
14928 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
14929 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
14930 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
14931 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
14932 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14933 // Properties test sitting with elements tests - not fooling anyone.
14934 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
14936 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14939 #define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
14940 RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \
14941 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14942 return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
14945 TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
14947 #undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
14950 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
14951 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
14952 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14953 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
14956 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
14958 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
14961 RUNTIME_FUNCTION(Runtime_HaveSameMap) {
14962 SealHandleScope shs(isolate);
14963 ASSERT(args.length() == 2);
14964 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14965 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
14966 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14970 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
14971 SealHandleScope shs(isolate);
14972 ASSERT(args.length() == 1);
14973 CONVERT_ARG_CHECKED(Object, obj, 0);
14974 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
14978 RUNTIME_FUNCTION(Runtime_IsObserved) {
14979 SealHandleScope shs(isolate);
14980 ASSERT(args.length() == 1);
14982 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14983 CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
14984 if (obj->IsJSGlobalProxy()) {
14985 Object* proto = obj->GetPrototype();
14986 if (proto->IsNull()) return isolate->heap()->false_value();
14987 ASSERT(proto->IsJSGlobalObject());
14988 obj = JSReceiver::cast(proto);
14990 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14994 RUNTIME_FUNCTION(Runtime_SetIsObserved) {
14995 HandleScope scope(isolate);
14996 ASSERT(args.length() == 1);
14997 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
14998 if (obj->IsJSGlobalProxy()) {
14999 Object* proto = obj->GetPrototype();
15000 if (proto->IsNull()) return isolate->heap()->undefined_value();
15001 ASSERT(proto->IsJSGlobalObject());
15002 obj = handle(JSReceiver::cast(proto));
15004 if (obj->IsJSProxy())
15005 return isolate->heap()->undefined_value();
15007 ASSERT(obj->IsJSObject());
15008 JSObject::SetObserved(Handle<JSObject>::cast(obj));
15009 return isolate->heap()->undefined_value();
15013 RUNTIME_FUNCTION(Runtime_SetMicrotaskPending) {
15014 SealHandleScope shs(isolate);
15015 ASSERT(args.length() == 1);
15016 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
15017 bool old_state = isolate->microtask_pending();
15018 isolate->set_microtask_pending(new_state);
15019 return isolate->heap()->ToBoolean(old_state);
15023 RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
15024 HandleScope scope(isolate);
15025 ASSERT(args.length() == 0);
15026 if (isolate->microtask_pending()) Execution::RunMicrotasks(isolate);
15027 return isolate->heap()->undefined_value();
15031 RUNTIME_FUNCTION(Runtime_GetMicrotaskState) {
15032 SealHandleScope shs(isolate);
15033 ASSERT(args.length() == 0);
15034 return isolate->heap()->microtask_state();
15038 RUNTIME_FUNCTION(Runtime_GetObservationState) {
15039 SealHandleScope shs(isolate);
15040 ASSERT(args.length() == 0);
15041 return isolate->heap()->observation_state();
15045 RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) {
15046 HandleScope scope(isolate);
15047 ASSERT(args.length() == 0);
15048 // TODO(adamk): Currently this runtime function is only called three times per
15049 // isolate. If it's called more often, the map should be moved into the
15050 // strong root list.
15052 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
15053 Handle<JSWeakMap> weakmap =
15054 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
15055 return *WeakCollectionInitialize(isolate, weakmap);
15059 static bool ContextsHaveSameOrigin(Handle<Context> context1,
15060 Handle<Context> context2) {
15061 return context1->security_token() == context2->security_token();
15065 RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) {
15066 HandleScope scope(isolate);
15067 ASSERT(args.length() == 3);
15068 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
15069 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
15070 CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2);
15072 Handle<Context> observer_context(observer->context()->native_context(),
15074 Handle<Context> object_context(object->GetCreationContext());
15075 Handle<Context> record_context(record->GetCreationContext());
15077 return isolate->heap()->ToBoolean(
15078 ContextsHaveSameOrigin(object_context, observer_context) &&
15079 ContextsHaveSameOrigin(object_context, record_context));
15083 RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) {
15084 HandleScope scope(isolate);
15085 ASSERT(args.length() == 1);
15086 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
15088 Handle<Context> creation_context(object->GetCreationContext(), isolate);
15089 return isolate->heap()->ToBoolean(
15090 ContextsHaveSameOrigin(creation_context, isolate->native_context()));
15094 RUNTIME_FUNCTION(Runtime_ObjectObserveInObjectContext) {
15095 HandleScope scope(isolate);
15096 ASSERT(args.length() == 3);
15097 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
15098 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 1);
15099 CONVERT_ARG_HANDLE_CHECKED(Object, accept, 2);
15100 RUNTIME_ASSERT(accept->IsUndefined() || accept->IsJSObject());
15102 Handle<Context> context(object->GetCreationContext(), isolate);
15103 Handle<JSFunction> function(context->native_object_observe(), isolate);
15104 Handle<Object> call_args[] = { object, callback, accept };
15105 Handle<Object> result;
15107 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
15109 Execution::Call(isolate, function,
15110 handle(context->object_function(), isolate),
15111 ARRAY_SIZE(call_args), call_args, true));
15116 RUNTIME_FUNCTION(Runtime_ObjectGetNotifierInObjectContext) {
15117 HandleScope scope(isolate);
15118 ASSERT(args.length() == 1);
15119 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
15121 Handle<Context> context(object->GetCreationContext(), isolate);
15122 Handle<JSFunction> function(context->native_object_get_notifier(), isolate);
15123 Handle<Object> call_args[] = { object };
15124 Handle<Object> result;
15126 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
15128 Execution::Call(isolate, function,
15129 handle(context->object_function(), isolate),
15130 ARRAY_SIZE(call_args), call_args, true));
15135 RUNTIME_FUNCTION(Runtime_ObjectNotifierPerformChangeInObjectContext) {
15136 HandleScope scope(isolate);
15137 ASSERT(args.length() == 3);
15138 CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0);
15139 CONVERT_ARG_HANDLE_CHECKED(String, change_type, 1);
15140 CONVERT_ARG_HANDLE_CHECKED(JSFunction, change_fn, 2);
15142 Handle<Context> context(object_info->GetCreationContext(), isolate);
15143 Handle<JSFunction> function(context->native_object_notifier_perform_change(),
15145 Handle<Object> call_args[] = { object_info, change_type, change_fn };
15146 Handle<Object> result;
15148 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
15150 Execution::Call(isolate, function, isolate->factory()->undefined_value(),
15151 ARRAY_SIZE(call_args), call_args, true));
15156 static Object* ArrayConstructorCommon(Isolate* isolate,
15157 Handle<JSFunction> constructor,
15158 Handle<AllocationSite> site,
15159 Arguments* caller_args) {
15160 Factory* factory = isolate->factory();
15162 bool holey = false;
15163 bool can_use_type_feedback = true;
15164 if (caller_args->length() == 1) {
15165 Handle<Object> argument_one = caller_args->at<Object>(0);
15166 if (argument_one->IsSmi()) {
15167 int value = Handle<Smi>::cast(argument_one)->value();
15168 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
15169 // the array is a dictionary in this case.
15170 can_use_type_feedback = false;
15171 } else if (value != 0) {
15175 // Non-smi length argument produces a dictionary
15176 can_use_type_feedback = false;
15180 Handle<JSArray> array;
15181 if (!site.is_null() && can_use_type_feedback) {
15182 ElementsKind to_kind = site->GetElementsKind();
15183 if (holey && !IsFastHoleyElementsKind(to_kind)) {
15184 to_kind = GetHoleyElementsKind(to_kind);
15185 // Update the allocation site info to reflect the advice alteration.
15186 site->SetElementsKind(to_kind);
15189 // We should allocate with an initial map that reflects the allocation site
15190 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
15191 // the constructor.
15192 Handle<Map> initial_map(constructor->initial_map(), isolate);
15193 if (to_kind != initial_map->elements_kind()) {
15194 initial_map = Map::AsElementsKind(initial_map, to_kind);
15197 // If we don't care to track arrays of to_kind ElementsKind, then
15198 // don't emit a memento for them.
15199 Handle<AllocationSite> allocation_site;
15200 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
15201 allocation_site = site;
15204 array = Handle<JSArray>::cast(factory->NewJSObjectFromMap(
15205 initial_map, NOT_TENURED, true, allocation_site));
15207 array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
15209 // We might need to transition to holey
15210 ElementsKind kind = constructor->initial_map()->elements_kind();
15211 if (holey && !IsFastHoleyElementsKind(kind)) {
15212 kind = GetHoleyElementsKind(kind);
15213 JSObject::TransitionElementsKind(array, kind);
15217 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
15219 ElementsKind old_kind = array->GetElementsKind();
15220 RETURN_FAILURE_ON_EXCEPTION(
15221 isolate, ArrayConstructInitializeElements(array, caller_args));
15222 if (!site.is_null() &&
15223 (old_kind != array->GetElementsKind() ||
15224 !can_use_type_feedback)) {
15225 // The arguments passed in caused a transition. This kind of complexity
15226 // can't be dealt with in the inlined hydrogen array constructor case.
15227 // We must mark the allocationsite as un-inlinable.
15228 site->SetDoNotInlineCall();
15234 RUNTIME_FUNCTION(RuntimeHidden_ArrayConstructor) {
15235 HandleScope scope(isolate);
15236 // If we get 2 arguments then they are the stub parameters (constructor, type
15237 // info). If we get 4, then the first one is a pointer to the arguments
15238 // passed by the caller, and the last one is the length of the arguments
15239 // passed to the caller (redundant, but useful to check on the deoptimizer
15240 // with an assert).
15241 Arguments empty_args(0, NULL);
15242 bool no_caller_args = args.length() == 2;
15243 ASSERT(no_caller_args || args.length() == 4);
15244 int parameters_start = no_caller_args ? 0 : 1;
15245 Arguments* caller_args = no_caller_args
15247 : reinterpret_cast<Arguments*>(args[0]);
15248 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
15249 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
15251 if (!no_caller_args) {
15252 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
15253 ASSERT(arg_count == caller_args->length());
15257 Handle<AllocationSite> site;
15258 if (!type_info.is_null() &&
15259 *type_info != isolate->heap()->undefined_value()) {
15260 site = Handle<AllocationSite>::cast(type_info);
15261 ASSERT(!site->SitePointsToLiteral());
15264 return ArrayConstructorCommon(isolate,
15271 RUNTIME_FUNCTION(RuntimeHidden_InternalArrayConstructor) {
15272 HandleScope scope(isolate);
15273 Arguments empty_args(0, NULL);
15274 bool no_caller_args = args.length() == 1;
15275 ASSERT(no_caller_args || args.length() == 3);
15276 int parameters_start = no_caller_args ? 0 : 1;
15277 Arguments* caller_args = no_caller_args
15279 : reinterpret_cast<Arguments*>(args[0]);
15280 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
15282 if (!no_caller_args) {
15283 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
15284 ASSERT(arg_count == caller_args->length());
15287 return ArrayConstructorCommon(isolate,
15289 Handle<AllocationSite>::null(),
15294 RUNTIME_FUNCTION(Runtime_MaxSmi) {
15295 ASSERT(args.length() == 0);
15296 return Smi::FromInt(Smi::kMaxValue);
15300 #define RETURN_Float32x4_RESULT(value) \
15301 return *isolate->factory()->NewFloat32x4(value);
15304 #define RETURN_Float64x2_RESULT(value) \
15305 return *isolate->factory()->NewFloat64x2(value);
15308 #define RETURN_Int32x4_RESULT(value) \
15309 return *isolate->factory()->NewInt32x4(value);
15312 RUNTIME_FUNCTION(Runtime_CreateFloat32x4) {
15313 HandleScope scope(isolate);
15314 ASSERT(args.length() == 4);
15315 RUNTIME_ASSERT(args[0]->IsNumber());
15316 RUNTIME_ASSERT(args[1]->IsNumber());
15317 RUNTIME_ASSERT(args[2]->IsNumber());
15318 RUNTIME_ASSERT(args[3]->IsNumber());
15320 float32x4_value_t value;
15321 value.storage[0] = static_cast<float>(args.number_at(0));
15322 value.storage[1] = static_cast<float>(args.number_at(1));
15323 value.storage[2] = static_cast<float>(args.number_at(2));
15324 value.storage[3] = static_cast<float>(args.number_at(3));
15326 RETURN_Float32x4_RESULT(value);
15330 RUNTIME_FUNCTION(Runtime_CreateFloat64x2) {
15331 HandleScope scope(isolate);
15332 ASSERT(args.length() == 2);
15333 RUNTIME_ASSERT(args[0]->IsNumber());
15334 RUNTIME_ASSERT(args[1]->IsNumber());
15336 float64x2_value_t value;
15337 value.storage[0] = args.number_at(0);
15338 value.storage[1] = args.number_at(1);
15340 RETURN_Float64x2_RESULT(value);
15344 RUNTIME_FUNCTION(Runtime_CreateInt32x4) {
15345 HandleScope scope(isolate);
15346 ASSERT(args.length() == 4);
15347 RUNTIME_ASSERT(args[0]->IsNumber());
15348 RUNTIME_ASSERT(args[1]->IsNumber());
15349 RUNTIME_ASSERT(args[2]->IsNumber());
15350 RUNTIME_ASSERT(args[3]->IsNumber());
15352 int32x4_value_t value;
15353 value.storage[0] = NumberToInt32(args[0]);
15354 value.storage[1] = NumberToInt32(args[1]);
15355 value.storage[2] = NumberToInt32(args[2]);
15356 value.storage[3] = NumberToInt32(args[3]);
15358 RETURN_Int32x4_RESULT(value);
15362 // Used to convert between uint32_t and float32 without breaking strict
15364 union float32_uint32 {
15367 float32_uint32(float v) {
15370 float32_uint32(uint32_t v) {
15376 union float64_uint64 {
15379 float64_uint64(double v) {
15382 float64_uint64(uint64_t v) {
15388 RUNTIME_FUNCTION(Runtime_Float32x4GetSignMask) {
15389 HandleScope scope(isolate);
15390 ASSERT(args.length() == 1);
15391 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15392 float32_uint32 x(self->x());
15393 float32_uint32 y(self->y());
15394 float32_uint32 z(self->z());
15395 float32_uint32 w(self->w());
15396 uint32_t mx = (x.u & 0x80000000) >> 31;
15397 uint32_t my = (y.u & 0x80000000) >> 31;
15398 uint32_t mz = (z.u & 0x80000000) >> 31;
15399 uint32_t mw = (w.u & 0x80000000) >> 31;
15400 uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
15401 return *isolate->factory()->NewNumberFromUint(value);
15405 RUNTIME_FUNCTION(Runtime_Float64x2GetSignMask) {
15406 HandleScope scope(isolate);
15407 ASSERT(args.length() == 1);
15408 CONVERT_ARG_CHECKED(Float64x2, self, 0);
15409 float64_uint64 x(self->x());
15410 float64_uint64 y(self->y());
15411 uint64_t mx = x.u >> 63;
15412 uint64_t my = y.u >> 63;
15413 uint32_t value = mx | (my << 1) ;
15414 return *isolate->factory()->NewNumberFromUint(value);
15418 RUNTIME_FUNCTION(Runtime_Int32x4GetSignMask) {
15419 HandleScope scope(isolate);
15420 ASSERT(args.length() == 1);
15421 CONVERT_ARG_CHECKED(Int32x4, self, 0);
15422 uint32_t mx = (self->x() & 0x80000000) >> 31;
15423 uint32_t my = (self->y() & 0x80000000) >> 31;
15424 uint32_t mz = (self->z() & 0x80000000) >> 31;
15425 uint32_t mw = (self->w() & 0x80000000) >> 31;
15426 uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
15427 return *isolate->factory()->NewNumberFromUint(value);
15431 #define LANE_VALUE(VALUE, LANE) \
15435 #define LANE_FLAG(VALUE, LANE) \
15439 #define SIMD128_LANE_ACCESS_FUNCTIONS(V) \
15440 V(Float32x4, GetX, NewNumber, x, LANE_VALUE) \
15441 V(Float32x4, GetY, NewNumber, y, LANE_VALUE) \
15442 V(Float32x4, GetZ, NewNumber, z, LANE_VALUE) \
15443 V(Float32x4, GetW, NewNumber, w, LANE_VALUE) \
15444 V(Float64x2, GetX, NewNumber, x, LANE_VALUE) \
15445 V(Float64x2, GetY, NewNumber, y, LANE_VALUE) \
15446 V(Int32x4, GetX, NewNumberFromInt, x, LANE_VALUE) \
15447 V(Int32x4, GetY, NewNumberFromInt, y, LANE_VALUE) \
15448 V(Int32x4, GetZ, NewNumberFromInt, z, LANE_VALUE) \
15449 V(Int32x4, GetW, NewNumberFromInt, w, LANE_VALUE) \
15450 V(Int32x4, GetFlagX, ToBoolean, x, LANE_FLAG) \
15451 V(Int32x4, GetFlagY, ToBoolean, y, LANE_FLAG) \
15452 V(Int32x4, GetFlagZ, ToBoolean, z, LANE_FLAG) \
15453 V(Int32x4, GetFlagW, ToBoolean, w, LANE_FLAG)
15456 #define DECLARE_SIMD_LANE_ACCESS_FUNCTION( \
15457 TYPE, NAME, HEAP_FUNCTION, LANE, ACCESS_FUNCTION) \
15458 RUNTIME_FUNCTION(Runtime_##TYPE##NAME) { \
15459 HandleScope scope(isolate); \
15460 ASSERT(args.length() == 1); \
15462 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15464 return *isolate->factory()->HEAP_FUNCTION( \
15465 ACCESS_FUNCTION(a, LANE)); \
15469 SIMD128_LANE_ACCESS_FUNCTIONS(DECLARE_SIMD_LANE_ACCESS_FUNCTION)
15472 template<typename T>
15473 static inline T Neg(T a) {
15478 template<typename T>
15479 static inline T Not(T a) {
15484 template<typename T>
15485 static inline T Reciprocal(T a) {
15491 inline float Reciprocal<float>(float a) {
15496 template<typename T>
15497 static inline T ReciprocalSqrt(T a) {
15503 inline float ReciprocalSqrt<float>(float a) {
15504 return sqrtf(1.0f / a);
15508 template<typename T>
15509 static inline T Sqrt(T a) {
15515 inline float Sqrt<float>(float a) {
15521 inline double Sqrt<double>(double a) {
15526 #define SIMD128_UNARY_FUNCTIONS(V) \
15527 V(Float32x4, Abs) \
15528 V(Float32x4, Neg) \
15529 V(Float32x4, Reciprocal) \
15530 V(Float32x4, ReciprocalSqrt) \
15531 V(Float32x4, Sqrt) \
15532 V(Float64x2, Abs) \
15533 V(Float64x2, Neg) \
15534 V(Float64x2, Sqrt) \
15539 #define DECLARE_SIMD_UNARY_FUNCTION(TYPE, FUNCTION) \
15540 RUNTIME_FUNCTION(Runtime_##TYPE##FUNCTION) { \
15541 HandleScope scope(isolate); \
15542 ASSERT(args.length() == 1); \
15544 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15546 TYPE::value_t result; \
15547 for (int i = 0; i < TYPE::kLanes; i++) { \
15548 result.storage[i] = FUNCTION(a->getAt(i)); \
15551 RETURN_##TYPE##_RESULT(result); \
15555 SIMD128_UNARY_FUNCTIONS(DECLARE_SIMD_UNARY_FUNCTION)
15558 template<typename T1, typename T2>
15559 inline void BitsTo(T1 s, T2* t) {
15560 memcpy(t, &s, sizeof(T2));
15564 template<typename T1, typename T2>
15565 inline void To(T1 s, T2* t) {
15570 inline void To<int32_t, float>(int32_t s, float* t) {
15571 *t = static_cast<float>(s);
15576 inline void To<float, int32_t>(float s, int32_t* t) {
15577 *t = DoubleToInt32(static_cast<double>(s));
15581 #define SIMD128_CONVERSION_FUNCTIONS(V) \
15582 V(Float32x4, BitsTo, Int32x4) \
15583 V(Float32x4, To, Int32x4) \
15584 V(Int32x4, BitsTo, Float32x4) \
15585 V(Int32x4, To, Float32x4)
15588 #define DECLARE_SIMD_CONVERSION_FUNCTION( \
15589 SOURCE_TYPE, FUNCTION, TARGET_TYPE) \
15590 RUNTIME_FUNCTION( \
15591 Runtime_##SOURCE_TYPE##FUNCTION##TARGET_TYPE) { \
15592 HandleScope scope(isolate); \
15593 ASSERT(args.length() == 1); \
15595 CONVERT_ARG_CHECKED(SOURCE_TYPE, a, 0); \
15597 TARGET_TYPE::value_t result; \
15598 for (int i = 0; i < SOURCE_TYPE::kLanes; i++) { \
15599 FUNCTION(a->getAt(i), &result.storage[i]); \
15602 RETURN_##TARGET_TYPE##_RESULT(result); \
15606 SIMD128_CONVERSION_FUNCTIONS(DECLARE_SIMD_CONVERSION_FUNCTION)
15609 template<typename T>
15610 static inline T Add(T a, T b) {
15615 template<typename T>
15616 static inline T Div(T a, T b) {
15621 template<typename T>
15622 static inline T Mul(T a, T b) {
15627 template<typename T>
15628 static inline T Sub(T a, T b) {
15633 template<typename T>
15634 static inline int32_t Equal(T a, T b) {
15635 return a == b ? -1 : 0;
15639 template<typename T>
15640 static inline int32_t NotEqual(T a, T b) {
15641 return a != b ? -1 : 0;
15645 template<typename T>
15646 static inline int32_t GreaterThanOrEqual(T a, T b) {
15647 return a >= b ? -1 : 0;
15651 template<typename T>
15652 static inline int32_t GreaterThan(T a, T b) {
15653 return a > b ? -1 : 0;
15657 template<typename T>
15658 static inline int32_t LessThan(T a, T b) {
15659 return a < b ? -1 : 0;
15663 template<typename T>
15664 static inline int32_t LessThanOrEqual(T a, T b) {
15665 return a <= b ? -1 : 0;
15669 template<typename T>
15670 static inline T And(T a, T b) {
15675 template<typename T>
15676 static inline T Or(T a, T b) {
15681 template<typename T>
15682 static inline T Xor(T a, T b) {
15687 #define SIMD128_BINARY_FUNCTIONS(V) \
15688 V(Float32x4, Add, Float32x4) \
15689 V(Float32x4, Div, Float32x4) \
15690 V(Float32x4, Max, Float32x4) \
15691 V(Float32x4, Min, Float32x4) \
15692 V(Float32x4, Mul, Float32x4) \
15693 V(Float32x4, Sub, Float32x4) \
15694 V(Float32x4, Equal, Int32x4) \
15695 V(Float32x4, NotEqual, Int32x4) \
15696 V(Float32x4, GreaterThanOrEqual, Int32x4) \
15697 V(Float32x4, GreaterThan, Int32x4) \
15698 V(Float32x4, LessThan, Int32x4) \
15699 V(Float32x4, LessThanOrEqual, Int32x4) \
15700 V(Float64x2, Add, Float64x2) \
15701 V(Float64x2, Div, Float64x2) \
15702 V(Float64x2, Max, Float64x2) \
15703 V(Float64x2, Min, Float64x2) \
15704 V(Float64x2, Mul, Float64x2) \
15705 V(Float64x2, Sub, Float64x2) \
15706 V(Int32x4, Add, Int32x4) \
15707 V(Int32x4, And, Int32x4) \
15708 V(Int32x4, Mul, Int32x4) \
15709 V(Int32x4, Or, Int32x4) \
15710 V(Int32x4, Sub, Int32x4) \
15711 V(Int32x4, Xor, Int32x4) \
15712 V(Int32x4, Equal, Int32x4) \
15713 V(Int32x4, GreaterThan, Int32x4) \
15714 V(Int32x4, LessThan, Int32x4)
15717 #define DECLARE_SIMD_BINARY_FUNCTION( \
15718 TYPE, FUNCTION, RETURN_TYPE) \
15719 RUNTIME_FUNCTION(Runtime_##TYPE##FUNCTION) { \
15720 HandleScope scope(isolate); \
15721 ASSERT(args.length() == 2); \
15723 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15724 CONVERT_ARG_CHECKED(TYPE, b, 1); \
15726 RETURN_TYPE::value_t result; \
15727 for (int i = 0; i < TYPE::kLanes; i++) { \
15728 result.storage[i] = FUNCTION(a->getAt(i), b->getAt(i)); \
15731 RETURN_##RETURN_TYPE##_RESULT(result); \
15735 SIMD128_BINARY_FUNCTIONS(DECLARE_SIMD_BINARY_FUNCTION)
15738 #define SIMD128_SHUFFLE_FUNCTIONS(V) \
15743 #define DECLARE_SIMD_SHUFFLE_FUNCTION(TYPE) \
15744 RUNTIME_FUNCTION(Runtime_##TYPE##Shuffle) { \
15745 HandleScope scope(isolate); \
15746 ASSERT(args.length() == 2); \
15748 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15749 RUNTIME_ASSERT(args[1]->IsNumber()); \
15750 uint32_t m = NumberToUint32(args[1]); \
15752 TYPE::value_t result; \
15753 for (int i = 0; i < TYPE::kLanes; i++) { \
15754 result.storage[i] = a->getAt((m >> (i * 2)) & 0x3); \
15757 RETURN_##TYPE##_RESULT(result); \
15761 SIMD128_SHUFFLE_FUNCTIONS(DECLARE_SIMD_SHUFFLE_FUNCTION)
15764 RUNTIME_FUNCTION(Runtime_Float32x4Scale) {
15765 HandleScope scope(isolate);
15766 ASSERT(args.length() == 2);
15768 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15769 RUNTIME_ASSERT(args[1]->IsNumber());
15771 float _s = static_cast<float>(args.number_at(1));
15772 float32x4_value_t result;
15773 result.storage[0] = self->x() * _s;
15774 result.storage[1] = self->y() * _s;
15775 result.storage[2] = self->z() * _s;
15776 result.storage[3] = self->w() * _s;
15778 RETURN_Float32x4_RESULT(result);
15782 RUNTIME_FUNCTION(Runtime_Float64x2Scale) {
15783 HandleScope scope(isolate);
15784 ASSERT(args.length() == 2);
15786 CONVERT_ARG_CHECKED(Float64x2, self, 0);
15787 RUNTIME_ASSERT(args[1]->IsNumber());
15789 double _s = args.number_at(1);
15790 float64x2_value_t result;
15791 result.storage[0] = self->x() * _s;
15792 result.storage[1] = self->y() * _s;
15794 RETURN_Float64x2_RESULT(result);
15798 #define ARG_TO_FLOAT32(x) \
15799 CONVERT_DOUBLE_ARG_CHECKED(t, 1); \
15800 float x = static_cast<float>(t);
15803 #define ARG_TO_FLOAT64(x) \
15804 CONVERT_DOUBLE_ARG_CHECKED(x, 1); \
15807 #define ARG_TO_INT32(x) \
15808 RUNTIME_ASSERT(args[1]->IsNumber()); \
15809 int32_t x = NumberToInt32(args[1]);
15812 #define ARG_TO_BOOLEAN(x) \
15813 CONVERT_BOOLEAN_ARG_CHECKED(flag, 1); \
15814 int32_t x = flag ? -1 : 0;
15816 #define SIMD128_SET_LANE_FUNCTIONS(V) \
15817 V(Float32x4, WithX, ARG_TO_FLOAT32, 0) \
15818 V(Float32x4, WithY, ARG_TO_FLOAT32, 1) \
15819 V(Float32x4, WithZ, ARG_TO_FLOAT32, 2) \
15820 V(Float32x4, WithW, ARG_TO_FLOAT32, 3) \
15821 V(Float64x2, WithX, ARG_TO_FLOAT64, 0) \
15822 V(Float64x2, WithY, ARG_TO_FLOAT64, 1) \
15823 V(Int32x4, WithX, ARG_TO_INT32, 0) \
15824 V(Int32x4, WithY, ARG_TO_INT32, 1) \
15825 V(Int32x4, WithZ, ARG_TO_INT32, 2) \
15826 V(Int32x4, WithW, ARG_TO_INT32, 3) \
15827 V(Int32x4, WithFlagX, ARG_TO_BOOLEAN, 0) \
15828 V(Int32x4, WithFlagY, ARG_TO_BOOLEAN, 1) \
15829 V(Int32x4, WithFlagZ, ARG_TO_BOOLEAN, 2) \
15830 V(Int32x4, WithFlagW, ARG_TO_BOOLEAN, 3)
15833 #define DECLARE_SIMD_SET_LANE_FUNCTION( \
15834 TYPE, NAME, ARG_FUNCTION, LANE) \
15835 RUNTIME_FUNCTION(Runtime_##TYPE##NAME) { \
15836 HandleScope scope(isolate); \
15837 ASSERT(args.length() == 2); \
15839 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15840 ARG_FUNCTION(value); \
15842 TYPE::value_t result; \
15843 for (int i = 0; i < TYPE::kLanes; i++) { \
15845 result.storage[i] = a->getAt(i); \
15847 result.storage[i] = value; \
15850 RETURN_##TYPE##_RESULT(result); \
15854 SIMD128_SET_LANE_FUNCTIONS(DECLARE_SIMD_SET_LANE_FUNCTION)
15857 RUNTIME_FUNCTION(Runtime_Float32x4Clamp) {
15858 HandleScope scope(isolate);
15859 ASSERT(args.length() == 3);
15861 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15862 CONVERT_ARG_CHECKED(Float32x4, lo, 1);
15863 CONVERT_ARG_CHECKED(Float32x4, hi, 2);
15865 float32x4_value_t result;
15866 float _x = self->x() > lo->x() ? self->x() : lo->x();
15867 float _y = self->y() > lo->y() ? self->y() : lo->y();
15868 float _z = self->z() > lo->z() ? self->z() : lo->z();
15869 float _w = self->w() > lo->w() ? self->w() : lo->w();
15870 result.storage[0] = _x > hi->x() ? hi->x() : _x;
15871 result.storage[1] = _y > hi->y() ? hi->y() : _y;
15872 result.storage[2] = _z > hi->z() ? hi->z() : _z;
15873 result.storage[3] = _w > hi->w() ? hi->w() : _w;
15875 RETURN_Float32x4_RESULT(result);
15879 RUNTIME_FUNCTION(Runtime_Float64x2Clamp) {
15880 HandleScope scope(isolate);
15881 ASSERT(args.length() == 3);
15883 CONVERT_ARG_CHECKED(Float64x2, self, 0);
15884 CONVERT_ARG_CHECKED(Float64x2, lo, 1);
15885 CONVERT_ARG_CHECKED(Float64x2, hi, 2);
15887 float64x2_value_t result;
15888 double _x = self->x() > lo->x() ? self->x() : lo->x();
15889 double _y = self->y() > lo->y() ? self->y() : lo->y();
15890 result.storage[0] = _x > hi->x() ? hi->x() : _x;
15891 result.storage[1] = _y > hi->y() ? hi->y() : _y;
15893 RETURN_Float64x2_RESULT(result);
15897 RUNTIME_FUNCTION(Runtime_Float32x4ShuffleMix) {
15898 HandleScope scope(isolate);
15899 ASSERT(args.length() == 3);
15901 CONVERT_ARG_CHECKED(Float32x4, first, 0);
15902 CONVERT_ARG_CHECKED(Float32x4, second, 1);
15903 RUNTIME_ASSERT(args[2]->IsNumber());
15905 uint32_t m = NumberToUint32(args[2]);
15906 float32x4_value_t result;
15907 float data1[4] = { first->x(), first->y(), first->z(), first->w() };
15908 float data2[4] = { second->x(), second->y(), second->z(), second->w() };
15909 result.storage[0] = data1[m & 0x3];
15910 result.storage[1] = data1[(m >> 2) & 0x3];
15911 result.storage[2] = data2[(m >> 4) & 0x3];
15912 result.storage[3] = data2[(m >> 6) & 0x3];
15914 RETURN_Float32x4_RESULT(result);
15918 RUNTIME_FUNCTION(Runtime_Int32x4Select) {
15919 HandleScope scope(isolate);
15920 ASSERT(args.length() == 3);
15922 CONVERT_ARG_CHECKED(Int32x4, self, 0);
15923 CONVERT_ARG_CHECKED(Float32x4, tv, 1);
15924 CONVERT_ARG_CHECKED(Float32x4, fv, 2);
15926 uint32_t _maskX = self->x();
15927 uint32_t _maskY = self->y();
15928 uint32_t _maskZ = self->z();
15929 uint32_t _maskW = self->w();
15930 // Extract floats and interpret them as masks.
15931 float32_uint32 tvx(tv->x());
15932 float32_uint32 tvy(tv->y());
15933 float32_uint32 tvz(tv->z());
15934 float32_uint32 tvw(tv->w());
15935 float32_uint32 fvx(fv->x());
15936 float32_uint32 fvy(fv->y());
15937 float32_uint32 fvz(fv->z());
15938 float32_uint32 fvw(fv->w());
15940 float32_uint32 tempX((_maskX & tvx.u) | (~_maskX & fvx.u));
15941 float32_uint32 tempY((_maskY & tvy.u) | (~_maskY & fvy.u));
15942 float32_uint32 tempZ((_maskZ & tvz.u) | (~_maskZ & fvz.u));
15943 float32_uint32 tempW((_maskW & tvw.u) | (~_maskW & fvw.u));
15945 float32x4_value_t result;
15946 result.storage[0] = tempX.f;
15947 result.storage[1] = tempY.f;
15948 result.storage[2] = tempZ.f;
15949 result.storage[3] = tempW.f;
15951 RETURN_Float32x4_RESULT(result);
15955 // ----------------------------------------------------------------------------
15956 // Implementation of Runtime
15958 #define F(name, number_of_args, result_size) \
15959 { Runtime::k##name, Runtime::RUNTIME, #name, \
15960 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
15963 #define FH(name, number_of_args, result_size) \
15964 { Runtime::kHidden##name, Runtime::RUNTIME_HIDDEN, NULL, \
15965 FUNCTION_ADDR(RuntimeHidden_##name), number_of_args, result_size },
15968 #define I(name, number_of_args, result_size) \
15969 { Runtime::kInline##name, Runtime::INLINE, \
15970 "_" #name, NULL, number_of_args, result_size },
15973 #define IO(name, number_of_args, result_size) \
15974 { Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, \
15975 "_" #name, FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
15978 static const Runtime::Function kIntrinsicFunctions[] = {
15979 RUNTIME_FUNCTION_LIST(F)
15980 RUNTIME_HIDDEN_FUNCTION_LIST(FH)
15981 INLINE_FUNCTION_LIST(I)
15982 INLINE_OPTIMIZED_FUNCTION_LIST(IO)
15991 void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate,
15992 Handle<NameDictionary> dict) {
15993 ASSERT(dict->NumberOfElements() == 0);
15994 HandleScope scope(isolate);
15995 for (int i = 0; i < kNumFunctions; ++i) {
15996 const char* name = kIntrinsicFunctions[i].name;
15997 if (name == NULL) continue;
15998 Handle<NameDictionary> new_dict = NameDictionary::Add(
16000 isolate->factory()->InternalizeUtf8String(name),
16001 Handle<Smi>(Smi::FromInt(i), isolate),
16002 PropertyDetails(NONE, NORMAL, Representation::None()));
16003 // The dictionary does not need to grow.
16004 CHECK(new_dict.is_identical_to(dict));
16009 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
16010 Heap* heap = name->GetHeap();
16011 int entry = heap->intrinsic_function_names()->FindEntry(name);
16012 if (entry != kNotFound) {
16013 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
16014 int function_index = Smi::cast(smi_index)->value();
16015 return &(kIntrinsicFunctions[function_index]);
16021 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
16022 return &(kIntrinsicFunctions[static_cast<int>(id)]);
16025 } } // namespace v8::internal